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/models.py b/commentaries/models.py
index 27db6d732b4144dfb15a8ca6c86997a6ac04b7b1..a1c41fdafe2c0f6b3e88388371ed69c39c18e81b 100644
--- a/commentaries/models.py
+++ b/commentaries/models.py
@@ -25,43 +25,36 @@ class Commentary(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)
+    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')
 
     objects = CommentaryManager()
@@ -72,6 +65,9 @@ class Commentary(TimeStampedModel):
     def __str__(self):
         return self.pub_title
 
+    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,)),
diff --git a/commentaries/views.py b/commentaries/views.py
index 3dc87784707e61820a4f7afc2749d5ddebccb52c..5bf4f0ef87745667375a2fa15a4c79d2dc4ac544 100644
--- a/commentaries/views.py
+++ b/commentaries/views.py
@@ -17,7 +17,6 @@ from .forms import DOIToQueryForm, ArxivQueryForm, VetCommentaryForm, RequestCom
 
 from comments.models import Comment
 from comments.forms import CommentForm
-from scipost.models import Contributor
 
 import strings
 
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/managers.py b/comments/managers.py
index 823b4c0d79a732c224bc62bec58d1f70d1f416fb..37f5baef8c803436d56818518ac4549b85514756 100644
--- a/comments/managers.py
+++ b/comments/managers.py
@@ -3,7 +3,7 @@ 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)
 
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..aabeaf9f993d9f4e0935df4837070193f732bb29
--- /dev/null
+++ b/comments/migrations/0014_auto_20170726_2117.py
@@ -0,0 +1,39 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-07-26 19:17
+from __future__ import unicode_literals
+
+from django.db import migrations
+
+from guardian.shortcuts import assign_perm
+
+from ..constants import STATUS_PENDING
+
+
+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')
+    count = 0
+    for comment in Comment.objects.filter(status=STATUS_PENDING):
+        if comment.submission:
+            eic_user = comment.submission.editor_in_charge.user
+            assign_perm('comments.can_vet_comments', eic_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/models.py b/comments/models.py
index fd52703d222870e5694815c6b39acb632abfbea9..c1c25c9a1e3338297b74c70ecf6e3de5f1cc13d7 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -1,12 +1,13 @@
 from django.db import models
 from django.shortcuts import get_object_or_404
+from django.utils import timezone
 
 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
 
 
 class Comment(TimeStampedModel):
@@ -16,10 +17,9 @@ 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]
-    )
+    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.
     commentary = models.ForeignKey('commentaries.Commentary', blank=True, null=True,
                                    on_delete=models.CASCADE)
@@ -35,6 +35,7 @@ class Comment(TimeStampedModel):
                                            on_delete=models.CASCADE)
     author = models.ForeignKey('scipost.Contributor', on_delete=models.CASCADE)
     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,22 +47,26 @@ 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 +
