Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions docs/md/journal-visibility-and-publishing-status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Journal visibility and publishing status

Janeway has several mechanisms for allowing editors and press managers to control content visibility and filter data streams for each journal.

The following Journal fields provide the configuration options:

- `Journal.hide_from_press`
- `Journal.status`

## What are some example use cases for these configuration options?

Users may find it tricky to distinguish `hide_from_press` and the "Test" publishing status. But they have to remain distinct for a few use cases. Here are some.

### Not hidden from press

* Active: publishing normally
* Archived: no longer publishing but have a backlist
* Coming soon: planning to start publishing soon
* Test: not applicable, as users should always hide test journals from the press

### Hidden from press

* Active: publishing normally but do not wish to be listed on the publisher site
* Archived: no longer published by the press but back content is still available at the journal site
* Coming soon: planning to start publishing soon but want to avoid appearing on the press site
* Test: testing options and training editors

## What areas are affected by these configuration options?

The `hide_from_press` field does exactly what it says--it puts up a wall between the journal and press, preventing records like `Journal`, like `Issue`, `Section`, `Article`, and `NewsItem` from showing up on press level websites and APIs.

The "Test" publishing status prevents users from accidentally sending data to places it is difficult to remove, like DOI registration. It does not interfere with anything else, including sitemaps, APIs, or RSS feeds, because these too are features that users would want to test at the journal level. This is why it is important for test journals to have `hide_from_press` turned on.

### User interfaces

| Area | Hide from press | Test status |
|-------------------------------------------|-------------------|-------------|
| Lists of journals on press website | Does what it says | No effect |
| Journal submission in repository system | No effect | Prevented |
| Publications list on public user profiles | Does what it says | Not listed |
| Back-office menus that list journals | No effect | No effect |
| Django admin menus that list journals | No effect | No effect |
| Reporting (plugin) | Does what it says | No effect |

### Data feeds and alternate user interfaces

