diff --git a/.gitignore b/.gitignore
index a2274b00d145b376cee7323396849040f0118584..2673ca550fb5d82633cc80cf1c145f3c9b1d157e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 __pycache__
 
 *.json
+!**/fixtures/*.json
 
 *~
 
@@ -14,4 +15,4 @@ SCIPOST_JOURNALS
 UPLOADS
 
 docs/_build
-local_files
\ No newline at end of file
+local_files
diff --git a/comments/forms.py b/comments/forms.py
index 0e94f326ed13e5e2388230d1c5d4cdf41a19fecf..d87f969a38eb8bb7c03fba8d8fc7bfb632141207 100644
--- a/comments/forms.py
+++ b/comments/forms.py
@@ -62,7 +62,6 @@ class CommentForm(forms.ModelForm):
             )
 
 
-
 class VetCommentForm(forms.Form):
     action_option = forms.ChoiceField(widget=forms.RadioSelect, choices=COMMENT_ACTION_CHOICES,
                                       required=True, label='Action')
diff --git a/comments/models.py b/comments/models.py
index d18801033f5fa367ab1b16bfbf812dd0cb0e25fa..1e6c1c5d1da23a916f201a3e664b24e001ab0d7d 100644
--- a/comments/models.py
+++ b/comments/models.py
@@ -33,15 +33,11 @@ COMMENT_STATUS = (
 )
 comment_status_dict = dict(COMMENT_STATUS)
 
+
 class Comment(models.Model):
     """ A Comment is an unsollicited note, submitted by a Contributor,
     on a particular publication or in reply to an earlier Comment. """
-    # status:
-    # 1: vetted
-    # 0: unvetted
-    # -1: rejected (unclear)
-    # -2: rejected (incorrect)
-    # -3: rejected (not useful)
+
     status = models.SmallIntegerField(default=0)
     vetted_by = models.ForeignKey(Contributor, blank=True, null=True,
                                   on_delete=models.CASCADE,
diff --git a/journals/models.py b/journals/models.py
index 8581d9d7915b7f7f4ad6acc16d0d5b2097ad3ed7..7afb01756af51cc4ac083b00d0fbff342e9d2b27 100644
--- a/journals/models.py
+++ b/journals/models.py
@@ -22,9 +22,11 @@ SCIPOST_JOURNALS = (
     )
 journals_dict = dict(SCIPOST_JOURNALS)
 
+
 class JournalNameError(Exception):
     def __init__(self, name):
         self.name = name
+
     def __str__(self):
         return self.name
 
diff --git a/requirements.txt b/requirements.txt
index 1dbfb212397ecfd37a21f1fac65f3bafd5975002..b25c7e2fba57bc091dcc0578fac5910b75817117 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -10,14 +10,18 @@ django-mptt==0.8.6
 django-simple-captcha==0.5.3
 djangorestframework==3.5.3
 docutils==0.12
+factory-boy==2.7.0
+fake-factory==0.7.2
 feedparser==5.2.1
 imagesize==0.7.1
 Jinja2==2.8
 Markdown==2.6.7
 MarkupSafe==0.23
+pep8==1.7.0
 Pillow==3.4.2
 psycopg2==2.6.2
 Pygments==2.1.3
+python-dateutil==2.6.0
 pytz==2016.7
 requests==2.12.1
 six==1.10.0
diff --git a/scipost/factories.py b/scipost/factories.py
new file mode 100644
index 0000000000000000000000000000000000000000..80a4c045804aa2cf133823d882323c7d20013927
--- /dev/null
+++ b/scipost/factories.py
@@ -0,0 +1,41 @@
+import factory
+
+from django.contrib.auth import get_user_model
+from django.contrib.auth.models import Group, User
+
+from .models import Contributor
+
+
+class ContributorFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = Contributor
+
+    title = "MR"
+    user = factory.SubFactory(UserFactory, contributor=None)
+    status = 1
+    vetted_by = factory.SubFactory(ContributorFactory)
+
+
+class UserFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = get_user_model()
+
+    username = factory.Faker('user_name')
+    password = factory.Faker('password')
+    email = factory.Faker('safe_email')
+    first_name = factory.Faker('first_name')
+    last_name = factory.Faker('last_name')
+    # When user object is created, associate new Contributor object to it.
+    contributor = factory.RelatedFactory(ContributorFactory, 'user')
+
+    @factory.post_generation
+    def groups(self, create, extracted, **kwargs):
+        # If the object is not saved, we cannot use many-to-many relationship.
+        if not create:
+            return
+        # If group objects were passed in, use those.
+        if extracted:
+            for group in extracted:
+                self.groups.add(group)
+        else:
+            self.groups.add(Group.objects.get(name="Registered Contributors"))
diff --git a/scipost/fixtures/contributors.json b/scipost/fixtures/contributors.json
new file mode 100644
index 0000000000000000000000000000000000000000..a4863604278b1460829d963d108b4db098579aef
--- /dev/null
+++ b/scipost/fixtures/contributors.json
@@ -0,0 +1,32 @@
+[
+  {
+    "model": "auth.user",
+    "pk": 1,
+    "fields": {
+      "password": "pbkdf2_sha256$30000$iqtXX60Ahqcx$IKfNZNSMbSca/agzPXHTdEej3dXhQi1sK/MCrBTnuW4=",
+      "last_login": null,
+      "is_superuser": false,
+      "username": "Test",
+      "first_name": "Firstname",
+      "last_name": "Testuser",
+      "email": "testuser@test.com",
+      "is_staff": false,
+      "is_active": true,
+      "date_joined": "2016-12-14T20:41:31.282Z",
+      "groups": [
+        6
+      ],
+      "user_permissions": []
+    }
+  },
+  {
+    "model": "scipost.contributor",
+    "pk": 2,
+    "fields": {
+      "user": 1,
+      "status": 1,
+      "title": "MR",
+      "vetted_by": 2
+    }
+  }
+]
diff --git a/scipost/fixtures/groups.json b/scipost/fixtures/groups.json
new file mode 100644
index 0000000000000000000000000000000000000000..82fafdc4738001941947ba92ecf8d9a5749ad11d
--- /dev/null
+++ b/scipost/fixtures/groups.json
@@ -0,0 +1,116 @@
+[
+{
+    "model": "auth.group",
+    "pk": 1,
+    "fields": {
+        "name": "SciPost Administrators",
+        "permissions": [
+            143,
+            130,
+            131,
+            148,
+            128,
+            147,
+            139,
+            137,
+            140,
+            126,
+            138,
+            142
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 2,
+    "fields": {
+        "name": "Advisory Board",
+        "permissions": [
+            128
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 3,
+    "fields": {
+        "name": "Editorial Administrators",
+        "permissions": [
+            143,
+            148,
+            147,
+            149,
+            142
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 4,
+    "fields": {
+        "name": "Editorial College",
+        "permissions": [
+            144,
+            145,
+            142,
+            132
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 5,
+    "fields": {
+        "name": "Vetting Editors",
+        "permissions": [
+            139,
+            137,
+            140,
+            138
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 6,
+    "fields": {
+        "name": "Registered Contributors",
+        "permissions": [
+            134,
+            146,
+            135,
+            136,
+            133,
+            141
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 7,
+    "fields": {
+        "name": "Testers",
+        "permissions": []
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 8,
+    "fields": {
+        "name": "Ambassadors",
+        "permissions": [
+            128
+        ]
+    }
+},
+{
+    "model": "auth.group",
+    "pk": 9,
+    "fields": {
+        "name": "Junior Ambassadors",
+        "permissions": [
+            127
+        ]
+    }
+}
+]
diff --git a/scipost/fixtures/permissions.json b/scipost/fixtures/permissions.json
new file mode 100644
index 0000000000000000000000000000000000000000..a718c3476c978d97c20a15d8b81f01ac0500596f
--- /dev/null
+++ b/scipost/fixtures/permissions.json
@@ -0,0 +1,1343 @@
+[
+{
+    "model": "auth.permission",
+    "pk": 1,
+    "fields": {
+        "name": "Can add log entry",
+        "content_type": 1,
+        "codename": "add_logentry"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 2,
+    "fields": {
+        "name": "Can change log entry",
+        "content_type": 1,
+        "codename": "change_logentry"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 3,
+    "fields": {
+        "name": "Can delete log entry",
+        "content_type": 1,
+        "codename": "delete_logentry"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 4,
+    "fields": {
+        "name": "Can add user",
+        "content_type": 2,
+        "codename": "add_user"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 5,
+    "fields": {
+        "name": "Can change user",
+        "content_type": 2,
+        "codename": "change_user"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 6,
+    "fields": {
+        "name": "Can delete user",
+        "content_type": 2,
+        "codename": "delete_user"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 7,
+    "fields": {
+        "name": "Can add group",
+        "content_type": 3,
+        "codename": "add_group"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 8,
+    "fields": {
+        "name": "Can change group",
+        "content_type": 3,
+        "codename": "change_group"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 9,
+    "fields": {
+        "name": "Can delete group",
+        "content_type": 3,
+        "codename": "delete_group"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 10,
+    "fields": {
+        "name": "Can add permission",
+        "content_type": 4,
+        "codename": "add_permission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 11,
+    "fields": {
+        "name": "Can change permission",
+        "content_type": 4,
+        "codename": "change_permission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 12,
+    "fields": {
+        "name": "Can delete permission",
+        "content_type": 4,
+        "codename": "delete_permission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 13,
+    "fields": {
+        "name": "Can add content type",
+        "content_type": 5,
+        "codename": "add_contenttype"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 14,
+    "fields": {
+        "name": "Can change content type",
+        "content_type": 5,
+        "codename": "change_contenttype"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 15,
+    "fields": {
+        "name": "Can delete content type",
+        "content_type": 5,
+        "codename": "delete_contenttype"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 16,
+    "fields": {
+        "name": "Can add session",
+        "content_type": 6,
+        "codename": "add_session"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 17,
+    "fields": {
+        "name": "Can change session",
+        "content_type": 6,
+        "codename": "change_session"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 18,
+    "fields": {
+        "name": "Can delete session",
+        "content_type": 6,
+        "codename": "delete_session"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 19,
+    "fields": {
+        "name": "Can add captcha store",
+        "content_type": 7,
+        "codename": "add_captchastore"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 20,
+    "fields": {
+        "name": "Can change captcha store",
+        "content_type": 7,
+        "codename": "change_captchastore"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 21,
+    "fields": {
+        "name": "Can delete captcha store",
+        "content_type": 7,
+        "codename": "delete_captchastore"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 22,
+    "fields": {
+        "name": "Can add user object permission",
+        "content_type": 8,
+        "codename": "add_userobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 23,
+    "fields": {
+        "name": "Can change user object permission",
+        "content_type": 8,
+        "codename": "change_userobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 24,
+    "fields": {
+        "name": "Can delete user object permission",
+        "content_type": 8,
+        "codename": "delete_userobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 25,
+    "fields": {
+        "name": "Can add group object permission",
+        "content_type": 9,
+        "codename": "add_groupobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 26,
+    "fields": {
+        "name": "Can change group object permission",
+        "content_type": 9,
+        "codename": "change_groupobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 27,
+    "fields": {
+        "name": "Can delete group object permission",
+        "content_type": 9,
+        "codename": "delete_groupobjectpermission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 28,
+    "fields": {
+        "name": "Can add commentary",
+        "content_type": 10,
+        "codename": "add_commentary"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 29,
+    "fields": {
+        "name": "Can change commentary",
+        "content_type": 10,
+        "codename": "change_commentary"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 30,
+    "fields": {
+        "name": "Can delete commentary",
+        "content_type": 10,
+        "codename": "delete_commentary"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 31,
+    "fields": {
+        "name": "Can add comment",
+        "content_type": 11,
+        "codename": "add_comment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 32,
+    "fields": {
+        "name": "Can change comment",
+        "content_type": 11,
+        "codename": "change_comment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 33,
+    "fields": {
+        "name": "Can delete comment",
+        "content_type": 11,
+        "codename": "delete_comment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 34,
+    "fields": {
+        "name": "Can add issue",
+        "content_type": 12,
+        "codename": "add_issue"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 35,
+    "fields": {
+        "name": "Can change issue",
+        "content_type": 12,
+        "codename": "change_issue"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 36,
+    "fields": {
+        "name": "Can delete issue",
+        "content_type": 12,
+        "codename": "delete_issue"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 37,
+    "fields": {
+        "name": "Can add journal",
+        "content_type": 13,
+        "codename": "add_journal"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 38,
+    "fields": {
+        "name": "Can change journal",
+        "content_type": 13,
+        "codename": "change_journal"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 39,
+    "fields": {
+        "name": "Can delete journal",
+        "content_type": 13,
+        "codename": "delete_journal"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 40,
+    "fields": {
+        "name": "Can add unregistered author",
+        "content_type": 14,
+        "codename": "add_unregisteredauthor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 41,
+    "fields": {
+        "name": "Can change unregistered author",
+        "content_type": 14,
+        "codename": "change_unregisteredauthor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 42,
+    "fields": {
+        "name": "Can delete unregistered author",
+        "content_type": 14,
+        "codename": "delete_unregisteredauthor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 43,
+    "fields": {
+        "name": "Can add deposit",
+        "content_type": 15,
+        "codename": "add_deposit"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 44,
+    "fields": {
+        "name": "Can change deposit",
+        "content_type": 15,
+        "codename": "change_deposit"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 45,
+    "fields": {
+        "name": "Can delete deposit",
+        "content_type": 15,
+        "codename": "delete_deposit"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 46,
+    "fields": {
+        "name": "Can add publication",
+        "content_type": 16,
+        "codename": "add_publication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 47,
+    "fields": {
+        "name": "Can change publication",
+        "content_type": 16,
+        "codename": "change_publication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 48,
+    "fields": {
+        "name": "Can delete publication",
+        "content_type": 16,
+        "codename": "delete_publication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 49,
+    "fields": {
+        "name": "Can add volume",
+        "content_type": 17,
+        "codename": "add_volume"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 50,
+    "fields": {
+        "name": "Can change volume",
+        "content_type": 17,
+        "codename": "change_volume"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 51,
+    "fields": {
+        "name": "Can delete volume",
+        "content_type": 17,
+        "codename": "delete_volume"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 52,
+    "fields": {
+        "name": "Can add news item",
+        "content_type": 18,
+        "codename": "add_newsitem"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 53,
+    "fields": {
+        "name": "Can change news item",
+        "content_type": 18,
+        "codename": "change_newsitem"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 54,
+    "fields": {
+        "name": "Can delete news item",
+        "content_type": 18,
+        "codename": "delete_newsitem"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 55,
+    "fields": {
+        "name": "Can add precooked email",
+        "content_type": 19,
+        "codename": "add_precookedemail"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 56,
+    "fields": {
+        "name": "Can change precooked email",
+        "content_type": 19,
+        "codename": "change_precookedemail"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 57,
+    "fields": {
+        "name": "Can delete precooked email",
+        "content_type": 19,
+        "codename": "delete_precookedemail"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 58,
+    "fields": {
+        "name": "Can add affiliation object",
+        "content_type": 20,
+        "codename": "add_affiliationobject"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 59,
+    "fields": {
+        "name": "Can change affiliation object",
+        "content_type": 20,
+        "codename": "change_affiliationobject"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 60,
+    "fields": {
+        "name": "Can delete affiliation object",
+        "content_type": 20,
+        "codename": "delete_affiliationobject"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 61,
+    "fields": {
+        "name": "Can add registration invitation",
+        "content_type": 21,
+        "codename": "add_registrationinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 62,
+    "fields": {
+        "name": "Can change registration invitation",
+        "content_type": 21,
+        "codename": "change_registrationinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 63,
+    "fields": {
+        "name": "Can delete registration invitation",
+        "content_type": 21,
+        "codename": "delete_registrationinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 64,
+    "fields": {
+        "name": "Can add spb membership agreement",
+        "content_type": 22,
+        "codename": "add_spbmembershipagreement"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 65,
+    "fields": {
+        "name": "Can change spb membership agreement",
+        "content_type": 22,
+        "codename": "change_spbmembershipagreement"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 66,
+    "fields": {
+        "name": "Can delete spb membership agreement",
+        "content_type": 22,
+        "codename": "delete_spbmembershipagreement"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 67,
+    "fields": {
+        "name": "Can add supporting partner",
+        "content_type": 23,
+        "codename": "add_supportingpartner"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 68,
+    "fields": {
+        "name": "Can change supporting partner",
+        "content_type": 23,
+        "codename": "change_supportingpartner"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 69,
+    "fields": {
+        "name": "Can delete supporting partner",
+        "content_type": 23,
+        "codename": "delete_supportingpartner"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 70,
+    "fields": {
+        "name": "Can add arc",
+        "content_type": 24,
+        "codename": "add_arc"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 71,
+    "fields": {
+        "name": "Can change arc",
+        "content_type": 24,
+        "codename": "change_arc"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 72,
+    "fields": {
+        "name": "Can delete arc",
+        "content_type": 24,
+        "codename": "delete_arc"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 73,
+    "fields": {
+        "name": "Can add graph",
+        "content_type": 25,
+        "codename": "add_graph"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 74,
+    "fields": {
+        "name": "Can view graph",
+        "content_type": 25,
+        "codename": "view_graph"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 75,
+    "fields": {
+        "name": "Can change graph",
+        "content_type": 25,
+        "codename": "change_graph"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 76,
+    "fields": {
+        "name": "Can delete graph",
+        "content_type": 25,
+        "codename": "delete_graph"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 77,
+    "fields": {
+        "name": "Can add contributor",
+        "content_type": 26,
+        "codename": "add_contributor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 78,
+    "fields": {
+        "name": "Can change contributor",
+        "content_type": 26,
+        "codename": "change_contributor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 79,
+    "fields": {
+        "name": "Can delete contributor",
+        "content_type": 26,
+        "codename": "delete_contributor"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 80,
+    "fields": {
+        "name": "Can add authorship claim",
+        "content_type": 27,
+        "codename": "add_authorshipclaim"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 81,
+    "fields": {
+        "name": "Can change authorship claim",
+        "content_type": 27,
+        "codename": "change_authorshipclaim"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 82,
+    "fields": {
+        "name": "Can delete authorship claim",
+        "content_type": 27,
+        "codename": "delete_authorshipclaim"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 83,
+    "fields": {
+        "name": "Can add unavailability period",
+        "content_type": 28,
+        "codename": "add_unavailabilityperiod"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 84,
+    "fields": {
+        "name": "Can change unavailability period",
+        "content_type": 28,
+        "codename": "change_unavailabilityperiod"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 85,
+    "fields": {
+        "name": "Can delete unavailability period",
+        "content_type": 28,
+        "codename": "delete_unavailabilityperiod"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 86,
+    "fields": {
+        "name": "Can add list",
+        "content_type": 29,
+        "codename": "add_list"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 87,
+    "fields": {
+        "name": "Can view list",
+        "content_type": 29,
+        "codename": "view_list"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 88,
+    "fields": {
+        "name": "Can change list",
+        "content_type": 29,
+        "codename": "change_list"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 89,
+    "fields": {
+        "name": "Can delete list",
+        "content_type": 29,
+        "codename": "delete_list"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 90,
+    "fields": {
+        "name": "Can add node",
+        "content_type": 30,
+        "codename": "add_node"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 91,
+    "fields": {
+        "name": "Can view node",
+        "content_type": 30,
+        "codename": "view_node"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 92,
+    "fields": {
+        "name": "Can change node",
+        "content_type": 30,
+        "codename": "change_node"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 93,
+    "fields": {
+        "name": "Can delete node",
+        "content_type": 30,
+        "codename": "delete_node"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 94,
+    "fields": {
+        "name": "Can add draft invitation",
+        "content_type": 31,
+        "codename": "add_draftinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 95,
+    "fields": {
+        "name": "Can change draft invitation",
+        "content_type": 31,
+        "codename": "change_draftinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 96,
+    "fields": {
+        "name": "Can delete draft invitation",
+        "content_type": 31,
+        "codename": "delete_draftinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 97,
+    "fields": {
+        "name": "Can add team",
+        "content_type": 32,
+        "codename": "add_team"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 98,
+    "fields": {
+        "name": "Can view team",
+        "content_type": 32,
+        "codename": "view_team"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 99,
+    "fields": {
+        "name": "Can change team",
+        "content_type": 32,
+        "codename": "change_team"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 100,
+    "fields": {
+        "name": "Can delete team",
+        "content_type": 32,
+        "codename": "delete_team"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 101,
+    "fields": {
+        "name": "Can add remark",
+        "content_type": 33,
+        "codename": "add_remark"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 102,
+    "fields": {
+        "name": "Can change remark",
+        "content_type": 33,
+        "codename": "change_remark"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 103,
+    "fields": {
+        "name": "Can delete remark",
+        "content_type": 33,
+        "codename": "delete_remark"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 104,
+    "fields": {
+        "name": "Can add editorial communication",
+        "content_type": 34,
+        "codename": "add_editorialcommunication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 105,
+    "fields": {
+        "name": "Can change editorial communication",
+        "content_type": 34,
+        "codename": "change_editorialcommunication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 106,
+    "fields": {
+        "name": "Can delete editorial communication",
+        "content_type": 34,
+        "codename": "delete_editorialcommunication"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 107,
+    "fields": {
+        "name": "Can add referee invitation",
+        "content_type": 35,
+        "codename": "add_refereeinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 108,
+    "fields": {
+        "name": "Can change referee invitation",
+        "content_type": 35,
+        "codename": "change_refereeinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 109,
+    "fields": {
+        "name": "Can delete referee invitation",
+        "content_type": 35,
+        "codename": "delete_refereeinvitation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 110,
+    "fields": {
+        "name": "Can add submission",
+        "content_type": 36,
+        "codename": "add_submission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 111,
+    "fields": {
+        "name": "Can change submission",
+        "content_type": 36,
+        "codename": "change_submission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 112,
+    "fields": {
+        "name": "Can delete submission",
+        "content_type": 36,
+        "codename": "delete_submission"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 113,
+    "fields": {
+        "name": "Can take editorial actions",
+        "content_type": 36,
+        "codename": "can_take_editorial_actions"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 114,
+    "fields": {
+        "name": "Can add report",
+        "content_type": 37,
+        "codename": "add_report"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 115,
+    "fields": {
+        "name": "Can change report",
+        "content_type": 37,
+        "codename": "change_report"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 116,
+    "fields": {
+        "name": "Can delete report",
+        "content_type": 37,
+        "codename": "delete_report"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 117,
+    "fields": {
+        "name": "Can add eic recommendation",
+        "content_type": 38,
+        "codename": "add_eicrecommendation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 118,
+    "fields": {
+        "name": "Can change eic recommendation",
+        "content_type": 38,
+        "codename": "change_eicrecommendation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 119,
+    "fields": {
+        "name": "Can delete eic recommendation",
+        "content_type": 38,
+        "codename": "delete_eicrecommendation"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 120,
+    "fields": {
+        "name": "Can add editorial assignment",
+        "content_type": 39,
+        "codename": "add_editorialassignment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 121,
+    "fields": {
+        "name": "Can change editorial assignment",
+        "content_type": 39,
+        "codename": "change_editorialassignment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 122,
+    "fields": {
+        "name": "Can delete editorial assignment",
+        "content_type": 39,
+        "codename": "delete_editorialassignment"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 123,
+    "fields": {
+        "name": "Can add thesis link",
+        "content_type": 40,
+        "codename": "add_thesislink"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 124,
+    "fields": {
+        "name": "Can change thesis link",
+        "content_type": 40,
+        "codename": "change_thesislink"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 125,
+    "fields": {
+        "name": "Can delete thesis link",
+        "content_type": 40,
+        "codename": "delete_thesislink"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 126,
+    "fields": {
+        "name": "Can vet registration requests",
+        "content_type": 26,
+        "codename": "can_vet_registration_requests"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 127,
+    "fields": {
+        "name": "Can draft registration invitations",
+        "content_type": 26,
+        "codename": "can_draft_registration_invitations"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 128,
+    "fields": {
+        "name": "Can manage registration invitations",
+        "content_type": 26,
+        "codename": "can_manage_registration_invitations"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 129,
+    "fields": {
+        "name": "Can invite Fellows",
+        "content_type": 26,
+        "codename": "can_invite_Fellows"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 130,
+    "fields": {
+        "name": "Can email group members",
+        "content_type": 26,
+        "codename": "can_email_group_members"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 131,
+    "fields": {
+        "name": "Can email particulars",
+        "content_type": 26,
+        "codename": "can_email_particulars"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 132,
+    "fields": {
+        "name": "Can view By-laws of Editorial College",
+        "content_type": 26,
+        "codename": "view_bylaws"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 133,
+    "fields": {
+        "name": "Can submit Comments",
+        "content_type": 26,
+        "codename": "can_submit_comments"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 134,
+    "fields": {
+        "name": "Can express opinion on Comments",
+        "content_type": 26,
+        "codename": "can_express_opinion_on_comments"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 135,
+    "fields": {
+        "name": "Can request opening of Commentara Pages",
+        "content_type": 26,
+        "codename": "can_request_commentary_pages"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 136,
+    "fields": {
+        "name": "Can request Thesis Links",
+        "content_type": 26,
+        "codename": "can_request_thesislinks"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 137,
+    "fields": {
+        "name": "Can vet Commentary page requests",
+        "content_type": 26,
+        "codename": "can_vet_commentary_requests"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 138,
+    "fields": {
+        "name": "Can vet Thesis Link requests",
+        "content_type": 26,
+        "codename": "can_vet_thesislink_requests"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 139,
+    "fields": {
+        "name": "Can vet Authorship claims",
+        "content_type": 26,
+        "codename": "can_vet_authorship_claims"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 140,
+    "fields": {
+        "name": "Can vet submitted Comments",
+        "content_type": 26,
+        "codename": "can_vet_comments"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 141,
+    "fields": {
+        "name": "Can submit manuscript",
+        "content_type": 26,
+        "codename": "can_submit_manuscript"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 142,
+    "fields": {
+        "name": "Can view Submissions Pool",
+        "content_type": 26,
+        "codename": "can_view_pool"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 143,
+    "fields": {
+        "name": "Can assign incoming Submissions to potential Editor-in-charge",
+        "content_type": 26,
+        "codename": "can_assign_submissions"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 144,
+    "fields": {
+        "name": "Can take charge (become Editor-in-charge) of submissions",
+        "content_type": 26,
+        "codename": "can_take_charge_of_submissions"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 145,
+    "fields": {
+        "name": "Can vet submitted Reports",
+        "content_type": 26,
+        "codename": "can_vet_submitted_reports"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 146,
+    "fields": {
+        "name": "Can act as a referee and submit reports on Submissions",
+        "content_type": 26,
+        "codename": "can_referee"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 147,
+    "fields": {
+        "name": "Can prepare recommendations for voting",
+        "content_type": 26,
+        "codename": "can_prepare_recommendations_for_voting"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 148,
+    "fields": {
+        "name": "Can fix the College voting decision",
+        "content_type": 26,
+        "codename": "can_fix_College_decision"
+    }
+},
+{
+    "model": "auth.permission",
+    "pk": 149,
+    "fields": {
+        "name": "Can publish accepted submission",
+        "content_type": 26,
+        "codename": "can_publish_accepted_submission"
+    }
+}
+]
diff --git a/scipost/management/commands/add_groups_and_permissions.py b/scipost/management/commands/add_groups_and_permissions.py
index b1bec7e869bd53965dfc402c1d8f29b86eb9634b..86a4ef7af77102d1c21cb930873bd6a59ee4d58f 100644
--- a/scipost/management/commands/add_groups_and_permissions.py
+++ b/scipost/management/commands/add_groups_and_permissions.py
@@ -5,21 +5,22 @@ from django.contrib.contenttypes.models import ContentType
 
 from scipost.models import Contributor
 
+
 class Command(BaseCommand):
     help = 'Defines groups and permissions'
-    
+
     def add_arguments(self, parser):
         """Append arguments optionally for setup of Contributor roles."""
-        parser.add_argument('-u', '--setup-user', metavar='<username>', type=str, required=False, 
+        parser.add_argument('-u', '--setup-user', metavar='<username>', type=str, required=False,
                             help='Username to make registered contributor')
-        parser.add_argument('-a', '--make-admin', required=False, action='store_true', 
+        parser.add_argument('-a', '--make-admin', required=False, action='store_true',
                             help='Grant admin permissions to user (superuser only)')
-        parser.add_argument('-t', '--make-tester',  required=False, action='store_true', 
+        parser.add_argument('-t', '--make-tester',  required=False, action='store_true',
                             help='Grant test permissions to user')
 
     def handle(self, *args, **options):
         """Append all user Groups and setup a Contributor roles to user."""
-        
+
         # Create Groups
         SciPostAdmin, created = Group.objects.get_or_create(name='SciPost Administrators')
         AdvisoryBoard, created = Group.objects.get_or_create(name='Advisory Board')
@@ -203,7 +204,7 @@ class Command(BaseCommand):
         )
 
         self.stdout.write(self.style.SUCCESS('Successfully created groups and permissions.'))
-        
+
         if options['setup_user']:
             # Username is given, check options
             try:
@@ -222,8 +223,8 @@ class Command(BaseCommand):
             elif options['make_admin']:
                 # Make admin failed, user not a superuser
                 self.stdout.write(self.style.WARNING('User %s is not a superuser.' % user))
-                
+
             if options['make_tester']:
                 # Setup test contributor
                 user.groups.add(Testers)
-                self.stdout.write(self.style.SUCCESS('Successfully made %s tester.' % user))
\ No newline at end of file
+                self.stdout.write(self.style.SUCCESS('Successfully made %s tester.' % user))
diff --git a/scipost/management/commands/populate_db.py b/scipost/management/commands/populate_db.py
new file mode 100644
index 0000000000000000000000000000000000000000..26e2d1a3ac72011e41781b943cedfd7e015b137d
--- /dev/null
+++ b/scipost/management/commands/populate_db.py
@@ -0,0 +1,20 @@
+from django.core.management.base import BaseCommand
+from django.contrib.auth.models import User
+
+from ...models import Contributor
+
+
+class Command(BaseCommand):
+    def add_arguments(self, parser):
+        parser.add_argument(
+            '--username', type=str, required=True,
+            help='Username of user to use for contributor model')
+
+    def create_contributor(self, username):
+        user = User.objects.get(username=username)
+        contributor = Contributor(user=user, status=1, title="MR")
+        contributor.vetted_by = contributor
+        contributor.save()
+
+    def handle(self, *args, **options):
+        self.create_contributor(options['username'])
diff --git a/scipost/models.py b/scipost/models.py
index e55e21212f59b31cd8e58c8d81ae2679b3549f51..59afc30d53d40172bfd37ea69989e8943afe2cef 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -225,7 +225,6 @@ class Contributor(models.Model):
         default=True,
         verbose_name="I accept to receive SciPost emails")
 
-
     def __str__(self):
         return '%s, %s' % (self.user.last_name, self.user.first_name)
 
diff --git a/submissions/forms.py b/submissions/forms.py
index 210a0adcb339cca19e8a4aa0c37eeab21a3c6d89..e299e58cd601c661b44c9bcd3adb8148729ed554 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -1,4 +1,5 @@
 from django import forms
+from django.core.validators import RegexValidator
 #from django.contrib.auth.models import User, Group
 
 from .models import *
@@ -20,10 +21,22 @@ class SubmissionSearchForm(forms.Form):
 ###############################
 
 class SubmissionIdentifierForm(forms.Form):
-    identifier = forms.CharField(widget=forms.TextInput(
-        {'label': 'arXiv identifier',
-         'placeholder': 'new style (with version nr) ####.####(#)v#(#)',
-         'cols': 20}))
+    identifier = forms.CharField(
+        widget=forms.TextInput(
+            {'label': 'arXiv identifier',
+             'placeholder': 'new style (with version nr) ####.####(#)v#(#)',
+             'cols': 20}
+        ),
+        validators=[
+            RegexValidator(
+                regex="^[0-9]{4,}.[0-9]{4,5}v[0-9]{1,2}$",
+                message='The identifier you entered is improperly formatted '
+                        '(did you forget the version number?)',
+                code='invalid_identifier'
+            ),
+        ])
+
+
 
 class SubmissionForm(forms.ModelForm):
     class Meta:
diff --git a/submissions/models.py b/submissions/models.py
index ae7648b5b84926795a557f723aa99621ec117cf0..68a3d1e867b2720f97fd109dee8cd1d8a18d681a 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -57,18 +57,6 @@ SUBMISSION_STATUS_PUBLICLY_UNLISTED = [
     'withdrawn',
 ]
 
-# SUBMISSION_ACTION_REQUIRED = (
-#     ('assign_EIC', 'Editor-in-charge to be assigned'),
-# #    ('Fellow_accepts_or_refuse_assignment', 'Fellow must accept or refuse assignment'),
-#     ('EIC_runs_refereeing_round', 'Editor-in-charge to run refereeing round (inviting referees)'),
-#     ('EIC_closes_refereeing_round', 'Editor-in-charge to close refereeing round'),
-#     ('EIC_invites_author_response', 'Editor-in-charge invites authors to complete their replies'),
-#     ('EIC_formulates_editorial_recommendation',
-#      'Editor-in-charge to formulate editorial recommendation'),
-#     ('EC_ratification', 'Editorial College ratifies editorial recommendation'),
-#     ('Decision_to_authors', 'Editor-in-charge forwards decision to authors'),
-#     )
-
 SUBMISSION_TYPE = (
     ('Letter', 'Letter (broad-interest breakthrough results)'),
     ('Article', 'Article (in-depth reports on specialized research)'),
@@ -78,6 +66,7 @@ submission_type_dict = dict(SUBMISSION_TYPE)
 
 
 class Submission(models.Model):
+    # Main submission fields
     is_current = models.BooleanField(default=True)
     is_resubmission = models.BooleanField(default=False)
     submitted_by = models.ForeignKey(Contributor, on_delete=models.CASCADE)
@@ -89,13 +78,12 @@ class Submission(models.Model):
                                        blank=True, null=True, default=None)
     discipline = models.CharField(max_length=20, choices=SCIPOST_DISCIPLINES, default='physics')
     domain = models.CharField(max_length=3, choices=SCIPOST_JOURNALS_DOMAINS)
-#    specialization = models.CharField(max_length=1, choices=SCIPOST_JOURNALS_SPECIALIZATIONS)
     subject_area = models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS,
                                     verbose_name='Primary subject area', default='Phys:QP')
     secondary_areas = ChoiceArrayField(
         models.CharField(max_length=10, choices=SCIPOST_SUBJECT_AREAS),
         blank=True, null=True)
-    status = models.CharField(max_length=30, choices=SUBMISSION_STATUS) # set by Editors
+    status = models.CharField(max_length=30, choices=SUBMISSION_STATUS)  # set by Editors
     author_comments = models.TextField(blank=True, null=True)
     list_of_changes = models.TextField(blank=True, null=True)
     remarks_for_editors = models.TextField(blank=True, null=True)
@@ -106,17 +94,22 @@ class Submission(models.Model):
     open_for_commenting = models.BooleanField(default=False)
     title = models.CharField(max_length=300)
     author_list = models.CharField(max_length=1000, verbose_name="author list")
+
     # Authors which have been mapped to contributors:
-    authors = models.ManyToManyField (Contributor, blank=True, related_name='authors_sub')
-    authors_claims = models.ManyToManyField (Contributor, blank=True,
-                                             related_name='authors_sub_claims')
-    authors_false_claims = models.ManyToManyField (Contributor, blank=True,
-                                                   related_name='authors_sub_false_claims')
+    authors = models.ManyToManyField(Contributor, blank=True, related_name='authors_sub')
+    authors_claims = models.ManyToManyField(Contributor, blank=True,
+                                            related_name='authors_sub_claims')
+    authors_false_claims = models.ManyToManyField(Contributor, blank=True,
+                                                  related_name='authors_sub_false_claims')
     abstract = models.TextField()
+
+    # Arxiv identifiers with/without version number
     arxiv_identifier_w_vn_nr = models.CharField(max_length=15, default='0000.00000v0')
     arxiv_identifier_wo_vn_nr = models.CharField(max_length=10, default='0000.00000')
     arxiv_vn_nr = models.PositiveSmallIntegerField(default=1)
     arxiv_link = models.URLField(verbose_name='arXiv link (including version nr)')
+
+    # Metadata
     metadata = JSONField(default={}, blank=True, null=True)
     submission_date = models.DateField(verbose_name='submission date')
     latest_activity = models.DateTimeField(default=timezone.now)
@@ -126,7 +119,7 @@ class Submission(models.Model):
             ('can_take_editorial_actions', 'Can take editorial actions'),
             )
 
-    def __str__ (self):
+    def __str__(self):
         header = (self.arxiv_identifier_w_vn_nr + ', '
                   + self.title[:30] + ' by ' + self.author_list[:30])
         if self.is_current:
diff --git a/submissions/services.py b/submissions/services.py
new file mode 100644
index 0000000000000000000000000000000000000000..bd16fb2ae70960507034ca3e46f8b6780a85fe87
--- /dev/null
+++ b/submissions/services.py
@@ -0,0 +1,86 @@
+# Module for making external api calls as needed in the submissions cycle
+import feedparser
+
+from .models import *
+
+
+class ArxivCaller():
+    def lookup_article(identifier):
+        # Pre-checks
+        if same_version_exists(identifier)
+            return False, "This preprint version has already been submitted to SciPost."
+
+        # Split the given identifier in an article identifier and version number
+        identifier_without_vn_nr = identifier.rpartition('v')[0]
+        arxiv_vn_nr = int(identifier.rpartition('v')[2])
+
+        resubmission = False
+        if previous_submission_undergoing_refereeing(identifier):
+            errormessage = '<p>There exists a preprint with this arXiv identifier '
+                            'but an earlier version number, which is still undergoing '
+                            'peer refereeing.</p>'
+                            '<p>A resubmission can only be performed after request '
+                            'from the Editor-in-charge. Please wait until the '
+                            'closing of the previous refereeing round and '
+                            'formulation of the Editorial Recommendation '
+                            'before proceeding with a resubmission.</p>'
+            return False, errormessage
+
+        # Arxiv query
+        queryurl = ('http://export.arxiv.org/api/query?id_list=%s'
+                    % identifier)
+        arxiv_response = feedparser.parse(queryurl)
+
+        # Check if response has at least one entry
+        if not 'entries' in arxiv_response
+            errormessage = 'Bad response from Arxiv.'
+            return False, errormessage
+
+        # Check if preprint exists
+        if not preprint_exists(arxiv_response)
+            errormessage = 'A preprint associated to this identifier does not exist.'
+            return False, errormessage
+
+        # Check via journal ref if already published
+        arxiv_journal_ref = published_journal_ref
+        if arxiv_journal_ref
+            errormessage = 'This paper has been published as ' + arxiv_journal_ref +
+                            '. You cannot submit it to SciPost anymore.'
+            return False, resubmission
+
+        # Check via DOI if already published
+        arxiv_doi = published_journal_ref
+        if arxiv_doi
+            errormessage = 'This paper has been published under DOI ' + arxiv_doi
+                            + '. You cannot submit it to SciPost anymore.'
+            return False, errormessage
+
+        return arxiv_response, ""
+
+
+    def same_version_exists(identifier):
+        return Submission.objects.filter(arxiv_identifier_w_vn_nr=identifier).exists()
+
+    def previous_submission_undergoing_refereeing(identifier):
+        previous_submissions = Submission.objects.filter(
+            arxiv_identifier_wo_vn_nr=identifier).order_by('-arxiv_vn_nr')
+
+        if previous_submissions:
+            return not previous_submissions[0].status == 'revision_requested'
+        else:
+            return False
+
+    def preprint_exists(arxiv_response):
+        return 'title' in arxiv_response['entries'][0]
+
+    def published_journal_ref(arxiv_response):
+        if 'arxiv_journal_ref' in arxiv_response['entries'][0]
+            return arxiv_response['entries'][0]['arxiv_journal_ref']
+        else:
+            return False
+
+    def published_DOI(arxiv_response):
+        if 'arxiv_doi' in arxiv_response['entries'][0]
+            return arxiv_response['entries'][0]['arxiv_doi']
+        else:
+            return False
diff --git a/submissions/tests.py b/submissions/tests/test_models.py
similarity index 55%
rename from submissions/tests.py
rename to submissions/tests/test_models.py
index 7ce503c2dd97ba78597f6ff6e4393132753573f6..2e9cb5f6ba351402af656aec1be5d9ac257bc5c0 100644
--- a/submissions/tests.py
+++ b/submissions/tests/test_models.py
@@ -1,3 +1 @@
 from django.test import TestCase
-
-# Create your tests here.
diff --git a/submissions/tests/test_views.py b/submissions/tests/test_views.py
new file mode 100644
index 0000000000000000000000000000000000000000..f35d237bde6def6e0755612febe441d1d10d6d63
--- /dev/null
+++ b/submissions/tests/test_views.py
@@ -0,0 +1,27 @@
+from django.test import TestCase
+from django.test import Client
+
+from submissions.views import *
+
+
+
+class PrefillUsingIdentifierTest(TestCase):
+    fixtures = ['permissions', 'groups', 'contributors']
+
+    def test_retrieving_existing_arxiv_paper(self):
+        client = Client()
+        client.login(username="Test", password="testpw")
+
+        response = client.post('/submissions/prefill_using_identifier',
+                               {'identifier': '1512.00030v1'})
+
+        self.assertEqual(response.status_code, 200)
+
+    def test_still_200_ok_if_identifier_is_wrong(self):
+        client = Client()
+        client.login(username="Test", password="testpw")
+
+        response = client.post('/submissions/prefill_using_identifier',
+                               {'identifier': '1512.00030'})
+
+        self.assertEqual(response.status_code, 200)
diff --git a/submissions/views.py b/submissions/views.py
index d3e7718ce4628b68cd323ac4758a668fecf86c91..f7a4ac054a33887fecb3f5c76662125ea437275f 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -44,25 +44,15 @@ def prefill_using_identifier(request):
     if request.method == "POST":
         identifierform = SubmissionIdentifierForm(request.POST)
         if identifierform.is_valid():
-            # we allow 1 or 2 digits for version
-            identifierpattern = re.compile("^[0-9]{4,}.[0-9]{4,5}v[0-9]{1,2}$")
-            errormessage = ''
-            if not identifierpattern.match(identifierform.cleaned_data['identifier']):
-                errormessage = ('The identifier you entered is improperly formatted '
-                                '(did you forget the version number?)')
-            elif (Submission.objects
-                  #.filter(arxiv_link__contains=identifierform.cleaned_data['identifier'])
-                  .filter(arxiv_identifier_w_vn_nr=identifierform.cleaned_data['identifier'])
-                  .exists()):
-                errormessage = 'This preprint version has already been submitted to SciPost.'
-            if errormessage != '':
+            # Perform Arxiv query and check if results are OK for submission
+            metadata, errormessage = lookup_article(identifierform.cleaned_data['identifier'])
+
+            if not metadata:
                 form = SubmissionForm()
                 return render(request, 'submissions/submit_manuscript.html',
                               {'identifierform': identifierform, 'form': form,
                                'errormessage': errormessage})
-            # Otherwise we query arXiv for the information:
-            identifier_without_vn_nr = identifierform.cleaned_data['identifier'].rpartition('v')[0]
-            arxiv_vn_nr = int(identifierform.cleaned_data['identifier'].rpartition('v')[2])
+
             is_resubmission = False
             resubmessage = ''
             previous_submissions = Submission.objects.filter(
@@ -95,6 +85,7 @@ def prefill_using_identifier(request):
                     errormessage = 'A preprint associated to this identifier does not exist.'
                 except:
                     pass
+
                 # If paper has been published, should comment on published version
                 try:
                     arxiv_journal_ref = arxivquery['entries'][0]['arxiv_journal_ref']
@@ -113,22 +104,7 @@ def prefill_using_identifier(request):
                     context = {'identifierform': identifierform, 'form': form,
                                'errormessage': errormessage}
                     return render(request, 'submissions/submit_manuscript.html', context)
-                # otherwise prefill the form:
-                # metadata = arxivquery
-                # title = arxivquery['entries'][0]['title']
-                # authorlist = arxivquery['entries'][0]['authors'][0]['name']
-                # for author in arxivquery['entries'][0]['authors'][1:]:
-                #     authorlist += ', ' + author['name']
-                # arxiv_link = arxivquery['entries'][0]['id']
-                # abstract = arxivquery['entries'][0]['summary']
-                # form = SubmissionForm(
-                #     initial={'is_resubmission': is_resubmission,
-                #              'metadata': metadata,
-                #              'title': title, 'author_list': authorlist,
-                #              'arxiv_identifier_w_vn_nr': identifierform.cleaned_data['identifier'],
-                #              'arxiv_identifier_wo_vn_nr': identifier_without_vn_nr,
-                #              'arxiv_vn_nr': arxiv_vn_nr,
-                #              'arxiv_link': arxiv_link, 'abstract': abstract})
+
                 metadata = arxivquery
                 title = arxivquery['entries'][0]['title']
                 authorlist = arxivquery['entries'][0]['authors'][0]['name']
@@ -148,7 +124,6 @@ def prefill_using_identifier(request):
                     initialdata['submission_type'] = previous_submissions[0].submission_type
                     initialdata['discipline'] = previous_submissions[0].discipline
                     initialdata['domain'] = previous_submissions[0].domain
-#                    initialdata['specialization'] = previous_submissions[0].specialization
                     initialdata['subject_area'] = previous_submissions[0].subject_area
                     initialdata['secondary_areas'] = previous_submissions[0].secondary_areas
                     initialdata['referees_suggested'] = previous_submissions[0].referees_suggested
@@ -165,7 +140,9 @@ def prefill_using_identifier(request):
                            'errormessage': errormessage,}
                 return render(request, 'submissions/submit_manuscript.html', context)
         else:
-            pass
+            form = SubmissionForm()
+            return render(request, 'submissions/submit_manuscript.html',
+                          {'identifierform': identifierform, 'form': form})
     return redirect(reverse('submissions:submit_manuscript'))
 
 
@@ -185,7 +162,7 @@ def submit_manuscript(request):
                 return render(request, 'submissions/submit_manuscript.html',
                               {'identifierform': identifierform, 'form': form,
                                'errormessage': errormessage})
-            submission = Submission (
+            submission = Submission(
                 is_current = True,
                 is_resubmission = form.cleaned_data['is_resubmission'],
                 submitted_by = submitted_by,
diff --git a/theses/factories.py b/theses/factories.py
new file mode 100644
index 0000000000000000000000000000000000000000..19489c3c15babf86f0939a1a261c234fb7285560
--- /dev/null
+++ b/theses/factories.py
@@ -0,0 +1,18 @@
+import factory
+from .models import ThesisLink
+from scipost.factories import ContributorFactory
+
+
+class ThesisLinkFactory(factory.django.DjangoModelFactory):
+    class Meta:
+        model = ThesisLink
+
+    requested_by = factory.SubFactory(ContributorFactory)
+    type = ThesisLink.MASTER_THESIS
+    title = factory.Sequence(lambda n: "thesis {0}".format(n))
+    pub_link = factory.Faker('uri')
+    author = factory.Faker('name')
+    supervisor = factory.Faker('name')
+    institution = factory.Faker('company')
+    defense_date = factory.Faker('date_time_this_century')
+    abstract = factory.Faker('text')
diff --git a/theses/forms.py b/theses/forms.py
index 95849d3b3d8bd0bb00ca8de031ee2326950a7651..2193a767c32084fbfdd4f5e7b34143408a68e58d 100644
--- a/theses/forms.py
+++ b/theses/forms.py
@@ -14,6 +14,7 @@ THESIS_REFUSAL_CHOICES = (
     (-2, 'the external link to this thesis does not work'),
     )
 
+
 class RequestThesisLinkForm(forms.ModelForm):
     class Meta:
         model = ThesisLink
@@ -27,6 +28,7 @@ class RequestThesisLinkForm(forms.ModelForm):
         self.fields['pub_link'].widget.attrs.update({'placeholder': 'Full URL'})
         self.fields['abstract'].widget.attrs.update({'cols': 100})
 
+
 class VetThesisLinkForm(forms.Form):
     action_option = forms.ChoiceField(widget=forms.RadioSelect,
                                       choices=THESIS_ACTION_CHOICES,
@@ -35,6 +37,7 @@ class VetThesisLinkForm(forms.Form):
     email_response_field = forms.CharField(widget=forms.Textarea(
         attrs={'rows': 5, 'cols': 40}), label='Justification (optional)', required=False)
 
+
 class ThesisLinkSearchForm(forms.Form):
     author = forms.CharField(max_length=100, required=False, label="Author")
     title_keyword = forms.CharField(max_length=100, label="Title", required=False)
diff --git a/theses/models.py b/theses/models.py
index 37fcb52f07fd7f09fc90c3a53982bd18c9d162e8..139948b9175deb6bc62fdc098bef6d3fc4a4ef86 100644
--- a/theses/models.py
+++ b/theses/models.py
@@ -8,15 +8,18 @@ from .models import *
 from journals.models import *
 from scipost.models import *
 
-THESIS_TYPES = (
-    ('MA', 'Master\'s'),
-    ('PhD', 'Ph.D.'),
-    ('Hab', 'Habilitation'),
-    )
-thesis_type_dict = dict(THESIS_TYPES)
-
 
 class ThesisLink(models.Model):
+    MASTER_THESIS = 'MA'
+    PHD_THESIS = 'PhD'
+    HABILITATION_THESIS = 'Hab'
+    THESIS_TYPES = (
+        (MASTER_THESIS, 'Master\'s'),
+        (PHD_THESIS, 'Ph.D.'),
+        (HABILITATION_THESIS, 'Habilitation'),
+    )
+    THESIS_TYPES_DICT = dict(THESIS_TYPES)
+
     """ An URL pointing to a thesis """
     requested_by = models.ForeignKey(
         Contributor, blank=True, null=True,
@@ -26,13 +29,13 @@ class ThesisLink(models.Model):
     vetted_by = models.ForeignKey(
         Contributor, blank=True, null=True,
         on_delete=models.CASCADE)
-    type = models.CharField(max_length=3, choices=THESIS_TYPES)
+    type = models.CharField(choices=THESIS_TYPES, max_length=3)
     discipline = models.CharField(
         max_length=20, choices=SCIPOST_DISCIPLINES,
         default='physics')
     domain = models.CharField(
         max_length=3, choices=SCIPOST_JOURNALS_DOMAINS,
-        blank=True)
+        blank=False)
     subject_area = models.CharField(
         max_length=10,
         choices=SCIPOST_SUBJECT_AREAS,
@@ -85,7 +88,7 @@ class ThesisLink(models.Model):
             header += '<td>(not claimed)</td>'
         header += (
             '</tr>'
-            '<tr><td>Type: </td><td></td><td>' + thesis_type_dict[self.type] +
+            '<tr><td>Type: </td><td></td><td>' + self.THESIS_TYPES_DICT[self.type] +
             '</td></tr>'
             '<tr><td>Discipline: </td><td></td><td>' +
             disciplines_dict[self.discipline] + '</td></tr>'
@@ -110,11 +113,13 @@ class ThesisLink(models.Model):
             'pub_link': self.pub_link, 'institution': self.institution,
             'supervisor': self.supervisor, 'defense_date': self.defense_date,
             'latest_activity': self.latest_activity.strftime('%Y-%m-%d %H:%M')})
+        print(subject_areas_dict)
+        print(self.subject_area in subject_areas_dict)
         header = (
             '<li><div class="flex-container">'
             '<div class="flex-whitebox0"><p><a href="/thesis/{{ id }}" '
             'class="pubtitleli">{{ title }}</a></p>'
-            '<p>' + thesis_type_dict[self.type] + ' thesis by {{ author }} '
+            '<p>' + self.THESIS_TYPES_DICT[self.type] + ' thesis by {{ author }} '
             '(supervisor(s): {{ supervisor }}) in ' +
             disciplines_dict[self.discipline] + ', ' +
             journals_domains_dict[self.domain] + ' ' +
@@ -133,7 +138,7 @@ class ThesisLink(models.Model):
             '<li><div class="flex-container">'
             '<div class="flex-whitebox0"><p><a href="/thesis/{{ id }}" '
             'class="pubtitleli">{{ title }}</a></p>'
-            '<p>' + thesis_type_dict[self.type] +
+            '<p>' + self.THESIS_TYPES_DICT[self.type] +
             ' thesis by {{ author }} </div></div></li>')
         template = Template(header)
         return template.render(context)
diff --git a/theses/tests.py b/theses/test_forms.py
similarity index 55%
rename from theses/tests.py
rename to theses/test_forms.py
index 7ce503c2dd97ba78597f6ff6e4393132753573f6..2e9cb5f6ba351402af656aec1be5d9ac257bc5c0 100644
--- a/theses/tests.py
+++ b/theses/test_forms.py
@@ -1,3 +1 @@
 from django.test import TestCase
-
-# Create your tests here.
diff --git a/theses/test_models.py b/theses/test_models.py
new file mode 100644
index 0000000000000000000000000000000000000000..4308ab25f1d22c56e33cb5047cb6f571fe080bf7
--- /dev/null
+++ b/theses/test_models.py
@@ -0,0 +1,15 @@
+import re
+
+from django.test import TestCase
+from django.core.exceptions import ValidationError
+
+from .models import ThesisLink
+from .factories import ThesisLinkFactory
+
+
+class ThesisLinkTestCase(TestCase):
+    def test_domain_cannot_be_blank(self):
+        thesis_link = ThesisLinkFactory()
+        thesis_link.domain = ""
+        self.assertRaisesRegexp(ValidationError, re.compile(r'domain'),
+                                thesis_link.full_clean)
diff --git a/theses/test_views.py b/theses/test_views.py
new file mode 100644
index 0000000000000000000000000000000000000000..e1c9c7982e1cd36b83d213a82f3794ec860a05f5
--- /dev/null
+++ b/theses/test_views.py
@@ -0,0 +1,10 @@
+from django.test import TestCase
+from django.test.client import Client
+
+
+class TestThesisDetail(TestCase):
+
+    def test_acknowledges_after_submitting_comment(self):
+        client = Client()
+        response = client.post('/theses/1')
+        self.assertEqual(response.get('location'), 'bladiebla')
diff --git a/theses/urls.py b/theses/urls.py
index 59758c05e57add2fa5e09e8fdcca125810b36e36..88bd434545a5636f9b09e832bbd7e24b91bf6d12 100644
--- a/theses/urls.py
+++ b/theses/urls.py
@@ -7,9 +7,10 @@ urlpatterns = [
     # Thesis Links
     url(r'^$', views.theses, name='theses'),
     url(r'^browse/(?P<discipline>[a-z]+)/(?P<nrweeksback>[0-9]+)/$', views.browse, name='browse'),
-    #url(r'^thesis/(?P<thesislink_id>[0-9]+)/$', views.thesis_detail, name='thesis'),
     url(r'^(?P<thesislink_id>[0-9]+)/$', views.thesis_detail, name='thesis'),
     url(r'^request_thesislink$', views.request_thesislink, name='request_thesislink'),
-    url(r'^vet_thesislink_requests$', views.vet_thesislink_requests, name='vet_thesislink_requests'),
-    url(r'^vet_thesislink_request_ack/(?P<thesislink_id>[0-9]+)$', views.vet_thesislink_request_ack, name='vet_thesislink_request_ack'),
+    url(r'^vet_thesislink_requests$', views.vet_thesislink_requests,
+        name='vet_thesislink_requests'),
+    url(r'^vet_thesislink_request_ack/(?P<thesislink_id>[0-9]+)$',
+        views.vet_thesislink_request_ack, name='vet_thesislink_request_ack'),
 ]
diff --git a/theses/views.py b/theses/views.py
index 882c2f192f88353debfe4235bbcf6154ab763b27..7a2a2309d363eae341a18e0a62c4470c6f5b1cdf 100644
--- a/theses/views.py
+++ b/theses/views.py
@@ -17,7 +17,8 @@ from comments.models import Comment
 from comments.forms import CommentForm
 from scipost.forms import TITLE_CHOICES, AuthenticationForm
 
-title_dict = dict(TITLE_CHOICES) # Convert titles for use in emails
+
+title_dict = dict(TITLE_CHOICES)  # Convert titles for use in emails
 
 ################
 # Theses
@@ -30,23 +31,23 @@ def request_thesislink(request):
         form = RequestThesisLinkForm(request.POST)
         if form.is_valid():
             contributor = Contributor.objects.get(user=request.user)
-            thesislink = ThesisLink (
-                requested_by = contributor,
-                type = form.cleaned_data['type'],
-                discipline = form.cleaned_data['discipline'],
-                domain = form.cleaned_data['domain'],
-                subject_area = form.cleaned_data['subject_area'],
-                title = form.cleaned_data['title'],
-                author = form.cleaned_data['author'],
-                supervisor = form.cleaned_data['supervisor'],
-                institution = form.cleaned_data['institution'],
-                defense_date = form.cleaned_data['defense_date'],
-                pub_link = form.cleaned_data['pub_link'],
-                abstract = form.cleaned_data['abstract'],
-                latest_activity = timezone.now(),
-                )
+            thesislink = ThesisLink(
+                requested_by=contributor,
+                type=form.cleaned_data['type'],
+                discipline=form.cleaned_data['discipline'],
+                domain=form.cleaned_data['domain'],
+                subject_area=form.cleaned_data['subject_area'],
+                title=form.cleaned_data['title'],
+                author=form.cleaned_data['author'],
+                supervisor=form.cleaned_data['supervisor'],
+                institution=form.cleaned_data['institution'],
+                defense_date=form.cleaned_data['defense_date'],
+                pub_link=form.cleaned_data['pub_link'],
+                abstract=form.cleaned_data['abstract'],
+                latest_activity=timezone.now(),
+            )
             thesislink.save()
-            #return HttpResponseRedirect('request_thesislink_ack')
+            # return HttpResponseRedirect('request_thesislink_ack')
             context = {'ack_header': 'Thank you for your request for a Thesis Link',
                        'ack_message': 'Your request will soon be handled by an Editor. ',
                        'followup_message': 'Return to your ',
@@ -61,11 +62,13 @@ def request_thesislink(request):
 @permission_required('scipost.can_vet_thesislink_requests', raise_exception=True)
 def vet_thesislink_requests(request):
     contributor = Contributor.objects.get(user=request.user)
-    thesislink_to_vet = ThesisLink.objects.filter(vetted=False).first() # only handle one at a time
+    thesislink_to_vet = ThesisLink.objects.filter(
+        vetted=False).first()  # only handle one at a time
     form = VetThesisLinkForm()
-    context = {'contributor': contributor, 'thesislink_to_vet': thesislink_to_vet, 'form': form }
+    context = {'contributor': contributor, 'thesislink_to_vet': thesislink_to_vet, 'form': form}
     return render(request, 'theses/vet_thesislink_requests.html', context)
 
+
 @permission_required('scipost.can_vet_thesislink_requests', raise_exception=True)
 def vet_thesislink_request_ack(request, thesislink_id):
     if request.method == 'POST':
@@ -112,8 +115,8 @@ def vet_thesislink_request_ack(request, thesislink_id):
                                             ['theses@scipost.org'],
                                             reply_to=['theses@scipost.org'])
                 # Don't send email yet... only when option 1 has succeeded!
-                #emailmessage.send(fail_silently=False)
-                context = {'form': form2 }
+                # emailmessage.send(fail_silently=False)
+                context = {'form': form2}
                 return render(request, 'theses/request_thesislink.html', context)
             elif form.cleaned_data['action_option'] == '2':
                 email_text = ('Dear ' + title_dict[thesislink.requested_by.title] + ' '
@@ -124,7 +127,8 @@ def vet_thesislink_request_ack(request, thesislink_id):
                               + form.cleaned_data['refusal_reason']
                               + '.\n\nThank you for your interest, \nThe SciPost Team.')
                 if form.cleaned_data['email_response_field']:
-                    email_text += '\n\nFurther explanations: ' + form.cleaned_data['email_response_field']
+                    email_text += '\n\nFurther explanations: ' + \
+                        form.cleaned_data['email_response_field']
                 emailmessage = EmailMessage('SciPost Thesis Link', email_text,
                                             'SciPost Theses <theses@scipost.org>',
                                             [thesislink.requested_by.user.email],
@@ -133,8 +137,6 @@ def vet_thesislink_request_ack(request, thesislink_id):
                 emailmessage.send(fail_silently=False)
                 thesislink.delete()
 
-    #context = {'thesislink_id': thesislink_id }
-    #return render(request, 'theses/vet_thesislink_request_ack.html', context)
     context = {'ack_header': 'Thesis Link request vetted.',
                'followup_message': 'Return to the ',
                'followup_link': reverse('theses:vet_thesislink_requests'),
@@ -152,7 +154,7 @@ def theses(request):
                 abstract__icontains=form.cleaned_data['abstract_keyword'],
                 supervisor__icontains=form.cleaned_data['supervisor'],
                 vetted=True,
-                )
+            )
             thesislink_search_list.order_by('-pub_date')
         else:
             thesislink_search_list = []
@@ -165,7 +167,7 @@ def theses(request):
                               .filter(vetted=True,
                                       latest_activity__gte=timezone.now() + datetime.timedelta(days=-7)))
     context = {'form': form, 'thesislink_search_list': thesislink_search_list,
-               'thesislink_recent_list': thesislink_recent_list }
+               'thesislink_recent_list': thesislink_recent_list}
     return render(request, 'theses/theses.html', context)
 
 
@@ -179,11 +181,11 @@ def browse(request, discipline, nrweeksback):
                 abstract__icontains=form.cleaned_data['abstract_keyword'],
                 supervisor__icontains=form.cleaned_data['supervisor'],
                 vetted=True,
-                )
+            )
             thesislink_search_list.order_by('-pub_date')
         else:
             thesislink_search_list = []
-        context = {'form': form, 'thesislink_search_list': thesislink_search_list }
+        context = {'form': form, 'thesislink_search_list': thesislink_search_list}
         return HttpResponseRedirect(request, 'theses/theses.html', context)
     else:
         form = ThesisLinkSearchForm()
@@ -192,7 +194,7 @@ def browse(request, discipline, nrweeksback):
         latest_activity__gte=timezone.now() + datetime.timedelta(weeks=-int(nrweeksback))))
     context = {'form': form, 'discipline': discipline,
                'nrweeksback': nrweeksback,
-               'thesislink_browse_list': thesislink_browse_list }
+               'thesislink_browse_list': thesislink_browse_list}
     return render(request, 'theses/theses.html', context)
 
 
@@ -203,26 +205,27 @@ def thesis_detail(request, thesislink_id):
         form = CommentForm(request.POST)
         if form.is_valid():
             author = Contributor.objects.get(user=request.user)
-            newcomment = 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(),
-                )
-            newcomment.save()
+            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()
             request.session['thesislink_id'] = thesislink_id
-            return HttpResponseRedirect(reverse('comments:comment_submission_ack'))
+            context = {}
+            return render(request, 'scipost/acknowledgement.html', context)
     else:
         form = CommentForm()