diff --git a/comments/templates/comments/_vet_comment_form.html b/comments/templates/comments/_vet_comment_form.html
new file mode 100644
index 0000000000000000000000000000000000000000..dd01802345af1267abc90e834d7e65bbab50a9a9
--- /dev/null
+++ b/comments/templates/comments/_vet_comment_form.html
@@ -0,0 +1,62 @@
+{% load bootstrap %}
+{% load filename %}
+{% load file_extentions %}
+
+<div class="card card-vetting">
+    <div class="card-header">
+
+        {% if comment.commentary %}
+            <h2>From Commentary (<a href="{{comment.commentary.get_absolute_url}}">link</a>)</h2>
+            {% include 'commentaries/_commentary_summary.html' with commentary=comment.commentary %}
+        {% endif %}
+
+        {% if comment.submission %}
+            <h2>From Submission (<a href="{{comment.submission.get_absolute_url}}">link</a>)</h2>
+            {% include 'submissions/_submission_summary_short.html' with submission=comment.submission %}
+        {% endif %}
+
+        {% if comment.thesislink %}
+            <h2>From Thesis Link (<a href="{{comment.thesislink.get_absolute_url}}">link</a>)</h2>
+            {% include 'theses/_thesislink_information.html' with thesislink=comment.thesislink %}
+        {% endif %}
+    </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_vetting.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/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.html b/comments/templates/comments/vet_submitted_comments.html
deleted file mode 100644
index e3a71b702cb6ab815ad2af54cf9abf1147506ad5..0000000000000000000000000000000000000000
--- a/comments/templates/comments/vet_submitted_comments.html
+++ /dev/null
@@ -1,90 +0,0 @@
-{% extends 'scipost/base.html' %}
-
-{% load bootstrap %}
-{% load filename %}
-{% load file_extentions %}
-
-{% 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 %}
-            <div class="card card-vetting">
-                <div class="card-header">
-
-                    {% if comment_to_vet.commentary %}
-                        <h2>From Commentary (<a href="{% url 'commentaries:commentary' arxiv_or_DOI_string=comment_to_vet.commentary.arxiv_or_DOI_string %}">link</a>)</h2>
-                        {% include 'commentaries/_commentary_summary.html' with commentary=comment_to_vet.commentary %}
-                    {% endif %}
-
-                    {% if comment_to_vet.submission %}
-                        <h2>From Submission (<a href="{% url 'submissions:submission' arxiv_identifier_w_vn_nr=comment_to_vet.submission.arxiv_identifier_w_vn_nr %}">link</a>)</h2>
-                        {% include 'submissions/_submission_summary_short.html' with submission=comment_to_vet.submission %}
-                    {% endif %}
-
-                    {% if comment_to_vet.thesislink %}
-                        <h2>From Thesis Link (<a href="{% url 'theses:thesis' comment_to_vet.thesislink.id %}">link</a>)</h2>
-                        {% include 'theses/_thesislink_information.html' with thesislink=comment_to_vet.thesislink %}
-                    {% endif %}
-                </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_vetting.html' with comment=comment_to_vet %}
-                            <hr class="small">
-
-                            <h3>Comment text:</h3>
-                            <p>{{ comment_to_vet.comment_text }}</p>
-
-                            {% if comment_to_vet.file_attachment %}
-                                <h3>Attachment:</h3>
-                                <p>
-                                    <a target="_blank" href="{{ comment_to_vet.file_attachment.url }}">
-                                        {% if comment_to_vet.file_attachment|is_image %}
-                                            <img class="attachment attachment-comment" src="{{ comment_to_vet.file_attachment.url }}">
-                                        {% else %}
-                                            {{ comment_to_vet.file_attachment|filename }}<br><small>{{ comment_to_vet.file_attachment.size|filesizeformat }}</small>
-                                        {% endif %}
-                                    </a>
-                                </p>
-                            {% endif %}
-
-                            {% if comment_to_vet.remarks_for_editors %}
-                                <h3>Remarks for Editors only:</h3>
-                                <p>{{ comment_to_vet.remarks_for_editors }}</p>
-                            {% endif %}
-                        </div>
-                        <div class="col-md-6">
-                            <form action="{% url 'comments:vet_submitted_comment_ack' comment_id=comment_to_vet.id %}" method="post">
-                                {% csrf_token %}
-                                {{ form|bootstrap }}
-                                <input class="btn btn-primary" type="submit" value="Submit" />
-                            </form>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        {% endfor %}
-    </div>
-</div>
-{% endif %}
-
-{% 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/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..662841c025a96addd05519fea0a79eb128d99452 100644
--- a/comments/views.py
+++ b/comments/views.py
@@ -1,18 +1,18 @@
 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.http import HttpResponseRedirect
+from django.db import transaction
 
+from guardian.shortcuts import assign_perm, 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 +21,147 @@ 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}
-                )
+    form = CommentForm(request.POST or None)
+    if form.is_valid():
+        object_id = int(kwargs["object_id"])
+        type_of_object = kwargs["type_of_object"]
 
+        new_comment = form.save(commit=False)
+        new_comment.author = request.user.contributor
+
+        if type_of_object == "thesislink":
+            _object = get_object_or_404(ThesisLink.objects.open_for_commenting(), id=object_id)
+            new_comment.thesislink = _object
             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
+        elif type_of_object == "submission":
+            _object = get_object_or_404(Submission.objects.open_for_commenting(), id=object_id)
+            new_comment.submission = _object
+            new_comment.save()
+            _object.add_event_for_eic('A new comment has been added.')
 
+            # Add permissions for EIC only, the Vetting-group already has it!
+            assign_perm('comments.can_vet_comments', _object.editor_in_charge.user, new_comment)
+        elif type_of_object == "commentary":
+            _object = get_object_or_404(Commentary.objects.open_for_commenting(), id=object_id)
+            new_comment.commentary = _object
+            new_comment.save()
 
