From 595e02f3dab8ad1e01a86955e726b6360a1d9e2b Mon Sep 17 00:00:00 2001
From: Jorran de Wit <jorrandewit@outlook.com>
Date: Sat, 10 Mar 2018 17:38:56 +0100
Subject: [PATCH] Ready

---
 funders/forms.py                              |   4 +-
 journals/behaviors.py                         |  10 +-
 journals/constants.py                         |   3 +-
 journals/forms.py                             | 271 ++++++++++++------
 journals/managers.py                          |  33 ++-
 journals/models.py                            |  19 ++
 journals/templates/journals/_base.html        |   2 +-
 journals/templates/journals/add_author.html   |   2 -
 .../templates/journals/journal_accepted.html  |   2 +-
 .../journals/journal_issue_detail.html        |   4 +-
 .../templates/journals/journal_issues.html    |   2 +-
 .../journals/journal_landing_page.html        |  18 +-
 .../templates/journals/journal_recent.html    |   2 +-
 journals/templates/journals/journals.html     |   8 +-
 .../templates/journals/manage_metadata.html   |  46 ++-
 .../journals/publication_detail.html          |   2 +-
 .../templates/journals/publication_form.html  |   2 +-
 .../templates/xml/publication_crossref.html   |  48 ++--
 journals/urls/general.py                      |  50 ++--
 journals/urls/journal.py                      |   6 +-
 journals/views.py                             | 208 ++++++++------
 .../scipost/assets/css/_list_group.scss       |   4 +
 scipost/urls.py                               |  10 +-
 .../submissions/submission_list.html          |   2 +-
 submissions/views.py                          |  25 +-
 25 files changed, 505 insertions(+), 278 deletions(-)

diff --git a/funders/forms.py b/funders/forms.py
index a5c7d8d29..a88322618 100644
--- a/funders/forms.py
+++ b/funders/forms.py
@@ -28,9 +28,9 @@ class GrantForm(HttpRefererFormMixin, forms.ModelForm):
     def __init__(self, *args, **kwargs):
         super().__init__(*args, **kwargs)
         self.fields['recipient'] = forms.ModelChoiceField(
-            queryset=Contributor.objects.all().order_by('user__last_name'),
+            queryset=Contributor.objects.select_related('user').order_by('user__last_name'),
             required=False)
 
 
 class GrantSelectForm(forms.Form):
-    grant = forms.ModelChoiceField(queryset=Grant.objects.all())
+    grant = forms.ModelChoiceField(queryset=Grant.objects.all().select_related('funder'))
diff --git a/journals/behaviors.py b/journals/behaviors.py
index eca874354..8079e19c7 100644
--- a/journals/behaviors.py
+++ b/journals/behaviors.py
@@ -1,5 +1,8 @@
 from django.core.validators import RegexValidator
 