| Area | Hide from press | Test status |
|----------------------------|-------------------|-----------------------------------|
| sitemaps | Does what it says | No effect |
| APIs | Does what it says | No effect |
| RSS/Atom feed | Does what it says | No effect |
| reader notifications | Not applicable | No effect |
| Crossref deposits | Not applicable | Deposits use Crossref test server |
| Datacite deposits (plugin) | Not applicable | Deposits use Datacite test server |
| Galley healthcheck command | Not applicable | Articles ignored |
| DOI check command | Not applicable | Articles ignored |
| Store ithenticate command | Not applicable | Articles ignored |
| Metrics core app | Does what it says | Articles excluded |
17 changes: 16 additions & 1 deletion src/api/oai/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
A django implementation of the OAI-PMH interface
"""

import warnings

from django.utils import timezone
from django.views.generic.base import TemplateView

Expand Down Expand Up @@ -50,7 +52,6 @@ class OAIListRecords(OAIPagedModelView):

def get_queryset(self):
queryset = super().get_queryset()

if self.request.journal:
queryset = queryset.filter(journal=self.request.journal)
else:
Expand Down Expand Up @@ -217,6 +218,10 @@ def get_context_data(self, *args, **kwargs):
journal=self.request.journal,
stage=submission_models.STAGE_PUBLISHED,
)
else:
articles = articles.filter(
journal__hide_from_press=False,
)

context["earliest_article"] = articles.earliest("date_published")
context["verb"] = self.request.GET.get("verb")
Expand Down Expand Up @@ -247,6 +252,16 @@ def get_context_data(self, *args, **kwargs):
sections = sections.filter(
journal=self.request.journal,
)
else:
journals = journals.filter(
hide_from_press=False,
)
all_issues = all_issues.filter(
journal__hide_from_press=False,
)
sections = sections.filter(
journal__hide_from_press=False,
)

context["journals"] = journals
context["all_issues"] = all_issues
Expand Down
50 changes: 49 additions & 1 deletion src/api/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
from django.test import TestCase, override_settings
from django.urls import reverse
from django.utils import timezone

from rest_framework.test import APIClient

from utils.testing import helpers
from core import models as core_models
from submission import models as submission_models


class TestAPI(TestCase):
@classmethod
def setUpTestData(cls):
cls.press = helpers.create_press()
cls.journal, _ = helpers.create_journals()
cls.journal, cls.hidden_journal = helpers.create_journals()
cls.hidden_journal.hide_from_press = True
cls.hidden_journal.save()
cls.staff_member = helpers.create_user(
username="t.paris@voyager.com",
roles=["author"],
Expand All @@ -34,6 +38,14 @@ def setUpTestData(cls):
helpers.create_roles(
["journal-manager"],
)
cls.hidden_article = helpers.create_article(
cls.hidden_journal,
with_author=True,
title="Article in journal hidden from press",
)
cls.hidden_article.stage = submission_models.STAGE_PUBLISHED
cls.hidden_article.date_published = timezone.now()
cls.hidden_article.save()
cls.api_client = APIClient()

@override_settings(URL_CONFIG="domain")
Expand Down Expand Up @@ -89,3 +101,39 @@ def test_editor_cannot_assign_journal_manager_role(self):
journal_manager_role,
)
)

@override_settings(URL_CONFIG="domain")
def test_press_api_excludes_journal_hidden_from_press(self):
url = self.press.site_url(reverse("journal-list"))
response = self.api_client.get(
url,
SERVER_NAME=self.press.domain,
)
self.assertNotIn(
self.hidden_journal.pk,
[journal["pk"] for journal in response.json().get("results", [])],
)

@override_settings(URL_CONFIG="domain")
def test_press_api_excludes_article_in_journal_hidden_from_press(self):
url = self.press.site_url(reverse("article-list"))
response = self.api_client.get(
url,
SERVER_NAME=self.press.domain,
)
self.assertNotIn(
self.hidden_article.title,
[article["title"] for article in response.json().get("results", [])],
)

@override_settings(URL_CONFIG="domain")
def test_api_works_at_journal_level_even_if_hidden_from_press(self):
url = self.hidden_journal.site_url(reverse("article-list"))
response = self.api_client.get(
url,
SERVER_NAME=self.hidden_journal.domain,
)
self.assertIn(
self.hidden_article.title,
[article["title"] for article in response.json().get("results", [])],
)
41 changes: 40 additions & 1 deletion src/api/tests/test_oai.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ def assertXMLEqual(self, a, b):
@classmethod
def setUpTestData(cls):
cls.press = helpers.create_press()
cls.journal, _ = helpers.create_journals()
cls.journal, cls.hidden_journal = helpers.create_journals()
cls.hidden_journal.hide_from_press = True
cls.hidden_journal.save()
cls.author = helpers.create_author(cls.journal)
cls.article = helpers.create_submission(
journal_id=cls.journal.pk,
Expand All @@ -86,6 +88,13 @@ def setUpTestData(cls):
)
cls.article.primary_issue = cls.issue
cls.article.save()
cls.hidden_article = helpers.create_article(
cls.hidden_journal,
with_author=True,
stage=sm_models.STAGE_PUBLISHED,
title="Article in journal hidden from press",
date_published="1986-07-12T17:00:00.000+0200",
)

@classmethod
def validate_oai_schema(cls, xml):
Expand Down Expand Up @@ -297,3 +306,33 @@ def test_oai_resumption_token_encode(self):
expected_encoded in unquote_plus(response.context["resumption_token"]),
"Query parameter has not been encoded into resumption_token",
)

@override_settings(URL_CONFIG="domain")
@freeze_time(FROZEN_DATETIME_2012)
def test_list_records_jats_excludes_hidden_journal(self):
path = self.press.site_url(reverse("OAI_list_records"))
query_params = dict(
verb="ListRecords",
metadataPrefix="jats",
)
query_string = urlencode(query_params)
response = self.client.get(
f"{path}?{query_string}",
SERVER_NAME=self.press.domain,
)
self.assertNotIn(self.hidden_article, response.context["object_list"])

@override_settings(URL_CONFIG="domain")
@freeze_time(FROZEN_DATETIME_2012)
def test_list_records_jats_works_at_journal_level_even_if_hidden_from_press(self):
path = self.hidden_journal.site_url(reverse("OAI_list_records"))
query_params = dict(
verb="ListRecords",
metadataPrefix="jats",
)
query_string = urlencode(query_params)
response = self.client.get(
f"{path}?{query_string}",
SERVER_NAME=self.hidden_journal.domain,
)
self.assertIn(self.hidden_article, response.context["object_list"])
6 changes: 3 additions & 3 deletions src/api/tests/test_oai_data/get_record_data_until.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ListRecords>
<record>
<header>
<identifier>oai:TST:id:2</identifier>
<identifier>oai:TST:id:3</identifier>
<datestamp>1975-01-01T15:00:00Z</datestamp>
</header>
<metadata>
Expand All @@ -27,8 +27,8 @@
<dc:type>info:eu-repo/semantics/article</dc:type>
<dc:publisher>Press</dc:publisher>
<dc:journalTitle>Journal One</dc:journalTitle>
<dc:identifier>http://testserver/article/id/2/</dc:identifier>
<dc:fullTextUrl>http://testserver/article/id/2/</dc:fullTextUrl>
<dc:identifier>http://testserver/article/id/3/</dc:identifier>
<dc:fullTextUrl>http://testserver/article/id/3/</dc:fullTextUrl>
<dc:source>0000-0000</dc:source>
<dc:format.extent>1</dc:format.extent>
</oai_dc:dc>
Expand Down
42 changes: 28 additions & 14 deletions src/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import io
import json
import re
import warnings

from django.apps import apps
from django.http import HttpResponse
from django.shortcuts import render
from django.utils import timezone
Expand Down Expand Up @@ -76,35 +78,39 @@ class JournalViewSet(viewsets.ModelViewSet):
API Endpoint for journals.
"""

