AndyRussG has uploaded a new change for review.
https://gerrit.wikimedia.org/r/154482
Change subject: Add validators module and use it in cohort_upload
......................................................................
Add validators module and use it in cohort_upload
Change-Id: Ic1c2aeb38d812ab9bdf016d87bc6090d8f3eba78
---
M tests/test_controllers/test_cohorts.py
M wikimetrics/controllers/cohorts.py
M wikimetrics/forms/cohort_upload.py
M wikimetrics/forms/fields.py
A wikimetrics/forms/validators.py
5 files changed, 91 insertions(+), 29 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/analytics/wikimetrics
refs/changes/82/154482/1
diff --git a/tests/test_controllers/test_cohorts.py
b/tests/test_controllers/test_cohorts.py
index 5181de7..739349e 100644
--- a/tests/test_controllers/test_cohorts.py
+++ b/tests/test_controllers/test_cohorts.py
@@ -379,7 +379,7 @@
))
assert_equal(response.status_code, 200)
assert_true(response.data.find('<h3>Create a Cohort') >= 0)
- assert_true(response.data.find('That Cohort name is already taken') >=
0)
+ assert_true(response.data.find('This cohort name is taken.') >= 0)
def test_upload_works(self):
response = self.app.post('/cohorts/upload', data=dict(
diff --git a/wikimetrics/controllers/cohorts.py
b/wikimetrics/controllers/cohorts.py
index f7ff8ac..ca20507 100644
--- a/wikimetrics/controllers/cohorts.py
+++ b/wikimetrics/controllers/cohorts.py
@@ -185,10 +185,6 @@
if not form.validate():
flash('Please fix validation problems.', 'warning')
- # NOTE: The following two lines will be removed in validation
refactor
- elif g.cohort_service.get_cohort_by_name(db.get_session(),
form.name.data):
- flash('That Cohort name is already taken.', 'warning')
-
else:
form.parse_records()
vc = ValidateCohort.from_upload(form, current_user.id)
@@ -210,6 +206,10 @@
@app.route('/cohorts/validate/name')
def validate_cohort_name_allowed():
+ """
+ Returns true if there are no other cohorts with this name. Remote call is
+ set up in static/js/cohortUpload.js.
+ """
name = request.args.get('name')
session = db.get_session()
available = g.cohort_service.get_cohort_by_name(session, name) is None
@@ -218,6 +218,10 @@
@app.route('/cohorts/validate/project')
def validate_cohort_project_allowed():
+ """
+ Returns true if a valid project is provided. Remote call is set up in
+ static/js/cohortUpload.js.
+ """
project = request.args.get('project')
valid = project in db.get_project_host_map()
return json.dumps(valid)
diff --git a/wikimetrics/forms/cohort_upload.py
b/wikimetrics/forms/cohort_upload.py
index 5bffe1f..63ef404 100644
--- a/wikimetrics/forms/cohort_upload.py
+++ b/wikimetrics/forms/cohort_upload.py
@@ -3,8 +3,10 @@
from wtforms.validators import Required
from wikimetrics.utils import parse_username
-from fields import RequiredIfNot
from secure_form import WikimetricsSecureForm
+from validators import (
+ CohortNameUnused, CohortNameLegalCharacters, ProjectExists, RequiredIfNot
+)
class CohortUpload(WikimetricsSecureForm):
@@ -16,10 +18,15 @@
when we read text fields (user names or user ids) from a csv file those
would be
returned as strings via python csv module.
"""
- name = StringField([Required()])
+ name = StringField('Name',
+ [Required(), CohortNameUnused(),
+ CohortNameLegalCharacters()])
+
description = TextAreaField()
- project = StringField('Default Project', [Required()])
- csv = FileField('Upload File',
[RequiredIfNot('paste_usernames')])
+ project = StringField('Default Project',
+ [Required(), ProjectExists()])
+
+ csv = FileField('Upload File',
[RequiredIfNot('paste_username')])
paste_username = TextAreaField('Paste Usernames',
[RequiredIfNot('csv')])
validate_as_user_ids = RadioField('Validate As', [Required()], choices=[
('True', 'User Ids (Numbers found in the user_id column of the user
table)'),
diff --git a/wikimetrics/forms/fields.py b/wikimetrics/forms/fields.py
index bb016e9..7f60466 100644
--- a/wikimetrics/forms/fields.py
+++ b/wikimetrics/forms/fields.py
@@ -1,6 +1,5 @@
from datetime import datetime, date, time
from wtforms import Field, BooleanField, DateField, DateTimeField
-from wtforms.validators import Required, ValidationError
from wtforms.widgets import TextInput
@@ -97,22 +96,3 @@
def report_invalid(self):
self.data = None
raise ValueError(self.gettext('Not a valid datetime value'))
-
-
-class RequiredIfNot(Required):
- """
- A validator which makes a field mutually exclusive with another
- """
-
- def __init__(self, other_field_name, *args, **kwargs):
- self.other_field_name = other_field_name
- super(RequiredIfNot, self).__init__(*args, **kwargs)
-
- def __call__(self, form, field):
- other_field = form._fields.get(self.other_field_name)
- other_field_set = other_field and bool(other_field.data)
- field_set = field and bool(field.data)
- if other_field_set == field_set:
- raise ValidationError('Please use either {0} or {1}'.format(
- other_field.label.text, field.label.text
- ))
diff --git a/wikimetrics/forms/validators.py b/wikimetrics/forms/validators.py
new file mode 100644
index 0000000..1c9adc0
--- /dev/null
+++ b/wikimetrics/forms/validators.py
@@ -0,0 +1,71 @@
+import re
+from wtforms import ValidationError
+from wtforms.validators import Required
+
+from wikimetrics.configurables import db
+from wikimetrics.api import CohortService
+
+
+class CohortNameUnused(object):
+ """
+ Checks that a cohort name is unused.
+
+ Note: the same message appears in static/js/cohortUpload.js, and the same
+ logic is in wikimetrics.controllers.cohorts.validate_cohort_name_allowed().
+ This is because the upload form is validated on both the client and the
server.
+
+ TODO: Maybe add this constraint to the model, too?
+ """
+
+ def __call__(self, form, field):
+ session = db.get_session()
+
+ if CohortService().get_cohort_by_name(session, field.data) is not None:
+ raise ValidationError('This cohort name is taken.')
+
+
+class CohortNameLegalCharacters(object):
+ """
+ Checks that a cohort name only contains allowed characters.
+ Note: the same logic and message also appear in static/js/cohortUpload.js.
+ This is because the upload form is validated on both the client and the
server.
+ """
+
+ def __call__(self, form, field):
+
+ if not re.match(r"^[0-9_\-A-Za-z ]*$", field.data):
+ raise ValidationError('Cohort names should only contain letters, '
+ 'numbers, spaces, dashes, and underscores.')
+
+
+class ProjectExists(object):
+ """
+ Checks that a project exists.
+ Note: the same message appears in static/js/cohortUpload.js, and the same
+ logic is in
wikimetrics.controllers.cohorts.validate_cohort_project_allowed().
+ This is because the upload form is validated on both the client and the
server.
+ """
+
+ def __call__(self, form, field):
+
+ if field.data not in db.get_project_host_map():
+ raise ValidationError('That project does not exist.')
+
+
+class RequiredIfNot(Required):
+ """
+ A validator which makes a field mutually exclusive with another
+ """
+
+ def __init__(self, other_field_name, *args, **kwargs):
+ self.other_field_name = other_field_name
+ super(RequiredIfNot, self).__init__(*args, **kwargs)
+
+ def __call__(self, form, field):
+ other_field = form._fields.get(self.other_field_name)
+ other_field_set = other_field and bool(other_field.data)
+ field_set = field and bool(field.data)
+ if other_field_set == field_set:
+ raise ValidationError('Please use either {0} or {1}'.format(
+ other_field.label.text, field.label.text
+ ))
--
To view, visit https://gerrit.wikimedia.org/r/154482
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: Ic1c2aeb38d812ab9bdf016d87bc6090d8f3eba78
Gerrit-PatchSet: 1
Gerrit-Project: analytics/wikimetrics
Gerrit-Branch: master
Gerrit-Owner: AndyRussG <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits