diff --git a/README.md b/README.md
index 0a4608961069118a9a1404f4966efe48fdb0e225..d4549003bc656b5061462e47133d85e4e5f89303 100644
--- a/README.md
+++ b/README.md
@@ -129,6 +129,20 @@ Users of the portal are known as Contributors and are created through the regist
 
 You can create a number of users, and use the admin site to give them various permissions through memberships of certain groups. For example, you'll want members of the SciPost Administrators and Editorial Administrators groups in order to access the internal management and editorial tools.
 
+### Initial data
+If you're working on a (almost) empty database, one can easily fill its test database using one of the built-in commands. To create few instances for each available object, simply run:
+
+```shell
+(scipostenv) $ ./manage.py populate_db --all
+```
+
+Run the help argument to find arguments to create instances for individual models.
+
+```shell
+(scipostenv) $ ./manage.py populate_db --help
+```
+
+
 ## Maintaining database migratons
 Every time fields in any of the models change, a [database migration](https://docs.djangoproject.com/en/1.10/topics/migrations/)
 needs to be created and applied. The first documents a database change and its
@@ -143,7 +157,23 @@ can use them.
 ```
 
 ## Documentation
-Project documentation can be found in `docs` and can be rendered using
+All project documentation is gathered from `.rst` files and code-embedded docstrings.
+The documentation itself can be found in `docs`.
+
+### Sphinxdoc
+The documentation is saved in the local database as a Project with name `SciPost`
+(this project should be manually created in the admin under the `Sphinxdoc` app).
+
+To update the docs, simply run
+```shell
+(scipostenv) $ python3 ../manage.py updatedoc -b scipost
+```
+
+The documentation is then viewable by navigating to `docs/`.
+
+
+### Locally-served
+The documentation can be rendered using
 [Sphinx](http://www.sphinx-doc.org/). Note that rendering documentation is only
 available from the virtual environment - and only when the host settings have
 been configured.
diff --git a/commentaries/constants.py b/commentaries/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..5fe492bf1f29a6f2d63f6d10742f5ee9c8ba05e2
--- /dev/null
+++ b/commentaries/constants.py
@@ -0,0 +1,6 @@
+COMMENTARY_PUBLISHED = 'published'
+COMMENTARY_PREPRINT = 'preprint'
+COMMENTARY_TYPES = (
+    (COMMENTARY_PUBLISHED, 'published paper'),
+    (COMMENTARY_PREPRINT, 'arXiv preprint'),
+)
diff --git a/commentaries/factories.py b/commentaries/factories.py
index 6e1a5b8224f4772abbaf7f093442e5d38878d3a5..1f0110a5d0a44caa1ffb3519f8f86a3703a2871d 100644
--- a/commentaries/factories.py
+++ b/commentaries/factories.py
@@ -1,43 +1,56 @@
 import factory
 
-from scipost.constants import DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS
-from scipost.factories import ContributorFactory
+from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS
+from scipost.models import Contributor
 from journals.constants import SCIPOST_JOURNALS_DOMAINS
-from common.helpers import random_arxiv_identifier_with_version_number
+from common.helpers import random_arxiv_identifier_with_version_number, random_external_doi
 
-from .models import Commentary, COMMENTARY_TYPES
+from .constants import COMMENTARY_TYPES
+from .models import Commentary
+
+from faker import Faker
 
 
 class CommentaryFactory(factory.django.DjangoModelFactory):
     class Meta:
         model = Commentary
-        abstract = True
-
-    requested_by = factory.SubFactory(ContributorFactory)
-    vetted_by = factory.SubFactory(ContributorFactory)
-    type = COMMENTARY_TYPES[0][0]
-    discipline = DISCIPLINE_PHYSICS
-    domain = SCIPOST_JOURNALS_DOMAINS[0][0]
-    subject_area = SCIPOST_SUBJECT_AREAS[0][1][0][0]
-    pub_title = factory.Faker('bs')
-    pub_DOI = '10.1103/PhysRevB.92.214427'
+
+    requested_by = factory.Iterator(Contributor.objects.all())
+    type = factory.Iterator(COMMENTARY_TYPES, getter=lambda c: c[0])
+    discipline = factory.Iterator(SCIPOST_DISCIPLINES, getter=lambda c: c[0])
+    domain = factory.Iterator(SCIPOST_JOURNALS_DOMAINS, getter=lambda c: c[0])
+    subject_area = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: c[0])
+    pub_title = factory.Faker('text')
+    pub_DOI = factory.Sequence(lambda n: random_external_doi())
     arxiv_identifier = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number())
     author_list = factory.Faker('name')
     pub_abstract = factory.Faker('text')
     pub_date = factory.Faker('date')
+    arxiv_link = factory.Faker('uri')
+    pub_abstract = factory.lazy_attribute(lambda x: Faker().paragraph())
+
+    @factory.post_generation
+    def arxiv_link(self, create, extracted, **kwargs):
+        self.arxiv_link = 'https://arxiv.org/abs/%s' % self.arxiv_identifier
+        self.arxiv_or_DOI_string = self.arxiv_identifier
 
     @factory.post_generation
     def create_urls(self, create, extracted, **kwargs):
         self.parse_links_into_urls(commit=create)
 
-
-class EmptyCommentaryFactory(CommentaryFactory):
-    pub_DOI = None
-    arxiv_identifier = None
+    @factory.post_generation
+    def add_authors(self, create, extracted, **kwargs):
+        contributors = list(Contributor.objects.order_by('?')
+                            .exclude(pk=self.requested_by.pk).all()[:4])
+        for contrib in contributors:
+            self.author_list += ', %s %s' % (contrib.user.first_name, contrib.user.last_name)
+            if create:
+                self.authors.add(contrib)
 
 
 class VettedCommentaryFactory(CommentaryFactory):
     vetted = True
+    vetted_by = factory.Iterator(Contributor.objects.all())
 
 
 class UnpublishedVettedCommentaryFactory(VettedCommentaryFactory):
diff --git a/commentaries/models.py b/commentaries/models.py
index ac6dab51bf5723cbad95556ed95bfa5c13ec9641..51490c7d8fc3c344e9ed2f3104db5a3cb2b80823 100644
--- a/commentaries/models.py
+++ b/commentaries/models.py
@@ -8,17 +8,10 @@ from scipost.behaviors import ArxivCallable, TimeStampedModel
 from scipost.models import Contributor
 from scipost.constants import SCIPOST_DISCIPLINES, DISCIPLINE_PHYSICS, SCIPOST_SUBJECT_AREAS
 
+from .constants import COMMENTARY_TYPES
 from .managers import CommentaryManager
 
 
-COMMENTARY_PUBLISHED = 'published'
-COMMENTARY_PREPRINT = 'preprint'
-COMMENTARY_TYPES = (
-    (COMMENTARY_PUBLISHED, 'published paper'),
-    (COMMENTARY_PREPRINT, 'arXiv preprint'),
-)
-
-
 class Commentary(ArxivCallable, TimeStampedModel):
     """
     A Commentary contains all the contents of a SciPost Commentary page for a given publication.
diff --git a/commentaries/templates/commentaries/vet_commentary_email_accepted.html b/commentaries/templates/commentaries/vet_commentary_email_accepted.html
index 69ba77f82041bc55e7d95c3dc5b34f4e486de797..7c5056b8e24c8cdb402c3cfafb8801684f8e2a2f 100644
--- a/commentaries/templates/commentaries/vet_commentary_email_accepted.html
+++ b/commentaries/templates/commentaries/vet_commentary_email_accepted.html
@@ -1,6 +1,6 @@
 Dear {{commentary.requested_by.get_title}} {{commentary.requested_by.user.last_name}},
 
-The Commentary Page you have requested, concerning publication with title {{commentary.pub_title}} by {{commentary.author_list}}, has been activated at https://scipost.org/commentary/'{{commentary.arxiv_or_DOI_string}}.
+The Commentary Page you have requested, concerning publication with title {{commentary.pub_title}} by {{commentary.author_list}}, has been activated at https://scipost.org/commentary/{{commentary.arxiv_or_DOI_string}}.
 You are now welcome to submit your comments.
 
 Thank you for your contribution,
diff --git a/commentaries/views.py b/commentaries/views.py
index b8eb6d4e4eb4eb75750d08bc98ce1b7af0367e01..53d0b1c15eb3b4fd2a38e274ced6f20366f87575 100644
--- a/commentaries/views.py
+++ b/commentaries/views.py
@@ -150,7 +150,7 @@ def vet_commentary_request_ack(request, commentary_id):
             email_args = (
                 'SciPost Commentary Page activated',
                 email_text,
-                [commentary.requested_by.user.email],
+                commentary.requested_by.user.email,
                 ['commentaries@scipost.org']
             )
             emailmessage = EmailMessage(*email_args, reply_to=['commentaries@scipost.org'])
diff --git a/comments/admin.py b/comments/admin.py
index ac6a36e65aab47674d8579434abd6d721b104d8f..6cfa6fa189234c235205ff884230843cb796e43a 100644
--- a/comments/admin.py
+++ b/comments/admin.py
@@ -4,13 +4,17 @@ from .constants import STATUS_VETTED
 from .models import Comment
 
 
+def comment_opening(comment):
+    return comment.comment_text[:30] + '...'
+
+
 def comment_is_vetted(comment):
     '''Check if comment is vetted.'''
     return comment.status is STATUS_VETTED
 
 
 class CommentAdmin(admin.ModelAdmin):
-    list_display = ('comment_text', 'author', 'date_submitted', comment_is_vetted)
+    list_display = (comment_opening, 'author', 'date_submitted', comment_is_vetted)
     date_hierarchy = 'date_submitted'
     list_filter = ('status',)
     comment_is_vetted.boolean = True
diff --git a/comments/factories.py b/comments/factories.py
index 010251601a8ea7186e8df653d3cdef9ff54422ae..d74370a136d4a140fd82e8f6d060acf6497526b4 100644
--- a/comments/factories.py
+++ b/comments/factories.py
@@ -1,16 +1,46 @@
 import factory
+import pytz
 
 from django.utils import timezone
 
-from scipost.factories import ContributorFactory
+from commentaries.factories import VettedCommentaryFactory
+from scipost.models import Contributor
+from submissions.factories import EICassignedSubmissionFactory
+from theses.factories import VettedThesisLinkFactory
 
+from .constants import STATUS_VETTED
 from .models import Comment
 
+from faker import Faker
+
+timezone.now()
+
 
 class CommentFactory(factory.django.DjangoModelFactory):
+    author = factory.Iterator(Contributor.objects.all())
+    comment_text = factory.lazy_attribute(lambda x: Faker().paragraph())
+    remarks_for_editors = factory.lazy_attribute(lambda x: Faker().paragraph())
+    file_attachment = Faker().file_name(extension='pdf')
+    status = STATUS_VETTED  # All comments will have status vetted!
+    vetted_by = factory.Iterator(Contributor.objects.all())
+    date_submitted = Faker().date_time_between(start_date="-3y", end_date="now", tzinfo=pytz.UTC)
+
     class Meta:
         model = Comment
+        abstract = True
+
+
+class CommentaryCommentFactory(CommentFactory):
+    commentary = factory.SubFactory(VettedCommentaryFactory)
+
+
+class SubmissionCommentFactory(CommentFactory):
+    submission = factory.SubFactory(EICassignedSubmissionFactory)
+
+
+class ThesislinkCommentFactory(CommentFactory):
+    thesislink = factory.SubFactory(VettedThesisLinkFactory)
+
 
-    author = factory.SubFactory(ContributorFactory)
-    comment_text = factory.Faker('text')
-    date_submitted = timezone.now()
+class ReplyCommentFactory(CommentFactory):
+    in_reply_to_comment = factory.SubFactory(SubmissionCommentFactory)
diff --git a/common/helpers/__init__.py b/common/helpers/__init__.py
index 78f99d9b8e50de1c0ce2fc15ae82ddf0eb23ef85..abe97df91f6222671cdcf4338f5ac1a39d0073ba 100644
--- a/common/helpers/__init__.py
+++ b/common/helpers/__init__.py
@@ -1,6 +1,8 @@
 import random
 import string
 
+from journals.constants import SCIPOST_JOURNALS_SUBMIT
+
 
 def model_form_data(model, form_class, form_kwargs={}):
     '''
@@ -29,6 +31,7 @@ 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"
 
@@ -37,6 +40,34 @@ def random_arxiv_identifier_without_version_number():
     return random_digits(4) + "." + random_digits(5)
 
 
+def random_scipost_journal():
+    return random.choice(SCIPOST_JOURNALS_SUBMIT)[0]
+
+
+def random_external_journal():
+    return random.choice((
+        'PhysRevA.',
+        'PhysRevB.',
+        'PhysRevC.',
+        'nature.'
+        'S0550-3213(01)',
+        '1742-5468/',
+        '0550-3213(96)'
+    ))
+
+
+def random_pub_number():
+    return '%i.%i.%s' % (random.randint(1, 9), random.randint(1, 9), random_digits(3))
+
+
+def random_scipost_doi():
+    return '10.21468/%s.%s' % (random_scipost_journal(), random_pub_number())
+
+
+def random_external_doi():
+    return '10.%s/%s%s' % (random_digits(5), random_external_journal(), random_pub_number())
+
+
 def random_digits(n):
     return "".join(random.choice(string.digits) for _ in range(n))
 
diff --git a/common/helpers/test.py b/common/helpers/test.py
index 2c0d7c96d9724179fc73d98a7a14709ba2d35fbb..e7ed63a924a7a08acbaaba035fd49e9e394d1d3e 100644
--- a/common/helpers/test.py
+++ b/common/helpers/test.py
@@ -1,4 +1,5 @@
 import scipost.management.commands.add_groups_and_permissions
 
+
 def add_groups_and_permissions():
     scipost.management.commands.add_groups_and_permissions.Command().handle(verbose=False)
diff --git a/docs/contributors/contributors.rst b/docs/contributors/contributors.rst
deleted file mode 100644
index a8de5a00fe9861ad6ba1ed60d219b6d1eebba549..0000000000000000000000000000000000000000
--- a/docs/contributors/contributors.rst
+++ /dev/null
@@ -1,9 +0,0 @@
-For Contributors
-================
-
-
-.. toctree::
-   :maxdepth: 2
-
-   editorial_fellows/editorial_fellows
-   editorial_administrators/editorial_administrators
diff --git a/docs/contributors/editorial_fellows/editorial_fellows.rst b/docs/contributors/editorial_fellows/editorial_fellows.rst
deleted file mode 100644
index 506d4173785b2206f943563ecafa68f4b0ae1a6c..0000000000000000000000000000000000000000
--- a/docs/contributors/editorial_fellows/editorial_fellows.rst
+++ /dev/null
@@ -1,2 +0,0 @@
-For Editorial Fellows
-=====================
diff --git a/docs/guides/guides.rst b/docs/guides/guides.rst
new file mode 100644
index 0000000000000000000000000000000000000000..fcb34041d6e101fc71e625ecd489cc46bafc71bd
--- /dev/null
+++ b/docs/guides/guides.rst
@@ -0,0 +1,10 @@
+Guides
+======
+
+
+.. toctree::
+   :maxdepth: 2
+
+   submissions_processing/submissions_processing
+   production/production
+   maintenance/maintenance
diff --git a/docs/guides/maintenance/maintenance.rst b/docs/guides/maintenance/maintenance.rst
new file mode 100644
index 0000000000000000000000000000000000000000..82ab83716d571b416716ac03deafe5d6eaa82247
--- /dev/null
+++ b/docs/guides/maintenance/maintenance.rst
@@ -0,0 +1,8 @@
+Maintenance
+===========
+
+
+.. toctree::
+   :maxdepth: 2
+
+   maintenance/maintenance
diff --git a/docs/contributors/editorial_administrators/maintenance.rst b/docs/guides/maintenance/maintenance/maintenance.rst
similarity index 72%
rename from docs/contributors/editorial_administrators/maintenance.rst
rename to docs/guides/maintenance/maintenance/maintenance.rst
index ee7dc9e6f594a447dd3e25c5a95a5e3634fab86b..02a6140f0dc143bba0638cacbad7c719a592c86a 100644
--- a/docs/contributors/editorial_administrators/maintenance.rst
+++ b/docs/guides/maintenance/maintenance/maintenance.rst
@@ -1,5 +1,5 @@
-Maintenance of published material
-=================================
+Maintenance of SciPost Publications
+===================================
 
 This guide is meant for **Editorial Administrators**.
 It describes the post-publication maintenance of the published material.
diff --git a/docs/contributors/editorial_administrators/production.rst b/docs/guides/production/initial_production/initial_production.rst
similarity index 63%
rename from docs/contributors/editorial_administrators/production.rst
rename to docs/guides/production/initial_production/initial_production.rst
index 1a42a9c8d24605e4f845beed1c29888baeb2a004..937068f30fb0171264f45ed703b16aaca525c3b9 100644
--- a/docs/contributors/editorial_administrators/production.rst
+++ b/docs/guides/production/initial_production/initial_production.rst
@@ -3,9 +3,9 @@
 Production of SciPost Publications
 ==================================
 
-This guide is meant for **Editorial Administrators** and **Production Officers**. It describes the post-acceptance workflow from paper acceptance to publication.
+This guide is meant for **Editorial Administrators**, **Production Supervisors** and **Production Officers**. It describes the post-acceptance workflow from paper acceptance to publication.
 
-Version: 2016-12-20.
+Version: 2017-05-11.
 
 
 Formatting check
@@ -13,8 +13,8 @@ Formatting check
 
    If the Submission's references are not properly formatted,
    and/or if these do not include the required DOIs,
-   the authors should be emailed and asked to do so,
-   by providing either the ``.bbl`` file or the ``.bib`` source.
+   the authors should be emailed and asked to provide them,
+   by sending in either an updated ``.bbl`` file or ``.bib`` source.
 
    Any extra material provided by the authors which supplements
    the arXiv source should be put in a folder ``EXTRA_FROM_AUTH``.
@@ -24,7 +24,7 @@ Source retrieval and folder preparation
 ---------------------------------------
 
    #. On the SciPost server, navigate to folder
-      ``[Journal full name]/IN PRODUCTION``.
+      ``[Journal full name]/IN_PRODUCTION``.
    #. Create a folder
       ``[journal abbrev. name]_[arxiv identifier]_[first author last name]``,
       e.g. ``SciPost_Phys_1604.98141v3_Smart``.
@@ -32,10 +32,13 @@ Source retrieval and folder preparation
    #. NOTE: the file will be named ``####.#####v#``, which is not recognized
       as a ``.tar.gz`` file on a UNIX system. Rename the file
       ``####.####v#.tar.gz``. Unzip it to produce the folder ``####.#####v#``.
+      If this produces another tar file, it is because the submission consists of
+      a single ``.tex`` file; you should then rename this to ``####.#####v#.tex``.
    #. Copy the paper’s sources one level down (so from ``####.#####v#`` to
       the current directory). BE CAREFUL: if the authors have included any of
       the SciPost style files (``SciPost.cls``, ``SciPost_bibstyle.bst``), DO NOT
-      copy those down.
+      copy those down. You can skip this step if the previous step immediately led
+      to a ``.tex`` file.
    #. Copy the files in
       ``[Journal full name]/v##_production/FILES_TO_COPY_IN_PAPER_DIR``
       to the current directory. There are 5 files:
@@ -44,7 +47,7 @@ Source retrieval and folder preparation
 	 * ``logo_scipost_with_bgd.pdf``
 	 * ``SciPost_bibstyle.bst``
 	 * ``SciPost.cls``
-	 * ``SciPost_Phys_Skeleton.tex``
+	 * ``SciPost_[Phys, or other as appropriate]_Skeleton.tex``
 
    #. Copy the skeleton ``.tex`` source to a new file using the name convention
       ``[Journal abbrev. name]_####_#####v#_[first author last name].tex``
@@ -91,14 +94,14 @@ General LaTeX tips
 Step-by-step procedure
 ~~~~~~~~~~~~~~~~~~~~~~
 
-   #. TODO: PAPER CITATION 1 and 2
+   #. TODO: PAPER CITATION
 
-      In these two places, fill the missing numbers in the citation header::
+      In this place, fill the missing numbers in the citation header::
 
       \rhead{\small \href{https://scipost.org/SciPostPhys.?.?.???}{SciPost Phys. ?, ??? (20??)}}
 
 
-      The first argument of the ``href`` is the simple permanent URL for the publication. This includes 3 numbers: the volume number, issue, and three-digit paper number, for example ``SciPostPhys.1.2.011``. At this stage, leave the paper number to ``???``: this number will be assigned and filled in in the last stage of production.
+      The first argument of the ``href`` is the simple permanent URL for the publication. This includes 3 numbers: the volume number, issue, and three-digit paper number, for example ``SciPostPhys.1.2.011``. Verify the appropriate issue number (this will be verified later by an EdAdmin). At this stage, leave the paper number to ``???``: this number will be assigned and filled in in the last stage of production.
 
       The second argument to the ``href`` uses the simple citation, dropping the issue number, for example ``SciPostPhys. 1, 011 (2016)``.
 
@@ -146,7 +149,7 @@ Step-by-step procedure
 	[title]
 	}}}\end{center}
 
-      Paste the title in this block. If the title is multiline, end it with ``\\``
+      Paste the title in this block. End the title with ``\\``
       in order to ensure proper uniform spacing between the lines.
 
 
@@ -155,7 +158,8 @@ Step-by-step procedure
       Author names should be in format ``firstname lastname``, e.g. ``John Smith``,
       and should be in textbf. No ``comma`` but rather an ``and`` before
       the last author. If multiple authors and affiliations, use ``\textsuperscript``
-      and positive integer labels, with a ``*`` for the corresponding author.
+      and positive integer labels, with a ``$\star$`` for the corresponding author.
+      If multiple email addresses are given, reference them with ``$\dagger$, ...``.
 
 
    #. TODO: AFFILIATIONS
@@ -172,8 +176,8 @@ Step-by-step procedure
 
 	``\href{mailto:[email]}{\small \sf [email]}``
 
-      prepended with ``*`` if corresponding author. If no email is to be given,
-      comment out the ``* \href{mailto:[email]}{\small \sf [email]}`` line.
+      prepended with ``$\star$`` if corresponding author. If no email is to be given,
+      comment out the ``$\star$ \href{mailto:[email]}{\small \sf [email]}`` line.
 
       If a web link is offered, use the format ``{\small \url{[url]}}``.
 
@@ -198,7 +202,7 @@ Step-by-step procedure
 
 	\vspace{10pt}
 	\noindent\rule{\textwidth}{1pt}
-	\tableofcontents\thispagestyle{fancy}
+	\tableofcontents
 	\noindent\rule{\textwidth}{1pt}
 	\vspace{10pt}
 
@@ -206,10 +210,13 @@ Step-by-step procedure
 
 	\vspace{10pt}
 	%\noindent\rule{\textwidth}{1pt}
-	%\tableofcontents\thispagestyle{fancy}
+	%\tableofcontents
 	\noindent\rule{\textwidth}{1pt}
 	\vspace{10pt}
 
+      If a single horizontal line is pushed to the next page, correct by
+      playing with negatime ``\vspace``.
+
 
    #. TODO: COPYRIGHT
 
@@ -226,7 +233,7 @@ Step-by-step procedure
       format ``DD-MM-YYYY``. Be careful to use the correct submission data,
       namely that of the original submission.
 
-      The published date will be filled in later on.
+      The accepted and published dates will be filled in later on.
 
 
    #. TODO: DOI
@@ -237,13 +244,16 @@ Step-by-step procedure
 
    #. TODO: LINENO
 
-      During proofs stage, activate line numbers.
+      During proofs stage, make sure line numbers are activated (they should
+      be by default).
 
 
    #. TODO: CONTENTS
 
       Paste the entire bulk of the paper in this block,
       including all sections and eventual appendices.
+      Check that there are no appendices after the references in the
+      original tex file.
 
 
    #. TODO: BIBNR
@@ -372,6 +382,8 @@ References formatting
 
       * Volume number is in bold.
 
+      * Issue number can be left out; if included, in parentheses after volume nr.
+
       * Year is in parentheses.
 
       * Commas separate all elements.
@@ -388,13 +400,20 @@ References formatting
       If not, use the format ``\href{https://arxiv.org/abs/####.#####}{arXiv:####.#####}``,
       and remove any ``(YEAR)``.
 
-      \J. Stat. Mech. is annoying (volume number is year). Manually remove volume nr for
-      these, so the format becomes ``A. Bee, \emp{Bee's nice paper}, J. Stat. Mech.: Th. Exp. [P,L]##### (20##), \doi{10...}.``
+      \J. Stat. Mech. and JHEP are annoying (because the volume number is the year).
+      Manually remove volume nr for these, so the format becomes ``A. Bee, \emp{Bee's nice paper}, J. Stat. Mech.: Th. Exp. [P,L]##### (20##), \doi{10...}.``
 
       \J. Phys. A is also annoying. Up to and including volume 39 (2006), it's
       \J. Phys. A: Math. Gen. Afterwards, volume 40 (2007) onwards, it's
       \J. Phys. A: Math. Theor.
 
+      Entries in the bibliography which are not references but footnotes,
+      should be formatted as such in the main text (using ``\footnote{}``).
+
+
+      Check that all DOIs work. Remove the ``\meta`` at the end of the bibitem
+      if it is present.
+
 
 Layout verification
 ~~~~~~~~~~~~~~~~~~~
@@ -404,163 +423,3 @@ Layout verification
 
    In particular, the punctuation of equations should be checked and corrected
    if necessary.
-
-
-Proofs
-------
-
-   * Once the paper has been properly formatted, the ``.tex`` and ``.pdf`` files
-     should be copied into new files carrying the ``_proofs_v[nr]`` suffix,
-     for example ``SciPost_Phys_1699_9999v9_Bee_proofs_v1.tex``.
-
-   * The ``.pdf`` proofs should be email to the authors for verification.
-     Authors should return either an annotated pdf or a list of corrections
-     by plain text email.
-
-   * Any modifications should be implemented directly in the main ``.tex`` file.
-
-   * If any further check by the authors are required, start this proofs
-     todo-list again, increasing the proofs version number.
-
-   * Once the authors have approved the proofs, the paper can be put forward
-     to online publication.
-
-
-Online publication
-------------------
-
-   These tasks must be performed by an **Editorial Administrator**.
-
-
-Preparation of final version of record
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-   #. Copy the whole paper folder from folder [journal name]/IN\_PRODUCTION \\to [journal name]/Volume\_[volume nr].
-
-   #. Check online to see which paper number is next available.
-
-   #. Rename this folder using the convention [journal name]\_[volume number]([issue number])\_[paper nr].
-
-   #. Within this folder, take the author-accepted version tex file and rename it using the convention [journal name abbrev]\_[volume nr]\_[issue nr]\_[paper nr].tex.
-
-   #. In this tex source, replace the ??? with the 3-digit paper number (6 places: 4 in preamble, 2 in copyright statement).
-
-   #. Ensure that the author names are in format Abe Bee, Cee Dee and Elle Fine.
-
-   #. Insert the correct Received, Accepted and Published dates in copyright statement.
-
-   #. Make sure linenumbers are deactivated.
-
-   #. Does the table of contents (if present) look OK? (Beware of hanging closing
-      line pushed to top of second page). If needed, adjust the ``\vspace`` spacings
-      defined around the table of contents, and/or insert an additional ``vspace``
-      with negative spacing before the abstract.
-
-   #. If the author-accepted proofs version used BiBTeX, copy the contents of the bbl
-      file into the .tex file, so that BiBTeX is not needed anymore.
-
-   #. Verify each reference: authors, title, journal reference, doi link.
-      Manually correct any incorrect references.
-
-   #. Recompile the LaTeX, and CAREFULLY CHECK EVERYTHING.
-
-
-Uploading to ``scipost.org``
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-
-   #. From the Submissions Pool, click on the link to initiate the publication process.
-
-   #. Fill in the initiate publication form (using the dates in format YYYY-MM-DD). Submit. You are now on the validate publication page.
-
-   #. Check that the paper number is correct. If not, modify the final tex source to account for this (see previous subsection).
-
-   #. Select who the first author is (if registered as a Contributor; if not, inform the EdAdmin, and choose another author who is registered).
-
-   #. Select the final version's pdf file.
-
-   #. Submit. The paper is now published online.
-
-
-Metadata preparation and DOI registration with Crossref
--------------------------------------------------------
-
-   These tasks must be performed by **Editorial Administrators**,
-   who have access to the Publication's editorial tools
-   by navigating to the Publication's page.
-
-
-Author listing
-~~~~~~~~~~~~~~
-
-   If not all authors appear in the list presented at the top of the EdAdmin tools,
-   these should be added by following the ``Add a missing author`` link.
-
-   The search form can be used to find missing authors who might be
-   Registered Contributors. If found, a one-click process adds them.
-
-   You can otherwise create an UnregisteredAuthor object instance and link
-   it to the publication, by simply filling in the first and last name fields
-   and clicking on ``Add``.
-
-
-Preparation of the citations list
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-   Follow the ``Create/update citation list metadata`` link.
-
-   In the text area, paste the entire list of bibitems from the paper's
-   final ``.tex`` file. Upon clicking on ``Submit``, all DOI entires
-   are extracted and formatted into XML metadata which is saved in the
-   database.
-
-   Citations with no valid DOI (*e.g.* arXiv preprints, books, etc)
-   do not appear in the metadata.
-
-
-Funding info
-~~~~~~~~~~~~
-
-   Following the ``Create/update funding info metadata`` link leads to a
-   page where the funding statement of the Publication's ``.tex`` file
-   (found either as a separate subsection or in the Acknowledgements)
-   can be pasted.
-
-
-Preparation of the metadata XML
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-   Following the ``Create/update metadata XML`` link auto-generates a
-   full XML text field containing all the provided information,
-   properly formatted for the upcoming submission to Crossref.
-
-   Verify that the first author is indeed enclosed in a
-   ``<person_name sequence='first' contributor_role='author'>`` tag,
-   and that subsequent authors (enclosed in
-   ``<person_name sequence='additional' contributor_role='author'>`` tags)
-   appear in the order of the Publication's author list.
-
-   Once the metadata is set, clicking on ``Accept the metadata``
-   saves the metadata to the database and returns one to the Publication's
-   page.
-
-
-Metadata testing and deposit
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-   At this stage, the metadata is ready for uploading to Crossref.
-   This occurs via a POST query to either the test or live Crossref server.
-
-   Clicking on ``Test metadata deposit`` immediately posts the metadata
-   to the test server, and takes you to a page where the server's
-   response headers are displayed. The server also sends a more detailed
-   response via email
-   (to ``admin@scipost.org``; if you do not have access to this mailbox,
-   ask SciPost Administration) with the success status.
-
-   Similarly, the actual deposit is immediately performed upon clicking on the
-   ``Deposit the metadata to Crossref``. The response headers are displayed,
-   and a detailed email response is sent by Crossref to ``admin@scipost.org``.
-
-
-   **This completes the publication process.**
diff --git a/docs/guides/production/online_publication/online_publication.rst b/docs/guides/production/online_publication/online_publication.rst
new file mode 100644
index 0000000000000000000000000000000000000000..92c29b6ef4609e75843f1ed61bd4ddfa9ae5be91
--- /dev/null
+++ b/docs/guides/production/online_publication/online_publication.rst
@@ -0,0 +1,148 @@
+.. Howto for publication production
+
+Online Publication
+==================
+
+This guide is meant for **Editorial Administrators**. It describes the final publication of manuscripts, after final author proofs approval.
+
+Version: 2017-05-11.
+
+
+Finalization of manuscript production
+-------------------------------------
+
+The steps described here follow up on the :doc:`production` instructions used by production officers.
+
+
+Preparation of final version of record
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   #. Copy the whole paper folder from folder [journal name]/IN\_PRODUCTION \\to [journal name]/Volume\_[volume nr].
+
+   #. Check online to see which paper number is next available.
+
+   #. Rename this folder using the convention [journal name]\_[volume number]([issue number])\_[paper nr].
+
+   #. Within this folder, take the author-accepted version tex file and rename it using the convention [journal name abbrev]\_[volume nr]\_[issue nr]\_[paper nr].tex.
+
+   #. In this tex source, replace the ??? with the 3-digit paper number (3 places: 2 in preamble, 1 in copyright statement).
+
+   #. Ensure that the author names are in format Abe Bee, Cee Dee and Elle Fine.
+
+   #. Insert the correct Received, Accepted and Published dates in copyright statement.
+
+   #. Make sure linenumbers are deactivated.
+
+   #. Does the table of contents (if present) look OK? (Beware of hanging closing
+      line pushed to top of second page). If needed, adjust the ``\vspace`` spacings
+      defined around the table of contents, and/or insert an additional ``vspace``
+      with negative spacing before the abstract.
+
+   #. If the author-accepted proofs version used BiBTeX, copy the contents of the bbl
+      file into the .tex file, so that BiBTeX is not needed anymore.
+
+   #. Verify each reference: authors, title, journal reference, doi link.
+      Manually correct any incorrect references.
+
+   #. Recompile the LaTeX, and CAREFULLY CHECK EVERYTHING.
+
+
+Uploading to ``scipost.org``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+   #. From the Submissions Pool, click on the link to initiate the publication process.
+
+   #. Fill in the initiate publication form (using the dates in format YYYY-MM-DD). Submit. You are now on the validate publication page.
+
+   #. Check that the paper number is correct. If not, modify the final tex source to account for this (see previous subsection).
+
+   #. Select who the first author is (if registered as a Contributor; if not, inform the EdAdmin, and choose another author who is registered).
+
+   #. Select the final version's pdf file.
+
+   #. Submit. The paper is now published online.
+
+
+Metadata preparation and DOI registration with Crossref
+-------------------------------------------------------
+
+   These tasks must be performed by **Editorial Administrators**,
+   who have access to the Publication's editorial tools
+   by navigating to the Publication's page.
+
+
+Author listing
+~~~~~~~~~~~~~~
+
+   If not all authors appear in the list presented at the top of the EdAdmin tools,
+   these should be added by following the ``Add a missing author`` link.
+
+   The search form can be used to find missing authors who might be
+   Registered Contributors. If found, a one-click process adds them.
+
+   You can otherwise create an UnregisteredAuthor object instance and link
+   it to the publication, by simply filling in the first and last name fields
+   and clicking on ``Add``.
+
+
+Preparation of the citations list
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   Follow the ``Create/update citation list metadata`` link.
+
+   In the text area, paste the entire list of bibitems from the paper's
+   final ``.tex`` file. Upon clicking on ``Submit``, all DOI entires
+   are extracted and formatted into XML metadata which is saved in the
+   database.
+
+   Citations with no valid DOI (*e.g.* arXiv preprints, books, etc)
+   do not appear in the metadata.
+
+
+Funding info
+~~~~~~~~~~~~
+
+   Following the ``Create/update funding info metadata`` link leads to a
+   page where the funding statement of the Publication's ``.tex`` file
+   (found either as a separate subsection or in the Acknowledgements)
+   can be pasted.
+
+
+Preparation of the metadata XML
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   Following the ``Create/update metadata XML`` link auto-generates a
+   full XML text field containing all the provided information,
+   properly formatted for the upcoming submission to Crossref.
+
+   Verify that the first author is indeed enclosed in a
+   ``<person_name sequence='first' contributor_role='author'>`` tag,
+   and that subsequent authors (enclosed in
+   ``<person_name sequence='additional' contributor_role='author'>`` tags)
+   appear in the order of the Publication's author list.
+
+   Once the metadata is set, clicking on ``Accept the metadata``
+   saves the metadata to the database and returns one to the Publication's
+   page.
+
+
+Metadata testing and deposit
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+   At this stage, the metadata is ready for uploading to Crossref.
+   This occurs via a POST query to either the test or live Crossref server.
+
+   Clicking on ``Test metadata deposit`` immediately posts the metadata
+   to the test server, and takes you to a page where the server's
+   response headers are displayed. The server also sends a more detailed
+   response via email
+   (to ``admin@scipost.org``; if you do not have access to this mailbox,
+   ask SciPost Administration) with the success status.
+
+   Similarly, the actual deposit is immediately performed upon clicking on the
+   ``Deposit the metadata to Crossref``. The response headers are displayed,
+   and a detailed email response is sent by Crossref to ``admin@scipost.org``.
+
+
+   **This completes the publication process.**
diff --git a/docs/guides/production/production.rst b/docs/guides/production/production.rst
new file mode 100644
index 0000000000000000000000000000000000000000..0d2e6d139bae69d46084939bf8c28a61e0e51369
--- /dev/null
+++ b/docs/guides/production/production.rst
@@ -0,0 +1,10 @@
+Production
+==========
+
+
+.. toctree::
+   :maxdepth: 2
+
+   initial_production/initial_production
+   proofs/proofs
+   online_publication/online_publication
diff --git a/docs/guides/production/proofs/proofs.rst b/docs/guides/production/proofs/proofs.rst
new file mode 100644
index 0000000000000000000000000000000000000000..eb50aee6c46c9efee9501d5b8d840453564dabc4
--- /dev/null
+++ b/docs/guides/production/proofs/proofs.rst
@@ -0,0 +1,26 @@
+.. Howto for proofs
+
+Proofs
+======
+
+This guide is meant for **Production supervisors**. It describes the proofs cycle between production team and manuscript authors.
+
+
+Proofs version production
+-------------------------
+
+   * Once the paper has been properly formatted, the ``.tex`` and ``.pdf`` files
+     should be copied into new files carrying the ``_proofs_v[nr]`` suffix,
+     for example ``SciPost_Phys_1699_9999v9_Bee_proofs_v1.tex``.
+
+   * The ``.pdf`` proofs should be emailed to the authors for verification.
+     Authors should return either an annotated pdf or a list of corrections
+     by plain text email.
+
+   * Any modifications should be implemented directly in the main ``.tex`` file.
+
+   * If any further check by the authors are required, start this proofs
+     todo-list again, increasing the proofs version number.
+
+   * Once the authors have approved the proofs, the paper can be put forward
+     to online publication.
diff --git a/docs/contributors/editorial_administrators/submission_processing.rst b/docs/guides/submissions_processing/submissions_processing.rst
similarity index 100%
rename from docs/contributors/editorial_administrators/submission_processing.rst
rename to docs/guides/submissions_processing/submissions_processing.rst
diff --git a/docs/index.rst b/docs/index.rst
index 5b4a14377165a55f0ee5a0355ad9ec4095e357c9..a7922f3d586c4b8d1aa354b6ea660c1f1564ae5c 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -9,9 +9,10 @@ Welcome to SciPost's documentation!
 Contents:
 
 .. toctree::
-   :maxdepth: 3
+   :maxdepth: 2
 
-   contributors/contributors
+   roles/roles
+   guides/guides
    developers/developers
 
 
diff --git a/docs/contributors/editorial_administrators/editorial_administrators.rst b/docs/roles/editorial/editorial_administrators.rst
similarity index 59%
rename from docs/contributors/editorial_administrators/editorial_administrators.rst
rename to docs/roles/editorial/editorial_administrators.rst
index 33e054b533e1a4951058019a0f2644e8622f11cd..d6747f7d357c5799fb77d8450dac71a258523b3d 100644
--- a/docs/contributors/editorial_administrators/editorial_administrators.rst
+++ b/docs/roles/editorial/editorial_administrators.rst
@@ -4,7 +4,3 @@ Editorial Administrators
 
 .. toctree::
    :maxdepth: 2
-
-   submission_processing
-   production
-   maintenance
diff --git a/docs/roles/editorial/editorial_fellows.rst b/docs/roles/editorial/editorial_fellows.rst
new file mode 100644
index 0000000000000000000000000000000000000000..00973f28a2fff53aa8726ed59a63da0bc3fd0122
--- /dev/null
+++ b/docs/roles/editorial/editorial_fellows.rst
@@ -0,0 +1,6 @@
+Editorial Fellows
+=================
+
+
+.. toctree::
+   :maxdepth: 2
diff --git a/docs/roles/production/production_officers.rst b/docs/roles/production/production_officers.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b9b79da1740c33ef7a2ca3c382e9a29a512985d6
--- /dev/null
+++ b/docs/roles/production/production_officers.rst
@@ -0,0 +1,6 @@
+Production Officers
+===================
+
+
+.. toctree::
+   :maxdepth: 2
diff --git a/docs/roles/roles.rst b/docs/roles/roles.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3df3c2c3eda344d4ddf876bb4e6072a053f6321e
--- /dev/null
+++ b/docs/roles/roles.rst
@@ -0,0 +1,10 @@
+Roles: responsibilities and task lists
+======================================
+
+
+.. toctree::
+   :maxdepth: 2
+
+   editorial/editorial_administrators
+   editorial/editorial_fellows
+   production/production_officers
diff --git a/journals/factories.py b/journals/factories.py
new file mode 100644
index 0000000000000000000000000000000000000000..8d8de8ee154b5922fe4f728ca37ef39f8e3accee
--- /dev/null
+++ b/journals/factories.py
@@ -0,0 +1,111 @@
+import factory
+import datetime
+import pytz
+
+from django.utils import timezone
+
+from common.helpers import random_digits
+from journals.constants import SCIPOST_JOURNALS
+from submissions.factories import PublishedSubmissionFactory
+
+from .models import Journal, Volume, Issue, Publication
+
+from faker import Faker
+
+
+class JournalFactory(factory.django.DjangoModelFactory):
+    name = factory.Iterator(SCIPOST_JOURNALS, getter=lambda c: c[0])
+    doi_label = factory.Iterator(SCIPOST_JOURNALS, getter=lambda c: c[0])
+    issn = factory.lazy_attribute(lambda n: random_digits(8))
+
+    class Meta:
+        model = Journal
+        django_get_or_create = ('name', 'doi_label',)
+
+
+class VolumeFactory(factory.django.DjangoModelFactory):
+    in_journal = factory.SubFactory(JournalFactory)
+    number = 9999
+    doi_label = factory.Faker('md5')
+
+    @factory.post_generation
+    def doi(self, create, extracted, **kwargs):
+        self.number = self.in_journal.volume_set.count()
+        self.doi_label = self.in_journal.doi_label + '.' + str(self.number)
+
+    @factory.post_generation
+    def dates(self, create, extracted, **kwargs):
+        timezone.now()
+        self.start_date = Faker().date_time_between(start_date="-3y", end_date="now",
+                                                    tzinfo=pytz.UTC)
+        self.until_date = self.start_date + datetime.timedelta(weeks=26)
+
+    class Meta:
+        model = Volume
+        django_get_or_create = ('in_journal', 'number')
+
+
+class IssueFactory(factory.django.DjangoModelFactory):
+    in_volume = factory.Iterator(Volume.objects.all())
+    number = 9999
+    doi_label = factory.Faker('md5')
+
+    @factory.post_generation
+    def doi(self, create, extracted, **kwargs):
+        self.number = self.in_volume.issue_set.count()
+        self.doi_label = self.in_volume.doi_label + '.' + str(self.number)
+
+    @factory.post_generation
+    def dates(self, create, extracted, **kwargs):
+        timezone.now()
+        self.start_date = Faker().date_time_between(start_date=self.in_volume.start_date,
+                                                    end_date=self.in_volume.until_date,
+                                                    tzinfo=pytz.UTC)
+        self.until_date = self.start_date + datetime.timedelta(weeks=4)
+
+    class Meta:
+        model = Issue
+        django_get_or_create = ('in_volume', 'number')
+
+
+class PublicationFactory(factory.django.DjangoModelFactory):
+    accepted_submission = factory.SubFactory(PublishedSubmissionFactory)
+    paper_nr = 9999
+    pdf_file = Faker().file_name(extension='pdf')
+    in_issue = factory.Iterator(Issue.objects.all())
+    submission_date = factory.Faker('date')
+    acceptance_date = factory.Faker('date')
+    publication_date = factory.Faker('date')
+    doi_label = factory.Faker('md5')
+
+    @factory.post_generation
+    def doi(self, create, extracted, **kwargs):
+        paper_nr = self.in_issue.publication_set.count()
+        self.paper_nr = paper_nr
+        self.doi_label = self.in_issue.doi_label + '.' + str(paper_nr).rjust(3, '0')
+
+    @factory.post_generation
+    def submission_data(self, create, extracted, **kwargs):
+        # Content
+        self.discipline = self.accepted_submission.discipline
+        self.domain = self.accepted_submission.domain
+        self.subject_area = self.accepted_submission.subject_area
+        self.title = self.accepted_submission.title
+        self.abstract = self.accepted_submission.abstract
+
+        # Authors
+        self.author_list = self.accepted_submission.author_list
+        self.authors.add(*self.accepted_submission.authors.all())
+        self.first_author = self.accepted_submission.authors.first()
+        self.authors_claims.add(*self.accepted_submission.authors_claims.all())
+        self.authors_false_claims.add(*self.accepted_submission.authors_false_claims.all())
+
+        # Dates
+        self.submission_date = self.accepted_submission.latest_activity
+        self.acceptance_date = self.accepted_submission.latest_activity
+        self.publication_date = self.accepted_submission.latest_activity
+        self.latest_activity = self.accepted_submission.latest_activity
+
+    class Meta:
+        model = Publication
+        django_get_or_create = ('accepted_submission', )
diff --git a/journals/helpers.py b/journals/helpers.py
index c31314def9187347421ba9fd7251603d5dd688f5..d1d656c2bad92ed789800d15dbe3685f93ca4d84 100644
--- a/journals/helpers.py
+++ b/journals/helpers.py
@@ -8,6 +8,8 @@ def journal_name_abbrev_citation(journal_name):
         return 'SciPost Phys. Sel.'
     elif journal_name == 'SciPostPhysLectNotes':
         return 'SciPost Phys. Lect. Notes'
+    elif journal_name == 'SciPostPhysProc':
+        return 'SciPost Phys. Proc.'
     else:
         raise JournalNameError(journal_name)
 
diff --git a/journals/templates/journals/_base.html b/journals/templates/journals/_base.html
index f6d61a1c6c0ff323a8fc1f45b055407874b2502d..d1813d03f65b98262441e431460898f13a213ba8 100644
--- a/journals/templates/journals/_base.html
+++ b/journals/templates/journals/_base.html
@@ -1,5 +1,7 @@
 {% extends 'scipost/base.html' %}
 
+{% load staticfiles %}
+
 {% block pagetitle %}: {{journal}}{% endblock pagetitle %}
 {% block body_class %}{{block.super}} journals{% endblock %}
 
@@ -48,9 +50,12 @@
         <div class="row my-1">
             <div class="col-12">
                 {% if journal.active %}
-                    {{journal}} is published by the SciPost Foundation under the journal doi: 10.21468/{{journal.name}} and ISSN {{journal.issn}}.
+                    <p>{{journal}} is published by the SciPost Foundation under the journal doi: 10.21468/{{journal.name}} and ISSN {{journal.issn}}.</p>
                 {% endif %}
-            </div>
+		{% if journal.doi_label == 'SciPostPhys' %}
+    		<p class="mb-0">All content in {{ journal }} is deposited and permanently preserved in the CLOCKSS archive <a href="https://www.clockss.org/clockss/Home" target="_blank"><img src="{% static 'scipost/images/clockss_original_logo_boxed_ai-cropped-90.png' %}" alt="CLOCKSS logo" width="40"></a></p>
+		{% endif %}
+	    </div>
         </div>
     </footer>
 {% endblock %}
diff --git a/requirements.txt b/requirements.txt
index ba25dba1447cf01d84a54298194168b368fbd502..8a82ef7057d72bccf77dc2a8d9aeec140e2861bf 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -17,6 +17,7 @@ django-webpack-loader==0.4.1
 djangorestframework==3.5.3
 docutils==0.12
 factory-boy==2.7.0
+Faker==0.7.11
 fake-factory==0.7.2
 feedparser==5.2.1
 imagesize==0.7.1
diff --git a/scipost/factories.py b/scipost/factories.py
index 7381d6173165155478253327f9aacac1665129c7..ce122a6556cc9fb8ffdc1666608f2197382a2b7a 100644
--- a/scipost/factories.py
+++ b/scipost/factories.py
@@ -4,16 +4,16 @@ import random
 from django.contrib.auth import get_user_model
 from django.contrib.auth.models import Group
 
-from django_countries.data import COUNTRIES
+from submissions.models import Submission
 
-from .models import Contributor, EditorialCollege, EditorialCollegeFellowship
-from .constants import TITLE_CHOICES
+from .models import Contributor, EditorialCollege, EditorialCollegeFellowship, Remark
+from .constants import TITLE_CHOICES, SCIPOST_SUBJECT_AREAS
 
+from django_countries.data import COUNTRIES
+from faker import Faker
 
-class ContributorFactory(factory.django.DjangoModelFactory):
-    class Meta:
-        model = Contributor
 
+class ContributorFactory(factory.django.DjangoModelFactory):
     title = random.choice(list(dict(TITLE_CHOICES).keys()))
     user = factory.SubFactory('scipost.factories.UserFactory', contributor=None)
     status = 1  # normal user
@@ -21,6 +21,11 @@ class ContributorFactory(factory.django.DjangoModelFactory):
     personalwebpage = factory.Faker('url')
     country_of_employment = factory.Iterator(list(COUNTRIES))
     affiliation = factory.Faker('company')
+    expertises = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: [c[0]])
+
+    class Meta:
+        model = Contributor
+        django_get_or_create = ('user',)
 
 
 class VettingEditorFactory(ContributorFactory):
@@ -32,9 +37,6 @@ class VettingEditorFactory(ContributorFactory):
 
 
 class UserFactory(factory.django.DjangoModelFactory):
-    class Meta:
-        model = get_user_model()
-
     username = factory.Faker('user_name')
     password = factory.PostGenerationMethodCall('set_password', 'adm1n')
     email = factory.Faker('safe_email')
@@ -44,6 +46,9 @@ class UserFactory(factory.django.DjangoModelFactory):
     # When user object is created, associate new Contributor object to it.
     contributor = factory.RelatedFactory(ContributorFactory, 'user')
 
+    class Meta:
+        model = get_user_model()
+
     @factory.post_generation
     def groups(self, create, extracted, **kwargs):
         # If the object is not saved, we cannot use many-to-many relationship.
@@ -58,17 +63,27 @@ class UserFactory(factory.django.DjangoModelFactory):
 
 
 class EditorialCollegeFactory(factory.django.DjangoModelFactory):
+    discipline = random.choice(['Physics', 'Chemistry', 'Medicine'])
+
     class Meta:
         model = EditorialCollege
         django_get_or_create = ('discipline', )
 
-    discipline = random.choice(['Physics', 'Chemistry', 'Medicine'])
-
 
 class EditorialCollegeFellowshipFactory(factory.django.DjangoModelFactory):
-    class Meta:
-        model = EditorialCollegeFellowship
-
     college = factory.Iterator(EditorialCollege.objects.all())
     contributor = factory.Iterator(Contributor.objects.exclude(
                                    user__username='deleted').order_by('?'))
+
+    class Meta:
+        model = EditorialCollegeFellowship
+
+
+class SubmissionRemarkFactory(factory.django.DjangoModelFactory):
+    contributor = factory.Iterator(Contributor.objects.all())
+    submission = factory.Iterator(Submission.objects.all())
+    date = factory.Faker('date_time_this_decade')
+    remark = factory.lazy_attribute(lambda x: Faker().paragraph())
+
+    class Meta:
+        model = Remark
diff --git a/scipost/forms.py b/scipost/forms.py
index 0b7bb73ef229655d7483e8dd890d0126d42c6c58..e1508ded5f231432cd2cb86afe3ff354c3b84cd1 100644
--- a/scipost/forms.py
+++ b/scipost/forms.py
@@ -82,7 +82,7 @@ class RegistrationForm(forms.Form):
             self.add_error('email', 'This email address is already in use')
         return self.cleaned_data.get('email', '')
 
-    def create_and_save_contributor(self, invitation_key=''):
+    def create_and_save_contributor(self):
         user = User.objects.create_user(**{
             'first_name': self.cleaned_data['first_name'],
             'last_name': self.cleaned_data['last_name'],
@@ -93,7 +93,7 @@ class RegistrationForm(forms.Form):
         })
         contributor, new = Contributor.objects.get_or_create(**{
             'user': user,
-            'invitation_key': invitation_key,
+            'invitation_key': self.cleaned_data.get('invitation_key', ''),
             'title': self.cleaned_data['title'],
             'orcid_id': self.cleaned_data['orcid_id'],
             'country_of_employment': self.cleaned_data['country_of_employment'],
@@ -102,7 +102,8 @@ class RegistrationForm(forms.Form):
             'personalwebpage': self.cleaned_data['personalwebpage'],
         })
 
-        if contributor.invitation_key == '':
+        if contributor.activation_key == '':
+            # Seems redundant?
             contributor.generate_key()
         contributor.save()
         return contributor
diff --git a/scipost/management/commands/populate_db.py b/scipost/management/commands/populate_db.py
index 4880a671c3f06ff63e924fa0ffdb591a89638e89..4efe19d85887e5a79782a2b8defb1919286e049f 100644
--- a/scipost/management/commands/populate_db.py
+++ b/scipost/management/commands/populate_db.py
@@ -1,8 +1,16 @@
 from django.core.management.base import BaseCommand
 
+from commentaries.factories import VettedCommentaryFactory
+from comments.factories import CommentaryCommentFactory, SubmissionCommentFactory,\
+                               ThesislinkCommentFactory
+from scipost.factories import SubmissionRemarkFactory
+from journals.factories import JournalFactory, VolumeFactory, IssueFactory, PublicationFactory
 from news.factories import NewsItemFactory
+from submissions.factories import EICassignedSubmissionFactory
+from theses.factories import VettedThesisLinkFactory
 
-from ...factories import ContributorFactory, EditorialCollegeFactory, EditorialCollegeFellowshipFactory
+from ...factories import ContributorFactory, EditorialCollegeFactory,\
+                         EditorialCollegeFellowshipFactory
 
 
 class Command(BaseCommand):
@@ -14,19 +22,75 @@ class Command(BaseCommand):
             default=False,
             help='Add NewsItems',
         )
+        parser.add_argument(
+            '--commentaries',
+            action='store_true',
+            dest='commentaries',
+            default=False,
+            help='Add 5 Commentaries',
+        )
+        parser.add_argument(
+            '--comments',
+            action='store_true',
+            dest='comments',
+            default=False,
+            help='Add 10 Comments',
+        )
         parser.add_argument(
             '--contributor',
             action='store_true',
             dest='contributor',
             default=False,
-            help='Add Contributors',
+            help='Add 5 Contributors',
         )
         parser.add_argument(
             '--college',
             action='store_true',
             dest='editorial-college',
             default=False,
-            help='Add Editorial College and Fellows (Contributors required)',
+            help='Add 5 Editorial College and Fellows (Contributors required)',
+        )
+        parser.add_argument(
+            '--pubset',
+            action='store_true',
+            dest='pubset',
+            default=False,
+            help='Add 5 Issues, Volumes and Journals',
+        )
+        parser.add_argument(
+            '--issues',
+            action='store_true',
+            dest='issues',
+            default=False,
+            help='Add 5 Issues',
+        )
+        parser.add_argument(
+            '--submissions',
+            action='store_true',
+            dest='submissions',
+            default=False,
+            help='Add 5 new submissions status EIC assigned',
+        )
+        parser.add_argument(
+            '--publications',
+            action='store_true',
+            dest='publications',
+            default=False,
+            help='Add 5 Publications (includes --issues action)',
+        )
+        parser.add_argument(
+            '--remarks',
+            action='store_true',
+            dest='remarks',
+            default=False,
+            help='Add 5 new Remarks linked to Submissions',
+        )
+        parser.add_argument(
+            '--theses',
+            action='store_true',
+            dest='theses',
+            default=False,
+            help='Add 5 ThesisLinks',
         )
         parser.add_argument(
             '--all',
@@ -38,25 +102,81 @@ class Command(BaseCommand):
 
     def handle(self, *args, **kwargs):
         if kwargs['contributor'] or kwargs['all']:
-            self.create_contributors()
+            n = 5
+            if kwargs['all']:
+                n += 10
+            self.create_contributors(n)
+        if kwargs['commentaries'] or kwargs['all']:
+            self.create_commentaries()
+        if kwargs['comments'] or kwargs['all']:
+            self.create_comments()
         if kwargs['editorial-college'] or kwargs['all']:
             self.create_editorial_college()
             self.create_editorial_college_fellows()
         if kwargs['news'] or kwargs['all']:
             self.create_news_items()
+        if kwargs['submissions'] or kwargs['all']:
+            self.create_submissions()
+        if kwargs['pubset'] or kwargs['all']:
+            self.create_pubset()
+        if kwargs['issues'] or kwargs['all']:
+            self.create_issues()
+        if kwargs['publications'] or kwargs['all']:
+            self.create_publications()
+        if kwargs['remarks'] or kwargs['all']:
+            self.create_remarks()
+        if kwargs['theses'] or kwargs['all']:
+            self.create_theses()
+
+    def create_contributors(self, n=5):
+        ContributorFactory.create_batch(n)
+        self.stdout.write(self.style.SUCCESS('Successfully created %i Contributors.' % n))
 
-    def create_contributors(self):
-        ContributorFactory.create_batch(5)
-        self.stdout.write(self.style.SUCCESS('Successfully created Contributors.'))
+    def create_commentaries(self):
+        VettedCommentaryFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Commentaries.'))
+
+    def create_comments(self):
+        CommentaryCommentFactory.create_batch(3)
+        SubmissionCommentFactory.create_batch(4)
+        ThesislinkCommentFactory.create_batch(3)
+        self.stdout.write(self.style.SUCCESS('Successfully created 10 Comments.'))
 
     def create_editorial_college(self):
         EditorialCollegeFactory.create_batch(5)
-        self.stdout.write(self.style.SUCCESS('Successfully created Editorial College\'s.'))
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Editorial College\'s.'))
 
     def create_editorial_college_fellows(self):
         EditorialCollegeFellowshipFactory.create_batch(5)
-        self.stdout.write(self.style.SUCCESS('Successfully created Editorial College Fellows.'))
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Editorial College Fellows.'))
 
     def create_news_items(self):
         NewsItemFactory.create_batch(5)
-        self.stdout.write(self.style.SUCCESS('Successfully created News items.'))
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 News items.'))
+
+    def create_submissions(self):
+        EICassignedSubmissionFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Submissions.'))
+
+    def create_pubset(self):
+        VolumeFactory.create_batch(5)
+        IssueFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS(
+                          'Successfully created 5x {Journal, Volume and Issue}.'))
+
+    def create_issues(self):
+        IssueFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS(
+                          'Successfully created 5 Issue.'))
+
+    def create_publications(self):
+        PublicationFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Publications.'))
+
+    def create_remarks(self):
+        SubmissionRemarkFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 Remarks.'))
+
+    def create_theses(self):
+        VettedThesisLinkFactory.create_batch(5)
+        self.stdout.write(self.style.SUCCESS('Successfully created 5 ThesisLinks.'))
diff --git a/scipost/models.py b/scipost/models.py
index ecc4dcd821ed8ebb96a74b2c849839b69f28b95a..6cd9f4bca121d80600f13367d54f7edf41ec8118 100644
--- a/scipost/models.py
+++ b/scipost/models.py
@@ -344,7 +344,7 @@ class CitationNotification(models.Model):
     def __str__(self):
         text = str(self.contributor) + ', cited in '
         if self.cited_in_submission:
-            text += self.cited_in_submission.arxiv_nr_w_vn_nr
+            text += self.cited_in_submission.arxiv_identifier_w_vn_nr
         elif self.cited_in_publication:
             text += self.cited_in_publication.citation()
         if self.processed:
diff --git a/scipost/static/scipost/assets/css/_navbar.scss b/scipost/static/scipost/assets/css/_navbar.scss
index c9ca47fc15fc69689f38f779cc68b3a1ed8d1aa3..302993352ba812300a5f38972268bed0c3e2b81e 100644
--- a/scipost/static/scipost/assets/css/_navbar.scss
+++ b/scipost/static/scipost/assets/css/_navbar.scss
@@ -25,10 +25,6 @@
         flex-direction: row;
     }
 
-    // .navbar-collapse.show .nav-item {
-    //     margin-bottom: .25rem;
-    // }
-
     .active > .nav-link {
         border-color: $scipost-darkblue;
     }
@@ -54,7 +50,7 @@
     }
 
     .form-inline {
-        min-width: 250px;
+        min-width: 280px;
 
         .form-control {
             width: auto !important;
diff --git a/scipost/static/scipost/images/clockss_original_logo_boxed_ai-cropped-90.png b/scipost/static/scipost/images/clockss_original_logo_boxed_ai-cropped-90.png
new file mode 100644
index 0000000000000000000000000000000000000000..3f3ac1910793a41e225994f3cc02175c026d8ab5
Binary files /dev/null and b/scipost/static/scipost/images/clockss_original_logo_boxed_ai-cropped-90.png differ
diff --git a/scipost/templates/scipost/_draft_registration_tables.html b/scipost/templates/scipost/_draft_registration_tables.html
index 84b73ce78a71408b64b688fb5ffd2747760d9f26..d0909ac9068a93196bdaadb663b869ec96fdb0b9 100644
--- a/scipost/templates/scipost/_draft_registration_tables.html
+++ b/scipost/templates/scipost/_draft_registration_tables.html
@@ -46,7 +46,7 @@
                 </tr>
             </thead>
             <tbody>
-                {% for fellow in sent_reg_inv_contrib %}
+                {% for invitation in sent_reg_inv_contrib %}
                   <tr>
                     <td>{{ invitation.last_name }}</td>
                     <td>{{ invitation.first_name }}</td>
diff --git a/scipost/templates/scipost/registration_invitations.html b/scipost/templates/scipost/registration_invitations.html
index e3a2467cbc19fa56f5e97c654b084e41665d5bd3..1fee0baa3705ccf9843f59d33dfd7a5bb64ed33e 100644
--- a/scipost/templates/scipost/registration_invitations.html
+++ b/scipost/templates/scipost/registration_invitations.html
@@ -95,7 +95,7 @@ $(document).ready(function(){
                         <ul>
                         {% for ac in draft|associated_contributors %}
                             <li>
-                                <a href="{% url 'scipost:map_draft_reg_inv_to_contributor' draft_id=draft.id contributor_id=ac.id %}">Map to {{ ac.user.first_name }} {{ ac.user.last_name }}</a>>
+                                <a href="{% url 'scipost:map_draft_reg_inv_to_contributor' draft_id=draft.id contributor_id=ac.id %}">Map to {{ ac.user.first_name }} {{ ac.user.last_name }}</a>
                             </li>
                         {% empty %}
                             <li>No associated contributors found.</li>
diff --git a/submissions/constants.py b/submissions/constants.py
index d937973d28acfbcd1e85fce61eb2ba14c0c928de..ffb506708de9a0fddee0c601d6e2ca7f97007cf4 100644
--- a/submissions/constants.py
+++ b/submissions/constants.py
@@ -4,6 +4,11 @@ STATUS_REVISION_REQUESTED = 'revision_requested'
 STATUS_EIC_ASSIGNED = 'EICassigned'
 STATUS_AWAITING_ED_REC = 'awaiting_ed_rec'
 STATUS_REVIEW_CLOSED = 'review_closed'
+STATUS_ACCEPTED = 'accepted'
+STATUS_PUBLISHED = 'published'
+STATUS_RESUBMITTED = 'resubmitted'
+STATUS_RESUBMITTED_REJECTED = 'resubmitted_and_rejected'
+STATUS_RESUBMITTED_REJECTED_VISIBLE = 'resubmitted_and_rejected_visible'
 SUBMISSION_STATUS = (
     (STATUS_UNASSIGNED, 'Unassigned, undergoing pre-screening'),
     (STATUS_RESUBMISSION_INCOMING, 'Resubmission incoming'),
@@ -12,19 +17,19 @@ SUBMISSION_STATUS = (
     (STATUS_REVIEW_CLOSED, 'Review period closed, editorial recommendation pending'),
     # If revisions required: resubmission creates a new Submission object
     (STATUS_REVISION_REQUESTED, 'Editor-in-charge has requested revision'),
-    ('resubmitted', 'Has been resubmitted'),
-    ('resubmitted_and_rejected', 'Has been resubmitted and subsequently rejected'),
-    ('resubmitted_and_rejected_visible',
+    (STATUS_RESUBMITTED, 'Has been resubmitted'),
+    (STATUS_RESUBMITTED_REJECTED, 'Has been resubmitted and subsequently rejected'),
+    (STATUS_RESUBMITTED_REJECTED_VISIBLE,
      'Has been resubmitted and subsequently rejected (still publicly visible)'),
     # If acceptance/rejection:
     ('voting_in_preparation', 'Voting in preparation (eligible Fellows being selected)'),
     ('put_to_EC_voting', 'Undergoing voting at the Editorial College'),
     (STATUS_AWAITING_ED_REC, 'Awaiting Editorial Recommendation'),
     ('EC_vote_completed', 'Editorial College voting rounded up'),
-    ('accepted', 'Publication decision taken: accept'),
+    (STATUS_ACCEPTED, 'Publication decision taken: accept'),
     ('rejected', 'Publication decision taken: reject'),
     ('rejected_visible', 'Publication decision taken: reject (still publicly visible)'),
-    ('published', 'Published'),
+    (STATUS_PUBLISHED, 'Published'),
     # If withdrawn:
     ('withdrawn', 'Withdrawn by the Authors'),
 )
diff --git a/submissions/exceptions.py b/submissions/exceptions.py
new file mode 100644
index 0000000000000000000000000000000000000000..19c5684bd004f175ffe4169cc2938d312d66edf0
--- /dev/null
+++ b/submissions/exceptions.py
@@ -0,0 +1,6 @@
+class CycleUpdateDeadlineError(Exception):
+    def __init__(self, name):
+        self.name = name
+
+    def __str__(self):
+        return self.name
diff --git a/submissions/factories.py b/submissions/factories.py
index d67299983ce9f4c0221e1dc9d05018289950e8b2..6c602275452772293c4f8303caf37c5baf63152a 100644
--- a/submissions/factories.py
+++ b/submissions/factories.py
@@ -1,37 +1,144 @@
 import factory
+import pytz
 
-from scipost.factories import ContributorFactory
-from journals.constants import SCIPOST_JOURNAL_PHYSICS
-from common.helpers import random_arxiv_identifier_with_version_number
+from django.utils import timezone
 
-from .constants import STATUS_UNASSIGNED, STATUS_EIC_ASSIGNED, STATUS_RESUBMISSION_INCOMING
+from scipost.constants import SCIPOST_SUBJECT_AREAS
+from scipost.models import Contributor
+from journals.constants import SCIPOST_JOURNALS_DOMAINS
+from common.helpers import random_arxiv_identifier_without_version_number, random_scipost_journal
+
+from .constants import STATUS_UNASSIGNED, STATUS_EIC_ASSIGNED, STATUS_RESUBMISSION_INCOMING,\
+                       STATUS_PUBLISHED, SUBMISSION_TYPE, STATUS_RESUBMITTED
 from .models import Submission
 
+from faker import Faker
+
 
 class SubmissionFactory(factory.django.DjangoModelFactory):
     class Meta:
         model = Submission
 
     author_list = factory.Faker('name')
-    submitted_by = factory.SubFactory(ContributorFactory)
-    submitted_to_journal = SCIPOST_JOURNAL_PHYSICS
-    title = factory.Faker('bs')
-    abstract = factory.Faker('text')
+    submitted_by = factory.Iterator(Contributor.objects.all())
+    submitted_to_journal = factory.Sequence(lambda n: random_scipost_journal())
+    title = factory.lazy_attribute(lambda x: Faker().sentence())
+    abstract = factory.lazy_attribute(lambda x: Faker().paragraph())
     arxiv_link = factory.Faker('uri')
-    arxiv_identifier_w_vn_nr = factory.Sequence(lambda n: random_arxiv_identifier_with_version_number())
-    domain = 'E'
+    arxiv_identifier_wo_vn_nr = factory.Sequence(
+                                    lambda n: random_arxiv_identifier_without_version_number())
+    subject_area = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: c[0])
+    domain = factory.Iterator(SCIPOST_JOURNALS_DOMAINS, getter=lambda c: c[0])
+    abstract = Faker().paragraph()
+    author_comments = Faker().paragraph()
+    remarks_for_editors = Faker().paragraph()
+    submission_type = factory.Iterator(SUBMISSION_TYPE, getter=lambda c: c[0])
+    is_current = True
+
+    @factory.post_generation
+    def fill_arxiv_fields(self, create, extracted, **kwargs):
+        '''Fill empty arxiv fields.'''
+        self.arxiv_link = 'https://arxiv.org/abs/%s' % self.arxiv_identifier_wo_vn_nr
+        self.arxiv_identifier_w_vn_nr = '%sv1' % self.arxiv_identifier_wo_vn_nr
+        self.arxiv_vn_nr = kwargs.get('arxiv_vn_nr', 1)
+
+    @factory.post_generation
+    def contributors(self, create, extracted, **kwargs):
+        contributors = list(Contributor.objects.order_by('?')[:4])
+
+        # Auto-add the submitter as an author
+        self.submitted_by = contributors.pop()
+
+        if not create:
+            return
+        self.authors.add(self.submitted_by)
+
+        # Add three random authors
+        for contrib in contributors:
+            self.authors.add(contrib)
+            self.author_list += ', %s %s' % (contrib.user.first_name, contrib.user.last_name)
+
+    @factory.post_generation
+    def dates(self, create, extracted, **kwargs):
+        timezone.now()
+        if kwargs.get('submission', False):
+            self.submission_date = kwargs['submission']
+            self.cycle.update_deadline()
+            return
+        self.submission_date = Faker().date_time_between(start_date="-3y", end_date="now",
+                                                         tzinfo=pytz.UTC).date()
+        self.latest_activity = Faker().date_time_between(start_date=self.submission_date,
+                                                         end_date="now", tzinfo=pytz.UTC)
+        self.cycle.update_deadline()
+
+
+class UnassignedSubmissionFactory(SubmissionFactory):
+    '''This Submission is a 'new request' by a Contributor for its Submission.'''
+    status = STATUS_UNASSIGNED
 
 
 class EICassignedSubmissionFactory(SubmissionFactory):
     status = STATUS_EIC_ASSIGNED
-    editor_in_charge = factory.SubFactory(ContributorFactory)
     open_for_commenting = True
+    open_for_reporting = True
 
+    @factory.post_generation
+    def eic(self, create, extracted, **kwargs):
+        '''Assign an EIC to submission.'''
+        author_ids = list(self.authors.values_list('id', flat=True))
+        self.editor_in_charge = (Contributor.objects.order_by('?')
+                                            .exclude(pk=self.submitted_by.pk)
+                                            .exclude(pk__in=author_ids).first())
 
-class UnassignedSubmissionFactory(SubmissionFactory):
-    status = STATUS_UNASSIGNED
 
+class ResubmittedSubmissionFactory(SubmissionFactory):
+    '''This Submission is a `resubmitted` version.'''
+    status = STATUS_RESUBMITTED
+    open_for_commenting = False
+    open_for_reporting = False
+    is_current = False
+    is_resubmission = False
 
-class ResubmittedScreeningSubmissionFactory(SubmissionFactory):
+
+class ResubmissionFactory(SubmissionFactory):
+    """
+    This Submission is a newer version of a Submission which is
+    already known by the SciPost database.
+    """
     status = STATUS_RESUBMISSION_INCOMING
-    editor_in_charge = factory.SubFactory(ContributorFactory)
+    open_for_commenting = True
+    open_for_reporting = True
+    is_resubmission = True
+
+    @factory.post_generation
+    def fill_arxiv_fields(self, create, extracted, **kwargs):
+        '''Fill empty arxiv fields.'''
+        self.arxiv_link = 'https://arxiv.org/abs/%s' % self.arxiv_identifier_wo_vn_nr
+        self.arxiv_identifier_w_vn_nr = '%sv2' % self.arxiv_identifier_wo_vn_nr
+        self.arxiv_vn_nr = 2
+
+    @factory.post_generation
+    def eic(self, create, extracted, **kwargs):
+        '''Assign an EIC to submission.'''
+        author_ids = list(self.authors.values_list('id', flat=True))
+        self.editor_in_charge = (Contributor.objects.order_by('?')
+                                            .exclude(pk=self.submitted_by.pk)
+                                            .exclude(pk__in=author_ids).first())
+
+    @factory.post_generation
+    def dates(self, create, extracted, **kwargs):
+        """Overwrite the parent `dates` method to skip the update_deadline call."""
+        timezone.now()
+        if kwargs.get('submission', False):
+            self.submission_date = kwargs['submission']
+            return
+        self.submission_date = Faker().date_time_between(start_date="-3y", end_date="now",
+                                                         tzinfo=pytz.UTC).date()
+        self.latest_activity = Faker().date_time_between(start_date=self.submission_date,
+                                                         end_date="now", tzinfo=pytz.UTC)
+
+
+class PublishedSubmissionFactory(SubmissionFactory):
+    status = STATUS_PUBLISHED
+    open_for_commenting = False
+    open_for_reporting = False
diff --git a/submissions/forms.py b/submissions/forms.py
index 73f7f6fe50718aec0e89944e9908b6edfbb26385..70b2b792e8f3465889566fbb4e4ac600b6b59254 100644
--- a/submissions/forms.py
+++ b/submissions/forms.py
@@ -2,7 +2,7 @@ from django import forms
 from django.core.validators import RegexValidator
 
 from .constants import ASSIGNMENT_BOOL, ASSIGNMENT_REFUSAL_REASONS,\
-                       REPORT_ACTION_CHOICES, REPORT_REFUSAL_CHOICES, SUBMISSION_CYCLES
+                       REPORT_ACTION_CHOICES, REPORT_REFUSAL_CHOICES
 from .models import Submission, RefereeInvitation, Report, EICRecommendation
 
 from scipost.constants import SCIPOST_SUBJECT_AREAS
@@ -14,8 +14,19 @@ from crispy_forms.layout import Layout, Div, Field, HTML, Submit
 
 class SubmissionSearchForm(forms.Form):
     author = forms.CharField(max_length=100, required=False, label="Author(s)")
-    title_keyword = forms.CharField(max_length=100, label="Title", required=False)
-    abstract_keyword = forms.CharField(max_length=1000, required=False, label="Abstract")
+    title = forms.CharField(max_length=100, required=False)
+    abstract = forms.CharField(max_length=1000, required=False)
+    subject_area = forms.CharField(max_length=10, required=False, widget=forms.Select(
+                                   choices=((None, 'Show all'),) + SCIPOST_SUBJECT_AREAS[0][1]))
+
+    def search_results(self):
+        """Return all Submission objects according to search"""
+        return Submission.objects.public_overcomplete().filter(
+            title__icontains=self.cleaned_data.get('title', ''),
+            author_list__icontains=self.cleaned_data.get('author', ''),
+            abstract__icontains=self.cleaned_data.get('abstract', ''),
+            subject_area__icontains=self.cleaned_data.get('subject_area', '')
+        )
 
 
 ###############################
@@ -77,6 +88,30 @@ class SubmissionForm(forms.ModelForm):
             'placeholder': 'Optional: names of referees whose reports should be treated with caution (+ short reason)',
             'rows': 3})
 
+    def check_user_may_submit(self, current_user):
+        """
+        Important check!
+
+        The submitting user must be an author of the submission.
+        Also possibly may be extended to check permissions and give ultimate submission
+        power to certain user groups.
+        """
+        return current_user.last_name.lower() in self.cleaned_data['author_list'].lower()
+
+    def update_submission_data(self):
+        """
+        Some fields should not be accessible in the HTML form by the user and should be
+        inserted by for example an extra call to Arxiv into the Submission instance, right
+        *after* the form is submitted.
+
+        Example fields:
+        - is_resubmission
+        - arxiv_link
+        - arxiv_identifier_w_vn_nr
+        - metadata (!)
+        """
+        raise NotImplementedError
+
 
 ######################
 # Editorial workflow #
@@ -134,8 +169,7 @@ class ConsiderRefereeInvitationForm(forms.Form):
 
 
 class SetRefereeingDeadlineForm(forms.Form):
-    deadline = forms.DateField(required=False, label='',
-                               widget=forms.SelectDateWidget)
+    deadline = forms.DateField(required=False, label='', widget=forms.SelectDateWidget)
 
 
 class VotingEligibilityForm(forms.Form):
diff --git a/submissions/managers.py b/submissions/managers.py
index ddff884029fae485b0589446aa9b947d341ee5cc..f1ce5d8a9ec241367cdfa27d31e7624bbea4c4ac 100644
--- a/submissions/managers.py
+++ b/submissions/managers.py
@@ -8,6 +8,22 @@ from .constants import SUBMISSION_STATUS_OUT_OF_POOL, SUBMISSION_STATUS_PUBLICLY
 
 
 class SubmissionManager(models.Manager):
+    def _newest_version_only(self, queryset):
+        """
+        The current Queryset should return only the latest version
+        of the Arxiv submissions known to SciPost.
+
+        Method only compatible with PostGresQL
+        """
+        # This method used a double query, which is a consequence of the complex distinct()
+        # filter combined with the PostGresQL engine. Without the double query, ordering
+        # on a specific field after filtering would be impossible.
+        ids = (queryset
+               .order_by('arxiv_identifier_wo_vn_nr', '-arxiv_vn_nr')
+               .distinct('arxiv_identifier_wo_vn_nr')
+               .values_list('id', flat=True))
+        return queryset.filter(id__in=ids)
+
     def user_filter(self, user):
         """
         Prevent conflic of interest by filtering submissions possible related to user.
@@ -54,7 +70,8 @@ class SubmissionManager(models.Manager):
         This query contains an overcomplete set of public submissions, i.e. also containing
         submissions with status "published" or "resubmitted".
         """
-        return self.exclude(status__in=SUBMISSION_STATUS_PUBLICLY_INVISIBLE)
+        queryset = self.exclude(status__in=SUBMISSION_STATUS_PUBLICLY_INVISIBLE)
+        return self._newest_version_only(queryset)
 
 
 class EditorialAssignmentManager(models.Manager):
diff --git a/submissions/migrations/0042_auto_20170511_2321.py b/submissions/migrations/0042_auto_20170511_2321.py
new file mode 100644
index 0000000000000000000000000000000000000000..20b3a653e5fc906c41d3159a46c85278dba8b182
--- /dev/null
+++ b/submissions/migrations/0042_auto_20170511_2321.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-05-11 21:21
+from __future__ import unicode_literals
+
+import datetime
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0041_auto_20170418_1022'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='submission',
+            name='submission_date',
+            field=models.DateField(default=datetime.date.today, verbose_name='submission date'),
+        ),
+    ]
diff --git a/submissions/migrations/0043_auto_20170512_0836.py b/submissions/migrations/0043_auto_20170512_0836.py
new file mode 100644
index 0000000000000000000000000000000000000000..badd52ad60321186d16f52a6cb4ba9922e5cbb20
--- /dev/null
+++ b/submissions/migrations/0043_auto_20170512_0836.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10.3 on 2017-05-12 06:36
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('submissions', '0042_auto_20170511_2321'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='submission',
+            name='latest_activity',
+            field=models.DateTimeField(auto_now=True),
+        ),
+    ]
diff --git a/submissions/models.py b/submissions/models.py
index 0a2b82f9ae8f5dfb2a42b6a9df8c0a3978d772e3..c2364962e70eeff53d55c6d22691d6e965131bb1 100644
--- a/submissions/models.py
+++ b/submissions/models.py
@@ -78,8 +78,8 @@ class Submission(ArxivCallable, models.Model):
 
     # Metadata
     metadata = JSONField(default={}, blank=True, null=True)
-    submission_date = models.DateField(verbose_name='submission date', default=timezone.now)
-    latest_activity = models.DateTimeField(default=timezone.now)
+    submission_date = models.DateField(verbose_name='submission date', default=datetime.date.today)
+    latest_activity = models.DateTimeField(auto_now=True)
 
     objects = SubmissionManager()
 
diff --git a/submissions/templates/submissions/_submission_refereeing_invitations.html b/submissions/templates/submissions/_submission_refereeing_invitations.html
index b53073395f26521028611dcf2c7dd6495e83e7da..8af3a7a1081f5007ba03fcb6be4d6a32a8322caf 100644
--- a/submissions/templates/submissions/_submission_refereeing_invitations.html
+++ b/submissions/templates/submissions/_submission_refereeing_invitations.html
@@ -20,7 +20,7 @@
                     {% endif %}
                     <div>{{invitation.date_responded}}</div>
                 {% else %}
-                    reponse pending
+                    response pending
                 {% endif %}
             </td>
 
diff --git a/submissions/templates/submissions/new_submission.html b/submissions/templates/submissions/new_submission.html
index ba80d4cb1826f76836ba35354c8836d075c9e9dd..e0dbc27ad7279b3d3b2ead3ff73a8489c311fc5e 100644
--- a/submissions/templates/submissions/new_submission.html
+++ b/submissions/templates/submissions/new_submission.html
@@ -55,7 +55,7 @@ $(document).ready(function(){
     <div class="col-12">
         {% if perms.scipost.can_submit_manuscript %}
 
-            {% if form.arxiv_link.value %}
+            {% if form.arxiv_link %}
                 <form id="full_submission_form" action="{% url 'submissions:submit_manuscript' %}" method="post">
                     {% csrf_token %}
                     {{form|bootstrap}}
diff --git a/submissions/templates/submissions/submissions.html b/submissions/templates/submissions/submissions.html
index 3ad37262ba81ad38ee39bdaf773600a6aab58fc4..380ca755ab0b7e6abc482de47cdcd41c2ba268f0 100644
--- a/submissions/templates/submissions/submissions.html
+++ b/submissions/templates/submissions/submissions.html
@@ -23,7 +23,7 @@
               <h2 class="card-title">Search SciPost Submissions:</h2>
               <form action="{% url 'submissions:submissions' %}" class="small" method="get">
                 {{ form|bootstrap:'4,8,sm' }}
-                <input class="btn btn-sm btn-secondary" type="submit" name="Submit" />
+                <input class="btn btn-sm btn-secondary" type="submit" value="Search"/>
               </form>
             </div>
         </div>
diff --git a/submissions/test_utils.py b/submissions/test_utils.py
new file mode 100644
index 0000000000000000000000000000000000000000..d070e6c8a4cf5ef81706d3b83344987f311425b0
--- /dev/null
+++ b/submissions/test_utils.py
@@ -0,0 +1,137 @@
+import datetime
+
+from django.test import TestCase, tag
+
+from common.helpers.test import add_groups_and_permissions
+from scipost.factories import ContributorFactory
+from scipost.models import Contributor
+
+from .constants import STATUS_UNASSIGNED, STATUS_RESUBMISSION_INCOMING, STATUS_AWAITING_ED_REC,\
+                       STATUS_EIC_ASSIGNED, CYCLE_DEFAULT, CYCLE_DIRECT_REC
+from .exceptions import CycleUpdateDeadlineError
+from .factories import UnassignedSubmissionFactory, ResubmissionFactory
+from .utils import GeneralSubmissionCycle
+
+
+class TestDefaultSubmissionCycle(TestCase):
+    '''
+    This TestCase should act as a master test to check all steps in the
+    submission's cycle: default.
+    '''
+
+    def setUp(self):
+        """Basics for all tests"""
+        self.submission_date = datetime.date.today()
+        add_groups_and_permissions()
+        ContributorFactory.create_batch(5)
+        self.new_submission = UnassignedSubmissionFactory(
+            dates__submission=self.submission_date
+        )
+
+    @tag('cycle', 'core')
+    def test_init_submission_factory_is_valid(self):
+        """Ensure valid fields for the factory."""
+        self.assertEqual(self.new_submission.status, STATUS_UNASSIGNED)
+        self.assertIsNone(self.new_submission.editor_in_charge)
+        self.assertTrue(self.new_submission.is_current)
+        self.assertFalse(self.new_submission.is_resubmission)
+        self.assertIsNot(self.new_submission.title, '')
+        self.assertIsInstance(self.new_submission.submitted_by, Contributor)
+        self.assertFalse(self.new_submission.open_for_commenting)
+        self.assertFalse(self.new_submission.open_for_reporting)
+        self.assertEqual(self.new_submission.submission_date, self.submission_date)
+
+    @tag('cycle', 'core')
+    def test_initial_cycle_required_actions_and_deadline(self):
+        """Test valid required actions for default cycle."""
+        self.assertIsInstance(self.new_submission.cycle, GeneralSubmissionCycle)
+
+        # Explicit: No actions required if no EIC is assigned yet
+        self.assertFalse(self.new_submission.cycle.get_required_actions())
+
+        # Two weeks deadline check
+        self.new_submission.cycle.update_deadline()
+        real_report_deadline = self.submission_date + datetime.timedelta(days=28)
+        self.assertEqual(self.new_submission.reporting_deadline.day, real_report_deadline.day)
+        self.assertEqual(self.new_submission.reporting_deadline.month, real_report_deadline.month)
+        self.assertEqual(self.new_submission.reporting_deadline.year, real_report_deadline.year)
+        self.assertIsInstance(self.new_submission.reporting_deadline, datetime.datetime)
+
+
+class TestResubmissionSubmissionCycle(TestCase):
+    '''
+    This TestCase should act as a master test to check all steps in the
+    submission's cycle: resubmission.
+    '''
+
+    def setUp(self):
+        """Basics for all tests"""
+        self.submission_date = datetime.date.today()
+        add_groups_and_permissions()
+        ContributorFactory.create_batch(5)
+        self.submission = ResubmissionFactory(
+            dates__submission=self.submission_date
+        )
+
+    @tag('cycle', 'core')
+    def test_init_resubmission_factory_is_valid(self):
+        """Ensure valid fields for the factory."""
+        self.assertEqual(self.submission.status, STATUS_RESUBMISSION_INCOMING)
+        self.assertIsInstance(self.submission.editor_in_charge, Contributor)
+        self.assertTrue(self.submission.is_current)
+        self.assertTrue(self.submission.is_resubmission)
+        self.assertIsNot(self.submission.title, '')
+        self.assertIsInstance(self.submission.submitted_by, Contributor)
+        self.assertTrue(self.submission.open_for_commenting)
+        self.assertTrue(self.submission.open_for_reporting)
+        self.assertEqual(self.submission.submission_date, self.submission_date)
+        self.assertEqual(self.submission.refereeing_cycle, CYCLE_DEFAULT)
+
+    @tag('cycle', 'core')
+    def test_initial_cycle_required_actions_and_deadline(self):
+        """Test valid required actions for default cycle."""
+        self.assertRaises(CycleUpdateDeadlineError, self.submission.cycle.update_deadline)
+
+        # Update status for default cycle to check new status
+        self.submission.cycle.update_status()
+        self.assertEqual(self.submission.status, STATUS_EIC_ASSIGNED)
+
+
+class TestResubmissionDirectSubmissionCycle(TestCase):
+    '''
+    This TestCase should act as a master test to check all steps in the
+    submission's cycle: resubmission (cycle: DIRECT_RECOMMENDATION).
+    '''
+
+    def setUp(self):
+        """Basics for all tests"""
+        self.submission_date = datetime.date.today()
+        add_groups_and_permissions()
+        ContributorFactory.create_batch(5)
+        self.submission = ResubmissionFactory(
+            dates__submission=self.submission_date,
+            refereeing_cycle=CYCLE_DIRECT_REC
+        )
+
+    @tag('cycle', 'core')
+    def test_init_resubmission_factory_is_valid(self):
+        """Ensure valid fields for the factory."""
+        self.assertEqual(self.submission.status, STATUS_RESUBMISSION_INCOMING)
+        self.assertIsInstance(self.submission.editor_in_charge, Contributor)
+        self.assertTrue(self.submission.is_current)
+        self.assertTrue(self.submission.is_resubmission)
+        self.assertIsNot(self.submission.title, '')
+        self.assertIsInstance(self.submission.submitted_by, Contributor)
+        self.assertTrue(self.submission.open_for_commenting)
+        self.assertTrue(self.submission.open_for_reporting)
+        self.assertEqual(self.submission.submission_date, self.submission_date)
+        self.assertEqual(self.submission.refereeing_cycle, CYCLE_DIRECT_REC)
+
+    @tag('cycle', 'core')
+    def test_initial_cycle_required_actions_and_deadline(self):
+        """Test valid required actions for default cycle."""
+        self.assertRaises(CycleUpdateDeadlineError, self.submission.cycle.update_deadline)
+
+        # Update status for default cycle to check new status
+        self.submission.cycle.update_status()
+        self.assertEqual(self.submission.status, STATUS_AWAITING_ED_REC)
diff --git a/submissions/test_views.py b/submissions/test_views.py
index 8b797db80ccb9ddac353a6174482359509d428c3..11e9c210a19bd604c2791a96a4359d6f1c7672b4 100644
--- a/submissions/test_views.py
+++ b/submissions/test_views.py
@@ -1,59 +1,202 @@
+import json
+
+from django.core.urlresolvers import reverse
 from django.test import TestCase
 from django.test import Client
-from submissions.views import *
-import django.core.urlresolvers
 
-from .factories import EICassignedSubmissionFactory
+from common.helpers import random_arxiv_identifier_without_version_number
+from common.helpers.test import add_groups_and_permissions
+from scipost.factories import ContributorFactory
+# from scipost.models import Contributor
+
+from .constants import STATUS_UNASSIGNED
+from .factories import UnassignedSubmissionFactory, EICassignedSubmissionFactory,\
+                       ResubmittedSubmissionFactory, ResubmissionFactory,\
+                       PublishedSubmissionFactory
+from .forms import SubmissionForm, SubmissionIdentifierForm
+from .models import Submission
+
+# This is content of a real arxiv submission. As long as it isn't published it should
+# be possible to run tests using this submission.
+TEST_SUBMISSION = {
+    'is_resubmission': False,
+    'title': ('General solution of 2D and 3D superconducting quasiclassical'
+              ' systems:\n  coalescing vortices and nanodisk geometries'),
+    'author_list': 'Morten Amundsen, Jacob Linder',
+    'arxiv_identifier_w_vn_nr': '1512.00030v1',
+    'arxiv_identifier_wo_vn_nr': '1512.00030',
+    'arxiv_vn_nr': 1,
+    'arxiv_link': 'http://arxiv.org/abs/1512.00030v1',
+    'abstract': ('In quasiclassical Keldysh theory, the Green function matrix $\\check{g}$'
+                 ' is\nused to compute a variety of physical quantities in mesoscopic syst'
+                 'ems.\nHowever, solving the set of non-linear differential equations that'
+                 ' provide\n$\\check{g}$ becomes a challenging task when going to higher s'
+                 'patial dimensions\nthan one. Such an extension is crucial in order to de'
+                 'scribe physical phenomena\nlike charge/spin Hall effects and topological'
+                 ' excitations like vortices and\nskyrmions, none of which can be captured'
+                 ' in one-dimensional models. We here\npresent a numerical finite element '
+                 'method which solves the 2D and 3D\nquasiclassical Usadel equation, witho'
+                 'ut any linearisation, relevant for the\ndiffusive regime. We show the ap'
+                 'plication of this on two model systems with\nnon-trivial geometries: (i)'
+                 ' a bottlenecked Josephson junction with external\nflux and (ii) a nanodi'
+                 'sk ferromagnet deposited on top of a superconductor. We\ndemonstrate tha'
+                 't it is possible to control externally not only the geometrical\narray i'
+                 'n which superconducting vortices arrange themselves, but also to cause\n'
+                 'coalescence and thus tune the number of vortices. The finite element met'
+                 'hod\npresented herein could pave the way for gaining insight in physical'
+                 ' phenomena\nwhich so far have remained largely unexplored due to the com'
+                 'plexity of solving\nthe full quasiclassical equations in higher dimensio'
+                 'ns.')
+}
+
+
+class BaseContributorTestCase(TestCase):
+    def setUp(self):
+        add_groups_and_permissions()
+        ContributorFactory.create_batch(5)
+        ContributorFactory.create(
+            user__last_name='Linder',  # To pass the author check in create submissions view
+            user__username='Test',
+            user__password='testpw'
+        )
 
 
-class PrefillUsingIdentifierTest(TestCase):
-    fixtures = ['permissions', 'groups', 'contributors']
+class PrefillUsingIdentifierTest(BaseContributorTestCase):
+    def setUp(self):
+        super().setUp()
+        self.client = Client()
+        self.url = reverse('submissions:prefill_using_identifier')
+        self.assertTrue(self.client.login(username="Test", password="testpw"))
 
-    def test_retrieving_existing_arxiv_paper(self):
+    def test_basic_responses(self):
+        # Test anonymous client is rejected
         client = Client()
-        client.login(username="Test", password="testpw")
-
-        response = client.post(reverse('submissions:prefill_using_identifier'),
-                               {'identifier': '1512.00030v1'})
+        response = client.get(self.url)
+        self.assertEqual(response.status_code, 403)
+        response = client.post(self.url,
+                               {'identifier': TEST_SUBMISSION['arxiv_identifier_w_vn_nr']})
+        self.assertEqual(response.status_code, 403)
+
+        # Registered Contributor should get 200
+        response = self.client.get(self.url)
+        self.assertEqual(response.status_code, 200)
 
+    def test_retrieving_existing_arxiv_paper(self):
+        '''Test view with a valid post request.'''
+        response = self.client.post(self.url,
+                                    {'identifier':
+                                        TEST_SUBMISSION['arxiv_identifier_w_vn_nr']})
         self.assertEqual(response.status_code, 200)
+        self.assertIsInstance(response.context['form'], SubmissionForm)
+        self.assertIsInstance(response.context['identifierform'], SubmissionIdentifierForm)
+        self.assertTrue(response.context['identifierform'].is_valid())
+
+        # Explicitly compare fields instead of assertDictEqual as metadata field may be outdated
+        self.assertEqual(TEST_SUBMISSION['is_resubmission'],
+                         response.context['form'].initial['is_resubmission'])
+        self.assertEqual(TEST_SUBMISSION['title'], response.context['form'].initial['title'])
+        self.assertEqual(TEST_SUBMISSION['author_list'],
+                         response.context['form'].initial['author_list'])
+        self.assertEqual(TEST_SUBMISSION['arxiv_identifier_w_vn_nr'],
+                         response.context['form'].initial['arxiv_identifier_w_vn_nr'])
+        self.assertEqual(TEST_SUBMISSION['arxiv_identifier_wo_vn_nr'],
+                         response.context['form'].initial['arxiv_identifier_wo_vn_nr'])
+        self.assertEqual(TEST_SUBMISSION['arxiv_vn_nr'],
+                         response.context['form'].initial['arxiv_vn_nr'])
+        self.assertEqual(TEST_SUBMISSION['arxiv_link'],
+                         response.context['form'].initial['arxiv_link'])
+        self.assertEqual(TEST_SUBMISSION['abstract'],
+                         response.context['form'].initial['abstract'])
 
     def test_still_200_ok_if_identifier_is_wrong(self):
-        client = Client()
-        client.login(username="Test", password="testpw")
-
-        response = client.post(reverse('submissions:prefill_using_identifier'),
-                               {'identifier': '1512.00030'})
-
+        response = self.client.post(self.url, {'identifier': '1512.00030'})
         self.assertEqual(response.status_code, 200)
 
 
-class SubmitManuscriptTest(TestCase):
-    fixtures = ['permissions', 'groups', 'contributors']
-
+class SubmitManuscriptTest(BaseContributorTestCase):
     def test_submit_correct_manuscript(self):
+        '''Check is view POST request works as expected.'''
         client = Client()
-        client.login(username="Test", password="testpw")
 
+        # Unauthorized request shouldn't be possible
         response = client.post(reverse('submissions:prefill_using_identifier'),
-                               {'identifier': '1512.00030v1'})
-
-        params = response.context['form'].initial
-
-        extras = {'discipline': 'physics',
-                  'submitted_to_journal': 'SciPost Physics',
-                  'submission_type': 'Article',
-                  'domain': 'T'}
-        response = client.post(reverse('submissions:submit_manuscript'),
-                               {**params, **extras})
+                               {'identifier': TEST_SUBMISSION['arxiv_identifier_w_vn_nr']})
+        self.assertEquals(response.status_code, 403)
 
+        # Registered Contributor should get 200; assuming prefiller is working properly
+        self.assertTrue(client.login(username="Test", password="testpw"))
+        response = client.post(reverse('submissions:prefill_using_identifier'),
+                               {'identifier': TEST_SUBMISSION['arxiv_identifier_w_vn_nr']})
         self.assertEqual(response.status_code, 200)
 
+        # Fill form parameters
+        params = response.context['form'].initial
+        params.update({
+            'discipline': 'physics',
+            'subject_area': 'Phys:MP',
+            'submitted_to_journal': 'SciPostPhys',
+            'submission_type': 'Article',
+            'domain': 'T'
+        })
+        params['metadata'] = json.dumps(params['metadata'], separators=(',', ':'))
+
+        # Submit new Submission form
+        response = client.post(reverse('submissions:submit_manuscript'), params)
+        self.assertEqual(response.status_code, 302)
+
+        # Do a quick check on the Submission submitted.
+        submission = Submission.objects.filter(status=STATUS_UNASSIGNED).last()
+        self.assertIsNotNone(submission)
+        self.assertEqual(TEST_SUBMISSION['is_resubmission'], submission.is_resubmission)
+        self.assertEqual(TEST_SUBMISSION['title'], submission.title)
+        self.assertEqual(TEST_SUBMISSION['author_list'], submission.author_list)
+        self.assertEqual(TEST_SUBMISSION['arxiv_identifier_w_vn_nr'],
+                         submission.arxiv_identifier_w_vn_nr)
+        self.assertEqual(TEST_SUBMISSION['arxiv_identifier_wo_vn_nr'],
+                         submission.arxiv_identifier_wo_vn_nr)
+        self.assertEqual(TEST_SUBMISSION['arxiv_vn_nr'], submission.arxiv_vn_nr)
+        self.assertEqual(TEST_SUBMISSION['arxiv_link'], submission.arxiv_link)
+        self.assertEqual(TEST_SUBMISSION['abstract'], submission.abstract)
+
+    def test_non_author_tries_submission(self):
+        '''See what happens if a non-author of an Arxiv submission submits to SciPost.'''
+        client = Client()
 
-class SubmissionDetailTest(TestCase):
-    fixtures = ['permissions', 'groups']
+        # Contributor Linder tries to submit the Quench Action.
+        # Eventually this call should already give an error. Waiting for
+        # Arxiv caller which is under construction [Jorran de Wit, 12 May 2017]
+        self.assertTrue(client.login(username="Test", password="testpw"))
+        response = client.post(reverse('submissions:prefill_using_identifier'),
+                               {'identifier': '1603.04689v1'})
+        self.assertEqual(response.status_code, 200)
 
+        # Fill form parameters
+        params = response.context['form'].initial
+        params.update({
+            'discipline': 'physics',
+            'subject_area': 'Phys:MP',
+            'submitted_to_journal': 'SciPostPhys',
+            'submission_type': 'Article',
+            'domain': 'T'
+        })
+        params['metadata'] = json.dumps(params['metadata'], separators=(',', ':'))
+
+        # Submit new Submission form
+        response = client.post(reverse('submissions:submit_manuscript'), params)
+        self.assertEqual(response.status_code, 302)
+
+        # No real check is done here to see if submission submit is aborted.
+        # To be implemented after Arxiv caller.
+        # Temporary fix:
+        last_submission = Submission.objects.last()
+        if last_submission:
+            self.assertNotEqual(last_submission.title, 'The Quench Action')
+            self.assertNotEqual(last_submission.arxiv_identifier_w_vn_nr, '1603.04689v1')
+
+
+class SubmissionDetailTest(BaseContributorTestCase):
     def setUp(self):
+        super().setUp()
         self.client = Client()
         self.submission = EICassignedSubmissionFactory()
         self.target = reverse(
@@ -64,3 +207,42 @@ class SubmissionDetailTest(TestCase):
     def test_status_code_200(self):
         response = self.client.get(self.target)
         self.assertEqual(response.status_code, 200)
+
+
+class SubmissionListTest(BaseContributorTestCase):
+    def test_public_list_view(self):
+        # Create invisible Submissions.
+        arxiv_id_resubmission = random_arxiv_identifier_without_version_number()
+        UnassignedSubmissionFactory.create()
+        ResubmissionFactory.create(arxiv_identifier_wo_vn_nr=arxiv_id_resubmission)
+
+        # Create visible submissions
+        visible_submission_ids = []
+        visible_submission_ids.append(ResubmittedSubmissionFactory
+                                      .create(arxiv_identifier_wo_vn_nr=arxiv_id_resubmission).id)
+        visible_submission_ids.append(EICassignedSubmissionFactory.create().id)
+        visible_submission_ids.append(PublishedSubmissionFactory.create().id)
+
+        # Extra submission with multiple versions where the newest is publicly visible
+        # again. Earlier versions should therefore be invisible!
+        arxiv_id_resubmission = random_arxiv_identifier_without_version_number()
+        ResubmittedSubmissionFactory.create(arxiv_identifier_wo_vn_nr=arxiv_id_resubmission)
+        visible_submission_ids.append(
+            EICassignedSubmissionFactory.create(
+                arxiv_identifier_wo_vn_nr=arxiv_id_resubmission,
+                fill_arxiv_fields__arxiv_vn_nr=2
+            ).id
+        )
+
+        # Check with hardcoded URL as this url shouldn't change!
+        client = Client()
+        response = client.get('/submissions/')
+        self.assertEqual(response.status_code, 200)
+
+        # Check submissions returned
+        returned_submissions_ids = [sub.id for sub in response.context['object_list']]
+
+        # Check if submission lists are equal
+        returned_submissions_ids.sort()
+        visible_submission_ids.sort()
+        self.assertListEqual(returned_submissions_ids, visible_submission_ids)
diff --git a/submissions/utils.py b/submissions/utils.py
index d713236f3f2b66dab3fd04300962da4ece33e9a6..29ed7e85be4febc089c51bd4b476b66f3db4c21a 100644
--- a/submissions/utils.py
+++ b/submissions/utils.py
@@ -7,6 +7,7 @@ from django.utils import timezone
 from .constants import NO_REQUIRED_ACTION_STATUSES,\
                        STATUS_REVISION_REQUESTED, STATUS_EIC_ASSIGNED,\
                        STATUS_RESUBMISSION_INCOMING, STATUS_AWAITING_ED_REC
+from .exceptions import CycleUpdateDeadlineError
 
 from scipost.utils import EMAIL_FOOTER
 from common.utils import BaseMailUtil
@@ -112,11 +113,19 @@ class BaseSubmissionCycle:
                 SubmissionUtils.reinvite_referees_email()
 
     def update_deadline(self, period=None):
+        """
+        Reset the reporting deadline according to current datetime and default cycle length.
+        New reporting deadline may be explicitly given as datetime instance.
+        """
+        if self.submission.status == STATUS_RESUBMISSION_INCOMING:
+            raise CycleUpdateDeadlineError('Submission has invalid status: %s'
+                                           % self.submission.status)
         delta_d = period or self.default_days
         deadline = timezone.now() + datetime.timedelta(days=delta_d)
         self.submission.reporting_deadline = deadline
         self.submission.save()
 
+
     def get_required_actions(self):
         '''Return list of the submission its required actions'''
         if not self.updated_action:
diff --git a/submissions/views.py b/submissions/views.py
index ce94d8f6cecd0b88133cd1c32a4914b707cbaeff..b49f185de05e6050d7eba0075423db59f14458c4 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -27,9 +27,9 @@ from .forms import SubmissionIdentifierForm, SubmissionForm, SubmissionSearchFor
                    SubmissionCycleChoiceForm
 from .utils import SubmissionUtils
 
+from journals.constants import SCIPOST_JOURNALS_SPECIALIZATIONS
 from scipost.forms import ModifyPersonalMessageForm, RemarkForm
 from scipost.models import Contributor, Remark, RegistrationInvitation
-
 from scipost.services import ArxivCaller
 from scipost.utils import Utils
 from strings import arxiv_caller_errormessages_submissions
@@ -109,28 +109,7 @@ class PrefillUsingIdentifierView(PermissionRequiredMixin, FormView):
 
 class SubmissionCreateView(PermissionRequiredMixin, CreateView):
     model = Submission
-    fields = [
-        'is_resubmission',
-        'discipline',
-        'submitted_to_journal',
-        'submission_type',
-        'domain',
-        'subject_area',
-        'secondary_areas',
-        'title',
-        'author_list',
-        'abstract',
-        'arxiv_identifier_w_vn_nr',
-        'arxiv_identifier_wo_vn_nr',
-        'arxiv_vn_nr',
-        'arxiv_link',
-        'metadata',
-        'author_comments',
-        'list_of_changes',
-        'remarks_for_editors',
-        'referees_suggested',
-        'referees_flagged'
-    ]
+    form_class = SubmissionForm
 
     template_name = 'submissions/new_submission.html'
     permission_required = 'scipost.can_submit_manuscript'
@@ -148,6 +127,15 @@ class SubmissionCreateView(PermissionRequiredMixin, CreateView):
         submitted_by = Contributor.objects.get(user=self.request.user)
         form.instance.submitted_by = submitted_by
 
+        # Temporary until moved to new Arxiv Caller
+        # Check submitting user for authorship !
+        # With the new Arxiv caller, this message should already be given in the prefil form!
+        if not form.check_user_may_submit(self.request.user):
+            msg = ('Your name does not match that of any of the authors. '
+                   'You are not authorized to submit this preprint.')
+            messages.error(self.request, msg)
+            return redirect('submissions:prefill_using_identifier')
+
         # Save all the information contained in the form
         submission = form.save()
 
@@ -198,12 +186,13 @@ class SubmissionCreateView(PermissionRequiredMixin, CreateView):
 class SubmissionListView(ListView):
     model = Submission
     template_name = 'submissions/submissions.html'
-    form = SubmissionSearchForm()
+    form = SubmissionSearchForm
     submission_search_list = []
     paginate_by = 10
 
     def get_queryset(self):
-        queryset = Submission.objects.public_overcomplete().filter(is_current=True)
+        queryset = Submission.objects.public_overcomplete()
+        self.form = self.form(self.request.GET)
         if 'to_journal' in self.kwargs:
             queryset = queryset.filter(
                 latest_activity__gte=timezone.now() + datetime.timedelta(days=-60),
@@ -216,26 +205,17 @@ class SubmissionListView(ListView):
                 discipline=discipline,
                 latest_activity__gte=timezone.now() + datetime.timedelta(weeks=-int(nrweeksback))
             )
-        elif 'Submit' in self.request.GET:
-            queryset = queryset.filter(
-                title__icontains=self.request.GET.get('title_keyword', ''),
-                author_list__icontains=self.request.GET.get('author', ''),
-                abstract__icontains=self.request.GET.get('abstract_keyword', '')
-            )
+        elif self.form.is_valid() and self.form.has_changed():
+            queryset = self.form.search_results()
 
         return queryset.order_by('-submission_date')
 
     def get_context_data(self, **kwargs):
         # Call the base implementation first to get a context
-        context = super(SubmissionListView, self).get_context_data(**kwargs)
+        context = super().get_context_data(**kwargs)
 
-        # Keep any search fields previously filled
-        initialdata = {
-            'author': self.request.GET.get('author', ''),
-            'title_keyword': self.request.GET.get('title_keyword', ''),
-            'abstract_keyword': self.request.GET.get('abstract_keyword', '')
-        }
-        context['form'] = SubmissionSearchForm(initial=initialdata)
+        # Form into the context!
+        context['form'] = self.form
 
         # To customize display in the template
         if 'to_journal' in self.kwargs:
@@ -244,7 +224,7 @@ class SubmissionListView(ListView):
             context['discipline'] = self.kwargs['discipline']
             context['nrweeksback'] = self.kwargs['nrweeksback']
             context['browse'] = True
-        elif 'Submit' not in self.request.GET:
+        elif not self.form.is_valid() or not self.form.has_changed():
             context['recent'] = True
 
         return context
diff --git a/templates/email/referee_response_to_EIC.html b/templates/email/referee_response_to_EIC.html
index fdc5c1dc553aaf855fbb959bc1d9d1b62b861ede..baca1fbcedfd7e29c9b470c4b4f5e9518571566e 100644
--- a/templates/email/referee_response_to_EIC.html
+++ b/templates/email/referee_response_to_EIC.html
@@ -1,6 +1,6 @@
 Dear {{ invitation.submission.editor_in_charge.get_title_display }} {{ invitation.submission.editor_in_charge.user.last_name }},\n\n
 
-Referee {% if invitation.referee %}{{ invitation.referee.get_title_display }} {{ invitation.referee.user.last_name }}{% else %}{{ invitation.title }} {{ invitation.first_name }} {{ invitation.last_name }}{% endif %} has {% if invitation.accepted %}accepted{% else %}declined (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission\n\n
+Referee {% if invitation.referee %}{{ invitation.referee.get_title_display }} {{ invitation.referee.user.last_name }}{% else %}{{ invitation.get_title_display }} {{ invitation.first_name }} {{ invitation.last_name }}{% endif %} has {% if invitation.accepted %}accepted{% else %}declined (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission\n\n
 
 {{ invitation.submission.title }}\n by {{ invitation.submission.author_list }}\n\n
 
diff --git a/templates/email/referee_response_to_EIC_html.html b/templates/email/referee_response_to_EIC_html.html
index f932f38e7a200cd79e0d2ee29674c205d365acd1..99dc01a0f92abb424b098ab7e9fc15fc94a510a0 100644
--- a/templates/email/referee_response_to_EIC_html.html
+++ b/templates/email/referee_response_to_EIC_html.html
@@ -1,7 +1,7 @@
 <p>Dear {{ invitation.submission.editor_in_charge.get_title_display }} {{ invitation.submission.editor_in_charge.user.last_name }},</p>
 
 <p>
-    Referee {% if invitation.referee %}{{ invitation.referee.get_title_display }} {{ invitation.referee.user.last_name }}{% else %}{{ invitation.title }} {{ invitation.first_name }} {{ invitation.last_name }}{% endif %} has {% if invitation.accepted %}accepted{% else %}declined (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission
+    Referee {% if invitation.referee %}{{ invitation.referee.get_title_display }} {{ invitation.referee.user.last_name }}{% else %}{{ invitation.get_title_display }} {{ invitation.first_name }} {{ invitation.last_name }}{% endif %} has {% if invitation.accepted %}accepted{% else %}declined (due to reason: {{ invitation.get_refusal_reason_display }}){% endif %} to referee Submission
 </p>
 <p>
   {{ invitation.submission.title }}
diff --git a/templates/email/submission_eic_reappointment.html b/templates/email/submission_eic_reappointment.html
index a4b8eba72d81a8b39c1a0e0a21958651d760dc7e..01c9463755a1254e5397d6a529f5904212a4c13b 100644
--- a/templates/email/submission_eic_reappointment.html
+++ b/templates/email/submission_eic_reappointment.html
@@ -1,14 +1,14 @@
-Dear {{submission.editor_in_charge.get_title_display}} {{submission.editor_in_charge.user.last_name}},\n\n
+Dear {{ submission.editor_in_charge.get_title_display }} {{ submission.editor_in_charge.user.last_name }},\n\n
 
 The authors of the SciPost Submission\n\n
-{{submission.title}}
+{{ submission.title }}
 \n\n
-by {{submission.author_list}}
+by {{ submission.author_list }}
 \n\n
 have resubmitted their manuscript.\n\n
 
-As Editor-in-charge, you can take your editorial actions from the submission\'s editorial page: https://scipost.org{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}.\n
-(also accessible from your personal page under the Editorial Actions tab), see https://scipost.org{% url 'scipost:personal_page' %}. \n\n
+As Editor-in-charge, you can take your editorial actions from the submission\'s editorial page https://scipost.org{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %},
+which is also accessible from your personal page at https://scipost.org{% url 'scipost:personal_page' %} under the Editorial Actions tab.\n\n
 
 You can either take an immediate acceptance/rejection decision, quickly consult previous referees or run a new refereeing round, in which case you should now invite at least 3 referees; you might want to make sure you are aware of the detailed procedure described in the Editorial College by-laws. See https://scipost.org{% url 'scipost:EdCol_by-laws' %}.
 \n\n
diff --git a/templates/email/submission_eic_reappointment_html.html b/templates/email/submission_eic_reappointment_html.html
index 9603dd70a5cf2d9f2698bea43584834b15acd6a2..6d2d4ee38dd3dae48e4f74641cd00b1bdef37b80 100644
--- a/templates/email/submission_eic_reappointment_html.html
+++ b/templates/email/submission_eic_reappointment_html.html
@@ -1,11 +1,18 @@
-<p>Dear {{submission.editor_in_charge.get_title_display}} {{submission.editor_in_charge.user.last_name}},</p>
+<p>Dear {{ submission.editor_in_charge.get_title_display }} {{ submission.editor_in_charge.user.last_name }},</p>
 
 <p>
-    The authors of the SciPost Submission "{{submission.title}} by {{submission.author_list}}" have resubmitted their manuscript.
+  The authors of the SciPost Submission
 </p>
 <p>
-    As Editor-in-charge, you can take your editorial actions from the submission\'s <a href="https://scipost.org{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}">editorial page</a>.
-    (also accessible from your <a href="https://scipost.org{% url 'scipost:personal_page' %}">personal page</a> under the Editorial Actions tab).
+  {{submission.title}}
+  <br/>
+  by {{submission.author_list}}
+</p>
+<p>
+  have resubmitted their manuscript.
+</p>
+<p>
+    As Editor-in-charge, you can take your editorial actions from the submission's <a href="https://scipost.org{% url 'submissions:editorial_page' submission.arxiv_identifier_w_vn_nr %}">editorial page</a>, which is also accessible from your <a href="https://scipost.org{% url 'scipost:personal_page' %}">personal page</a> under the Editorial Actions tab.
 </p>
 <p>
     You can either take an immediate acceptance/rejection decision, quickly consult previous referees or run a new refereeing round, in which case you should now invite at least 3 referees; you might want to make sure you are aware of the detailed procedure described in the <a href="https://scipost.org{% url 'scipost:EdCol_by-laws' %}">Editorial College by-laws</a>.
diff --git a/theses/factories.py b/theses/factories.py
index fe9091788560fdc69f34f7b65519f0d0772157b9..c5461a1a6160fe74397f854ed00309966ed6c06c 100644
--- a/theses/factories.py
+++ b/theses/factories.py
@@ -1,31 +1,41 @@
 import factory
 
+from django.utils import timezone
+
 from common.helpers.factories import FormFactory
-from scipost.factories import ContributorFactory
+from journals.constants import SCIPOST_JOURNALS_DOMAINS
+from scipost.constants import SCIPOST_DISCIPLINES, SCIPOST_SUBJECT_AREAS
+from scipost.models import Contributor
 
 from .models import ThesisLink
 from .forms import VetThesisLinkForm
-from .constants import MASTER_THESIS
+from .constants import THESIS_TYPES
+
+from faker import Faker
+
+timezone.now()
 
 
 class ThesisLinkFactory(factory.django.DjangoModelFactory):
     class Meta:
         model = ThesisLink
 
-    requested_by = factory.SubFactory(ContributorFactory)
-    type = MASTER_THESIS
-    title = factory.Faker('bs')
+    requested_by = factory.Iterator(Contributor.objects.all())
+    type = factory.Iterator(THESIS_TYPES, getter=lambda c: c[0])
+    domain = factory.Iterator(SCIPOST_JOURNALS_DOMAINS, getter=lambda c: c[0])
+    discipline = factory.Iterator(SCIPOST_DISCIPLINES, getter=lambda c: c[0])
+    subject_area = factory.Iterator(SCIPOST_SUBJECT_AREAS[0][1], getter=lambda c: c[0])
+    title = factory.Faker('text')
     pub_link = factory.Faker('uri')
     author = factory.Faker('name')
     supervisor = factory.Faker('name')
     institution = factory.Faker('company')
     defense_date = factory.Faker('date')
-    abstract = factory.Faker('text')
-    domain = 'ET'
+    abstract = factory.lazy_attribute(lambda x: Faker().paragraph())
 
 
 class VettedThesisLinkFactory(ThesisLinkFactory):
-    vetted_by = factory.SubFactory(ContributorFactory)
+    vetted_by = factory.Iterator(Contributor.objects.all())
     vetted = True