-@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))
+        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
+            if comment.commentary:
+                comment.commentary.latest_activity = timezone.now()
+                comment.commentary.save()
+            elif comment.submission:
+                comment.submission.latest_activity = timezone.now()
+                comment.submission.save()
+
+                # Add events to Submission and send mail to author of the Submission
+                comment.submission.add_event_for_eic('A Comment has been accepted.')
+                comment.submission.add_event_for_author('A new Comment has been added.')
+                if not comment.is_author_reply:
+                    SubmissionUtils.load({'submission': comment.submission})
+                    SubmissionUtils.send_author_comment_received_email()
+            elif comment.thesislink:
+                comment.thesislink.latest_activity = timezone.now()
+                comment.thesislink.save()
+        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()
+
+            # Send emails
+            CommentUtils.load({'comment': comment})
+            CommentUtils.email_comment_vet_rejected_to_author(
+                email_response=form.cleaned_data['email_response_field'])
+
+            if comment.submission:
+                comment.submission.add_event_for_eic('A Comment has been rejected.')
+
+        messages.success(request, 'Submitted Comment vetted.')
+        if comment.submission and comment.submission.editor_in_charge == request.user.contributor:
+            # Redirect a EIC back to the Editorial Page!
+            return redirect(reverse('submissions:editorial_page',
+                                    args=(comment.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()
+    if comment.submission and not is_author:
+        is_author = comment.submission.authors.filter(id=request.user.contributor.id).exists()
+    elif comment.commentary and not is_author:
+        is_author = comment.commentary.authors.filter(id=request.user.contributor.id).exists()
+    elif comment.thesislink and not is_author:
+        is_author = comment.thesislink.author == request.user.contributor
+
+    form = CommentForm(request.POST or None, request.FILES or None)
+    if form.is_valid():
+        newcomment = form.save(commit=False)
+        # Either one of commentary, submission or thesislink will be not Null
+        newcomment.commentary = comment.commentary
+        newcomment.submission = comment.submission
+        newcomment.thesislink = comment.thesislink
+        newcomment.is_author_reply = is_author
+        newcomment.in_reply_to_comment = comment
+        newcomment.author = request.user.contributor
+        newcomment.save()
+
+        messages.success(request, '<h3>Thank you for contributing a Reply</h3>'
+                                  'It will soon be vetted by an Editor.')
+
+        if newcomment.submission:
+            return redirect(newcomment.submission.get_absolute_url())
+        elif newcomment.commentary:
+            return redirect(newcomment.commentary.get_absolute_url())
+        elif newcomment.thesislink:
+            return redirect(newcomment.thesislink.get_absolute_url())
+        return redirect(reverse('scipost:index'))
 
     context = {'comment': comment, 'is_author': is_author, 'form': form}
     return render(request, 'comments/reply_to_comment.html', context)
@@ -250,49 +170,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.submission = report.submission
+        newcomment.is_author_reply = is_author
+        newcomment.in_reply_to_report = report
+        newcomment.author = request.user.contributor
+        newcomment.save()
+
+        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)
 
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/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 a59ea8df52301965ee597ab3f795dff1048dfe02..2c32f440b4a64de2ab4369b647e419cf5cdd0743 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -53,7 +53,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/templates/scipost/personal_page.html b/scipost/templates/scipost/personal_page.html
index 76a4053791473192d3b0d39252ec5c38e691293c..54c211a0ded22fc4951bf4c11f611e28cc562e4f 100644
--- a/scipost/templates/scipost/personal_page.html
+++ b/scipost/templates/scipost/personal_page.html
@@ -250,7 +250,7 @@
                                 <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>
diff --git a/submissions/managers.py b/submissions/managers.py
index cba54e4f69b167a34a4a550b2b3a34339991fc49..43c1902c7c538f1cf93f7f462f22370831e9adbe 100644
--- a/submissions/managers.py
+++ b/submissions/managers.py
@@ -99,6 +99,9 @@ class SubmissionManager(models.Manager):
     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):
diff --git a/submissions/models.py b/submissions/models.py
index 790619f7d3891d2ee7a4f93118c8f52bd5a30c2b..158ae9b3695dec0fa89b0306c1f1b085e79a4323 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -91,7 +91,7 @@ class Submission(models.Model):
     class Meta:
         permissions = (
             ('can_take_editorial_actions', 'Can take editorial actions'),
-            )
+        )
 
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
diff --git a/submissions/templates/submissions/editorial_page.html b/submissions/templates/submissions/editorial_page.html
index 069d183b679e7f09def5b4bb8cf87e95253f314b..aee2c35959ff5b4e807262693949cc2563e84567 100644
--- a/submissions/templates/submissions/editorial_page.html
+++ b/submissions/templates/submissions/editorial_page.html
@@ -171,6 +171,20 @@
                             </form>
                         </li>
                         <li><a href="{% url 'submissions:vet_submitted_reports' %}">Vet submitted Reports</a> ({{ submission.reports.awaiting_vetting.count }})</li>
