diff --git a/SciPost_v1/settings/base.py b/SciPost_v1/settings/base.py
index 861544adb28ad4486484f1974dffafa2cb563a9a..28b54d4d47b36226691056e38982ab5f4569efe6 100644
--- a/SciPost_v1/settings/base.py
+++ b/SciPost_v1/settings/base.py
@@ -95,6 +95,7 @@ INSTALLED_APPS = (
     'virtualmeetings',
     'production',
     'partners',
+    'funders',
     'webpack_loader',
 )
 
diff --git a/SciPost_v1/urls.py b/SciPost_v1/urls.py
index adf26e3aa41c52e07475da80c70f1e99700c13c7..cb5b11d4bc6ea39ec73f242818ed3c5c5ebd5435 100644
--- a/SciPost_v1/urls.py
+++ b/SciPost_v1/urls.py
@@ -20,6 +20,7 @@ urlpatterns = [
     url(r'^commentaries/', include('commentaries.urls', namespace="commentaries")),
     url(r'^commentary/', include('commentaries.urls', namespace="commentaries")),
     url(r'^comments/', include('comments.urls', namespace="comments")),
+    url(r'^funders/', include('funders.urls', namespace="funders")),
     url(r'^journals/', include('journals.urls.general', namespace="journals")),
     url(r'^mailing_list/', include('mailing_lists.urls', namespace="mailing_lists")),
     url(r'^submissions/', include('submissions.urls', namespace="submissions")),
diff --git a/commentaries/factories.py b/commentaries/factories.py
index 9cac495d97050431bf7ccbacfdd2475cf7c55dcd..c908621441bff8715a7bbaf5cce7cd3833994445 100644
--- a/commentaries/factories.py
+++ b/commentaries/factories.py
@@ -20,7 +20,7 @@ class CommentaryFactory(factory.django.DjangoModelFactory):
     discipline = factory.Iterator(SCIPOST_DISCIPLINES, getter=lambda c: c[0])
     domain = factory.Iterator(SCIPOST_JOURNALS_DOMAINS, getter=lambda c: c[0])
     subject_area = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: c[0])
-    pub_title = factory.Faker('text')
+    title = factory.Faker('text')
     pub_DOI = factory.Sequence(lambda n: random_external_doi())
     arxiv_identifier = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number())
     author_list = factory.Faker('name')
@@ -60,6 +60,7 @@ class UnpublishedVettedCommentaryFactory(VettedCommentaryFactory):
 class UnvettedCommentaryFactory(CommentaryFactory):
     vetted = False
 
+
 class UnvettedArxivPreprintCommentaryFactory(CommentaryFactory):
     vetted = False
-    pub_DOI = None
+    pub_DOI = ''
diff --git a/commentaries/forms.py b/commentaries/forms.py
index 4e77b521a054eae82330c8b8e2f61a2099e01475..ce198737a14d3e2e06dc19a59946bbb4edb85d2c 100644
--- a/commentaries/forms.py
+++ b/commentaries/forms.py
@@ -90,7 +90,7 @@ class RequestCommentaryForm(forms.ModelForm):
     class Meta:
         model = Commentary
         fields = [
-            'discipline', 'domain', 'subject_area', 'pub_title',
+            'discipline', 'domain', 'subject_area', 'title',
             'author_list', 'pub_date', 'pub_abstract'
         ]
         placeholders = {
@@ -272,7 +272,7 @@ class VetCommentaryForm(forms.Form):
         # Modified actions are not doing anything. Users are redirected to an edit page instead.
         if self.commentary_is_accepted():
             self.commentary.vetted = True
-            self.commentary.vetted_by = Contributor.objects.get(user=self.user)
+            self.commentary.vetted_by = self.user.contributor
             self.commentary.save()
             return self.commentary
         elif self.commentary_is_refused():
@@ -289,6 +289,6 @@ class CommentarySearchForm(forms.Form):
     def search_results(self):
         """Return all Commentary objects according to search"""
         return Commentary.objects.vetted(
-            pub_title__icontains=self.cleaned_data['title'],
+            title__icontains=self.cleaned_data['title'],
             pub_abstract__icontains=self.cleaned_data['abstract'],
             author_list__icontains=self.cleaned_data['author']).order_by('-pub_date')
diff --git a/commentaries/managers.py b/commentaries/managers.py
index 545a1740ffa0c8efca402352431551ad28c6fd18..9a83ae43472c96d61ff16a29b1f459c3e81218fa 100644
--- a/commentaries/managers.py
+++ b/commentaries/managers.py
@@ -7,3 +7,6 @@ class CommentaryManager(models.Manager):
 
     def awaiting_vetting(self, **kwargs):
         return self.filter(vetted=False, **kwargs)
+
+    def open_for_commenting(self):
+        return self.filter(open_for_commenting=True)
diff --git a/commentaries/migrations/0015_auto_20170726_1615.py b/commentaries/migrations/0015_auto_20170726_1615.py
new file mode 100644
index 0000000000000000000000000000000000000000..34a805eeb7f6c3e07632f800f8214f7a3cb2a764
--- /dev/null
+++ b/commentaries/migrations/0015_auto_20170726_1615.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 14:15
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+def do_nothing(apps, schema_editor):
+    return
+
+
+def fill_empty_strings_for_nulls(apps, schema_editor):
+    Commentary = apps.get_model('commentaries', 'Commentary')
+    Commentary.objects.filter(arxiv_identifier__isnull=True).update(arxiv_identifier='')
+    Commentary.objects.filter(arxiv_or_DOI_string__isnull=True).update(arxiv_or_DOI_string='')
+    Commentary.objects.filter(journal__isnull=True).update(journal='')
+    Commentary.objects.filter(pages__isnull=True).update(pages='')
+    Commentary.objects.filter(pub_DOI__isnull=True).update(pub_DOI='')
+    Commentary.objects.filter(volume__isnull=True).update(volume='')
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('commentaries', '0014_auto_20170201_1243'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='commentary',
+            name='arxiv_identifier',
+            field=models.CharField(blank=True, default='', max_length=100, null=True, verbose_name='arXiv identifier (including version nr)'),
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='arxiv_or_DOI_string',
+            field=models.CharField(default='', max_length=100, null=True, verbose_name='string form of arxiv nr or DOI for commentary url'),
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='journal',
+            field=models.CharField(blank=True, default='', max_length=300, null=True),
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='pages',
+            field=models.CharField(blank=True, default='', max_length=50, null=True),
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='pub_DOI',
+            field=models.CharField(blank=True, default='', max_length=200, null=True, verbose_name='DOI of the original publication'),
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='volume',
+            field=models.CharField(blank=True, default='', max_length=50, null=True),
+        ),
+        migrations.RunPython(fill_empty_strings_for_nulls, do_nothing),
+    ]
diff --git a/commentaries/migrations/0016_auto_20170726_1616.py b/commentaries/migrations/0016_auto_20170726_1616.py
new file mode 100644
index 0000000000000000000000000000000000000000..63e1a1ea5a56f469c28a29d391c19122e76cb056
--- /dev/null
+++ b/commentaries/migrations/0016_auto_20170726_1616.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 14:16
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('commentaries', '0015_auto_20170726_1615'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='commentary',
+            name='arxiv_identifier',
+            field=models.CharField(blank=True, default='', max_length=100, verbose_name='arXiv identifier (including version nr)'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='arxiv_or_DOI_string',
+            field=models.CharField(default='', max_length=100, verbose_name='string form of arxiv nr or DOI for commentary url'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='journal',
+            field=models.CharField(blank=True, default='', max_length=300),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='pages',
+            field=models.CharField(blank=True, default='', max_length=50),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='pub_DOI',
+            field=models.CharField(blank=True, default='', max_length=200, verbose_name='DOI of the original publication'),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='commentary',
+            name='volume',
+            field=models.CharField(blank=True, default='', max_length=50),
+            preserve_default=False,
+        ),
+    ]
diff --git a/commentaries/migrations/0017_auto_20170728_1901.py b/commentaries/migrations/0017_auto_20170728_1901.py
new file mode 100644
index 0000000000000000000000000000000000000000..4965029020dcd247aa1d12d87794b5e96c09760a
--- /dev/null
+++ b/commentaries/migrations/0017_auto_20170728_1901.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-28 17:01
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('commentaries', '0016_auto_20170726_1616'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='commentary',
+            old_name='pub_title',
+            new_name='title',
+        ),
+    ]
diff --git a/commentaries/models.py b/commentaries/models.py
index da8321b411630469c64122437bb5de53f452a870..a6176b57643f971bd840014227ff795e9cfb53cd 100644
--- a/commentaries/models.py
+++ b/commentaries/models.py
@@ -1,18 +1,18 @@
 from django.db import models
+from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.postgres.fields import JSONField
 from django.core.urlresolvers import reverse
 from django.template import Template, Context
 
 from journals.constants import SCIPOST_JOURNALS_DOMAINS
-from scipost.behaviors import ArxivCallable, TimeStampedModel
-from scipost.models import Contributor
+from scipost.behaviors import TimeStampedModel
 from scipost.constants import SCIPOST_DISCIPLINES, DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS
 
 from .constants import COMMENTARY_TYPES
 from .managers import CommentaryManager
 
 
-class Commentary(ArxivCallable, TimeStampedModel):
+class Commentary(TimeStampedModel):
     """
     A Commentary contains all the contents of a SciPost Commentary page for a given publication.
     """
@@ -25,63 +25,58 @@ class Commentary(ArxivCallable, TimeStampedModel):
     discipline = models.CharField(max_length=20,
                                   choices=SCIPOST_DISCIPLINES, default=DISCIPLINE_PHYSICS)
     domain = models.CharField(max_length=3, choices=SCIPOST_JOURNALS_DOMAINS)
-    subject_area = models.CharField(
-        max_length=10, choices=SCIPOST_SUBJECT_AREAS,
-        default='Phys:QP')
+    subject_area = models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS,
+                                    default='Phys:QP')
     open_for_commenting = models.BooleanField(default=True)
-    pub_title = models.CharField(max_length=300, verbose_name='title')
-    arxiv_identifier = models.CharField(
-        max_length=100, verbose_name="arXiv identifier (including version nr)",
-        blank=True, null=True)
+    title = models.CharField(max_length=300, verbose_name='title')
+    arxiv_identifier = models.CharField(max_length=100, blank=True,
+                                        verbose_name="arXiv identifier (including version nr)")
     arxiv_link = models.URLField(verbose_name='arXiv link (including version nr)', blank=True)
-    pub_DOI = models.CharField(
-        max_length=200, verbose_name='DOI of the original publication',
-        blank=True, null=True)
+    pub_DOI = models.CharField(max_length=200, verbose_name='DOI of the original publication',
+                               blank=True)
     pub_DOI_link = models.URLField(
         verbose_name='DOI link to the original publication',
         blank=True)
     metadata = JSONField(default={}, blank=True, null=True)
-    arxiv_or_DOI_string = models.CharField(
-        max_length=100, default='',
-        verbose_name='string form of arxiv nr or DOI for commentary url')
+    arxiv_or_DOI_string = models.CharField(max_length=100,
+                                           verbose_name='string form of arxiv nr or'
+                                                        ' DOI for commentary url')
     author_list = models.CharField(max_length=1000)
 
     # Authors which have been mapped to contributors:
-    authors = models.ManyToManyField(
-        Contributor, blank=True,
-        related_name='authors_com')
-    authors_claims = models.ManyToManyField(
-        Contributor, blank=True,
-        related_name='authors_com_claims')
-    authors_false_claims = models.ManyToManyField(
-        Contributor, blank=True,
-        related_name='authors_com_false_claims')
-    journal = models.CharField(max_length=300, blank=True, null=True)
-    volume = models.CharField(max_length=50, blank=True, null=True)
-    pages = models.CharField(max_length=50, blank=True, null=True)
-    pub_date = models.DateField(
-        verbose_name='date of original publication',
-        blank=True, null=True)
+    authors = models.ManyToManyField('scipost.Contributor', blank=True,
+                                     related_name='authors_com')
+    authors_claims = models.ManyToManyField('scipost.Contributor', blank=True,
+                                            related_name='authors_com_claims')
+    authors_false_claims = models.ManyToManyField('scipost.Contributor', blank=True,
+                                                  related_name='authors_com_false_claims')
+    journal = models.CharField(max_length=300, blank=True)
+    volume = models.CharField(max_length=50, blank=True)
+    pages = models.CharField(max_length=50, blank=True)
+    pub_date = models.DateField(verbose_name='date of original publication',
+                                blank=True, null=True)
     pub_abstract = models.TextField(verbose_name='abstract')
 
+    # Comments can be added to a Commentary
+    comments = GenericRelation('comments.Comment', related_query_name='commentaries')
+
     objects = CommentaryManager()
 
     class Meta:
         verbose_name_plural = 'Commentaries'
 
     def __str__(self):
-        return self.pub_title
+        return self.title
 
-    @classmethod
-    def same_version_exists(self, identifier):
-        return self.objects.filter(arxiv_identifier=identifier).exists()
+    def get_absolute_url(self):
+        return reverse('commentaries:commentary', args=(self.arxiv_or_DOI_string,))
 
     def title_label(self):
         context = Context({
             'scipost_url': reverse('commentaries:commentary', args=(self.arxiv_or_DOI_string,)),
-            'pub_title': self.pub_title
+            'title': self.title
         })
-        template = Template('<a href="{{scipost_url}}" class="pubtitleli">{{pub_title}}</a>')
+        template = Template('<a href="{{scipost_url}}" class="pubtitleli">{{title}}</a>')
         return template.render(context)
 
     def parse_links_into_urls(self, commit=False):
diff --git a/commentaries/templates/commentaries/_commentary_card_content.html b/commentaries/templates/commentaries/_commentary_card_content.html
index 5585602e4414705bb58aec183318cc752476f03d..33aee23fc70a3f14b779e034528259c8629f7a07 100644
--- a/commentaries/templates/commentaries/_commentary_card_content.html
+++ b/commentaries/templates/commentaries/_commentary_card_content.html
@@ -1,6 +1,6 @@
 <div class="card-block">
     <h3 class="card-title">
-        <a href="{% url 'commentaries:commentary' commentary.arxiv_or_DOI_string %}">{{ commentary.pub_title }}</a>
+        <a href="{% url 'commentaries:commentary' commentary.arxiv_or_DOI_string %}">{{ commentary.title }}</a>
     </h3>
     <p class="mt-0 mb-3">
         by {{ commentary.author_list }}{% if commentary.type == 'published' %}, {{ commentary.journal }} {{ commentary.volume }}, {{ commentary.pages }}{% elif commentary.type == 'preprint' %} &middot; <a href="{{ commentary.arxiv_link }}">{{ commentary.arxiv_link }}</a>{% endif %}
diff --git a/commentaries/templates/commentaries/_commentary_summary.html b/commentaries/templates/commentaries/_commentary_summary.html
index be9db8316e26049b3d925a5d52d3886e564b0ccc..914dd82eadc074a2b44a9ca2c396aa7837c2fbe3 100644
--- a/commentaries/templates/commentaries/_commentary_summary.html
+++ b/commentaries/templates/commentaries/_commentary_summary.html
@@ -1,7 +1,7 @@
 <table class="commentary summary">
     <tr>
         <td>Title:</td>
-        <td>{{commentary.pub_title}}</td>
+        <td>{{commentary.title}}</td>
     </tr>
     <tr>
         <td>Author(s):</td>
diff --git a/commentaries/templates/commentaries/commentary_detail.html b/commentaries/templates/commentaries/commentary_detail.html
index 5b47e90f8844ea97816973ff8de2271abd9a271c..ad8cee7adb14d5cf208ef086a3dc79d3065cfe17 100644
--- a/commentaries/templates/commentaries/commentary_detail.html
+++ b/commentaries/templates/commentaries/commentary_detail.html
@@ -6,25 +6,6 @@
 
 {% load scipost_extras %}
 
-<script>
-  $(document).ready(function(){
-
-    var comment_text_input = $("#id_comment_text");
-
-    function set_comment_text(value) {
-      $("#preview-comment_text").text(value)
-    }
-    set_comment_text(comment_text_input.val());
-
-    comment_text_input.keyup(function(){
-      var new_text = $(this).val()
-      set_comment_text(new_text)
-      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
-    });
-
-  });
-</script>
-
 {% endblock headsup %}
 
 {% block content %}
@@ -49,7 +30,7 @@
     </div>
 </div>
 
-{% include 'scipost/comments_block.html' %}
+{% include 'scipost/comments_block.html' with comments=commentary.comments.vetted type_of_object='Commentary' %}
 
 {% include 'comments/new_comment.html' with object_id=commentary.id type_of_object='commentary' open_for_commenting=commentary.open_for_commenting %}
 
diff --git a/commentaries/templates/commentaries/vet_commentary_email_accepted.html b/commentaries/templates/commentaries/vet_commentary_email_accepted.html
index 7c5056b8e24c8cdb402c3cfafb8801684f8e2a2f..cc92f551efbeea589b1df655eb6f1610cafda868 100644
--- a/commentaries/templates/commentaries/vet_commentary_email_accepted.html
+++ b/commentaries/templates/commentaries/vet_commentary_email_accepted.html
@@ -1,6 +1,6 @@
 Dear {{commentary.requested_by.get_title}} {{commentary.requested_by.user.last_name}},
 
-The Commentary Page you have requested, concerning publication with title {{commentary.pub_title}} by {{commentary.author_list}}, has been activated at https://scipost.org/commentary/{{commentary.arxiv_or_DOI_string}}.
+The Commentary Page you have requested, concerning publication with title {{commentary.title}} by {{commentary.author_list}}, has been activated at https://scipost.org/commentary/{{commentary.arxiv_or_DOI_string}}.
 You are now welcome to submit your comments.
 
 Thank you for your contribution,
diff --git a/commentaries/templates/commentaries/vet_commentary_email_modified.html b/commentaries/templates/commentaries/vet_commentary_email_modified.html
index f3ad85365c4ab2f4398dc9b9e644aeece54b7559..fa419f41fc6c3904cedfbe12892b16e16e05bd0d 100644
--- a/commentaries/templates/commentaries/vet_commentary_email_modified.html
+++ b/commentaries/templates/commentaries/vet_commentary_email_modified.html
@@ -1,6 +1,6 @@
 Dear {{commentary.requested_by.get_title}} {{commentary.requested_by.user.last_name}},
 
-The Commentary Page you have requested, concerning publication with title {{commentary.pub_title}} by {{commentary.author_list}}, has been activated (with slight modifications to your submitted details).
+The Commentary Page you have requested, concerning publication with title {{commentary.title}} by {{commentary.author_list}}, has been activated (with slight modifications to your submitted details).
 You are now welcome to submit your comments.
 
 Thank you for your contribution,
diff --git a/commentaries/templates/commentaries/vet_commentary_email_rejected.html b/commentaries/templates/commentaries/vet_commentary_email_rejected.html
index b9d99fade03b2a34cfcb59728285f97b7e677c61..0273fb35bd9b7ec36071a1e179698f9de15f01eb 100644
--- a/commentaries/templates/commentaries/vet_commentary_email_rejected.html
+++ b/commentaries/templates/commentaries/vet_commentary_email_rejected.html
@@ -1,6 +1,6 @@
 Dear {{commentary.requested_by.get_title}} {{commentary.requested_by.user.last_name}},
 
-The Commentary Page you have requested, concerning publication with title {{commentary.pub_title}} by {{commentary.author_list}}, has not been activated for the following reason: {{refusal_reason}}.
+The Commentary Page you have requested, concerning publication with title {{commentary.title}} by {{commentary.author_list}}, has not been activated for the following reason: {{refusal_reason}}.
 
 {% if further_explanation %}
 Further explanations:
diff --git a/commentaries/test_forms.py b/commentaries/test_forms.py
index 64d6fda33f5bb8bcb968d89dd17567becdbf6bef..35e65abb64b3b50ed5f3aca96a9a65dbefce65a5 100644
--- a/commentaries/test_forms.py
+++ b/commentaries/test_forms.py
@@ -101,14 +101,13 @@ class TestVetCommentaryForm(TestCase):
         add_groups_and_permissions()
         ContributorFactory.create_batch(5)
         self.commentary = UnvettedCommentaryFactory.create()
-        self.user = UserFactory()
+        self.user = UserFactory.create()
         self.form_data = {
             'action_option': VetCommentaryForm.ACTION_ACCEPT,
             'refusal_reason': VetCommentaryForm.REFUSAL_EMPTY,
             'email_response_field': 'Lorem Ipsum'
         }
 
-
     def test_valid_accepted_form(self):
         """Test valid form data and return Commentary"""
         form = VetCommentaryForm(self.form_data, commentary_id=self.commentary.id, user=self.user)
@@ -127,7 +126,7 @@ class TestVetCommentaryForm(TestCase):
         form = VetCommentaryForm(self.form_data, commentary_id=self.commentary.id, user=self.user)
         self.assertTrue(form.is_valid())
         self.assertFalse(Commentary.objects.vetted().exists())
-        self.assertTrue(Commentary.objects.awaiting_vetting().exists())
+        self.assertTrue(Commentary.objects.awaiting_vetting().count() == 1)
 
         # Delete the Commentary
         form.process_commentary()
@@ -156,7 +155,7 @@ class TestVetCommentaryForm(TestCase):
     def test_process_before_validation(self):
         """Test response of form on processing before validation"""
         form = VetCommentaryForm(self.form_data, commentary_id=self.commentary.id, user=self.user)
-        self.assertRaises(ValueError, form.process_commentary)
+        self.assertRaises(AttributeError, form.process_commentary)
 
 
 class TestRequestPublishedArticleForm(TestCase):
diff --git a/commentaries/views.py b/commentaries/views.py
index f6153335f31d852d12d98181fef79a1aafdcad2e..dcbf31f3ff6c8fc1a92becea8812706c7e13e541 100644
--- a/commentaries/views.py
+++ b/commentaries/views.py
@@ -3,7 +3,6 @@ from django.contrib import messages
 from django.contrib.auth.decorators import login_required, permission_required
 from django.core.mail import EmailMessage
 from django.core.urlresolvers import reverse, reverse_lazy
-from django.db.models import Q
 from django.shortcuts import redirect
 from django.template.loader import render_to_string
 from django.views.generic.edit import CreateView
@@ -209,12 +208,7 @@ class CommentaryListView(ListView):
         context = super().get_context_data(**kwargs)
 
         # Get newest comments
-        context['comment_list'] = (Comment.objects.vetted()
-                                   .filter(Q(commentary__isnull=False) |
-                                           Q(submission__isnull=False) |
-                                           Q(thesislink__isnull=False))
-                                   .select_related('author__user', 'submission', 'commentary')
-                                   .order_by('-date_submitted')[:10])
+        context['comment_list'] = Comment.objects.vetted().order_by('-date_submitted')[:10]
 
         # Form into the context!
         context['form'] = self.form
@@ -234,7 +228,6 @@ def commentary_detail(request, arxiv_or_DOI_string):
     commentary = get_object_or_404(Commentary.objects.vetted(),
                                    arxiv_or_DOI_string=arxiv_or_DOI_string)
 
-    comments = commentary.comment_set.all()
     form = CommentForm()
     try:
         author_replies = Comment.objects.filter(
@@ -242,6 +235,5 @@ def commentary_detail(request, arxiv_or_DOI_string):
     except Comment.DoesNotExist:
         author_replies = ()
     context = {'commentary': commentary,
-               'comments': comments.filter(status__gte=1).order_by('-date_submitted'),
                'author_replies': author_replies, 'form': form}
     return render(request, 'commentaries/commentary_detail.html', context)
diff --git a/comments/admin.py b/comments/admin.py
index 6cfa6fa189234c235205ff884230843cb796e43a..25c767aa4691c951af14d3c43bedf9ee032ec059 100644
--- a/comments/admin.py
+++ b/comments/admin.py
@@ -1,5 +1,7 @@
 from django.contrib import admin
 
+from guardian.admin import GuardedModelAdmin
+
 from .constants import STATUS_VETTED
 from .models import Comment
 
@@ -13,7 +15,7 @@ def comment_is_vetted(comment):
     return comment.status is STATUS_VETTED
 
 
-class CommentAdmin(admin.ModelAdmin):
+class CommentAdmin(GuardedModelAdmin):
     list_display = (comment_opening, 'author', 'date_submitted', comment_is_vetted)
     date_hierarchy = 'date_submitted'
     list_filter = ('status',)
diff --git a/comments/factories.py b/comments/factories.py
index d74370a136d4a140fd82e8f6d060acf6497526b4..1f76cf6a460001cb60077d1d5e73bdf075dd2c6a 100644
--- a/comments/factories.py
+++ b/comments/factories.py
@@ -31,16 +31,16 @@ class CommentFactory(factory.django.DjangoModelFactory):
 
 
 class CommentaryCommentFactory(CommentFactory):
-    commentary = factory.SubFactory(VettedCommentaryFactory)
+    content_object = factory.SubFactory(VettedCommentaryFactory)
 
 
 class SubmissionCommentFactory(CommentFactory):
-    submission = factory.SubFactory(EICassignedSubmissionFactory)
+    content_object = factory.SubFactory(EICassignedSubmissionFactory)
 
 
 class ThesislinkCommentFactory(CommentFactory):
-    thesislink = factory.SubFactory(VettedThesisLinkFactory)
+    content_object = factory.SubFactory(VettedThesisLinkFactory)
 
 
 class ReplyCommentFactory(CommentFactory):
-    in_reply_to_comment = factory.SubFactory(SubmissionCommentFactory)
+    content_object = factory.SubFactory(SubmissionCommentFactory)
diff --git a/comments/forms.py b/comments/forms.py
index 8aace94b0c36586c54abc63509f04588f093ff64..94b6fa62fefff353346ba27926df9aaa7f7e1ebb 100644
--- a/comments/forms.py
+++ b/comments/forms.py
@@ -3,9 +3,6 @@ from django import forms
 from .constants import COMMENT_ACTION_CHOICES, COMMENT_REFUSAL_CHOICES
 from .models import Comment
 
-from crispy_forms.helper import FormHelper
-from crispy_forms.layout import Layout, Div, Field, Fieldset, HTML, Submit
-
 
 class CommentForm(forms.ModelForm):
     class Meta:
@@ -20,34 +17,6 @@ class CommentForm(forms.ModelForm):
             {'placeholder': 'NOTE: only serious and meaningful Comments will be accepted.'})
         self.fields['remarks_for_editors'].widget.attrs.update(
             {'rows': 3, 'placeholder': '(these remarks will not be publicly visible)'})
-        self.helper = FormHelper()
-        self.helper.layout = Layout(
-            Div(
-                Div(
-                    Field('comment_text'),
-                    HTML('<p>In your comment, you can use LaTeX \$...\$ for in-text '
-                         'equations or \ [ ... \ ] for on-line equations.</p>'),
-                    HTML('<p id="goodCommenter"><i>Be professional. Only serious and '
-                         'meaningful comments will be vetted through.</i></p><br/>'),
-                    Field('remarks_for_editors'),
-                    css_class="col-md-9"),
-                Div(
-                    Fieldset(
-                        'Specify categorization(s):',
-                        'is_cor', 'is_rem', 'is_que', 'is_ans', 'is_obj',
-                        'is_rep', 'is_val', 'is_lit', 'is_sug',
-                        style="border: 0px; font-size: 90%"),
-                    HTML('<br>'),
-                    Div(
-                        Submit('submit', 'Submit your Comment for vetting',
-                               css_class="submitButton"),
-                        HTML('<p id="goodCommenter"><i>By clicking on Submit, you agree with the '
-                             '<a href="{% url \'scipost:terms_and_conditions\' %}">'
-                             'Terms and Conditions</a>.</i></p>'),
-                        ),
-                    css_class="col-md-3"),
-                css_class="row"),
-            )
 
 
 class VetCommentForm(forms.Form):
diff --git a/comments/managers.py b/comments/managers.py
index 823b4c0d79a732c224bc62bec58d1f70d1f416fb..70e6f20693fb1986569befa36a54852d8e130d1f 100644
--- a/comments/managers.py
+++ b/comments/managers.py
@@ -3,9 +3,15 @@ from django.db import models
 from .constants import STATUS_PENDING
 
 
-class CommentManager(models.Manager):
+class CommentQuerySet(models.QuerySet):
     def vetted(self):
         return self.filter(status__gte=1)
 
     def awaiting_vetting(self):
         return self.filter(status=STATUS_PENDING)
+
+    def regular_comments(self):
+        return self.filter(is_author_reply=False)
+
+    def author_replies(self):
+        return self.filter(is_author_reply=True)
diff --git a/comments/migrations/0013_auto_20170726_1538.py b/comments/migrations/0013_auto_20170726_1538.py
new file mode 100644
index 0000000000000000000000000000000000000000..81672bccbd46993e8e2c62a2b1956c3c934424a0
--- /dev/null
+++ b/comments/migrations/0013_auto_20170726_1538.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 13:38
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('comments', '0012_auto_20170415_1659'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='comment',
+            options={'permissions': (('can_vet_comments', 'Can vet submitted Comments'),)},
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='date_submitted',
+            field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='date submitted'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='remarks_for_editors',
+            field=models.TextField(blank=True, verbose_name='optional remarks for the Editors only'),
+        ),
+    ]
diff --git a/comments/migrations/0014_auto_20170726_2117.py b/comments/migrations/0014_auto_20170726_2117.py
new file mode 100644
index 0000000000000000000000000000000000000000..93abe8af32d17736bc80b3162131d5ca14258454
--- /dev/null
+++ b/comments/migrations/0014_auto_20170726_2117.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 19:17
+from __future__ import unicode_literals
+
+from django.contrib.auth import get_user_model
+from django.db import migrations
+
+from guardian.shortcuts import assign_perm
+
+
+def do_nothing(apps, schema_editor):
+    return
+
+
+def update_eic_permissions(apps, schema_editor):
+    """
+    Grant EIC of submission related to unvetted comment
+    permission to vet his submission's comment.
+    """
+    Comment = apps.get_model('comments', 'Comment')
+    User = get_user_model()
+
+    count = 0
+    for comment in Comment.objects.filter(status=0):
+        if comment.submission:
+            # Grant Permissions
+            user = User.objects.get(id=comment.submission.editor_in_charge.user.id)
+            assign_perm('comments.can_vet_comments', user, comment)
+            count += 1
+    print('\nGranted permission to %i Editor(s)-in-charge to vet related Comments.' % count)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('comments', '0013_auto_20170726_1538'),
+    ]
+
+    operations = [
+        migrations.RunPython(update_eic_permissions, do_nothing),
+    ]
diff --git a/comments/migrations/0015_auto_20170727_1248.py b/comments/migrations/0015_auto_20170727_1248.py
new file mode 100644
index 0000000000000000000000000000000000000000..de0a61ca5a5096e1364b319d57e0af4434a5a8e8
--- /dev/null
+++ b/comments/migrations/0015_auto_20170727_1248.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-27 10:48
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('contenttypes', '0002_remove_content_type_name'),
+        ('comments', '0014_auto_20170726_2117'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='comment',
+            name='content_type',
+            field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
+            preserve_default=False,
+        ),
+        migrations.AddField(
+            model_name='comment',
+            name='object_id',
+            field=models.PositiveIntegerField(default=1),
+            preserve_default=False,
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='submission',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='comments_old', to='submissions.Submission'),
+        ),
+    ]
diff --git a/comments/migrations/0016_auto_20170728_1901.py b/comments/migrations/0016_auto_20170728_1901.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2e4e4a7236ea66e88104c31723f9511dda1cf04
--- /dev/null
+++ b/comments/migrations/0016_auto_20170728_1901.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-28 17:01
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('comments', '0015_auto_20170727_1248'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='comment',
+            name='in_reply_to_comment',
+            field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='nested_comments_old', to='comments.Comment'),
+        ),
+    ]
diff --git a/comments/migrations/0017_auto_20170729_0717.py b/comments/migrations/0017_auto_20170729_0717.py
new file mode 100644
index 0000000000000000000000000000000000000000..db86be1347d9f1c75a3c61ef6d07bf5028ae94c9
--- /dev/null
+++ b/comments/migrations/0017_auto_20170729_0717.py
@@ -0,0 +1,126 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-29 05:17
+from __future__ import unicode_literals
+
+from django.contrib.auth import get_user_model
+from django.contrib.contenttypes.models import ContentType
+from django.db import migrations
+
+from guardian.shortcuts import assign_perm
+
+
+def update_all_contenttypes(**kwargs):
+    from django.apps import apps
+    from django.contrib.contenttypes.management import update_contenttypes
+
+    for app_config in apps.get_app_configs():
+        update_contenttypes(app_config, **kwargs)
+
+
+def create_all_permissions(**kwargs):
+    from django.contrib.auth.management import create_permissions
+    from django.apps import apps
+
+    for app_config in apps.get_app_configs():
+        create_permissions(app_config, **kwargs)
+
+
+def forward():
+    update_all_contenttypes()
+    create_all_permissions()
+
+
+def migrate_comments_from_generic_relations(apps, schema_editor):
+    """
+    Migrate all GenericRelations a Comment has to the oldschool ForeignKey relations.
+    """
+    return
+    Comment = apps.get_model('comments', 'Comment')
+    Report = apps.get_model('submissions', 'Report')
+    Submission = apps.get_model('submissions', 'Submission')
+    Commentary = apps.get_model('commentaries', 'Commentary')
+    ThesisLink = apps.get_model('theses', 'ThesisLink')
+
+    all_comments = Comment.objects.all()
+    for comment in all_comments:
+        _object = comment.content_object
+        if isinstance(_object, Comment):
+            comment.in_reply_to_comment = _object
+
+            # Nested Comments have more relations
+            if isinstance(_object.content_object, ThesisLink):
+                comment.thesislink = _object.content_object
+            elif isinstance(_object.content_object, Submission):
+                comment.submission = _object.content_object
+            elif isinstance(_object.content_object, Commentary):
+                comment.commentary = _object.content_object
+        elif isinstance(_object, Report):
+            comment.in_reply_to_report = _object
+            comment.submission = _object.submission
+        elif isinstance(_object, ThesisLink):
+            comment.thesislink = _object
+        elif isinstance(_object, Submission):
+            comment.submission = _object
+        elif isinstance(_object, Commentary):
+            comment.commentary = _object
+        else:
+            raise AttributeError('Comment has no relation to another valid object.')
+        comment.save()
+    print('\nMigrated %i comments back to oldschool ForeignKey relations.' % len(all_comments))
+
+
+def migrate_comments_to_generic_relations(apps, schema_editor):
+    """
+    Migrate all foreignkey relations a Comment has to the new GenericRelation.
+    """
+    forward()
+    Comment = apps.get_model('comments', 'Comment')
+    User = get_user_model()
+
+    all_comments = Comment.objects.all()
+    for comment in all_comments:
+        if comment.in_reply_to_comment:
+            _object = comment.in_reply_to_comment
+            _object_id = comment.in_reply_to_comment.id
+            _object_type = ContentType.objects.get(app_label="comments", model="comment").id
+        elif comment.in_reply_to_report:
+            _object = comment.in_reply_to_report
+            _object_id = comment.in_reply_to_report.id
+            _object_type = ContentType.objects.get(app_label="submissions", model="report").id
+        elif comment.thesislink:
+            _object = comment.thesislink
+            _object_id = comment.thesislink.id
+            _object_type = ContentType.objects.get(app_label="theses", model="thesislink").id
+        elif comment.submission:
+            _object = comment.submission
+            _object_id = comment.submission.id
+            _object_type = ContentType.objects.get(app_label="submissions", model="submission").id
+        elif comment.commentary:
+            _object = comment.commentary
+            _object_id = comment.commentary.id
+            _object_type = ContentType.objects.get(app_label="commentaries", model="commentary").id
+        else:
+            print('\nNo valid relation for Comment: ', comment.id,)
+        comment.content_object = _object
+        comment.content_type_id = _object_type
+        comment.object_id = _object_id
+        comment.save()
+
+        # Grant Permissions
+        if comment.submission:
+            user = User.objects.get(id=comment.submission.editor_in_charge.user.id)
+            assign_perm('comments.can_vet_comments', user, comment)
+
+    print('\nMigrated %i comments to GenericRelations.' % len(all_comments))
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('comments', '0016_auto_20170728_1901'),
+    ]
+
+    operations = [
+        migrations.RunPython(migrate_comments_to_generic_relations,
+                             migrate_comments_from_generic_relations),
+    ]
diff --git a/comments/migrations/0018_auto_20170729_1617.py b/comments/migrations/0018_auto_20170729_1617.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2d3cfed9b3b2ef1f12c2e3431ec846795050927
--- /dev/null
+++ b/comments/migrations/0018_auto_20170729_1617.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-29 14:17
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('comments', '0017_auto_20170729_0717'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='comment',
+            name='author',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='comments', to='scipost.Contributor'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='commentary',
+            field=models.ForeignKey(blank=True, help_text='Warning: This field is out of service and will be removed in the future.', null=True, on_delete=django.db.models.deletion.CASCADE, to='commentaries.Commentary'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='content_type',
+            field=models.ForeignKey(help_text='Warning: Rather use/edit `content_object` instead or be 100% sure you know what you are doing!', on_delete=django.db.models.deletion.CASCADE, to='contenttypes.ContentType'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='in_reply_to_comment',
+            field=models.ForeignKey(blank=True, help_text='Warning: This field is out of service and will be removed in the future.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='nested_comments_old', to='comments.Comment'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='in_reply_to_report',
+            field=models.ForeignKey(blank=True, help_text='Warning: This field is out of service and will be removed in the future.', null=True, on_delete=django.db.models.deletion.CASCADE, to='submissions.Report'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='object_id',
+            field=models.PositiveIntegerField(help_text='Warning: Rather use/edit `content_object` instead or be 100% sure you know what you are doing!'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='submission',
+            field=models.ForeignKey(blank=True, help_text='Warning: This field is out of service and will be removed in the future.', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='comments_old', to='submissions.Submission'),
+        ),
+        migrations.AlterField(
+            model_name='comment',
+            name='thesislink',
+            field=models.ForeignKey(blank=True, help_text='Warning: This field is out of service and will be removed in the future.', null=True, on_delete=django.db.models.deletion.CASCADE, to='theses.ThesisLink'),
+        ),
+    ]
diff --git a/comments/models.py b/comments/models.py
index fd52703d222870e5694815c6b39acb632abfbea9..82ae4cf7bb8e43c962f9fdf99fd3ead00923e41d 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -1,12 +1,22 @@
+from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
+from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.shortcuts import get_object_or_404
+from django.utils import timezone
+from django.utils.functional import cached_property
+
+from guardian.shortcuts import assign_perm
 
 from scipost.behaviors import TimeStampedModel
 from scipost.models import Contributor
 
 from .behaviors import validate_file_extension, validate_max_file_size
 from .constants import COMMENT_STATUS, STATUS_PENDING
-from .managers import CommentManager
+from .managers import CommentQuerySet
+
+
+WARNING_TEXT = 'Warning: Rather use/edit `content_object` instead or be 100% sure you know what you are doing!'
+US_NOTICE = 'Warning: This field is out of service and will be removed in the future.'
 
 
 class Comment(TimeStampedModel):
@@ -16,25 +26,41 @@ class Comment(TimeStampedModel):
     status = models.SmallIntegerField(default=STATUS_PENDING, choices=COMMENT_STATUS)
     vetted_by = models.ForeignKey('scipost.Contributor', blank=True, null=True,
                                   on_delete=models.CASCADE, related_name='comment_vetted_by')
-    file_attachment = models.FileField(
-        upload_to='uploads/comments/%Y/%m/%d/', blank=True,
-        validators=[validate_file_extension, validate_max_file_size]
-    )
-    # a Comment is either for a Commentary or Submission or a ThesisLink.
+    file_attachment = models.FileField(upload_to='uploads/comments/%Y/%m/%d/', blank=True,
+                                       validators=[validate_file_extension, validate_max_file_size]
+                                       )
+
+    # A Comment is always related to another model
+    # This construction implicitly has property: `on_delete=models.CASCADE`
+    content_type = models.ForeignKey(ContentType, help_text=WARNING_TEXT)
+    object_id = models.PositiveIntegerField(help_text=WARNING_TEXT)
+    content_object = GenericForeignKey()
+
+    nested_comments = GenericRelation('comments.Comment', related_query_name='comments')
+
+    # -- U/S
+    # These fields will be removed in the future.
+    # They still exists only to prevent possible data loss.
     commentary = models.ForeignKey('commentaries.Commentary', blank=True, null=True,
-                                   on_delete=models.CASCADE)
+                                   on_delete=models.CASCADE, help_text=US_NOTICE)
     submission = models.ForeignKey('submissions.Submission', blank=True, null=True,
-                                   on_delete=models.CASCADE, related_name='comments')
+                                   on_delete=models.CASCADE, related_name='comments_old',
+                                   help_text=US_NOTICE)
     thesislink = models.ForeignKey('theses.ThesisLink', blank=True, null=True,
-                                   on_delete=models.CASCADE)
-    is_author_reply = models.BooleanField(default=False)
+                                   on_delete=models.CASCADE, help_text=US_NOTICE)
     in_reply_to_comment = models.ForeignKey('self', blank=True, null=True,
-                                            related_name="nested_comments",
-                                            on_delete=models.CASCADE)
+                                            related_name="nested_comments_old",
+                                            on_delete=models.CASCADE, help_text=US_NOTICE)
     in_reply_to_report = models.ForeignKey('submissions.Report', blank=True, null=True,
-                                           on_delete=models.CASCADE)
-    author = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE)
+                                           on_delete=models.CASCADE, help_text=US_NOTICE)
+    # -- End U/S
+
+    # Author info
+    is_author_reply = models.BooleanField(default=False)
+    author = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE,
+                               related_name='comments')
     anonymous = models.BooleanField(default=False, verbose_name='Publish anonymously')
+
     # Categories:
     is_cor = models.BooleanField(default=False, verbose_name='correction/erratum')
     is_rem = models.BooleanField(default=False, verbose_name='remark')
@@ -46,27 +72,74 @@ class Comment(TimeStampedModel):
     is_lit = models.BooleanField(default=False, verbose_name='pointer to related literature')
     is_sug = models.BooleanField(default=False, verbose_name='suggestion for further work')
     comment_text = models.TextField()
-    remarks_for_editors = models.TextField(default='', blank=True,
+    remarks_for_editors = models.TextField(blank=True,
                                            verbose_name='optional remarks for the Editors only')
-    date_submitted = models.DateTimeField('date submitted')
+    date_submitted = models.DateTimeField('date submitted', default=timezone.now)
     # Opinions
     nr_A = models.PositiveIntegerField(default=0)
-    in_agreement = models.ManyToManyField(Contributor, related_name='in_agreement', blank=True)
+    in_agreement = models.ManyToManyField('scipost.Contributor', related_name='in_agreement',
+                                          blank=True)
     nr_N = models.PositiveIntegerField(default=0)
-    in_notsure = models.ManyToManyField(Contributor, related_name='in_notsure', blank=True)
+    in_notsure = models.ManyToManyField('scipost.Contributor', related_name='in_notsure',
+                                        blank=True)
     nr_D = models.PositiveIntegerField(default=0)
-    in_disagreement = models.ManyToManyField(
-        Contributor,
-        related_name='in_disagreement',
-        blank=True
-    )
+    in_disagreement = models.ManyToManyField('scipost.Contributor', related_name='in_disagreement',
+                                             blank=True)
+
+    objects = CommentQuerySet.as_manager()
 
-    objects = CommentManager()
+    class Meta:
+        permissions = (
+            ('can_vet_comments', 'Can vet submitted Comments'),
+        )
 
     def __str__(self):
         return ('by ' + self.author.user.first_name + ' ' + self.author.user.last_name +
                 ' on ' + self.date_submitted.strftime('%Y-%m-%d') + ', ' + self.comment_text[:30])
 
+    @property
+    def title(self):
+        """
+        This property is (mainly) used to let Comments get the title of the Submission without
+        annoying logic.
+        """
+        try:
+            return self.content_object.title
+        except:
+            return self.content_type
+
+    @cached_property
+    def core_content_object(self):
+        # Import here due to circular import errors
+        from commentaries.models import Commentary
+        from submissions.models import Submission, Report
+        from theses.models import ThesisLink
+
+        to_object = self.content_object
+        while True:
+            if (isinstance(to_object, Submission) or isinstance(to_object, Commentary) or
+               isinstance(to_object, ThesisLink)):
+                return to_object
+            elif isinstance(to_object, Report):
+                return to_object.submission
+            elif isinstance(to_object, Comment):
+                # Nested Comment.
+                to_object = to_object.content_object
+            else:
+                raise Exception
+
+    def get_absolute_url(self):
+        return self.content_object.get_absolute_url().split('#')[0] + '#comment_id' + str(self.id)
+
+    def grant_permissions(self):
+        # Import here due to circular import errors
+        from submissions.models import Submission
+
+        to_object = self.core_content_object
+        if isinstance(to_object, Submission):
+            # Add permissions for EIC only, the Vetting-group already has it!
+            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!!!'''
         if not self.anonymous:
diff --git a/comments/templates/comments/_add_comment_form.html b/comments/templates/comments/_add_comment_form.html
index aa5a8bd0abe0f8b1d1b5c64899c88de47f3f9552..b3a51a16b34e172a2155dfb7ff6031e318a541e1 100644
--- a/comments/templates/comments/_add_comment_form.html
+++ b/comments/templates/comments/_add_comment_form.html
@@ -1,34 +1,62 @@
-<script>
-  $(document).ready(function(){
+{% load bootstrap %}
 
-    var comment_text_input = $("#id_comment_text");
+<script>
+    $(document).ready(function(){
+        var comment_text_input = $("#id_comment_text");
 
-    function set_comment_text(value) {
-      $("#preview-comment_text").text(value)
-    }
-    set_comment_text(comment_text_input.val())
+        comment_text_input.on('keyup', function(){
+            var new_text = $(this).val()
+            $("#preview-comment_text").text(new_text)
+            MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
+        }).trigger('keyup')
+    });
+</script>
 
-    comment_text_input.keyup(function(){
-      var new_text = $(this).val()
-      set_comment_text(new_text)
-      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
-    })
+<form enctype="multipart/form-data" action="{{url}}" method="post">
+      {% csrf_token %}
+      <div class="row">
+          <div class="col-md-9">
+              {{form.comment_text|bootstrap:'12,12'}}
+              <p>
+                  In your comment, you can use LaTeX \$...\$ for in-text equations or \ [ ... \ ] for on-line equations.
+              </p>
+              <p id="goodCommenter"><em>
+                  Be professional. Only serious and meaningful comments will be vetted through.
+              </em></p>
+          </div>
+          <div class="col-md-3 radio-list">
+              <label>Specify categorization(s):</label>
+              {{form.is_cor|bootstrap}}
+              {{form.is_rem|bootstrap}}
+              {{form.is_que|bootstrap}}
+              {{form.is_ans|bootstrap}}
+              {{form.is_obj|bootstrap}}
+              {{form.is_rep|bootstrap}}
+              {{form.is_val|bootstrap}}
+              {{form.is_lit|bootstrap}}
+              {{form.is_sug|bootstrap}}
+          </div>
+      </div>
 
-  });
-</script>
+      <div class="row">
+          <div class="col-md-9">
+              {{form.remarks_for_editors|bootstrap:'12,12'}}
+          </div>
+          <div class="col-md-3">
+              {{form.file_attachment|bootstrap:'12,12'}}
+          </div>
+      </div>
 
-<div class="row">
-    <div class="col-12">
-        <form enctype="multipart/form-data" action="{{url}}" method="post">
-            {% csrf_token %}
-            {% load crispy_forms_tags %}
-            {% crispy form %}
-        </form>
-    </div>
-</div>
+      <div class="row">
+          <div class="col-12">
+              <input type="submit" name="submit" value="Submit your Comment for vetting" class="btn btn-primary" id="submit-id-submit">
+              <p class="mt-2" id="goodCommenter"><i>By clicking on Submit, you agree with the <a target="_blank" href="{% url 'scipost:terms_and_conditions' %}">Terms and Conditions</a>.</i></p>
+          </div>
+      </div>
+</form>
 
 <div class="row">
-    <div class="col-md-10">
+    <div class="col-md-9">
         <h3>Preview of your comment:</h3>
         <p id="preview-comment_text"></p>
     </div>
diff --git a/comments/templates/comments/_comment_card_content.html b/comments/templates/comments/_comment_card_content.html
index 0d94fd1d473725515db46c4f399e995708667235..c6788a79a355818dc3e31f711bdda0027efcdeaf 100644
--- a/comments/templates/comments/_comment_card_content.html
+++ b/comments/templates/comments/_comment_card_content.html
@@ -1,33 +1,20 @@
 <div class="card-block card-comment">
     {% block card_block_header %}{% endblock %}
-    <p class="card-text pb-1">
+    <p class="card-text">
+        <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a>:
 
-        <a href="{% if comment.get_author %}{% url 'scipost:contributor_info' comment.get_author.id %}{% else %}javascript:;{% endif %}">{{comment.get_author_str}}</a><span class="text-blue">:</span>
+        <a href="{{comment.get_absolute_url}">
+            "{{comment.comment_text|slice:'30'}}{% if comment.comment_text|length > 30 %}...{% endif %}"
+        </a>
+        </p><p class="card-text pl-md-3">
+        in {{comment.content_type|capfirst}} on <a href="{{comment.content_object.get_absolute_url}}" class="pubtitleli">{{comment.title}}</a>
 
-        {% if comment.submission %}
-            <a href="{% url 'submissions:submission' comment.submission.arxiv_identifier_w_vn_nr %}#comment_id{{comment.id}}">
-                "{{comment.comment_text|slice:'50'}}{% if comment.comment_text|length > 50 %}...{% endif %}"
-            </a>
-            </p>
-            <p class="card-text pl-md-4 pb-1">
-                in submission on <a href="{% url 'submissions:submission' comment.submission.arxiv_identifier_w_vn_nr %}" class="pubtitleli">{{comment.submission.title}}</a>
-                <span class="text-muted">by {{comment.submission.author_list}}</span>
-        {% elif comment.commentary %}
-            <a href="{% url 'commentaries:commentary' comment.commentary.arxiv_or_DOI_string %}#comment_id{{comment.id}}">
-                "{{comment.comment_text|slice:'50'}}{% if comment.comment_text|length > 50 %}...{% endif %}"
-            </a>
-            </p>
-            <p class="card-text pl-md-4 pb-1">
-                in commentary on <a href="{% url 'commentaries:commentary' comment.commentary.arxiv_or_DOI_string %}" class="pubtitleli">{{comment.commentary.pub_title}}</a>
-                <span class="text-muted">by {{comment.commentary.author_list}}</span>
-        {% elif comment.thesislink %}
-            <a href="{% url 'theses:thesis' comment.thesislink.id %}#comment_id{{comment.id}}">
-                "{{comment.comment_text|slice:'50'}}{% if comment.comment_text|length > 50 %}...{% endif %}"
-            </a>
-            </p>
-            <p class="card-text pl-md-4 pb-1">
-                in thesislink on <a href="{% url 'theses:thesis' comment.thesislink.id %}" class="pubtitleli">{{comment.thesislink.title}}</a>
-                <span class="text-muted">by {{ comment.thesislink.author }}</span>
+        {% if comment.content_object.author_list %}
+            {% comment %}
+                Using 'by xxx' on non-submission comments here would be ambigious. Does the `by xxx` apply to the
+                other object (eg. Report), or the Submission, the Comment, etc?
+            {% endcomment %}
+            <span class="text-muted">by {{comment.content_object.author_list}}</span>
         {% endif %}
-        </p>
+    </p>
 </div>
diff --git a/comments/templates/comments/_comment_card_extended_for_author.html b/comments/templates/comments/_comment_card_extended_for_author.html
new file mode 100644
index 0000000000000000000000000000000000000000..aaac79e90846156ed8c28b7b195aad7bd4921aef
--- /dev/null
+++ b/comments/templates/comments/_comment_card_extended_for_author.html
@@ -0,0 +1,16 @@
+<div class="card-block card-comment">
+    <div class="mb-4 mt-2">
+        <div class="d-inline-block mr-1">Nr {{comment.id}}</div>
+        {% include 'comments/_comment_voting_summary.html' with comment=comment class='small' %}
+    </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>
+
+    {% comment %}
+        Using 'by xxx' on non-submission comments here would be ambigious. Does the `by xxx` apply to the
+        other object (eg. Report), or the Submission, the Comment, etc?
+    {% endcomment %}
+    <p class="card-text text-muted">Comment submitted {{comment.date_submitted}}</p>
+    <p class="card-text">Status: <span class="{% if comment.status == 1 %} text-success{% elif comment.status == 0 %} text-danger{% endif %}">{{comment.get_status_display}}</span></p>
+</div>
diff --git a/comments/templates/comments/_comment_categories.html b/comments/templates/comments/_comment_categories.html
index fec5707adee9e21640e36ce5c4d8208df2ee2893..e848c6632b726cbb6c94cc1db013cefb6ac53f19 100644
--- a/comments/templates/comments/_comment_categories.html
+++ b/comments/templates/comments/_comment_categories.html
@@ -1,30 +1,34 @@
-<div class="btn-group category-group {{class}}">
-    <label class="btn btn-secondary name">Category:</label>
-    {% if comment.is_rem %}
-        <label class="btn btn-secondary"><span class="inner">remark</spin></label>
-    {% endif %}
-    {% if comment.is_que %}
-        <label class="btn btn-secondary"><span class="inner">question</spin></label>
-    {% endif %}
-    {% if comment.is_ans %}
-        <label class="btn btn-secondary"><span class="inner">answer to question</spin></label>
-    {% endif %}
-    {% if comment.is_obj %}
-        <label class="btn btn-secondary"><span class="inner">objection</spin></label>
-    {% endif %}
-    {% if comment.is_rep %}
-        <label class="btn btn-secondary"><span class="inner">reply to objection</spin></label>
-    {% endif %}
-    {% if comment.is_cor %}
-        <label class="btn btn-secondary"><span class="inner">correction</spin></label>
-    {% endif %}
-    {% if comment.is_val %}
-        <label class="btn btn-secondary"><span class="inner">validation or rederivation</spin></label>
-    {% endif %}
-    {% if comment.is_lit %}
-        <label class="btn btn-secondary"><span class="inner">pointer to related literature</spin></label>
-    {% endif %}
-    {% if comment.is_sug %}
-        <label class="btn btn-secondary"><span class="inner">suggestion for further work</spin></label>
-    {% endif %}
-</div>
+{% load comment_extras %}
+
+{% if comment|has_category %}
+    <div class="btn-group category-group mr-2">
+        <label class="btn btn-secondary name">Category:</label>
+        {% if comment.is_rem %}
+            <label class="btn btn-secondary"><span class="inner">remark</spin></label>
+        {% endif %}
+        {% if comment.is_que %}
+            <label class="btn btn-secondary"><span class="inner">question</spin></label>
+        {% endif %}
+        {% if comment.is_ans %}
+            <label class="btn btn-secondary"><span class="inner">answer to question</spin></label>
+        {% endif %}
+        {% if comment.is_obj %}
+            <label class="btn btn-secondary"><span class="inner">objection</spin></label>
+        {% endif %}
+        {% if comment.is_rep %}
+            <label class="btn btn-secondary"><span class="inner">reply to objection</spin></label>
+        {% endif %}
+        {% if comment.is_cor %}
+            <label class="btn btn-secondary"><span class="inner">correction</spin></label>
+        {% endif %}
+        {% if comment.is_val %}
+            <label class="btn btn-secondary"><span class="inner">validation or rederivation</spin></label>
+        {% endif %}
+        {% if comment.is_lit %}
+            <label class="btn btn-secondary"><span class="inner">pointer to related literature</spin></label>
+        {% endif %}
+        {% if comment.is_sug %}
+            <label class="btn btn-secondary"><span class="inner">suggestion for further work</spin></label>
+        {% endif %}
+    </div>
+{% endif %}
diff --git a/comments/templates/comments/_comment_identifier.html b/comments/templates/comments/_comment_identifier.html
index f30c460f3925344561cf1272f2c3c705523c92c9..5e668b933aefc737db21a22149daf829a8594fce 100644
--- a/comments/templates/comments/_comment_identifier.html
+++ b/comments/templates/comments/_comment_identifier.html
@@ -1,31 +1,23 @@
+{% load comment_extras %}
+
 <div class="commentid" id="comment_id{{comment.id}}">
     <h3>
         {% if comment.is_author_reply %}Author{% endif %}
 
-        {% block comment_author %}
-            {% if not comment.anonymous %}
-                <a href="{% url 'scipost:contributor_info' comment.get_author.id  %}">{{comment.get_author_str}}</a>
-            {% else %}
-                Anonymous
-            {% endif %}
-        {% endblock comment_author %}
+        <a href="{{comment.author.get_absolute_url}}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a>
         on {{comment.date_submitted|date:'Y-m-d'}}
     </h3>
-    {% if comment.in_reply_to_comment or comment.in_reply_to_report %}
-        <h4>
-            {% if comment.in_reply_to_comment %}
-                (in reply to <a href="#comment_id{{comment.in_reply_to_comment.id}}">{{comment.in_reply_to_comment.comment.get_author_str}}</a> on {{comment.in_reply_to_comment.date_submitted|date:'Y-m-d'}})
-            {% elif comment.in_reply_to_report %}
-                (in reply to <a href="#report_id{{comment.in_reply_to_report.id}}">
 
-                {% if not comment.in_reply_to_report.anonymous %}
-                    {{comment.in_reply_to_report.get_author_str}}
-                {% else %}
-                    Report {{comment.in_reply_to_report.id}}
-                {% endif %}
+    {% if comment|is_reply_to_comment %}
+        (in reply to <a href="{{comment.get_absolute_url}}">{{comment.content_object.author.user.first_name}} {{comment.content_object.author.user.last_name}}</a> on {{comment.content_object.date_submitted|date:'Y-m-d'}})
+    {% elif comment|is_reply_to_report %}
+        (in reply to <a href="{{comment.get_absolute_url}}">
+
+        Report {{comment.content_object.report_nr}}
+        {% if not comment.content_object.anonymous %}
+            by {{comment.content_object.author.user.first_name}} {{comment.content_object.author.user.last_name}}
+        {% endif %}
 
-                </a> on {{comment.in_reply_to_report.date_submitted|date:'Y-m-d'}})
-            {% endif %}
-        </h4>
+        </a> on {{comment.content_object.date_submitted|date:'Y-m-d'}})
     {% endif %}
 </div>
diff --git a/comments/templates/comments/_comment_identifier_vetting.html b/comments/templates/comments/_comment_identifier_vetting.html
deleted file mode 100644
index edf903c7eac54853e71e69c30c5640d01262bf42..0000000000000000000000000000000000000000
--- a/comments/templates/comments/_comment_identifier_vetting.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{% extends 'comments/_comment_identifier.html' %}
-
-{% comment %}
-
-    Be careful using this template!!!
-    It overwrites the anonymity of the writer!
-
-{% endcomment %}
-
-{% block comment_author %}
-    <a href="{% url 'scipost:contributor_info' comment.author.id %}">{{comment.author.user.first_name}} {{comment.author.user.last_name}}</a>
-{% endblock comment_author %}
diff --git a/comments/templates/comments/_comment_tex_template.html b/comments/templates/comments/_comment_tex_template.html
new file mode 100644
index 0000000000000000000000000000000000000000..cb39aa0d3c78f50d5fe9f2d75f618abadc9ce8a5
--- /dev/null
+++ b/comments/templates/comments/_comment_tex_template.html
@@ -0,0 +1,11 @@
+{% spaceless %}
+Received {{comment.date_submitted|date:'d-m-Y'}}\ \\
+{% if comment.file_attachment %}- \textit{This {% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} has an Attachment, please download it online.}\ \\{% endif %}\ \\{{comment.comment_text}}
+{% 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}} }
+
+    \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}} }
+    {% include 'comments/_comment_tex_template.html' with comment=subcomment %}
+{% endfor %}
diff --git a/comments/templates/comments/_comment_voting_form.html b/comments/templates/comments/_comment_voting_form.html
index 1563284d7cfd90111e4864b04809f642d3d05b47..b1b8fe06b242a5879ea229b93baeff599bac3bd7 100644
--- a/comments/templates/comments/_comment_voting_form.html
+++ b/comments/templates/comments/_comment_voting_form.html
@@ -1,3 +1,4 @@
+
 {% if user.is_authenticated and perms.scipost.can_express_opinion_on_comments %}
     {% if user.contributor != comment.author %}
     <div class="btn-group voting-group {{class}}">
diff --git a/comments/templates/comments/_single_comment.html b/comments/templates/comments/_single_comment.html
index 1eaaf85a016bf09f61c8b349bd7339cbae35e843..0759c42ee017a67d2bbf6d345f140b5baf7b29aa 100644
--- a/comments/templates/comments/_single_comment.html
+++ b/comments/templates/comments/_single_comment.html
@@ -2,53 +2,40 @@
 {% load filename %}
 {% load file_extentions %}
 
-<div class="row">
-    <div class="col-12">
-        <div class="comment" id="comment_id{{comment.id}}">
-
-            <div class="row">
-                <div class="col-12">
-                    {% include 'comments/_comment_identifier.html' with comment=comment %}
-
-                    {% include 'comments/_comment_categories.html' with comment=comment class='mr-2' %}
-
-                    {% include 'comments/_comment_voting_form.html' with comment=comment perms=perms user=user %}
-                </div>
-            </div>
-
-
-            <div class="row">
-                <div class="col-12">
-                    <p>
-                        {{ comment.comment_text|linebreaks }}
-
-                        {% if comment.file_attachment %}
-                            <h3>Attachment:</h3>
-                            <p>
-                                <a target="_blank" href="{{ comment.file_attachment.url }}">
-                                    {% if comment.file_attachment|is_image %}
-                                        <img class="attachment attachment-comment" src="{{ comment.file_attachment.url }}">
-                                    {% else %}
-                                        {{ comment.file_attachment|filename }}<br><small>{{ comment.file_attachment.size|filesizeformat }}</small>
-                                    {% endif %}
-                                </a>
-                            </p>
-                        {% endif %}
-                    </p>
-                    {% if user|is_in_group:'Editorial College' or user|is_in_group:'Editorial Administrators' %}
-                        {% if comment.remarks_for_editors %}
-                            <h3>Remarks for editors:</h3>
-                            <p>{{ comment.remarks_for_editors|linebreaks }}</p>
-                        {% endif %}
-                    {% endif %}
-                </div>
-            </div>
+<div class="comment">
+
+    {% include 'comments/_comment_identifier.html' with comment=comment %}
+
+    {% include 'comments/_comment_categories.html' with comment=comment %}
 
-            {% for reply in comment.nested_comments.vetted %}
-                {% include 'comments/_single_comment.html' with comment=reply perms=perms user=user %}
-            {% endfor %}
+    {% include 'comments/_comment_voting_form.html' with comment=comment perms=perms user=user %}
 
-            {% block comment_footer %}{% endblock %}
-        </div>
-    </div>
+    <p class="my-3 pb-2">
+        {{ comment.comment_text|linebreaksbr }}
+
+        {% if comment.file_attachment %}
+            <h3>Attachment:</h3>
+            <p>
+                <a target="_blank" href="{{ comment.file_attachment.url }}">
+                    {% if comment.file_attachment|is_image %}
+                        <img class="attachment attachment-comment" src="{{ comment.file_attachment.url }}">
+                    {% else %}
+                        {{ comment.file_attachment|filename }}<br><small>{{ comment.file_attachment.size|filesizeformat }}</small>
+                    {% endif %}
+                </a>
+            </p>
+        {% endif %}
+    </p>
+    {% if user|is_in_group:'Editorial College' or user|is_in_group:'Editorial Administrators' %}
+        {% if comment.remarks_for_editors %}
+            <h3>Remarks for editors:</h3>
+            <p>{{ comment.remarks_for_editors|linebreaks }}</p>
+        {% endif %}
+    {% endif %}
+
+    {% for reply in comment.nested_comments.vetted %}
+        {% include 'comments/_single_comment.html' with comment=reply perms=perms user=user %}
+    {% endfor %}
+
+    {% block comment_footer %}{% endblock %}
 </div>
diff --git a/comments/templates/comments/_single_comment_with_link.html b/comments/templates/comments/_single_comment_with_link.html
index 06cf9a4b95f2bb72bfe3d90b5ed87eac4b8e0b73..552db102a5a95357cd548a96b5b4cb2d3419bacb 100644
--- a/comments/templates/comments/_single_comment_with_link.html
+++ b/comments/templates/comments/_single_comment_with_link.html
@@ -3,10 +3,6 @@
 {% block comment_footer %}
     {% if user.is_authenticated and perms.scipost.can_submit_comments %}
         <hr class="small">
-        <div class="row">
-            <div class="col-12">
-                <h3><a href="{% url 'comments:reply_to_comment' comment_id=comment.id %}">Reply to this comment</a></h3>
-            </div>
-        </div>
+        <h3 class="mb-3"><a href="{% url 'comments:reply_to_comment' comment_id=comment.id %}">Reply to this comment</a></h3>
     {% endif %}
 {% endblock %}
diff --git a/comments/templates/comments/_vet_comment_form.html b/comments/templates/comments/_vet_comment_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..204b12d7017b92b141c0e0aeb8c04271136f0e6b
--- /dev/null
+++ b/comments/templates/comments/_vet_comment_form.html
@@ -0,0 +1,50 @@
+{% load bootstrap %}
+{% load filename %}
+{% load file_extentions %}
+{% load comment_extras %}
+
+<div class="card card-vetting">
+    <div class="card-header">
+        <h2>From {{comment.core_content_object|get_core_content_type|capfirst}} (<a href="{{comment.get_absolute_url}}" target="_blank">link</a>)</h2>
+        {% get_summary_template comment.core_content_object %}
+    </div>
+    <div class="card-block">
+
+        <h2 class="card-title">The Comment to be vetted:</h2>
+
+        <div class="row">
+            <div class="col-md-6">
+                {% include 'comments/_comment_identifier.html' with comment=comment %}
+                <hr class="small">
+
+                <h3>Comment text:</h3>
+                <p>{{ comment.comment_text }}</p>
+
+                {% if comment.file_attachment %}
+                    <h3>Attachment:</h3>
+                    <p>
+                        <a target="_blank" href="{{ comment.file_attachment.url }}">
+                            {% if comment.file_attachment|is_image %}
+                                <img class="attachment attachment-comment" src="{{ comment.file_attachment.url }}">
+                            {% else %}
+                                {{ comment.file_attachment|filename }}<br><small>{{ comment.file_attachment.size|filesizeformat }}</small>
+                            {% endif %}
+                        </a>
+                    </p>
+                {% endif %}
+
+                {% if comment.remarks_for_editors %}
+                    <h3>Remarks for Editors only:</h3>
+                    <p>{{ comment.remarks_for_editors }}</p>
+                {% endif %}
+            </div>
+            <div class="col-md-6">
+                <form action="{% url 'comments:vet_submitted_comment' comment_id=comment.id %}" method="post">
+                    {% csrf_token %}
+                    {{ form|bootstrap }}
+                    <input class="btn btn-primary" type="submit" value="Submit" />
+                </form>
+            </div>
+        </div>
+    </div>
+</div>
diff --git a/comments/templates/comments/new_comment.html b/comments/templates/comments/new_comment.html
index 4aedb638ec55c389f72c29ca872dd1cbb1aa6609..55d670be89d662dbad2d39a6f85bf65315bd7c63 100644
--- a/comments/templates/comments/new_comment.html
+++ b/comments/templates/comments/new_comment.html
@@ -2,83 +2,11 @@
 
 {% if user.is_authenticated and open_for_commenting and perms.scipost.can_submit_comments %}
 
-<script>
-  $(document).ready(function(){
-
-    var comment_text_input = $("#id_comment_text");
-
-    function set_comment_text(value) {
-      $("#preview-comment_text").text(value)
-    }
-    set_comment_text(comment_text_input.val())
-
-    comment_text_input.keyup(function(){
-      var new_text = $(this).val()
-      set_comment_text(new_text)
-      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
-    })
-
-  });
-</script>
-
 <hr>
 
-<div class="row" id="contribute_comment">
-    <div class="col-12">
-        <h2 class="highlight">Contribute a Comment:</h2>
-    </div>
-</div>
-<div class="row">
-    <div class="col-12">
-        <form enctype="multipart/form-data"
-            action="{% url 'comments:new_comment' object_id=object_id type_of_object=type_of_object %}"
-            method="post">
-          {% csrf_token %}
-          <div class="row">
-              <div class="col-md-9">
-                  {{form.comment_text|bootstrap:'12,12'}}
-                  <p>
-                      In your comment, you can use LaTeX \$...\$ for in-text equations or \ [ ... \ ] for on-line equations.
-                  </p>
-                  <p id="goodCommenter"><em>
-                      Be professional. Only serious and meaningful comments will be vetted through.
-                  </em></p>
-              </div>
-              <div class="col-md-3 radio-list">
-                  <label>Specify categorization(s):</label>
-                  {{form.is_cor|bootstrap}}
-                  {{form.is_rem|bootstrap}}
-                  {{form.is_que|bootstrap}}
-                  {{form.is_ans|bootstrap}}
-                  {{form.is_obj|bootstrap}}
-                  {{form.is_rep|bootstrap}}
-                  {{form.is_val|bootstrap}}
-                  {{form.is_lit|bootstrap}}
-                  {{form.is_sug|bootstrap}}
-              </div>
-          </div>
-
-          <div class="row">
-              <div class="col-md-9">
-                  {{form.remarks_for_editors|bootstrap:'12,12'}}
-              </div>
-              <div class="col-md-3">
-                  {{form.file_attachment|bootstrap:'12,12'}}
-              </div>
-          </div>
+<h2 class="highlight" id="contribute_comment">Contribute a Comment:</h2>
 
-          <div class="row">
-              <div class="col-12">
-                  <input type="submit" name="submit" value="Submit your Comment for vetting" class="btn btn-primary" id="submit-id-submit">
-                  <p class="mt-2" id="goodCommenter"><i>By clicking on Submit, you agree with the <a target="_blank" href="{% url 'scipost:terms_and_conditions' %}">Terms and Conditions</a>.</i></p>
-              </div>
-          </div>
-        </form>
-    </div>
-    <div class="col-12">
-        <h3>Preview of your comment:</h3>
-        <p id="preview-comment_text"></p>
-    </div>
-</div>
+{% url 'comments:new_comment' object_id=object_id type_of_object=type_of_object as url %}
+{% include 'comments/_add_comment_form.html' with form=form url=url %}
 
 {% endif %}
diff --git a/comments/templates/comments/reply_to_comment.html b/comments/templates/comments/reply_to_comment.html
index 3937e5d0051a557def52eb7728998e2b5f0ccbf3..26a545ddbe4c0b0c1b984b9dc77a18166e9999ba 100644
--- a/comments/templates/comments/reply_to_comment.html
+++ b/comments/templates/comments/reply_to_comment.html
@@ -1,5 +1,7 @@
 {% extends 'scipost/base.html' %}
 
+{% load comment_extras %}
+
 {% block pagetitle %}: reply to comment{% endblock pagetitle %}
 
 {% block content %}
@@ -13,25 +15,8 @@
 
     <div class="row">
         <div class="col-12">
-            {% if comment.commentary %}
-                <h2>The Commentary concerned:</h2>
-                {% include 'commentaries/_commentary_summary.html' with commentary=comment.commentary %}
-
-                <h3 class="mt-3">Abstract:</h3>
-                <p>{{ comment.commentary.pub_abstract }}</p>
-            {% endif %}
-
-            {% if comment.submission %}
-                <h2>The Submission concerned:</h2>
-
-                {% include 'submissions/_submission_summary.html' with submission=comment.submission %}
-
-            {% endif %}
-
-            {% if comment.thesislink %}
-                <h2>The Thesis concerned:</h2>
-                {% include "theses/_thesislink_information.html" with thesislink=comment.thesislink %}
-            {% endif %}
+            <h2>The {{comment.core_content_object|get_core_content_type|capfirst}} concerned:</h2>
+            {% get_summary_template comment.core_content_object %}
         </div>
     </div>
 
@@ -49,7 +34,7 @@
 
                 {% include 'comments/_comment_voting_summary.html' with comment=comment %}
 
-                <p>{{ comment.comment_text|linebreaks }}</p>
+                <p>{{ comment.comment_text|linebreaksbr }}</p>
             </div>
         </div>
     </div>
diff --git a/comments/templates/comments/reply_to_report.html b/comments/templates/comments/reply_to_report.html
index 348d82701826f73a80777e21357ef24fbc042db9..d796bb1210d20cd90057e987d2eb59a5c9755c63 100644
--- a/comments/templates/comments/reply_to_report.html
+++ b/comments/templates/comments/reply_to_report.html
@@ -14,7 +14,7 @@
     <div class="row">
         <div class="col-12">
             {% if not is_author %}
-                <h2>(you are not identified as an author of this Submission; if you are, you can claim authorship on your Personal Page)</h2>
+                <h2>You are not identified as an author of this Submission; if you are, you can claim authorship on your Personal Page.</h2>
             {% else %}
                 <h2>The Submission concerned:</h2>
 
diff --git a/comments/templates/comments/submit_comment_form.html b/comments/templates/comments/submit_comment_form.html
deleted file mode 100644
index 8251b3daf4faa657f5d34a537139069dbc4c61c1..0000000000000000000000000000000000000000
--- a/comments/templates/comments/submit_comment_form.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{% load bootstrap %}
-
-{# This template should eventually be used to create a single template for all comment forms ! #}
-
-
-
-{% for field in form %}
-    {% include 'tags/bootstrap/field.html' with field=field %}
-{% endfor %}
diff --git a/comments/templates/comments/vet_submitted_comment.html b/comments/templates/comments/vet_submitted_comment.html
new file mode 100644
index 0000000000000000000000000000000000000000..3cfe9f3b2b68106b590acc3c8773477a2301bb1b
--- /dev/null
+++ b/comments/templates/comments/vet_submitted_comment.html
@@ -0,0 +1,19 @@
+{% extends 'scipost/base.html' %}
+
+{% load bootstrap %}
+{% load filename %}
+{% load file_extentions %}
+
+{% block pagetitle %}: vet comments{% endblock pagetitle %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">SciPost Comment to vet:</h1>
+    </div>
+</div>
+
+{% include 'comments/_vet_comment_form.html' with comment=comment form=form %}
+
+{% endblock content %}
diff --git a/comments/templates/comments/vet_submitted_comments_list.html b/comments/templates/comments/vet_submitted_comments_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..d58676554085260383dffe0c957a9578d7821357
--- /dev/null
+++ b/comments/templates/comments/vet_submitted_comments_list.html
@@ -0,0 +1,29 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: vet comments{% endblock pagetitle %}
+
+{% block content %}
+
+{% if not comments_to_vet %}
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">There are no comments for you to vet.</h1>
+    </div>
+</div>
+{% else %}
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">SciPost Comments to vet:</h1>
+    </div>
+</div>
+
+<div class="row">
+    <div class="col-12">
+        {% for comment_to_vet in comments_to_vet %}
+            {% include 'comments/_vet_comment_form.html' with comment=comment_to_vet form=form %}
+        {% endfor %}
+    </div>
+</div>
+{% endif %}
+
+{% endblock content %}
diff --git a/theses/templatetags/__init__.py b/comments/templatetags/__init__.py
similarity index 100%
rename from theses/templatetags/__init__.py
rename to comments/templatetags/__init__.py
diff --git a/comments/templatetags/comment_extras.py b/comments/templatetags/comment_extras.py
new file mode 100644
index 0000000000000000000000000000000000000000..60d6707af00baeb81ce772d30f6437a83e2f5cf2
--- /dev/null
+++ b/comments/templatetags/comment_extras.py
@@ -0,0 +1,92 @@
+from django import template
+from django.utils.safestring import mark_safe
+
+from ..models import Comment
+
+from commentaries.models import Commentary
+from submissions.models import Submission, Report
+from theses.models import ThesisLink
+
+register = template.Library()
+
+
+class CommentTemplateNode(template.Node):
+    """
+    This template node accepts an object being a Submission, Commentary or ThesisLink
+    and includes its summary page.
+    """
+    def __init__(self, content_object):
+        self.content_object = content_object
+
+    def render(self, context):
+        content_object = self.content_object.resolve(context)
+        if isinstance(content_object, Submission):
+            t = context.template.engine.get_template('submissions/_submission_summary_short.html')
+            return t.render(template.Context({'submission': content_object}))
+        elif isinstance(content_object, Commentary):
+            t = context.template.engine.get_template('commentaries/_commentary_summary.html')
+            return t.render(template.Context({'commentary': content_object}))
+        elif isinstance(content_object, ThesisLink):
+            t = context.template.engine.get_template('theses/_thesislink_information.html')
+            return t.render(template.Context({'thesislink': content_object}))
+        else:
+            raise template.TemplateSyntaxError(
+                "The instance type given as an argument is not supported.")
+
+
+@register.filter
+def get_core_content_type(content_object):
+    if isinstance(content_object, Submission):
+        return 'submission'
+    elif isinstance(content_object, Commentary):
+        return 'commentary'
+    elif isinstance(content_object, ThesisLink):
+        return 'thesislink'
+
+
+@register.tag
+def get_summary_template(parser, token):
+    """
+    This tag includes the summary template of the object, using `CommentTemplateNode`
+    to determine the template and its context.
+    """
+    try:
+        tag_name, content_object = token.split_contents()
+    except ValueError:
+        raise template.TemplateSyntaxError(
+            "get_summary_template tag requires exactly two arguments")
+    content_object = template.Variable(content_object)
+    return CommentTemplateNode(content_object)
+
+
+@register.filter
+def is_reply_to_comment(comment):
+    return isinstance(comment.content_object, Comment)
+
+
+@register.filter
+def is_reply_to_report(comment):
+    return isinstance(comment.content_object, Report)
+
+
+@register.filter
+def has_category(comment):
+    if comment.is_cor:
+        return True
+    elif comment.is_rem:
+        return True
+    elif comment.is_que:
+        return True
+    elif comment.is_ans:
+        return True
+    elif comment.is_obj:
+        return True
+    elif comment.is_rep:
+        return True
+    elif comment.is_val:
+        return True
+    elif comment.is_lit:
+        return True
+    elif comment.is_sug:
+        return True
+    return False
diff --git a/comments/test_views.py b/comments/test_views.py
index d80fea2bd5e779336dc0d3ce31a6e77f9ae23a91..c16e256953ec7be3ea87ce46c9e96f16763cb15c 100644
--- a/comments/test_views.py
+++ b/comments/test_views.py
@@ -1,8 +1,7 @@
 from django.test import TestCase, RequestFactory, Client
-from django.urls import reverse, reverse_lazy
-from django.contrib.auth.models import Group
+from django.urls import reverse
 from django.contrib.messages.storage.fallback import FallbackStorage
-from django.core.exceptions import PermissionDenied
+from django.http import Http404
 
 from scipost.factories import ContributorFactory
 from theses.factories import ThesisLinkFactory
@@ -20,6 +19,7 @@ from common.helpers.test import add_groups_and_permissions
 class TestNewComment(TestCase):
     def setUp(self):
         add_groups_and_permissions()
+        ContributorFactory.create_batch(5)
 
     def install_messages_middleware(self, request):
         # I don't know what the following three lines do, but they help make a RequestFactory
@@ -33,7 +33,7 @@ class TestNewComment(TestCase):
 
         contributor = ContributorFactory()
         thesislink = ThesisLinkFactory()
-        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        valid_comment_data = model_form_data(CommentFactory, CommentForm)
         target = reverse('comments:new_comment', kwargs={'object_id': thesislink.id, 'type_of_object': 'thesislink'})
 
         comment_count = Comment.objects.filter(author=contributor).count()
@@ -56,7 +56,7 @@ class TestNewComment(TestCase):
         submission = EICassignedSubmissionFactory()
         submission.open_for_commenting = True
         submission.save()
-        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        valid_comment_data = model_form_data(CommentFactory, CommentForm)
         target = reverse(
             'comments:new_comment',
             kwargs={'object_id': submission.id, 'type_of_object': 'submission'},
@@ -80,13 +80,12 @@ class TestNewComment(TestCase):
         )
         self.assertRedirects(response, expected_redirect_link)
 
-
     def test_submitting_comment_on_commentary_creates_comment_and_redirects(self):
         """ Valid Comment gets saved """
 
         contributor = ContributorFactory()
         commentary = UnpublishedVettedCommentaryFactory()
-        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        valid_comment_data = model_form_data(CommentFactory, CommentForm)
         target = reverse('comments:new_comment', kwargs={'object_id': commentary.id, 'type_of_object': 'commentary'})
 
         comment_count = Comment.objects.filter(author=contributor).count()
@@ -97,7 +96,7 @@ class TestNewComment(TestCase):
         request.user = contributor.user
         response = new_comment(request, object_id=commentary.id, type_of_object='commentary')
 
-        comment_count = commentary.comment_set.count()
+        comment_count = commentary.comments.count()
         self.assertEqual(comment_count, 1)
 
         response.client = Client()
@@ -105,13 +104,12 @@ class TestNewComment(TestCase):
             'commentaries:commentary', kwargs={'arxiv_or_DOI_string': commentary.arxiv_or_DOI_string})
         self.assertRedirects(response, expected_redirect_link)
 
-
     def test_submitting_comment_on_submission_that_is_not_open_for_commenting_should_be_impossible(self):
         contributor = ContributorFactory()
         submission = EICassignedSubmissionFactory()
         submission.open_for_commenting = False
         submission.save()
-        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        valid_comment_data = model_form_data(CommentFactory, CommentForm)
         target = reverse(
             'comments:new_comment',
             kwargs={'object_id': submission.id, 'type_of_object': 'submission'},
@@ -123,5 +121,5 @@ class TestNewComment(TestCase):
         request = RequestFactory().post(target, valid_comment_data)
         self.install_messages_middleware(request)
         request.user = contributor.user
-        with self.assertRaises(PermissionDenied):
-            response = new_comment(request, object_id=submission.id, type_of_object='submission')
+        with self.assertRaises(Http404):
+            new_comment(request, object_id=submission.id, type_of_object='submission')
diff --git a/comments/urls.py b/comments/urls.py
index 3d1747ee28e087ff4a52d0da5cd0a794032fc935..213fbd1ad0d6a5bcfaa152aaf878469adc2ed086 100644
--- a/comments/urls.py
+++ b/comments/urls.py
@@ -4,11 +4,15 @@ from . import views
 
 urlpatterns = [
     # Comments
-    url(r'^reply_to_comment/(?P<comment_id>[0-9]+)$', views.reply_to_comment, name='reply_to_comment'),
-    url(r'^reply_to_report/(?P<report_id>[0-9]+)$', views.reply_to_report, name='reply_to_report'),
-    url(r'^vet_submitted_comments$', views.vet_submitted_comments, name='vet_submitted_comments'),
-    url(r'^vet_submitted_comment_ack/(?P<comment_id>[0-9]+)$', views.vet_submitted_comment_ack, name='vet_submitted_comment_ack'),
-    url(r'^express_opinion/(?P<comment_id>[0-9]+)$', views.express_opinion, name='express_opinion'),
-    url(r'^express_opinion/(?P<comment_id>[0-9]+)/(?P<opinion>[AND])$', views.express_opinion, name='express_opinion'),
-    url(r'^new_comment/(?P<type_of_object>[a-z]+)/(?P<object_id>[0-9]+)$', views.new_comment, name='new_comment')
+    url(r'^reports/(?P<report_id>[0-9]+)/reply$', views.reply_to_report, name='reply_to_report'),
+    url(r'^vet_submitted$', views.vet_submitted_comments_list, name='vet_submitted_comments_list'),
+    url(r'^new/(?P<type_of_object>[a-z]+)/(?P<object_id>[0-9]+)$', views.new_comment,
+        name='new_comment'),
+    url(r'^(?P<comment_id>[0-9]+)/reply$', views.reply_to_comment, name='reply_to_comment'),
+    url(r'^(?P<comment_id>[0-9]+)/vet$', views.vet_submitted_comment,
+        name='vet_submitted_comment'),
+    url(r'^(?P<comment_id>[0-9]+)/express_opinion$', views.express_opinion,
+        name='express_opinion'),
+    url(r'^(?P<comment_id>[0-9]+)/express_opinion/(?P<opinion>[AND])$', views.express_opinion,
+        name='express_opinion'),
 ]
diff --git a/comments/utils.py b/comments/utils.py
index be461a1e031d8b08a64c784f055b11460e07b0ab..9fad691fe5fa29525817682fb275218d35171b35 100644
--- a/comments/utils.py
+++ b/comments/utils.py
@@ -1,7 +1,39 @@
 import os
 
+from common.utils import BaseMailUtil
+
 
 def validate_file_extention(value, 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
+
+
+class CommentUtils(BaseMailUtil):
+    mail_sender = 'comments@scipost.org'
+    mail_sender_title = 'The SciPost Team'
+
+    @classmethod
+    def email_comment_vet_accepted_to_author(cls):
+        """
+        Send mail after Comment is vetted: `Accept`
+
+        Requires loading:
+        comment -- Comment
+        """
+        cls._send_mail(cls, 'comment_vet_accepted',
+                       [cls._context['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`
+
+        Requires loading:
+        comment -- Comment
+        """
+        cls._send_mail(cls, 'comment_vet_rejected',
+                       [cls._context['comment'].author.user.email],
+                       'SciPost Comment rejected',
+                       extra_context={'email_response': email_response})
diff --git a/comments/views.py b/comments/views.py
index af5577b3316f4f7d4508ebf52bf1a2e244d9a760..fba5791ba8e8a1b212eee8660dc77d77b7f32bb0 100644
--- a/comments/views.py
+++ b/comments/views.py
@@ -1,18 +1,17 @@
 from django.utils import timezone
 from django.shortcuts import get_object_or_404, render, redirect
-from django.contrib.auth.decorators import permission_required
+from django.contrib.auth.decorators import permission_required, login_required
 from django.contrib import messages
-from django.core.mail import EmailMessage
 from django.core.urlresolvers import reverse
-from django.core.exceptions import PermissionDenied
-from django.http import HttpResponseRedirect, Http404
+from django.db import transaction
 
+from guardian.shortcuts import get_objects_for_user
 import strings
 
 from .models import Comment
 from .forms import CommentForm, VetCommentForm
+from .utils import CommentUtils
 
-from scipost.models import Contributor
 from theses.models import ThesisLink
 from submissions.utils import SubmissionUtils
 from submissions.models import Submission, Report
@@ -21,227 +20,129 @@ from commentaries.models import Commentary
 
 @permission_required('scipost.can_submit_comments', raise_exception=True)
 def new_comment(request, **kwargs):
-    if request.method == "POST":
-        form = CommentForm(request.POST)
-        if form.is_valid():
-            author = Contributor.objects.get(user=request.user)
-            object_id = int(kwargs["object_id"])
-            type_of_object = kwargs["type_of_object"]
-            new_comment = Comment(
-                author=author,
-                is_rem=form.cleaned_data['is_rem'],
-                is_que=form.cleaned_data['is_que'],
-                is_ans=form.cleaned_data['is_ans'],
-                is_obj=form.cleaned_data['is_obj'],
-                is_rep=form.cleaned_data['is_rep'],
-                is_val=form.cleaned_data['is_val'],
-                is_lit=form.cleaned_data['is_lit'],
-                is_sug=form.cleaned_data['is_sug'],
-                file_attachment=form.cleaned_data['file_attachment'],
-                comment_text=form.cleaned_data['comment_text'],
-                remarks_for_editors=form.cleaned_data['remarks_for_editors'],
-                date_submitted=timezone.now(),
-            )
-            if type_of_object == "thesislink":
-                thesislink = ThesisLink.objects.get(id=object_id)
-                if not thesislink.open_for_commenting:
-                    raise PermissionDenied
-                new_comment.thesislink = thesislink
-                redirect_link = reverse('theses:thesis', kwargs={"thesislink_id": thesislink.id})
-            elif type_of_object == "submission":
-                submission = Submission.objects.get(id=object_id)
-                if not submission.open_for_commenting:
-                    raise PermissionDenied
-                new_comment.submission = submission
-                redirect_link = reverse(
-                    'submissions:submission',
-                    kwargs={"arxiv_identifier_w_vn_nr": submission.arxiv_identifier_w_vn_nr}
-                )
-            elif type_of_object == "commentary":
-                commentary = Commentary.objects.get(id=object_id)
-                if not commentary.open_for_commenting:
-                    raise PermissionDenied
-                new_comment.commentary = commentary
-                redirect_link = reverse(
-                    'commentaries:commentary',
-                    kwargs={'arxiv_or_DOI_string': commentary.arxiv_or_DOI_string}
-                )
-
-            new_comment.save()
-            author.nr_comments = Comment.objects.filter(author=author).count()
-            author.save()
-            messages.add_message(
-                request, messages.SUCCESS, strings.acknowledge_submit_comment)
-            return redirect(redirect_link)
-    else:
-        # This view is only accessible by POST request
-        raise Http404
+    form = CommentForm(request.POST or None)
+    if form.is_valid():
+        object_id = int(kwargs["object_id"])
+        type_of_object = kwargs["type_of_object"]
 
+        if type_of_object == "thesislink":
+            _object = get_object_or_404(ThesisLink.objects.open_for_commenting(), id=object_id)
+        elif type_of_object == "submission":
+            _object = get_object_or_404(Submission.objects.open_for_commenting(), id=object_id)
+            _object.add_event_for_eic('A new comment has been added.')
+        elif type_of_object == "commentary":
+            _object = get_object_or_404(Commentary.objects.open_for_commenting(), id=object_id)
 
-@permission_required('scipost.can_vet_comments', raise_exception=True)
-def vet_submitted_comments(request):
-    contributor = Contributor.objects.get(user=request.user)
-    comments_to_vet = Comment.objects.filter(status=0).order_by('date_submitted')
-    form = VetCommentForm()
-    context = {'contributor': contributor, 'comments_to_vet': comments_to_vet, 'form': form}
-    return(render(request, 'comments/vet_submitted_comments.html', context))
+        new_comment = form.save(commit=False)
+        new_comment.author = request.user.contributor
+        new_comment.content_object = _object
+        new_comment.save()
+        new_comment.grant_permissions()
+
+        messages.success(request, strings.acknowledge_submit_comment)
+        return redirect(_object.get_absolute_url())
 
 
 @permission_required('scipost.can_vet_comments', raise_exception=True)
-def vet_submitted_comment_ack(request, comment_id):
-    if request.method == 'POST':
-        form = VetCommentForm(request.POST)
-        comment = Comment.objects.get(pk=comment_id)
-        if form.is_valid():
-            if form.cleaned_data['action_option'] == '1':
-                # accept the comment as is
-                comment.status = 1
-                comment.vetted_by = request.user.contributor
-                comment.save()
-                email_text = ('Dear ' + comment.author.get_title_display() + ' '
-                              + comment.author.user.last_name +
-                              ', \n\nThe Comment you have submitted, '
-                              'concerning publication with title ')
-                if comment.commentary is not None:
-                    email_text += (comment.commentary.pub_title + ' by '
-                                   + comment.commentary.author_list
-                                   + ' at Commentary Page https://scipost.org/commentary/'
-                                   + comment.commentary.arxiv_or_DOI_string)
-                    comment.commentary.latest_activity = timezone.now()
-                    comment.commentary.save()
-                elif comment.submission is not None:
-                    email_text += (comment.submission.title + ' by '
-                                   + comment.submission.author_list
-                                   + ' at Submission page https://scipost.org/submission/'
-                                   + comment.submission.arxiv_identifier_w_vn_nr)
-                    comment.submission.latest_activity = timezone.now()
-                    comment.submission.save()
-                    if not comment.is_author_reply:
-                        SubmissionUtils.load({'submission': comment.submission})
-                        SubmissionUtils.send_author_comment_received_email()
-                elif comment.thesislink is not None:
-                    email_text += (comment.thesislink.title + ' by ' + comment.thesislink.author +
-                                   ' at Thesis Link https://scipost.org/thesis/'
-                                   + str(comment.thesislink.id))
-                    comment.thesislink.latest_activity = timezone.now()
-                    comment.thesislink.save()
-                email_text += (', has been accepted and published online.' +
-                               '\n\nWe copy it below for your convenience.' +
-                               '\n\nThank you for your contribution, \nThe SciPost Team.' +
-                               '\n\n' + comment.comment_text)
-                emailmessage = EmailMessage('SciPost Comment published', email_text,
-                                            'comments@scipost.org',
-                                            [comment.author.user.email],
-                                            ['comments@scipost.org'],
-                                            reply_to=['comments@scipost.org'])
-                emailmessage.send(fail_silently=False)
-            elif form.cleaned_data['action_option'] == '2':
-                # the comment request is simply rejected
-                comment.status = int(form.cleaned_data['refusal_reason'])
-                if comment.status == 0:
-                    comment.status == -1
-                comment.save()
-                email_text = ('Dear ' + comment.author.get_title_display() + ' '
-                              + comment.author.user.last_name
-                              + ', \n\nThe Comment you have submitted, '
-                              'concerning publication with title ')
-                if comment.commentary is not None:
-                    email_text += comment.commentary.pub_title + ' by ' +\
-                                                            comment.commentary.author_list
-                elif comment.submission is not None:
-                    email_text += comment.submission.title + ' by ' +\
-                                                            comment.submission.author_list
-                elif comment.thesislink is not None:
-                    email_text += comment.thesislink.title + ' by ' + comment.thesislink.author
-                email_text += (', has been rejected for the following reason: '
-                               + comment.get_status_display() + '.' +
-                               '\n\nWe copy it below for your convenience.' +
-                               '\n\nThank you for your contribution, \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\n' + comment.comment_text
-                emailmessage = EmailMessage('SciPost Comment rejected', email_text,
-                                            'comments@scipost.org',
-                                            [comment.author.user.email],
-                                            ['comments@scipost.org'],
-                                            reply_to=['comments@scipost.org'])
-                emailmessage.send(fail_silently=False)
-
-    # context = {}
-    # return render(request, 'comments/vet_submitted_comment_ack.html', context)
-    context = {'ack_header': 'Submitted Comment vetted.',
-               'followup_message': 'Back to ',
-               'followup_link': reverse('comments:vet_submitted_comments'),
-               'followup_link_label': 'submitted Comments page'}
-    return render(request, 'scipost/acknowledgement.html', context)
+def vet_submitted_comments_list(request):
+    comments_to_vet = Comment.objects.awaiting_vetting().order_by('date_submitted')
+    form = VetCommentForm()
+    context = {'comments_to_vet': comments_to_vet, 'form': form}
+    return(render(request, 'comments/vet_submitted_comments_list.html', context))
+
+
+@login_required
+@transaction.atomic
+def vet_submitted_comment(request, comment_id):
+    # Method `get_objects_for_user` gets all Comments that are assigned to the user
+    # or *all* comments if user has the `scipost.can_vet_comments` permission.
+    comment = get_object_or_404((get_objects_for_user(request.user, 'comments.can_vet_comments')
+                                 .awaiting_vetting()),
+                                id=comment_id)
+    form = VetCommentForm(request.POST or None)
+    if form.is_valid():
+        if form.cleaned_data['action_option'] == '1':
+            # Accept the comment as is
+            comment.status = 1
+            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()
+            content_object.save()
+
+            if isinstance(content_object, Submission):
+                # Add events to Submission and send mail to author of the Submission
+                content_object.add_event_for_eic('A Comment has been accepted.')
+                content_object.add_event_for_author('A new Comment has been added.')
+                if not comment.is_author_reply:
+                    SubmissionUtils.load({'submission': content_object})
+                    SubmissionUtils.send_author_comment_received_email()
+
+        elif form.cleaned_data['action_option'] == '2':
+            # The comment request is simply rejected
+            comment.status = int(form.cleaned_data['refusal_reason'])
+            if comment.status == 0:
+                comment.status = -1  # Why's this here??
+            comment.save()
+
+            # Send emails
+            CommentUtils.load({'comment': comment})
+            CommentUtils.email_comment_vet_rejected_to_author(
+                email_response=form.cleaned_data['email_response_field'])
+
+            if isinstance(comment.content_object, Submission):
+                # Add event if commented to Submission
+                comment.content_object.add_event_for_eic('A Comment has been rejected.')
+
+        messages.success(request, 'Submitted Comment vetted.')
+        if isinstance(comment.content_object, Submission):
+            submission = comment.content_object
+            if submission.editor_in_charge == request.user.contributor:
+                # Redirect a EIC back to the Editorial Page!
+                return redirect(reverse('submissions:editorial_page',
+                                        args=(submission.arxiv_identifier_w_vn_nr,)))
+        elif request.user.has_perm('scipost.can_vet_comments'):
+            # Redirect vetters back to check for other unvetted comments!
+            return redirect(reverse('comments:vet_submitted_comments_list'))
+        return redirect(comment.get_absolute_url())
+
+    context = {
+        'comment': comment,
+        'form': form
+    }
+    return(render(request, 'comments/vet_submitted_comment.html', context))
 
 
 @permission_required('scipost.can_submit_comments', raise_exception=True)
 def reply_to_comment(request, comment_id):
     comment = get_object_or_404(Comment, pk=comment_id)
+
     # Verify if this is from an author:
-    is_author = False
-    if comment.submission is not None:
-        if comment.submission.authors.filter(id=request.user.contributor.id).exists():
-            is_author = True
-    elif comment.commentary is not None:
-        if comment.commentary.authors.filter(id=request.user.contributor.id).exists():
-            is_author = True
-    elif comment.thesislink is not None:
-        if comment.thesislink.author == request.user.contributor:
-            is_author = True
-
-    if request.method == 'POST':
-        form = CommentForm(request.POST, request.FILES)
-        if form.is_valid():
-            newcomment = Comment(
-                commentary=comment.commentary,  # one of commentary, submission or thesislink will be not Null
-                submission=comment.submission,
-                thesislink=comment.thesislink,
-                is_author_reply=is_author,
-                in_reply_to_comment=comment,
-                author=Contributor.objects.get(user=request.user),
-                is_rem=form.cleaned_data['is_rem'],
-                is_que=form.cleaned_data['is_que'],
-                is_ans=form.cleaned_data['is_ans'],
-                is_obj=form.cleaned_data['is_obj'],
-                is_rep=form.cleaned_data['is_rep'],
-                is_cor=form.cleaned_data['is_cor'],
-                is_val=form.cleaned_data['is_val'],
-                is_lit=form.cleaned_data['is_lit'],
-                is_sug=form.cleaned_data['is_sug'],
-                file_attachment=form.cleaned_data['file_attachment'],
-                comment_text=form.cleaned_data['comment_text'],
-                remarks_for_editors=form.cleaned_data['remarks_for_editors'],
-                date_submitted=timezone.now(),
-                )
-            newcomment.save()
-
-            context = {'ack_header': 'Thank you for contributing a Reply.',
-                       'ack_message': 'It will soon be vetted by an Editor.',
-                       'followup_message': 'Back to the ', }
-            if newcomment.submission is not None:
-                context['followup_link'] = reverse(
-                    'submissions:submission',
-                    kwargs={
-                        'arxiv_identifier_w_vn_nr': newcomment.submission.arxiv_identifier_w_vn_nr
-                    }
-                )
-                context['followup_link_label'] = ' Submission page you came from'
-            elif newcomment.commentary is not None:
-                context['followup_link'] = reverse(
-                    'commentaries:commentary',
-                    kwargs={'arxiv_or_DOI_string': newcomment.commentary.arxiv_or_DOI_string})
-                context['followup_link_label'] = ' Commentary page you came from'
-            elif newcomment.thesislink is not None:
-                context['followup_link'] = reverse(
-                    'theses:thesis',
-                    kwargs={'thesislink_id': newcomment.thesislink.id})
-                context['followup_link_label'] = ' Thesis Link page you came from'
-            return render(request, 'scipost/acknowledgement.html', context)
-    else:
-        form = CommentForm()
+    try:
+        # Submission/Commentary
+        is_author = comment.content_object.authors.filter(id=request.user.contributor.id).exists()
+    except AttributeError:
+        # ThesisLink
+        is_author = comment.content_object.author == request.user.contributor
+
+    form = CommentForm(request.POST or None, request.FILES or None)
+    if form.is_valid():
+        newcomment = form.save(commit=False)
+        newcomment.content_object = comment
+        newcomment.is_author_reply = is_author
+        newcomment.author = request.user.contributor
+        newcomment.save()
+        newcomment.grant_permissions()
+
+        messages.success(request, '<h3>Thank you for contributing a Reply</h3>'
+                                  'It will soon be vetted by an Editor.')
+        return redirect(newcomment.content_object.get_absolute_url())
 
     context = {'comment': comment, 'is_author': is_author, 'form': form}
     return render(request, 'comments/reply_to_comment.html', context)
@@ -250,49 +151,23 @@ def reply_to_comment(request, comment_id):
 @permission_required('scipost.can_submit_comments', raise_exception=True)
 def reply_to_report(request, report_id):
     report = get_object_or_404(Report, pk=report_id)
+
     # Verify if this is from an author:
-    is_author = False
-    if report.submission.authors.filter(id=request.user.contributor.id).exists():
-        is_author = True
-    if is_author and request.method == 'POST':
-        form = CommentForm(request.POST, request.FILES)
-        if form.is_valid():
-            newcomment = Comment(
-                submission=report.submission,
-                is_author_reply=is_author,
-                in_reply_to_report=report,
-                author=Contributor.objects.get(user=request.user),
-                is_rem=form.cleaned_data['is_rem'],
-                is_que=form.cleaned_data['is_que'],
-                is_ans=form.cleaned_data['is_ans'],
-                is_obj=form.cleaned_data['is_obj'],
-                is_rep=form.cleaned_data['is_rep'],
-                is_cor=form.cleaned_data['is_cor'],
-                is_val=form.cleaned_data['is_val'],
-                is_lit=form.cleaned_data['is_lit'],
-                is_sug=form.cleaned_data['is_sug'],
-                file_attachment=form.cleaned_data['file_attachment'],
-                comment_text=form.cleaned_data['comment_text'],
-                remarks_for_editors=form.cleaned_data['remarks_for_editors'],
-                date_submitted=timezone.now(),
-                )
-            newcomment.save()
-            # return HttpResponseRedirect(reverse('comments:comment_submission_ack'))
-            context = {
-                'ack_header': 'Thank you for contributing a Reply.',
-                'ack_message': 'It will soon be vetted by an Editor.',
-                'followup_message': 'Back to the ',
-                'followup_link': reverse(
-                    'submissions:submission',
-                    kwargs={
-                        'arxiv_identifier_w_vn_nr': newcomment.submission.arxiv_identifier_w_vn_nr
-                    }
-                ),
-                'followup_link_label': ' Submission page you came from'
-            }
-            return render(request, 'scipost/acknowledgement.html', context)
-    else:
-        form = CommentForm()
+    is_author = report.submission.authors.filter(user=request.user).exists()
+
+    form = CommentForm(request.POST or None, request.FILES or None)
+    if form.is_valid():
+        newcomment = form.save(commit=False)
+        newcomment.content_object = report
+        newcomment.is_author_reply = is_author
+        newcomment.author = request.user.contributor
+        newcomment.save()
+        newcomment.grant_permissions()
+
+        messages.success(request, '<h3>Thank you for contributing a Reply</h3>'
+                                  'It will soon be vetted by an Editor.')
+        return redirect(newcomment.submission.get_absolute_url())
+
     context = {'report': report, 'is_author': is_author, 'form': form}
     return render(request, 'comments/reply_to_report.html', context)
 
@@ -300,18 +175,6 @@ def reply_to_report(request, report_id):
 @permission_required('scipost.can_express_opinion_on_comments', raise_exception=True)
 def express_opinion(request, comment_id, opinion):
     # A contributor has expressed an opinion on a comment
-    contributor = request.user.contributor
     comment = get_object_or_404(Comment, pk=comment_id)
-    comment.update_opinions(contributor.id, opinion)
-    if comment.submission is not None:
-        return HttpResponseRedirect('/submission/' + comment.submission.arxiv_identifier_w_vn_nr +
-                                    '/#comment_id' + str(comment.id))
-    if comment.commentary is not None:
-        return HttpResponseRedirect('/commentary/' + str(comment.commentary.arxiv_or_DOI_string) +
-                                    '/#comment_id' + str(comment.id))
-    if comment.thesislink is not None:
-        return HttpResponseRedirect('/thesis/' + str(comment.thesislink.id) +
-                                    '/#comment_id' + str(comment.id))
-    else:
-        # will never call this
-        return(render(request, 'scipost/index.html'))
+    comment.update_opinions(request.user.contributor.id, opinion)
+    return redirect(comment.get_absolute_url())
diff --git a/funders/__init__.py b/funders/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/funders/admin.py b/funders/admin.py
new file mode 100644
index 0000000000000000000000000000000000000000..d049c6c0f9c56085ce4857538938ef681b322d2a
--- /dev/null
+++ b/funders/admin.py
@@ -0,0 +1,9 @@
+from django.contrib import admin
+
+from .models import Funder, Grant
+
+
+admin.site.register(Funder)
+
+
+admin.site.register(Grant)
diff --git a/funders/apps.py b/funders/apps.py
new file mode 100644
index 0000000000000000000000000000000000000000..413a2e31ce19ca0141ad1185bba7b99059676c38
--- /dev/null
+++ b/funders/apps.py
@@ -0,0 +1,5 @@
+from django.apps import AppConfig
+
+
+class FundersConfig(AppConfig):
+    name = 'funders'
diff --git a/funders/forms.py b/funders/forms.py
new file mode 100644
index 0000000000000000000000000000000000000000..64676af4446f442411f856981a0393bf8a512945
--- /dev/null
+++ b/funders/forms.py
@@ -0,0 +1,22 @@
+from django import forms
+
+from .models import Funder, Grant
+
+class FunderRegistrySearchForm(forms.Form):
+    name = forms.CharField(max_length=128)
+
+
+class FunderForm(forms.ModelForm):
+    class Meta:
+        model = Funder
+        fields = ['name', 'identifier',]
+
+
+class GrantForm(forms.ModelForm):
+    class Meta:
+        model = Grant
+        fields = ['funder', 'number', 'recipient_name', 'recipient',]
+
+
+class GrantSelectForm(forms.Form):
+    grant = forms.ModelChoiceField(queryset=Grant.objects.all())
diff --git a/funders/migrations/0001_initial.py b/funders/migrations/0001_initial.py
new file mode 100644
index 0000000000000000000000000000000000000000..bf7e7e4fbf8e63399cdbd03efaeaad0edc080a0d
--- /dev/null
+++ b/funders/migrations/0001_initial.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:40
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+        ('scipost', '0059_auto_20170701_1356'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Funder',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+                ('identifier', models.CharField(max_length=200, unique=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Grant',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('number', models.CharField(max_length=64)),
+                ('recipient_name', models.CharField(blank=True, max_length=64, null=True)),
+                ('funder', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='funders.Funder')),
+                ('recipient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+            ],
+        ),
+    ]
diff --git a/funders/migrations/0002_auto_20170725_2011.py b/funders/migrations/0002_auto_20170725_2011.py
new file mode 100644
index 0000000000000000000000000000000000000000..c689cf120f8d2cb66918c65a7d4726e3250c0ac9
--- /dev/null
+++ b/funders/migrations/0002_auto_20170725_2011.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 18:11
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='funder',
+            options={'ordering': ['name']},
+        ),
+        migrations.AlterModelOptions(
+            name='grant',
+            options={'ordering': ['funder', 'recipient', 'recipient_name', 'number']},
+        ),
+    ]
diff --git a/funders/migrations/0003_auto_20170726_0606.py b/funders/migrations/0003_auto_20170726_0606.py
new file mode 100644
index 0000000000000000000000000000000000000000..d7c8df068e205aade1009695525a669cf16c6100
--- /dev/null
+++ b/funders/migrations/0003_auto_20170726_0606.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 04:06
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0002_auto_20170725_2011'),
+    ]
+
+    operations = [
+        migrations.AlterUniqueTogether(
+            name='grant',
+            unique_together=set([('funder', 'number')]),
+        ),
+    ]
diff --git a/funders/migrations/__init__.py b/funders/migrations/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/funders/models.py b/funders/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..3957bf92f13ae9a3825a06aa780e68c6063e6b73
--- /dev/null
+++ b/funders/models.py
@@ -0,0 +1,41 @@
+from django.db import models
+
+
+class Funder(models.Model):
+    """
+    Funding info metadata is linked to funders from Crossref's
+    Fundref registry.
+    """
+    name = models.CharField(max_length=256)
+    identifier = models.CharField(max_length=200, unique=True)
+
+    class Meta:
+        ordering = ['name']
+
+    def __str__(self):
+        return self.name
+
+
+class Grant(models.Model):
+    """
+    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(Funder, on_delete=models.CASCADE)
+    number = models.CharField(max_length=64)
+    recipient_name = models.CharField(max_length=64, blank=True, null=True)
+    recipient = models.ForeignKey('scipost.Contributor', blank=True, null=True,
+                                  on_delete=models.CASCADE)
+
+    class Meta:
+        ordering = ['funder', 'recipient', 'recipient_name', 'number']
+        unique_together = ('funder', 'number')
+
+    def __str__(self):
+        grantstring = '%s, grant number %s' % (str(self.funder), self.number)
+        if self.recipient:
+            grantstring += ' (%s)' % str(self.recipient)
+        elif self.recipient_name:
+            grantstring += ' (%s)' % self.recipient_name
+        return grantstring
diff --git a/funders/templates/funders/funders.html b/funders/templates/funders/funders.html
new file mode 100644
index 0000000000000000000000000000000000000000..7ae67d06b8fa03d6fb504cd5475f30f1c22120cb
--- /dev/null
+++ b/funders/templates/funders/funders.html
@@ -0,0 +1,133 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: Funders{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+        <h1 class="highlight">Funders (and associated grants)</h1>
+  </div>
+</div>
+
+
+<div class="row">
+    <div class="col-12">
+        <div class="tab-nav-container">
+            <div class="tab-nav-inner">
+                <!-- Nav tabs -->
+                <ul class="nav btn-group personal-page-nav" role="tablist">
+                  <li class="nav-item btn btn-secondary">
+                    <a href="#funders" class="nav-link active" data-toggle="tab">Funders</a>
+                  </li>
+                  <li class="nav-item btn btn-secondary">
+                    <a href="#grants" class="nav-link" data-toggle="tab">Grants</a>
+                  </li>
+                </ul>
+            </div>
+        </div>
+    </div>
+</div>
+
+
+
+<div class="tab-content">
+
+  <!-- Tab: Funders -->
+  <div class="tab-pane active" id="funders" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+        <h2 class="highlight">Funders</h2>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-12">
+	<h2>Find a new funder in the Fundref registry</h2>
+        <form action="{% url 'funders:query_crossref_for_funder' %}" method="post">
+          {% csrf_token %}
+          {{form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Search">
+        </form>
+	<br/>
+	<h2>Funders in the SciPost database</h2>
+	<table class="table table-hover mb-5">
+	  <thead class="thead-default">
+	    <tr>
+	      <th>Name</th>
+	      <th>Identifier</th>
+	    </tr>
+	  </thead>
+	  <tbody id="accordion" role="tablist" aria-multiselectable="true">
+	    {% for funder in funders %}
+	    <tr data-toggle="collapse" data-parent="#accordion" href="#collapse{{ funder.id }}" aria-expanded="true" aria-controls="collapse{{ funder.id }}" style="cursor: pointer;">
+	      <td>{{ funder.name }}</td>
+	      <td>{{ funder.identifier }}</td>
+	    </tr>
+            {% empty %}
+            <tr>
+              <td colspan="3">No funders found</td>
+            </tr>
+	    {% endfor %}
+	  </tbody>
+	</table>
+      </div>
+    </div>
+  </div>
+
+
+  <!-- Tab: Grants -->
+  <div class="tab-pane" id="grants" role="tabpanel">
+    <div class="row">
+      <div class="col-12">
+        <h2 class="highlight">Grants</h2>
+      </div>
+    </div>
+
+    <div class="row">
+      <div class="col-12">
+	<h2>Add a grant</h2>
+        <form action="{% url 'funders:add_grant' %}" method="post">
+          {% csrf_token %}
+          {{grant_form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Add">
+        </form>
+	<br/>
+	<h2>Grants in the SciPost database</h2>
+	<table class="table table-hover mb-5">
+	  <thead class="thead-default">
+	    <tr>
+	      <th>Funder Name</th>
+	      <th>Recipient</th>
+	      <th>Number</th>
+	    </tr>
+	  </thead>
+	  <tbody id="accordion" role="tablist" aria-multiselectable="true">
+	    {% for grant in grants %}
+	    <tr data-toggle="collapse" data-parent="#accordion" href="#collapse{{ grant.id }}" aria-expanded="true" aria-controls="collapse{{ grant.id }}" style="cursor: pointer;">
+	      <td>{{ grant.funder.name }}</td>
+	      {% if grant.recipient %}
+	      <td>{{ grant.recipient }}</td>
+	      {% elif grant.recipient_name %}
+	      <td>{{ grant.recipient_name }}</td>
+	      {% else %}
+	      <td></td>
+	      {% endif %}
+	      <td>{{ grant.number }}</td>
+	    </tr>
+            {% empty %}
+            <tr>
+              <td colspan="3">No grants found</td>
+            </tr>
+	    {% endfor %}
+	  </tbody>
+	</table>
+      </div>
+    </div>
+  </div>
+</div>
+
+
+{% endblock content %}
diff --git a/funders/templates/funders/query_crossref_for_funder.html b/funders/templates/funders/query_crossref_for_funder.html
new file mode 100644
index 0000000000000000000000000000000000000000..b8459c8a21ff63b830f9c8919fdefb2fe28f9174
--- /dev/null
+++ b/funders/templates/funders/query_crossref_for_funder.html
@@ -0,0 +1,48 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Query Crossref for funder{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block content %}
+
+<div class="row">
+  <div class="col-12">
+        <h1 class="highlight">Query Crossref Fundref Registry for Funders</h1>
+        <form action="{% url 'funders:query_crossref_for_funder' %}" method="post">
+          {% csrf_token %}
+          {{form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Search">
+        </form>
+	{% if response_headers %}
+	<p>{{ response_headers }}</p>
+	{% endif %}
+	{% if response_text %}
+	<p>{{ response_text }}</p>
+	{% endif %}
+	{% if response %}
+	<p>{{ response }}</p>
+	<ul>
+	  {% for item in response.message.items %}
+	  <li>
+	    {{ item.name }}, {{ item.id }}, {{ item.uri }}
+	    <form action="{% url 'funders:add_funder' %}" method="post">
+              {% csrf_token %}
+	      <input name='name' style="width: 64%" value='{{ item.name }}'>
+	      <input name='identifier' style="width: 64%" value='{{ item.uri }}'>
+              <input class="btn btn-secondary" type="submit" value="Add this funder">
+	    </form>
+	  </li>
+	  {% endfor %}
+	</ul>
+	<form action="{% url 'funders:add_funder' %}" method="post">
+          {% csrf_token %}
+          {{funder_form|bootstrap}}
+          <input class="btn btn-secondary" type="submit" value="Submit">
+        </form>
+	{% endif %}
+  </div>
+</div>
+
+
+{% endblock content %}
diff --git a/funders/tests.py b/funders/tests.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ce503c2dd97ba78597f6ff6e4393132753573f6
--- /dev/null
+++ b/funders/tests.py
@@ -0,0 +1,3 @@
+from django.test import TestCase
+
+# Create your tests here.
diff --git a/funders/urls.py b/funders/urls.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec3521ede5af0392724a07aca2ab22f95403c0c7
--- /dev/null
+++ b/funders/urls.py
@@ -0,0 +1,18 @@
+from django.conf.urls import url
+from django.views.generic import TemplateView
+
+from . import views
+
+urlpatterns = [
+    url(r'^$', views.funders,
+        name='funders'),
+    url(r'^query_crossref_for_funder$',
+        views.query_crossref_for_funder,
+        name='query_crossref_for_funder'),
+    url(r'^add_funder$',
+        views.add_funder,
+        name='add_funder'),
+    url(r'^add_grant$',
+        views.add_grant,
+        name='add_grant'),
+]
diff --git a/funders/views.py b/funders/views.py
new file mode 100644
index 0000000000000000000000000000000000000000..50f46f967e463036e4f4d78e4a3a641643ed182c
--- /dev/null
+++ b/funders/views.py
@@ -0,0 +1,65 @@
+import requests
+import json
+
+from django.contrib import messages
+from django.contrib.auth.decorators import permission_required
+from django.core.urlresolvers import reverse
+from django.shortcuts import render, redirect
+
+from .models import Funder, Grant
+from .forms import FunderRegistrySearchForm, FunderForm, GrantForm
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def funders(request):
+    funders = Funder.objects.all()
+    form = FunderRegistrySearchForm()
+    grants = Grant.objects.all()
+    grant_form = GrantForm()
+    context = {'form': form, 'funders': funders,
+               'grants': grants, 'grant_form': grant_form}
+    return render(request, 'funders/funders.html', context)
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def query_crossref_for_funder(request):
+    """
+    Checks Crossref's Fundref Registry for an entry
+    corresponding to the funder name being looked for.
+    If found, creates a funders.Funder instance.
+    """
+    form = FunderRegistrySearchForm(request.POST or None)
+    context = {'form': form}
+    if form.is_valid():
+        queryurl = 'http://api.crossref.org/funders?query=%s' % form.cleaned_data['name']
+        query = requests.get(queryurl)
+        response = json.loads(query.text)
+        context['response_headers'] = query.headers
+        context['response_text'] = query.text
+        context['response'] = response
+        context['funder_form'] = FunderForm()
+    return render(request, 'funders/query_crossref_for_funder.html', context)
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def add_funder(request):
+    form = FunderForm(request.POST or None)
+    if form.is_valid():
+        funder = form.save()
+        messages.success(request, ('<h3>Funder %s successfully created</h3>') %
+                         str(funder))
+    elif form.has_changed():
+        messages.warning(request, 'The form was invalidly filled.')
+    return redirect(reverse('funders:funders'))
+
+
+@permission_required('scipost.can_publish_accepted_submission', raise_exception=True)
+def add_grant(request):
+    grant_form = GrantForm(request.POST or None)
+    if grant_form.is_valid():
+        grant = grant_form.save()
+        messages.success(request, ('<h3>Grant %s successfully added</h3>') %
+                         str(grant))
+    elif grant_form.has_changed():
+        messages.warning(request, 'The form was invalidly filled (grant already exists?).')
+    return redirect(reverse('funders:funders'))
diff --git a/journals/admin.py b/journals/admin.py
index 6b5f4cecdf14c7289cd748ca007979ae20f083c9..0ed07f17e294622f403b9d3823ca201d673bb53e 100644
--- a/journals/admin.py
+++ b/journals/admin.py
@@ -64,6 +64,7 @@ class PublicationAdmin(admin.ModelAdmin):
 admin.site.register(Publication, PublicationAdmin)
 
 
+
 class DepositAdmin(admin.ModelAdmin):
     list_display = ('publication', 'timestamp', 'doi_batch_id', 'deposition_date',)
     readonly_fields = ('publication', 'doi_batch_id', 'metadata_xml', 'deposition_date',)
diff --git a/journals/forms.py b/journals/forms.py
index eb54e4deb587df7ccbc6bbb533d2eb6450988883..688ade7e6c2f450da0473aeadc48cabb756c1dff 100644
--- a/journals/forms.py
+++ b/journals/forms.py
@@ -8,21 +8,13 @@ from .models import UnregisteredAuthor, Issue, Publication
 from submissions.models import Submission
 
 
-
 class InitiatePublicationForm(forms.Form):
-    accepted_submission = forms.ModelChoiceField(
-        queryset=Submission.objects.filter(status='accepted'))
-    original_submission_date = forms.DateField()
-    acceptance_date = forms.DateField()
+    accepted_submission = forms.ModelChoiceField(queryset=Submission.objects.accepted())
     to_be_issued_in = forms.ModelChoiceField(
         queryset=Issue.objects.filter(until_date__gt=timezone.now()))
 
     def __init__(self, *args, **kwargs):
         super(InitiatePublicationForm, self).__init__(*args, **kwargs)
-        self.fields['original_submission_date'].widget.attrs.update(
-            {'placeholder': 'YYYY-MM-DD'})
-        self.fields['acceptance_date'].widget.attrs.update(
-            {'placeholder': 'YYYY-MM-DD'})
 
 
 class ValidatePublicationForm(forms.ModelForm):
@@ -30,7 +22,7 @@ class ValidatePublicationForm(forms.ModelForm):
         model = Publication
         exclude = ['authors', 'authors_claims', 'authors_false_claims',
                    'metadata', 'metadata_xml',
-                   'latest_activity', ]
+                   'latest_activity']
 
 
 class UnregisteredAuthorForm(forms.ModelForm):
@@ -66,16 +58,22 @@ class FundingInfoForm(forms.Form):
     funding_statement = forms.CharField(widget=forms.Textarea())
 
     def __init__(self, *args, **kwargs):
-        super(FundingInfoForm, self).__init__(*args, **kwargs)
-        self.fields['funding_statement'].widget.attrs.update(
-            {'rows': 10, 'cols': 50,
-             'placeholder': 'Paste the funding info statement here'})
+        super().__init__(*args, **kwargs)
+        self.fields['funding_statement'].widget.attrs.update({
+            'rows': 10,
+            'cols': 50,
+            'placeholder': 'Paste the funding info statement here'
+        })
 
 
-class CreateMetadataXMLForm(forms.Form):
-    metadata_xml = forms.CharField(widget=forms.Textarea())
+class CreateMetadataXMLForm(forms.ModelForm):
+    class Meta:
+        model = Publication
+        fields = ['metadata_xml']
 
     def __init__(self, *args, **kwargs):
-        super(CreateMetadataXMLForm, self).__init__(*args, **kwargs)
-        self.fields['metadata_xml'].widget.attrs.update(
-            {'rows': 50, 'cols': 50, })
+        super().__init__(*args, **kwargs)
+        self.fields['metadata_xml'].widget.attrs.update({
+            'rows': 50,
+            'cols': 50
+        })
diff --git a/journals/migrations/0036_auto_20170725_1729.py b/journals/migrations/0036_auto_20170725_1729.py
new file mode 100644
index 0000000000000000000000000000000000000000..65ec9846bc191d8d6962a9c67e79a59a8af30302
--- /dev/null
+++ b/journals/migrations/0036_auto_20170725_1729.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:29
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0059_auto_20170701_1356'),
+        ('journals', '0035_auto_20170714_0609'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Funder',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('name', models.CharField(max_length=256)),
+                ('identifier', models.CharField(max_length=200, unique=True)),
+            ],
+        ),
+        migrations.CreateModel(
+            name='Grant',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('number', models.CharField(max_length=64)),
+                ('recipient_name', models.CharField(blank=True, max_length=64, null=True)),
+                ('funder', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='journals.Funder')),
+                ('recipient', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='scipost.Contributor')),
+            ],
+        ),
+        migrations.AddField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, null=True, to='journals.Grant'),
+        ),
+    ]
diff --git a/journals/migrations/0036_auto_20170725_2048.py b/journals/migrations/0036_auto_20170725_2048.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f740ec130985368925a88ae469fc465d5b4d1a9
--- /dev/null
+++ b/journals/migrations/0036_auto_20170725_2048.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 18:48
+from __future__ import unicode_literals
+
+import django.contrib.postgres.fields.jsonb
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0035_auto_20170714_0609'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='publication',
+            name='metadata_DOAJ',
+            field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default={}, null=True),
+        ),
+    ]
diff --git a/journals/migrations/0037_auto_20170725_1730.py b/journals/migrations/0037_auto_20170725_1730.py
new file mode 100644
index 0000000000000000000000000000000000000000..db456745ef9aa668ae34fc88ee197461a03ec30f
--- /dev/null
+++ b/journals/migrations/0037_auto_20170725_1730.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:30
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0036_auto_20170725_1729'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, to='journals.Grant'),
+        ),
+    ]
diff --git a/journals/migrations/0038_auto_20170725_1738.py b/journals/migrations/0038_auto_20170725_1738.py
new file mode 100644
index 0000000000000000000000000000000000000000..0d32403d115b27f88615e7f48c243a70f6c71d9b
--- /dev/null
+++ b/journals/migrations/0038_auto_20170725_1738.py
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:38
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0037_auto_20170725_1730'),
+    ]
+
+    operations = [
+        migrations.RemoveField(
+            model_name='grant',
+            name='funder',
+        ),
+        migrations.RemoveField(
+            model_name='grant',
+            name='recipient',
+        ),
+        migrations.RemoveField(
+            model_name='publication',
+            name='grants',
+        ),
+        migrations.DeleteModel(
+            name='Funder',
+        ),
+        migrations.DeleteModel(
+            name='Grant',
+        ),
+    ]
diff --git a/journals/migrations/0039_publication_grants.py b/journals/migrations/0039_publication_grants.py
new file mode 100644
index 0000000000000000000000000000000000000000..8b2f9b1c3e2c66f38a68cc2d6290d5e4c2da2614
--- /dev/null
+++ b/journals/migrations/0039_publication_grants.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 15:40
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('funders', '0001_initial'),
+        ('journals', '0038_auto_20170725_1738'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='publication',
+            name='grants',
+            field=models.ManyToManyField(blank=True, to='funders.Grant'),
+        ),
+    ]
diff --git a/journals/migrations/0040_merge_20170726_0945.py b/journals/migrations/0040_merge_20170726_0945.py
new file mode 100644
index 0000000000000000000000000000000000000000..d2c7a67aca6e2f637275e1ea48b8fc99b88b63eb
--- /dev/null
+++ b/journals/migrations/0040_merge_20170726_0945.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 07:45
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('journals', '0036_auto_20170725_2048'),
+        ('journals', '0039_publication_grants'),
+    ]
+
+    operations = [
+    ]
diff --git a/journals/models.py b/journals/models.py
index 2eae14d02015e2b1cd3d5560268cd66fdbbcff75..36e739a040f8fff042d5e5a24c7eefbd90d2e30b 100644
--- a/journals/models.py
+++ b/journals/models.py
@@ -144,10 +144,11 @@ class Publication(models.Model):
     abstract = models.TextField()
     pdf_file = models.FileField(upload_to='UPLOADS/PUBLICATIONS/%Y/%m/', max_length=200)
     cc_license = models.CharField(max_length=32, choices=CC_LICENSES, default=CCBY4)
+    grants = models.ManyToManyField('funders.Grant', blank=True)
     metadata = JSONField(default={}, blank=True, null=True)
     metadata_xml = models.TextField(blank=True, null=True)  # for Crossref deposit
     latest_metadata_update = models.DateTimeField(blank=True, null=True)
-    metadata_DOAJ = JSONField(blank=True, null=True)
+    metadata_DOAJ = JSONField(default={}, blank=True, null=True)
     BiBTeX_entry = models.TextField(blank=True, null=True)
     doi_label = models.CharField(max_length=200, unique=True, db_index=True,
                                  validators=[doi_publication_validator])
@@ -183,7 +184,6 @@ class Publication(models.Model):
                 + ' (' + self.publication_date.strftime('%Y') + ')')
 
 
-
 class Deposit(models.Model):
     """
     Each time a Crossref deposit is made for a Publication,
diff --git a/journals/templates/journals/_publication_details.html b/journals/templates/journals/_publication_details.html
index 90427ac19b8fe27cc009c981d08cd2d1ec5c1ba7..09460585a57824dced8a72b11653262f3c14bbc3 100644
--- a/journals/templates/journals/_publication_details.html
+++ b/journals/templates/journals/_publication_details.html
@@ -14,6 +14,12 @@
             </li>
             <li><a href="javascript:;" data-toggle="modal" data-target="#bibtextmodal">BiBTeX</a></li>
             <li><a href="{% url 'submissions:submission' publication.accepted_submission.arxiv_identifier_w_vn_nr %}">Submissions/Reports</a></li>
+	    <li>
+	      <!-- Start Crossmark Snippet v2.0 -->
+	      <script src="https://crossmark-cdn.crossref.org/widget/v2.0/widget.js"></script>
+	      <a data-target="crossmark"><img src="https://crossmark-cdn.crossref.org/widget/v2.0/logos/CROSSMARK_Color_horizontal.svg" width="120" /></a>
+	      <!-- End Crossmark Snippet -->
+	    </li>
         </ul>
     </div>
 </div>
diff --git a/journals/templates/journals/crossmark_policy.html b/journals/templates/journals/crossmark_policy.html
new file mode 100644
index 0000000000000000000000000000000000000000..504ad53e1f00cc2aa172895bddf6ba2b557e6cbe
--- /dev/null
+++ b/journals/templates/journals/crossmark_policy.html
@@ -0,0 +1,20 @@
+{% extends 'scipost/base.html' %}
+
+{% block pagetitle %}: SciPost Journals: Crossmark Policy{% endblock pagetitle %}
+
+{% load staticfiles %}
+
+{% block content %}
+
+
+<hr>
+<div class="row">
+  <div class="col-12">
+      <h2 id="Crossmark Policy">Crossmark Policy</h2>
+      <p><a href="https://www.crossref.org/services/crossmark/">Crossmark</a> is a multi-publisher initiative from Crossref to provide a standard way for readers to locate the current version of a piece of content.</p>
+      <p>By applying the Crossmark logo SciPost is committing to maintaining the content it publishes and to alerting readers to changes if and when they occur. Clicking on the Crossmark logo will tell you the current status of a document and may also give you additional publication record information about the document.</p>
+      <p>Please refer to our <a href="{% url 'journals:journals_terms_and_conditions' %}">Journals Terms and Conditions</a> for details about our Corrections and Retractions policy.</p>
+  </div>
+</div>
+
+{% endblock content %}
diff --git a/journals/templates/journals/journals_terms_and_conditions.html b/journals/templates/journals/journals_terms_and_conditions.html
index 396b5c67c91e0f05551c496450e3ab405f0fbec5..840fdd57a922bf39548766a8c21f9e0a07d9d291 100644
--- a/journals/templates/journals/journals_terms_and_conditions.html
+++ b/journals/templates/journals/journals_terms_and_conditions.html
@@ -247,4 +247,22 @@
   </div>
 </div>
 
+<hr>
+<div class="row">
+  <div class="col-12">
+      <h2 id="Corrections and retractions">Corrections and retractions</h3>
+      <p>
+	SciPost pursues the following policy for making corrections to its peer-reviewed content:
+      </p>
+      <ul>
+	<li><strong>Modification of a paper</strong>: SciPost reserves the right to replace a published paper if purely technical corrections are necessary (e.g. corrupt file or incorrect bibliographical entry). In such cases, archives and indices are informed. Under no circumstances will the content be changed.</li>
+	<li><strong>Corrigendum</strong>: notification of an important error made by the author(s) or by the journal that affects the publication record or the scientific integrity of the published, peer-reviewed work or the reputation of the author or the journal. Corrigenda are represented by a formal online notice.</li>
+	<li><strong>Retraction</strong>: authors or, in specific cases, SciPost can decide to formally withdraw a published journal article. The article stays online but the reader is notified about the retraction. Such retractions are most often accompanied by an editorial note explaining the background.</li>
+	<li><strong>Marked as fraud</strong>: in the unlikely case that SciPost is notified that a published journal article turns out to be a fraud, the paper stays online but is formally withdrawn. The reader is notified about the status and fraud papers are always accompanied by an editorial note pointing out the malpractice.</li>
+      </ul>
+      <p>All corrections and retractions can be traced through our participation in Crossref's <a href="https://www.crossref.org/services/crossmark/">Crossmark</a> service, as detailed on our <a href="{% url 'journals:crossmark_policy' %}">Crossmark Policy Page</a>.</p>
+
+  </div>
+</div>
+
 {% endblock content %}
diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html
index b9ca627d8401da8c0d6225fff22d306c32f39045..89f1796afce4c103f9dba4c3e3b991e10555f8b6 100644
--- a/journals/templates/journals/manage_metadata.html
+++ b/journals/templates/journals/manage_metadata.html
@@ -56,11 +56,12 @@ event: "focusin"
     </tr>
     <tr id="collapse{{ publication.id }}" class="collapse" role="tabpanel" aria-labelledby="heading{{ publication.id }}" style="background-color: #fff;">
       <td colspan="5">
-	<h3 class="ml-3">Actions</h3>
-        <ul>
-          <li>Mark the first author (currently: {% if publication.first_author %}{{ publication.first_author }} {% elif publication.first_author_unregistered %}{{ publication.first_author_unregistered }} (unregistered){% endif %})
-	    <div class="row">
-              <div class="col-md-5">
+
+	<h2 class="ml-3">Actions</h2>
+	<div class="row">
+          <div class="col-md-5">
+            <ul>
+              <li>Mark the first author (currently: {% if publication.first_author %}{{ publication.first_author }} {% elif publication.first_author_unregistered %}{{ publication.first_author_unregistered }} (unregistered){% endif %})
                 <p>registered authors:</p>
                 <ul>
                   {% for author in publication.authors.all %}
@@ -69,8 +70,6 @@ event: "focusin"
                   </li>
                   {% endfor %}
                 </ul>
-              </div>
-              <div class="col-md-5">
                 <p>unregistered authors:</p>
                 <ul>
                   {% for author_unreg in publication.authors_unregistered.all %}
@@ -79,20 +78,50 @@ event: "focusin"
                   </li>
                   {% endfor %}
                 </ul>
-              </div>
-	    </div>
-          </li>
-          <li><a href="{% url 'journals:add_author' publication.id %}">Add a missing author</a></li>
-          <li><a href="{% url 'journals:create_citation_list_metadata' publication.doi_label %}">Create/update citation list metadata</a></li>
-          <li><a href="{% url 'journals:create_funding_info_metadata' publication.doi_label %}">Create/update funding info metadata</a></li>
-
-          <li><a href="{% url 'journals:create_metadata_xml' publication.doi_label %}">(re)create metadata</a></li>
-          <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'test' %}">Test metadata deposit (via Crossref test server)</a></li>
-          <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'deposit' %}">Deposit the metadata to Crossref</a></li>
-	  <li><a href="{% url 'journals:produce_metadata_DOAJ' doi_label=publication.doi_label %}">Produce DOAJ metadata</a></li>
-	  <li><a href="{% url 'journals:metadata_DOAJ_deposit' doi_label=publication.doi_label %}">Deposit the metadata to DOAJ</a></li>
-        </ul>
-	<h3 class="ml-3">Crossref Deposits</h3>
+	      </li>
+              <li><a href="{% url 'journals:add_author' publication.id %}">Add a missing author</a></li>
+              <li><a href="{% url 'journals:create_citation_list_metadata' publication.doi_label %}">Create/update citation list metadata</a></li>
+              <li><a href="{% url 'journals:create_funding_info_metadata' publication.doi_label %}">Create/update funding info metadata</a></li>
+
+              <li><a href="{% url 'journals:create_metadata_xml' publication.doi_label %}">(re)create metadata</a></li>
+              <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'test' %}">Test metadata deposit (via Crossref test server)</a></li>
+              <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'deposit' %}">Deposit the metadata to Crossref</a></li>
+	      <li><a href="{% url 'journals:produce_metadata_DOAJ' doi_label=publication.doi_label %}">Produce DOAJ metadata</a></li>
+	      <li><a href="{% url 'journals:metadata_DOAJ_deposit' doi_label=publication.doi_label %}">Deposit the metadata to DOAJ</a></li>
+            </ul>
+          </div>
+
+          <div class="col-md-5">
+	    <h2>Funding info for this publication:</h2>
+	    {% if publication.funding_info %}
+	    <p>{{ publication.funding_info }}</p>
+	    {% else %}
+	    <p>No funding info was found</p>
+	    {% endif %}
+	    <h2>Grants associated to this publication:</h2>
+	    <ul>
+	      {% for grant in publication.grants.all %}
+	      <li> {{ grant }}</li>
+	      {% empty %}
+	      <li>no associated grants found</li>
+	      {% endfor %}
+	    </ul>
+	    <br/>
+	    <h3>Associate a grant to this publication:</h3>
+	    <form action="{% url 'journals:add_associated_grant' publication.doi_label %}" method="post">
+	      {% csrf_token %}
+	      {{associate_grant_form|bootstrap}}
+	      <input class="btn btn-secondary" type="submit" value="Add">
+	    </form>
+	    <h3>Other grant-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>
+	    </ul>
+	  </div>
+	</div>
+
+
+	<h2 class="ml-3">Crossref Deposits</h2>
 	<table class="ml-5">
 	  <thead class="thead-default">
 	    <th>Timestamp</th>
@@ -123,7 +152,7 @@ event: "focusin"
 	  </tbody>
 	</table>
 
-	<h3 class="ml-3">DOAJ Deposits</h3>
+	<h2 class="ml-3">DOAJ Deposits</h2>
 	<table class="ml-5">
 	  <thead class="thead-default">
 	    <th>Timestamp</th>
diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html
index cf323f58bd990fd4478e0960c35922b9bb04a405..9181566b3c5d8b80aba8a062031cce3292b298fb 100644
--- a/journals/templates/journals/publication_detail.html
+++ b/journals/templates/journals/publication_detail.html
@@ -31,6 +31,18 @@
     <meta name="citation_firstpage" content="{{ publication.paper_nr|paper_nr_string_filter }}"/>
     <meta name="citation_pdf_url" content="https://scipost.org/{{ publication.doi_string }}/pdf"/>
 
+    <meta name="dc.identifier" content="doi:{{ publication.doi_string }}"/>
+
+    <script>
+      $(document).ready(function(){
+        $("#citationslist").hide();
+
+        $("#citationslistbutton").click(function(){
+          $("#citationslist").toggle();
+        });
+      });
+    </script>
+
 {% endblock headsup %}
 
 {% block content %}
diff --git a/journals/urls/general.py b/journals/urls/general.py
index d0bfd264443304e8aad17248e0ba1e37fc0f4d4e..7af9d780d4c4b5db5490a33e018bd5ba924780b1 100644
--- a/journals/urls/general.py
+++ b/journals/urls/general.py
@@ -12,6 +12,9 @@ urlpatterns = [
     url(r'^journals_terms_and_conditions$',
         TemplateView.as_view(template_name='journals/journals_terms_and_conditions.html'),
         name='journals_terms_and_conditions'),
+    url(r'^crossmark_policy$',
+        TemplateView.as_view(template_name='journals/crossmark_policy.html'),
+        name='crossmark_policy'),
 
     # Editorial and Administrative Workflow
     url(r'^initiate_publication$',
@@ -47,6 +50,9 @@ urlpatterns = [
     url(r'^create_funding_info_metadata/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
         journals_views.create_funding_info_metadata,
         name='create_funding_info_metadata'),
+    url(r'^add_associated_grant/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
+        journals_views.add_associated_grant,
+        name='add_associated_grant'),
     url(r'^create_metadata_xml/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
         journals_views.create_metadata_xml,
         name='create_metadata_xml'),
diff --git a/journals/views.py b/journals/views.py
index 332662b3329a02f74da6d6a2312830edac2b2444..57c4b6da29a331ab8ca524c61a17ace570d3ee43 100644
--- a/journals/views.py
+++ b/journals/views.py
@@ -9,10 +9,9 @@ from django.core.urlresolvers import reverse
 from django.core.files.base import ContentFile
 from django.conf import settings
 from django.contrib import messages
+from django.http import Http404
 from django.utils import timezone
 from django.shortcuts import get_object_or_404, render, redirect
-from django.template import Context
-from django.template.loader import get_template
 from django.db import transaction
 from django.http import HttpResponse
 
@@ -23,9 +22,12 @@ from .forms import FundingInfoForm, InitiatePublicationForm, ValidatePublication
                    UnregisteredAuthorForm, CreateMetadataXMLForm, CitationListBibitemsForm
 from .utils import JournalUtils
 
+from funders.models import Funder
 from submissions.models import Submission
 from scipost.models import Contributor
 
+from funders.forms import GrantSelectForm
+
 from guardian.decorators import permission_required
 
 
@@ -97,9 +99,9 @@ def accepted(request, doi_label):
     have been accepted but are not yet published.
     """
     journal = get_object_or_404(Journal, doi_label=doi_label)
-    accepted_SP_submissions = Submission.objects.filter(
-        submitted_to_journal=journal.name, status='accepted'
-    ).order_by('-latest_activity')
+    accepted_SP_submissions = (Submission.objects.accepted()
+                               .filter(submitted_to_journal=journal.name)
+                               .order_by('-latest_activity'))
     context = {
         'accepted_SP_submissions': accepted_SP_submissions,
         'journal': journal
@@ -157,72 +159,61 @@ def initiate_publication(request):
     This method prefills a ValidatePublicationForm for further
     processing (verification in validate_publication method).
     """
-    if request.method == 'POST':
-        initiate_publication_form = InitiatePublicationForm(request.POST)
-        if initiate_publication_form.is_valid():
-            submission = get_object_or_404(Submission, pk=initiate_publication_form.cleaned_data[
-                                                'accepted_submission'].id)
-            current_issue = get_object_or_404(Issue, pk=initiate_publication_form.cleaned_data[
-                                                'to_be_issued_in'].id)
-
-            # Determine next available paper number:
-            papers_in_current_volume = Publication.objects.filter(
-                in_issue__in_volume=current_issue.in_volume)
-            paper_nr = 1
-            while papers_in_current_volume.filter(paper_nr=paper_nr).exists():
-                paper_nr += 1
-                if paper_nr > 999:
-                    raise PaperNumberingError(paper_nr)
-            doi_label = (
-                current_issue.in_volume.in_journal.name
-                + '.' + str(current_issue.in_volume.number)
-                + '.' + str(current_issue.number) + '.' + paper_nr_string(paper_nr)
-            )
-            doi_string = '10.21468/' + doi_label
-            BiBTeX_entry = (
-                '@Article{' + doi_label + ',\n'
-                '\ttitle={{' + submission.title + '}},\n'
-                '\tauthor={' + submission.author_list.replace(',', ' and') + '},\n'
-                '\tjournal={'
-                + current_issue.in_volume.in_journal.get_abbreviation_citation()
-                + '},\n'
-                '\tvolume={' + str(current_issue.in_volume.number) + '},\n'
-                '\tissue={' + str(current_issue.number) + '},\n'
-                '\tpages={' + paper_nr_string(paper_nr) + '},\n'
-                '\tyear={' + current_issue.until_date.strftime('%Y') + '},\n'
-                '\tpublisher={SciPost},\n'
-                '\tdoi={' + doi_string + '},\n'
-                '\turl={https://scipost.org/' + doi_string + '},\n'
-                '}\n'
-            )
-            initial = {
-                'accepted_submission': submission,
-                'in_issue': current_issue,
-                'paper_nr': paper_nr,
-                'discipline': submission.discipline,
-                'domain': submission.domain,
-                'subject_area': submission.subject_area,
-                'secondary_areas': submission.secondary_areas,
-                'title': submission.title,
-                'author_list': submission.author_list,
-                'abstract': submission.abstract,
-                'BiBTeX_entry': BiBTeX_entry,
-                'doi_label': doi_label,
-                'submission_date': initiate_publication_form.cleaned_data['original_submission_date'],
-                'acceptance_date': initiate_publication_form.cleaned_data['acceptance_date'],
-                'publication_date': timezone.now(),
-                'latest_activity': timezone.now(),
-            }
-            validate_publication_form = ValidatePublicationForm(initial=initial)
-            context = {'validate_publication_form': validate_publication_form, }
-            return render(request, 'journals/validate_publication.html', context)
-        else:
-            errormessage = 'The form was not filled validly.'
-            context = {'initiate_publication_form': initiate_publication_form,
-                       'errormessage': errormessage}
-            return render(request, 'journals/initiate_publication.html', context)
-    else:
-        initiate_publication_form = InitiatePublicationForm()
+    initiate_publication_form = InitiatePublicationForm(request.POST or None)
+    if initiate_publication_form.is_valid():
+        submission = initiate_publication_form.cleaned_data['accepted_submission']
+        current_issue = initiate_publication_form.cleaned_data['to_be_issued_in']
+
+        # Determine next available paper number:
+        paper_nr = Publication.objects.filter(in_issue__in_volume=current_issue.in_volume).count()
+        paper_nr += 1
+        if paper_nr > 999:
+            raise PaperNumberingError(paper_nr)
+
+        # Build form data
+        doi_label = (
+            current_issue.in_volume.in_journal.name
+            + '.' + str(current_issue.in_volume.number)
+            + '.' + str(current_issue.number) + '.' + paper_nr_string(paper_nr)
+        )
+        doi_string = '10.21468/' + doi_label
+        BiBTeX_entry = (
+            '@Article{' + doi_label + ',\n'
+            '\ttitle={{' + submission.title + '}},\n'
+            '\tauthor={' + submission.author_list.replace(',', ' and') + '},\n'
+            '\tjournal={'
+            + current_issue.in_volume.in_journal.get_abbreviation_citation()
+            + '},\n'
+            '\tvolume={' + str(current_issue.in_volume.number) + '},\n'
+            '\tissue={' + str(current_issue.number) + '},\n'
+            '\tpages={' + paper_nr_string(paper_nr) + '},\n'
+            '\tyear={' + current_issue.until_date.strftime('%Y') + '},\n'
+            '\tpublisher={SciPost},\n'
+            '\tdoi={' + doi_string + '},\n'
+            '\turl={https://scipost.org/' + doi_string + '},\n'
+            '}\n'
+        )
+        initial = {
+            'accepted_submission': submission,
+            'in_issue': current_issue,
+            'paper_nr': paper_nr,
+            'discipline': submission.discipline,
+            'domain': submission.domain,
+            'subject_area': submission.subject_area,
+            'secondary_areas': submission.secondary_areas,
+            'title': submission.title,
+            'author_list': submission.author_list,
+            'abstract': submission.abstract,
+            'BiBTeX_entry': BiBTeX_entry,
+            'doi_label': doi_label,
+            'acceptance_date': submission.acceptance_date,
+            'submission_date': submission.submission_date,
+            'publication_date': timezone.now(),
+        }
+        validate_publication_form = ValidatePublicationForm(initial=initial)
+        context = {'validate_publication_form': validate_publication_form}
+        return render(request, 'journals/validate_publication.html', context)
+
     context = {'initiate_publication_form': initiate_publication_form}
     return render(request, 'journals/initiate_publication.html', context)
 
@@ -243,6 +234,7 @@ def validate_publication(request):
                                                         request.FILES or None)
     if validate_publication_form.is_valid():
         publication = validate_publication_form.save()
+
         # Fill in remaining data
         publication.pdf_file = request.FILES['pdf_file']
         submission = publication.accepted_submission
@@ -250,6 +242,7 @@ def validate_publication(request):
         publication.authors_claims.add(*submission.authors_claims.all())
         publication.authors_false_claims.add(*submission.authors_false_claims.all())
         publication.save()
+
         # Move file to final location
         initial_path = publication.pdf_file.path
         new_dir = (settings.MEDIA_ROOT + publication.in_issue.path + '/'
@@ -259,17 +252,23 @@ def validate_publication(request):
         os.rename(initial_path, new_path)
         publication.pdf_file.name = new_path
         publication.save()
+
         # Mark the submission as having been published:
-        publication.accepted_submission.published_as = publication
-        publication.accepted_submission.status = 'published'
-        publication.accepted_submission.save()
+        submission.published_as = publication
+        submission.status = 'published'
+        submission.save()
+
         # TODO: Create a Commentary Page
         # Email authors
         JournalUtils.load({'publication': publication})
         JournalUtils.send_authors_paper_published_email()
-        ack_header = 'The publication has been validated.'
-        context['ack_header'] = ack_header
-        return render(request, 'scipost/acknowledgement.html', context)
+
+        # Add SubmissionEvents
+        submission.add_general_event('The Submission has been published as %s.'
+                                     % publication.doi_label)
+
+        messages.success(request, 'The publication has been validated.')
+        return redirect(publication.get_absolute_url())
     else:
         context['errormessage'] = 'The form was invalid.'
 
@@ -280,8 +279,10 @@ def validate_publication(request):
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
 def manage_metadata(request):
     publications = Publication.objects.order_by('-publication_date', '-paper_nr')
+    associate_grant_form = GrantSelectForm()
     context = {
-        'publications': publications
+        'publications': publications,
+        'associate_grant_form': associate_grant_form,
     }
     return render(request, 'journals/manage_metadata.html', context)
 
@@ -367,14 +368,10 @@ def add_new_unreg_author(request, publication_id):
     if request.method == 'POST':
         new_unreg_author_form = UnregisteredAuthorForm(request.POST)
         if new_unreg_author_form.is_valid():
-            new_unreg_author = UnregisteredAuthor(
-                first_name=new_unreg_author_form.cleaned_data['first_name'],
-                last_name=new_unreg_author_form.cleaned_data['last_name'],)
-            new_unreg_author.save()
+            new_unreg_author = new_unreg_author_form.save()
             publication.authors_unregistered.add(new_unreg_author)
             return redirect(publication.get_absolute_url())
-    errormessage = 'Method add_new_unreg_author can only be called with POST.'
-    return render(request, 'scipost/error.html', context={'errormessage': errormessage})
+    raise Http404
 
 
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
@@ -410,27 +407,43 @@ def create_funding_info_metadata(request, doi_label):
     in the metadata field in a Publication instance.
     """
     publication = get_object_or_404(Publication, doi_label=doi_label)
-    if request.method == 'POST':
-        funding_info_form = FundingInfoForm(request.POST)
-        if funding_info_form.is_valid():
-            publication.metadata['funding_statement'] = funding_info_form.cleaned_data[
-                                                            'funding_statement']
-            publication.save()
 
-    initial = {'funding_statement': '', }
-    funding_statement = ''
+    funding_info_form = FundingInfoForm(request.POST or None)
+    if funding_info_form.is_valid():
+        publication.metadata['funding_statement'] = funding_info_form.cleaned_data[
+                                                        'funding_statement']
+        publication.save()
+
     try:
-        initial['funding_statement'] = publication.metadata['funding_statement']
+        initial = {'funding_statement': publication.metadata['funding_statement']}
         funding_statement = initial['funding_statement']
     except KeyError:
-        pass
+        initial = {'funding_statement': ''}
+        funding_statement = ''
+
     context = {'publication': publication,
                'funding_info_form': FundingInfoForm(initial=initial),
-               'funding_statement': funding_statement, }
+               'funding_statement': funding_statement}
 
     return render(request, 'journals/create_funding_info_metadata.html', context)
 
 
+@permission_required('scipost.can_publish_accepted_submission', return_403=True)
+@transaction.atomic
+def add_associated_grant(request, doi_label):
+    """
+    Called by an Editorial Administrator.
+    This associates a grant from the database to this publication.
+    """
+    publication = get_object_or_404(Publication, doi_label=doi_label)
+    grant_select_form = GrantSelectForm(request.POST or None)
+    if grant_select_form.is_valid():
+        publication.grants.add(grant_select_form.cleaned_data['grant'])
+        publication.save()
+        messages.success(request, 'Grant added to publication %s' % str(publication))
+    return redirect(reverse('journals:manage_metadata'))
+
+
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
 @transaction.atomic
 def create_metadata_xml(request, doi_label):
@@ -442,12 +455,11 @@ def create_metadata_xml(request, doi_label):
     """
     publication = get_object_or_404(Publication, doi_label=doi_label)
 
-    if request.method == 'POST':
-        create_metadata_xml_form = CreateMetadataXMLForm(request.POST)
-        if create_metadata_xml_form.is_valid():
-            publication.metadata_xml = create_metadata_xml_form.cleaned_data['metadata_xml']
-            publication.save()
-            return redirect(reverse('journals:manage_metadata'))
+    create_metadata_xml_form = CreateMetadataXMLForm(request.POST or None, instance=publication)
+    if create_metadata_xml_form.is_valid():
+        create_metadata_xml_form.save()
+        messages.success(request, 'Metadata XML saved')
+        return redirect(reverse('journals:manage_metadata'))
 
     # create a doi_batch_id
     salt = ""
@@ -461,10 +473,11 @@ def create_metadata_xml(request, doi_label):
     initial = {'metadata_xml': ''}
     initial['metadata_xml'] += (
         '<?xml version="1.0" encoding="UTF-8"?>\n'
-        '<doi_batch version="4.3.7" xmlns="http://www.crossref.org/schema/4.3.7" '
+        '<doi_batch version="4.4.0" xmlns="http://www.crossref.org/schema/4.4.0" '
         'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
-        'xsi:schemaLocation="http://www.crossref.org/schema/4.3.7 '
-        'http://www.crossref.org/shema/deposit/crossref4.3.7.xsd">\n'
+        'xmlns:fr="http://www.crossref.org/fundref.xsd" '
+        'xsi:schemaLocation="http://www.crossref.org/schema/4.4.0 '
+        'http://www.crossref.org/shema/deposit/crossref4.4.0.xsd">\n'
         '<head>\n'
         '<doi_batch_id>' + str(doi_batch_id) + '</doi_batch_id>\n'
         '<timestamp>' + timezone.now().strftime('%Y%m%d%H%M%S') + '</timestamp>\n'
@@ -503,6 +516,7 @@ def create_metadata_xml(request, doi_label):
         '<titles><title>' + publication.title + '</title></titles>\n'
         '<contributors>\n'
     )
+
     # Precondition: all authors MUST be listed in authors field of publication instance,
     # this to be checked by EdAdmin before publishing.
     for author in publication.authors.all():
@@ -547,6 +561,38 @@ def create_metadata_xml(request, doi_label):
         '<publisher_item><item_number item_number_type="article_number">'
         + paper_nr_string(publication.paper_nr) +
         '</item_number></publisher_item>\n'
+        '<crossmark>\n'
+        '<crossmark_policy>10.21468/SciPost.CrossmarkPolicy</crossmark_policy>\n'
+        '<crossmark_domains>\n'
+        '<crossmark_domain><domain>scipost.org</domain></crossmark_domain>\n'
+        '</crossmark_domains>\n'
+        '<crossmark_domain_exclusive>false</crossmark_domain_exclusive>\n'
+        '<custom_metadata>\n'
+        )
+    funders = Funder.objects.filter(grant__in=publication.grants.all()).distinct()
+    nr_funders = funders.count()
+    if nr_funders > 0:
+        initial['metadata_xml'] += '<fr:program name="fundref">\n'
+        for funder in funders:
+            if nr_funders > 1:
+                initial['metadata_xml'] += '<fr:assertion name="fundgroup">\n'
+            initial['metadata_xml'] += (
+                '<fr:assertion name="funder_name">' + funder.name + '\n'
+                '<fr:assertion name="funder_identifier">'
+                + funder.identifier + '</fr:assertion>\n'
+                '</fr:assertion>\n')
+            for grant in publication.grants.all():
+                if grant.funder == funder:
+                    initial['metadata_xml'] += (
+                        '<fr:assertion name="award_number">'
+                        + grant.number + '</fr:assertion>\n')
+            if nr_funders > 1:
+                initial['metadata_xml'] += '</fr:assertion>\n'
+        initial['metadata_xml'] += '</fr:program>\n'
+
+    initial['metadata_xml'] += (
+        '</custom_metadata>\n'
+        '</crossmark>\n'
         '<archive_locations><archive name="CLOCKSS"></archive></archive_locations>\n'
         '<doi_data>\n'
         '<doi>' + publication.doi_string + '</doi>\n'
@@ -575,12 +621,13 @@ def create_metadata_xml(request, doi_label):
         '</journal>\n'
     )
     initial['metadata_xml'] += '</body>\n</doi_batch>'
+
     publication.latest_metadata_update = timezone.now()
     publication.save()
-
-    context = {'publication': publication,
-               'create_metadata_xml_form': CreateMetadataXMLForm(initial=initial),
-               }
+    context = {
+        'publication': publication,
+        'create_metadata_xml_form': CreateMetadataXMLForm(initial=initial, instance=publication),
+    }
     return render(request, 'journals/create_metadata_xml.html', context)
 
 
@@ -620,10 +667,7 @@ def metadata_xml_deposit(request, doi_label, option='test'):
         'login_passwd': settings.CROSSREF_LOGIN_PASSWORD,
         }
     files = {'fname': ('metadata.xml', publication.metadata_xml, 'multipart/form-data')}
-    r = requests.post(url,
-                      params=params,
-                      files=files,
-                      )
+    r = requests.post(url, params=params, files=files)
     response_headers = r.headers
     response_text = r.text
 
@@ -730,13 +774,6 @@ def metadata_DOAJ_deposit(request, doi_label):
     f.write(publication.metadata_DOAJ)
     f.close()
 
-    # response_headers = r.headers
-    # response_text = r.text
-    # context = {
-    #     'publication': publication,
-    #     'response_headers': response_headers,
-    #     'response_text': response_text,
-    # }
     messages.success(request, '<h3>%s</h3>Successfull deposit of metadata DOAJ.'
                               % publication.doi_label)
     return redirect(reverse('journals:manage_metadata'))
@@ -794,7 +831,7 @@ def harvest_citedby_links(request, doi_label):
               'pwd': settings.CROSSREF_LOGIN_PASSWORD,
               'qdata': query_xml,
               'doi': publication.doi_string, }
-    r = requests.post(url, params=params,)
+    r = requests.post(url, params=params)
     if r.status_code == 401:
         messages.warning(request, ('<h3>Crossref credentials are invalid.</h3>'
                                    'Please contact the SciPost Admin.'))
diff --git a/models.py b/models.py
new file mode 100644
index 0000000000000000000000000000000000000000..578b6c71dd5d2f603bab5c7534eb3c3c17473120
--- /dev/null
+++ b/models.py
@@ -0,0 +1,60 @@
+from django.db import models
+from django.core.urlresolvers import reverse
+
+from staff.behaviors import WhiteLabelClientMixin, TimeStampedMixin
+
+from .managers import LocationManager
+
+
+class Location(WhiteLabelClientMixin):
+    """
+    Physical location to be related to WCLs.
+    """
+    code = models.CharField(max_length=64)
+    client = models.ForeignKey('clients.Client', related_name='locations', blank=True, null=True)
+    subtitle = models.CharField(max_length=128, blank=True)
+    address = models.CharField(max_length=512)
+    postal_code = models.CharField(max_length=512, blank=True)
+    main_phone = models.CharField(max_length=32, blank=True)
+    city = models.CharField(max_length=512, blank=True)
+    description = models.TextField(blank=True)
+
+    objects = LocationManager()
+
+    class Meta:
+        unique_together = ('white_label_client', 'code',)
+        ordering = ('-code',)
+
+    def __str__(self):
+        return '%s, %s' % (self.address, self.city)
+
+    def get_absolute_url(self):
+        return reverse('locations:detailview', args=(self.code,))
+
+    def get_edit_url(self):
+        return reverse('locations:editview', args=(self.code,))
+
+
+class GeoLocation(TimeStampedMixin):
+    """
+    Geocode which links `Location` objects to the 2D map.
+    """
+    location = models.OneToOneField('locations.Location')
+    latitude = models.CharField(max_length=64)
+    longitude = models.CharField(max_length=64)
+
+
+class LocationObject(TimeStampedMixin):
+    """
+    An physical object can be assigned to a `Location` object.
+    """
+    location = models.ForeignKey('locations.Location', related_name='location_objects')
+    code = models.CharField(max_length=64, blank=True)
+    name = models.CharField(max_length=255)
+    description = models.TextField(blank=True)
+
+    def __str__(self):
+        _str = self.name
+        if self.code:
+            _str += ' (%s)' % self.code
+        return _str
diff --git a/partners/managers.py b/partners/managers.py
index 2b3e4b390a9ce49512f1a0dc01783ea7c582a968..d542b138578ce59188e4a7e20b462d54d0dec067 100644
--- a/partners/managers.py
+++ b/partners/managers.py
@@ -1,5 +1,4 @@
 from django.db import models
-from django.db.models import F
 from django.utils import timezone
 
 from .constants import MEMBERSHIP_SUBMITTED, PROSPECTIVE_PARTNER_PROCESSED, REQUEST_INITIATED
diff --git a/partners/migrations/0012_auto_20170625_1253.py b/partners/migrations/0012_auto_20170625_1253.py
new file mode 100644
index 0000000000000000000000000000000000000000..30925ad9583c28dc83c6796e46480923b23d73f2
--- /dev/null
+++ b/partners/migrations/0012_auto_20170625_1253.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-06-25 10:53
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0011_auto_20170609_2234'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='prospectivepartnerevent',
+            name='event',
+            field=models.CharField(choices=[('requested', 'Requested (from online form)'), ('comment', 'Comment added'), ('email_sent', 'Email sent'), ('negotiating', 'Initiated negotiation'), ('marked_as_uninterested', 'Marked as uninterested'), ('promoted', 'Promoted to Partner')], max_length=64),
+        ),
+    ]
diff --git a/partners/migrations/0027_merge_20170707_1857.py b/partners/migrations/0027_merge_20170707_1857.py
new file mode 100644
index 0000000000000000000000000000000000000000..f7cc870609266767c610c3011cac24be5ecca2c0
--- /dev/null
+++ b/partners/migrations/0027_merge_20170707_1857.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-07 16:57
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0012_auto_20170625_1253'),
+        ('partners', '0026_auto_20170627_1809'),
+    ]
+
+    operations = [
+    ]
diff --git a/partners/migrations/0028_merge_20170724_1840.py b/partners/migrations/0028_merge_20170724_1840.py
new file mode 100644
index 0000000000000000000000000000000000000000..9f4c6d0143be160c234a0e5284516bc1145d53a3
--- /dev/null
+++ b/partners/migrations/0028_merge_20170724_1840.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 16:40
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0027_merge_20170707_1857'),
+        ('partners', '0027_membershipagreement_end_date'),
+    ]
+
+    operations = [
+    ]
diff --git a/partners/migrations/0028_merge_20170724_1958.py b/partners/migrations/0028_merge_20170724_1958.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f39aef937f2a6b8532c416da7a1d1504a6cabc6
--- /dev/null
+++ b/partners/migrations/0028_merge_20170724_1958.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 17:58
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0027_membershipagreement_end_date'),
+        ('partners', '0027_merge_20170707_1857'),
+    ]
+
+    operations = [
+    ]
diff --git a/partners/migrations/0029_merge_20170726_0945.py b/partners/migrations/0029_merge_20170726_0945.py
new file mode 100644
index 0000000000000000000000000000000000000000..04f23ee6b5245d487ce7c1e100e37fdec75ef684
--- /dev/null
+++ b/partners/migrations/0029_merge_20170726_0945.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 07:45
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('partners', '0028_merge_20170724_1958'),
+        ('partners', '0028_merge_20170724_1840'),
+    ]
+
+    operations = [
+    ]
diff --git a/scipost/admin.py b/scipost/admin.py
index 4fe9c27cd08971c8949375475d8e7bc850906f45..21a0de1351f583a3073d8292ca7df866b37d9f01 100644
--- a/scipost/admin.py
+++ b/scipost/admin.py
@@ -123,6 +123,7 @@ class DraftInvitationAdminForm(forms.ModelForm):
         model = DraftInvitation
         fields = '__all__'
 
+
 class DraftInvitationAdmin(admin.ModelAdmin):
     search_fields = ['first_name', 'last_name', 'email', 'processed']
     form = DraftInvitationAdminForm
diff --git a/scipost/behaviors.py b/scipost/behaviors.py
index 1140c889dd21a75820f85e10182286069b4a13f3..7904262e934152b73b11ce7374c979ee55b02c1f 100644
--- a/scipost/behaviors.py
+++ b/scipost/behaviors.py
@@ -4,16 +4,6 @@ from django.utils import timezone
 from .db.fields import AutoDateTimeField
 
 
-class ArxivCallable(object):
-    '''Models that contain a Arxiv identification should contain these
-    methods to be compatible with the ArxivCaller().
-    '''
-    @classmethod
-    def same_version_exists(self, identifier):
-        '''Check if the given identifier already is present in the database.'''
-        raise NotImplementedError
-
-
 class TimeStampedModel(models.Model):
     """
     All objects should inherit from this abstract model.
diff --git a/scipost/constants.py b/scipost/constants.py
index 7a37244c270c6ec72a85cc3312c5695332e9cc8f..30565b7314c13104136891ffca8981cfd41d6be7 100644
--- a/scipost/constants.py
+++ b/scipost/constants.py
@@ -1,5 +1,3 @@
-
-
 DISCIPLINE_PHYSICS = 'physics'
 DISCIPLINE_ASTROPHYSICS = 'astrophysics'
 DISCIPLINE_MATH = 'mathematics'
diff --git a/scipost/management/commands/add_groups_and_permissions.py b/scipost/management/commands/add_groups_and_permissions.py
index d3d038c9c4facfd50eb84c6d950e4be179c5613a..9de95fd8b9fbd9a03677829ec90a66b3c329c83e 100644
--- a/scipost/management/commands/add_groups_and_permissions.py
+++ b/scipost/management/commands/add_groups_and_permissions.py
@@ -4,7 +4,8 @@ from django.contrib.auth.models import Group, Permission
 from django.contrib.contenttypes.models import ContentType
 
 from partners.models import Contact
-from scipost.models import Contributor
+from scipost.models import Contributor, DraftInvitation
+from submissions.models import Report
 
 
 class Command(BaseCommand):
@@ -35,6 +36,8 @@ class Command(BaseCommand):
         # Create Permissions
         content_type = ContentType.objects.get_for_model(Contributor)
         content_type_contact = ContentType.objects.get_for_model(Contact)
+        content_type_draft_invitation = ContentType.objects.get_for_model(DraftInvitation)
+        content_type_report = ContentType.objects.get_for_model(Report)
 
         # Supporting Partners
         can_manage_SPB, created = Permission.objects.get_or_create(
@@ -63,6 +66,13 @@ class Command(BaseCommand):
             content_type=content_type)
 
         # Registration and invitations
+        change_draft_invitation, created = Permission.objects.get_or_create(
+            codename='change_draftinvitation',
+            defaults={
+                'name': 'Can vet registration requests',
+                'content_type': content_type_draft_invitation
+            }
+        )
         can_vet_registration_requests, created = Permission.objects.get_or_create(
             codename='can_vet_registration_requests',
             name='Can vet registration requests',
@@ -122,7 +132,7 @@ class Command(BaseCommand):
             name='Can request Thesis Links',
             content_type=content_type)
 
-        # Vetting of simple objects
+        # Vetting of objects
         can_vet_commentary_requests, created = Permission.objects.get_or_create(
             codename='can_vet_commentary_requests',
             name='Can vet Commentary page requests',
@@ -139,12 +149,20 @@ class Command(BaseCommand):
             codename='can_vet_comments',
             name='Can vet submitted Comments',
             content_type=content_type)
+        can_vet_submitted_reports, created = Permission.objects.get_or_create(
+            codename='can_vet_submitted_reports',
+            name='Can vet submitted Reports',
+            content_type=content_type_report)
 
         # Submissions
         can_submit_manuscript, created = Permission.objects.get_or_create(
             codename='can_submit_manuscript',
             name='Can submit manuscript',
             content_type=content_type)
+        can_read_all_eic_events, created = Permission.objects.get_or_create(
+            codename='can_read_all_eic_events',
+            name='Can read all Editor-in-charge events',
+            content_type=content_type)
 
         # Submission handling
         can_view_pool, created = Permission.objects.get_or_create(
@@ -159,10 +177,6 @@ class Command(BaseCommand):
             codename='can_take_charge_of_submissions',
             name='Can take charge (become Editor-in-charge) of submissions',
             content_type=content_type)
-        can_vet_submitted_reports, created = Permission.objects.get_or_create(
-            codename='can_vet_submitted_reports',
-            name='Can vet submitted Reports',
-            content_type=content_type)
 
         # Refereeing
         can_referee, created = Permission.objects.get_or_create(
@@ -174,6 +188,12 @@ class Command(BaseCommand):
             name='Can oversee refereeing',
             content_type=content_type)
 
+        # Reports
+        can_manage_reports, created = Permission.objects.get_or_create(
+            codename='can_manage_reports',
+            name='Can manage Reports',
+            content_type=content_type)
+
         # Voting
         can_prepare_recommendations_for_voting, created = Permission.objects.get_or_create(
             codename='can_prepare_recommendations_for_voting',
@@ -215,6 +235,7 @@ class Command(BaseCommand):
         # Assign permissions to groups
         SciPostAdmin.permissions.set([
             can_manage_registration_invitations,
+            change_draft_invitation,
             can_email_group_members,
             can_email_particulars,
             can_resend_registration_requests,
@@ -222,6 +243,7 @@ class Command(BaseCommand):
             can_vet_commentary_requests,
             can_vet_thesislink_requests,
             can_vet_authorship_claims,
+            can_vet_submitted_reports,
             can_vet_comments,
             can_view_pool,
             can_assign_submissions,
@@ -239,6 +261,7 @@ class Command(BaseCommand):
 
         AdvisoryBoard.permissions.set([
             can_manage_registration_invitations,
+            change_draft_invitation,
             can_attend_VGMs,
         ])
 
@@ -252,12 +275,13 @@ class Command(BaseCommand):
             can_view_timesheets,
             can_publish_accepted_submission,
             can_attend_VGMs,
+            can_manage_reports,
+            can_read_all_eic_events,
         ])
 
         EditorialCollege.permissions.set([
             can_view_pool,
             can_take_charge_of_submissions,
-            can_vet_submitted_reports,
             view_bylaws,
             can_attend_VGMs,
         ])
@@ -266,6 +290,7 @@ class Command(BaseCommand):
             can_vet_commentary_requests,
             can_vet_thesislink_requests,
             can_vet_authorship_claims,
+            can_vet_submitted_reports,
             can_vet_comments,
         ])
 
@@ -284,6 +309,7 @@ class Command(BaseCommand):
 
         Ambassadors.permissions.set([
             can_manage_registration_invitations,
+            change_draft_invitation,
         ])
 
         JuniorAmbassadors.permissions.set([
diff --git a/scipost/migrations/0060_auto_20170726_1612.py b/scipost/migrations/0060_auto_20170726_1612.py
new file mode 100644
index 0000000000000000000000000000000000000000..5faee7244032b1e0960daea7615c4adc1512b9d0
--- /dev/null
+++ b/scipost/migrations/0060_auto_20170726_1612.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 14:12
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('scipost', '0059_auto_20170701_1356'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='contributor',
+            name='address',
+            field=models.CharField(blank=True, max_length=1000, verbose_name='address'),
+        ),
+    ]
diff --git a/scipost/models.py b/scipost/models.py
index f23ba2a89a33984c8f5e08acf79d653f9dc3fa4c..0ff51058b6f3eeee82f21da2eb3649443b170765 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -9,6 +9,7 @@ from django.contrib.postgres.fields import ArrayField
 from django.db import models
 from django.template import Template, Context
 from django.utils import timezone
+from django.urls import reverse
 
 from django_countries.fields import CountryField
 
@@ -54,7 +55,7 @@ class Contributor(models.Model):
     country_of_employment = CountryField()
     affiliation = models.CharField(max_length=300, verbose_name='affiliation')
     address = models.CharField(max_length=1000, verbose_name="address",
-                               default='', blank=True)
+                               blank=True)
     personalwebpage = models.URLField(verbose_name='personal web page',
                                       blank=True)
     vetted_by = models.ForeignKey('self', on_delete=models.SET(get_sentinel_user),
diff --git a/scipost/services.py b/scipost/services.py
index 9e61ccd731882f140a3095e7d0b7dfb786250892..3df2ce70fb903edf7ea290f81830ce69094d566c 100644
--- a/scipost/services.py
+++ b/scipost/services.py
@@ -23,7 +23,7 @@ class DOICaller:
 
     def _format_data(self):
         data = self._crossref_data
-        pub_title = data['title'][0]
+        title = data['title'][0]
         author_list = ['{} {}'.format(author['given'], author['family']) for author in data['author']]
         # author_list is given as a comma separated list of names on the relevant models (Commentary, Submission)
         author_list = ", ".join(author_list)
@@ -33,7 +33,7 @@ class DOICaller:
         pub_date = self._get_pub_date(data)
 
         self.data = {
-            'pub_title': pub_title,
+            'title': title,
             'author_list': author_list,
             'journal': journal,
             'volume': volume,
@@ -86,7 +86,7 @@ class ArxivCaller:
 
     def _format_data(self):
         data = self._arxiv_data
-        pub_title = data['title']
+        title = data['title']
         author_list = [author['name'] for author in data['authors']]
         # author_list is given as a comma separated list of names on the relevant models (Commentary, Submission)
         author_list = ", ".join(author_list)
@@ -95,8 +95,7 @@ class ArxivCaller:
         pub_date = dateutil.parser.parse(data['published']).date()
 
         self.data = {
-            'pub_title': pub_title,
-            'title': pub_title,  # Duplicate for Commentary/Submission cross-compatibility
+            'title': title,
             'author_list': author_list,
             'arxiv_link': arxiv_link,
             'pub_abstract': abstract,
diff --git a/scipost/static/scipost/assets/css/_code.scss b/scipost/static/scipost/assets/css/_code.scss
index 6ef7af126c765ddc43e46b916902bc3ad54eea65..4a8d281e75da807866bdf5bc6a927612fb854f70 100644
--- a/scipost/static/scipost/assets/css/_code.scss
+++ b/scipost/static/scipost/assets/css/_code.scss
@@ -9,3 +9,7 @@ pre {
         margin: 0;
     }
 }
+
+.clickfocus {
+    cursor: pointer;
+}
diff --git a/scipost/static/scipost/assets/css/_list_group.scss b/scipost/static/scipost/assets/css/_list_group.scss
index a1c49fc9caa46a5e5b953dd2e6b29511e762ba09..835bd38a5a4b649a88d37390a38d5e0f7d622602 100644
--- a/scipost/static/scipost/assets/css/_list_group.scss
+++ b/scipost/static/scipost/assets/css/_list_group.scss
@@ -3,7 +3,51 @@
      border: 0;
  }
 
+
 .list-group-item {
     margin-bottom: 0;
     border-top-color: #f9f9f9;
 }
+ul.events-list {
+    padding-left: 30px;
+
+    &:before {
+        content: '';
+        width: 3px;
+        height: calc(100% - 16px);
+        position: absolute;
+        left: 20px;
+        background: $scipost-darkblue;
+        top: 16px;
+        z-index: 97;
+    }
+
+    li {
+        padding-top: 0.5rem;
+        padding-bottom: 0.5rem;
+
+        &:before {
+            content: '';
+            width: 13px;
+            height: 13px;
+            left: -25px;
+            border-radius: 99px;
+            position: absolute;
+            top: 11px;
+            background: #fff;
+            border: 3px solid $scipost-darkblue;
+            z-index: 99;
+        }
+
+        &:last-child:after {
+            content: '';
+            width: 3px;
+            height: calc(100% - 16px);
+            position: absolute;
+            left: -20px;
+            background: #fff;
+            bottom: 0;
+            z-index: 98;
+        }
+    }
+}
diff --git a/scipost/templates/scipost/comments_block.html b/scipost/templates/scipost/comments_block.html
index 03f432575bb1d77dc7ce6659054f36948cb596fd..ba9a2e069b566a3b13c7b599494bc8dd355a22bd 100644
--- a/scipost/templates/scipost/comments_block.html
+++ b/scipost/templates/scipost/comments_block.html
@@ -4,7 +4,7 @@
     <div class="col-12">
         <div class="card card-grey">
             <div class="card-block">
-                <h2 class="card-title mb-0">Comments on this publication</h2>
+                <h2 class="card-title mb-0">{% if type_of_object %} on this {{type_of_object}}{% endif %}</h2>
                 <a href="javascript:;" data-toggle="toggle" data-target="#commentslist">Toggle comments view</a>
             </div>
         </div>
diff --git a/scipost/templates/scipost/draft_registration_invitation.html b/scipost/templates/scipost/draft_registration_invitation.html
index b3afdc15d3ececf1e95a18abc3900b0a5791f3f2..7c81a644bbb4352521510044e6030b9a4e8612b6 100644
--- a/scipost/templates/scipost/draft_registration_invitation.html
+++ b/scipost/templates/scipost/draft_registration_invitation.html
@@ -66,6 +66,7 @@ $(document).ready(function(){
                     <th>Date drafted</th>
                     <th>Type</th>
                     <th>Drafted by</th>
+                    <th></th>
                 </tr>
             </thead>
             <tbody>
@@ -77,10 +78,14 @@ $(document).ready(function(){
                     <td>{{ draft.date_drafted }} </td>
                     <td>{{ draft.get_invitation_type_display }}</td>
                     <td>{{ draft.drafted_by.user.first_name }} {{ draft.drafted_by.user.last_name }}</td>
+                    <td>
+                        {% if draft.drafted_by.user == request.user %}
+                            <a href="{% url 'scipost:edit_draft_reg_inv' draft.id %}">Edit</a>
+                        {% endif %}</td>
                   </tr>
                 {% empty %}
                     <tr>
-                        <td colspan="6">No drafts found.</td>
+                        <td colspan="7">No drafts found.</td>
                     </tr>
                 {% endfor %}
             </tbody>
diff --git a/scipost/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html
index dd9465f3554d6a3e6cc85074b99656e92e9ec438..c5534d31391d943a5dbcc8ab59c0de5c7415e9c9 100644
--- a/scipost/templates/scipost/personal_page.html
+++ b/scipost/templates/scipost/personal_page.html
@@ -58,10 +58,14 @@
                         <a class="nav-link" data-toggle="tab" href="#theses">Theses</a>
                       </li>
                       <li class="nav-item btn btn-secondary">
-                        <a class="nav-link" data-toggle="tab" href="#comments">Comments</a>
+                          {% with request.user.contributor.comments.regular_comments.awaiting_vetting.count as count %}
+                            <a class="nav-link" data-toggle="tab" href="#comments">Comments{% if count %} ({{count}} unvetted){% endif %}</a>
+                          {% endwith %}
                       </li>
                       <li class="nav-item btn btn-secondary">
-                        <a class="nav-link" data-toggle="tab" href="#author-replies">Author Replies</a>
+                          {% with request.user.contributor.comments.author_replies.awaiting_vetting.count as count %}
+                            <a class="nav-link" data-toggle="tab" href="#author-replies">Author Replies{% if count %} ({{count}} unvetted){% endif %}</a>
+                          {% endwith %}
                       </li>
                     </ul>
                 </div>
@@ -227,30 +231,33 @@
                         </ul>
                         {% endif %}
 
-                        <h3>Email communications</h3>
-                        <ul>
-                            {% if perms.scipost.can_email_group_members %}
-                                <li><a href="{% url 'scipost:email_group_members' %}">Email Group Members</a></li>
-                            {% endif %}
-                            {% if perms.scipost.can_email_particulars %}
-                                <li><a href="{% url 'scipost:send_precooked_email' %}">Send a precooked email</a></li>
-                                <li><a href="{% url 'scipost:email_particular' %}">Email a particular individual/address</a></li>
-                            {% endif %}
-                            {% if perms.scipost.can_manage_mailchimp %}
-                                <li><a href="{% url 'mailing_lists:overview' %}">Manage mailing lists</a></li>
-                            {% endif %}
-                        </ul>
+                        {% if 'SciPost Administrators' in user_groups %}
+                            <h3>Email communications</h3>
+                            <ul>
+                                {% if perms.scipost.can_email_group_members %}
+                                    <li><a href="{% url 'scipost:email_group_members' %}">Email Group Members</a></li>
+                                {% endif %}
+                                {% if perms.scipost.can_email_particulars %}
+                                    <li><a href="{% url 'scipost:send_precooked_email' %}">Send a precooked email</a></li>
+                                    <li><a href="{% url 'scipost:email_particular' %}">Email a particular individual/address</a></li>
+                                {% endif %}
+                                {% if perms.scipost.can_manage_mailchimp %}
+                                    <li><a href="{% url 'mailing_lists:overview' %}">Manage mailing lists</a></li>
+                                {% endif %}
+                            </ul>
+                        {% endif %}
                     </div>
                     {% endif %}
 
                     <div class="col-md-4">
+                        {% if 'Vetting Editors' in user_groups or perms.scipost.can_vet_submitted_reports %}
                         <h3>Vetting actions</h3>
                         <ul>
                             {% if perms.scipost.can_vet_commentary_requests %}
                                 <li><a href="{% url 'commentaries:vet_commentary_requests' %}">Vet Commentary Page requests</a> ({{ nr_commentary_page_requests_to_vet }})</li>
                             {% endif %}
                             {% if perms.scipost.can_vet_comments %}
-                                <li><a href="{% url 'comments:vet_submitted_comments' %}">Vet submitted Comments</a> ({{ nr_comments_to_vet }})</li>
+                                <li><a href="{% url 'comments:vet_submitted_comments_list' %}">Vet submitted Comments</a> ({{ nr_comments_to_vet }})</li>
                             {% endif %}
                             {% if perms.scipost.can_vet_thesislink_requests %}
                                 <li><a href="{% url 'theses:unvetted_thesislinks' %}">Vet Thesis Link Requests</a> ({{ nr_thesislink_requests_to_vet }})</li>
@@ -259,17 +266,19 @@
                                 <li><a href="{% url 'scipost:vet_authorship_claims' %}">Vet Authorship Claims</a> ({{ nr_authorship_claims_to_vet }})</li>
                             {% endif %}
                             {% if perms.scipost.can_vet_submitted_reports %}
-                                <li><a href="{% url 'submissions:vet_submitted_reports' %}">Vet submitted Reports</a> ({{ nr_reports_to_vet }})</li>
+                                <li><a href="{% url 'submissions:vet_submitted_reports_list' %}">Vet submitted Reports</a> ({{ nr_reports_to_vet }})</li>
                             {% endif %}
                         </ul>
+                        {% endif %}
 
                         {% if 'Editorial Administrators' in user_groups %}
                             <h3>Editorial Admin actions</h3>
                             <ul>
-                              {% if perms.scipost.can_publish_accepted_submission %}
-			      <li><a href="{% url 'journals:manage_metadata' %}">Manage metadata</a></li>
+                              <li><a href="{% url 'submissions:reports_accepted_list' %}">Accepted Reports</a>{% if nr_reports_without_pdf %} ({{nr_reports_without_pdf}} unfinished){% endif %}</li>
+                              <li><a href="{% url 'submissions:latest_events' %}">All events in the last 24 hours</a></li>
+                              <li><a href="{% url 'submissions:treated_submissions_list' %}">Fully treated Submissions</a>{% if nr_treated_submissions_without_pdf %} ({{nr_treated_submissions_without_pdf}} unfinished){% endif %}</li>
                               <li><a href="{% url 'journals:harvest_citedby_list' %}">Harvest citedby data</a></li>
-                              {% endif %}
+                              <li><a href="{% url 'journals:manage_metadata' %}">Manage metadata</a></li>
                             </ul>
                         {% endif %}
 
@@ -573,9 +582,9 @@
             <div class="row" id="mycommentslist">
                 <div class="col-12">
                     <ul class="list-group list-group-flush">
-                        {% for own_comment in own_commentsx %}
+                        {% for own_comment in own_comments %}
                             <li class="list-group-item">
-                                {% include 'comments/_comment_card_extended_content.html' with comment=own_comment %}
+                                {% include 'comments/_comment_card_extended_for_author.html' with comment=own_comment %}
                             </li>
                         {% empty %}
                             <li class="list-group-item"><em>You have not commented yet.</em></li>
@@ -602,7 +611,7 @@
                     <ul class="list-group list-group-flush">
                       {% for own_reply in own_authorreplies %}
                           <li class="list-group-item">
-                              {% include 'comments/_comment_card_extended_content.html' with comment=own_reply %}
+                              {% include 'comments/_comment_card_extended_for_author.html' with comment=own_reply %}
                           </li>
                       {% empty %}
                           <li class="list-group-item"><em>You do not have Author Replies yet.</em></li>
diff --git a/scipost/templatetags/texfilters.py b/scipost/templatetags/texfilters.py
new file mode 100644
index 0000000000000000000000000000000000000000..f8e3d05e6f587e54ef526741ccd29c4e0f7ebce7
--- /dev/null
+++ b/scipost/templatetags/texfilters.py
@@ -0,0 +1,26 @@
+from django import template
+from django.utils.html import escape
+from django.utils.text import normalize_newlines
+from django.utils.safestring import SafeData, mark_safe
+
+register = template.Library()
+
+
+@register.filter(is_safe=False, needs_autoescape=True)
+def linebreaktex(value, autoescape=True):
+    """
+    Convert all newlines in a piece of plain text to HTML line breaks
+    """
+    autoescape = autoescape and not isinstance(value, SafeData)
+    value = normalize_newlines(value)
+    if autoescape:
+        value = escape(value)
+    return mark_safe(value.replace('\n', '&#92;&#92; \n'))
+
+
+@register.filter(is_safe=False, needs_autoescape=True)
+def safe_tex_url(value, autoescape=True):
+    """
+    Convert all newlines in a piece of plain text to HTML line breaks
+    """
+    return mark_safe(value.replace('#', '&#92;#'))
diff --git a/scipost/test_services.py b/scipost/test_services.py
index 727a20213e84256e79fc3d85f875df77f9be56a7..cce23f55eca75dbf7a4a3aa0a845ead809d5c964 100644
--- a/scipost/test_services.py
+++ b/scipost/test_services.py
@@ -12,7 +12,7 @@ class ArxivCallerTest(TestCase):
         caller = ArxivCaller('1612.07611v1')
         self.assertTrue(caller.is_valid)
         correct_data = {
-            'pub_abstract': 'The Berezinskii-Kosterlitz-Thouless (BKT) transitions of the six-state clock\nmodel on the square lattice are investigated by means of the corner-transfer\nmatrix renormalization group method. The classical analogue of the entanglement\nentropy $S( L, T )$ is calculated for $L$ by $L$ square system up to $L = 129$,\nas a function of temperature $T$. The entropy has a peak at $T = T^{*}_{~}( L\n)$, where the temperature depends on both $L$ and boundary conditions. Applying\nthe finite-size scaling to $T^{*}_{~}( L )$ and assuming the presence of BKT\ntransitions, the transition temperature is estimated to be $T_1^{~} = 0.70$ and\n$T_2^{~} = 0.88$. The obtained results agree with previous analyses. It should\nbe noted that no thermodynamic function is used in this study.', 'author_list': ['Roman Krčmár', 'Andrej Gendiar', 'Tomotoshi Nishino'], 'arxiv_link': 'http://arxiv.org/abs/1612.07611v1', 'pub_title': 'Phase transition of the six-state clock model observed from the\n  entanglement entropy', 'pub_date': datetime.date(2016, 12, 22)
+            'pub_abstract': 'The Berezinskii-Kosterlitz-Thouless (BKT) transitions of the six-state clock\nmodel on the square lattice are investigated by means of the corner-transfer\nmatrix renormalization group method. The classical analogue of the entanglement\nentropy $S( L, T )$ is calculated for $L$ by $L$ square system up to $L = 129$,\nas a function of temperature $T$. The entropy has a peak at $T = T^{*}_{~}( L\n)$, where the temperature depends on both $L$ and boundary conditions. Applying\nthe finite-size scaling to $T^{*}_{~}( L )$ and assuming the presence of BKT\ntransitions, the transition temperature is estimated to be $T_1^{~} = 0.70$ and\n$T_2^{~} = 0.88$. The obtained results agree with previous analyses. It should\nbe noted that no thermodynamic function is used in this study.', 'author_list': ['Roman Krčmár', 'Andrej Gendiar', 'Tomotoshi Nishino'], 'arxiv_link': 'http://arxiv.org/abs/1612.07611v1', 'title': 'Phase transition of the six-state clock model observed from the\n  entanglement entropy', 'pub_date': datetime.date(2016, 12, 22)
         }
         self.assertEqual(caller.data, correct_data)
 
@@ -20,7 +20,7 @@ class ArxivCallerTest(TestCase):
         caller = ArxivCaller('cond-mat/0612480')
         self.assertTrue(caller.is_valid)
         correct_data = {
-            'author_list': ['Kouji Ueda', 'Chenglong Jin', 'Naokazu Shibata', 'Yasuhiro Hieida', 'Tomotoshi Nishino'], 'pub_date': datetime.date(2006, 12, 19), 'arxiv_link': 'http://arxiv.org/abs/cond-mat/0612480v2', 'pub_abstract': 'A kind of least action principle is introduced for the discrete time\nevolution of one-dimensional quantum lattice models. Based on this principle,\nwe obtain an optimal condition for the matrix product states on succeeding time\nslices generated by the real-time density matrix renormalization group method.\nThis optimization can also be applied to classical simulations of quantum\ncircuits. We discuss the time reversal symmetry in the fully optimized MPS.', 'pub_title': 'Least Action Principle for the Real-Time Density Matrix Renormalization\n  Group'
+            'author_list': ['Kouji Ueda', 'Chenglong Jin', 'Naokazu Shibata', 'Yasuhiro Hieida', 'Tomotoshi Nishino'], 'pub_date': datetime.date(2006, 12, 19), 'arxiv_link': 'http://arxiv.org/abs/cond-mat/0612480v2', 'pub_abstract': 'A kind of least action principle is introduced for the discrete time\nevolution of one-dimensional quantum lattice models. Based on this principle,\nwe obtain an optimal condition for the matrix product states on succeeding time\nslices generated by the real-time density matrix renormalization group method.\nThis optimization can also be applied to classical simulations of quantum\ncircuits. We discuss the time reversal symmetry in the fully optimized MPS.', 'title': 'Least Action Principle for the Real-Time Density Matrix Renormalization\n  Group'
         }
         self.assertEqual(caller.data, correct_data)
 
@@ -39,7 +39,7 @@ class DOICallerTest(TestCase):
             'author_list': [
                 'R. Vlijm', 'M. Ganahl', 'D. Fioretto', 'M. Brockmann', 'M. Haque', 'H. G. Evertz', 'J.-S. Caux'],
             'volume': '92',
-            'pub_title': 'Quasi-soliton scattering in quantum spin chains'
+            'title': 'Quasi-soliton scattering in quantum spin chains'
         }
         self.assertTrue(caller.is_valid)
         self.assertEqual(caller.data, correct_data)
@@ -49,7 +49,7 @@ class DOICallerTest(TestCase):
         correct_data = {
             'pub_date': '2017-04-04',
             'journal': 'SciPost Physics',
-            'pub_title': 'One-particle density matrix of trapped one-dimensional impenetrable bosons from conformal invariance',
+            'title': 'One-particle density matrix of trapped one-dimensional impenetrable bosons from conformal invariance',
             'pages': '',
             'volume': '2',
             'author_list': ['Yannis Brun', 'Jerome Dubail']
diff --git a/scipost/utils.py b/scipost/utils.py
index 3af0f72d92b19ed5e9ebedee46971ff3d681ffeb..7fd4653f98d60cb3e99ff7f2ed383e7caf283d97 100644
--- a/scipost/utils.py
+++ b/scipost/utils.py
@@ -403,13 +403,13 @@ class Utils(BaseMailUtil):
                 'Contributor to the site.')
             email_text_html += (
                 '<p>Your work has been cited in a paper published by SciPost,</p>'
-                '<p>{{ pub_title }}</p> <p>by {{ pub_author_list }}</p>'
+                '<p>{{ title }}</p> <p>by {{ pub_author_list }}</p>'
                 '(published as <a href="https://scipost.org/{{ doi_label }}">{{ citation }}</a>).'
                 '</p>'
                 '\n<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 to the site.</p>')
-            email_context['pub_title'] = cls.invitation.cited_in_publication.title
+            email_context['title'] = cls.invitation.cited_in_publication.title
             email_context['pub_author_list'] = cls.invitation.cited_in_publication.author_list
             email_context['doi_label'] = cls.invitation.cited_in_publication.doi_label
             email_context['citation'] = cls.invitation.cited_in_publication.citation()
@@ -640,7 +640,7 @@ class Utils(BaseMailUtil):
             email_text_html += (
                 '<p>We would like to notify you that '
                 'your work has been cited in a paper published by SciPost,</p>'
-                '<p>{{ pub_title }}</p><p>by {{ pub_author_list }}</p>'
+                '<p>{{ title }}</p><p>by {{ pub_author_list }}</p>'
                 '<p>(published as <a href="https://scipost.org/{{ doi_label }}">'
                 '{{ citation }}</a>).</p>'
                 '<p>We hope you will find this paper of interest to your own research.</p>'
@@ -648,7 +648,7 @@ class Utils(BaseMailUtil):
                 + EMAIL_FOOTER + '<br/>'
                 '\n<p style="font-size: 10px;">Don\'t want to receive such emails? '
                 '<a href="%s">Unsubscribe</a>.</p>' % url_unsubscribe)
-            email_context['pub_title'] = cls.notification.cited_in_publication.title
+            email_context['title'] = cls.notification.cited_in_publication.title
             email_context['pub_author_list'] = cls.notification.cited_in_publication.author_list
             email_context['doi_label'] = cls.notification.cited_in_publication.doi_label
             email_context['citation'] = cls.notification.cited_in_publication.citation()
diff --git a/scipost/views.py b/scipost/views.py
index db7e96e0004dc97bdc333c8f04c1e13d6d084218..66ab962a32015b64bb561bce5607a80565826c58 100644
--- a/scipost/views.py
+++ b/scipost/views.py
@@ -20,6 +20,7 @@ from django.views.generic.list import ListView
 from django.db.models import Prefetch
 
 from guardian.decorators import permission_required
+from guardian.shortcuts import assign_perm, get_objects_for_user
 
 from .constants import SCIPOST_SUBJECT_AREAS, subject_areas_raw_dict, SciPost_from_addresses_dict
 from .decorators import has_contributor
@@ -89,7 +90,7 @@ def documentsSearchResults(query):
     NEEDS UPDATING with e.g. Haystack.
     """
     publication_query = get_query(query, ['title', 'author_list', 'abstract', 'doi_label'])
-    commentary_query = get_query(query, ['pub_title', 'author_list', 'pub_abstract'])
+    commentary_query = get_query(query, ['title', 'author_list', 'pub_abstract'])
     submission_query = get_query(query, ['title', 'author_list', 'abstract'])
     thesislink_query = get_query(query, ['title', 'author', 'abstract', 'supervisor'])
     comment_query = get_query(query, ['comment_text'])
@@ -98,7 +99,7 @@ def documentsSearchResults(query):
                                    .filter(publication_query).order_by('-publication_date'))
     commentary_search_queryset = (Commentary.objects.vetted()
                                   .filter(commentary_query).order_by('-pub_date'))
-    submission_search_queryset = (Submission.objects.public()
+    submission_search_queryset = (Submission.objects.public_unlisted()
                                   .filter(submission_query).order_by('-submission_date'))
     thesislink_search_list = (ThesisLink.objects.vetted()
                               .filter(thesislink_query).order_by('-defense_date'))
@@ -439,6 +440,9 @@ def draft_registration_invitation(request):
         invitation = draft_inv_form.save(commit=False)
         invitation.drafted_by = request.user.contributor
         invitation.save()
+
+        # Assign permission to 'drafter' to edit the draft afterwards
+        assign_perm('comments.change_draftinvitation', request.user, invitation)
         messages.success(request, 'Draft invitation saved.')
         return redirect(reverse('scipost:draft_registration_invitation'))
 
@@ -482,9 +486,11 @@ def draft_registration_invitation(request):
     return render(request, 'scipost/draft_registration_invitation.html', context)
 
 
-@permission_required('scipost.can_manage_registration_invitations', return_403=True)
+@login_required
 def edit_draft_reg_inv(request, draft_id):
-    draft = get_object_or_404(DraftInvitation, id=draft_id)
+    draft = get_object_or_404((get_objects_for_user(request.user, 'scipost.change_draftinvitation')
+                               .filter(processed=False)),
+                              id=draft_id)
 
     draft_inv_form = DraftInvitationForm(request.POST or None, current_user=request.user,
                                          instance=draft)
@@ -799,8 +805,6 @@ def personal_page(request):
     nr_submissions_to_assign = 0
     nr_recommendations_to_prepare_for_voting = 0
     if contributor.is_SP_Admin():
-        intwodays = now + timezone.timedelta(days=2)
-
         # count the number of pending registration requests
         nr_reg_to_vet = Contributor.objects.filter(user__is_active=True, status=0).count()
         nr_reg_awaiting_validation = (Contributor.objects.awaiting_validation()
@@ -809,6 +813,7 @@ def personal_page(request):
         nr_submissions_to_assign = Submission.objects.filter(status__in=['unassigned']).count()
         nr_recommendations_to_prepare_for_voting = EICRecommendation.objects.filter(
             submission__status__in=['voting_in_preparation']).count()
+
     nr_assignments_to_consider = 0
     active_assignments = None
     nr_reports_to_vet = 0
@@ -827,7 +832,7 @@ def personal_page(request):
     if contributor.is_VE():
         nr_commentary_page_requests_to_vet = (Commentary.objects.awaiting_vetting()
                                               .exclude(requested_by=contributor).count())
-        nr_comments_to_vet = Comment.objects.filter(status=0).count()
+        nr_comments_to_vet = Comment.objects.awaiting_vetting().count()
         nr_thesislink_requests_to_vet = ThesisLink.objects.filter(vetted=False).count()
         nr_authorship_claims_to_vet = AuthorshipClaim.objects.filter(status='0').count()
 
@@ -844,9 +849,7 @@ def personal_page(request):
     own_submissions = (Submission.objects
                        .filter(authors__in=[contributor], is_current=True)
                        .order_by('-submission_date'))
-    own_commentaries = (Commentary.objects
-                        .filter(authors__in=[contributor])
-                        .order_by('-latest_activity'))
+    own_commentaries = Commentary.objects.filter(authors=contributor).order_by('-latest_activity')
     own_thesislinks = ThesisLink.objects.filter(author_as_cont__in=[contributor])
     nr_submission_authorships_to_claim = (Submission.objects.filter(
         author_list__contains=contributor.user.last_name)
@@ -866,11 +869,10 @@ def personal_page(request):
                                       .exclude(author_claims__in=[contributor])
                                       .exclude(author_false_claims__in=[contributor])
                                       .count())
-    own_comments = (Comment.objects.select_related('author', 'submission')
-                    .filter(author=contributor, is_author_reply=False)
+    own_comments = (Comment.objects.filter(author=contributor, is_author_reply=False)
+                    .select_related('author', 'submission')
                     .order_by('-date_submitted'))
-    own_authorreplies = (Comment.objects
-                         .filter(author=contributor, is_author_reply=True)
+    own_authorreplies = (Comment.objects.filter(author=contributor, is_author_reply=True)
                          .order_by('-date_submitted'))
 
     appellation = contributor.get_title_display() + ' ' + contributor.user.last_name
@@ -900,9 +902,17 @@ def personal_page(request):
         'own_submissions': own_submissions,
         'own_commentaries': own_commentaries,
         'own_thesislinks': own_thesislinks,
-        'own_comments': own_comments, 'own_authorreplies': own_authorreplies,
+        'own_comments': own_comments,
+        'own_authorreplies': own_authorreplies,
     }
 
+    # Only add variables if user has right permission
+    if request.user.has_perm('scipost.can_manage_reports'):
+        context['nr_reports_without_pdf'] = (Report.objects.accepted()
+                                             .filter(pdf_report='').count())
+        context['nr_treated_submissions_without_pdf'] = (Submission.objects.treated()
+                                                         .filter(pdf_refereeing_pack='').count())
+
     return render(request, 'scipost/personal_page.html', context)
 
 
@@ -1113,7 +1123,7 @@ def contributor_info(request, contributor_id):
     """
     contributor = get_object_or_404(Contributor, pk=contributor_id)
     contributor_publications = Publication.objects.published().filter(authors=contributor)
-    contributor_submissions = Submission.objects.public().filter(authors=contributor)
+    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()
diff --git a/submissions/admin.py b/submissions/admin.py
index 0e394cedfb8da410dfbcda6c3c72047380a6b39e..2d88cdc52264761d1405028e361c86c7ec52982f 100644
--- a/submissions/admin.py
+++ b/submissions/admin.py
@@ -1,14 +1,19 @@
 from django.contrib import admin
+from django.contrib.contenttypes.admin import GenericTabularInline
 from django import forms
 
 from guardian.admin import GuardedModelAdmin
 
+from comments.models import Comment
 from submissions.models import Submission, EditorialAssignment, RefereeInvitation, Report,\
-                               EditorialCommunication, EICRecommendation
-
+                               EditorialCommunication, EICRecommendation, SubmissionEvent
 from scipost.models import Contributor
 
 
+class CommentsGenericInline(GenericTabularInline):
+    model = Comment
+
+
 def submission_short_title(obj):
     return obj.submission.title[:30]
 
@@ -33,8 +38,10 @@ class SubmissionAdmin(GuardedModelAdmin):
     search_fields = ['submitted_by__user__last_name', 'title', 'author_list', 'abstract']
     list_display = ('title', 'author_list', 'status', 'submission_date', 'publication',)
     date_hierarchy = 'submission_date'
-    list_filter = ('status', 'discipline', 'submission_type', )
+    list_filter = ('status', 'discipline', 'submission_type',)
     form = SubmissionAdminForm
+    # inlines = (CommentsGenericInline,)
+    exclude = ('comments', 'comments_old')
 
 
 admin.site.register(Submission, SubmissionAdmin)
@@ -100,6 +107,7 @@ class ReportAdmin(admin.ModelAdmin):
     list_display_links = ('author',)
     date_hierarchy = 'date_submitted'
     list_filter = ('status',)
+    readonly_fields = ('report_nr',)
     form = ReportAdminForm
 
 
@@ -148,3 +156,5 @@ class EICRecommendationAdmin(admin.ModelAdmin):
 
 
 admin.site.register(EICRecommendation, EICRecommendationAdmin)
+
+admin.site.register(SubmissionEvent)
diff --git a/submissions/constants.py b/submissions/constants.py
index 6fa524e42eafdb888dbf6aa8d1c8ff3f847a6149..aac77500f373188103b1435b6b7d50599df0bc72 100644
--- a/submissions/constants.py
+++ b/submissions/constants.py
@@ -45,7 +45,7 @@ SUBMISSION_HTTP404_ON_EDITORIAL_PAGE = [
 ]
 
 SUBMISSION_STATUS_OUT_OF_POOL = SUBMISSION_HTTP404_ON_EDITORIAL_PAGE + [
-    'resubmitted'
+    STATUS_RESUBMITTED
 ]
 
 SUBMISSION_EXCLUDE_FROM_REPORTING = SUBMISSION_HTTP404_ON_EDITORIAL_PAGE + [
@@ -69,24 +69,22 @@ SUBMISSION_STATUS_PUBLICLY_INVISIBLE = [
     STATUS_UNASSIGNED,
     STATUS_RESUBMISSION_INCOMING,
     'assignment_failed',
-    'resubmitted_rejected',
     STATUS_RESUBMITTED_REJECTED,
-    'rejected',
+    STATUS_REJECTED,
     'withdrawn',
 ]
 
 # Submissions which should not appear in search lists
 SUBMISSION_STATUS_PUBLICLY_UNLISTED = SUBMISSION_STATUS_PUBLICLY_INVISIBLE + [
-    'resubmitted',
-    'resubmitted_rejected_visible',
+    STATUS_RESUBMITTED,
     STATUS_RESUBMITTED_REJECTED_VISIBLE,
-    'published'
+    STATUS_PUBLISHED
 ]
 
 # Submissions for which voting on a related recommendation is deprecated:
 SUBMISSION_STATUS_VOTING_DEPRECATED = [
-    'rejected',
-    'published',
+    STATUS_REJECTED,
+    STATUS_PUBLISHED,
     'withdrawn',
 ]
 
@@ -208,3 +206,12 @@ SUBMISSION_CYCLES = (
     (CYCLE_SHORT, 'Short cycle'),
     (CYCLE_DIRECT_REC, 'Direct editorial recommendation'),
 )
+
+EVENT_GENERAL = 'gen'
+EVENT_FOR_EIC = 'eic'
+EVENT_FOR_AUTHOR = 'auth'
+EVENT_TYPES = (
+    (EVENT_GENERAL, 'General comment'),
+    (EVENT_FOR_EIC, 'Comment for Editor-in-charge'),
+    (EVENT_FOR_AUTHOR, 'Comment for author'),
+)
diff --git a/submissions/forms.py b/submissions/forms.py
index 8500b892e96a1fd3ae9eb414c0aa7e99111cbb32..e6b3cd433e0f6adc4f31f247a07fd4751ce104fa 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -32,7 +32,7 @@ class SubmissionSearchForm(forms.Form):
 
     def search_results(self):
         """Return all Submission objects according to search"""
-        return Submission.objects.public_overcomplete().filter(
+        return Submission.objects.public_newest().filter(
             title__icontains=self.cleaned_data.get('title', ''),
             author_list__icontains=self.cleaned_data.get('author', ''),
             abstract__icontains=self.cleaned_data.get('abstract', ''),
@@ -332,6 +332,12 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm):
         return submission
 
 
+class SubmissionReportsForm(forms.ModelForm):
+    class Meta:
+        model = Submission
+        fields = ['pdf_refereeing_pack']
+
+
 ######################
 # Editorial workflow #
 ######################
@@ -412,6 +418,12 @@ class VotingEligibilityForm(forms.Form):
 # Reports:
 ############
 
+class ReportPDFForm(forms.ModelForm):
+    class Meta:
+        model = Report
+        fields = ['pdf_report']
+
+
 class ReportForm(forms.ModelForm):
     class Meta:
         model = Report
@@ -628,6 +640,6 @@ class SubmissionCycleChoiceForm(forms.ModelForm):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.fields['refereeing_cycle'].default = None
-        other_submission = self.instance.other_versions().first()
+        other_submission = self.instance.other_versions.first()
         if other_submission:
             self.fields['referees_reinvite'].queryset = other_submission.referee_invitations.all()
diff --git a/submissions/managers.py b/submissions/managers.py
index 4af4e221c2c9c30bbc3a861bdf5b166c1538aa39..232c7ed9da7949148e0775276619a0378a089b64 100644
--- a/submissions/managers.py
+++ b/submissions/managers.py
@@ -4,8 +4,10 @@ from django.db.models import Q
 from .constants import SUBMISSION_STATUS_OUT_OF_POOL, SUBMISSION_STATUS_PUBLICLY_UNLISTED,\
                        SUBMISSION_STATUS_PUBLICLY_INVISIBLE, STATUS_UNVETTED, STATUS_VETTED,\
                        STATUS_UNCLEAR, STATUS_INCORRECT, STATUS_NOT_USEFUL, STATUS_NOT_ACADEMIC,\
-                       SUBMISSION_HTTP404_ON_EDITORIAL_PAGE, STATUS_DRAFT,\
-                       SUBMISSION_EXCLUDE_FROM_REPORTING
+                       SUBMISSION_HTTP404_ON_EDITORIAL_PAGE, STATUS_DRAFT, STATUS_PUBLISHED,\
+                       SUBMISSION_EXCLUDE_FROM_REPORTING, STATUS_REJECTED_VISIBLE,\
+                       STATUS_ACCEPTED, STATUS_RESUBMITTED, STATUS_RESUBMITTED_REJECTED_VISIBLE,\
+                       EVENT_FOR_EIC, EVENT_GENERAL, EVENT_FOR_AUTHOR
 
 
 class SubmissionManager(models.Manager):
@@ -57,6 +59,13 @@ class SubmissionManager(models.Manager):
                 .order_by('-submission_date'))
 
     def public(self):
+        """
+        This query contains set of public submissions, i.e. also containing
+        submissions with status "published" or "resubmitted".
+        """
+        return self.exclude(status__in=SUBMISSION_STATUS_PUBLICLY_INVISIBLE)
+
+    def public_unlisted(self):
         """
         List only all public submissions. Should be used as a default filter!
 
@@ -66,13 +75,12 @@ class SubmissionManager(models.Manager):
         """
         return self.exclude(status__in=SUBMISSION_STATUS_PUBLICLY_UNLISTED)
 
-    def public_overcomplete(self):
+    def public_newest(self):
         """
-        This query contains an overcomplete set of public submissions, i.e. also containing
-        submissions with status "published" or "resubmitted".
+        This query contains set of public() submissions, filtered to only the newest available
+        version.
         """
-        queryset = self.exclude(status__in=SUBMISSION_STATUS_PUBLICLY_INVISIBLE)
-        return self._newest_version_only(queryset)
+        return self._newest_version_only(self.public())
 
     def open_for_reporting(self):
         """
@@ -81,6 +89,33 @@ class SubmissionManager(models.Manager):
         """
         return self.exclude(status__in=SUBMISSION_EXCLUDE_FROM_REPORTING)
 
+    def treated(self):
+        """
+        This query returns all Submissions that are expected to be 'done'.
+        """
+        return self.filter(status__in=[STATUS_ACCEPTED, STATUS_REJECTED_VISIBLE, STATUS_PUBLISHED,
+                                       STATUS_RESUBMITTED, STATUS_RESUBMITTED_REJECTED_VISIBLE])
+
+    def accepted(self):
+        return self.filter(status=STATUS_ACCEPTED)
+
+    def open_for_commenting(self):
+        return self.filter(open_for_commenting=True)
+
+
+class SubmissionEventQuerySet(models.QuerySet):
+    def for_author(self):
+        """
+        Return all events that are meant to be for the author(s) of a submission.
+        """
+        return self.filter(event__in=[EVENT_FOR_AUTHOR, EVENT_GENERAL])
+
+    def for_eic(self):
+        """
+        Return all events that are meant to be for the Editor-in-charge of a submission.
+        """
+        return self.filter(event__in=[EVENT_FOR_EIC, EVENT_GENERAL])
+
 
 class EditorialAssignmentManager(models.Manager):
     def get_for_user_in_pool(self, user):
@@ -116,7 +151,7 @@ class EICRecommendationManager(models.Manager):
             return self.none()
 
 
-class ReportManager(models.Manager):
+class ReportQuerySet(models.QuerySet):
     def accepted(self):
         return self.filter(status=STATUS_VETTED)
 
diff --git a/submissions/migrations/0046_auto_20170625_1311.py b/submissions/migrations/0046_auto_20170625_1311.py
new file mode 100644
index 0000000000000000000000000000000000000000..d33f029e92a097989c4398e3319df4cb57609b32
--- /dev/null
+++ b/submissions/migrations/0046_auto_20170625_1311.py
@@ -0,0 +1,34 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-06-25 11:11
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+def set_report_counters(apps, schema_editor):
+    Report = apps.get_model('submissions', 'Report')
+    for report in Report.objects.order_by('date_submitted'):
+        if not report.report_nr:
+            report.report_nr = report.submission.reports.filter(report_nr__gte=1).count() + 1
+        report.save()
+    print('Updated all Report counters.')
+
+
+def do_nothing(*args):
+    pass
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0045_auto_20170608_1710'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='report',
+            name='report_nr',
+            field=models.PositiveSmallIntegerField(default=0),
+        ),
+        migrations.RunPython(set_report_counters, do_nothing)
+    ]
diff --git a/submissions/migrations/0047_auto_20170625_1331.py b/submissions/migrations/0047_auto_20170625_1331.py
new file mode 100644
index 0000000000000000000000000000000000000000..151166d05dd98ce29eef6b9b44b137516fe1b4bb
--- /dev/null
+++ b/submissions/migrations/0047_auto_20170625_1331.py
@@ -0,0 +1,29 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-06-25 11:31
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0046_auto_20170625_1311'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='report',
+            name='pdf_report',
+            field=models.FileField(blank=True, max_length=200, upload_to='UPLOADS/REPORTS/%Y/%m/'),
+        ),
+        migrations.AlterField(
+            model_name='report',
+            name='report_nr',
+            field=models.PositiveSmallIntegerField(default=0, help_text='This number is a unique number refeering to the Report nr. of the Submission'),
+        ),
+        migrations.AlterUniqueTogether(
+            name='report',
+            unique_together=set([('submission', 'report_nr')]),
+        ),
+    ]
diff --git a/submissions/migrations/0048_auto_20170721_0931.py b/submissions/migrations/0048_auto_20170721_0931.py
new file mode 100644
index 0000000000000000000000000000000000000000..3f0a084e264d15c611c97fe05ec58596f3769f18
--- /dev/null
+++ b/submissions/migrations/0048_auto_20170721_0931.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-21 07:31
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0047_submission_acceptance_date'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='report',
+            name='requested_changes',
+            field=models.TextField(blank=True, verbose_name='requested changes'),
+        ),
+        migrations.AlterField(
+            model_name='report',
+            name='strengths',
+            field=models.TextField(blank=True),
+        ),
+        migrations.AlterField(
+            model_name='report',
+            name='weaknesses',
+            field=models.TextField(blank=True),
+        ),
+    ]
diff --git a/submissions/migrations/0048_merge_20170707_1857.py b/submissions/migrations/0048_merge_20170707_1857.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0b38b3d8fe4c76efb193145855351d562885c9b
--- /dev/null
+++ b/submissions/migrations/0048_merge_20170707_1857.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-07 16:57
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0047_auto_20170625_1331'),
+        ('submissions', '0047_submission_acceptance_date'),
+    ]
+
+    operations = [
+    ]
diff --git a/submissions/migrations/0049_submission_pdf_refereeing_pack.py b/submissions/migrations/0049_submission_pdf_refereeing_pack.py
new file mode 100644
index 0000000000000000000000000000000000000000..32166d197857ea1466eae54f2008776c5d3499f3
--- /dev/null
+++ b/submissions/migrations/0049_submission_pdf_refereeing_pack.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-07 16:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0048_merge_20170707_1857'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='submission',
+            name='pdf_refereeing_pack',
+            field=models.FileField(blank=True, max_length=200, upload_to='UPLOADS/REFEREE/%Y/%m/'),
+        ),
+    ]
diff --git a/submissions/migrations/0050_auto_20170707_2126.py b/submissions/migrations/0050_auto_20170707_2126.py
new file mode 100644
index 0000000000000000000000000000000000000000..6a454b3e19e435c2e0ac9c57536c3faccc598db8
--- /dev/null
+++ b/submissions/migrations/0050_auto_20170707_2126.py
@@ -0,0 +1,24 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-07 19:26
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0049_submission_pdf_refereeing_pack'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='report',
+            options={'ordering': ['report_nr']},
+        ),
+        migrations.AddField(
+            model_name='report',
+            name='doi_label',
+            field=models.CharField(blank=True, max_length=200),
+        ),
+    ]
diff --git a/submissions/migrations/0051_merge_20170721_0934.py b/submissions/migrations/0051_merge_20170721_0934.py
new file mode 100644
index 0000000000000000000000000000000000000000..2f8075edd4eaf34bd361875a9bf701fd761d7b83
--- /dev/null
+++ b/submissions/migrations/0051_merge_20170721_0934.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-21 07:34
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0050_auto_20170707_2126'),
+        ('submissions', '0048_auto_20170721_0931'),
+    ]
+
+    operations = [
+    ]
diff --git a/submissions/migrations/0055_auto_20170724_1734.py b/submissions/migrations/0055_auto_20170724_1734.py
new file mode 100644
index 0000000000000000000000000000000000000000..aeab30e64171c0ae2c5b0c3247c932b218882b80
--- /dev/null
+++ b/submissions/migrations/0055_auto_20170724_1734.py
@@ -0,0 +1,41 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 15:34
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+import scipost.db.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0054_auto_20170721_1148'),
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='SubmissionEvent',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('created', models.DateTimeField(default=django.utils.timezone.now)),
+                ('latest_activity', scipost.db.fields.AutoDateTimeField(blank=True, default=django.utils.timezone.now, editable=False)),
+                ('event', models.CharField(choices=[('gen', 'General comment'), ('eic', 'Comment for Editor-in-charge'), ('auth', 'Comment for author')], default='gen', max_length=4)),
+                ('blub', models.TextField()),
+                ('submission', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='submissions.Submission')),
+            ],
+            options={
+                'abstract': False,
+            },
+        ),
+        migrations.AlterModelOptions(
+            name='editorialcommunication',
+            options={'ordering': ['timestamp']},
+        ),
+        migrations.AlterField(
+            model_name='editorialcommunication',
+            name='submission',
+            field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='editorial_communications', to='submissions.Submission'),
+        ),
+    ]
diff --git a/submissions/migrations/0055_merge_20170724_1958.py b/submissions/migrations/0055_merge_20170724_1958.py
new file mode 100644
index 0000000000000000000000000000000000000000..54ca985482cecb5aa225e844789ea2733674e3fc
--- /dev/null
+++ b/submissions/migrations/0055_merge_20170724_1958.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 17:58
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0051_merge_20170721_0934'),
+        ('submissions', '0054_auto_20170721_1148'),
+    ]
+
+    operations = [
+    ]
diff --git a/submissions/migrations/0056_auto_20170724_1818.py b/submissions/migrations/0056_auto_20170724_1818.py
new file mode 100644
index 0000000000000000000000000000000000000000..aa28c521016056f66eca92029c5996d37d01eb35
--- /dev/null
+++ b/submissions/migrations/0056_auto_20170724_1818.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 16:18
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0055_auto_20170724_1734'),
+    ]
+
+    operations = [
+        migrations.RenameField(
+            model_name='submissionevent',
+            old_name='blub',
+            new_name='text',
+        ),
+    ]
diff --git a/submissions/migrations/0057_merge_20170724_1840.py b/submissions/migrations/0057_merge_20170724_1840.py
new file mode 100644
index 0000000000000000000000000000000000000000..4aadf6b7eb41e6a1e83106facef409d5b80a739e
--- /dev/null
+++ b/submissions/migrations/0057_merge_20170724_1840.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 16:40
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0056_auto_20170724_1818'),
+        ('submissions', '0051_merge_20170721_0934'),
+    ]
+
+    operations = [
+    ]
diff --git a/submissions/migrations/0058_auto_20170724_1857.py b/submissions/migrations/0058_auto_20170724_1857.py
new file mode 100644
index 0000000000000000000000000000000000000000..788449d8efc8b6e3819f5f81fd765c5041f56791
--- /dev/null
+++ b/submissions/migrations/0058_auto_20170724_1857.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-24 16:57
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0057_merge_20170724_1840'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='report',
+            options={'ordering': ['-date_submitted']},
+        ),
+    ]
diff --git a/submissions/migrations/0059_auto_20170725_2048.py b/submissions/migrations/0059_auto_20170725_2048.py
new file mode 100644
index 0000000000000000000000000000000000000000..292342c7362a11dccd2e418283798f970769fca8
--- /dev/null
+++ b/submissions/migrations/0059_auto_20170725_2048.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-25 18:48
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0058_auto_20170724_1857'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='submissionevent',
+            options={'ordering': ['-created']},
+        ),
+        migrations.AlterField(
+            model_name='eicrecommendation',
+            name='remarks_for_editorial_college',
+            field=models.TextField(blank=True, default='', verbose_name='optional remarks for the Editorial College'),
+            preserve_default=False,
+        ),
+    ]
diff --git a/submissions/migrations/0060_merge_20170726_0945.py b/submissions/migrations/0060_merge_20170726_0945.py
new file mode 100644
index 0000000000000000000000000000000000000000..c48723096d587337ff501c4aef5f3885769a7edd
--- /dev/null
+++ b/submissions/migrations/0060_merge_20170726_0945.py
@@ -0,0 +1,16 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 07:45
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0055_merge_20170724_1958'),
+        ('submissions', '0059_auto_20170725_2048'),
+    ]
+
+    operations = [
+    ]
diff --git a/submissions/migrations/0061_auto_20170727_1012.py b/submissions/migrations/0061_auto_20170727_1012.py
new file mode 100644
index 0000000000000000000000000000000000000000..af6a59d02f96680652df95d98b9354de9c0fd5fd
--- /dev/null
+++ b/submissions/migrations/0061_auto_20170727_1012.py
@@ -0,0 +1,38 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-27 08:12
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+from guardian.shortcuts import assign_perm
+
+from ..models import Report
+
+
+def do_nothing(apps, schema_editor):
+    return
+
+
+def update_eic_permissions(apps, schema_editor):
+    """
+    Grant EIC of submission related to unvetted Reports
+    permission to vet his submission's Report.
+    """
+    # Report = apps.get_model('submissions', 'Report')  -- This doesn't work due to shitty imports
+    count = 0
+    for rep in Report.objects.filter(status='unvetted'):
+        eic_user = rep.submission.editor_in_charge
+        assign_perm('submissions.can_vet_submitted_reports', eic_user.user, rep)
+        count += 1
+    print('\nGranted permission to %i Editor(s)-in-charge to vet related Reports.' % count)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0060_merge_20170726_0945'),
+    ]
+
+    operations = [
+        migrations.RunPython(update_eic_permissions, do_nothing),
+    ]
diff --git a/submissions/migrations/0062_auto_20170727_1032.py b/submissions/migrations/0062_auto_20170727_1032.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2f7ac53fdc2513e16c8322d11200e03bfd8a062
--- /dev/null
+++ b/submissions/migrations/0062_auto_20170727_1032.py
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-27 08:32
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0061_auto_20170727_1012'),
+    ]
+
+    operations = [
+        migrations.AlterModelOptions(
+            name='report',
+            options={'ordering': ['-date_submitted'], 'permissions': (('can_vet_submitted_reports', 'Can vet submitted Reports'),)},
+        ),
+    ]
diff --git a/submissions/models.py b/submissions/models.py
index 8e887cc01e4678c4371faf3353b074afa5f447b7..cd0056ce17b3f73fc836d7f01c704745a6c9e33d 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -1,8 +1,10 @@
 import datetime
 
+from django.contrib.postgres.fields import JSONField
+from django.contrib.contenttypes.fields import GenericRelation
 from django.utils import timezone
 from django.db import models
-from django.contrib.postgres.fields import JSONField
+from django.db.models import Q
 from django.urls import reverse
 from django.utils.functional import cached_property
 
@@ -10,13 +12,15 @@ from .constants import ASSIGNMENT_REFUSAL_REASONS, ASSIGNMENT_NULLBOOL,\
                        SUBMISSION_TYPE, ED_COMM_CHOICES, REFEREE_QUALIFICATION, QUALITY_SPEC,\
                        RANKING_CHOICES, REPORT_REC, SUBMISSION_STATUS, STATUS_UNASSIGNED,\
                        REPORT_STATUSES, STATUS_UNVETTED, SUBMISSION_EIC_RECOMMENDATION_REQUIRED,\
-                       SUBMISSION_CYCLES, CYCLE_DEFAULT, CYCLE_SHORT, CYCLE_DIRECT_REC
+                       SUBMISSION_CYCLES, CYCLE_DEFAULT, CYCLE_SHORT, CYCLE_DIRECT_REC,\
+                       EVENT_GENERAL, EVENT_TYPES, EVENT_FOR_AUTHOR, EVENT_FOR_EIC
 from .managers import SubmissionManager, EditorialAssignmentManager, EICRecommendationManager,\
-                      ReportManager
+                      ReportQuerySet, SubmissionEventQuerySet
 from .utils import ShortSubmissionCycle, DirectRecommendationSubmissionCycle,\
                    GeneralSubmissionCycle
 
-from scipost.behaviors import ArxivCallable
+from comments.models import Comment
+from scipost.behaviors import TimeStampedModel
 from scipost.constants import TITLE_CHOICES
 from scipost.fields import ChoiceArrayField
 from scipost.models import Contributor
@@ -28,7 +32,7 @@ from journals.models import Publication
 ###############
 # Submissions:
 ###############
-class Submission(ArxivCallable, models.Model):
+class Submission(models.Model):
     # Main submission fields
     author_comments = models.TextField(blank=True, null=True)
     author_list = models.CharField(max_length=1000, verbose_name="author list")
@@ -48,6 +52,7 @@ class Submission(ArxivCallable, models.Model):
     secondary_areas = ChoiceArrayField(
         models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS),
         blank=True, null=True)
+
     # Status set by Editors
     status = models.CharField(max_length=30, choices=SUBMISSION_STATUS, default=STATUS_UNASSIGNED)
     refereeing_cycle = models.CharField(max_length=30, choices=SUBMISSION_CYCLES,
@@ -57,6 +62,7 @@ class Submission(ArxivCallable, models.Model):
     submission_type = models.CharField(max_length=10, choices=SUBMISSION_TYPE,
                                        blank=True, null=True, default=None)
     submitted_by = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE)
+
     # Replace this by foreignkey?
     submitted_to_journal = models.CharField(max_length=30, choices=SCIPOST_JOURNALS_SUBMIT,
                                             verbose_name="Journal to be submitted to")
@@ -70,12 +76,18 @@ class Submission(ArxivCallable, models.Model):
                                                   related_name='authors_sub_false_claims')
     abstract = models.TextField()
 
+    # Comments can be added to a Submission
+    comments = GenericRelation('comments.Comment', related_query_name='submissions')
+
     # Arxiv identifiers with/without version number
     arxiv_identifier_w_vn_nr = models.CharField(max_length=15, default='0000.00000v0')
     arxiv_identifier_wo_vn_nr = models.CharField(max_length=10, default='0000.00000')
     arxiv_vn_nr = models.PositiveSmallIntegerField(default=1)
     arxiv_link = models.URLField(verbose_name='arXiv link (including version nr)')
 
+    pdf_refereeing_pack = models.FileField(upload_to='UPLOADS/REFEREE/%Y/%m/',
+                                           max_length=200, blank=True)
+
     # Metadata
     metadata = JSONField(default={}, blank=True, null=True)
     submission_date = models.DateField(verbose_name='submission date', default=datetime.date.today)
@@ -87,7 +99,7 @@ class Submission(ArxivCallable, models.Model):
     class Meta:
         permissions = (
             ('can_take_editorial_actions', 'Can take editorial actions'),
-            )
+        )
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
@@ -111,6 +123,16 @@ class Submission(ArxivCallable, models.Model):
             pass
         return header
 
+    def comments_set_complete(self):
+        """
+        Return comments to Submission, comments on Reports of Submission and
+        nested comments related to this Submission.
+        """
+        return Comment.objects.filter(Q(submissions=self) |
+                                      Q(reports__submission=self) |
+                                      Q(comments__reports__submission=self) |
+                                      Q(comments__submissions=self)).distinct()
+
     def _update_cycle(self):
         """
         Append the specific submission cycle to the instance to eventually handle the
@@ -133,6 +155,7 @@ class Submission(ArxivCallable, models.Model):
     def reporting_deadline_has_passed(self):
         return timezone.now() > self.reporting_deadline
 
+    @cached_property
     def other_versions(self):
         return Submission.objects.filter(
             arxiv_identifier_wo_vn_nr=self.arxiv_identifier_wo_vn_nr
@@ -157,11 +180,54 @@ class Submission(ArxivCallable, models.Model):
     def count_obtained_reports(self):
         return self.reports.accepted().filter(invited__isnull=False).count()
 
-    def count_refused_reports(self):
-        return self.reports.rejected().count()
+    def add_general_event(self, message):
+        event = SubmissionEvent(
+            submission=self,
+            event=EVENT_GENERAL,
+            text=message,
+        )
+        event.save()
+
+    def add_event_for_author(self, message):
+        event = SubmissionEvent(
+            submission=self,
+            event=EVENT_FOR_AUTHOR,
+            text=message,
+        )
+        event.save()
+
+    def add_event_for_eic(self, message):
+        event = SubmissionEvent(
+            submission=self,
+            event=EVENT_FOR_EIC,
+            text=message,
+        )
+        event.save()
+
+
+class SubmissionEvent(TimeStampedModel):
+    """
+    The SubmissionEvent's goal is to act as a messaging/logging model
+    for the Submission cycle. Its main audience will be the author(s) and
+    the Editor-in-charge of a Submission.
+
+    Be aware!
+    Both the author and editor-in-charge will read the submission event.
+    Make sure the right text is given to the right event-type, to protect
+    the fellow's identity.
+    """
+    submission = models.ForeignKey('submissions.Submission', on_delete=models.CASCADE,
+                                   related_name='events')
+    event = models.CharField(max_length=4, choices=EVENT_TYPES, default=EVENT_GENERAL)
+    text = models.TextField()
 
-    def count_awaiting_vetting(self):
-        return self.reports.awaiting_vetting().count()
+    objects = SubmissionEventQuerySet.as_manager()
+
+    class Meta:
+        ordering = ['-created']
+
+    def __str__(self):
+        return '%s: %s' % (str(self.submission), self.get_event_display())
 
 
 ######################
@@ -248,7 +314,12 @@ class Report(models.Model):
     to explicitly implement the perticular differences in for example the form used.
     """
     status = models.CharField(max_length=16, choices=REPORT_STATUSES, default=STATUS_UNVETTED)
-    submission = models.ForeignKey('submissions.Submission', on_delete=models.CASCADE)
+    submission = models.ForeignKey('submissions.Submission', related_name='reports',
+                                   on_delete=models.CASCADE)
+    report_nr = models.PositiveSmallIntegerField(default=0,
+                                                 help_text='This number is a unique number '
+                                                           'refeering to the Report nr. of '
+                                                           'the Submission')
     vetted_by = models.ForeignKey('scipost.Contributor', related_name="report_vetted_by",
                                   blank=True, null=True, on_delete=models.CASCADE)
 
@@ -269,6 +340,9 @@ class Report(models.Model):
     report = models.TextField()
     requested_changes = models.TextField(verbose_name="requested changes", blank=True)
 
+    # Comments can be added to a Submission
+    comments = GenericRelation('comments.Comment', related_query_name='reports')
+
     # Qualities:
     validity = models.PositiveSmallIntegerField(choices=RANKING_CHOICES,
                                                 null=True, blank=True)
@@ -286,18 +360,46 @@ class Report(models.Model):
     recommendation = models.SmallIntegerField(choices=REPORT_REC)
     remarks_for_editors = models.TextField(blank=True,
                                            verbose_name='optional remarks for the Editors only')
+    doi_label = models.CharField(max_length=200, blank=True)
     anonymous = models.BooleanField(default=True, verbose_name='Publish anonymously')
+    pdf_report = models.FileField(upload_to='UPLOADS/REPORTS/%Y/%m/', max_length=200, blank=True)
 
-    objects = ReportManager()
+    objects = ReportQuerySet.as_manager()
 
     class Meta:
+        unique_together = ('submission', 'report_nr')
         default_related_name = 'reports'
         ordering = ['-date_submitted']
+        permissions = (
+            ('can_vet_submitted_reports', 'Can vet submitted Reports'),
+        )
 
     def __str__(self):
         return (self.author.user.first_name + ' ' + self.author.user.last_name + ' on ' +
                 self.submission.title[:50] + ' by ' + self.submission.author_list[:50])
 
+    def save(self, *args, **kwargs):
+        # Control Report count per Submission.
+        if not self.report_nr:
+            self.report_nr = self.submission.reports.count() + 1
+        return super().save(*args, **kwargs)
+
+    def get_absolute_url(self):
+        return self.submission.get_absolute_url() + '#report_' + str(self.report_nr)
+
+    @property
+    def doi_string(self):
+        if self.doi_label:
+            return '10.21468/' + self.doi_label
+
+    @cached_property
+    def title(self):
+        """
+        This property is (mainly) used to let Comments get the title of the Submission without
+        annoying logic.
+        """
+        return self.submission.title
+
     @cached_property
     def is_followup_report(self):
         """
@@ -326,13 +428,17 @@ class EditorialCommunication(models.Model):
     Each individual communication between Editor-in-charge
     to and from Referees and Authors becomes an instance of this class.
     """
-    submission = models.ForeignKey('submissions.Submission', on_delete=models.CASCADE)
+    submission = models.ForeignKey('submissions.Submission', on_delete=models.CASCADE,
+                                   related_name='editorial_communications')
     referee = models.ForeignKey('scipost.Contributor', related_name='referee_in_correspondence',
                                 blank=True, null=True, on_delete=models.CASCADE)
     comtype = models.CharField(max_length=4, choices=ED_COMM_CHOICES)
     timestamp = models.DateTimeField(default=timezone.now)
     text = models.TextField()
 
+    class Meta:
+        ordering = ['timestamp']
+
     def __str__(self):
         output = self.comtype
         if self.referee is not None:
@@ -353,10 +459,11 @@ class EICRecommendation(models.Model):
     date_submitted = models.DateTimeField('date submitted', default=timezone.now)
     remarks_for_authors = models.TextField(blank=True, null=True)
     requested_changes = models.TextField(verbose_name="requested changes", blank=True, null=True)
-    remarks_for_editorial_college = models.TextField(
-        default='', blank=True, null=True,
-        verbose_name='optional remarks for the Editorial College')
+    remarks_for_editorial_college = models.TextField(blank=True,
+                                                     verbose_name='optional remarks for the'
+                                                                  ' Editorial College')
     recommendation = models.SmallIntegerField(choices=REPORT_REC)
+
     # Editorial Fellows who have assessed this recommendation:
     eligible_to_vote = models.ManyToManyField(Contributor, blank=True,
                                               related_name='eligible_to_vote')
diff --git a/submissions/templates/submissions/_refereeing_pack_tex_template.html b/submissions/templates/submissions/_refereeing_pack_tex_template.html
new file mode 100644
index 0000000000000000000000000000000000000000..707246a319c37864228ca28e761e34e2c3ee3687
--- /dev/null
+++ b/submissions/templates/submissions/_refereeing_pack_tex_template.html
@@ -0,0 +1,200 @@
+{% load texfilters %}\documentclass{SciPost}
+
+% Prevent all line breaks in inline equations.
+\binoppenalty=10000
+\relpenalty=10000
+
+\hypersetup{
+    colorlinks,
+    linkcolor={red!50!black},
+    citecolor={blue!50!black},
+    urlcolor={blue!80!black}
+}
+
+\usepackage[bitstream-charter]{mathdesign}
+\urlstyle{sf}
+
+\fancypagestyle{SPstyle}{
+\fancyhf{}
+\lhead{\raisebox{-1.5mm}[0pt][0pt]{\href{https://scipost.org}{\includegraphics[width=20mm]{logo_scipost_with_bgd.pdf}}}}
+
+{% if report.doi_string %}
+    \rhead{\small \href{https://scipost.org{{report.doi_string|safe_tex_url}} }{ {{report.doi_string|safe_tex_url}} ({{report.date_submitted|date:'Y'}})}}
+{% endif %}
+
+\renewcommand{\headrulewidth}{1pt}
+\fancyfoot[C]{\textbf{\thepage}}
+}
+
+\begin{document}
+
+\pagestyle{SPstyle}
+
+\begin{center}
+\Large\color{scipostdeepblue}{\textbf{
+%%%%%%%%%% TITLE + AUTHORS
+Refereeing Package of\href{https://scipost.org{{submission.get_absolute_url|safe_tex_url}} }{\color{scipostdeepblue}{ {{submission.title}} }}by {{submission.author_list}}
+}}
+\end{center}
+
+\begin{center}
+\Large\color{scipostdeepblue}{\textbf{
+%%%%%%%%%% ARXIV CODE
+\href{https://scipost.org{{submission.get_absolute_url|safe_tex_url}} }{\color{scipostdeepblue}{ {{submission.arxiv_identifier_w_vn_nr}} }}
+}}
+\end{center}
+
+\vspace{10pt}
+
+%%%%%%%%%% DATES
+\small{\ \\Received {{submission.submission_date|date:'d-m-Y'}}\newline
+{% if submission.acceptance_date %}Accepted {{submission.acceptance_date|date:'d-m-Y'}} \newline{% endif %}
+Submitted to {{submission.get_submitted_to_journal_display}}
+}
+
+
+%%%%% TABLE OF CONTENT
+\vspace{10pt}
+\noindent\rule{\textwidth}{1pt}
+\tableofcontents
+\noindent\rule{\textwidth}{1pt}
+\vspace{10pt}
+
+
+%%%%%%%%%% CONTENT
+
+{% for report in submission.reports.accepted %}
+    \newpage
+    \setcounter{section}{0}
+
+    \addcontentsline{toc}{section}{\protect\numberline{}Report {{report.report_nr}}{% if report.doi_string %} $\cdot$ doi: {{report.doi_string|safe_tex_url}}{% endif %} }
+
+    \fancypagestyle{SPstylereport{{report.id}} }{
+    \fancyhf{}
+    \lhead{\raisebox{-1.5mm}[0pt][0pt]{\href{https://scipost.org}{\includegraphics[width=20mm]{logo_scipost_with_bgd.pdf}}}}
+
+    {% if report.doi_string %}
+        \rhead{\small \href{https://scipost.org{{report.doi_string|safe_tex_url}} }{ {{report.doi_string|safe_tex_url}} ({{report.date_submitted|date:'Y'}})}}
+    {% endif %}
+
+    \renewcommand{\headrulewidth}{1pt}
+    \fancyfoot[C]{\textbf{\thepage}}
+    }
+    \pagestyle{SPstylereport{{report.id}} }
+
+    \begin{center}
+    \Large\color{scipostdeepblue}{\textbf{
+    %%%%%%%%%% TITLE
+    Report {{report.report_nr}} on\href{https://scipost.org{{report.get_absolute_url|safe_tex_url}} }{\color{scipostdeepblue}{ {{report.submission.title}} }}by {{report.submission.author_list}}
+    }}
+    \end{center}
+
+    {% if report.doi_string %}
+        \begin{center}
+        \Large\color{scipostdeepblue}{\textbf{
+        %%%%%%%%%% TITLE
+        doi:\href{https://scipost.org{{report.get_absolute_url|safe_tex_url}} }{\color{scipostdeepblue}{ {{report.doi_string|safe_tex_url}} }}
+        }}
+        \end{center}
+    {% endif %}
+
+    \begin{center}
+    \large\textbf{
+    %%%%%%%%%% AUTHORS
+    Report by {% if report.anonymous %}anonymous{% else %}{{report.author.user.first_name}} {{report.author.user.last_name}}\textsuperscript{1}{% endif %}
+    }
+    \end{center}
+
+    {% if not report.anonymous %}
+        \begin{center}
+        %%%%%%%%%% AFFILIATIONS
+        {\bf 1} {{report.author.affiliation}}\\
+        \end{center}
+    {% endif %}
+
+
+    \vspace{10pt}
+
+
+    \begin{center}
+    \begin{tabular}{lr}
+    \begin{minipage}{0.5\textwidth}
+    \raisebox{-1mm}[0pt][0pt]{\includegraphics[width=12mm]{by.eps}}
+
+    %%%%%%%%%% COPYRIGHT
+
+    {\small Copyright {% if report.anonymous %}anonymous{% else %}{{report.author.user.first_name}} {{report.author.user.last_name}}{% endif %}. \newline
+    This work is licensed under the Creative Commons \newline
+    \href{http://creativecommons.org/licenses/by/4.0/}{Attribution 4.0 International License}. \newline
+    Published by the SciPost Foundation.
+    }
+    \end{minipage}
+    &
+    \begin{minipage}{0.5\textwidth}
+    %%%%%%%%%% DATES
+    {\small Received {{report.date_submitted|date:'d-m-Y'}}
+    {% if report.doi_string %}
+        doi:\href{//dx.doi.org{{report.doi_string|safe_tex_url}} }{ {{report.doi_string|safe_tex_url}} }
+    {% endif %}
+    }
+    \end{minipage}
+    \end{tabular}
+    \end{center}
+
+    \vspace{10pt}
+    \noindent\rule{\textwidth}{1pt}
+
+    %%%%%%%% CONTENTS
+
+    \section*{Ratings}
+    \begin{center}
+    \begin{tabular}{r p{0.15\columnwidth} r l}
+    	{\bf Validity} & {{report.get_validity_display}} & {\bf Clarity} & {{report.get_clarity_display}} \\
+    	{\bf Significance} & {{report.get_significance_display}} & {\bf Formatting} & {{report.get_formatting_display}} \\
+    	{\bf Originality} & {{report.get_originality_display}} & {\bf Grammar} & {{report.get_grammar_display}}
+    \end{tabular}
+    \end{center}
+
+    \section*{Strengths}
+    {{report.strengths|linebreaktex}}
+
+    \section*{Weaknesses}
+    {{report.weaknesses|linebreaktex}}
+
+    \section*{Report}
+    {{report.report|linebreaktex}}
+
+
+    \section*{Requested changes}
+    {{report.requested_changes|linebreaktex}}
+
+
+    {% if report.comments.vetted %}
+        \newpage
+        \pagestyle{SPstyle}
+        \section*{Comments and Author Replies to this Report}
+
+        {% for comment in report.comments.vetted %}
+            \addcontentsline{toc}{subsection}{\protect\numberline{}{% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} to Report by {% if comment.anonymous %}anonymous{% else %}{{comment.author.user.first_name}} {{comment.author.user.last_name}}{% endif %} }
+
+            \subsection*{ {% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} to Report by {% if comment.anonymous %}anonymous{% else %}{{comment.author.user.first_name}} {{comment.author.user.last_name}}{% endif %} }
+            {% include 'comments/_comment_tex_template.html' with comment=comment %}
+        {% endfor %}
+    {% endif %}
+
+{% endfor %}
+
+{% if submission.comments.vetted %}
+    \newpage
+    \setcounter{section}{0}
+    \pagestyle{SPstyle}
+
+    {% for comment in submission.comments.vetted %}
+        \addcontentsline{toc}{section}{\protect\numberline{}{% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} by {% if comment.anonymous %}anonymous{% else %}{{comment.author.user.first_name}} {{comment.author.user.last_name}}{% endif %} }
+
+        \section*{ {% if comment.is_author_reply %}Author Reply{% else %}Comment{% endif %} {{forloop.counter}} by {% if comment.anonymous %}anonymous{% else %}{{comment.author.user.first_name}} {{comment.author.user.last_name}}{% endif %} }
+        {% include 'comments/_comment_tex_template.html' with comment=comment %}
+    {% endfor %}
+{% endif %}
+
+\end{document}
diff --git a/submissions/templates/submissions/_report_tex_template.html b/submissions/templates/submissions/_report_tex_template.html
new file mode 100644
index 0000000000000000000000000000000000000000..edb59afc172ed68722591107bcd2b97c5a737a01
--- /dev/null
+++ b/submissions/templates/submissions/_report_tex_template.html
@@ -0,0 +1,112 @@
+{% load texfilters %}\documentclass{SciPost}
+
+% Prevent all line breaks in inline equations.
+\binoppenalty=10000
+\relpenalty=10000
+
+\hypersetup{
+    colorlinks,
+    linkcolor={red!50!black},
+    citecolor={blue!50!black},
+    urlcolor={blue!80!black}
+}
+
+\usepackage[bitstream-charter]{mathdesign}
+\urlstyle{sf}
+
+\fancypagestyle{SPstyle}{
+\fancyhf{}
+\lhead{\raisebox{-1.5mm}[0pt][0pt]{\href{https://scipost.org}{\includegraphics[width=20mm]{logo_scipost_with_bgd.pdf}}}}
+
+{% if report.doi_string %}
+    \rhead{\small \href{https://scipost.org{{report.doi_string|safe_tex_url}} }{ {{report.doi_string|safe_tex_url}} ({{report.date_submitted|date:'Y'}})}}
+{% endif %}
+
+\renewcommand{\headrulewidth}{1pt}
+\fancyfoot[C]{\textbf{\thepage}}
+}
+
+\begin{document}
+
+\pagestyle{SPstyle}
+
+\begin{center}
+\Large\color{scipostdeepblue}{\textbf{
+%%%%%%%%%% TITLE
+Report {{report.report_nr}} on\href{https://scipost.org{{report.get_absolute_url|safe_tex_url}} }{\color{scipostdeepblue}{ {{report.submission.title}} }}by {{report.submission.author_list}}
+}}
+\end{center}
+
+\begin{center}
+\large\textbf{
+%%%%%%%%%% AUTHORS
+Report by {% if report.anonymous %}anonymous{% else %}{{report.author.user.first_name}} {{report.author.user.last_name}}\textsuperscript{1}{% endif %}
+}
+\end{center}
+
+{% if not report.anonymous %}
+    \begin{center}
+    %%%%%%%%%% AFFILIATIONS
+    {\bf 1} {{report.author.affiliation}}\\
+    \end{center}
+{% endif %}
+
+
+\vspace{10pt}
+
+
+\begin{center}
+\begin{tabular}{lr}
+\begin{minipage}{0.5\textwidth}
+\raisebox{-1mm}[0pt][0pt]{\includegraphics[width=12mm]{by.eps}}
+
+%%%%%%%%%% COPYRIGHT
+
+{\small Copyright {% if report.anonymous %}anonymous{% else %}{{report.author.user.first_name}} {{report.author.user.last_name}}{% endif %}. \newline
+
+This work is licensed under the Creative Commons \newline
+\href{http://creativecommons.org/licenses/by/4.0/}{Attribution 4.0 International License}. \newline
+Published by the SciPost Foundation.
+}
+\end{minipage}
+&
+\begin{minipage}{0.5\textwidth}
+%%%%%%%%%% DATES
+{\small Received {{report.date_submitted|date:'d-m-Y'}}
+{% if report.doi_string %}
+    doi:\href{//dx.doi.org{{report.doi_string|safe_tex_url}} }{ {{report.doi_string|safe_tex_url}} }
+{% endif %}
+}
+\end{minipage}
+\end{tabular}
+\end{center}
+
+\vspace{10pt}
+\noindent\rule{\textwidth}{1pt}
+
+%%%%%%%% CONTENTS
+
+\section*{Ratings}
+\begin{center}
+\begin{tabular}{r p{0.15\columnwidth} r l}
+	{\bf Validity} & {{report.get_validity_display}} & {\bf Clarity} & {{report.get_clarity_display}} \\
+	{\bf Significance} & {{report.get_significance_display}} & {\bf Formatting} & {{report.get_formatting_display}} \\
+	{\bf Originality} & {{report.get_originality_display}} & {\bf Grammar} & {{report.get_grammar_display}}
+\end{tabular}
+\end{center}
+
+\section{Strengths}
+{{report.strengths|linebreaktex}}
+
+\section{Weaknesses}
+{{report.weaknesses|linebreaktex}}
+
+\section{Report}
+{{report.report|linebreaktex}}
+
+
+\section{Requested changes}
+{{report.requested_changes|linebreaktex}}
+
+
+\end{document}
diff --git a/submissions/templates/submissions/_single_public_report.html b/submissions/templates/submissions/_single_public_report.html
index a733936561c287c2c8b5ccf6f579efe52b20fd56..efdc5c5144fb7f7dde0959338e2d3c9b751582b4 100644
--- a/submissions/templates/submissions/_single_public_report.html
+++ b/submissions/templates/submissions/_single_public_report.html
@@ -1,10 +1,12 @@
 {% extends 'submissions/_single_public_report_without_comments.html' %}
 
 {% block single_report_footer %}
-    <hr class="small">
-    <h3><a href="{% url 'comments:reply_to_report' report_id=report.id %}">Reply to this Report</a> (authors only)</h3>
+    {% if user.is_authenticated and perms.scipost.can_submit_comments %}
+        <hr class="small">
+        <h3><a href="{% url 'comments:reply_to_report' report_id=report.id %}">Reply to this Report</a> (authors only)</h3>
+    {% endif %}
 
-    {% for reply in report.comment_set.vetted %}
+    {% for reply in report.comments.vetted %}
         {% include 'comments/_single_comment_with_link.html' with comment=reply perms=perms user=user %}
     {% endfor %}
 {% endblock %}
diff --git a/submissions/templates/submissions/_single_public_report_without_comments.html b/submissions/templates/submissions/_single_public_report_without_comments.html
index f39932745a139ece5d79a744868724e0bf1945f8..289f2169d1d34bc4bd64517f86e2dea2d29ff11e 100644
--- a/submissions/templates/submissions/_single_public_report_without_comments.html
+++ b/submissions/templates/submissions/_single_public_report_without_comments.html
@@ -3,13 +3,19 @@
 
 <div class="row">
     <div class="col-12">
-        <div class="report">
+        <div class="report" id="report_{{report.report_nr}}">
             {% if user.contributor == submission.editor_in_charge or user|is_in_group:'Editorial Administrators' and user|is_not_author_of_submission:submission.arxiv_identifier_w_vn_nr %}
 
                 <div class="reportid">
-                    <h3>{% if report.anonymous %}(chose public anonymity) {% endif %}<a href="{% url 'scipost:contributor_info' report.author.id %}">{{ report.author.user.first_name }} {{ report.author.user.last_name }}</a>
+                    <h3>{% if report.anonymous %}(chose public anonymity) {% endif %}<a href="{{report.author.get_absolute_url}}">{{ report.author.user.first_name }} {{ report.author.user.last_name }}</a>
                         on {{ report.date_submitted|date:'Y-n-j' }}</h3>
                     </h3>
+                    {% if report.pdf_report %}
+                        <a href="{% url 'submissions:report_detail_pdf' report.submission.arxiv_identifier_w_vn_nr report.report_nr %}" target="_blank">Download as PDF</a>
+                    {% endif %}
+                    {% if perms.scipost.can_manage_reports %}
+                        {% if report.pdf_report %}&middot; {% endif %}<a href="{% url 'submissions:report_pdf_compile' report.id %}">Update/Compile the Report pdf</a>
+                    {% endif %}
                 </div>
 
                 {% if report.flagged %}
@@ -40,9 +46,15 @@
                 </div>
             {% else %}
                 <div class="reportid">
-                    <h3 id="report_id{{report.id}}">{% if report.anonymous %}Anonymous Report {{report.id}}{% else %}<a href="{% url 'scipost:contributor_info' report.author.id %}">{{ report.author.user.first_name }} {{ report.author.user.last_name }}</a>{% endif %}
+                    <h3>{% if report.anonymous %}Anonymous Report {{report.report_nr}}{% else %}<a href="{{report.author.get_absolute_url}}">{{ report.author.user.first_name }} {{ report.author.user.last_name }}</a>{% endif %}
                         on {{ report.date_submitted|date:'Y-n-j' }}</h3>
                     </h3>
+                    {% if report.pdf_report %}
+                        <a href="{% url 'submissions:report_detail_pdf' report.submission.arxiv_identifier_w_vn_nr report.report_nr %}" target="_blank">Download as PDF</a>
+                    {% endif %}
+                    {% if perms.scipost.can_manage_reports %}
+                        {% if report.pdf_report %}&middot; {% endif %}<a href="{% url 'submissions:report_pdf_compile' report.id %}">Update/Compile the Report pdf</a>
+                    {% endif %}
                 </div>
 
                 {% include 'submissions/_single_report_content.html' with report=report %}
diff --git a/submissions/templates/submissions/_single_report_card_summary.html b/submissions/templates/submissions/_single_report_card_summary.html
new file mode 100644
index 0000000000000000000000000000000000000000..e0f9fb2fe14cf4714659a4fde5045bc15771d5eb
--- /dev/null
+++ b/submissions/templates/submissions/_single_report_card_summary.html
@@ -0,0 +1,5 @@
+<div class="card-block {% block cardblock_class_block %}{% endblock %}">
+    <h3>{{report.get_status_display}} Report {{report.report_nr}} by {% if report.anonymous %}<em>anonymous</em>{% else %}<a href="{{report.author.get_absolute_url}}">{{ report.author.user.first_name }} {{ report.author.user.last_name }}</a>{% endif %}</h3>
+    <h4>Received: {{ report.date_submitted|date:'Y-n-j' }}</h4>
+    On Submission: <a href="{{report.submission.get_absolute_url}}">{{report.submission}}</a>
+</div>
diff --git a/submissions/templates/submissions/_submission_refereeing_status.html b/submissions/templates/submissions/_submission_refereeing_status.html
index 50066b96f9b564b3e9d18b1dc24d191c56e922f6..5d1ea7b1d2c3baea8d9b6efab91ba7bc895382c8 100644
--- a/submissions/templates/submissions/_submission_refereeing_status.html
+++ b/submissions/templates/submissions/_submission_refereeing_status.html
@@ -1,6 +1,6 @@
 {% if submission.refereeing_cycle != 'direct_rec' %}
     <div class="card-block">
         <p class="card-text">Nr referees invited: {{submission.referee_invitations.count}} <span>[{{submission.count_accepted_invitations}} acccepted / {{submission.count_declined_invitations}} declined / {{submission.count_pending_invitations}} response pending]</span></p>
-        <p class="card-text">Nr reports obtained: {{submission.count_obtained_reports}} [{{submission.count_invited_reports}} invited / {{submission.count_contrib_reports}} contributed], nr refused: {{submission.count_refused_reports}}, nr awaiting vetting: {{submission.count_awaiting_vetting}}</p>
+        <p class="card-text">Nr reports obtained: {{submission.count_obtained_reports}} [{{submission.count_invited_reports}} invited / {{submission.count_contrib_reports}} contributed], nr refused: {{submission.reports.rejected.count}}, nr awaiting vetting: {{submission.reports.awaiting_vetting.count}}</p>
     </div>
 {% endif %}
diff --git a/submissions/templates/submissions/_submission_summary.html b/submissions/templates/submissions/_submission_summary.html
index 334f2d67912757293c26183e4412ee0e8f6d1601..613cc023ff67d310dc160c307b72ce562be694b6 100644
--- a/submissions/templates/submissions/_submission_summary.html
+++ b/submissions/templates/submissions/_submission_summary.html
@@ -1,6 +1,11 @@
 {% extends 'submissions/_submission_summary_short.html' %}
 
 {% block submission_summary_footer %}
+    {% if submission.pdf_refereeing_pack %}
+        <p class="mt-3">
+            <a href="{% url 'submissions:refereeing_package_pdf' submission.arxiv_identifier_w_vn_nr %}" target="_blank" class="btn btn-outline-primary">Download Refereeing Package</a>
+        </p>
+    {% endif %}
     <h3 class="mt-3">Abstract</h3>
     <p>{{submission.abstract}}</p>
 {% endblock %}
diff --git a/submissions/templates/submissions/_submission_summary_short.html b/submissions/templates/submissions/_submission_summary_short.html
index fc5176d60f740db8048110ff0f11229588091490..ce30c5cbbd34f9fa8d6ba3186606ebeb71e5b004 100644
--- a/submissions/templates/submissions/_submission_summary_short.html
+++ b/submissions/templates/submissions/_submission_summary_short.html
@@ -19,7 +19,7 @@
     </tr>
 
     <tr>
-        <td>arxiv Link:</td>
+        <td>Arxiv Link:</td>
         <td>
             <a href="{{submission.arxiv_link}}" target="_blank">{{submission.arxiv_link}}</a>
         </td>
diff --git a/submissions/templates/submissions/editorial_page.html b/submissions/templates/submissions/editorial_page.html
index c2a20c722a204e2b42e55e0f762038b6af899185..65a024d1e8dcdf5ecf47910a1fd5f345f84e2845 100644
--- a/submissions/templates/submissions/editorial_page.html
+++ b/submissions/templates/submissions/editorial_page.html
@@ -26,10 +26,10 @@
                 <p class="card-text">(go to the <a href="{% url 'submissions:submission' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}">Submissions Page</a> to view Reports and Comments)</h3>
             </div>
         </div>
-        {% if other_versions %}
+        {% if submission.other_versions %}
             <h3>Other versions of this Submission exist:</h3>
             <div class="pl-4">
-                {% for vn in other_versions %}
+                {% for vn in submission.other_versions %}
                     {% include 'submissions/_submission_version.html' with submission=vn %}
                 {% endfor %}
             </div>
@@ -71,24 +71,22 @@
     </div>
 </div>
 
-{% if recommendation %}
-    <div class="row">
-        <div class="col-12">
-            <div class="card card-outline-secondary">
-                {% include 'submissions/_recommendation_author_content.html' with recommendation=recommendation %}
+{% with recommendation as submission.eicrecommendations.first %}
+    {% if recommendation %}
+        <div class="row">
+            <div class="col-12">
+                <div class="card card-outline-secondary">
+                    {% include 'submissions/_recommendation_author_content.html' with recommendation=recommendation %}
+                </div>
             </div>
         </div>
-    </div>
-{% endif %}
+    {% endif %}
+{% endwith %}
 
-<div class="row">
-    <div class="col-12">
-        <div class="card card-grey">
-            <div class="card-block">
-                <h1 class="card-title">Editorial Workflow</h1>
-                <a href="{% url 'submissions:editorial_workflow' %}">How-to guide: summary of the editorial workflow</a>
-            </div>
-        </div>
+<div class="card card-grey my-4">
+    <div class="card-block">
+        <h2 class="card-title">Editorial Workflow</h2>
+        <a href="{% url 'submissions:editorial_workflow' %}">How-to guide: summary of the editorial workflow</a>
     </div>
 </div>
 
@@ -111,7 +109,6 @@
         </div>
     </div>
 {% else %}
-
     {% if submission.refereeing_cycle != 'direct_rec' %}
         <div class="row">
             <div class="col-12">
@@ -123,7 +120,7 @@
         <div class="row">
             <div class="col-12">
                 <h3 class="mb-2">Detail of refereeing invitations:</h3>
-                {% include 'submissions/_submission_refereeing_invitations.html' with submission=submission invitations=ref_invitations %}
+                {% include 'submissions/_submission_refereeing_invitations.html' with submission=submission invitations=submission.referee_invitations.all %}
             </div>
         </div>
     {% endif %}
@@ -148,7 +145,7 @@
 
     <div class="row">
         <div class="col-12">
-            <h3>Actions:</h3>
+            <h2 class="mt-3">Actions</h2>
                 <ul>
                     {% if submission.refereeing_cycle != 'direct_rec' %}
                         <li>
@@ -173,7 +170,36 @@
                                 </div>
                             </form>
                         </li>
-                        <li><a href="{% url 'submissions:vet_submitted_reports' %}">Vet submitted Reports</a> ({{ nr_reports_to_vet }})</li>
+                        {% with submission.reports.awaiting_vetting as reports %}
+                            {% if reports %}
+                                <li>
+                                    Vet submitted Report{{reports|pluralize}}:
+                                    <ul class="mb-1">
+                                        {% for report in reports %}
+                                            <li><a href="{% url 'submissions:vet_submitted_report' report.id %}">{{report}}</a></li>
+                                        {% endfor %}
+                                    </ul>
+                                </li>
+                            {% else %}
+                                <li>All Reports have been vetted.</li>
+                            {% endif %}
+                        {% endwith %}
+
+                        {% with submission.comments_set_complete.awaiting_vetting as comments %}
+                            {% if comments %}
+                                <li>
+                                    Vet submitted Comment{{comments|pluralize}}:
+                                    <ul class="mb-1">
+                                        {% for comment in comments %}
+                                            <li><a href="{% url 'comments:vet_submitted_comment' comment.id %}">{{comment}}</a></li>
+                                        {% endfor %}
+                                    </ul>
+                                </li>
+                            {% else %}
+                                <li>All Comments have been vetted.</li>
+                            {% endif %}
+                        {% endwith %}
+
                         {% if not submission.reporting_deadline_has_passed %}
                             <li><a href="{% url 'submissions:close_refereeing_round' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}">Close the refereeing round</a> &nbsp;(deactivates submission of new Reports and Comments)</li>
                         {% endif %}
@@ -188,28 +214,29 @@
     </div>
 {% endif %}
 
-<div class="row">
-    <div class="col-12">
-        <h1 class="highlight">Communications</h1>
-        <ul>
-            <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='EtoA' %}">Draft and send a communication with the submitting Author</a></li>
-            <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='EtoS' %}">Draft and send a communication with SciPost Editorial Administration</a></li>
-        </ul>
-    </div>
-</div>
+<h2 class="mt-3">Communications</h2>
+<ul>
+    <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='EtoA' %}">Draft and send a communication with the submitting Author</a></li>
+    <li><a href="{% url 'submissions:communication' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr comtype='EtoS' %}">Draft and send a communication with SciPost Editorial Administration</a></li>
+</ul>
 
 <div class="row">
     <div class="col-12">
-        <ul class="list-group list-group-flush">
-            {% for comm in communications %}
-                <li class="list-group-item">
-                    {% include 'submissions/_editorial_communication_content.html' with communication=comm %}
-                </li>
-            {% empty %}
-                <li class="list-group-item">There have been no communications for this Submission.</li>
-            {% endfor %}
-        </ul>
+            <ul class="list-group list-group-flush">
+                {% for comm in submission.editorial_communications.all %}
+                    <li class="list-group-item">
+                        {% include 'submissions/_editorial_communication_content.html' with communication=comm %}
+                    </li>
+                {% empty %}
+                    <li class="list-group-item">There have been no communications for this Submission.</li>
+                {% endfor %}
+            </ul>
     </div>
 </div>
 
+<h2 class="mt-3">Events</h2>
+{% include 'submissions/submission_event_list.html' with events=submission.events.for_eic %}
+
+
+<div class="mb-5"></div>
 {% endblock content %}
diff --git a/submissions/templates/submissions/latest_events.html b/submissions/templates/submissions/latest_events.html
new file mode 100644
index 0000000000000000000000000000000000000000..3025ec20dc1effe510f5e3693f80f6ec18700a20
--- /dev/null
+++ b/submissions/templates/submissions/latest_events.html
@@ -0,0 +1,26 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Latest events{% endblock pagetitle %}
+
+{% load scipost_extras %}
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="javascript:;" class="breadcrumb-item">Admin</a>
+    <span class="breadcrumb-item">All events in the last 24 hours</span>
+{% endblock %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1>All events in the last 24 hours</h1>
+        <h2 class="text-warning">Submission Events are under construction. Please note this list may not be complete!</h2>
+        <div class="ml-md-5 mt-5">{% include 'submissions/submission_event_list_general.html' with events=events %}</div>
+    </div>
+</div>
+
+
+
+{% endblock content %}
diff --git a/submissions/templates/submissions/reports_accepted_list.html b/submissions/templates/submissions/reports_accepted_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..b4a2ff77d264bdbcf7531ec7d39e47e39e15573b
--- /dev/null
+++ b/submissions/templates/submissions/reports_accepted_list.html
@@ -0,0 +1,54 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <span class="breadcrumb-item">Accepted Reports</span>
+{% endblock %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}: Accepted Reports{% endblock pagetitle %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Accepted Reports</h1>
+    </div>
+</div>
+
+<div class="row">
+    <div class="col-12">
+        <table class="table">
+            <thead>
+                <tr>
+                    <th>Report nr. of Submission</th>
+                    <th>Submission</th>
+                    <th>Report author</th>
+                    <th>Has PDF</th>
+                    <th>Action</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for report in reports %}
+                    <tr{% if not report.pdf_report %} class="table-danger"{% endif %}>
+                        <td>{{report.report_nr}}</td>
+                        <td><a href="{{report.get_absolute_url}}">{{report.submission.arxiv_identifier_w_vn_nr}}</a></td>
+                        <td>{% if report.anonymous %}<em>Anonymous</em>{% else %}{{report.author}}{% endif %}</td>
+                        <td>
+                            {{report.pdf_report|yesno:"Yes,No"}}
+                            {% if report.pdf_report %}
+                                &middot; <a href="{% url 'submissions:report_detail_pdf' report.submission.arxiv_identifier_w_vn_nr report.report_nr %}" target="_blank">Download</a>
+                            {% endif %}
+                        </td>
+                        <td>
+                            <a href="{% url 'submissions:report_pdf_compile' report.id %}">Compile/upload report</a>
+                        </td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/submissions/templates/submissions/reports_pdf_compile.html b/submissions/templates/submissions/reports_pdf_compile.html
new file mode 100644
index 0000000000000000000000000000000000000000..bf46e0b6860c836b3d5a3c7d843508ea94253412
--- /dev/null
+++ b/submissions/templates/submissions/reports_pdf_compile.html
@@ -0,0 +1,74 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Upload Report PDF{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="{% url 'submissions:reports_accepted_list' %}" class="breadcrumb-item">Accepted Reports</a>
+    <span class="breadcrumb-item">Upload Report PDF</span>
+{% endblock %}
+
+{% block content %}
+
+    <div class="row">
+        <div class="col-12">
+            <h1 class="highlight">Upload Report PDF</h1>
+            <div class="card">
+                {% include 'submissions/_single_report_card_summary.html' with submission=report %}
+            </div>
+        </div>
+    </div>
+
+    <div class="row">
+        <div class="col-12">
+            <h3>Please process this code in your Tex Compiler:</h3>
+            <p>To compile, one needs the SciPost Latex Package. Please <a href="mailto: info@scipost.org">contact SciPost</a> if you did not receive it.</p>
+            <pre class="clickfocus" style="max-height: 200px;"><code>{% include 'submissions/_report_tex_template.html' with report=report %}</code></pre>
+        </div>
+    </div>
+
+
+    <div class="row">
+        <div class="col-12">
+          <form method="post" enctype="multipart/form-data">
+            {% csrf_token %}
+            {{ form|bootstrap }}
+            <input class="btn btn-secondary" type="submit" value="Upload"/>
+          </form>
+        </div>
+    </div>
+
+<script>
+    jQuery.fn.selectText = function(){
+        this.find('input').each(function() {
+            if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) {
+                $('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
+            }
+            $(this).prev().html($(this).val());
+        });
+        var doc = document;
+        var element = this[0];
+
+        if (doc.body.createTextRange) {
+            var range = document.body.createTextRange();
+            range.moveToElementText(element);
+            range.select();
+        } else if (window.getSelection) {
+            var selection = window.getSelection();
+            var range = document.createRange();
+            range.selectNodeContents(element);
+            selection.removeAllRanges();
+            selection.addRange(range);
+        }
+    };
+
+    $(function() {
+        $('.clickfocus').on('click', function() {
+            $(this).find('code').selectText();
+        });
+    });
+</script>
+
+{% endblock %}
diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html
index 02fc58b1c97ee3fe9b5db68eb7f8626e273b7e9f..30dfc87d14ac396c07fe22a56c85c5eec00b6d76 100644
--- a/submissions/templates/submissions/submission_detail.html
+++ b/submissions/templates/submissions/submission_detail.html
@@ -6,24 +6,12 @@
 
 {% load scipost_extras %}
 {% load submissions_extras %}
-{% load filename %}
-{% load file_extentions %}
 
   <script>
     $(document).ready(function(){
-
-    var comment_text_input = $("#id_comment_text");
-
-    function set_comment_text(value) {
-      $("#preview-comment_text").text(value)
-    }
-    set_comment_text(comment_text_input.val())
-
-    comment_text_input.keyup(function(){
-      var new_text = $(this).val()
-      set_comment_text(new_text)
-      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
-    })
+        $("#invitedreportsbutton").click(function(){
+            $("#invitedreportslist").toggle();
+        });
 
     });
   </script>
@@ -47,10 +35,10 @@
             </div>
         </div>
 
-        {% if other_versions %}
+        {% if submission.other_versions %}
             <h3>Other versions of this Submission (with Reports) exist:</h3>
             <div class="pl-4">
-                {% for vn in other_versions %}
+                {% for vn in submission.other_versions %}
                     {% include 'submissions/_submission_version.html' with submission=vn %}
                 {% endfor %}
             </div>
@@ -98,6 +86,14 @@
             </div>
         {% endif %}
     {% endif %}
+
+    <div class="mb-4">
+        <h2>Events</h2>
+        <a href="javascript:;" data-toggle="toggle" data-target="#eventslist">Show/hide events</a>
+        <div id="eventslist">
+            {% include 'submissions/submission_event_list.html' with events=submission.events.for_author %}
+        </div>
+    </div>
 {% endif %}
 
 
@@ -132,6 +128,14 @@
                 <li>Commenting on this Submission is closed.</li>
             {% endif %}
         </ul>
+        {% if perms.scipost.can_manage_reports %}
+            <h3>Admin Actions</h3>
+            <ul>
+                <li>
+                    <a href="{% url 'submissions:treated_submission_pdf_compile' submission.arxiv_identifier_w_vn_nr %}">Update the Refereeing Package pdf</a>
+                </li>
+            <ul>
+        {% endif %}
     </div>
 </div>
 {% endif %}
@@ -178,7 +182,7 @@
 
 {% endif %}
 
-{% include 'scipost/comments_block.html' %}
+{% include 'scipost/comments_block.html' with comments=submission.comments.vetted %}
 
 {% include 'comments/new_comment.html' with object_id=submission.id type_of_object='submission' open_for_commenting=submission.open_for_commenting %}
 
diff --git a/submissions/templates/submissions/submission_event_list.html b/submissions/templates/submissions/submission_event_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..01e3d1b2dad54dc98a151d7ca30b49035114e786
--- /dev/null
+++ b/submissions/templates/submissions/submission_event_list.html
@@ -0,0 +1,16 @@
+<div class="row">
+    <div class="col-12">
+            <ul class="list-group list-group-flush events-list">
+                {% for event in events %}
+                    <li class="list-group-item">
+                        <div>
+                            {{event.text}}<br>
+                            <span class="text-muted">{{event.created}}</span>
+                        </div>
+                    </li>
+                {% empty %}
+                    <li class="list-group-item">There have been no events for this Submission.</li>
+                {% endfor %}
+            </ul>
+    </div>
+</div>
diff --git a/submissions/templates/submissions/submission_event_list_general.html b/submissions/templates/submissions/submission_event_list_general.html
new file mode 100644
index 0000000000000000000000000000000000000000..a9d0b0d84d32f1fbf8845d4150b2e441d230c82a
--- /dev/null
+++ b/submissions/templates/submissions/submission_event_list_general.html
@@ -0,0 +1,17 @@
+<div class="row">
+    <div class="col-12">
+            <ul class="list-group list-group-flush events-list">
+                {% for event in events %}
+                    <li class="list-group-item">
+                        <div>
+                            <strong>{{event.text}}</strong><br>
+                            Submission: <a href="{{event.submission.get_absolute_url}}">{{event.submission.title}} ({{event.submission.arxiv_identifier_w_vn_nr}})</a><br>
+                            <span class="text-muted">{{event.created}}</span>
+                        </div>
+                    </li>
+                {% empty %}
+                    <li class="list-group-item">No events found.</li>
+                {% endfor %}
+            </ul>
+    </div>
+</div>
diff --git a/submissions/templates/submissions/treated_submission_pdf_compile.html b/submissions/templates/submissions/treated_submission_pdf_compile.html
new file mode 100644
index 0000000000000000000000000000000000000000..19e456fefbb06e35c872c25f1cc8c53e0020ea62
--- /dev/null
+++ b/submissions/templates/submissions/treated_submission_pdf_compile.html
@@ -0,0 +1,82 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block pagetitle %}: Upload Submission Refereeing PDF{% endblock pagetitle %}
+
+{% load bootstrap %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <a href="{% url 'submissions:treated_submissions_list' %}" class="breadcrumb-item">Treated Submissions</a>
+    <span class="breadcrumb-item">Upload Submission Refereeing PDF</span>
+{% endblock %}
+
+{% block content %}
+
+    <div class="row">
+        <div class="col-12">
+            <h1 class="highlight">Upload Submission Refereeing PDF</h1>
+            {% include 'submissions/_submission_summary_short.html' with submission=submission %}
+            <p class="my-2"><a href="{{submission.get_absolute_url}}">Go to Submission page</a></p>
+        </div>
+    </div>
+    <hr>
+
+    <div class="row">
+        <div class="col-12">
+            <h3>Please process this code in your Tex Compiler</h3>
+            <p>
+                You may need to compile twice because of the Table of Content.<br>
+                To compile, one needs the SciPost Latex Package. Please <a href="mailto: info@scipost.org">contact SciPost</a> if you did not receive it.
+            </p>
+            <h3>Content of the Refereeing Package</h3>
+            <p>
+                Number of Reports: {{submission.reports.accepted.count}}<br>
+                Number of Comments <small>(nested comments not counted)</small>: {{submission.comments.vetted.count}}
+            </p>
+            <pre class="clickfocus" style="max-height: 200px;"><code>{% include 'submissions/_refereeing_pack_tex_template.html' with submission=submission %}</code></pre>
+        </div>
+    </div>
+
+
+    <div class="row">
+        <div class="col-12">
+          <form method="post" enctype="multipart/form-data">
+            {% csrf_token %}
+            {{ form|bootstrap }}
+            <input class="btn btn-secondary" type="submit" value="Upload"/>
+          </form>
+        </div>
+    </div>
+
+<script>
+    jQuery.fn.selectText = function(){
+        this.find('input').each(function() {
+            if($(this).prev().length == 0 || !$(this).prev().hasClass('p_copy')) {
+                $('<p class="p_copy" style="position: absolute; z-index: -1;"></p>').insertBefore($(this));
+            }
+            $(this).prev().html($(this).val());
+        });
+        var doc = document;
+        var element = this[0];
+
+        if (doc.body.createTextRange) {
+            var range = document.body.createTextRange();
+            range.moveToElementText(element);
+            range.select();
+        } else if (window.getSelection) {
+            var selection = window.getSelection();
+            var range = document.createRange();
+            range.selectNodeContents(element);
+            selection.removeAllRanges();
+            selection.addRange(range);
+        }
+    };
+
+    $(function() {
+        $('.clickfocus').on('click', function() {
+            $(this).find('code').selectText();
+        });
+    });
+</script>
+
+{% endblock %}
diff --git a/submissions/templates/submissions/treated_submissions_list.html b/submissions/templates/submissions/treated_submissions_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..c9b167bd9832f074302c794376cfd497b0413f2c
--- /dev/null
+++ b/submissions/templates/submissions/treated_submissions_list.html
@@ -0,0 +1,56 @@
+{% extends 'scipost/_personal_page_base.html' %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <span class="breadcrumb-item">Treated Submissions</span>
+{% endblock %}
+
+{% load bootstrap %}
+
+{% block pagetitle %}: Treated Submissions{% endblock pagetitle %}
+
+{% block content %}
+
+<div class="row">
+    <div class="col-12">
+        <h1 class="highlight">Treated Submissions</h1>
+    </div>
+</div>
+
+<div class="row">
+    <div class="col-12">
+        <table class="table">
+            <thead>
+                <tr>
+                    <th>Submission</th>
+                    <th>Status</th>
+                    <th>Accepted</th>
+                    <th>Number of Reports</th>
+                    <th>Has PDF</th>
+                    <th>Action</th>
+                </tr>
+            </thead>
+            <tbody>
+                {% for submission in submissions %}
+                    <tr{% if not submission.pdf_refereeing_pack %} class="table-danger"{% endif %}>
+                        <td><a href="{{submission.get_absolute_url}}">{{submission.arxiv_identifier_w_vn_nr}}</a></td>
+                        <td>{{submission.get_status_display}}</td>
+                        <td>{{submission.acceptance_date|default_if_none:'Date unknown'}}</td>
+                        <td>{{submission.reports.accepted.count}}</td>
+                        <td>
+                            {{submission.pdf_refereeing_pack|yesno:"Yes,No"}}
+                            {% if submission.pdf_refereeing_pack %}
+                                &middot; <a href="{% url 'submissions:refereeing_package_pdf' submission.arxiv_identifier_w_vn_nr %}" target="_blank">Download</a>
+                            {% endif %}
+                        </td>
+                        <td>
+                            <a href="{% url 'submissions:treated_submission_pdf_compile' submission.arxiv_identifier_w_vn_nr %}">Compile/upload Refereeing Package</a>
+                        </td>
+                    </tr>
+                {% endfor %}
+            </tbody>
+        </table>
+    </div>
+</div>
+
+{% endblock %}
diff --git a/submissions/templates/submissions/vet_submitted_reports.html b/submissions/templates/submissions/vet_submitted_report.html
similarity index 94%
rename from submissions/templates/submissions/vet_submitted_reports.html
rename to submissions/templates/submissions/vet_submitted_report.html
index fe836e110153068f104f1ca0bee21dae20872f6f..64d36c03c9b7da45bd3285c4f4383d5bf3334f7f 100644
--- a/submissions/templates/submissions/vet_submitted_reports.html
+++ b/submissions/templates/submissions/vet_submitted_report.html
@@ -23,7 +23,7 @@ $(document).ready(function(){
 
 {% block breadcrumb_items %}
     {{block.super}}
-    <span class="breadcrumb-item">Vet Reports</span>
+    <span class="breadcrumb-item">Vet Report {{report.report_nr}}</span>
 {% endblock %}
 
 {% block content %}
@@ -49,7 +49,7 @@ $(document).ready(function(){
 
             <hr class="small">
             <h2>Please vet this Report:</h2>
-            <form action="{% url 'submissions:vet_submitted_reports' %}" method="post">
+            <form action="{% url 'submissions:vet_submitted_report' report_to_vet.id %}" method="post">
                 {% csrf_token %}
                 {{ form.report }}
                 {{ form.action_option|bootstrap }}
diff --git a/submissions/templates/submissions/vet_submitted_reports_list.html b/submissions/templates/submissions/vet_submitted_reports_list.html
new file mode 100644
index 0000000000000000000000000000000000000000..44697fdc21432a4a36b1278ec934c860a152b40f
--- /dev/null
+++ b/submissions/templates/submissions/vet_submitted_reports_list.html
@@ -0,0 +1,40 @@
+{% extends 'submissions/_pool_base.html' %}
+
+{% block pagetitle %}: vet reports{% endblock pagetitle %}
+
+{% block breadcrumb_items %}
+    {{block.super}}
+    <span class="breadcrumb-item">Vet Reports</span>
+{% endblock %}
+
+{% block content %}
+
+<h1>SciPost Reports to vet</h1>
+
+{% if reports_to_vet %}
+    <table class="table mt-4">
+        <thead>
+            <th>Report #</th>
+            <th>For submission</th>
+            <th>Submitted</th>
+            <th>Actions</th>
+        </thead>
+        <tbody>
+            {% for report in reports_to_vet %}
+                <tr>
+                    <td>{{report.report_nr}}</td>
+                    <td>{{report.submission.title}} ({{report.submission.arxiv_identifier_w_vn_nr}})</td>
+                    <td>{{report.date_submitted|timesince}} ago</td>
+                    <td><a href="{% url 'submissions:vet_submitted_report' report.id  %}">Go to vetting page</a></td>
+                </tr>
+            {% endfor %}
+        </tbody>
+    </table>
+{% else %}
+    <h2 class="mt-3">There are no Reports for you to vet.</h2>
+    <p>Go back to my <a href="{% url 'scipost:personal_page' %}">personal page</a>.</p>
+{% endif %}
+
+<div class="mb-5"></div>
+
+{% endblock content %}
diff --git a/submissions/templatetags/lookup.py b/submissions/templatetags/lookup.py
index 803edd8acbd338d2202c2c1666955ac082787673..c2f7e549124208067d554ffd7ce304d5f8758ae2 100644
--- a/submissions/templatetags/lookup.py
+++ b/submissions/templatetags/lookup.py
@@ -8,7 +8,7 @@ class SubmissionLookup(LookupChannel):
 
     def get_query(self, q, request):
         return (self.model.objects
-                .public()
+                .public_unlisted()
                 .order_by('-submission_date')
                 .filter(title__icontains=q)
                 .prefetch_related('publication')[:10])
diff --git a/submissions/urls.py b/submissions/urls.py
index 6e776fcf71b60a8500c7f7fc8657ac7eb0f9e8e2..8aaf200ee76128fc26c635f54bed0c6b6e93402e 100644
--- a/submissions/urls.py
+++ b/submissions/urls.py
@@ -18,6 +18,20 @@ urlpatterns = [
         name='submission_wo_vn_nr'),
     url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/$',
         views.submission_detail, name='submission'),
+    url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/(?P<report_nr>[0-9]+)/pdf$',
+        views.report_detail_pdf, name='report_detail_pdf'),
+    url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/pdf$',
+        views.submission_refereeing_package_pdf, name='refereeing_package_pdf'),
+
+    # Editorial Administration
+    url(r'^admin/treated$', views.treated_submissions_list, name='treated_submissions_list'),
+    url(r'^admin/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/compile$',
+        views.treated_submission_pdf_compile, name='treated_submission_pdf_compile'),
+    url(r'^admin/events/latest$', views.latest_events, name='latest_events'),
+    url(r'^admin/reports$', views.reports_accepted_list, name='reports_accepted_list'),
+    url(r'^admin/reports/(?P<report_id>[0-9]+)/compile$',
+        views.report_pdf_compile, name='report_pdf_compile'),
+
     url(r'^submit_manuscript$', views.RequestSubmission.as_view(), name='submit_manuscript'),
     url(r'^submit_manuscript/prefill$', views.prefill_using_arxiv_identifier,
         name='prefill_using_identifier'),
@@ -26,6 +40,7 @@ urlpatterns = [
         views.submissions_by_status, name='submissions_by_status'),
     url(r'^add_remark/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$',
         views.add_remark, name='add_remark'),
+
     # Assignment of Editor-in-charge
     url(r'^assign_submission/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$',
         views.assign_submission, name='assign_submission'),
@@ -72,10 +87,14 @@ urlpatterns = [
         views.eic_recommendation, name='eic_recommendation'),
     url(r'^cycle/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/submit$',
         views.cycle_form_submit, name='cycle_confirmation'),
+
     # Reports
-    url(r'^submit_report/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$',
+    url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/submit$',
         views.submit_report, name='submit_report'),
-    url(r'^vet_submitted_reports$', views.vet_submitted_reports, name='vet_submitted_reports'),
+    url(r'^reports/vet$', views.vet_submitted_reports_list, name='vet_submitted_reports_list'),
+    url(r'^reports/(?P<report_id>[0-9]+)/vet$', views.vet_submitted_report,
+        name='vet_submitted_report'),
+
     # Voting
     url(r'^prepare_for_voting/(?P<rec_id>[0-9]+)$', views.prepare_for_voting, name='prepare_for_voting'),
     url(r'^vote_on_rec/(?P<rec_id>[0-9]+)$', views.vote_on_rec, name='vote_on_rec'),
diff --git a/submissions/utils.py b/submissions/utils.py
index 385dbfc3402e25ff730686360b4f49f6561e8428..8c79eb53ba19d360d087df6144b522977a7a35af 100644
--- a/submissions/utils.py
+++ b/submissions/utils.py
@@ -298,7 +298,6 @@ class SubmissionUtils(BaseMailUtil):
                        'Invitation on resubmission',
                        extra_bcc=extra_bcc_list)
 
-
     @classmethod
     def send_authors_submission_ack_email(cls):
         """ Requires loading 'submission' attribute. """
@@ -625,7 +624,6 @@ class SubmissionUtils(BaseMailUtil):
         emailmessage.attach_alternative(html_version, 'text/html')
         emailmessage.send(fail_silently=False)
 
-
     @classmethod
     def send_refereeing_invitation_email(cls):
         """
@@ -819,7 +817,6 @@ class SubmissionUtils(BaseMailUtil):
         emailmessage.attach_alternative(html_version, 'text/html')
         emailmessage.send(fail_silently=False)
 
-
     @classmethod
     def send_ref_reminder_email(cls):
         """
@@ -906,7 +903,6 @@ class SubmissionUtils(BaseMailUtil):
         emailmessage.attach_alternative(html_version, 'text/html')
         emailmessage.send(fail_silently=False)
 
-
     @classmethod
     def send_ref_cancellation_email(cls):
         """
diff --git a/submissions/views.py b/submissions/views.py
index 1a79b91960b01cd2ebe09b2246547f08d98faf40..61debe7ab40c73b50e08116e30397f41481f10f9 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -6,26 +6,28 @@ from django.contrib.auth.decorators import login_required, permission_required
 from django.contrib.auth.models import Group
 from django.core.urlresolvers import reverse, reverse_lazy
 from django.db import transaction
-from django.http import Http404, HttpResponseRedirect
+from django.http import Http404, HttpResponse, HttpResponseRedirect
 from django.shortcuts import get_object_or_404, render, redirect
 from django.template import Template, Context
 from django.utils import timezone
 from django.utils.decorators import method_decorator
+from django.views.generic.edit import CreateView
+from django.views.generic.list import ListView
 
 from guardian.decorators import permission_required_or_403
-from guardian.shortcuts import assign_perm
+from guardian.shortcuts import assign_perm, get_objects_for_user
 
 from .constants import SUBMISSION_STATUS_VOTING_DEPRECATED, STATUS_VETTED, STATUS_EIC_ASSIGNED,\
                        SUBMISSION_STATUS_PUBLICLY_INVISIBLE, SUBMISSION_STATUS, ED_COMM_CHOICES,\
                        STATUS_DRAFT
 from .models import Submission, EICRecommendation, EditorialAssignment,\
-                    RefereeInvitation, Report, EditorialCommunication
+                    RefereeInvitation, Report, EditorialCommunication, SubmissionEvent
 from .forms import SubmissionIdentifierForm, RequestSubmissionForm, SubmissionSearchForm,\
                    RecommendationVoteForm, ConsiderAssignmentForm, AssignSubmissionForm,\
                    SetRefereeingDeadlineForm, RefereeSelectForm, RefereeRecruitmentForm,\
                    ConsiderRefereeInvitationForm, EditorialCommunicationForm,\
                    EICRecommendationForm, ReportForm, VetReportForm, VotingEligibilityForm,\
-                   SubmissionCycleChoiceForm
+                   SubmissionCycleChoiceForm, ReportPDFForm, SubmissionReportsForm
 from .utils import SubmissionUtils
 
 from scipost.forms import ModifyPersonalMessageForm, RemarkForm
@@ -35,9 +37,6 @@ from scipost.utils import Utils
 from comments.forms import CommentForm
 from production.models import ProductionStream
 
-from django.views.generic.edit import CreateView
-from django.views.generic.list import ListView
-
 import strings
 
 
@@ -64,6 +63,9 @@ class RequestSubmission(CreateView):
     @transaction.atomic
     def form_valid(self, form):
         submission = form.save()
+        submission.add_general_event('The manuscript has been submitted to %s.'
+                                     % submission.get_submitted_to_journal_display())
+
         text = ('<h3>Thank you for your Submission to SciPost</h3>'
                 'Your Submission will soon be handled by an Editor.')
         messages.success(self.request, text)
@@ -120,7 +122,7 @@ class SubmissionListView(ListView):
     paginate_by = 10
 
     def get_queryset(self):
-        queryset = Submission.objects.public_overcomplete()
+        queryset = Submission.objects.public_newest()
         self.form = self.form(self.request.GET)
         if 'to_journal' in self.kwargs:
             queryset = queryset.filter(
@@ -187,9 +189,6 @@ def submission_detail(request, arxiv_identifier_w_vn_nr):
                                                          'Editorial College']).exists()
             and not is_author):
         raise Http404
-    other_versions = Submission.objects.filter(
-        arxiv_identifier_wo_vn_nr=submission.arxiv_identifier_wo_vn_nr
-    ).exclude(pk=submission.id)
 
     form = CommentForm()
 
@@ -207,7 +206,6 @@ def submission_detail(request, arxiv_identifier_w_vn_nr):
         recommendation = None
 
     context = {'submission': submission,
-               'other_versions': other_versions,
                'recommendation': recommendation,
                'comments': comments,
                'invited_reports': invited_reports,
@@ -220,6 +218,101 @@ def submission_detail(request, arxiv_identifier_w_vn_nr):
     return render(request, 'submissions/submission_detail.html', context)
 
 
+def report_detail_pdf(request, arxiv_identifier_w_vn_nr, report_nr):
+    """
+    Download the PDF of a Report if available.
+    """
+    report = get_object_or_404(Report.objects.accepted(),
+                               submission__arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr,
+                               pdf_report__isnull=False, report_nr=report_nr)
+    response = HttpResponse(report.pdf_report.read(), content_type='application/pdf')
+    filename = '%s_report-%i.pdf' % (report.submission.arxiv_identifier_w_vn_nr, report.report_nr)
+    response['Content-Disposition'] = ('filename=' + filename)
+    return response
+
+
+def submission_refereeing_package_pdf(request, arxiv_identifier_w_vn_nr):
+    """
+    This view let's the user download all Report PDF's in a single merged PDF.
+    The merging takes places every time its downloaded to make sure all available report PDF's
+    are included and the EdColAdmin doesn't have to compile the package every time again.
+    """
+    submission = get_object_or_404(Submission.objects.public().exclude(pdf_refereeing_pack=''),
+                                   arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
+    response = HttpResponse(submission.pdf_refereeing_pack.read(), content_type='application/pdf')
+    filename = '%s-refereeing-package.pdf' % submission.arxiv_identifier_w_vn_nr
+    response['Content-Disposition'] = ('filename=' + filename)
+    return response
+
+
+@permission_required('scipost.can_manage_reports', raise_exception=True)
+def reports_accepted_list(request):
+    """
+    This view lists all accepted Reports. This shows if Report needs a PDF update/compile
+    in a convenient way.
+    """
+    reports = (Report.objects.accepted()
+               .order_by('pdf_report', 'submission').prefetch_related('submission'))
+    context = {
+        'reports': reports
+    }
+    return render(request, 'submissions/reports_accepted_list.html', context)
+
+
+@permission_required('scipost.can_manage_reports', raise_exception=True)
+def report_pdf_compile(request, report_id):
+    report = get_object_or_404(Report.objects.accepted(), id=report_id)
+    form = ReportPDFForm(request.POST or None, request.FILES or None, instance=report)
+    if form.is_valid():
+        report = form.save()
+        messages.success(request, 'Upload complete.')
+        return redirect(reverse('submissions:reports_accepted_list'))
+    context = {
+        'report': report,
+        'form': form
+    }
+    return render(request, 'submissions/reports_pdf_compile.html', context)
+
+
+@permission_required('scipost.can_manage_reports', raise_exception=True)
+def treated_submissions_list(request):
+    """
+    This view lists all accepted Reports. This shows if Report needs a PDF update/compile
+    in a convenient way.
+    """
+    submissions = Submission.objects.treated().order_by('pdf_refereeing_pack', '-acceptance_date')
+    context = {
+        'submissions': submissions
+    }
+    return render(request, 'submissions/treated_submissions_list.html', context)
+
+
+@permission_required('scipost.can_manage_reports', raise_exception=True)
+def treated_submission_pdf_compile(request, arxiv_identifier_w_vn_nr):
+    submission = get_object_or_404(Submission.objects.treated(),
+                                   arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
+    form = SubmissionReportsForm(request.POST or None, request.FILES or None, instance=submission)
+    if form.is_valid():
+        form.save()
+        messages.success(request, 'Upload complete.')
+        return redirect(reverse('submissions:treated_submissions_list'))
+    context = {
+        'submission': submission,
+        'form': form
+    }
+    return render(request, 'submissions/treated_submission_pdf_compile.html', context)
+
+
+@permission_required('scipost.can_read_all_eic_events', raise_exception=True)
+def latest_events(request):
+    events = (SubmissionEvent.objects.for_eic()
+              .filter(created__gte=timezone.now() - datetime.timedelta(hours=24)))
+    context = {
+        'events': events
+    }
+    return render(request, 'submissions/latest_events.html', context)
+
+
 ######################
 # Editorial workflow #
 ######################
@@ -398,6 +491,9 @@ def accept_or_decline_assignment_ack(request, assignment_id):
                 assign_perm('can_take_editorial_actions', ed_admins, assignment.submission)
                 SubmissionUtils.send_EIC_appointment_email()
                 SubmissionUtils.send_author_prescreening_passed_email()
+
+                # Add SubmissionEvents
+                assignment.submission.add_general_event('The Editor-in-charge has been assigned.')
             else:
                 assignment.accepted = False
                 assignment.refusal_reason = form.cleaned_data['refusal_reason']
@@ -458,6 +554,9 @@ def volunteer_as_EIC(request, arxiv_identifier_w_vn_nr):
     SubmissionUtils.send_EIC_appointment_email()
     SubmissionUtils.send_author_prescreening_passed_email()
 
+    # Add SubmissionEvents
+    submission.add_general_event('The Editor-in-charge has been assigned.')
+
     messages.success(request, 'Thank you for becoming Editor-in-charge of this submission.')
     return redirect(reverse('submissions:editorial_page',
                             args=[submission.arxiv_identifier_w_vn_nr]))
@@ -527,30 +626,11 @@ def assignments(request):
 def editorial_page(request, arxiv_identifier_w_vn_nr):
     submission = get_object_or_404(Submission.objects.filter_editorial_page(request.user),
                                    arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
-    other_versions = (Submission.objects
-                      .filter(arxiv_identifier_wo_vn_nr=submission.arxiv_identifier_wo_vn_nr)
-                      .exclude(pk=submission.id))
-    ref_invitations = RefereeInvitation.objects.filter(submission=submission)
-    nr_reports_to_vet = (Report.objects.awaiting_vetting()
-                         .filter(submission=submission,
-                                 submission__editor_in_charge=request.user.contributor)
-                         .count())
-    communications = (EditorialCommunication.objects
-                      .filter(submission=submission).order_by('timestamp'))
-    try:
-        recommendation = (EICRecommendation.objects.get_for_user_in_pool(request.user)
-                          .get(submission=submission))
-    except EICRecommendation.DoesNotExist:
-        recommendation = None
+
     context = {
         'submission': submission,
-        'other_versions': other_versions,
-        'recommendation': recommendation,
         'set_deadline_form': SetRefereeingDeadlineForm(),
         'cycle_choice_form': SubmissionCycleChoiceForm(instance=submission),
-        'ref_invitations': ref_invitations,
-        'nr_reports_to_vet': nr_reports_to_vet,
-        'communications': communications
     }
     return render(request, 'submissions/editorial_page.html', context)
 
@@ -662,6 +742,9 @@ def recruit_referee(request, arxiv_identifier_w_vn_nr):
             reg_invitation.save()
             Utils.load({'invitation': reg_invitation})
             Utils.send_registration_invitation_email()
+            submission.add_event_for_author('A referee has been invited.')
+            submission.add_event_for_eic('%s has been recruited and invited as a referee.'
+                                         % ref_recruit_form.cleaned_data['last_name'])
             # Copy the key to the refereeing invitation:
             ref_invitation.invitation_key = reg_invitation.invitation_key
             ref_invitation.save()
@@ -701,6 +784,9 @@ def send_refereeing_invitation(request, arxiv_identifier_w_vn_nr, contributor_id
     invitation.save()
     SubmissionUtils.load({'invitation': invitation})
     SubmissionUtils.send_refereeing_invitation_email()
+    submission.add_event_for_author('A referee has been invited.')
+    submission.add_event_for_eic('Referee %s has been invited.' % contributor.user.last_name)
+    messages.success(request, 'Invitation sent')
     return redirect(reverse('submissions:editorial_page',
                             kwargs={'arxiv_identifier_w_vn_nr': arxiv_identifier_w_vn_nr}))
 
@@ -754,14 +840,23 @@ def accept_or_decline_ref_invitation_ack(request, invitation_id):
         invitation.date_responded = timezone.now()
         if form.cleaned_data['accept'] == 'True':
             invitation.accepted = True
+            decision_string = 'accepted'
         else:
             invitation.accepted = False
+            decision_string = 'declined'
             invitation.refusal_reason = form.cleaned_data['refusal_reason']
         invitation.save()
         SubmissionUtils.load({'invitation': invitation}, request)
         SubmissionUtils.email_referee_response_to_EIC()
         SubmissionUtils.email_referee_in_response_to_decision()
 
+        # Add SubmissionEvents
+        invitation.submission.add_event_for_author('A referee has %s the refereeing invitation.'
+                                                   % decision_string)
+        invitation.submission.add_event_for_eic('Referee %s has %s the refereeing invitation.'
+                                                % (invitation.referee.user.last_name,
+                                                   decision_string))
+
     context = {'invitation': invitation}
     return render(request, 'submissions/accept_or_decline_ref_invitation_ack.html', context)
 
@@ -771,15 +866,28 @@ def decline_ref_invitation(request, invitation_key):
                                    accepted__isnull=True)
 
     form = ConsiderRefereeInvitationForm(request.POST or None, initial={'accept': False})
+    context = {'invitation': invitation, 'form': form}
     if form.is_valid():
+        if form.cleaned_data['accept'] == 'True':
+            # User filled in: Accept
+            messages.warning(request, 'Please login and go to your personal page if you'
+                                      ' want to accept the invitation.')
+            return render(request, 'submissions/decline_ref_invitation.html', context)
+
         invitation.accepted = False
         invitation.refusal_reason = form.cleaned_data['refusal_reason']
         invitation.save()
         SubmissionUtils.load({'invitation': invitation}, request)
         SubmissionUtils.email_referee_response_to_EIC()
+
+        # Add SubmissionEvents
+        invitation.submission.add_event_for_author('A referee has declined the'
+                                                   ' refereeing invitation.')
+        invitation.submission.add_event_for_eic('Referee %s has declined the refereeing '
+                                                'invitation.' % invitation.referee.user.last_name)
+
         messages.success(request, 'Thank you for informing us that you will not provide a Report.')
         return redirect(reverse('scipost:index'))
-    context = {'invitation': invitation, 'form': form}
     return render(request, 'submissions/decline_ref_invitation.html', context)
 
 
@@ -797,6 +905,12 @@ def cancel_ref_invitation(request, arxiv_identifier_w_vn_nr, invitation_id):
     invitation.save()
     SubmissionUtils.load({'invitation': invitation})
     SubmissionUtils.send_ref_cancellation_email()
+
+    # Add SubmissionEvents
+    invitation.submission.add_event_for_author('A referee invitation has been cancelled.')
+    invitation.submission.add_event_for_eic('Referee invitation for %s has been cancelled.'
+                                            % invitation.last_name)
+
     return redirect(reverse('submissions:editorial_page',
                             kwargs={'arxiv_identifier_w_vn_nr': arxiv_identifier_w_vn_nr}))
 
@@ -813,6 +927,8 @@ def extend_refereeing_deadline(request, arxiv_identifier_w_vn_nr, days):
     submission.status = 'EICassigned'
     submission.latest_activity = timezone.now()
     submission.save()
+
+    submission.add_general_event('A new refereeing deadline is set.')
     return redirect(reverse('submissions:editorial_page',
                             kwargs={'arxiv_identifier_w_vn_nr': arxiv_identifier_w_vn_nr}))
 
@@ -833,6 +949,7 @@ def set_refereeing_deadline(request, arxiv_identifier_w_vn_nr):
             submission.status = 'EICassigned'
             submission.latest_activity = timezone.now()
             submission.save()
+            submission.add_general_event('A new refereeing deadline is set.')
             context = {'ack_header': 'New reporting deadline set.',
                        'followup_message': 'Return to the ',
                        'followup_link': reverse('submissions:editorial_page',
@@ -867,6 +984,8 @@ def close_refereeing_round(request, arxiv_identifier_w_vn_nr):
     submission.reporting_deadline = timezone.now()
     submission.latest_activity = timezone.now()
     submission.save()
+    submission.add_general_event('Refereeing round has been closed.')
+
     return redirect(reverse('submissions:editorial_page',
                             kwargs={'arxiv_identifier_w_vn_nr': arxiv_identifier_w_vn_nr}))
 
@@ -946,16 +1065,12 @@ def eic_recommendation(request, arxiv_identifier_w_vn_nr):
 
     form = EICRecommendationForm(request.POST or None)
     if form.is_valid():
-        recommendation = EICRecommendation(
-            submission=submission,
-            date_submitted=timezone.now(),
-            remarks_for_authors=form.cleaned_data['remarks_for_authors'],
-            requested_changes=form.cleaned_data['requested_changes'],
-            remarks_for_editorial_college=form.cleaned_data['remarks_for_editorial_college'],
-            recommendation=form.cleaned_data['recommendation'],
-            voting_deadline=timezone.now() + datetime.timedelta(days=7),
-        )
+        # Create new EICRecommendation
+        recommendation = form.save(commit=False)
+        recommendation.submission = submission
+        recommendation.voting_deadline = timezone.now() + datetime.timedelta(days=7)
         recommendation.save()
+
         # If recommendation is to accept or reject,
         # it is forwarded to the Editorial College for voting
         # If it is to carry out minor or major revisions,
@@ -965,12 +1080,21 @@ def eic_recommendation(request, arxiv_identifier_w_vn_nr):
                 recommendation.recommendation == 3 or
                 recommendation.recommendation == -3):
             submission.status = 'voting_in_preparation'
+
+            # Add SubmissionEvent for EIC
+            submission.add_event_for_eic('An Editorial Recommendation has been formulated: %s.'
+                                         % recommendation.get_recommendation_display())
+
         elif (recommendation.recommendation == -1 or
               recommendation.recommendation == -2):
             submission.status = 'revision_requested'
             SubmissionUtils.load({'submission': submission,
                                   'recommendation': recommendation})
             SubmissionUtils.send_author_revision_requested_email()
+
+            # Add SubmissionEvents
+            submission.add_general_event('An Editorial Recommendation has been formulated: %s.'
+                                         % recommendation.get_recommendation_display())
         submission.open_for_reporting = False
         submission.save()
 
@@ -1033,9 +1157,6 @@ def submit_report(request, arxiv_identifier_w_vn_nr):
         errormessage = ('The system flagged you as a potential author of this Submission. '
                         'Please go to your personal page under the Submissions tab'
                         ' to clarify this.')
-    # if submission.reports.non_draft().filter(author=current_contributor).exists():
-    #     errormessage = ('You have already submitted a Report for this Submission. You cannot'
-    #                     ' submit an additional Report.')
 
     if errormessage:
         messages.warning(request, errormessage)
@@ -1063,6 +1184,14 @@ def submit_report(request, arxiv_identifier_w_vn_nr):
         SubmissionUtils.email_EIC_report_delivered()
         SubmissionUtils.email_referee_report_delivered()
 
+        # Assign explicit permission to EIC to vet this report
+        assign_perm('submissions.can_vet_submitted_reports', submission.editor_in_charge.user,
+                    newreport)
+
+        # Add SubmissionEvents for the EIC only, as it can also be rejected still
+        submission.add_event_for_eic('%s has submitted a new Report.'
+                                     % request.user.last_name)
+
         messages.success(request, 'Thank you for your Report')
         return redirect(reverse('scipost:personal_page'))
 
@@ -1071,22 +1200,33 @@ def submit_report(request, arxiv_identifier_w_vn_nr):
 
 
 @login_required
-@permission_required('scipost.can_take_charge_of_submissions', raise_exception=True)
-def vet_submitted_reports(request):
+@permission_required('submissions.can_vet_submitted_reports', raise_exception=True)
+def vet_submitted_reports_list(request):
+    """
+    Reports with status `unvetted` will be shown (oldest first).
     """
-    Reports with status `unvetted` will be shown one-by-one (oldest first). A user may only
-    vet reports of submissions he/she is EIC of.
+    reports_to_vet = Report.objects.awaiting_vetting().order_by('date_submitted')
+    context = {'reports_to_vet': reports_to_vet}
+    return render(request, 'submissions/vet_submitted_reports_list.html', context)
+
+
+@login_required
+@transaction.atomic
+def vet_submitted_report(request, report_id):
+    """
+    Report with status `unvetted` will be shown. A user may only vet reports of submissions
+    he/she is EIC of or if he/she is SciPost Admin or Vetting Editor.
 
     After vetting an email is sent to the report author, bcc EIC. If report
     has not been refused, the submission author is also mailed.
     """
-    contributor = request.user.contributor
-    report_to_vet = (Report.objects.awaiting_vetting()
-                     .select_related('submission')
-                     .filter(submission__editor_in_charge=contributor)
-                     .order_by('date_submitted').first())
+    # Method `get_objects_for_user` gets all Reports that are assigned to the user
+    # or *all* Reports if user is SciPost Admin or Vetting Editor.
+    report = get_object_or_404((get_objects_for_user(request.user,
+                                                     'submissions.can_vet_submitted_reports')
+                                .awaiting_vetting()), id=report_id)
 
-    form = VetReportForm(request.POST or None, initial={'report': report_to_vet})
+    form = VetReportForm(request.POST or None, initial={'report': report})
     if form.is_valid():
         report = form.process_vetting(request.user.contributor)
 
@@ -1094,19 +1234,29 @@ def vet_submitted_reports(request):
         SubmissionUtils.load({'report': report,
                               'email_response': form.cleaned_data['email_response_field']})
         SubmissionUtils.acknowledge_report_email()  # email report author, bcc EIC
+
+        # Add SubmissionEvent for the EIC
+        report.submission.add_event_for_eic('The Report by %s is vetted.'
+                                            % report.author.user.last_name)
+
         if report.status == STATUS_VETTED:
             SubmissionUtils.send_author_report_received_email()
 
+            # Add SubmissionEvent to tell the author about the new report
+            report.submission.add_event_for_author('A new Report has been submitted.')
+
         message = 'Submitted Report vetted for <a href="%s">%s</a>.' % (
-            reverse('submissions:editorial_page',
-                    args=(report.submission.arxiv_identifier_w_vn_nr,)),
-            report.submission.arxiv_identifier_w_vn_nr
-        )
+                    report.submission.get_absolute_url(),
+                    report.submission.arxiv_identifier_w_vn_nr)
         messages.success(request, message)
-        # Redirect instead of render to loose the POST call and make it a GET
-        return redirect(reverse('submissions:vet_submitted_reports'))
-    context = {'contributor': contributor, 'report_to_vet': report_to_vet, 'form': form}
-    return render(request, 'submissions/vet_submitted_reports.html', context)
+
+        if report.submission.editor_in_charge == request.user.contributor:
+            # Redirect a EIC back to the Editorial Page!
+            return redirect(reverse('submissions:editorial_page',
+                                    args=(report.submission.arxiv_identifier_w_vn_nr,)))
+        return redirect(reverse('submissions:vet_submitted_reports_list'))
+    context = {'report_to_vet': report, 'form': form}
+    return render(request, 'submissions/vet_submitted_report.html', context)
 
 
 @permission_required('scipost.can_prepare_recommendations_for_voting', raise_exception=True)
@@ -1131,6 +1281,11 @@ def prepare_for_voting(request, rec_id):
             recommendation.submission.status = 'put_to_EC_voting'
             recommendation.submission.save()
             messages.success(request, 'We have registered your selection.')
+
+            # Add SubmissionEvents
+            recommendation.submission.add_event_for_eic('The Editorial Recommendation has been '
+                                                        'put forward to the College for voting.')
+
             return redirect(reverse('submissions:editorial_page',
                                     args=[recommendation.submission.arxiv_identifier_w_vn_nr]))
     else:
@@ -1237,27 +1392,40 @@ def fix_College_decision(request, rec_id):
     """
     recommendation = get_object_or_404((EICRecommendation.objects
                                         .get_for_user_in_pool(request.user)), pk=rec_id)
+    submission = recommendation.submission
     if recommendation.recommendation in [1, 2, 3]:
         # Publish as Tier I, II or III
-        recommendation.submission.status = 'accepted'
-        recommendation.submission.acceptance_date = datetime.date.today()
+        submission.status = 'accepted'
+        submission.acceptance_date = datetime.date.today()
+
         # Create a ProductionStream object
-        prodstream = ProductionStream(submission=recommendation.submission)
+        prodstream = ProductionStream(submission=submission)
         prodstream.save()
+
+        # Add SubmissionEvent for authors
+        # Do not write a new event for minor/major modification: already done at moment of
+        # creation.
+        submission.add_event_for_author('An Editorial Recommendation has been formulated: %s.'
+                                        % recommendation.get_recommendation_display())
     elif recommendation.recommendation == -3:
-        # Reject
-        recommendation.submission.status = 'rejected'
-        previous_submissions = Submission.objects.filter(
-            arxiv_identifier_wo_vn_nr=recommendation.submission.arxiv_identifier_wo_vn_nr
-        ).exclude(pk=recommendation.submission.id)
-        for sub in previous_submissions:
+        # Reject + update-reject other versions of submission
+        submission.status = 'rejected'
+        for sub in submission.other_versions:
             sub.status = 'resubmitted_rejected'
             sub.save()
 
-    recommendation.submission.save()
-    SubmissionUtils.load({'submission': recommendation.submission,
-                          'recommendation': recommendation})
+        # Add SubmissionEvent for authors
+        # Do not write a new event for minor/major modification: already done at moment of
+        # creation.
+        submission.add_event_for_author('An Editorial Recommendation has been formulated: %s.'
+                                        % recommendation.get_recommendation_display())
+
+    # Add SubmissionEvent for EIC
+    submission.add_event_for_eic('The Editorial College\'s decision has been fixed: %s.'
+                                 % recommendation.get_recommendation_display())
+
+    submission.save()
+    SubmissionUtils.load({'submission': submission, 'recommendation': recommendation})
     SubmissionUtils.send_author_College_decision_email()
-    ack_message = 'The Editorial College\'s decision has been fixed.'
-    return render(request, 'scipost/acknowledgement.html',
-                  context={'ack_message': ack_message})
+    messages.success(request, 'The Editorial College\'s decision has been fixed.')
+    return redirect(reverse('submissions:pool'))
diff --git a/templates/email/comment_vet_accepted.html b/templates/email/comment_vet_accepted.html
new file mode 100644
index 0000000000000000000000000000000000000000..60908ef568720835558a91280c070fc2a48b7a0f
--- /dev/null
+++ b/templates/email/comment_vet_accepted.html
@@ -0,0 +1,23 @@
+<p>Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}},</p>
+
+<p>
+    The Comment you have submitted, concerning publication with title
+
+    {{comment.core_content_object.title}} by {% if comment.core_content_object.author_list %}{{comment.core_content_object.author_list}}{% elif comment.core_content_object.author %}{{comment.core_content_object.author}}{% endif %} (<a href="https://scipost.org{{comment.get_absolute_url}}">see on SciPost.org</a>)
+    has been accepted and published online.
+</p>
+<p>
+    We copy it below for your convenience.
+</p>
+<p>
+    Thank you for your contribution,<br><br>
+    The SciPost Team.
+</p>
+<p>
+    <br>
+    Comment:
+    <br>
+    {{comment.comment_text|linebreaksbr}}
+</p>
+
+{% include 'email/_footer.html' %}
diff --git a/templates/email/comment_vet_accepted.txt b/templates/email/comment_vet_accepted.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c717f5fe32e03c5c4c1724f5590c7bc6b2a02a0e
--- /dev/null
+++ b/templates/email/comment_vet_accepted.txt
@@ -0,0 +1,16 @@
+Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}}
+\n\n
+
+The Comment you have submitted, concerning publication with title
+
+{{comment.core_content_object.title}} by {% if comment.core_content_object.author_list %}{{comment.core_content_object.author_list}}{% elif comment.core_content_object.author %}{{comment.core_content_object.author}}{% endif %} at https://scipost.org{{comment.get_absolute_url}}
+
+has been accepted and published online.
+\n\nWe copy it below for your convenience.
+
+\n\nThank you for your contribution,
+\nThe SciPost Team.
+
+'\n\n'
+Comment:\n
+{{comment.comment_text}}
diff --git a/templates/email/comment_vet_rejected.html b/templates/email/comment_vet_rejected.html
new file mode 100644
index 0000000000000000000000000000000000000000..678771fb32954fdfb86ebf20402bad97f421ef3c
--- /dev/null
+++ b/templates/email/comment_vet_rejected.html
@@ -0,0 +1,28 @@
+<p>Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}},</p>
+
+<p>
+    The Comment you have submitted, concerning publication with title
+
+    {{comment.core_content_object.title}} by {% if comment.core_content_object.author_list %}{{comment.core_content_object.author_list}}{% elif comment.core_content_object.author %}{{comment.core_content_object.author}}{% endif %} (<a href="https://scipost.org{{comment.get_absolute_url}}">see on SciPost.org</a>)
+    has been rejected for the following reason: {{comment.get_status_display}}.
+</p>
+<p>
+    We copy it below for your convenience.
+</p>
+<p>
+    Thank you for your contribution,<br><br>
+    The SciPost Team.
+</p>
+
+{% if email_response %}
+    <p>Further explanations: {{email_response}}</p>
+{% endif %}
+
+<p>
+    <br>
+    Comment:
+    <br>
+    {{comment.comment_text|linebreaksbr}}
+</p>
+
+{% include 'email/_footer.html' %}
diff --git a/templates/email/comment_vet_rejected.txt b/templates/email/comment_vet_rejected.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c489d65acf3725c63f1542cfa0e2288a80f0ac22
--- /dev/null
+++ b/templates/email/comment_vet_rejected.txt
@@ -0,0 +1,22 @@
+Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}}
+\n\n
+
+The Comment you have submitted, concerning publication with title
+
+{{comment.core_content_object.title}} by {% if comment.core_content_object.author_list %}{{comment.core_content_object.author_list}}{% elif comment.core_content_object.author %}{{comment.core_content_object.author}}{% endif %} at https://scipost.org{{comment.get_absolute_url}}
+
+has been rejected for the following reason: {{comment.get_status_display}}.
+
+\n\nWe copy it below for your convenience.
+
+\n\nThank you for your contribution,
+
+\n\nThe SciPost Team.
+
+{% if email_response %}
+    \n\nFurther explanations: {{email_response}}
+{% endif %}
+
+\n\n
+Comment:\n
+{{comment.comment_text}}
diff --git a/theses/managers.py b/theses/managers.py
index 68dc44574b8722927314cc063cbd22ef26c02a58..4d2b06986cce30276d4753244d0fb149061f08b6 100644
--- a/theses/managers.py
+++ b/theses/managers.py
@@ -15,3 +15,6 @@ class ThesisLinkManager(models.Manager):
 
     def vetted(self):
         return self.filter(vetted=True)
+
+    def open_for_commenting(self):
+        return self.filter(open_for_commenting=True)
diff --git a/theses/models.py b/theses/models.py
index 40ce6e673a79eeeba2fd06b9cd63b0c163b9f8dc..e15ebe73301fc9b7b5282a5576ba81a7b515ee15 100644
--- a/theses/models.py
+++ b/theses/models.py
@@ -1,10 +1,10 @@
 from django.db import models
+from django.contrib.contenttypes.fields import GenericRelation
 from django.urls import reverse
 from django.utils import timezone
 
 from journals.constants import SCIPOST_JOURNALS_DOMAINS
 from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS
-from scipost.models import Contributor
 
 from .constants import THESIS_TYPES
 from .managers import ThesisLinkManager
@@ -13,12 +13,12 @@ from .managers import ThesisLinkManager
 class ThesisLink(models.Model):
     """ An URL pointing to a thesis """
     requested_by = models.ForeignKey(
-        Contributor, blank=True, null=True,
+        'scipost.Contributor', blank=True, null=True,
         related_name='thesislink_requested_by',
         on_delete=models.CASCADE)
     vetted = models.BooleanField(default=False)
     vetted_by = models.ForeignKey(
-        Contributor, blank=True, null=True,
+        'scipost.Contributor', blank=True, null=True,
         on_delete=models.CASCADE)
     type = models.CharField(choices=THESIS_TYPES, max_length=3)
     discipline = models.CharField(
@@ -36,17 +36,17 @@ class ThesisLink(models.Model):
     pub_link = models.URLField(verbose_name='URL (external repository)')
     author = models.CharField(max_length=1000)
     author_as_cont = models.ManyToManyField(
-        Contributor, blank=True,
+        'scipost.Contributor', blank=True,
         related_name='author_cont')
     author_claims = models.ManyToManyField(
-        Contributor, blank=True,
+        'scipost.Contributor', blank=True,
         related_name='authors_thesis_claims')
     author_false_claims = models.ManyToManyField(
-        Contributor, blank=True,
+        'scipost.Contributor', blank=True,
         related_name='authors_thesis_false_claims')
     supervisor = models.CharField(max_length=1000, default='')
     supervisor_as_cont = models.ManyToManyField(
-        Contributor, blank=True,
+        'scipost.Contributor', blank=True,
         verbose_name='supervisor(s)',
         related_name='supervisor_cont')
     institution = models.CharField(
@@ -56,6 +56,9 @@ class ThesisLink(models.Model):
     abstract = models.TextField(verbose_name='abstract, outline or summary')
     latest_activity = models.DateTimeField(default=timezone.now)
 
+    # Comments can be added to a ThesisLink
+    comments = GenericRelation('comments.Comment', related_query_name='theses')
+
     objects = ThesisLinkManager()
 
     def __str__(self):
diff --git a/theses/templates/theses/_thesislink_card_content.html b/theses/templates/theses/_thesislink_card_content.html
index 36ff9a1141e16e8a2c2ae9a0425e4887f408c4ad..ad0ec2cc3e083782b50d01ca35b2ad84cb9f7858 100644
--- a/theses/templates/theses/_thesislink_card_content.html
+++ b/theses/templates/theses/_thesislink_card_content.html
@@ -1,5 +1,3 @@
-{% load theses_extras %}
-
 <div class="card-block">
     <h5 class="pb-0">{{ thesislink.get_discipline_display }} &middot; {{ thesislink.get_domain_display }} &middot; {{ thesislink.get_subject_area_display }}</h5>
     <h3>
diff --git a/theses/templates/theses/_thesislink_information.html b/theses/templates/theses/_thesislink_information.html
index 5bc93fb0a777ad196559e29b2a749fcbf06cc879..204eb9d3fcafbc84a714d08659eb7d782e9a9d13 100644
--- a/theses/templates/theses/_thesislink_information.html
+++ b/theses/templates/theses/_thesislink_information.html
@@ -1,5 +1,3 @@
-{% load theses_extras %}
-
 <table class="mb-3">
     <tr>
         <td>Title: </td><td>&nbsp;</td><td>{{ thesislink.title }}</td>
@@ -18,16 +16,16 @@
         </td>
     </tr>
     <tr>
-        <td>Type: </td><td></td><td>  {{ thesislink|type }}</td>
+        <td>Type: </td><td></td><td>  {{ thesislink.get_type_display }}</td>
     </tr>
     <tr>
-        <td>Discipline: </td><td></td><td>{{ thesislink|discipline }}</td>
+        <td>Discipline: </td><td></td><td>{{ thesislink.get_discipline_display }}</td>
     </tr>
     <tr>
-        <td>Domain: </td><td></td><td>{{ thesislink|domain }}</td>
+        <td>Domain: </td><td></td><td>{{ thesislink.get_domain_display }}</td>
     </tr>
     <tr>
-        <td>Subject area: </td><td></td><td> {{ thesislink|subject_area }} </td>
+        <td>Subject area: </td><td></td><td> {{ thesislink.get_subject_area_display }} </td>
     </tr>
     <tr>
         <td>URL: </td><td>&nbsp;</td><td><a href="{{ thesislink.pub_link }}" target="_blank">{{ thesislink.pub_link }}</a></td>
diff --git a/theses/templates/theses/thesis_detail.html b/theses/templates/theses/thesis_detail.html
index 543b64d53a5f3e089bf6ff49fc806d7d9498c275..7ed53d775a8bdfde69e842e8803cd6b4d6ec91a9 100644
--- a/theses/templates/theses/thesis_detail.html
+++ b/theses/templates/theses/thesis_detail.html
@@ -1,39 +1,12 @@
 {% extends 'scipost/base.html' %}
 
-{% block pagetitle %}: Thesis Link detail{% endblock pagetitle %}
-
-{% block headsup %}
-
 {% load scipost_extras %}
 
-<script>
-  $(document).ready(function(){
-
-    var comment_text_input = $("#id_comment_text");
-
-    function set_comment_text(value) {
-      $("#preview-comment_text").text(value)
-    }
-    set_comment_text(comment_text_input.val())
-
-    comment_text_input.keyup(function(){
-      var new_text = $(this).val()
-      set_comment_text(new_text)
-      MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
-    })
-
-  });
-</script>
-
-{% endblock headsup %}
+{% block pagetitle %}: Thesis Link detail{% endblock pagetitle %}
 
 {% block content %}
 
-<div class="row">
-    <div class="col-12">
-        <h1 class="highlight">SciPost Thesis Link</h1>
-    </div>
-</div>
+<h1 class="highlight">SciPost Thesis Link</h1>
 
 <div class="row">
     <div class="col-12">
@@ -41,7 +14,7 @@
     </div>
 </div>
 
-{% include 'scipost/comments_block.html' %}
+{% include 'scipost/comments_block.html' with comments=thesislink.comments.vetted type_of_object='ThesisLink' %}
 
 {% include 'comments/new_comment.html' with object_id=thesislink.id type_of_object='thesislink' open_for_commenting=thesislink.open_for_commenting %}
 
diff --git a/theses/templates/theses/vet_thesislink.html b/theses/templates/theses/vet_thesislink.html
index 8822dfff11c61f69a0a0ded2b8e5ea12b0004f33..30b1bb1831560e02be8b702764931b10ddff418f 100644
--- a/theses/templates/theses/vet_thesislink.html
+++ b/theses/templates/theses/vet_thesislink.html
@@ -4,10 +4,6 @@
 
 {% block pagetitle %}: Unvetted Thesis Links{% endblock pagetitle %}
 
-{% block headsup %}
-
-{% endblock headsup %}
-
 {% block content %}
 
 <div class="row">
diff --git a/theses/templatetags/theses_extras.py b/theses/templatetags/theses_extras.py
deleted file mode 100644
index e60c4ecf59d309bd7596b3574c08f021dc1de282..0000000000000000000000000000000000000000
--- a/theses/templatetags/theses_extras.py
+++ /dev/null
@@ -1,27 +0,0 @@
-from django import template
-
-register = template.Library()
-
-
-@register.filter
-def type(thesislink):
-    # deprecated method, to be removed in future
-    return thesislink.get_type_display()
-
-
-@register.filter
-def discipline(thesislink):
-    # deprecated method, to be removed in future
-    return thesislink.get_discipline_display()
-
-
-@register.filter
-def domain(thesislink):
-    # deprecated method, to be removed in future
-    return thesislink.get_domain_display()
-
-
-@register.filter
-def subject_area(thesislink):
-    # deprecated method, to be removed in future
-    return thesislink.get_subject_area_display()
diff --git a/theses/views.py b/theses/views.py
index 4666b92c6c2cc24d30b532ab1ef24f54fede9948..285bda18f792efc3f376a78938a548b562825a71 100644
--- a/theses/views.py
+++ b/theses/views.py
@@ -87,24 +87,24 @@ class ThesisListView(ListView):
         # Context is not saved to View object by default
         self.pre_context = self.kwargs
 
-        # Browse is discipline is given
+        # Browse if discipline is given
         if 'discipline' in self.kwargs:
             self.pre_context['browse'] = True
 
         # Queryset for browsing
         if self.kwargs.get('browse', False):
-            return self.model.objects.vetted().filter(
-                discipline=self.kwargs['discipline'],
-                latest_activity__gte=timezone.now() + datetime.timedelta(
-                                        weeks=-int(self.kwargs['nrweeksback'])),
-            )
+            return (self.model.objects.vetted()
+                    .filter(discipline=self.kwargs['discipline'],
+                            latest_activity__gte=timezone.now() + datetime.timedelta(
+                                        weeks=-int(self.kwargs['nrweeksback'])))
+                    .order_by('-latest_activity'))
 
         # Queryset for searchform is processed by managers
         form = self.form(self.request.GET)
         if form.is_valid() and form.has_changed():
-            return self.model.objects.search_results(form)
+            return self.model.objects.search_results(form).order_by('-latest_activity')
         self.pre_context['recent'] = True
-        return self.model.objects.vetted()
+        return self.model.objects.vetted().order_by('-latest_activity')
 
     def get_context_data(self, **kwargs):
         # Update the context data from `get_queryset`
@@ -121,10 +121,5 @@ def thesis_detail(request, thesislink_id):
     thesislink = get_object_or_404(ThesisLink, pk=thesislink_id)
     form = CommentForm()
 
-    comments = thesislink.comment_set
-    author_replies = comments.filter(is_author_reply=True)
-
-    context = {'thesislink': thesislink,
-               'comments': comments.vetted().order_by('date_submitted'),
-               'author_replies': author_replies, 'form': form}
+    context = {'thesislink': thesislink, 'form': form}
     return render(request, 'theses/thesis_detail.html', context)