diff --git a/SciPost_v1/settings.py b/SciPost_v1/settings.py
index e999aaf861ad93644bac8aac6fa39b8d4a61a69c..9c9c14867438a7d096c4c664dcf8975f8434dd0d 100644
--- a/SciPost_v1/settings.py
+++ b/SciPost_v1/settings.py
@@ -107,6 +107,11 @@ SHELL_PLUS_POST_IMPORTS = (
     ('theses.factories', ('ThesisLinkFactory')),
     ('comments.factories', ('CommentFactory')),
     ('submissions.factories', ('SubmissionFactory', 'EICassignedSubmissionFactory')),
+    ('commentaries.factories',
+        ('EmptyCommentaryFactory',
+        'VettedCommentaryFactory',
+        'UnvettedCommentaryFactory',
+        'UnpublishedVettedCommentaryFactory',)),
 )
 
 MATHJAX_ENABLED = True
diff --git a/commentaries/factories.py b/commentaries/factories.py
index 18e72a7b59715315a717f78316e9011ea1f34477..31f1354fa2c7c811daccdbfa7bd9a27cdf55850f 100644
--- a/commentaries/factories.py
+++ b/commentaries/factories.py
@@ -1,11 +1,11 @@
 import factory
 
-from .models import Commentary, COMMENTARY_TYPES
-
 from scipost.constants import DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS
 from scipost.factories import ContributorFactory
 from journals.models import SCIPOST_JOURNALS_DOMAINS
+from common.helpers import random_arxiv_identifier_with_version_number
 
+from .models import Commentary, COMMENTARY_TYPES
 
 class CommentaryFactory(factory.django.DjangoModelFactory):
     class Meta:
@@ -18,12 +18,16 @@ class CommentaryFactory(factory.django.DjangoModelFactory):
     discipline = DISCIPLINE_PHYSICS
     domain = SCIPOST_JOURNALS_DOMAINS[0][0]
     subject_area = SCIPOST_SUBJECT_AREAS[0][1][0][0]
-    pub_title = factory.Sequence(lambda n: "Commentary %d" % n)
+    pub_title = factory.Faker('bs')
     pub_DOI = '10.1103/PhysRevB.92.214427'
-    arxiv_identifier = '1610.06911v1'
+    arxiv_identifier = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number())
     author_list = factory.Faker('name')
     pub_abstract = factory.Faker('text')
 
+    @factory.post_generation
+    def create_urls(self, create, extracted, **kwargs):
+        self.parse_links_into_urls(commit=create)
+
 
 class EmptyCommentaryFactory(CommentaryFactory):
     pub_DOI = None
@@ -34,5 +38,9 @@ class VettedCommentaryFactory(CommentaryFactory):
     vetted = True
 
 
-class UnVettedCommentaryFactory(CommentaryFactory):
+class UnpublishedVettedCommentaryFactory(VettedCommentaryFactory):
+    pub_DOI = ''
+
+
+class UnvettedCommentaryFactory(CommentaryFactory):
     vetted = False
diff --git a/commentaries/templates/commentaries/commentaries.html b/commentaries/templates/commentaries/commentaries.html
index 8414ca91ab9e0cbd56269e503f245f572b909d4c..d555bd005778f7f47c1417d24c707efb0efbb062 100644
--- a/commentaries/templates/commentaries/commentaries.html
+++ b/commentaries/templates/commentaries/commentaries.html
@@ -11,7 +11,6 @@
 {% block content %}
 
 
