From 095a1dbc9edc6c56084fe25b395537bf9daa9aa0 Mon Sep 17 00:00:00 2001 From: Geert Kapteijns <ghkapteijns@gmail.com> Date: Fri, 12 May 2017 13:08:57 +0200 Subject: [PATCH] Check if DOI belongs to existing resource. Move validation logic to form. --- commentaries/forms.py | 24 +++++++++++++++++++++--- commentaries/test_forms.py | 9 +++++++-- commentaries/test_models.py | 12 +++++++++++- commentaries/test_views.py | 16 ++++++++++++++-- commentaries/views.py | 10 +++++++--- scipost/services.py | 12 +++++++++--- scipost/test_services.py | 6 ++++++ 7 files changed, 75 insertions(+), 14 deletions(-) diff --git a/commentaries/forms.py b/commentaries/forms.py index 6364e224d..e1f29641d 100644 --- a/commentaries/forms.py +++ b/commentaries/forms.py @@ -6,6 +6,7 @@ from django.urls import reverse from .models import Commentary +from scipost.services import DOICaller from scipost.models import Contributor @@ -16,11 +17,23 @@ class DOIToQueryForm(forms.Form): def clean_doi(self): input_doi = self.cleaned_data['doi'] - if Commentary.objects.filter(pub_DOI=input_doi).exists(): + + if self.commentary_exists(input_doi): error_message = 'There already exists a Commentary Page on this publication.' raise forms.ValidationError(error_message) + + caller = DOICaller(input_doi) + if caller.is_valid: + self.crossref_data = DOICaller(input_doi).data + else: + error_message = 'Could not find a resource for that DOI.' + raise forms.ValidationError(error_message) + return input_doi + def commentary_exists(self, input_doi): + return Commentary.objects.filter(pub_DOI=input_doi).exists() + class IdentifierToQueryForm(forms.Form): identifier = forms.CharField(widget=forms.TextInput( @@ -56,18 +69,23 @@ class RequestPublishedArticleForm(forms.ModelForm): class Meta: model = Commentary fields = [ - 'type', 'discipline', 'domain', 'subject_area', 'pub_title', 'author_list', 'metadata', 'journal', 'volume', + 'discipline', 'domain', 'subject_area', 'pub_title', 'author_list', 'journal', 'volume', 'pages', 'pub_date', 'pub_DOI', 'pub_abstract' ] widgets = { 'metadata': forms.HiddenInput(), - 'type': forms.HiddenInput(), } placeholders = { 'pub_DOI': 'ex.: 10.21468/00.000.000000', 'pub_date': 'Format: YYYY-MM-DD', } + def save(self, *args): + commentary = super().save(*args) + commentary.metadata = self.metadata + commentary.save() + return commentary + class RequestCommentaryForm(forms.ModelForm): """Create new valid Commetary by user request""" diff --git a/commentaries/test_forms.py b/commentaries/test_forms.py index 964eb0e80..b225d2180 100644 --- a/commentaries/test_forms.py +++ b/commentaries/test_forms.py @@ -8,9 +8,9 @@ from scipost.factories import UserFactory from .factories import VettedCommentaryFactory, UnvettedCommentaryFactory from .forms import RequestCommentaryForm, VetCommentaryForm, DOIToQueryForm from .models import Commentary -from common.helpers import model_form_data from common.helpers.test import add_groups_and_permissions + class TestDOIToQueryForm(TestCase): def setUp(self): add_groups_and_permissions() @@ -43,6 +43,11 @@ class TestDOIToQueryForm(TestCase): form = DOIToQueryForm({'doi': old_doi}) self.assertTrue(form.is_valid()) + def test_valid_but_nonexistent_doi_is_invalid(self): + doi = "10.21468/NonExistentJournal.2.2.010" + form = DOIToQueryForm({'doi': doi}) + self.assertEqual(form.is_valid(), False) + class TestVetCommentaryForm(TestCase): def setUp(self): @@ -109,7 +114,7 @@ class TestVetCommentaryForm(TestCase): class TestRequestCommentaryForm(TestCase): def setUp(self): add_groups_and_permissions() - factory_instance = VettedCommentaryFactory.build() + factory_instance = UnvettedCommentaryFactory.build() self.user = UserFactory() self.valid_form_data = model_form_data(factory_instance, RequestCommentaryForm) diff --git a/commentaries/test_models.py b/commentaries/test_models.py index e4defabc8..5fb96f3ef 100644 --- a/commentaries/test_models.py +++ b/commentaries/test_models.py @@ -1 +1,11 @@ -# from django.test import TestCase +from django.test import TestCase + +from common.helpers.test import add_groups_and_permissions + +from scipost.factories import ContributorFactory +from .factories import UnvettedCommentaryFactory + + +class TestCommentary(TestCase): + def setUp(self): + add_groups_and_permissions() diff --git a/commentaries/test_views.py b/commentaries/test_views.py index ca2a6c8e4..96220a2eb 100644 --- a/commentaries/test_views.py +++ b/commentaries/test_views.py @@ -5,10 +5,11 @@ from django.test import TestCase, Client, RequestFactory from scipost.factories import ContributorFactory, UserFactory from .factories import UnvettedCommentaryFactory, VettedCommentaryFactory, UnpublishedVettedCommentaryFactory -from .forms import CommentarySearchForm +from .forms import CommentarySearchForm, RequestPublishedArticleForm from .models import Commentary -from .views import RequestCommentary, prefill_using_DOI +from .views import RequestPublishedArticle, prefill_using_DOI from common.helpers.test import add_groups_and_permissions +from common.helpers import model_form_data class RequestCommentaryTest(TestCase): @@ -34,6 +35,17 @@ class RequestCommentaryTest(TestCase): """Test different kind of invalid RequestCommentaryForm submits""" raise NotImplementedError + def test_saved_commentary_has_a_type(self): + self.assertEqual(Commentary.objects.count(), 0) + commentary = UnvettedCommentaryFactory.build() + valid_post_data = model_form_data(commentary, RequestPublishedArticleForm) + print(valid_post_data) + request = RequestFactory().post(reverse('commentaries:request_published_article'), valid_post_data) + request.user = UserFactory() + response = RequestPublishedArticle.as_view()(request) + + self.assertEqual(Commentary.objects.count(), 1) + class PrefillUsingDOITest(TestCase): def setUp(self): diff --git a/commentaries/views.py b/commentaries/views.py index aae2fc598..197905b17 100644 --- a/commentaries/views.py +++ b/commentaries/views.py @@ -22,7 +22,7 @@ from .forms import RequestCommentaryForm, DOIToQueryForm, IdentifierToQueryForm, from comments.models import Comment from comments.forms import CommentForm from scipost.models import Contributor -from scipost.services import ArxivCaller, DOICaller +from scipost.services import ArxivCaller import strings @@ -80,6 +80,11 @@ class RequestPublishedArticle(CreateView): context['doi_query_form'] = DOIToQueryForm() return context + def form_valid(self, form): + form.type = "published" + return super(RequestPublishedArticle, self).form_valid(form) + + @permission_required('scipost.can_request_commentary_pages', raise_exception=True) def prefill_using_DOI(request): if request.method == "POST": @@ -87,9 +92,8 @@ def prefill_using_DOI(request): # The form checks if doi is valid and commentary doesn't already exist. if doi_query_form.is_valid(): doi = doi_query_form.cleaned_data['doi'] - crossref_data = DOICaller(doi).data additional_form_data = {'type': 'published', 'pub_DOI': doi} - total_form_data = {**crossref_data, **additional_form_data} + total_form_data = {**doi_query_form.crossref_data, **additional_form_data} form = RequestPublishedArticleForm(initial=total_form_data) else: form = RequestPublishedArticleForm() diff --git a/scipost/services.py b/scipost/services.py index 78c38e849..47efe58b9 100644 --- a/scipost/services.py +++ b/scipost/services.py @@ -14,14 +14,20 @@ class DOICaller: def __init__(self, doi_string): self.doi_string = doi_string self._call_crosslink() - self._format_data() + if self.is_valid: + self._format_data() def _call_crosslink(self): url = 'http://api.crossref.org/works/%s' % self.doi_string - self.crossref_data = requests.get(url).json()['message'] + request = requests.get(url) + if request.ok: + self.is_valid = True + self._crossref_data = requests.get(url).json()['message'] + else: + self.is_valid = False def _format_data(self): - data = self.crossref_data + data = self._crossref_data pub_title = data['title'][0] authorlist = ['{} {}'.format(author['given'], author['family']) for author in data['author']] journal = data['container-title'][0] diff --git a/scipost/test_services.py b/scipost/test_services.py index 120a160da..6794725eb 100644 --- a/scipost/test_services.py +++ b/scipost/test_services.py @@ -58,6 +58,7 @@ class DOICallerTest(TestCase): 'volume': '92', 'pub_title': 'Quasi-soliton scattering in quantum spin chains' } + self.assertTrue(caller.is_valid) self.assertEqual(caller.data, correct_data) def test_works_for_scipost_doi(self): @@ -72,4 +73,9 @@ class DOICallerTest(TestCase): 'volume': '2', 'authorlist': ['Yannis Brun', 'Jerome Dubail'] } + self.assertTrue(caller.is_valid) self.assertEqual(caller.data, correct_data) + + def test_valid_but_non_existent_doi(self): + caller = DOICaller('10.21468/NonExistentJournal.2.2.012') + self.assertEqual(caller.is_valid, False) -- GitLab