Skip to content
Merged
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
3 changes: 3 additions & 0 deletions webapp/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,7 @@ def request_more_changes():
'email': last_compilation.email,
'submitted': last_compilation.submitted,
'accepted': last_compilation.accepted,
'revised': last_compilation.revised,
'pubtype': last_compilation.pubtype,
'errata_doi': last_compilation.errata_doi,
'compiled': now,
Expand Down Expand Up @@ -821,6 +822,8 @@ def change_issue():
metadata += '\\def\\IACR@Published{' + publishedDate + '}\n'
metadata += '\\def\\IACR@vol{' + str(volume.name) + '}\n'
metadata += '\\def\\IACR@no{' + str(issue.name) + '}\n'
if compilation.revised:
metadata += '\\def\\IACR@Revised{' + compilation.revised[:10] + '}\n'
metadata += '\\def\\IACR@CROSSMARKURL{https://crossmark.crossref.org/dialog/?doi=' + doi + '\&domain=pdf\&date\_stamp=' + publishedDate + '}\n'
metadata_file = input_dir / Path('main.iacrmetadata')
metadata_file.write_text(metadata)
Expand Down
1 change: 1 addition & 0 deletions webapp/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def export_issue(data_path: Path, output_path: Path, issue: Issue) -> datetime:
data = comp.meta.model_dump(exclude={'version': True}, exclude_none=True)
data['submitted'] = comp.submitted
data['accepted'] = comp.accepted
data['revised'] = comp.revised
data['compiled'] = comp.compiled.strftime('%Y-%m-%d %H:%M:%S')
data['errata_doi'] = comp.errata_doi
data['paperid'] = comp.paperid
Expand Down
20 changes: 19 additions & 1 deletion webapp/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from flask import current_app as app
from flask_wtf import FlaskForm
from flask_wtf.file import FileAllowed, FileRequired, FileField
from wtforms.validators import InputRequired, Email, EqualTo, Length, Regexp, NumberRange, AnyOf
from wtforms.validators import InputRequired, Optional, Email, EqualTo, Length, Regexp, NumberRange, AnyOf
from wtforms import EmailField, PasswordField, SubmitField, BooleanField, HiddenField, SelectField, StringField, ValidationError, IntegerField, FieldList, Form, FormField
from .metadata.db_models import Role, validate_version, Version
from .metadata import validate_paperid
from .metadata.compilation import dt_regex, PubType
import random, string # TODO - remove this
from . import create_hmac, validate_hmac
import logging
import re
import time