+                        {% with submission.comments.awaiting_vetting as comments %}
+                            {% if comments %}
+                                <li>
+                                    Vet submitted Comments:
+                                    <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 %}
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/templates/email/comment_vet_accepted.html b/templates/email/comment_vet_accepted.html
new file mode 100644
index 0000000000000000000000000000000000000000..de7c50065e5514e37fda15478c01178ffc68ce69
--- /dev/null
+++ b/templates/email/comment_vet_accepted.html
@@ -0,0 +1,29 @@
+<p>Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}},</p>
+
+<p>
+    The Comment you have submitted, concerning publication with title
+
+    {% if comment.commentary %}
+        {{comment.commentary.pub_title}} by {{comment.commentary.author_list}} (<a href="https://scipost.org{{comment.commentary.get_absolute_url}}">see Commentary Page on SciPost.org</a>)
+    {% elif comment.submission %}
+        {{comment.submission.title}} by {{comment.submission.author_list}} (<a href="https://scipost.org{{comment.submission.get_absolute_url}}">see Submission Page on SciPost.org</a>)
+    {% elif comment.thesislink %}
+        {{comment.thesislink.title}} by {{comment.thesislink.author}} (<a href="https://scipost.org{{comment.thesislink.get_absolute_url}}">see Thesis Link on SciPost.org</a>)
+    {% endif %}
+    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..79b53c5b8f0629c745ede71599301a9fffdbc838
--- /dev/null
+++ b/templates/email/comment_vet_accepted.txt
@@ -0,0 +1,21 @@
+Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}}
+\n\n
+
+The Comment you have submitted, concerning publication with title
+
+{% if comment.commentary %}
+    {{comment.commentary.pub_title}} by {{comment.commentary.author_list}} at Commentary Page https://scipost.org{{comment.commentary.get_absolute_url}}
+{% elif comment.submission %}
+    {{comment.submission.title}} by {{comment.submission.author_list}} at Submission page https://scipost.org{{comment.submission.get_absolute_url}}
+{% elif comment.thesislink %}
+    {{comment.thesislink.title}} by {{comment.thesislink.author}} at Thesis Link https://scipost.org{{comment.thesislink.get_absolute_url}}
+{% endif %}
+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..e6a5dd598b162e45792a80fe151f31bcb95178d8
--- /dev/null
+++ b/templates/email/comment_vet_rejected.html
@@ -0,0 +1,34 @@
+<p>Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}},</p>
+
+<p>
+    The Comment you have submitted, concerning publication with title
+
+    {% if comment.commentary %}
+        {{comment.commentary.pub_title}} by {{comment.commentary.author_list}} (<a href="https://scipost.org{{comment.commentary.get_absolute_url}}">see Commentary Page on SciPost.org</a>)
+    {% elif comment.submission %}
+        {{comment.submission.title}} by {{comment.submission.author_list}} (<a href="https://scipost.org{{comment.submission.get_absolute_url}}">see Submission Page on SciPost.org</a>)
+    {% elif comment.thesislink %}
+        {{comment.thesislink.title}} by {{comment.thesislink.author}} (<a href="https://scipost.org{{comment.thesislink.get_absolute_url}}">see Thesis Link on SciPost.org</a>)
+    {% endif %}
+    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..2eed6e1bae03f8e9f8bb083073d4a544d042b2e6
--- /dev/null
+++ b/templates/email/comment_vet_rejected.txt
@@ -0,0 +1,28 @@
+Dear {{comment.author.get_title_display}} {{comment.author.user.last_name}}
+\n\n
+
+The Comment you have submitted, concerning publication with title
+
+{% if comment.commentary %}
+    {{comment.commentary.pub_title}} by {{comment.commentary.author_list}} at Commentary Page https://scipost.org{{comment.commentary.get_absolute_url}}
+{% elif comment.submission %}
+    {{comment.submission.title}} by {{comment.submission.author_list}} at Submission page https://scipost.org{{comment.submission.get_absolute_url}}
+{% elif comment.thesislink %}
+    {{comment.thesislink.title}} by {{comment.thesislink.author}} at Thesis Link https://scipost.org{{comment.thesislink.get_absolute_url}}
+{% endif %}
+
+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)