diff --git a/submissions/constants.py b/submissions/constants.py index 4e8da2fefd15599063680e7711ffe62134cd4d2b..943de541f9e517ddce9b8ceb90bbaebda95e9cf5 100644 --- a/submissions/constants.py +++ b/submissions/constants.py @@ -1,3 +1,6 @@ +from journals.constants import SCIPOST_JOURNAL_PHYSICS + + STATUS_UNASSIGNED = 'unassigned' STATUS_RESUBMISSION_INCOMING = 'resubmitted_incoming' STATUS_REVISION_REQUESTED = 'revision_requested' @@ -216,3 +219,19 @@ EVENT_TYPES = ( (EVENT_FOR_EIC, 'Comment for Editor-in-charge'), (EVENT_FOR_AUTHOR, 'Comment for author'), ) + +# Use `.format()` https://docs.python.org/3.5/library/string.html#format-string-syntax +# In your regex multiple brackets may occur; +# Please make sure to double them in that case as per instructions in the reference! +SUBMISSIONS_NO_VN_REGEX = '(?P<arxiv_identifier_wo_vn_nr>[0-9]{4,}.[0-9]{4,})' +SUBMISSIONS_COMPLETE_REGEX = '(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{4,}v[0-9]{1,2})' + + +# `EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS` tracks the regex rules for the manuscripts +# submitted per journal. +# +# CAUTION: *triple* check whether the `default` regex also meets any other explicit journal regex! +EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS = { + SCIPOST_JOURNAL_PHYSICS: '(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})', + 'default': SUBMISSIONS_COMPLETE_REGEX +} diff --git a/submissions/forms.py b/submissions/forms.py index fd5fff6e7be2f8988fa5ddd6cd4755946be8363e..fe47475e57d4c1f80e52bd8bb1c246dddab27ba0 100644 --- a/submissions/forms.py +++ b/submissions/forms.py @@ -1,3 +1,5 @@ +import re + from django import forms from django.conf import settings from django.contrib.auth.models import Group @@ -10,7 +12,7 @@ from .constants import ASSIGNMENT_BOOL, ASSIGNMENT_REFUSAL_REASONS, STATUS_RESUB REPORT_ACTION_CHOICES, REPORT_REFUSAL_CHOICES, STATUS_REVISION_REQUESTED,\ STATUS_REJECTED, STATUS_REJECTED_VISIBLE, STATUS_RESUBMISSION_INCOMING,\ STATUS_DRAFT, STATUS_UNVETTED, REPORT_ACTION_ACCEPT, REPORT_ACTION_REFUSE,\ - STATUS_VETTED + STATUS_VETTED, EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS from . import exceptions, helpers from .models import Submission, RefereeInvitation, Report, EICRecommendation, EditorialAssignment,\ iThenticateReport @@ -120,6 +122,20 @@ class SubmissionChecks: 'before proceeding with a resubmission.') raise forms.ValidationError(error_message) + def arxiv_meets_regex(self, identifier, journal_code): + if journal_code in EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS.keys(): + regex = EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS[journal_code] + else: + regex = EXPLICIT_REGEX_MANUSCRIPT_CONSTRAINTS['default'] + + pattern = re.compile(regex) + if not pattern.match(identifier): + # No match object returned, identifier is invalid + error_message = ('The journal you want to submit to does not allow for this' + ' arXiv identifier. Please contact SciPost if you have' + ' any further questions.') + raise forms.ValidationError(error_message, code='submitted_to_journal') + def submission_is_resubmission(self): return self.is_resubmission @@ -239,6 +255,8 @@ class RequestSubmissionForm(SubmissionChecks, forms.ModelForm): """ cleaned_data = super().clean(*args, **kwargs) self.do_pre_checks(cleaned_data['arxiv_identifier_w_vn_nr']) + self.arxiv_meets_regex(cleaned_data['arxiv_identifier_w_vn_nr'], + cleaned_data['submitted_to_journal']) return cleaned_data def clean_author_list(self): diff --git a/submissions/urls.py b/submissions/urls.py index 431ae957cad857afb401cabd2a15b58a9f53fe67..c1f46c9ab3839e1758c764de519a0ae91a24eecf 100644 --- a/submissions/urls.py +++ b/submissions/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from django.views.generic import TemplateView from . import views +from .constants import SUBMISSIONS_NO_VN_REGEX, SUBMISSIONS_COMPLETE_REGEX urlpatterns = [ # Submissions @@ -14,25 +15,25 @@ urlpatterns = [ url(r'^author_guidelines$', TemplateView.as_view(template_name='submissions/author_guidelines.html'), name='author_guidelines'), - url(r'^(?P<arxiv_identifier_wo_vn_nr>[0-9]{4,}.[0-9]{5,})/$', views.submission_detail_wo_vn_nr, + url(r'^{regex}/$'.format(regex=SUBMISSIONS_NO_VN_REGEX), views.submission_detail_wo_vn_nr, name='submission_wo_vn_nr'), - url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/$', + url(r'^{regex}/$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.submission_detail, name='submission'), - url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/(?P<report_nr>[0-9]+)/pdf$', + url(r'^{regex}/reports/(?P<report_nr>[0-9]+)/pdf$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.report_detail_pdf, name='report_detail_pdf'), - url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/pdf$', + url(r'^{regex}/reports/pdf$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.submission_refereeing_package_pdf, name='refereeing_package_pdf'), # Editorial Administration url(r'^admin$', views.EditorialSummaryView.as_view(), name='admin'), url(r'^admin/treated$', views.treated_submissions_list, name='treated_submissions_list'), - url(r'^admin/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/compile$', + url(r'^admin/{regex}/reports/compile$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.treated_submission_pdf_compile, name='treated_submission_pdf_compile'), - url(r'^admin/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/plagiarism$', + url(r'^admin/{regex}/plagiarism$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.PlagiarismView.as_view(), name='plagiarism'), - url(r'^admin/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/plagiarism/report$', + url(r'^admin/{regex}/plagiarism/report$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.PlagiarismReportPDFView.as_view(), name='plagiarism_report'), - url(r'^admin/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/recommendations/(?P<rec_id>[0-9]+)$', + url(r'^admin/{regex}/recommendations/(?P<rec_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.EICRecommendationView.as_view(), name='eic_recommendation_detail'), url(r'^admin/reports$', views.reports_accepted_list, name='reports_accepted_list'), url(r'^admin/reports/(?P<report_id>[0-9]+)/compile$', @@ -46,30 +47,30 @@ urlpatterns = [ url(r'^pool$', views.pool, name='pool'), url(r'^submissions_by_status/(?P<status>[a-zA-Z_]+)$', views.submissions_by_status, name='submissions_by_status'), - url(r'^add_remark/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^add_remark/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.add_remark, name='add_remark'), # Assignment of Editor-in-charge - url(r'^assign_submission/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^assign_submission/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.assign_submission, name='assign_submission'), - url(r'^assign_submission_ack/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^assign_submission_ack/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.assign_submission_ack, name='assign_submission_ack'), url(r'^accept_or_decline_assignment_ack/(?P<assignment_id>[0-9]+)$', views.accept_or_decline_assignment_ack, name='accept_or_decline_assignment_ack'), - url(r'^volunteer_as_EIC/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^volunteer_as_EIC/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.volunteer_as_EIC, name='volunteer_as_EIC'), - url(r'^assignment_failed/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^assignment_failed/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.assignment_failed, name='assignment_failed'), # Editorial workflow and refereeing url(r'^editorial_workflow$', views.editorial_workflow, name='editorial_workflow'), url(r'^assignments$', views.assignments, name='assignments'), - url(r'^editorial_page/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^editorial_page/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.editorial_page, name='editorial_page'), - url(r'^select_referee/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^select_referee/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.select_referee, name='select_referee'), - url(r'^recruit_referee/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^recruit_referee/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.recruit_referee, name='recruit_referee'), - url(r'^send_refereeing_invitation/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<contributor_id>[0-9]+)$', + url(r'^send_refereeing_invitation/{regex}/(?P<contributor_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.send_refereeing_invitation, name='send_refereeing_invitation'), url(r'^accept_or_decline_ref_invitations/$', views.accept_or_decline_ref_invitations, name='accept_or_decline_ref_invitations'), @@ -77,27 +78,28 @@ urlpatterns = [ views.accept_or_decline_ref_invitation_ack, name='accept_or_decline_ref_invitation_ack'), url(r'^decline_ref_invitation/(?P<invitation_key>.+)$', views.decline_ref_invitation, name='decline_ref_invitation'), - url(r'^ref_invitation_reminder/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<invitation_id>[0-9]+)$', views.ref_invitation_reminder, name='ref_invitation_reminder'), - url(r'^cancel_ref_invitation/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<invitation_id>[0-9]+)$', + url(r'^ref_invitation_reminder/{regex}/(?P<invitation_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), + views.ref_invitation_reminder, name='ref_invitation_reminder'), + url(r'^cancel_ref_invitation/{regex}/(?P<invitation_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.cancel_ref_invitation, name='cancel_ref_invitation'), - url(r'^extend_refereeing_deadline/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<days>[0-9]+)$', + url(r'^extend_refereeing_deadline/{regex}/(?P<days>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.extend_refereeing_deadline, name='extend_refereeing_deadline'), - url(r'^set_refereeing_deadline/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^set_refereeing_deadline/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.set_refereeing_deadline, name='set_refereeing_deadline'), - url(r'^close_refereeing_round/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^close_refereeing_round/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.close_refereeing_round, name='close_refereeing_round'), url(r'^refereeing_overview$', views.refereeing_overview, name='refereeing_overview'), - url(r'^communication/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<comtype>[a-zA-Z]{4,})$', + url(r'^communication/{regex}/(?P<comtype>[a-zA-Z]{{4,}})$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.communication, name='communication'), - url(r'^communication/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/(?P<comtype>[a-zA-Z]{4,})/(?P<referee_id>[0-9]+)$', + url(r'^communication/{regex}/(?P<comtype>[a-zA-Z]{{4,}})/(?P<referee_id>[0-9]+)$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.communication, name='communication'), - url(r'^eic_recommendation/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})$', + url(r'^eic_recommendation/{regex}$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.eic_recommendation, name='eic_recommendation'), - url(r'^cycle/(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/submit$', + url(r'^cycle/{regex}/submit$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.cycle_form_submit, name='cycle_confirmation'), # Reports - url(r'^(?P<arxiv_identifier_w_vn_nr>[0-9]{4,}.[0-9]{5,}v[0-9]{1,2})/reports/submit$', + url(r'^{regex}/reports/submit$'.format(regex=SUBMISSIONS_COMPLETE_REGEX), views.submit_report, name='submit_report'), url(r'^reports/vet$', views.vet_submitted_reports_list, name='vet_submitted_reports_list'), url(r'^reports/(?P<report_id>[0-9]+)/vet$', views.vet_submitted_report,