from journal import models as journal_models

queryset = journal_models.Journal.objects.filter(hide_from_press=False)
serializer_class = serializers.JournalSerializer
http_method_names = ["get"]

def get_queryset(self):
Journal = apps.get_model("journal.Journal")
if self.request.journal:
queryset = Journal.objects.filter(pk=self.request.journal.pk)
else:
queryset = Journal.objects.filter(hide_from_press=False)
return queryset


class IssueViewSet(viewsets.ModelViewSet):
"""
API Endpoint for journals.
API endpoint for issues.
"""

serializer_class = serializers.IssueSerializer
http_method_names = ["get"]

def get_queryset(self):
from journal import models as journal_models

Issue = apps.get_model("journal.Issue")
if self.request.journal:
queryset = journal_models.Issue.objects.filter(journal=self.request.journal)
queryset = Issue.objects.filter(journal=self.request.journal)
else:
queryset = journal_models.Issue.objects.all()
queryset = Issue.objects.filter(journal__hide_from_press=False)

return queryset


class LicenceViewSet(viewsets.ModelViewSet):
"""
API Endpoint for journals.
API Endpoint for licenses.
"""

serializer_class = serializers.LicenceSerializer
Expand All @@ -117,7 +123,7 @@ def get_queryset(self):
)
else:
queryset = submission_models.Licence.objects.filter(
journal=self.request.press
press=self.request.press
)

return queryset
Expand All @@ -131,7 +137,7 @@ class KeywordsViewSet(viewsets.ModelViewSet):

class ArticleViewSet(viewsets.ModelViewSet):
"""
API Endpoint for journals.
API endpoint for articles.
"""

serializer_class = serializers.ArticleSerializer
Expand All @@ -148,6 +154,7 @@ def get_queryset(self):
queryset = submission_models.Article.objects.filter(
stage=submission_models.STAGE_PUBLISHED,
date_published__lte=timezone.now(),
journal__hide_from_press=False,
)

return queryset
Expand All @@ -170,6 +177,7 @@ def get_queryset(self):


def oai(request):
warnings.warn("This view is deprecated. OAI views are in api/oai/views.py")
articles = submission_models.Article.objects.filter(
stage=submission_models.STAGE_PUBLISHED
)
Expand Down Expand Up @@ -216,9 +224,15 @@ def kbart(request, tsv=True):
has_header = False
writer = None

for journal in journal_models.Journal.objects.filter(
is_remote=False, hide_from_press=False
):
journals = journal_models.Journal.objects.filter(
is_remote=False,
)

if request.journal:
journals = journals.filter(pk=request.journal.pk)
else:
journals = journals.filter(hide_from_press=False)
for journal in journals:
kbart_embargo = journal.get_setting("kbart", "embargo_period")
# Note that we here use an OrderedDict. This is important as the
# field headers are generated below at the late init of the TSV or
Expand Down
Loading