+from .constants import PUBLICATION_DOI_VALIDATION_REGEX
+
+
 doi_journal_validator = RegexValidator(r'^[a-zA-Z]+$',
                                        'Only valid DOI expressions are allowed ([a-zA-Z]+).')
 doi_volume_validator = RegexValidator(r'^[a-zA-Z]+.[0-9]+$',
@@ -7,6 +10,7 @@ doi_volume_validator = RegexValidator(r'^[a-zA-Z]+.[0-9]+$',
 doi_issue_validator = RegexValidator(r'^[a-zA-Z]+.[0-9]+.[0-9]+$',
                                      ('Only valid DOI expressions are allowed '
                                       '([a-zA-Z]+.[0-9]+.[0-9]+).'))
-doi_publication_validator = RegexValidator(r'^[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,}$',
-                                           ('Only valid DOI expressions are allowed '
-                                            '([a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,}).'))
+doi_publication_validator = RegexValidator(
+    r'^{regex}$'.format(regex=PUBLICATION_DOI_VALIDATION_REGEX),
+    ('Only valid DOI expressions are allowed '
+     '(`[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,}` or `[a-zA-Z]+.[0-9]+`)'))
diff --git a/journals/constants.py b/journals/constants.py
index ac2bd20b3..60a544014 100644
--- a/journals/constants.py
+++ b/journals/constants.py
@@ -26,6 +26,7 @@ REGEX_CHOICES = '|'.join([
     SCIPOST_JOURNAL_PHYSICS
 ])
 
+PUBLICATION_DOI_REGEX = PUBLICATION_DOI_VALIDATION_REGEX = '[a-zA-Z]+.[0-9]+(.[0-9]+.[0-9]{3,})?'
 
 SCIPOST_JOURNALS_DOMAINS = (
     ('E', 'Experimental'),
@@ -85,6 +86,6 @@ ISSUES_ONLY = 'IO'
 INDIVIDUAL_PUBLCATIONS = 'IP'
 JOURNAL_STRUCTURE = (
     (ISSUES_AND_VOLUMES, 'Issues and Volumes'),
-    (ISSUES_ONLY, 'Issues only'),
+    # (ISSUES_ONLY, 'Issues only'),  # This option complies with Crossref's rules, but is not implemented (yet).
     (INDIVIDUAL_PUBLCATIONS, 'Individual Publications'),
 )
diff --git a/journals/forms.py b/journals/forms.py
index bba8de058..4464d567a 100644
--- a/journals/forms.py
+++ b/journals/forms.py
@@ -19,6 +19,7 @@ from .utils import JournalUtils
 
 
 from funders.models import Grant, Funder
+from journals.models import Journal
 from mails.utils import DirectMailUtil
 from production.constants import PROOFS_PUBLISHED
 from production.models import ProductionEvent
@@ -127,17 +128,20 @@ class CreateMetadataXMLForm(forms.ModelForm):
 class CreateMetadataDOAJForm(forms.ModelForm):
     class Meta:
         model = Publication
-        fields = ()
+        fields = ['metadata_DOAJ']
 
     def __init__(self, *args, **kwargs):
         self.request = kwargs.pop('request')
+        kwargs['initial'] = {
+            'metadata_DOAJ': self.generate(kwargs.get('instance'))
+        }
         super().__init__(*args, **kwargs)
 
-    def save(self, *args, **kwargs):
-        self.instance.metadata_DOAJ = self.generate(self.instance)
-        return super().save(*args, **kwargs)
-
     def generate(self, publication):
+        if publication.in_issue:
+            issn = str(publication.in_issue.in_volume.in_journal.issn)
+        else:
+            issn = str(publication.in_journal.issn)
         md = {
             'bibjson': {
                 'author': [{'name': publication.author_list}],
@@ -149,7 +153,7 @@ class CreateMetadataDOAJForm(forms.ModelForm):
                 'identifier': [
                     {
                         'type': 'eissn',
-                        'id': str(publication.in_issue.in_volume.in_journal.issn)
+                        'id': issn
                     },
                     {
                         'type': 'doi',
@@ -162,28 +166,48 @@ class CreateMetadataDOAJForm(forms.ModelForm):
                         'type': 'fulltext',
                     }
                 ],
-                'journal': {
-                    'publisher': 'SciPost',
-                    'volume': str(publication.in_issue.in_volume.number),
-                    'number': str(publication.in_issue.number),
-                    'identifier': [{
-                        'type': 'eissn',
-                        'id': str(publication.in_issue.in_volume.in_journal.issn)
-                    }],
-                    'license': [
-                        {
-                            'url': self.request.build_absolute_uri(
-                                publication.in_issue.in_volume.in_journal.get_absolute_url()),
-                            'open_access': 'true',
-                            'type': publication.get_cc_license_display(),
-                            'title': publication.get_cc_license_display(),
-                        }
-                    ],
-                    'language': ['EN'],
-                    'title': publication.in_issue.in_volume.in_journal.get_name_display(),
-                }
             }
         }
+        if publication.in_issue:
+            md['journal'] = {
+                'publisher': 'SciPost',
+                'volume': str(publication.in_issue.in_volume.number),
+                'number': str(publication.in_issue.number),
+                'identifier': [{
+                    'type': 'eissn',
+                    'id': issn
+                }],
+                'license': [
+                    {
+                        'url': self.request.build_absolute_uri(
+                            publication.in_issue.in_volume.in_journal.get_absolute_url()),
+                        'open_access': 'true',
+                        'type': publication.get_cc_license_display(),
+                        'title': publication.get_cc_license_display(),
+                    }
+                ],
+                'language': ['EN'],
+                'title': publication.in_issue.in_volume.in_journal.get_name_display(),
+            }
+        else:
+            md['journal'] = {
+                'publisher': 'SciPost',
+                'identifier': [{
+                    'type': 'eissn',
+                    'id': issn
+                }],
+                'license': [
+                    {
+                        'url': self.request.build_absolute_uri(
+                            publication.in_journal.get_absolute_url()),
+                        'open_access': 'true',
+                        'type': publication.get_cc_license_display(),
+                        'title': publication.get_cc_license_display(),
+                    }
+                ],
+                'language': ['EN'],
+                'title': publication.in_journal.get_name_display(),
+            }
         return md
 
 
@@ -306,20 +330,32 @@ class DraftPublicationForm(forms.ModelForm):
         # Use separate instance to be able to prefill the form without any existing Publication
         self.submission = None
         self.issue = None
+        self.to_journal = None
         if arxiv_identifier_w_vn_nr:
             try:
                 self.submission = Submission.objects.accepted().get(
                     arxiv_identifier_w_vn_nr=arxiv_identifier_w_vn_nr)
             except Submission.DoesNotExist:
                 self.submission = None
-        if issue_id:
+
+        # Check if the Submission is related to a Journal with individual Publications only
+        if self.submission:
+            try:
+                self.to_journal = Journal.objects.has_individual_publications().get(
+                    name=self.submission.submitted_to_journal)
+            except Journal.DoesNotExist:
+                self.to_journal = None
+
+        # If the Journal is not for individual publications, choose a Issue for Publication
+        if issue_id and not self.to_journal:
             try:
                 self.issue = self.get_possible_issues().get(id=issue_id)
             except Issue.DoesNotExist:
                 self.issue = None
 
         super().__init__(data, *args, **kwargs)
-        if kwargs.get('instance') or self.issue:
+
+        if kwargs.get('instance') or self.issue or self.to_journal:
             # When updating: fix in_issue, because many fields are directly related to the issue.
             del self.fields['in_issue']
             self.prefill_fields()
@@ -328,7 +364,10 @@ class DraftPublicationForm(forms.ModelForm):
             self.delete_secondary_fields()
 
     def get_possible_issues(self):
-        return Issue.objects.filter(until_date__gte=timezone.now())
+        issues = Issue.objects.filter(until_date__gte=timezone.now())
+        if self.submission:
+            issues = issues.for_journal(self.submission.submitted_to_journal)
+        return issues
 
     def delete_secondary_fields(self):
         """
@@ -351,6 +390,17 @@ class DraftPublicationForm(forms.ModelForm):
         del self.fields['acceptance_date']
         del self.fields['publication_date']
 
+    def clean(self):
+        data = super().clean()
+        if not self.instance.id:
+            if self.submission:
+                self.instance.accepted_submission = self.submission
+            if self.issue:
+                self.instance.in_issue = self.issue
+            if self.to_journal:
+                self.instance.in_journal = self.to_journal
+        return data
+
     def save(self, *args, **kwargs):
         """
         Save the Publication object always as a draft and prefill the Publication with
@@ -359,10 +409,7 @@ class DraftPublicationForm(forms.ModelForm):
         do_prefill = False
         if not self.instance.id:
             do_prefill = True
-            if self.submission:
-                self.instance.accepted_submission = self.submission
-            self.instance.in_issue = self.issue
-        self.instance = super().save(*args, **kwargs)
+        super().save(*args, **kwargs)
         if do_prefill:
             self.first_time_fill()
         return self.instance
@@ -398,51 +445,101 @@ class DraftPublicationForm(forms.ModelForm):
             self.fields['secondary_areas'].initial = self.submission.secondary_areas
             self.fields['submission_date'].initial = self.submission.submission_date
             self.fields['acceptance_date'].initial = self.submission.acceptance_date
+            self.fields['publication_date'].initial = timezone.now()
 
         # Fill data that may be derived from the issue data
-        issue = self.instance.in_issue if hasattr(self.instance, 'in_issue') else self.issue
+        issue = None
+        if hasattr(self.instance, 'in_issue') and self.instance.in_issue:
+            issue = self.instance.in_issue
+        elif self.issue:
+            issue = self.issue
         if issue:
-            # Determine next available paper number:
-            paper_nr = Publication.objects.filter(in_issue__in_volume=issue.in_volume).count()
-            paper_nr += paper_nr
-            if paper_nr > 999:
-                raise PaperNumberingError(paper_nr)
-            self.fields['paper_nr'].initial = str(paper_nr)
-            doi_label = '{journal}.{vol}.{issue}.{paper}'.format(
-                journal=issue.in_volume.in_journal.name,
-                vol=issue.in_volume.number,
-                issue=issue.number,
-                paper=str(paper_nr).rjust(3, '0'))
-            self.fields['doi_label'].initial = doi_label
-
-            doi_string = '10.21468/{doi}'.format(doi=doi_label)
-            bibtex_entry = (
-                '@Article{%s,\n'
-                '\ttitle={{%s},\n'
-                '\tauthor={%s},\n'
-                '\tjournal={%s},\n'
-                '\tvolume={%i},\n'
-                '\tissue={%i},\n'
-                '\tpages={%i},\n'
-                '\tyear={%s},\n'
-                '\tpublisher={SciPost},\n'
-                '\tdoi={%s},\n'
-                '\turl={https://scipost.org/%s},\n'
-                '}'
-            ) % (
-                doi_string,
-                self.submission.title,
-                self.submission.author_list.replace(',', ' and'),
-                issue.in_volume.in_journal.abbreviation_citation,
-                issue.in_volume.number,
-                issue.number,
-                paper_nr,
-                issue.until_date.strftime('%Y'),
-                doi_string,
-                doi_string)
-            self.fields['BiBTeX_entry'].initial = bibtex_entry
-            if not self.instance.BiBTeX_entry:
-                self.instance.BiBTeX_entry = bibtex_entry
+            self.prefill_with_issue(issue)
+
+        # Fill data that may be derived from the issue data
+        journal = None
+        if hasattr(self.instance, 'in_journal') and self.instance.in_journal:
+            journal = self.instance.in_issue
+        elif self.to_journal:
+            journal = self.to_journal
+        if journal:
+            self.prefill_with_journal(journal)
+
+    def prefill_with_issue(self, issue):
+        # Determine next available paper number:
+        paper_nr = Publication.objects.filter(in_issue__in_volume=issue.in_volume).count() + 1
+        if paper_nr > 999:
+            raise PaperNumberingError(paper_nr)
+        self.fields['paper_nr'].initial = str(paper_nr)
+        doi_label = '{journal}.{vol}.{issue}.{paper}'.format(
+            journal=issue.in_volume.in_journal.name,
+            vol=issue.in_volume.number,
+            issue=issue.number,
+            paper=str(paper_nr).rjust(3, '0'))
+        self.fields['doi_label'].initial = doi_label
+
+        doi_string = '10.21468/{doi}'.format(doi=doi_label)
+        bibtex_entry = (
+            '@Article{%s,\n'
+            '\ttitle={{%s},\n'
+            '\tauthor={%s},\n'
+            '\tjournal={%s},\n'
+            '\tvolume={%i},\n'
+            '\tissue={%i},\n'
+            '\tpages={%i},\n'
+            '\tyear={%s},\n'
+            '\tpublisher={SciPost},\n'
+            '\tdoi={%s},\n'
+            '\turl={https://scipost.org/%s},\n'
+            '}'
+        ) % (
+            doi_string,
+            self.submission.title,
+            self.submission.author_list.replace(',', ' and'),
+            issue.in_volume.in_journal.abbreviation_citation,
+            issue.in_volume.number,
+            issue.number,
+            paper_nr,
+            issue.until_date.strftime('%Y'),
+            doi_string,
+            doi_string)
+        self.fields['BiBTeX_entry'].initial = bibtex_entry
+        if not self.instance.BiBTeX_entry:
+            self.instance.BiBTeX_entry = bibtex_entry
+
+    def prefill_with_journal(self, journal):
+        # Determine next available paper number:
+        paper_nr = journal.publications.count() + 1
+        self.fields['paper_nr'].initial = str(paper_nr)
+        doi_label = '{journal}.{paper}'.format(
+            journal=journal.name,
+            paper=paper_nr)
+        self.fields['doi_label'].initial = doi_label
+
+        doi_string = '10.21468/{doi}'.format(doi=doi_label)
+        bibtex_entry = (
+            '@Article{%s,\n'
+            '\ttitle={{%s},\n'
+            '\tauthor={%s},\n'
+            '\tjournal={%s},\n'
+            '\tpages={%i},\n'
+            '\tyear={%s},\n'
+            '\tpublisher={SciPost},\n'
+            '\tdoi={%s},\n'
+            '\turl={https://scipost.org/%s},\n'
+            '}'
+        ) % (
+            doi_string,
+            self.submission.title,
+            self.submission.author_list.replace(',', ' and'),
+            journal.abbreviation_citation,
+            paper_nr,
+            timezone.now().year,
+            doi_string,
+            doi_string)
+        self.fields['BiBTeX_entry'].initial = bibtex_entry
+        if not self.instance.BiBTeX_entry:
+            self.instance.BiBTeX_entry = bibtex_entry
 
 
 class DraftPublicationApprovalForm(forms.ModelForm):
@@ -483,14 +580,24 @@ class PublicationPublishForm(RequestFormMixin, forms.ModelForm):
         fields = []
 
     def move_pdf(self):
-        # Move file to final location
+        """
+        To keep the Publication pdfs organized we move the pdfs to their own folder
+        organized by journal and optional issue folder.
+        """
         initial_path = self.instance.pdf_file.path
-        new_dir = (settings.MEDIA_ROOT + self.instance.in_issue.path + '/'
-                   + self.instance.get_paper_nr())
-        new_path = new_dir + '/' + self.instance.doi_label.replace('.', '_') + '.pdf'
-        os.makedirs(new_dir)
-        os.rename(initial_path, new_path)
-        self.instance.pdf_file.name = new_path
+
+        new_dir = ''
+        if self.instance.in_issue:
+            new_dir += self.instance.in_issue.path
+        elif self.instance.in_journal:
+            new_dir += 'SCIPOST_JOURNALS/{name}'.format(name=self.instance.in_journal.name)
+
+        new_dir += '/{paper_nr}'.format(paper_nr=self.instance.get_paper_nr())
+        os.makedirs(settings.MEDIA_ROOT + new_dir)
+
+        new_dir += '/{doi}.pdf'.format(doi=self.instance.doi_label.replace('.', '_'))
+        os.rename(initial_path, settings.MEDIA_ROOT + new_dir)
+        self.instance.pdf_file.name = new_dir
         self.instance.status = PUBLICATION_PUBLISHED
         self.instance.save()
 
diff --git a/journals/managers.py b/journals/managers.py
index 573836301..8bddbf37b 100644
--- a/journals/managers.py
+++ b/journals/managers.py
@@ -2,7 +2,7 @@ from django.db import models
 from django.utils import timezone
 
 from .constants import STATUS_PUBLISHED, STATUS_DRAFT, PUBLICATION_PUBLISHED, ISSUES_AND_VOLUMES,\
-    ISSUES_ONLY
+    ISSUES_ONLY, INDIVIDUAL_PUBLCATIONS
 
 
 class JournalQuerySet(models.QuerySet):
@@ -12,19 +12,21 @@ class JournalQuerySet(models.QuerySet):
     def has_issues(self):
         return self.filter(structure__in=(ISSUES_AND_VOLUMES, ISSUES_ONLY))
 
+    def has_individual_publications(self):
+        return self.filter(structure=INDIVIDUAL_PUBLCATIONS)
+
 
 class IssueQuerySet(models.QuerySet):
-    def published(self, journal=None):
-        issues = self.filter(status=STATUS_PUBLISHED)
-        if journal:
-            issues.filter(in_volume__in_journal=journal)
-        return issues
-
-    def in_draft(self, journal=None):
-        issues = self.filter(status=STATUS_DRAFT)
-        if journal:
-            issues.filter(in_volume__in_journal=journal)
-        return issues
+    def published(self):
+        return self.filter(status=STATUS_PUBLISHED)
+
+    def in_draft(self):
+        return self.filter(status=STATUS_DRAFT)
+
+    def for_journal(self, journal_name):
+        return self.filter(
+            models.Q(in_volume__in_journal__name=journal_name) |
+            models.Q(in_journal__name=journal_name))
 
     def get_current_issue(self):
         return self.published(
@@ -32,7 +34,7 @@ class IssueQuerySet(models.QuerySet):
 
 
 class PublicationQuerySet(models.QuerySet):
-    def published(self, **kwargs):
+    def published(self):
         return self.filter(status=PUBLICATION_PUBLISHED).filter(
             models.Q(in_issue__status=STATUS_PUBLISHED) | models.Q(in_journal__active=True))
 
@@ -44,3 +46,8 @@ class PublicationQuerySet(models.QuerySet):
 
     def drafts(self):
         return self.filter(status=STATUS_DRAFT)
+
+    def for_journal(self, journal_name):
+        return self.filter(
+            models.Q(in_issue__in_volume__in_journal__name=journal_name) |
+            models.Q(in_journal__name=journal_name))
diff --git a/journals/models.py b/journals/models.py
index f33359a32..5b755195e 100644
--- a/journals/models.py
+++ b/journals/models.py
@@ -109,6 +109,20 @@ class Journal(models.Model):
     def abbreviation_citation(self):
         return journal_name_abbrev_citation(self.name)
 
+    def get_issues(self):
+        if self.structure == ISSUES_AND_VOLUMES:
+            return Issue.objects.filter(in_volume__in_journal=self)
+        elif self.structure == ISSUES_ONLY:
+            return self.issues.all()
+        return Issue.objects.none()
+
+    def get_publications(self):
+        if self.structure == ISSUES_AND_VOLUMES:
+            return Publication.objects.filter(in_issue__in_volume__in_journal=self)
+        elif self.structure == ISSUES_ONLY:
+            return Publication.objects.filter(in_issue__in_journal=self)
+        return self.publications.all()
+
     def nr_publications(self, tier=None):
         publications = Publication.objects.filter(in_issue__in_volume__in_journal=self)
         if tier:
@@ -153,6 +167,7 @@ class Volume(models.Model):
                                  validators=[doi_volume_validator])
 
     class Meta:
+        default_related_name = 'volumes'
         unique_together = ('number', 'in_journal')
 
     def __str__(self):
@@ -227,6 +242,7 @@ class Issue(models.Model):
     objects = IssueQuerySet.as_manager()
 
     class Meta:
+        default_related_name = 'issues'
         ordering = ('-until_date',)
         unique_together = ('number', 'in_volume')
 
@@ -495,6 +511,9 @@ class Publication(models.Model):
             year=self.publication_date.strftime('%Y'))
         return txt
 
+    def get_journal(self):
+        return self.in_journal or self.in_issue.in_volume.in_journal
+
     def get_paper_nr(self):
         return paper_nr_string(self.paper_nr)
 
diff --git a/journals/templates/journals/_base.html b/journals/templates/journals/_base.html
index 2d17cbad6..e34dfe309 100644
--- a/journals/templates/journals/_base.html
+++ b/journals/templates/journals/_base.html
@@ -21,7 +21,7 @@
 <div class="container mt-3">
     <div class="row">
         <div class="col journal">
-            <h2 class="banner d-inline-block mr-2"><a href="{% url 'scipost:landing_page' journal.doi_label %}">{{journal}}</a></h2>
+            <h2 class="banner d-inline-block mr-2"><a href="{{ journal.get_absolute_url }}">{{journal}}</a></h2>
             <ul class="links">
                 {% if journal.active or request.user.is_staff %}
                     {% if journal.has_issues %}
diff --git a/journals/templates/journals/add_author.html b/journals/templates/journals/add_author.html
index 668919333..627dd1a06 100644
--- a/journals/templates/journals/add_author.html
+++ b/journals/templates/journals/add_author.html
@@ -7,8 +7,6 @@
         <div class="container">
             <nav class="breadcrumb hidden-sm-down">
                 <a href="{% url 'journals:journals' %}" class="breadcrumb-item">Journals</a>
-                <a href="{{publication.in_issue.in_volume.in_journal.get_absolute_url}}" class="breadcrumb-item">{{publication.in_issue.in_volume.in_journal}}</a>
-                <a href="{{publication.in_issue.get_absolute_url}}" class="breadcrumb-item">{{publication.in_issue.short_str}}</a>
                 <a href="{{publication.get_absolute_url}}" class="breadcrumb-item">{{publication.citation}}</a>
                 <span class="breadcrumb-item active">Add author to publication</span>
 
diff --git a/journals/templates/journals/journal_accepted.html b/journals/templates/journals/journal_accepted.html
index 2eb16483d..d5944bf76 100644
--- a/journals/templates/journals/journal_accepted.html
+++ b/journals/templates/journals/journal_accepted.html
@@ -19,7 +19,7 @@
     <div class="row">
         <div class="col-12">
             <ul class="list-group list-group-flush">
-                {% for submission in accepted_SP_submissions %}
+                {% for submission in accepted_submissions %}
                     <li class="list-group-item">
                         <div class="card-body px-0">
                             {% include 'partials/submissions/submission_card_content.html' with submission=submission %}
diff --git a/journals/templates/journals/journal_issue_detail.html b/journals/templates/journals/journal_issue_detail.html
index 6b646613d..5b22c11f7 100644
--- a/journals/templates/journals/journal_issue_detail.html
+++ b/journals/templates/journals/journal_issue_detail.html
@@ -14,10 +14,10 @@
 
 {% block journal_header_block %}
     {% if prev_issue %}
-        <h4 class="d-inline-block"><a href="{{prev_issue.get_absolute_url}}">< Previous issue | {{prev_issue.short_str}}</a></h4>
+        <h4 class="d-inline-block"><a href="{{prev_issue.get_absolute_url}}"><i class="fa fa-long-arrow-left"></i> Previous issue | {{prev_issue.short_str}}</a></h4>
     {% endif %}
     {% if next_issue %}
-        <h4 class="float-right d-inline-block"><a href="{{next_issue.get_absolute_url}}">{{next_issue.short_str}} | Next issue ></a></h4>
+        <h4 class="float-right d-inline-block"><a href="{{next_issue.get_absolute_url}}">{{next_issue.short_str}} | Next issue <i class="fa fa-long-arrow-right"></i></a></h4>
     {% endif %}
 {% endblock %}
 
diff --git a/journals/templates/journals/journal_issues.html b/journals/templates/journals/journal_issues.html
index 601a8c550..e69b81f25 100644
--- a/journals/templates/journals/journal_issues.html
+++ b/journals/templates/journals/journal_issues.html
@@ -18,7 +18,7 @@
     <div class="row">
         <div class="col-12">
             <ul>
-                {% for issue in issues %}
+                {% for issue in journal.get_issues %}
                     <li>
                         <a href="{{issue.get_absolute_url}}">{{issue}}</a>
                         {% if issue.proceedings %}
diff --git a/journals/templates/journals/journal_landing_page.html b/journals/templates/journals/journal_landing_page.html
index eac446d3c..98bae00dc 100644
--- a/journals/templates/journals/journal_landing_page.html
+++ b/journals/templates/journals/journal_landing_page.html
@@ -13,7 +13,7 @@
                 <div class="col-12">
                     <h2 class="highlight-empty text-blue m-0 p-0 pt-2">Current issue: Vol. {{ current_issue.in_volume.number }} issue {{ current_issue.number }} (in progress)</h2>
                     {% if prev_issue %}
-                        <h4 class="d-inline-block"><a href="{{prev_issue.get_absolute_url}}">< Previous issue | Vol. {{prev_issue.in_volume.number}} issue {{prev_issue.number}}</a></h4>
+                        <h4 class="d-inline-block"><a href="{{prev_issue.get_absolute_url}}"><i class="fa fa-long-arrow-left"></i> Previous issue | Vol. {{prev_issue.in_volume.number}} issue {{prev_issue.number}}</a></h4>
                     {% endif %}
                 </div>
             </div>
@@ -65,11 +65,16 @@
                 </div>
             </div>
         {% endif %}
-    {% elif publications %}
+    {% elif page_object %}
+        <div class="row">
+            <div class="col-12">
+                <h2 class="text-blue">{{ journal.get_name_display }} Publications</h2>
+            </div>
+        </div>
         <div class="row">
             <div class="col-12">
                 <ul class="list-unstyled">
-                    {% for publication in publications %}
+                    {% for publication in page_object.object_list %}
                         <li>
                             {% include 'partials/journals/publication_card.html' with publication=publication %}
                         </li>
@@ -81,8 +86,13 @@
                 </ul>
             </div>
         </div>
+        <div class="row">
+            <div class="col-12">
+                {% include 'partials/pagination.html' with page_obj=page_object %}
+            </div>
+        </div>
     {% else %}
-        <h3>First Publication coming soon!</h3>
+        <h3 class="none-found">First Publication coming soon!</h3>
     {% endif %}
 
 {% endblock %}
diff --git a/journals/templates/journals/journal_recent.html b/journals/templates/journals/journal_recent.html
index d12a18090..66c96e501 100644
--- a/journals/templates/journals/journal_recent.html
+++ b/journals/templates/journals/journal_recent.html
@@ -19,7 +19,7 @@
     <div class="row">
         <div class="col-12">
             <ul class="list-unstyled">
-                {% for paper in recent_papers %}
+                {% for paper in journal.get_publications.published|slice:':20' %}
                     <li>
                         {% include 'partials/journals/publication_card.html' with publication=paper %}
                     </li>
diff --git a/journals/templates/journals/journals.html b/journals/templates/journals/journals.html
index de1e80066..a696b5cd0 100644
--- a/journals/templates/journals/journals.html
+++ b/journals/templates/journals/journals.html
@@ -77,9 +77,13 @@
         </div>
     </div>
     <div class="col-md-6">
-        <h1 class="banner">SciPost Physics Lecture Notes</h1>
+        <h1 class="banner"><a href="{% url 'scipost:landing_page' 'SciPostPhysLectNotes' %}">SciPost Physics Lecture Notes</a></h1>
         <div class="py-2">
-          <p>Research-level didactic material in all domains and subject areas of Physics.</p>
+          <p>
+              <a href="{% url 'journal:about' 'SciPostPhysLectNotes' %}">Go directly to SciPost Physics Lecture Notes</a>
+              <br><br>
+              Research-level didactic material in all domains and subject areas of Physics.
+          </p>
         </div>
     </div>
 </div>
diff --git a/journals/templates/journals/manage_metadata.html b/journals/templates/journals/manage_metadata.html
index d77c5d434..08ae88c80 100644
--- a/journals/templates/journals/manage_metadata.html
+++ b/journals/templates/journals/manage_metadata.html
@@ -19,23 +19,47 @@ event: "focusin"
     <span class="breadcrumb-item">Manage metadata</span>
 {% endblock %}
 
+{% block body_class %}{{ block.super }} manage_metadata{% endblock %}
+
 {% block content %}
 
 <div class="row">
     <div class="col-12">
-        <h1 class="highlight">Manage Publications Metadata{% if issue_doi_label %} for issue {{ issue_doi_label }}{% endif %}</h1>
-	{% if issue_doi_label %}
-	<h3>Return to the <a href="{% url 'journals:manage_metadata' %}">Main manage metadata page</a></h3>
-	{% endif %}
-	<h3>Manage metadata per issue:</h3>
-        <ul>
-          {% for issue in issues %}
-          <li>
-            <a href="{% url 'journals:manage_metadata' issue_doi_label=issue.doi_label %}">{{ issue }}</a>
-          </li>
-          {% endfor %}
+        <h1 class="highlight">Manage Publications Metadata{% if issue_doi_label %} for issue {{ issue_doi_label }}{% elif journal %} for {{ journal }}{% endif %}</h1>
+
+    </div>
+</div>
+<div class="row">
+    <div class="col-md-6">
+        <h3>Available journals</h3>
+        <ul class="links">
+            {% for journal in journals %}
+                {% url 'journals:manage_metadata' journal_doi_label=journal.doi_label as url %}
+                <li class="{% if url == request.path %}active{% endif %}">
+                    <a href="{{ url }}">{{ journal }}</a>
+                </li>
+            {% endfor %}
         </ul>
     </div>
+    <div class="col-md-6">
+        <h3>Manage metadata per issue:</h3>
+        {% if journal.has_issues %}
+            <ul class="links">
+              {% for volume in journal.volumes.all %}
+                  {% for issue in volume.issues.all %}
+                      {% url 'journals:manage_metadata' issue_doi_label=journal.doi_label as url %}
+                      <li class="{% if url == request.path %}active{% endif %}">
+                        <a href="{{ url }}">{{ issue }}</a>
+                      </li>
+                  {% endfor %}
+              {% empty %}
+                <li><em>There are no Volumes and Issues for this Journal</em></li>
+              {% endfor %}
+            </ul>
+        {% else %}
+            <em>This Journal does not have Issues, but individual Publications.</em>
+        {% endif %}
+    </div>
 </div>
 
 
diff --git a/journals/templates/journals/publication_detail.html b/journals/templates/journals/publication_detail.html
index f8d8085e3..20f08ba69 100644
--- a/journals/templates/journals/publication_detail.html
+++ b/journals/templates/journals/publication_detail.html
@@ -189,7 +189,7 @@
                   <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'test' %}">Test metadata deposit (via Crossref test server)</a></li>
                   <li><a href="{% url 'journals:metadata_xml_deposit' publication.doi_label 'deposit' %}">Deposit the metadata to Crossref</a></li>
                   <li><a href="{% url 'journals:harvest_citedby_links' publication.doi_label %}">Update Crossref cited-by links</a></li>
-                  <li><a href="{% url 'journals:manage_metadata' %}">Metadata management page</a></li>
+                  <li><a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">Metadata management page</a></li>
         	      <li><a href="{% url 'journals:manage_metadata' doi_label=publication.doi_label %}">This publication's metadata management page</a></li>
                   <li><a href="{% url 'journals:update_references' doi_label=publication.doi_label %}">Update references</a></li>
                   {% if not publication.is_published %}
diff --git a/journals/templates/journals/publication_form.html b/journals/templates/journals/publication_form.html
index 6217eef9d..8d46616c3 100644
--- a/journals/templates/journals/publication_form.html
+++ b/journals/templates/journals/publication_form.html
@@ -9,7 +9,7 @@
 
 <h1>Draft publication</h1>
 
-{% if request.GET.issue or form.instance.id %}
+{% if request.GET.issue or form.instance.id or form.to_journal %}
     <form method="post" enctype="multipart/form-data">
         {% csrf_token %}
         {{ form|bootstrap }}
diff --git a/journals/templates/xml/publication_crossref.html b/journals/templates/xml/publication_crossref.html
index 2d5eba9f2..f4fb35034 100644
--- a/journals/templates/xml/publication_crossref.html
+++ b/journals/templates/xml/publication_crossref.html
@@ -11,24 +11,36 @@
     </head>
     <body>
         <journal>
-            <journal_metadata>
-                <full_title>{{ publication.in_issue.in_volume.in_journal.get_name_display }}</full_title>
-                <abbrev_title>{{ publication.in_issue.in_volume.in_journal.abbreviation_citation }}</abbrev_title>
-                <issn media_type='electronic'>{{ publication.in_issue.in_volume.in_journal.issn }}</issn>
-                <doi_data>
-                    <doi>{{ publication.in_issue.in_volume.in_journal.doi_string }}</doi>
-                    <resource>https://scipost.org/{{ publication.in_issue.in_volume.in_journal.doi_string }}</resource>
-                </doi_data>
-            </journal_metadata>
-            <journal_issue>
-                <publication_date media_type='online'>
-                    <year>{{ publication.publication_date|date:'Y' }}</year>
-                </publication_date>
-                <journal_volume>
-                    <volume>{{ publication.in_issue.in_volume.number }}</volume>
-                </journal_volume>
-                <issue>{{ publication.in_issue.number }}</issue>
-            </journal_issue>
+            {% if publication.in_issue %}
+                <journal_metadata>
+                    <full_title>{{ publication.in_issue.in_volume.in_journal.get_name_display }}</full_title>
+                    <abbrev_title>{{ publication.in_issue.in_volume.in_journal.abbreviation_citation }}</abbrev_title>
+                    <issn media_type='electronic'>{{ publication.in_issue.in_volume.in_journal.issn }}</issn>
+                    <doi_data>
+                        <doi>{{ publication.in_issue.in_volume.in_journal.doi_string }}</doi>
+                        <resource>https://scipost.org/{{ publication.in_issue.in_volume.in_journal.doi_string }}</resource>
+                    </doi_data>
+                </journal_metadata>
+                <journal_issue>
+                    <publication_date media_type='online'>
+                        <year>{{ publication.publication_date|date:'Y' }}</year>
+                    </publication_date>
+                    <journal_volume>
+                        <volume>{{ publication.in_issue.in_volume.number }}</volume>
+                    </journal_volume>
+                    <issue>{{ publication.in_issue.number }}</issue>
+                </journal_issue>
+            {% else %}
+                <journal_metadata>
+                    <full_title>{{ publication.in_journal.get_name_display }}</full_title>
+                    <abbrev_title>{{ publication.in_journal.abbreviation_citation }}</abbrev_title>
+                    <issn media_type='electronic'>{{ publication.in_journal.issn }}</issn>
+                    <doi_data>
+                        <doi>{{ publication.in_journal.doi_string }}</doi>
+                        <resource>https://scipost.org/{{ publication.in_journal.doi_string }}</resource>
+                    </doi_data>
+                </journal_metadata>
+            {% endif %}
             <journal_article publication_type='full_text'>
                 <titles>
                     <title>{{ publication.title }}</title>
diff --git a/journals/urls/general.py b/journals/urls/general.py
index 0293ca043..bf2d672b4 100644
--- a/journals/urls/general.py
+++ b/journals/urls/general.py
@@ -4,8 +4,10 @@ from django.views.generic import TemplateView, RedirectView
 
 from submissions.constants import SUBMISSIONS_COMPLETE_REGEX
 
+from journals.constants import PUBLICATION_DOI_REGEX, REGEX_CHOICES
 from journals import views as journals_views
 
+
 urlpatterns = [
     # Journals
     url(r'^$', journals_views.journals, name='journals'),
@@ -22,64 +24,76 @@ urlpatterns = [
     url(r'^admin/publications/{regex}/$'.format(regex=SUBMISSIONS_COMPLETE_REGEX),
         journals_views.DraftPublicationUpdateView.as_view(),
         name='update_publication'),
-    url(r'^admin/publications/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/publish$',
+    url(r'^admin/publications/(?P<doi_label>{regex})/publish$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.PublicationPublishView.as_view(),
         name='publish_publication'),
-    url(r'^admin/publications/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/approval$',
+    url(r'^admin/publications/(?P<doi_label>{regex})/approval$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.DraftPublicationApprovalView.as_view(),
         name='send_publication_for_approval'),
-    url(r'^admin/publications/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/grants$',
+    url(r'^admin/publications/(?P<doi_label>{regex})/grants$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.PublicationGrantsView.as_view(),
         name='update_grants'),
-    url(r'^admin/publications/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/grants/(?P<grant_id>[0-9]+)/remove$',
+    url(r'^admin/publications/(?P<doi_label>{regex})/grants/(?P<grant_id>[0-9]+)/remove$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.PublicationGrantsRemovalView.as_view(),
         name='remove_grant'),
 
     # Editorial and Administrative Workflow
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/authors/add/(?P<contributor_id>[0-9]+)$',
+    url(r'^admin/(?P<doi_label>{regex})/authors/add/(?P<contributor_id>[0-9]+)$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.add_author,
         name='add_author'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/authors/add$',
+    url(r'^admin/(?P<doi_label>{regex})/authors/add$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.add_author,
         name='add_author'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/authors/mark_first/(?P<author_object_id>[0-9]+)$',
+    url(r'^admin/(?P<doi_label>{regex})/authors/mark_first/(?P<author_object_id>[0-9]+)$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.mark_first_author,
         name='mark_first_author'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/manage_metadata$',
+    url(r'^admin/(?P<doi_label>{regex})/manage_metadata$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.manage_metadata,
         name='manage_metadata'),
     url(r'^admin/(?P<issue_doi_label>[a-zA-Z]+.[0-9]+.[0-9]+)/manage_metadata$',
         journals_views.manage_metadata,
         name='manage_metadata'),
+    url(r'^admin/(?P<journal_doi_label>{regex})/manage_metadata$'.format(regex=REGEX_CHOICES),
+        journals_views.manage_metadata,
+        name='manage_metadata'),
     url(r'^admin/manage_metadata/$',
         journals_views.manage_metadata,
         name='manage_metadata'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/citation_list_metadata$',
+    url(r'^admin/(?P<doi_label>{regex})/citation_list_metadata$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.CitationUpdateView.as_view(),
         name='create_citation_list_metadata'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/update_references$',
+    url(r'^admin/(?P<doi_label>{regex})/update_references$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.update_references, name='update_references'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/funders/create_metadata$',
+    url(r'^admin/(?P<doi_label>{regex})/funders/create_metadata$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.FundingInfoView.as_view(),
         name='create_funding_info_metadata'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/funders/add_generic$',
+    url(r'^admin/(?P<doi_label>{regex})/funders/add_generic$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.add_generic_funder,
         name='add_generic_funder'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/grants/add$',
+    url(r'^admin/(?P<doi_label>{regex})/grants/add$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.add_associated_grant,
         name='add_associated_grant'),
 
     # Metadata handling
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/metadata/crossref/create$',
+    url(r'^admin/(?P<doi_label>{regex})/metadata/crossref/create$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.CreateMetadataXMLView.as_view(),
         name='create_metadata_xml'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/metadata/crossref/deposit/(?P<option>[a-z]+)$',
+    url(r'^admin/(?P<doi_label>{regex})/metadata/crossref/deposit/(?P<option>[a-z]+)$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.metadata_xml_deposit,
         name='metadata_xml_deposit'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/metadata/DOAJ$',
+    url(r'^admin/(?P<doi_label>{regex})/metadata/DOAJ$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.produce_metadata_DOAJ,
         name='produce_metadata_DOAJ'),
-    url(r'^admin/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/metadata/DOAJ/deposit$',
+    url(r'^admin/(?P<doi_label>{regex})/metadata/DOAJ/deposit$'.format(
+            regex=PUBLICATION_DOI_REGEX),
         journals_views.metadata_DOAJ_deposit,
         name='metadata_DOAJ_deposit'),
     url(r'^admin/metadata/crossref/(?P<deposit_id>[0-9]+)/mark/(?P<success>[0-1])$',
@@ -102,7 +116,7 @@ urlpatterns = [
     url(r'^admin/citedby/$',
         journals_views.harvest_citedby_list,
         name='harvest_citedby_list'),
-    url(r'^admin/citedby/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/harvest$',
+    url(r'^admin/citedby/(?P<doi_label>{regex})/harvest$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.harvest_citedby_links,
         name='harvest_citedby_links'),
 
diff --git a/journals/urls/journal.py b/journals/urls/journal.py
index 5cffb7d42..e8526ee4d 100644
--- a/journals/urls/journal.py
+++ b/journals/urls/journal.py
@@ -4,9 +4,9 @@ from journals import views as journals_views
 
 urlpatterns = [
     # Journal routes
-    url(r'^issues$', journals_views.issues, name='issues'),
-    url(r'^recent$', journals_views.recent, name='recent'),
-    url(r'^accepted$', journals_views.accepted, name='accepted'),
+    url(r'^issues$', journals_views.IssuesView.as_view(), name='issues'),
+    url(r'^recent$', journals_views.RecentView.as_view(), name='recent'),
+    url(r'^accepted$', journals_views.AcceptedView.as_view(), name='accepted'),
     url(r'^info_for_authors$', journals_views.info_for_authors, name='info_for_authors'),
     url(r'^about$', journals_views.about, name='about'),
 ]
diff --git a/journals/views.py b/journals/views.py
index e898a47de..5f2571efa 100644
--- a/journals/views.py
+++ b/journals/views.py
@@ -21,10 +21,10 @@ from django.utils import timezone
 from django.utils.decorators import method_decorator
 from django.views.generic.detail import DetailView
 from django.views.generic.edit import UpdateView
-from django.shortcuts import get_object_or_404, render, redirect
+from django.shortcuts import get_object_or_404, get_list_or_404, render, redirect
 
 from .constants import STATUS_DRAFT
-from .helpers import paper_nr_string, issue_doi_label_from_doi_label
+from .helpers import issue_doi_label_from_doi_label
 from .models import Journal, Issue, Publication, Deposit, DOAJDeposit,\
                     GenericDOIDeposit, PublicationAuthorsTable
 from .forms import FundingInfoForm,\
@@ -36,7 +36,7 @@ from .utils import JournalUtils
 
 from comments.models import Comment
 from funders.forms import FunderSelectForm, GrantSelectForm
-from funders.models import Funder, Grant
+from funders.models import Grant
 from submissions.models import Submission, Report
 from scipost.forms import ConfirmationForm
 from scipost.models import Contributor
@@ -68,11 +68,11 @@ def landing_page(request, doi_label):
     if journal.has_issues:
         current_issue = Issue.objects.published().filter(
             in_volume__in_journal=journal,
-            start_date__lte=timezone.now,
-            until_date__gte=timezone.now).first()
+            start_date__lte=timezone.now(),
+            until_date__gte=timezone.now()).first()
         latest_issue = Issue.objects.published().filter(
             in_volume__in_journal=journal,
-            until_date__lte=timezone.now).first()
+            until_date__lte=timezone.now()).first()
         prev_issue = None
         if current_issue:
             prev_issue = Issue.objects.published().filter(
@@ -85,65 +85,56 @@ def landing_page(request, doi_label):
             'prev_issue': prev_issue,
         })
     else:
-        context['publications'] = journal.publications.published()
+        paginator = Paginator(journal.publications.published(), 10)
+        context.update({
+            'page_object': paginator.page(request.GET.get('page', 1)),
+        })
     return render(request, 'journals/journal_landing_page.html', context)
 
 
-def issues(request, doi_label):
-    journal = get_object_or_404(Journal.objects.has_issues(), doi_label=doi_label)
-
-    issues = Issue.objects.published().filter(in_volume__in_journal=journal)
-    context = {
-        'issues': issues,
-        'journal': journal
-    }
-    return render(request, 'journals/journal_issues.html', context)
+class IssuesView(DetailView):
+    """
+    List all Issues sorted per Journal.
+    """
+    queryset = Journal.objects.has_issues()
+    slug_field = slug_url_kwarg = 'doi_label'
+    template_name = 'journals/journal_issues.html'
 
 
-def recent(request, doi_label):
+class RecentView(DetailView):
     """
-    Display page for the most recent 20 publications in SciPost Physics.
+    List all recent Publications for a specific Journal.
     """
-    journal = get_object_or_404(Journal, doi_label=doi_label)
-    recent_papers = Publication.objects.published().filter(
-        in_issue__in_volume__in_journal=journal).order_by('-publication_date',
-                                                          '-paper_nr')[:20]
-    context = {
-        'recent_papers': recent_papers,
-        'journal': journal,
-    }
-    return render(request, 'journals/journal_recent.html', context)
+    queryset = Journal.objects.active()
+    slug_field = slug_url_kwarg = 'doi_label'
+    template_name = 'journals/journal_recent.html'
 
 
-def accepted(request, doi_label):
+class AcceptedView(DetailView):
     """
-    Display page for submissions to SciPost Physics which
-    have been accepted but are not yet published.
+    List all Submissions for a specific Journal which have been accepted but are not
+    yet published.
     """
-    journal = get_object_or_404(Journal, doi_label=doi_label)
-    accepted_SP_submissions = (Submission.objects.accepted()
-                               .filter(submitted_to_journal=journal.name)
-                               .order_by('-latest_activity'))
-    context = {
-        'accepted_SP_submissions': accepted_SP_submissions,
-        'journal': journal
-    }
-    return render(request, 'journals/journal_accepted.html', context)
+    queryset = Journal.objects.active()
+    slug_field = slug_url_kwarg = 'doi_label'
+    template_name = 'journals/journal_accepted.html'
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context['accepted_submissions'] = Submission.objects.accepted().filter(
+            submitted_to_journal=context['journal'].name).order_by('-latest_activity')
+        return context
 
 
 def info_for_authors(request, doi_label):
     journal = get_object_or_404(Journal, doi_label=doi_label)
-    context = {
-        'journal': journal
-    }
+    context = {'journal': journal}
     return render(request, 'journals/%s_info_for_authors.html' % doi_label, context)
 
 
 def about(request, doi_label):
     journal = get_object_or_404(Journal, doi_label=doi_label)
-    context = {
-        'journal': journal
-    }
+    context = {'journal': journal}
     return render(request, 'journals/%s_about.html' % doi_label, context)
 
 
@@ -251,19 +242,40 @@ class PublicationPublishView(PermissionsMixin, RequestViewMixin, UpdateView):
 
 
 @permission_required('scipost.can_publish_accepted_submission', return_403=True)
-def manage_metadata(request, issue_doi_label=None, doi_label=None):
-    issues = Issue.objects.all().order_by('-until_date')
-    publications = Publication.objects.all()
+def manage_metadata(request, doi_label=None, issue_doi_label=None, journal_doi_label=None):
+    journal = None
+    journals = Journal.objects.all()
+    issue = None
+
     if doi_label:
-        issue_doi_label = issue_doi_label_from_doi_label(doi_label)
-    if issue_doi_label:
-        publications = publications.filter(in_issue__doi_label=issue_doi_label)
-    publications = publications.order_by('-publication_date', '-paper_nr')
+        publications = get_list_or_404(Publication, doi_label=doi_label)
+        journal = publications[0].get_journal()
+    elif issue_doi_label:
+        issue = get_object_or_404(Issue, doi_label=issue_doi_label)
+        if issue.in_volume:
+            journal = issue.in_volume.in_journal
+        else:
+            journal = issue.in_journal
+        publications = issue.publications.all()
+    elif journal_doi_label:
+        journal = get_object_or_404(Journal, doi_label=journal_doi_label)
+        publications = Publication.objects.for_journal(journal.name)
+    else:
+        # Limit the amount of Publications to still an idiot size
+        publications = Publication.objects.all()[:50]
+
+    # Speeds up operations by reducing the number of queries
+    if not isinstance(publications, list):
+        publications = publications.prefetch_related(
+            'authors', 'funders_generic', 'deposit_set', 'doajdeposit_set')
+
     associate_grant_form = GrantSelectForm()
     associate_generic_funder_form = FunderSelectForm()
     context = {
-        'issues': issues,
+        'journal': journal,
+        'journals': journals,
         'issue_doi_label': issue_doi_label,
+        'journal_doi_label': journal_doi_label,
         'publications': publications,
         'associate_grant_form': associate_grant_form,
         'associate_generic_funder_form': associate_generic_funder_form,
@@ -446,13 +458,27 @@ def metadata_xml_deposit(request, doi_label, option='test'):
         return redirect(reverse('journals:create_metadata_xml',
                                 kwargs={'doi_label': publication.doi_label}))
 
-    timestamp = (publication.metadata_xml.partition(
-        '<timestamp>'))[2].partition('</timestamp>')[0]
-    doi_batch_id = (publication.metadata_xml.partition(
-        '<doi_batch_id>'))[2].partition('</doi_batch_id>')[0]
-    path = (settings.MEDIA_ROOT + publication.in_issue.path + '/'
-            + publication.get_paper_nr() + '/' + publication.doi_label.replace('.', '_')
-            + '_Crossref_' + timestamp + '.xml')
+    timestamp = publication.metadata_xml.partition(
+        '<timestamp>')[2].partition('</timestamp>')[0]
+    doi_batch_id = publication.metadata_xml.partition(
+        '<doi_batch_id>')[2].partition('</doi_batch_id>')[0]
+
+    # Find Crossref xml files
+    path = settings.MEDIA_ROOT
+    if publication.in_issue:
+        path += '{issue_path}/{paper_nr}/{doi_label}_Crossref'.format(
+            issue_path=publication.in_issue.path,
+            paper_nr=publication.get_paper_nr(),
+            doi_label=publication.doi_label.replace('.', '_'))
+
+    if publication.in_journal:
+        path += 'SCIPOST_JOURNALS/{journal_name}/{paper_nr}/{doi_label}_Crossref'.format(
+            journal_name=publication.in_journal.name,
+            paper_nr=publication.get_paper_nr(),
+            doi_label=publication.doi_label.replace('.', '_'))
+
+    path_wo_timestamp = path + '.xml'
+    path += '_{timestamp}.xml'.format(timestamp=timestamp)
 
     valid = True
     response_headers = None
@@ -463,7 +489,7 @@ def metadata_xml_deposit(request, doi_label, option='test'):
     else:
         # New deposit, go for it.
         if option == 'deposit' and not settings.DEBUG:
-            # CAUTION: Real deposit only on production (non-debug-mode)
+            # CAUTION: Real deposit only on production!
             url = 'http://doi.crossref.org/servlet/deposit'
         else:
             url = 'http://test.crossref.org/servlet/deposit'
@@ -493,24 +519,14 @@ def metadata_xml_deposit(request, doi_label, option='test'):
             deposit.response_text = r.text
 
             # Save the filename with timestamp
-            path_with_timestamp = '{issue}/{paper}/{doi}_Crossref_{timestamp}.xml'.format(
-                issue=publication.in_issue.path,
-                paper=publication.get_paper_nr(),
-                doi=publication.doi_label.replace('.', '_'),
-                timestamp=timestamp)
-            f = open(settings.MEDIA_ROOT + path_with_timestamp, 'w', encoding='utf-8')
+            f = open(settings.MEDIA_ROOT + path, 'w', encoding='utf-8')
             f.write(publication.metadata_xml)
             f.close()
 
-            # Copy file
-            path_without_timestamp = '{issue}/{paper}/{doi}_Crossref.xml'.format(
-                issue=publication.in_issue.path,
-                paper=publication.get_paper_nr(),
-                doi=publication.doi_label.replace('.', '_'))
-            shutil.copyfile(settings.MEDIA_ROOT + path_with_timestamp,
-                            settings.MEDIA_ROOT + path_without_timestamp)
-
-            deposit.metadata_xml_file = path_with_timestamp
+            # Update Crossref timestamp-free file to latest deposit
+            shutil.copyfile(settings.MEDIA_ROOT + path,
+                            settings.MEDIA_ROOT + path_wo_timestamp)
+            deposit.metadata_xml_file = path
             deposit.save()
             publication.latest_crossref_deposit = timezone.now()
             publication.save()
@@ -567,11 +583,24 @@ def metadata_DOAJ_deposit(request, doi_label):
                                   'DOAJ metadata before depositing.' % publication.doi_label)
         return redirect(reverse('journals:manage_metadata'))
 
-    timestamp = (publication.metadata_xml.partition(
-        '<timestamp>'))[2].partition('</timestamp>')[0]
-    path = (settings.MEDIA_ROOT + publication.in_issue.path + '/'
-            + publication.get_paper_nr() + '/' + publication.doi_label.replace('.', '_')
-            + '_DOAJ_' + timestamp + '.json')
+    timestamp = publication.metadata_xml.partition('<timestamp>')[2].partition('</timestamp>')[0]
+
+    # Find DOAJ xml files
+    path = settings.MEDIA_ROOT
+    if publication.in_issue:
+        path += '{issue_path}/{paper_nr}/{doi_label}_DOAJ'.format(
+            issue_path=publication.in_issue.path,
+            paper_nr=publication.get_paper_nr(),
+            doi_label=publication.doi_label.replace('.', '_'))
+    elif publication.in_journal:
+        path += 'SCIPOST_JOURNALS/{journal_name}/{paper_nr}/{doi_label}_DOAJ'.format(
+            journal_name=publication.in_journal.name,
+            paper_nr=publication.get_paper_nr(),
+            doi_label=publication.doi_label.replace('.', '_'))
+
+    path_wo_timestamp = path + '.json'
+    path += '_{timestamp}.json'.format(timestamp=timestamp)
+
     if os.path.isfile(path):
         errormessage = 'The metadata file for this metadata timestamp already exists'
         return render(request, 'scipost/error.html', context={'errormessage': errormessage})
@@ -593,25 +622,16 @@ def metadata_DOAJ_deposit(request, doi_label):
     deposit.response_text = r.text
 
     # Save a copy to the filename with and without timestamp
-    path_with_timestamp = '{issue}/{paper}/{doi}_DOAJ_{timestamp}.json'.format(
-        issue=publication.in_issue.path,
-        paper=publication.get_paper_nr(),
-        doi=publication.doi_label.replace('.', '_'),
-        timestamp=timestamp)
-    f = open(settings.MEDIA_ROOT + path_with_timestamp, 'w')
+    f = open(settings.MEDIA_ROOT + path, 'w')
     f.write(json.dumps(publication.metadata_DOAJ))
     f.close()
 
     # Copy file
-    path_without_timestamp = '{issue}/{paper}/{doi}_DOAJ.json'.format(
-        issue=publication.in_issue.path,
-        paper=publication.get_paper_nr(),
-        doi=publication.doi_label.replace('.', '_'))
-    shutil.copyfile(settings.MEDIA_ROOT + path_with_timestamp,
-                    settings.MEDIA_ROOT + path_without_timestamp)
+    shutil.copyfile(settings.MEDIA_ROOT + path,
+                    settings.MEDIA_ROOT + path_wo_timestamp)
 
     # Save the database entry
-    deposit.metadata_DOAJ_file = path_with_timestamp
+    deposit.metadata_DOAJ_file = path
     deposit.save()
 
     messages.success(request, '<h3>%s</h3>Successfull deposit of metadata DOAJ.'
diff --git a/scipost/static/scipost/assets/css/_list_group.scss b/scipost/static/scipost/assets/css/_list_group.scss
index b598898a0..c2313938b 100644
--- a/scipost/static/scipost/assets/css/_list_group.scss
+++ b/scipost/static/scipost/assets/css/_list_group.scss
@@ -45,3 +45,7 @@ ul.references {
         margin: 0 0 0.2rem 2rem;
     }
 }
+
+ul.links > li.active a {
+    font-weight: 700;
+}
diff --git a/scipost/urls.py b/scipost/urls.py
index 9da0a19f2..862b31635 100644
--- a/scipost/urls.py
+++ b/scipost/urls.py
@@ -7,7 +7,7 @@ from .feeds import LatestNewsFeedRSS, LatestNewsFeedAtom, LatestCommentsFeedRSS,
                    LatestPublicationsFeedRSS, LatestPublicationsFeedAtom
 
 from journals import views as journals_views
-from journals.constants import REGEX_CHOICES
+from journals.constants import REGEX_CHOICES, PUBLICATION_DOI_REGEX
 from submissions import views as submission_views
 
 JOURNAL_REGEX = '(?P<doi_label>%s)' % REGEX_CHOICES
@@ -185,16 +185,16 @@ urlpatterns = [
         name='author_reply_detail'),
 
     # Publication detail (+pdf)
-    url(r'^10.21468/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
+    url(r'^10.21468/(?P<doi_label>{regex})$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.publication_detail,
         name='publication_detail'),
-    url(r'^(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})$',
+    url(r'^(?P<doi_label>{regex})$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.publication_detail,
         name='publication_detail'),
-    url(r'^10.21468/(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/pdf$',
+    url(r'^10.21468/(?P<doi_label>{regex})/pdf$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.publication_detail_pdf,
         name='publication_pdf'),
-    url(r'^(?P<doi_label>[a-zA-Z]+.[0-9]+.[0-9]+.[0-9]{3,})/pdf$',
+    url(r'^(?P<doi_label>{regex})/pdf$'.format(regex=PUBLICATION_DOI_REGEX),
         journals_views.publication_detail_pdf,
         name='publication_pdf'),
 
diff --git a/submissions/templates/submissions/submission_list.html b/submissions/templates/submissions/submission_list.html
index 05e114e3f..ca2cefaf7 100644
--- a/submissions/templates/submissions/submission_list.html
+++ b/submissions/templates/submissions/submission_list.html
@@ -44,7 +44,7 @@
 <div class="row">
     <div class="col-12">
         {% if recent %}
-          <h2>Recent Submissions:</h2>
+          <h2>Recent Submissions{% if to_journal %} to {{ to_journal }}{% endif %}:</h2>
         {% elif browse %}
           <h2>Submissions in {{ discipline }} in the last {{ nrweeksback }} week{% if nrweeksback == '1' %}{% else %}s{% endif %}:</h2>
         {% else %}
diff --git a/submissions/views.py b/submissions/views.py
index 382fa6213..3df758bca 100644
--- a/submissions/views.py
+++ b/submissions/views.py
@@ -1,5 +1,6 @@
 import datetime
 import feedparser
+import strings
 
 from django.contrib import messages
 from django.contrib.auth.decorators import login_required, permission_required
@@ -36,19 +37,17 @@ from .forms import SubmissionIdentifierForm, RequestSubmissionForm, SubmissionSe
 from .utils import SubmissionUtils
 
 from colleges.permissions import fellowship_required, fellowship_or_admin_required
-from mails.views import MailEditingSubView
-from scipost.forms import ModifyPersonalMessageForm, RemarkForm
-from scipost.mixins import PaginationMixin
-from scipost.models import Contributor, Remark
-
 from comments.forms import CommentForm
 from invitations.constants import INVITATION_REFEREEING
 from invitations.models import RegistrationInvitation
+from journals.models import Journal
 from mails.utils import DirectMailUtil
+from mails.views import MailEditingSubView
 from production.forms import ProofsDecisionForm
 from production.models import ProductionStream
-
-import strings
+from scipost.forms import ModifyPersonalMessageForm, RemarkForm
+from scipost.mixins import PaginationMixin
+from scipost.models import Contributor, Remark
 
 
 ###############
@@ -136,10 +135,10 @@ class SubmissionListView(PaginationMixin, ListView):
     def get_queryset(self):
         queryset = Submission.objects.public_newest()
         self.form = self.form(self.request.GET)
-        if 'to_journal' in self.kwargs:
+        if 'to_journal' in self.request.GET:
             queryset = queryset.filter(
                 latest_activity__gte=timezone.now() + datetime.timedelta(days=-60),
-                submitted_to_journal=self.kwargs['to_journal']
+                submitted_to_journal=self.request.GET['to_journal']
             )
         elif 'discipline' in self.kwargs and 'nrweeksback' in self.kwargs:
             discipline = self.kwargs['discipline']
@@ -161,8 +160,12 @@ class SubmissionListView(PaginationMixin, ListView):
         context['form'] = self.form
 
         # To customize display in the template
-        if 'to_journal' in self.kwargs:
-            context['to_journal'] = self.kwargs['to_journal']
+        if 'to_journal' in self.request.GET:
+            try:
+                context['to_journal'] = Journal.objects.filter(
+                    name=self.request.GET['to_journal']).first().get_name_display()
+            except (Journal.DoesNotExist, AttributeError):
+                context['to_journal'] = self.request.GET['to_journal']
         if 'discipline' in self.kwargs:
             context['discipline'] = self.kwargs['discipline']
             context['nrweeksback'] = self.kwargs['nrweeksback']
-- 
GitLab