class LoginForm(FlaskForm):
Expand Down Expand Up @@ -182,6 +183,15 @@ def __init__(self, *args, **kwargs):
validators=[InputRequired('Accepted date is required'),
Regexp(dt_regex, message='Format of accepted is YYYY-mm-dd HH:MM:SS')],
default='')
revised = HiddenField(id='revised',
name='revised',
default='',
validators=[Optional('Revised date could be empty')])
def validate_revised(form, field):
"""Revised field is optional, but must match a regex if specified."""
if field.data:
if not re.match(dt_regex, field.data):
raise ValidationError('Format of revised is YYYY-mm-dd HH:MM:SS')
pubtype = HiddenField(id='pubtype',
name='pubtype',
validators=[InputRequired('pubtype field is required'),
Expand Down Expand Up @@ -218,6 +228,7 @@ def check_auth(self):
self.version.data,
self.submitted.data,
self.accepted.data,
self.revised.data,
self.journal.data,
self.volume.data,
self.issue.data,
Expand All @@ -232,6 +243,7 @@ def generate_auth(self):
self.version.data,
self.submitted.data,
self.accepted.data,
self.revised.data,
self.journal.data,
self.volume.data,
self.issue.data,
Expand All @@ -241,6 +253,12 @@ def validate(self, extra_validators=None):
if not super(FlaskForm, self).validate():
logging.warning('failed to validate: ' + str(self.errors))
return False
if self.revised.data:
if (self.revised.data < self.submitted.data or
self.revised.data > self.accepted.data):
logging.warning('revised must be between submitted and accepted')
self.revised.errors.append('revised must be between submitted and accepted')
return False
return self.check_auth()

class NotifyFinalForm(FlaskForm):
Expand Down
3 changes: 3 additions & 0 deletions webapp/metadata/compilation.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ class Compilation(BaseModel):
accepted: Annotated[str, StringConstraints(pattern=dt_regex)] = Field(...,
title='When the paper was accepted for publication',
description = 'Authenticated upon acceptance.')
revised: Annotated[str, StringConstraints(pattern='|' + dt_regex)] = Field('',
title='When the paper was last revised after submission',
description = 'Authenticated upon acceptance.')
pubtype: PubType = Field(default=PubType.RESEARCH,
title='Type of publication',
description='Originates in review system')
Expand Down
1 change: 1 addition & 0 deletions webapp/metadata/db_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ class PaperStatus(Base):
email: Mapped[str] = mapped_column(String(50), nullable=False)
submitted: Mapped[str] = mapped_column(String(32), nullable=False)
accepted: Mapped[str] = mapped_column(String(32), nullable=False)
revised: Mapped[str] = mapped_column(String(32), nullable=False, default='')
pubtype: Mapped[PubType] = mapped_column(default=PubType.RESEARCH)
status: Mapped[PaperStatusEnum] = mapped_column(default=PaperStatusEnum.PENDING)
hotcrp: Mapped[str] = mapped_column(String(32),
Expand Down
12 changes: 11 additions & 1 deletion webapp/metadata/tests/metadata_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,4 +341,14 @@ def test_pubtype():
assert comp.pubtype == PubType.ERRATA
assert comp.errata_doi == '10.1791/foobar'


def test_revised():
data = _compile_data
data['revised'] = '2022-10-09 13:10:04'
comp = Compilation(**data)
assert comp.revised == '2022-10-09 13:10:04'

def test_empty_revised():
data = _compile_data
data['revised'] = ''
comp = Compilation(**data)
assert comp.revised == ''
31 changes: 27 additions & 4 deletions webapp/routes.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import datetime
import time
from io import BytesIO
from flask import json, Blueprint, render_template, request, jsonify, send_file, redirect, url_for
from flask import json, Blueprint, render_template, request, jsonify, send_file, redirect, url_for, flash
from flask import current_app as app
from flask_mail import Message
import hmac
Expand Down Expand Up @@ -66,14 +66,20 @@ def show_submit_version():
# In this case the submission doesn't come from hotcrp, so we make up some fields.
random.seed()
form.paperid.data = ''.join(random.choices(string.ascii_lowercase + string.digits, k=8))
paperid = form.paperid.data
form.hotcrp.data = NO_HOTCRP
form.hotcrp_id.data = NO_HOTCRP
form.version.data = 'candidate'
now = datetime.datetime.now()
submitted = now - datetime.timedelta(days=10)
submitted = now - datetime.timedelta(days=32)
accepted = now - datetime.timedelta(days=5)
form.accepted.data = accepted.strftime('%Y-%m-%d %H:%M:%S')
form.submitted.data = submitted.strftime('%Y-%m-%d %H:%M:%S')
if random.randint(0, 1) == 0:
revised = now - datetime.timedelta(days=7)
form.revised.data = submitted.strftime('%Y-%m-%d %H:%M:%S')
else:
form.revised.data = ''
form.volume.data = '9999'
form.issue.data = '1'
form.generate_auth()
Expand All @@ -91,7 +97,7 @@ def show_submit_version():
error='The token for this request is invalid')
paperid = form.paperid.data
# Submission form is limited to papers that are not in copy editing mode and not already
# accepted for publication.
# accepted for publication.
sql = select(PaperStatus).filter_by(paperid=paperid)
paper_status = db.session.execute(sql).scalar_one_or_none()
if paper_status:
Expand Down Expand Up @@ -137,6 +143,9 @@ def submit_version():
logging.critical('{}:{}:{} submission not authenticated'.format(form.paperid.data,
form.version.data,
form.auth.data))
for fieldname, errors in form.errors.items():
for error in errors:
flash('{}:{}'.format(fieldname,error))
return render_template('message.html',
title='The form data is invalid.',
error='The form data is invalid. This is a bug')
Expand All @@ -145,6 +154,7 @@ def submit_version():
version = args.get('version', Version.CANDIDATE.value)
accepted = args.get('accepted', '')
submitted = args.get('submitted', '')
revised = args.get('revised', '')
hotcrp = args.get('hotcrp', '')
hotcrp_id = args.get('hotcrp_id', '')
task_key = paper_key(paperid, version)
Expand Down Expand Up @@ -200,6 +210,7 @@ def submit_version():
email=args.get('email'),
submitted=submitted,
accepted=accepted,
revised=revised,
pubtype=pubtype,
journal_key=args.get('journal'),
volume_key=args.get('volume'),
Expand Down Expand Up @@ -295,6 +306,7 @@ def submit_version():
'venue': args.get('journal'),
'submitted': submitted,
'accepted': accepted,
'revised': revised,
'pubtype': pubtype.name,
'errata_doi': form.errata_doi.data,
'compiled': now,
Expand Down Expand Up @@ -326,10 +338,15 @@ def submit_version():
metadata += '\\def\\IACR@Received{' + receivedDate.strftime('%Y-%m-%d') + '}\n'
metadata += '\\def\\IACR@Accepted{' + acceptedDate.strftime('%Y-%m-%d') + '}\n'
metadata += '\\def\\IACR@Published{' + publishedDate + '}\n'
if revised:
revisedDate = datetime.datetime.strptime(revised[:10], '%Y-%m-%d')
metadata += '\\def\IACR@Revised{' + revisedDate.strftime('%Y-%m-%d') + '}\n'
if paper_status.issue:
metadata += '\\def\\IACR@vol{' + str(paper_status.issue.volume.name) + '}\n'
metadata += '\\def\\IACR@no{' + str(paper_status.issue.name) + '}\n'
metadata += '\\def\\IACR@CROSSMARKURL{https://crossmark.crossref.org/dialog/?doi=' + doi + r'\&domain=pdf\&date\_stamp=' + publishedDate + '}\n'
# We now check for version=final in iacrj.
metadata += '\\ifcsstring{@IACRversion}{final}{}{\\ClassError{iacrj}{This production system requires using version=final in \\string\documentclass}{}}'
metadata_file = input_dir / Path('main.iacrmetadata')
metadata_file.write_text(metadata)
output_dir = version_dir / Path('output')
Expand Down Expand Up @@ -483,6 +500,7 @@ def compile_for_copyedit():
'email': version_compilation.email,
'submitted': version_compilation.submitted,
'accepted': version_compilation.accepted,
'revised': version_compilation.revised,
'pubtype': version_compilation.pubtype,
'errata_doi': version_compilation.errata_doi,
'compiled': now,
Expand Down Expand Up @@ -615,6 +633,7 @@ def view_copyedit(paperid, auth):
volume=paper_status.volume_key,
submitted=paper_status.submitted,
accepted=paper_status.accepted,
revised=paper_status.revised,
email=paper_status.email,
journal=paper_status.journal_key,
pubtype=paper_status.pubtype.name,
Expand All @@ -624,6 +643,7 @@ def view_copyedit(paperid, auth):
Version.FINAL.value,
paper_status.submitted,
paper_status.accepted,
paper_status.revised,
paper_status.journal_key,
paper_status.volume_key,
paper_status.issue_key,
Expand Down Expand Up @@ -699,6 +719,7 @@ def respond_to_comment(paperid, itemid, auth):
volume=paper_status.volume_key,
submitted=paper_status.submitted,
accepted=paper_status.accepted,
revised=paper_status.revised,
email=paper_status.email,
journal=paper_status.journal_key,
auth=create_hmac([paperid, # TODO: authenticate other fields
Expand All @@ -707,6 +728,7 @@ def respond_to_comment(paperid, itemid, auth):
Version.FINAL.value,
paper_status.submitted,
paper_status.accepted,
paper_status.revised,
paper_status.journal_key,
paper_status.volume_key,
paper_status.issue_key,
Expand Down Expand Up @@ -850,7 +872,6 @@ def view_results(paperid, version, auth):
json_file = paper_path / Path('compilation.json')
comp = Compilation.model_validate_json(json_file.read_text(encoding='UTF-8'))
data['comp'] = comp
data['auth'] = create_hmac([paperid, version, comp.submitted, comp.accepted])
except Exception as e:
return render_template('message.html',
title='Unable to parse compilation',
Expand Down Expand Up @@ -901,12 +922,14 @@ def view_results(paperid, version, auth):
issue=pstatus.issue_key,
submitted=pstatus.submitted,
accepted=pstatus.accepted,
revised=pstatus.revised,
auth=create_hmac([paperid,
pstatus.hotcrp,
pstatus.hotcrp_id,
version,
comp.submitted,
comp.accepted,
comp.revised,
pstatus.journal_key,
pstatus.volume_key,
pstatus.issue_key,
Expand Down
4 changes: 4 additions & 0 deletions webapp/templates/admin/metadata.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,10 @@
<th>Accepted</th>
<td>{{comp.accepted}}</td>
</tr>
<tr>
<th>Revised</th>
<td>{{comp.revised}}</td>
</tr>
<tr>
<th>Compiled</th>
<td>{{comp.compiled.strftime('%Y-%m-%d %H:%M:%S')}}</td>
Expand Down
1 change: 1 addition & 0 deletions webapp/templates/compilation.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ <h5>Authors</h5>
<div class="elem" id="email"><div class="elem_title">email:</div> {{comp.email}}</div>
<div class="elem" id="submitted"><div class="elem_title">submitted:</div> {{comp.submitted}}</div>
<div class="elem" id="accepted"><div class="elem_title">accepted:</div> {{comp.accepted}}</div>
<div class="elem" id="revised"><div class="elem_title">revised:</div> {{comp.revised}}</div>
<div class="elem" id="compiled"><div class="elem_title">compiled:</div> {{comp.compiled}}</div>
<div class="elem" id="compile_time"><div class="elem_title">compile_time:</div> {{comp.compile_time}} seconds</div>
<div class="elem" id="doi"><div class="elem_title">DOI:</div> {{comp.meta.doi}}</div>
Expand Down
5 changes: 5 additions & 0 deletions webapp/templates/message.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
<main id="mainContent" class="container px-3 px-md-4">
<h2 class="mt-2 mb-5">{{title}}</h2>

{% for msg in get_flashed_messages() %}
<div class="alert alert-warning mt-3">
{{ msg }}
</div>
{% endfor %}
{% if message %}
<div class="alert alert-info">
{{message|safe}}
Expand Down
6 changes: 6 additions & 0 deletions webapp/templates/submit.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@
{% endfor %}
{% endif %}
{{ form.accepted }}
{% if form.revised.errors %}
{% for msg in form.revised.errors %}
<div class="alert alert-danger">{{ msg }}</div>
{% endfor %}
{% endif %}
{{ form.revised }}
{% if form.volume.errors %}
{% for msg in form.volume.errors %}
<div class="form-text text-danger">{{msg}}</div>
Expand Down
4 changes: 4 additions & 0 deletions webapp/templates/view.html
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,10 @@ <h3 id="metadata">Metadata</h3>
<th>Accepted</th>
<td>{{comp.accepted}}</td>
</tr>
<tr>
<th>Revised</th>
<td>{{comp.revised}}</td>
</tr>
<tr>
<th>Date compiled:</th>
<td>{{comp.compiled.strftime('%Y-%m-%d %H:%M:%S')}}</td>
Expand Down