Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
16 changes: 8 additions & 8 deletions src/core/dev_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
# You should change this key before you go live!
import os

DEBUG = True
DEBUG = False
FORCE_BUILTIN_XSL = False
SECRET_KEY = "uxprsdhk^gzd-r=_287byolxn)$k6tsd8_cepl^s^tms2w1qrv"
SERVE_MEDIA_LOCALLY = True

# This is the default redirect if no other sites are found.
DEFAULT_HOST = "https://www.example.org"
Expand All @@ -17,13 +18,8 @@

URL_CONFIG = "path" # path or domain

MIDDLEWARE = (
"utils.middleware.TimeMonitoring",
"debug_toolbar.middleware.DebugToolbarMiddleware",
)
INSTALLED_APPS = [
"debug_toolbar",
]
MIDDLEWARE = ("utils.middleware.TimeMonitoring",)
INSTALLED_APPS = []


BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
Expand All @@ -38,6 +34,10 @@ def show_toolbar(request):
"SHOW_TOOLBAR_CALLBACK": show_toolbar,
}

if DEBUG:
MIDDLEWARE += ("debug_toolbar.middleware.DebugToolbarMiddleware",)
INSTALLED_APPS += ["debug_toolbar"]

HIJACK_LOGIN_REDIRECT_URL = "/manager/"
HIJACK_USERS_ENABLED = True

Expand Down
5 changes: 5 additions & 0 deletions src/core/include_urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@
core_views.edit_settings_group,
name="core_edit_settings_group",
),
re_path(
r"^manager/settings/journal/keywords/suggest/$",
core_views.journal_keyword_suggestions,
name="core_journal_keyword_suggestions",
),
re_path(
r"^manager/settings/(?P<plugin>[-\w.:]+)/(?P<setting_group_name>[-\w.]+)/(?P<journal>\d+)/$",
core_views.edit_plugin_settings_groups,
Expand Down
14 changes: 11 additions & 3 deletions src/core/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,21 @@
]

try:
if settings.DEBUG or settings.IN_TEST_RUNNER:
import debug_toolbar

if (
settings.DEBUG
or settings.IN_TEST_RUNNER
or getattr(settings, "SERVE_MEDIA_LOCALLY", False)
):
urlpatterns += [
re_path(
r"^media/(?P<path>.*)$", serve, {"document_root": settings.MEDIA_ROOT}
),
]

if settings.DEBUG or settings.IN_TEST_RUNNER:
import debug_toolbar

urlpatterns += [
re_path(r"^404/$", error_views.handler404),
re_path(r"^500/$", error_views.handler500),
path("__debug__/", include("debug_toolbar.urls")),
Expand Down
24 changes: 21 additions & 3 deletions src/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@
from django.shortcuts import render, get_object_or_404, redirect, Http404
from django.utils import timezone
from django.utils.decorators import method_decorator
from django.http import HttpResponse, QueryDict
from django.http import HttpResponse, QueryDict, JsonResponse
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.sessions.models import Session
from django.core.validators import validate_email
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from django.conf import settings as django_settings
from django.views.decorators.http import require_POST
from django.views.decorators.http import require_GET, require_POST
from django.views.decorators.csrf import ensure_csrf_cookie
from django.views.generic import CreateView, UpdateView, DeleteView
from django.contrib.contenttypes.models import ContentType
Expand Down Expand Up @@ -1182,7 +1182,6 @@ def edit_setting(request, setting_group, setting_name):
}
return render(request, template, context)


@staff_member_required
def edit_default_setting(request, setting_group, setting_name):
"""Proxy view for edit_setting allowing editing the default value
Expand Down Expand Up @@ -1285,6 +1284,25 @@ def edit_settings_group(request, display_group):
return render(request, template, context)


@editor_user_required
@require_GET
def journal_keyword_suggestions(request):
"""
Returns a small list of matching existing keywords for journal disciplines.
"""
search_term = request.GET.get("q", "").strip()

current_keyword_ids = request.journal.keywords.values_list("pk", flat=True)
matches = submission_models.Keyword.objects.exclude(pk__in=current_keyword_ids)

if search_term:
matches = matches.filter(word__istartswith=search_term)

matches = matches.order_by("word").values_list("word", flat=True)[:10]

return JsonResponse(list(matches), safe=False)


@editor_user_required
def edit_plugin_settings_groups(
request, plugin, setting_group_name, journal=None, title=None
Expand Down
72 changes: 72 additions & 0 deletions src/security/test_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -4461,6 +4461,78 @@ def test_setting_is_available_in_group(self):
)
self.assertContains(response, "Journal Name")

def test_journal_settings_uses_remote_keyword_suggestions(self):
medicine = submission_models.Keyword.objects.create(word="Medicine")
arts = submission_models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine, arts)

self.client.force_login(self.editor)
response = self.client.get(
reverse(
"core_edit_settings_group",
kwargs={
"display_group": "journal",
},
),
SERVER_NAME="journal1.localhost",
)

self.assertEqual(response.status_code, 200)
self.assertContains(
response,
reverse("core_journal_keyword_suggestions"),
)
self.assertNotContains(response, '"Medicine"')
self.assertNotContains(response, '"Arts"')

def test_journal_keyword_suggestions_returns_matching_keywords(self):
medicine = submission_models.Keyword.objects.create(word="Medicine")
mediation = submission_models.Keyword.objects.create(word="Mediation")
arts = submission_models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine)
self.journal_two.keywords.add(arts)

self.client.force_login(self.editor)
response = self.client.get(
reverse("core_journal_keyword_suggestions"),
{"q": "Me"},
SERVER_NAME="journal1.localhost",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Mediation"])

def test_journal_keyword_suggestions_returns_initial_results_for_empty_query(self):
medicine = submission_models.Keyword.objects.create(word="Medicine")
arts = submission_models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine)
self.journal_two.keywords.add(arts)

self.client.force_login(self.editor)
response = self.client.get(
reverse("core_journal_keyword_suggestions"),
SERVER_NAME="journal1.localhost",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Arts"])

def test_journal_settings_page_requires_three_characters_before_searching(self):
self.client.force_login(self.editor)
response = self.client.get(
reverse(
"core_edit_settings_group",
kwargs={
"display_group": "journal",
},
),
SERVER_NAME="journal1.localhost",
)

self.assertEqual(response.status_code, 200)
self.assertContains(response, "minLength: 3")
self.assertNotContains(response, "showAutocompleteOnFocus: true")

def test_setting_is_removed_from_group(self):
# set the journal_name setting to only be editable by journal managers.
journal_manager_role = core_models.Role.objects.get(
Expand Down
184 changes: 184 additions & 0 deletions src/submission/tests/test_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,190 @@ def test_submit_info_view_form_selection_author(self):
self.assertEqual(response.status_code, 200)
self.assertNotContains(response, section.__str__())

@override_settings(URL_CONFIG="domain")
def test_submit_info_view_shows_journal_disciplines_as_keyword_suggestions(self):
author_1, _ = self.create_authors()
clear_cache()
article = models.Article.objects.create(
journal=self.journal_one,
title="Test article: keyword suggestions",
owner=author_1,
)
medicine = models.Keyword.objects.create(word="Medicine")
arts = models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine, arts)

self.client.force_login(author_1)
clear_script_prefix()
response = self.client.get(
reverse("submit_info", kwargs={"article_id": article.pk}),
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertContains(
response,
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
)
self.assertNotContains(response, '"Medicine"')
self.assertNotContains(response, '"Arts"')

@override_settings(URL_CONFIG="domain")
def test_edit_metadata_view_shows_journal_disciplines_as_keyword_suggestions(self):
article = helpers.create_article(self.journal_one)
medicine = models.Keyword.objects.create(word="Medicine")
arts = models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine, arts)

self.client.force_login(self.editor)
clear_script_prefix()
response = self.client.get(
reverse("edit_metadata", kwargs={"article_id": article.pk}),
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertContains(
response,
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
)
self.assertNotContains(response, '"Medicine"')
self.assertNotContains(response, '"Arts"')

@override_settings(URL_CONFIG="domain")
def test_keyword_suggestions_returns_filtered_journal_keywords(self):
author_1, _ = self.create_authors()
clear_cache()
article = models.Article.objects.create(
journal=self.journal_one,
title="Test article: keyword suggestions endpoint",
owner=author_1,
)
medicine = models.Keyword.objects.create(word="Medicine")
mediation = models.Keyword.objects.create(word="Mediation")
arts = models.Keyword.objects.create(word="Arts")
medieval = models.Keyword.objects.create(word="Medieval")
self.journal_one.keywords.add(medicine, mediation, arts)
self.journal_two.keywords.add(medieval)

self.client.force_login(author_1)
clear_script_prefix()
response = self.client.get(
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
{"q": "Me"},
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Mediation", "Medicine"])

@override_settings(URL_CONFIG="domain")
def test_keyword_suggestions_returns_initial_results_for_empty_query(self):
author_1, _ = self.create_authors()
clear_cache()
article = models.Article.objects.create(
journal=self.journal_one,
title="Test article: empty keyword query",
owner=author_1,
)
medicine = models.Keyword.objects.create(word="Medicine")
arts = models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine)
self.journal_one.keywords.add(arts)

self.client.force_login(author_1)
clear_script_prefix()
response = self.client.get(
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Arts", "Medicine"])

@override_settings(URL_CONFIG="domain")
def test_keyword_suggestions_can_filter_single_character_query(self):
author_1, _ = self.create_authors()
clear_cache()
article = models.Article.objects.create(
journal=self.journal_one,
title="Test article: short keyword query",
owner=author_1,
)
medicine = models.Keyword.objects.create(word="Medicine")
arts = models.Keyword.objects.create(word="Arts")
self.journal_one.keywords.add(medicine)
self.journal_one.keywords.add(arts)

self.client.force_login(author_1)
clear_script_prefix()
response = self.client.get(
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
{"q": "M"},
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Medicine"])

@override_settings(URL_CONFIG="domain")
def test_submission_keyword_autocomplete_requires_three_characters_before_searching(self):
author_1, _ = self.create_authors()
clear_cache()
article = models.Article.objects.create(
journal=self.journal_one,
title="Test article: keyword autocomplete threshold",
owner=author_1,
)

self.client.force_login(author_1)
clear_script_prefix()
response = self.client.get(
reverse("submit_info", kwargs={"article_id": article.pk}),
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertContains(response, "minLength: 3")
self.assertNotContains(response, "showAutocompleteOnFocus: true")

@override_settings(URL_CONFIG="domain")
def test_keyword_suggestions_available_for_editor_on_submitted_article(self):
article = helpers.create_article(self.journal_one)
article.stage = models.STAGE_UNDER_REVIEW
article.save()
medicine = models.Keyword.objects.create(word="Medicine")
self.journal_one.keywords.add(medicine)

self.client.force_login(self.editor)
clear_script_prefix()
response = self.client.get(
reverse(
"submission_keyword_suggestions",
kwargs={"article_id": article.pk},
),
{"q": "Me"},
SERVER_NAME="testserver",
)

self.assertEqual(response.status_code, 200)
self.assertEqual(response.json(), ["Medicine"])

def test_article_issue_title(self):
from utils.testing import helpers

Expand Down
Loading