-{# <section>#}
 <div class="row">
     <div class="col-md-4">
         <div class="panel page-header-panel">
diff --git a/commentaries/templates/commentaries/commentary_detail.html b/commentaries/templates/commentaries/commentary_detail.html
index e468065f95c17ca29d3c3cf5d850192aa9fbd558..b9c5fcd2f9a3691477692d54a4441d17f4b8c913 100644
--- a/commentaries/templates/commentaries/commentary_detail.html
+++ b/commentaries/templates/commentaries/commentary_detail.html
@@ -58,32 +58,6 @@
 
 {% include 'scipost/comments_block.html' %}
 
-
-{% if user.is_authenticated and commentary.open_for_commenting and perms.scipost.can_submit_comments %}
-<hr>
-
-<div class="row">
-    <div class="col-12">
-        <div class="panel">
-            <h2>Contribute a Comment:</h2>
-        </div>
-    </div>
-</div>
-<div class="row">
-    <div class="col-12">
-        <form enctype="multipart/form-data" action="{% url 'commentaries:commentary' arxiv_or_DOI_string=commentary.arxiv_or_DOI_string %}" method="post">
-          {% csrf_token %}
-          {% load crispy_forms_tags %}
-          {% crispy form %}
-        </form>
-    </div>
-    <div class="col-12">
-        <h3>Preview of your comment:</h3>
-        <p id="preview-comment_text"></p>
-    </div>
-</div>
-
-{% endif %}
-
+{% include 'comments/new_comment.html' with object_id=commentary.id type_of_object='commentary' open_for_commenting=commentary.open_for_commenting %}
 
 {% endblock content %}
diff --git a/commentaries/test_forms.py b/commentaries/test_forms.py
index 8a81d2abb6dd2c55da24c687e78ccde109544c71..cec31d3071f2944cc61a8c0cebb785adb186f27f 100644
--- a/commentaries/test_forms.py
+++ b/commentaries/test_forms.py
@@ -3,7 +3,7 @@ from django.test import TestCase
 from common.helpers import model_form_data
 from scipost.factories import UserFactory
 
-from .factories import VettedCommentaryFactory, UnVettedCommentaryFactory
+from .factories import VettedCommentaryFactory, UnvettedCommentaryFactory
 from .forms import RequestCommentaryForm, VetCommentaryForm
 from .models import Commentary
 
@@ -12,7 +12,7 @@ class TestVetCommentaryForm(TestCase):
     fixtures = ['permissions', 'groups']
 
     def setUp(self):
-        self.commentary = UnVettedCommentaryFactory.create()
+        self.commentary = UnvettedCommentaryFactory.create()
         self.user = UserFactory()
         self.form_data = {
             'action_option': VetCommentaryForm.ACTION_ACCEPT,
diff --git a/commentaries/test_views.py b/commentaries/test_views.py
index d724770ab2f0f57b8229618661ef257897fcfdd1..50d6850fd46c2b7166370a078492a227e04dcda5 100644
--- a/commentaries/test_views.py
+++ b/commentaries/test_views.py
@@ -1,10 +1,10 @@
 from django.core.urlresolvers import reverse
 from django.contrib.auth.models import Group
-from django.test import TestCase
+from django.test import TestCase, Client
 
 from scipost.factories import ContributorFactory
 
-from .factories import UnVettedCommentaryFactory, VettedCommentaryFactory
+from .factories import UnvettedCommentaryFactory, VettedCommentaryFactory, UnpublishedVettedCommentaryFactory
 from .forms import CommentarySearchForm
 from .models import Commentary
 
@@ -83,7 +83,7 @@ class VetCommentaryRequestsTest(TestCase):
         self.assertEquals(response.context['commentary_to_vet'], None)
 
         # Unvetted Commentaries do exist!
-        UnVettedCommentaryFactory()
+        UnvettedCommentaryFactory()
         response = self.client.get(self.view_url)
         self.assertTrue(type(response.context['commentary_to_vet']) is Commentary)
 
@@ -108,3 +108,19 @@ class BrowseCommentariesTest(TestCase):
         self.assertTrue(response.context['commentary_browse_list'].count() >= 1)
         # The search form is passed trough the view...
         self.assertTrue(type(response.context['form']) is CommentarySearchForm)
+
+
+class CommentaryDetailTest(TestCase):
+    fixtures = ['permissions', 'groups']
+
+    def setUp(self):
+        self.client = Client()
+        self.commentary = UnpublishedVettedCommentaryFactory()
+        self.target = reverse(
+            'commentaries:commentary',
+            kwargs={'arxiv_or_DOI_string': self.commentary.arxiv_or_DOI_string}
+        )
+
+    def test_status_code_200(self):
+        response = self.client.get(self.target)
+        self.assertEqual(response.status_code, 200)
diff --git a/commentaries/views.py b/commentaries/views.py
index 339bab4f935cf0a3bcaefbf36a682982be70c215..1ae2de1ceffbf60e70bfde80aa58b16db5149c22 100644
--- a/commentaries/views.py
+++ b/commentaries/views.py
@@ -299,45 +299,10 @@ def browse(request, discipline, nrweeksback):
 def commentary_detail(request, arxiv_or_DOI_string):
     commentary = get_object_or_404(Commentary, arxiv_or_DOI_string=arxiv_or_DOI_string)
     comments = commentary.comment_set.all()
-    if request.method == 'POST':
-        form = CommentForm(request.POST, request.FILES)
-        if form.is_valid():
-            author = Contributor.objects.get(user=request.user)
-            newcomment = Comment(commentary=commentary, 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(),
-                                 )
-            newcomment.save()
-            author.nr_comments = Comment.objects.filter(author=author).count()
-            author.save()
-            context = {'ack_header': 'Thank you for contributing a Comment.',
-                       'ack_message': 'It will soon be vetted by an Editor.',
-                       'followup_message': 'Back to the ',
-                       'followup_link': reverse(
-                           'commentaries:commentary',
-                           kwargs={
-                                'arxiv_or_DOI_string': newcomment.commentary.arxiv_or_DOI_string
-                           }
-                       ),
-                       'followup_link_label': ' Commentary page you came from'
-                       }
-            return render(request, 'scipost/acknowledgement.html', context)
-    else:
-        form = CommentForm()
+    form = CommentForm()
     try:
-        author_replies = Comment.objects.filter(commentary=commentary,
-                                                is_author_reply=True,
-                                                status__gte=1)
+        author_replies = Comment.objects.filter(
+            commentary=commentary, is_author_reply=True, status__gte=1)
     except Comment.DoesNotExist:
         author_replies = ()
     context = {'commentary': commentary,
diff --git a/comments/managers.py b/comments/managers.py
new file mode 100644
index 0000000000000000000000000000000000000000..7b71d0454d88ad178a94393c21cc5b310ce23960
--- /dev/null
+++ b/comments/managers.py
@@ -0,0 +1,5 @@
+from django.db import models
+
+class CommentManager(models.Manager):
+    def vetted(self):
+        return self.filter(status__gte=1)
diff --git a/comments/models.py b/comments/models.py
index e449d2a7382c0b0054082c1772ac5f46cf689b64..3851d0737a0a93519a09ae986e63be0dad6498f5 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -10,6 +10,8 @@ from scipost.models import TimeStampedModel, Contributor
 from submissions.models import Submission, Report
 from theses.models import ThesisLink
 
+from .managers import CommentManager
+
 COMMENT_CATEGORIES = (
     ('ERR', 'erratum'),
     ('REM', 'remark'),
@@ -37,19 +39,24 @@ class Comment(TimeStampedModel):
     on a particular publication or in reply to an earlier Comment. """
 
     status = models.SmallIntegerField(default=0)
-    vetted_by = models.ForeignKey(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])
+    vetted_by = models.ForeignKey(
+        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.
     commentary = models.ForeignKey(Commentary, blank=True, null=True, on_delete=models.CASCADE)
     submission = models.ForeignKey(Submission, blank=True, null=True, on_delete=models.CASCADE)
     thesislink = models.ForeignKey(ThesisLink, blank=True, null=True, on_delete=models.CASCADE)
     is_author_reply = models.BooleanField(default=False)
-    in_reply_to_comment = models.ForeignKey('self', blank=True, null=True,
-                                            on_delete=models.CASCADE)
+    in_reply_to_comment = models.ForeignKey('self', blank=True, null=True, on_delete=models.CASCADE)
     in_reply_to_report = models.ForeignKey(Report, blank=True, null=True, on_delete=models.CASCADE)
     author = models.ForeignKey(Contributor, on_delete=models.CASCADE)
     anonymous = models.BooleanField(default=False, verbose_name='Publish anonymously')
@@ -64,19 +71,20 @@ 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,
-                                           verbose_name='optional remarks for the Editors only')
+    remarks_for_editors = models.TextField(default='', blank=True, verbose_name='optional remarks for the Editors only')
     date_submitted = models.DateTimeField('date submitted')
     # Opinions
     nr_A = models.PositiveIntegerField(default=0)
-    in_agreement = models.ManyToManyField(Contributor,
-                                          related_name='in_agreement', blank=True)
+    in_agreement = models.ManyToManyField(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(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(
+        Contributor,
+        related_name='in_disagreement',
+        blank=True
+    )
+    objects = CommentManager()
 
     def __str__(self):
         return ('by ' + self.author.user.first_name + ' ' + self.author.user.last_name +
diff --git a/comments/templates/comments/new_comment.html b/comments/templates/comments/new_comment.html
new file mode 100644
index 0000000000000000000000000000000000000000..80f19afad8798a122d2dd5873019c139d02849ec
--- /dev/null
+++ b/comments/templates/comments/new_comment.html
@@ -0,0 +1,27 @@
+{% if user.is_authenticated and open_for_commenting and perms.scipost.can_submit_comments %}
+<hr />
+
+<div class="row">
+    <div class="col-12">
+        <div class="panel">
+            <h2>Contribute a Comment:</h2>
+        </div>
+    </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 %}
+          {% load crispy_forms_tags %}
+          {% crispy form %}
+        </form>
+    </div>
+    <div class="col-12">
+        <h3>Preview of your comment:</h3>
+        <p id="preview-comment_text"></p>
+    </div>
+</div>
+
+{% endif %}
diff --git a/comments/test_views.py b/comments/test_views.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1824139a5c2dd7def2f41ae2f6c6fd742914e41
--- /dev/null
+++ b/comments/test_views.py
@@ -0,0 +1,126 @@
+from django.test import TestCase, RequestFactory, Client
+from django.urls import reverse, reverse_lazy
+from django.contrib.auth.models import Group
+from django.contrib.messages.storage.fallback import FallbackStorage
+from django.core.exceptions import PermissionDenied
+
+from scipost.factories import ContributorFactory
+from theses.factories import ThesisLinkFactory
+from submissions.factories import EICassignedSubmissionFactory
+from commentaries.factories import UnpublishedVettedCommentaryFactory
+
+from .factories import CommentFactory
+from .forms import CommentForm
+from .models import Comment
+from .views import new_comment
+
+from common.helpers import model_form_data
+
+
+class TestNewComment(TestCase):
+    fixtures = ['groups', 'permissions']
+
+    def install_messages_middleware(self, request):
+        # I don't know what the following three lines do, but they help make a RequestFactory
+        # work with the messages middleware
+        setattr(request, 'session', 'session')
+        messages = FallbackStorage(request)
+        setattr(request, '_messages', messages)
+
+    def test_submitting_comment_on_thesislink_creates_comment_and_redirects(self):
+        """ Valid Comment gets saved """
+
+        contributor = ContributorFactory()
+        thesislink = ThesisLinkFactory()
+        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        target = reverse('comments:new_comment', kwargs={'object_id': thesislink.id, 'type_of_object': 'thesislink'})
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 0)
+
+        request = RequestFactory().post(target, valid_comment_data)
+        self.install_messages_middleware(request)
+        request.user = contributor.user
+        response = new_comment(request, object_id=thesislink.id, type_of_object='thesislink')
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 1)
+
+        response.client = Client()
+        expected_redirect_link = reverse('theses:thesis', kwargs={'thesislink_id': thesislink.id})
+        self.assertRedirects(response, expected_redirect_link)
+
+    def test_submitting_comment_on_submission_creates_comment_and_redirects(self):
+        contributor = ContributorFactory()
+        submission = EICassignedSubmissionFactory()
+        submission.open_for_commenting = True
+        submission.save()
+        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
+        target = reverse(
+            'comments:new_comment',
+            kwargs={'object_id': submission.id, 'type_of_object': 'submission'},
+        )
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 0)
+
+        request = RequestFactory().post(target, valid_comment_data)
+        self.install_messages_middleware(request)
+        request.user = contributor.user
+        response = new_comment(request, object_id=submission.id, type_of_object='submission')
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 1)
+
+        response.client = Client()
+        expected_redirect_link = reverse(
+            'submissions:submission',
+            kwargs={'arxiv_identifier_w_vn_nr': submission.arxiv_identifier_w_vn_nr}
+        )
+        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)
+        target = reverse('comments:new_comment', kwargs={'object_id': commentary.id, 'type_of_object': 'commentary'})
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 0)
+
+        request = RequestFactory().post(target, valid_comment_data)
+        self.install_messages_middleware(request)
+        request.user = contributor.user
+        response = new_comment(request, object_id=commentary.id, type_of_object='commentary')
+
+        comment_count = commentary.comment_set.count()
+        self.assertEqual(comment_count, 1)
+
+        response.client = Client()
+        expected_redirect_link = reverse(
+            '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)
+        target = reverse(
+            'comments:new_comment',
+            kwargs={'object_id': submission.id, 'type_of_object': 'submission'},
+        )
+
+        comment_count = Comment.objects.filter(author=contributor).count()
+        self.assertEqual(comment_count, 0)
+
+        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')
diff --git a/comments/urls.py b/comments/urls.py
index b417f028aa127ff3d16f325d953216416131e4a9..3d1747ee28e087ff4a52d0da5cd0a794032fc935 100644
--- a/comments/urls.py
+++ b/comments/urls.py
@@ -10,4 +10,5 @@ urlpatterns = [
     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')
 ]
diff --git a/comments/views.py b/comments/views.py
index 254206ca81d8248a8dadc41049646b1566b4ba8d..ce859b86553018a6788aee4a82472c71cfa388f8 100644
--- a/comments/views.py
+++ b/comments/views.py
@@ -1,17 +1,79 @@
 from django.utils import timezone
-from django.shortcuts import get_object_or_404, render
+from django.shortcuts import get_object_or_404, render, redirect
 from django.contrib.auth.decorators import permission_required
+from django.contrib import messages
 from django.core.mail import EmailMessage
 from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect
+from django.core.exceptions import PermissionDenied
+from django.http import HttpResponseRedirect, Http404
+
+import strings
 
 from .models import Comment
 from .forms import CommentForm, VetCommentForm, comment_refusal_dict
 
 from scipost.models import Contributor, title_dict
+from theses.models import ThesisLink
 from submissions.utils import SubmissionUtils
-from submissions.models import Report
+from submissions.models import Submission, Report
+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
 
 @permission_required('scipost.can_vet_comments', raise_exception=True)
 def vet_submitted_comments(request):
diff --git a/common/helpers/__init__.py b/common/helpers/__init__.py
index d91d1905c12f9529071e5406d04f90cd16891b0f..d1875920b99074217a6ce3d80fa10128bd4e568a 100644
--- a/common/helpers/__init__.py
+++ b/common/helpers/__init__.py
@@ -1,3 +1,6 @@
+import random
+import string
+
 def model_form_data(model, form_class, form_kwargs={}):
     '''
     Returns a dict that can be used to instantiate a form object.
@@ -25,6 +28,14 @@ def model_form_data(model, form_class, form_kwargs={}):
     form_fields = list(form_class(**form_kwargs).fields.keys())
     return filter_keys(model_data, form_fields)
 
+def random_arxiv_identifier_with_version_number():
+    return random_arxiv_identifier_without_version_number() + "v0"
+
+def random_arxiv_identifier_without_version_number():
+    return random_digits(4) + "." + random_digits(5)
+
+def random_digits(n):
+    return "".join(random.choice(string.digits) for _ in range(n))
 
 def filter_keys(dictionary, keys_to_keep):
     # Field is empty if not on model.
diff --git a/scipost/factories.py b/scipost/factories.py
index 27ebc93ef459df1de461cf65af874680d0ecbb48..e32c408deb837497d49cfbffff1e8e8c49b76b23 100644
--- a/scipost/factories.py
+++ b/scipost/factories.py
@@ -12,7 +12,7 @@ class ContributorFactory(factory.django.DjangoModelFactory):
 
     title = "MR"
     user = factory.SubFactory('scipost.factories.UserFactory', contributor=None)
-    status = 1
+    status = 1  # normal user
     vetted_by = factory.SubFactory('scipost.factories.ContributorFactory', vetted_by=None)
 
 
diff --git a/strings/__init__.py b/strings/__init__.py
index f51088e3aeecb9d059e14d341717c77936519e6c..acb0df6ceafab9bb8a85bae4049a9ccb7fdc8cec 100644
--- a/strings/__init__.py
+++ b/strings/__init__.py
@@ -7,6 +7,9 @@ acknowledge_request_commentary = (
     "Your request will soon be handled by an Editor. <br>"
     "Thank you for your request for a Commentary Page."
 )
+acknowledge_submit_comment = (
+    "Thank you for contributing a Comment. It will soon be vetted by an Editor."
+)
 
 # Arxiv response is not valid
 arxiv_caller_errormessages = {
diff --git a/submissions/factories.py b/submissions/factories.py
index 7f07c30523a94c2ec6c33b0b423a47cb62bd756f..1abdf6974e4c7caa28ae6ebcb49a9eb1096df83a 100644
--- a/submissions/factories.py
+++ b/submissions/factories.py
@@ -1,8 +1,7 @@
 import factory
-import random
-import string
 
 from scipost.factories import ContributorFactory
+from common.helpers import random_arxiv_identifier_with_version_number
 
 from .models import Submission
 
@@ -18,21 +17,10 @@ class SubmissionFactory(factory.django.DjangoModelFactory):
     abstract = factory.Faker('text')
     arxiv_link = factory.Faker('uri')
     arxiv_identifier_w_vn_nr = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number())
-    arxiv_identifier_wo_vn_nr = factory.LazyAttribute(lambda obj: obj.arxiv_identifier_w_vn_nr[0:-2])
     domain = 'E'
 
 
 class EICassignedSubmissionFactory(SubmissionFactory):
     status = 'EICassigned'
     editor_in_charge = factory.SubFactory(ContributorFactory)
-
-
-
-def random_arxiv_identifier_with_version_number():
-    return random_arxiv_identifier_without_version_number() + "v0"
-
-def random_arxiv_identifier_without_version_number():
-    return random_digits(4) + "." + random_digits(5)
-
-def random_digits(n):
-    return "".join(random.choice(string.digits) for _ in range(n))
+    open_for_commenting = True
diff --git a/submissions/templates/submissions/submission_detail.html b/submissions/templates/submissions/submission_detail.html
index 68750602f0e9eddaf708bac9af84bef5b2d2d317..3e793e6ced6e4fdf739845e90fc5ef1584e0fb95 100644
--- a/submissions/templates/submissions/submission_detail.html
+++ b/submissions/templates/submissions/submission_detail.html
@@ -205,7 +205,7 @@
 				    <p>
 				      <a target="_blank" href="{{ reply.file_attachment.url }}">
 					{% if reply.file_attachment|is_image %}
-					<img class="attachment attachment-comment" src="{{ reply.file_attachment.url }}">                                                                              
+					<img class="attachment attachment-comment" src="{{ reply.file_attachment.url }}">
 					{% else %}
 					{{ reply.file_attachment|filename }}<br><small>{{ reply.file_attachment.size|filesizeformat }}</small>
 					{% endif %}
@@ -304,37 +304,8 @@
 
 {% endif %}
 
-
-
 {% include 'scipost/comments_block.html' %}
 
-{% if user.is_authenticated and submission.open_for_commenting and perms.scipost.can_submit_comments %}
-<hr>
-<div id="contribute_comment">
-    <div class="row">
-        <div class="col-12">
-            <div class="panel">
-                <h2>Contribute a Comment:</h2>
-            </div>
-        </div>
-    </div>
-    <div class="row">
-        <div class="col-12">
-            <form enctype="multipart/form-data" action="{% url 'submissions:submission' arxiv_identifier_w_vn_nr=submission.arxiv_identifier_w_vn_nr %}" method="post">
-                {% csrf_token %}
-                {% load crispy_forms_tags %}
-                {% crispy form %}
-            </form>
-        </div>
-    </div>
-
-    <div class="row">
-        <div class="col-12">
-            <h3>Preview of your comment:</h3>
-            <p id="preview-comment_text"></p>
-        </div>
-    </div>
-</div>
-{% endif %}
+{% include 'comments/new_comment.html' with object_id=submission.id type_of_object='submission' open_for_commenting=submission.open_for_commenting %}
 
 {% endblock content %}
diff --git a/submissions/test_views.py b/submissions/test_views.py
index 5eef315b06ebc633dbb967284d7d0336a8073e17..bb177e9292a3dc57e2c9a01a91c3a161e47ffb89 100644
--- a/submissions/test_views.py
+++ b/submissions/test_views.py
@@ -3,6 +3,8 @@ from django.test import Client
 from submissions.views import *
 import django.core.urlresolvers
 
+from .factories import EICassignedSubmissionFactory
+
 
 class PrefillUsingIdentifierTest(TestCase):
     fixtures = ['permissions', 'groups', 'contributors']
@@ -45,3 +47,19 @@ class SubmitManuscriptTest(TestCase):
                                {**params, **extras})
 
         self.assertEqual(response.status_code, 200)
+
+
+class SubmissionDetailTest(TestCase):
+    fixtures = ['permissions', 'groups']
+
+    def setUp(self):
+        self.client = Client()
+        self.submission = EICassignedSubmissionFactory()
+        self.target = reverse(
+            'submissions:submission',
+            kwargs={'arxiv_identifier_w_vn_nr': self.submission.arxiv_identifier_w_vn_nr}
+        )
+
+    def test_status_code_200(self):
+        response = self.client.get(self.target)
+        self.assertEqual(response.status_code, 200)
diff --git a/submissions/views.py b/submissions/views.py
index f69b23d8c9e75518494648553fe98f18d87bdf63..2681da5f9dfafd7d11f42ee3bb6f18a085af8dc5 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -285,41 +285,8 @@ def submission_detail(request, 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)
-    if request.method == 'POST':
-        form = CommentForm(request.POST, request.FILES)
-        if form.is_valid():
-            author = Contributor.objects.get(user=request.user)
-            newcomment = Comment(
-                submission=submission,
-                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(),
-            )
-            newcomment.save()
-            author.nr_comments = Comment.objects.filter(author=author).count()
-            author.save()
-            context = {'ack_header': 'Thank you for contributing a Comment.',
-                       '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()
+
+    form = CommentForm()
 
     reports = submission.report_set.all()
     try:
diff --git a/theses/templates/theses/thesis_detail.html b/theses/templates/theses/thesis_detail.html
index f355fc701ff43ee369ebbfe9f8fc5d13e60f7270..edde03144f188effb6c6fad2c30bf6783b4ac6b9 100644
--- a/theses/templates/theses/thesis_detail.html
+++ b/theses/templates/theses/thesis_detail.html
@@ -50,30 +50,6 @@
 
 {% include 'scipost/comments_block.html' %}
 
-{% if user.is_authenticated and thesislink.open_for_commenting and perms.scipost.can_submit_comments %}
-<hr />
-
-<div class="row">
-    <div class="col-12">
-        <div class="panel">
-            <h2>Contribute a Comment:</h2>
-        </div>
-    </div>
-</div>
-<div class="row">
-    <div class="col-12">
-        <form enctype="multipart/form-data" action="{% url 'theses:thesis' thesislink_id=thesislink.id %}" method="post">
-          {% csrf_token %}
-          {% load crispy_forms_tags %}
-          {% crispy form %}
-        </form>
-    </div>
-    <div class="col-12">
-        <h3>Preview of your comment:</h3>
-        <p id="preview-comment_text"></p>
-    </div>
-</div>
-
-{% endif %}
+{% include 'comments/new_comment.html' with object_id=thesislink.id type_of_object='thesislink' open_for_commenting=thesislink.open_for_commenting %}
 
 {% endblock content %}
diff --git a/theses/test_views.py b/theses/test_views.py
index b5ee851bcf04cd742cfc21c0f7c33a3976019550..8f6d5f202018e73ecbec408158447ede95c0cc6b 100644
--- a/theses/test_views.py
+++ b/theses/test_views.py
@@ -30,24 +30,6 @@ class TestThesisDetail(TestCase):
         response = client.post(target)
         self.assertEqual(response.status_code, 200)
 
-    def test_submitting_comment_creates_comment(self):
-        """ Valid Comment gets saved """
-
-        contributor = ContributorFactory()
-        thesislink = ThesisLinkFactory()
-        valid_comment_data = model_form_data(CommentFactory.build(), CommentForm)
-        target = reverse('theses:thesis', kwargs={'thesislink_id': thesislink.id})
-
-        comment_count = Comment.objects.filter(author=contributor).count()
-        self.assertEqual(comment_count, 0)
-
-        request = RequestFactory().post(target, valid_comment_data)
-        request.user = contributor.user
-        response = thesis_detail(request, thesislink_id=thesislink.id)
-
-        comment_count = Comment.objects.filter(author=contributor).count()
-        self.assertEqual(comment_count, 1)
-
 
 class TestRequestThesisLink(TestCase):
     fixtures = ['groups', 'permissions']
@@ -186,7 +168,7 @@ class TestTheses(TestCase):
         response = self.client.get(self.target)
         search_results = response.context["search_results"]
         recent_theses = response.context["recent_theses"]
-        self.assertEqual(search_results.exists(), False)
+        self.assertEqual(search_results, [])
         self.assertEqual(recent_theses.exists(), True)
 
     def test_search_query_on_author(self):
diff --git a/theses/views.py b/theses/views.py
index b000a467910850a4be93dde39ab4db7acc7036d6..87d39a7f6d182336dc43c3e32c1de106acd1bdc7 100644
--- a/theses/views.py
+++ b/theses/views.py
@@ -131,48 +131,12 @@ def browse(request, discipline, nrweeksback):
 
 def thesis_detail(request, thesislink_id):
     thesislink = get_object_or_404(ThesisLink, pk=thesislink_id)
-    comments = thesislink.comment_set.all()
-    if request.method == 'POST':
-        form = CommentForm(request.POST)
-        if form.is_valid():
-            author = Contributor.objects.get(user=request.user)
-            new_comment = Comment(
-                thesislink=thesislink,
-                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'],
-                comment_text=form.cleaned_data['comment_text'],
-                remarks_for_editors=form.cleaned_data['remarks_for_editors'],
-                date_submitted=timezone.now(),
-            )
-            new_comment.save()
-            author.nr_comments = Comment.objects.filter(author=author).count()
-            author.save()
-            context = {
-                'ack_header': 'Thank you for contributing a Comment.',
-                'ack_message': 'It will soon be vetted by an Editor.',
-                'followup_message': 'Back to the ',
-                'followup_link': reverse(
-                    'theses:thesis',
-                    kwargs={'thesislink_id': new_comment.thesislink.id}
-                ),
-                'followup_link_label': ' Thesis Link page you came from'
-            }
-            return render(request, 'scipost/acknowledgement.html', context)
-    else:
-        form = CommentForm()
+    form = CommentForm()
+
+    comments = thesislink.comment_set
+    author_replies = comments.filter(is_author_reply=True)
 
-    try:
-        author_replies = Comment.objects.filter(thesislink=thesislink, is_author_reply=True)
-    except Comment.DoesNotExist:
-        author_replies = ()
     context = {'thesislink': thesislink,
-               'comments': comments.filter(status__gte=1).order_by('date_submitted'),
+               'comments': comments.vetted().order_by('date_submitted'),
                'author_replies': author_replies, 'form': form}
     return render(request, 'theses/thesis_detail.html', context)