Skip to content

Commit

Permalink
Merge pull request #579 from /issues/432/2
Browse files Browse the repository at this point in the history
Fixes #432 - Give common problem types as a choice for the user
  • Loading branch information
Mike Taylor committed Mar 9, 2015
2 parents 430a6e0 + bc8be6b commit 51c6b98
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 123 deletions.
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Flask-Cache==0.13.1
Flask-Limiter==0.7.4
Flask-SQLAlchemy==1.0
GitHub-Flask==0.3.4
WTForms==1.0.5
WTForms==2.0.2
ua-parser==0.3.5
nose==1.3.1
blinker==1.3
29 changes: 22 additions & 7 deletions tests/functional/reporting.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,22 +36,37 @@ define([
.get(require.toUrl(url + '?open=1'))
.findByCssSelector('#url').click()
.end()
.findByCssSelector('#summary').click()
.findByCssSelector('#browser').click()
.end()
.findByCssSelector('#url').type('hi')
.findByXpath('//*[@id="new-report"]/div/form/div[1]/div[2]/div[1]').getAttribute('class')
.then(function (className) {
assert.include(className, 'has-error');
assert.notInclude(className, 'no-error');
})
.end()
.findByCssSelector('#summary').click()
.findByCssSelector('#url').type('sup')
.end()
.findByCssSelector('.u-formGroup').getAttribute('class')
// xpath to the #url formGroup
.findByXpath('//*[@id="new-report"]/div/form/div[1]/div[2]/div[1]').getAttribute('class')
.then(function (className) {
assert.include(className, 'no-error');
assert.notInclude(className, 'has-error');
})
.end()
.findByCssSelector('#summary').type('sup')
// click in the textarea to trigger validation for radios
.findByCssSelector('#description').click()
.end()
.findByXpath('//*[@id="new-report"]/div/form/div[1]/div[1]/fieldset').getAttribute('class')
.then(function (className) {
assert.include(className, 'has-error');
assert.notInclude(className, 'no-error');
})
.end()
// pick a problem type
.findByCssSelector('#problem_category-0').click()
.end()
// xpath to the #summary formGroup
.findByXpath('//*[@id="new-report"]/div/form/div[1]/div[2]/div').getAttribute('class')
// validation message should be removed now
.findByXpath('//*[@id="new-report"]/div/form/div[1]/div[1]/fieldset').getAttribute('class')
.then(function (className) {
assert.include(className, 'no-error');
assert.notInclude(className, 'has-error');
Expand Down
75 changes: 37 additions & 38 deletions webcompat/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,24 @@
from wtforms import RadioField
from wtforms import StringField
from wtforms import TextAreaField
from wtforms.validators import InputRequired
from wtforms.validators import Length
from wtforms.validators import Optional
from wtforms.validators import Required

AUTH_REPORT = 'github-auth-report'
PROXY_REPORT = 'github-proxy-report'
SCHEMES = ('http://', 'https://')

owner_choices = [(u'True', u'Yes'), (u'False', u'No')]
problem_choices = [(u'browser_bug', u'Looks like the browser has a bug'),
(u'site_bug', u'Looks like the website has a bug.'),
(u'unknown_bug', u'Don\'t know but something\'s wrong.')]
problem_choices = [
(u'detection_bug', u'Desktop site instead of mobile site'),
(u'mobile_site_bug', u'Mobile site is not usable'),
(u'video_bug', u'Video doesn\'t play'),
(u'layout_bug', u'Layout is messed up'),
(u'text_bug', u'Text is not visible'),
(u'unknown_bug', u'Somethign else - I\'ll add details below')
]
url_message = u'A URL is required.'
summary_message = u'Please give a summary.'
radio_message = u'Problem type required.'
username_message = u'A valid username must be {0} characters long'.format(
random.randrange(0, 99))

Expand All @@ -41,19 +45,16 @@

class IssueForm(Form):
'''Define form fields and validation for our bug reporting form.'''
url = StringField(u'Site URL*', [Required(message=url_message)])
url = StringField(u'Site URL*', [InputRequired(message=url_message)])
browser = StringField(u'Browser / Version', [Optional()])
os = StringField(u'Operating System', [Optional()])
summary = StringField(u'Problem in 5 words*',
[Required(message=summary_message)])
username = StringField(u'Username',
[Length(max=0, message=username_message)])
description = TextAreaField(u'How can we replicate this?', [Optional()],
description = TextAreaField(u'Give more details', [Optional()],
default=desc_default)
site_owner = RadioField(u'Is this your website?', [Optional()],
choices=owner_choices)
problem_category = RadioField(u'What seems to be the trouble?',
[Optional()], choices=problem_choices)
problem_category = RadioField(u'What seems to be the trouble?*',
[InputRequired(message=radio_message)],
choices=problem_choices)


def get_problem(category):
Expand All @@ -65,14 +66,12 @@ def get_problem(category):
return u'Unknown'


def get_owner(is_site_owner):
'''Return human-readable language (Y/N) for site owner form value.'''
if is_site_owner == 'True':
return u'Yes'
elif is_site_owner == 'False':
return u'No'
def get_problem_summary(category):
'''Allows us to special case the "Other" radio choice summary.'''
if category == 'unknown_bug':
return u'see bug description'
else:
return u'Unknown'
return get_problem(category).lower()


def wrap_label(label):
Expand Down Expand Up @@ -127,7 +126,6 @@ def build_formdata(form_object):
URL -> part of body
Description -> part of body
Category -> labels
Owner -> labels
We'll try to parse the Browser and come up with a browser label, as well
as labels like mobile, desktop, tablet.
Expand All @@ -150,27 +148,28 @@ def build_formdata(form_object):
normalized_url = normalize_url(url)
# Domain extraction
domain = domain_name(normalized_url)
problem_summary = get_problem_summary(form_object.get('problem_category'))
if domain:
summary = '{0} - {1}'.format(domain, form_object.get('summary'))
summary = '{0} - {1}'.format(domain, problem_summary)
else:
summary = '{0}'.format(form_object.get('summary'))
summary = '{0} - {1}'.format(normalized_url, problem_summary)
# Preparing the body
body = u'''{0}{1}
**URL**: {2}
**Browser / Version**: {3}
**Operating System**: {4}
**Problem type**: {5}
**Site owner**: {6}
body = u'''{browser_label}{ua_label}
**URL**: {url}
**Browser / Version**: {browser}
**Operating System**: {os}
**Problem type**: {problem_type}
**Steps to Reproduce**
{7}'''.format(get_labels(form_object.get('browser')),
wrap_label(('ua_header', form_object.get('ua_header'))),
form_object.get('url'),
form_object.get('browser'),
form_object.get('os'),
get_problem(form_object.get('problem_category')),
get_owner(form_object.get('site_owner')),
form_object.get('description'))
{description}'''.format(
browser_label=get_labels(form_object.get('browser')),
ua_label=wrap_label(('ua_header', form_object.get('ua_header'))),
url=form_object.get('url'),
browser=form_object.get('browser'),
os=form_object.get('os'),
problem_type=get_problem(form_object.get('problem_category')),
description=form_object.get('description')
)
result = {}
result['title'] = summary
result['body'] = body
Expand Down
3 changes: 3 additions & 0 deletions webcompat/static/css/development/components/form.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ input[type="radio"] {
.u-formGroup {
margin-bottom:1.6em;
}
legend.u-formLabel {
width: 100%;
}
/* bootstrap overrides */
.radio-inline, .checkbox-inline {
/* Hack to get Chrome 24+ to behave.
Expand Down
59 changes: 39 additions & 20 deletions webcompat/static/js/lib/bugform.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,18 @@
function BugForm() {
var urlField = $('#url');
var descField = $('#description');
var summaryField = $('#summary');
var problemType = $('[name=problem_category]');
var submitButtons = $('.Report-form button.Button');
var inputMap = {
'url': {
'elm': urlField, // elm is a jQuery object
'valid': false,
'valid': null,
'helpText': 'A URL is required.'
},
'summary' : {
'elm': summaryField,
'valid': false,
'helpText': 'Please give a summary.'
'problem_type': {
'elm': problemType,
'valid': null,
'helpText': 'Problem type required.'
}
};

Expand All @@ -25,8 +25,9 @@ function BugForm() {
self.checkParams();
urlField.on('input', self.copyURL);
self.disableSubmits();
urlField.on('blur input', self.checkValidity);
summaryField.on('blur input', self.checkValidity);
descField.on('focus', self.checkProblemTypeValidity);
problemType.on('change', self.checkProblemTypeValidity);
urlField.on('blur input', self.checkURLValidity);
},
checkParams: function() {
// Assumes a URI like: /?open=1&url=http://webpy.org/, for use by addons
Expand Down Expand Up @@ -60,40 +61,58 @@ function BugForm() {
submitButtons.prop('disabled', false);
submitButtons.removeClass('is-disabled');
},
/* Check to see that the form element is not empty.
checkProblemTypeValidity: function() {
if (!$('[name=problem_category]:checked').length) {
self.makeInvalid('problem_type');
} else {
self.makeValid('problem_type');
}
},
/* Check to see that the URL input element is not empty.
We don't do any other kind of validation yet. */
checkValidity: function(e) {
if ($.trim(e.target.value) === "") {
self.makeInvalid(e.target.id);
checkURLValidity: function() {
if ($.trim(urlField.val()) === "") {
self.makeInvalid('url');
} else {
self.makeValid(e.target.id);
self.makeValid('url');
}
},
makeInvalid: function(id) {
// Early return if inline help is already in place.
if (inputMap[id].elm.parent().prev('.help-inline').length) {
if (inputMap[id].valid === false) {
return;
}

var inlineHelp = $('<span></span>', {
'class': 'help-inline wc-bold',
'text': inputMap[id].helpText
});


inputMap[id].valid = false;
inputMap[id].elm.parents('.u-formGroup')
.removeClass('no-error')
.addClass('has-error');

$('<span></span>', {
'class': 'help-inline wc-bold',
'text': inputMap[id].helpText
}).insertAfter('label[for='+id+']');
if (id === 'url') {
inlineHelp.insertAfter('label[for='+id+']');
}

if (id === 'problem_type') {
inlineHelp.appendTo('legend.u-formLabel');
}

self.disableSubmits();
},
makeValid: function(id) {
inputMap[id].valid = true;
inputMap[id].elm.parents('.u-formGroup')
.removeClass('has-error')
.addClass('no-error');
inputMap[id].elm.prev('.help-inline').remove();

if (inputMap['url'].valid && inputMap['summary'].valid) {
inputMap[id].elm.parents('.u-formGroup').find('.help-inline').remove();

if (inputMap['url'].valid && inputMap['problem_type'].valid) {
self.enableSubmits();
}
},
Expand Down
Loading

0 comments on commit 51c6b98

Please sign in to comment.