diff --git a/app/auth/forms.py b/app/auth/forms.py index a418bc51..e8825aa2 100644 --- a/app/auth/forms.py +++ b/app/auth/forms.py @@ -7,7 +7,7 @@ from wtforms import ( SubmitField, ValidationError ) -from wtforms.validators import DataRequired, Email, EqualTo, Length, Regexp +from wtforms.validators import DataRequired, InputRequired, Email, EqualTo, Length, Regexp from . import USERNAME_REGEX @@ -20,31 +20,18 @@ class LoginForm(FlaskForm): class RegistrationForm(FlaskForm): email = StringField('Email', validators=[DataRequired(), Email()]) - username = StringField( - 'Username', + username = StringField('Username', validators=[ - DataRequired(), - Length(1, 64), + InputRequired(), + Length(min=1, max=64), Regexp( USERNAME_REGEX, message='Usernames must have only letters, numbers, dots or underscores' # noqa ) ] ) - password = PasswordField( - 'Password', - validators=[ - DataRequired(), - EqualTo('password_confirmation', message='Passwords must match') - ] - ) - password_confirmation = PasswordField( - 'Password confirmation', - validators=[ - DataRequired(), - EqualTo('password', message='Passwords must match') - ] - ) + password = PasswordField('Password', validators=[DataRequired(), EqualTo('password_confirmation', message='Passwords must match')]) + password_confirmation = PasswordField('Password confirmation', validators=[DataRequired(), EqualTo('password', message='Passwords must match')]) submit = SubmitField('Register') def validate_email(self, field): @@ -57,20 +44,8 @@ class RegistrationForm(FlaskForm): class ResetPasswordForm(FlaskForm): - password = PasswordField( - 'New password', - validators=[ - DataRequired(), - EqualTo('password_confirmation', message='Passwords must match') - ] - ) - password_confirmation = PasswordField( - 'Password confirmation', - validators=[ - DataRequired(), - EqualTo('password', message='Passwords must match') - ] - ) + password = PasswordField('New password', validators=[DataRequired(), EqualTo('password_confirmation', message='Passwords must match')]) + password_confirmation = PasswordField('Password confirmation', validators=[DataRequired(), EqualTo('password', message='Passwords must match')]) submit = SubmitField('Reset Password') diff --git a/app/corpora/forms.py b/app/corpora/forms.py index 9af4a5ce..7e1e98d8 100644 --- a/app/corpora/forms.py +++ b/app/corpora/forms.py @@ -1,13 +1,13 @@ from flask_wtf import FlaskForm +from flask_wtf.file import FileField, FileRequired from werkzeug.utils import secure_filename from wtforms import ( - FileField, StringField, SubmitField, ValidationError, IntegerField ) -from wtforms.validators import DataRequired, Length +from wtforms.validators import DataRequired, InputRequired, Length class AddCorpusFileForm(FlaskForm): @@ -15,36 +15,25 @@ class AddCorpusFileForm(FlaskForm): Form to add a .vrt corpus file to the current corpus. ''' # Required fields - author = StringField('Author', validators=[DataRequired(), Length(1, 255)]) - file = FileField('File', validators=[DataRequired()]) - publishing_year = IntegerField('Publishing year', - validators=[DataRequired()]) - title = StringField('Title', validators=[DataRequired(), Length(1, 255)]) + author = StringField('Author', validators=[InputRequired(), Length(min=1, max=255)]) + publishing_year = IntegerField('Publishing year', validators=[InputRequired(), Length(min=1, max=255)]) + title = StringField('Title', validators=[InputRequired(), Length(min=1, max=255)]) + vrt = FileField('File', validators=[FileRequired()]) # Optional fields - address = StringField('Adress', validators=[Length(0, 255)]) - booktitle = StringField('Booktitle', validators=[Length(0, 255)]) - chapter = StringField('Chapter', validators=[Length(0, 255)]) - editor = StringField('Editor', validators=[Length(0, 255)]) - institution = StringField('Institution', validators=[Length(0, 255)]) - journal = StringField('Journal', validators=[Length(0, 255)]) - pages = StringField('Pages', validators=[Length(0, 255)]) - publisher = StringField('Publisher', validators=[Length(0, 255)]) - school = StringField('School', validators=[Length(0, 255)]) + address = StringField('Adress', validators=[Length(max=255)]) + booktitle = StringField('Booktitle', validators=[Length(max=255)]) + chapter = StringField('Chapter', validators=[Length(max=255)]) + editor = StringField('Editor', validators=[Length(max=255)]) + institution = StringField('Institution', validators=[Length(max=255)]) + journal = StringField('Journal', validators=[Length(max=255)]) + pages = StringField('Pages', validators=[Length(max=255)]) + publisher = StringField('Publisher', validators=[Length(max=255)]) + school = StringField('School', validators=[Length(max=255)]) submit = SubmitField() - def __init__(self, corpus, *args, **kwargs): - super().__init__(*args, **kwargs) - self.corpus = corpus - - def validate_file(self, field): + def validate_vrt(self, field): if not field.data.filename.lower().endswith('.vrt'): - raise ValidationError('File does not have an approved extension: ' - '.vrt') - field.data.filename = secure_filename(field.data.filename) - for corpus_file in self.corpus.files: - if field.data.filename == corpus_file.filename: - raise ValidationError('File already registered to corpus.') - + raise ValidationError('VRT files only!') class EditCorpusFileForm(FlaskForm): ''' @@ -52,8 +41,7 @@ class EditCorpusFileForm(FlaskForm): ''' # Required fields author = StringField('Author', validators=[DataRequired(), Length(1, 255)]) - publishing_year = IntegerField('Publishing year', - validators=[DataRequired()]) + publishing_year = IntegerField('Publishing year', validators=[DataRequired()]) title = StringField('Title', validators=[DataRequired(), Length(1, 255)]) # Optional fields address = StringField('Adress', validators=[Length(0, 255)]) @@ -72,27 +60,23 @@ class AddCorpusForm(FlaskForm): ''' Form to add a a new corpus. ''' - description = StringField('Description', - validators=[DataRequired(), Length(1, 255)]) - submit = SubmitField() + description = StringField('Description', validators=[DataRequired(), Length(1, 255)]) title = StringField('Title', validators=[DataRequired(), Length(1, 32)]) + submit = SubmitField() class ImportCorpusForm(FlaskForm): ''' Form to import a corpus. ''' - description = StringField('Description', - validators=[DataRequired(), Length(1, 255)]) - file = FileField('File', validators=[DataRequired()]) - submit = SubmitField() + description = StringField('Description', validators=[DataRequired(), Length(1, 255)]) + archive = FileField('File', validators=[DataRequired()]) title = StringField('Title', validators=[DataRequired(), Length(1, 32)]) + submit = SubmitField() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - def validate_file(self, field): - if not field.data.filename.lower().endswith('.zip'): - raise ValidationError('File does not have an approved extension: ' - '.zip') - field.data.filename = secure_filename(field.data.filename) + def validate_archive(self, field): + if field.data.mimetype != 'application/zip': + raise ValidationError('ZIP files only!') diff --git a/app/corpora/routes.py b/app/corpora/routes.py index 3b334d83..681789d9 100644 --- a/app/corpora/routes.py +++ b/app/corpora/routes.py @@ -190,7 +190,7 @@ def add_corpus_file(corpus_id): corpus = Corpus.query.get_or_404(corpus_id) if not (corpus.user == current_user or current_user.is_administrator()): abort(403) - form = AddCorpusFileForm(corpus, prefix='add-corpus-file-form') + form = AddCorpusFileForm(prefix='add-corpus-file-form') if form.is_submitted(): if not form.validate(): return make_response(form.errors, 400) @@ -269,8 +269,9 @@ def download_corpus_file(corpus_id, corpus_file_id): abort(403) return send_from_directory( as_attachment=True, + attachment_filename=corpus_file.filename, directory=os.path.dirname(corpus_file.path), - filename=corpus_file.filename + filename=os.path.basename(corpus_file.path) ) diff --git a/app/services/forms.py b/app/services/forms.py index 21db025e..5e184e35 100644 --- a/app/services/forms.py +++ b/app/services/forms.py @@ -1,7 +1,7 @@ -from app.models import Job, TesseractOCRModel +from app.models import TesseractOCRModel from flask_login import current_user from flask_wtf import FlaskForm -from flask_wtf.file import FileField, FileAllowed, FileRequired +from flask_wtf.file import FileField, FileRequired from wtforms import ( BooleanField, MultipleFileField, @@ -15,24 +15,10 @@ from . import SERVICES class AddJobForm(FlaskForm): - description = StringField('Description', validators=[InputRequired()]) # noqa - submit = SubmitField() - title = StringField('Title', validators=[InputRequired()]) + description = StringField('Description', validators=[InputRequired(), Length(min=1, max=255)]) + title = StringField('Title', validators=[InputRequired(), Length(min=1, max=32)]) version = SelectField('Version', validators=[DataRequired()]) - - def validate_description(self, field): - max_length = Job.description.property.columns[0].type.length - if len(field.data) > max_length: - raise ValidationError( - f'Description must be less than {max_length} characters' - ) - - def validate_title(self, field): - max_length = Job.title.property.columns[0].type.length - if len(field.data) > max_length: - raise ValidationError( - f'Title must be less than {max_length} characters' - ) + submit = SubmitField() class AddFileSetupPipelineJobForm(AddJobForm): diff --git a/app/settings/forms.py b/app/settings/forms.py index f17c5f89..cfc6918c 100644 --- a/app/settings/forms.py +++ b/app/settings/forms.py @@ -9,28 +9,13 @@ from wtforms import ( SubmitField, ValidationError ) -from wtforms.validators import DataRequired, Email, EqualTo, Length, Regexp +from wtforms.validators import DataRequired, InputRequired, Email, EqualTo, Length, Regexp class ChangePasswordForm(FlaskForm): password = PasswordField('Old password', validators=[DataRequired()]) - new_password = PasswordField( - 'New password', - validators=[ - DataRequired(), - EqualTo( - 'new_password_confirmation', - message='Passwords must match' - ) - ] - ) - new_password_confirmation = PasswordField( - 'Confirm new password', - validators=[ - DataRequired(), - EqualTo('new_password', message='Passwords must match') - ] - ) + new_password = PasswordField('New password', validators=[DataRequired(), EqualTo('new_password_confirmation', message='Passwords must match')]) + new_password_confirmation = PasswordField('Confirm new password', validators=[DataRequired(), EqualTo('new_password', message='Passwords must match')]) submit = SubmitField('Submit') def __init__(self, user, *args, **kwargs): @@ -43,14 +28,11 @@ class ChangePasswordForm(FlaskForm): class EditGeneralSettingsForm(FlaskForm): - email = StringField( - 'E-Mail', - validators=[DataRequired(), Length(1, 254), Email()] - ) + email = StringField('E-Mail', validators=[DataRequired(), Length(1, 254), Email()]) username = StringField( 'Username', validators=[ - DataRequired(), + InputRequired(), Length(1, 64), Regexp( USERNAME_REGEX, diff --git a/app/templates/_scripts.html.j2 b/app/templates/_scripts.html.j2 index ccfea839..f7668ab7 100644 --- a/app/templates/_scripts.html.j2 +++ b/app/templates/_scripts.html.j2 @@ -45,9 +45,14 @@ optionElementWithoutValue.disabled = true; } + // Set the data-length attribute on inputs with the maxlength attribute + for (let inputElement of document.querySelectorAll('input[maxlength]')) { + inputElement.dataset.length = inputElement.getAttribute('maxlength'); + } + // Initialize components M.AutoInit(); - M.CharacterCounter.init(document.querySelectorAll('input[data-length][type="email"], input[data-length][type="password"], input[data-length][type="text"], textarea[data-length]')); + M.CharacterCounter.init(document.querySelectorAll('input[data-length][type="text"], input[data-length][type="email"], input[data-length][type="search"], input[data-length][type="password"], input[data-length][type="tel"], input[data-length][type="url"]')); M.Dropdown.init( document.querySelectorAll('#nav-more-dropdown-trigger'), {alignment: 'right', constrainWidth: false, coverTrigger: false} diff --git a/app/templates/auth/register.html.j2 b/app/templates/auth/register.html.j2 index 99548a1e..5c195e56 100644 --- a/app/templates/auth/register.html.j2 +++ b/app/templates/auth/register.html.j2 @@ -32,9 +32,9 @@
{{ form.hidden_tag() }} - {{ wtf.render_field(form.username, data_length='64', material_icon='person') }} - {{ wtf.render_field(form.password, data_length='128', material_icon='vpn_key') }} - {{ wtf.render_field(form.password_confirmation, data_length='128', material_icon='vpn_key') }} + {{ wtf.render_field(form.username, material_icon='person') }} + {{ wtf.render_field(form.password, material_icon='vpn_key') }} + {{ wtf.render_field(form.password_confirmation, material_icon='vpn_key') }} {{ wtf.render_field(form.email, class_='validate', material_icon='email', type='email') }}
diff --git a/app/templates/auth/reset_password.html.j2 b/app/templates/auth/reset_password.html.j2 index 4be59edf..a0f4c32b 100644 --- a/app/templates/auth/reset_password.html.j2 +++ b/app/templates/auth/reset_password.html.j2 @@ -18,8 +18,8 @@
{{ form.hidden_tag() }} - {{ wtf.render_field(form.password, data_length='128') }} - {{ wtf.render_field(form.password_confirmation, data_length='128') }} + {{ wtf.render_field(form.password) }} + {{ wtf.render_field(form.password_confirmation) }}
{{ wtf.render_field(form.submit, material_icon='send') }} diff --git a/app/templates/corpora/add_corpus.html.j2 b/app/templates/corpora/add_corpus.html.j2 index 9d7f24e4..50cbc6e7 100644 --- a/app/templates/corpora/add_corpus.html.j2 +++ b/app/templates/corpora/add_corpus.html.j2 @@ -23,10 +23,10 @@ {{ form.hidden_tag() }}
- {{ wtf.render_field(form.title, data_length='32', material_icon='title') }} + {{ wtf.render_field(form.title, material_icon='title') }}
- {{ wtf.render_field(form.description, data_length='255', material_icon='description') }} + {{ wtf.render_field(form.description, material_icon='description') }}
diff --git a/app/templates/corpora/add_corpus_file.html.j2 b/app/templates/corpora/add_corpus_file.html.j2 index 8246821a..034fb5c2 100644 --- a/app/templates/corpora/add_corpus_file.html.j2 +++ b/app/templates/corpora/add_corpus_file.html.j2 @@ -23,16 +23,16 @@ {{ form.hidden_tag() }}
- {{ wtf.render_field(form.author, data_length='255', material_icon='person') }} + {{ wtf.render_field(form.author, material_icon='person') }}
- {{ wtf.render_field(form.title, data_length='255', material_icon='title') }} + {{ wtf.render_field(form.title, material_icon='title') }}
{{ wtf.render_field(form.publishing_year, material_icon='access_time') }}
- {{ wtf.render_field(form.file, accept='.vrt', placeholder='Choose your .vrt file') }} + {{ wtf.render_field(form.vrt, accept='.vrt', placeholder='Choose your .vrt file') }}
@@ -47,7 +47,7 @@
{% for field in form if field.short_name not in ['author', 'csrf_token', 'file', 'publishing_year', 'submit', 'title'] %} - {{ wtf.render_field(field, data_length='255', material_icon=field.label.text[0:1]) }} + {{ wtf.render_field(field, material_icon=field.label.text[0:1]) }} {% endfor %}
@@ -78,7 +78,7 @@ {{ super() }}