blob: 55700b19745afda7476a700316e47ca1a6d9fe3f [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import logging
import warnings
from pylons import app_globals as g, tmpl_context as c
from formencode import validators as fev
import formencode
import ew as ew_core
import ew.jinja2_ew as ew
from pytz import common_timezones, country_timezones, country_names
from paste.deploy.converters import aslist, asint
import tg
from allura.lib import validators as V
from allura.lib import helpers as h
from allura.lib import plugin
from allura.lib.widgets import form_fields as ffw
from allura.lib import exceptions as forge_exc
from allura import model as M
log = logging.getLogger(__name__)
weekdays = ['Monday', 'Tuesday', 'Wednesday',
'Thursday', 'Friday', 'Saturday', 'Sunday']
class _HTMLExplanation(ew.InputField):
template = ew.Snippet(
'''<label class="grid-4">&nbsp;</label>
<div class="grid-14" style="margin:2px;">{{widget.text}}</div>
''',
'jinja2')
class NeighborhoodProjectShortNameValidator(fev.FancyValidator):
def _validate_shortname(self, shortname, neighborhood, state):
if not h.re_project_name.match(shortname):
raise forge_exc.ProjectShortnameInvalid(
'Please use only letters, numbers, and dashes 3-15 characters long.',
shortname, state)
def _validate_allowed(self, shortname, neighborhood, state):
p = M.Project.query.get(
shortname=shortname, neighborhood_id=neighborhood._id)
if p:
raise forge_exc.ProjectConflict(
'This project name is taken.',
shortname, state)
def to_python(self, value, state=None, check_allowed=True, neighborhood=None):
"""
Validate a project shortname.
If check_allowed is False, the shortname will only be checked for
correctness. Otherwise, it will be rejected if already in use or
otherwise disallowed.
"""
if neighborhood is None:
neighborhood = M.Neighborhood.query.get(
name=state.full_dict['neighborhood'])
value = h.really_unicode(value or '').encode('utf-8').lower()
self._validate_shortname(value, neighborhood, state)
if check_allowed:
self._validate_allowed(value, neighborhood, state)
return value
class ForgeForm(ew.SimpleForm):
antispam = False
template = 'jinja:allura:templates/widgets/forge_form.html'
defaults = dict(
ew.SimpleForm.defaults,
submit_text='Save',
style='standard',
method='post',
enctype=None,
target=None)
def display_label(self, field, label_text=None):
ctx = super(ForgeForm, self).context_for(field)
label_text = (
label_text
or ctx.get('label')
or getattr(field, 'label', None)
or ctx['name'])
html = '<label for="%s">%s</label>' % (
ctx['id'], label_text)
return h.html.literal(html)
def context_for(self, field):
ctx = super(ForgeForm, self).context_for(field)
if self.antispam:
ctx['rendered_name'] = g.antispam.enc(ctx['name'])
return ctx
def display_field(self, field, ignore_errors=False):
ctx = self.context_for(field)
display = field.display(**ctx)
if ctx['errors'] and field.show_errors and not ignore_errors:
display = "%s<div class='error'>%s</div>" % (display,
ctx['errors'])
return h.html.literal(display)
def display_field_by_idx(self, idx, ignore_errors=False):
warnings.warn(
'ForgeForm.display_field_by_idx is deprecated; use '
'ForgeForm.display_field() instead', DeprecationWarning)
field = self.fields[idx]
ctx = self.context_for(field)
display = field.display(**ctx)
if ctx['errors'] and field.show_errors and not ignore_errors:
display = "%s<div class='error'>%s</div>" % (display,
ctx['errors'])
return display
class PasswordChangeBase(ForgeForm):
@property
def fields(self):
return [
ew.PasswordField(
name='pw',
label='New Password',
validator=fev.UnicodeString(
not_empty=True,
min=asint(tg.config.get('auth.min_password_len', 6)),
max=asint(tg.config.get('auth.max_password_len', 30)))),
ew.PasswordField(
name='pw2',
label='New Password (again)',
validator=fev.UnicodeString(not_empty=True)),
]
@ew_core.core.validator
def to_python(self, value, state):
d = super(PasswordChangeBase, self).to_python(value, state)
if d['pw'] != d['pw2']:
raise formencode.Invalid('Passwords must match', value, state)
return d
class PasswordChangeForm(PasswordChangeBase):
@property
def fields(self):
return [
ew.PasswordField(
name='oldpw',
label='Old Password',
validator=fev.UnicodeString(not_empty=True)),
ew.PasswordField(
name='pw',
label='New Password',
validator=fev.UnicodeString(
not_empty=True,
min=asint(tg.config.get('auth.min_password_len', 6)),
max=asint(tg.config.get('auth.max_password_len', 30)))),
ew.PasswordField(
name='pw2',
label='New Password (again)',
validator=fev.UnicodeString(not_empty=True)),
ew.HiddenField(name='return_to'),
]
@ew_core.core.validator
def to_python(self, value, state):
d = super(PasswordChangeForm, self).to_python(value, state)
if d['oldpw'] == d['pw']:
raise formencode.Invalid(
'Your old and new password should not be the same',
value, state)
return d
class PersonalDataForm(ForgeForm):
class fields(ew_core.NameList):
sex = ew.SingleSelectField(
label='Gender',
options=[ew.Option(py_value=v, label=v, selected=False)
for v in ['Male', 'Female', 'Unknown', 'Other']],
validator=formencode.All(
V.OneOfValidator(['Male', 'Female', 'Unknown', 'Other']),
fev.UnicodeString(not_empty=True)))
birthdate = ew.TextField(
label='Birth date',
validator=V.DateValidator(),
attrs=dict(value=None))
exp = _HTMLExplanation(
text="Use the format DD/MM/YYYY",
show_errors=False)
country = ew.SingleSelectField(
label='Country of residence',
validator=V.MapValidator(country_names, not_empty=False),
options=[
ew.Option(
py_value=" ", label=" -- Unknown -- ", selected=False)] +
[ew.Option(py_value=c, label=n, selected=False)
for c, n in sorted(country_names.items(),
key=lambda (k, v):v)],
attrs={'onchange': 'selectTimezone(this.value)'})
city = ew.TextField(
label='City of residence',
attrs=dict(value=None),
validator=fev.UnicodeString(not_empty=False))
timezone = ew.SingleSelectField(
label='Timezone',
attrs={'id': 'tz'},
validator=V.OneOfValidator(common_timezones, not_empty=False),
options=[
ew.Option(
py_value=" ",
label=" -- Unknown -- ")] +
[ew.Option(py_value=n, label=n)
for n in sorted(common_timezones)])
def display(self, **kw):
user = kw.get('user')
for opt in self.fields['sex'].options:
if opt.label == user.sex:
opt.selected = True
else:
opt.selected = False
if user.get_pref('birthdate'):
self.fields['birthdate'].attrs['value'] = \
user.get_pref('birthdate').strftime('%d/%m/%Y')
else:
self.fields['birthdate'].attrs['value'] = ''
for opt in self.fields['country'].options:
if opt.label == user.localization.country:
opt.selected = True
elif opt.py_value == " " and user.localization.country is None:
opt.selected = True
else:
opt.selected = False
if user.localization.city:
self.fields['city'].attrs['value'] = user.localization.city
else:
self.fields['city'].attrs['value'] = ''
for opt in self.fields['timezone'].options:
if opt.label == user.timezone:
opt.selected = True
elif opt.py_value == " " and user.timezone is None:
opt.selected = True
else:
opt.selected = False
return super(ForgeForm, self).display(**kw)
def resources(self):
def _append(x, y):
return x + y
yield ew.JSScript('''
var $allTimezones = $("#tz").clone();
var $t = {};
''' +
reduce(_append, [
'$t["' + el + '"] = ' + str([name.encode('utf-8')
for name in country_timezones[el]]) + ";\n"
for el in country_timezones]) + '''
function selectTimezone($country){
if($country == " "){
$("#tz").replaceWith($allTimezones);
}
else{
$("#tz option:gt(0)").remove();
$.each($t[$country], function(index, value){
$("#tz").append($("<option></option>").attr("value", value).text(value))
})
}
}''')
class AddTelNumberForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
class fields(ew_core.NameList):
newnumber = ew.TextField(
label='New telephone number',
attrs={'value': ''},
validator=fev.UnicodeString(not_empty=True))
def display(self, **kw):
initial_value = kw.get('initial_value', '')
self.fields['newnumber'].attrs['value'] = initial_value
return super(ForgeForm, self).display(**kw)
class AddWebsiteForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
class fields(ew_core.NameList):
newwebsite = ew.TextField(
label='New website url',
attrs={'value': ''},
validator=fev.URL())
def display(self, **kw):
initial_value = kw.get('initial_value', '')
self.fields['newwebsite'].attrs['value'] = initial_value
return super(ForgeForm, self).display(**kw)
class SkypeAccountForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
class fields(ew_core.NameList):
skypeaccount = ew.TextField(
label='Skype account',
attrs={'value': ''},
validator=fev.UnicodeString(not_empty=False))
def display(self, **kw):
initial_value = kw.get('initial_value', '')
self.fields['skypeaccount'].attrs['value'] = initial_value
return super(ForgeForm, self).display(**kw)
class RemoveTextValueForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
initial_value = kw.get('value', '')
label = kw.get('label', '')
description = kw.get('description')
self.fields = [
ew.RowField(
show_errors=False,
fields=[
ffw.DisplayOnlyField(text=label),
ffw.DisplayOnlyField(
name='oldvalue',
label=initial_value,
attrs={'value': initial_value},
show_errors=False),
ew.SubmitButton(
show_label=False,
attrs={'value': 'Remove'},
show_errors=False)])]
if description:
self.fields.append(
_HTMLExplanation(
text=description,
show_errors=False))
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveTextValueForm, self).to_python(kw, state)
d["oldvalue"] = kw.get('oldvalue', '')
return d
class AddSocialNetworkForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
@property
def fields(self):
socialnetworks = aslist(tg.config.get('socialnetworks',
['Facebook', 'Linkedin', 'Twitter', 'Google+']),
',')
return [
ew.SingleSelectField(
name='socialnetwork',
label='Social network',
validator=fev.UnicodeString(not_empty=True),
options=[ew.Option(py_value=name, label=name)
for name in socialnetworks]),
ew.TextField(
name='accounturl',
label='Account url',
validator=fev.UnicodeString(not_empty=True))
]
class RemoveSocialNetworkForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
account = kw.get('account', '')
socialnetwork = kw.get('socialnetwork', '')
self.fields = [
ew.RowField(
show_errors=False,
fields=[
ffw.DisplayOnlyField(
text='%s account' % socialnetwork,
name="socialnetwork",
attrs={'value': socialnetwork},
show_errors=False),
ffw.DisplayOnlyField(
name="account",
attrs={'value': account},
show_errors=False),
ew.SubmitButton(
show_label=False,
attrs={'value': 'Remove'},
show_errors=False)])]
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveSocialNetworkForm, self).to_python(kw, state)
d["account"] = kw.get('account', '')
d["socialnetwork"] = kw.get('socialnetwork', '')
return d
class AddInactivePeriodForm(ForgeForm):
class fields(ew_core.NameList):
startdate = ew.TextField(
label='Start date',
validator=formencode.All(
V.DateValidator(),
fev.UnicodeString(not_empty=True)))
enddate = ew.TextField(
label='End date',
validator=formencode.All(
V.DateValidator(),
fev.UnicodeString(not_empty=True)))
@ew_core.core.validator
def to_python(self, kw, state):
d = super(AddInactivePeriodForm, self).to_python(kw, state)
if d['startdate'] > d['enddate']:
raise formencode.Invalid(
'Invalid period: start date greater than end date.',
kw, state)
return d
class RemoveInactivePeriodForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
startdate = kw.get('startdate')
enddate = kw.get('enddate')
self.fields = [
ew.RowField(
show_label=False,
show_errors=False,
fields=[
ffw.DisplayOnlyField(
name='startdate',
attrs={'value': startdate.strftime('%d/%m/%Y')},
show_errors=False),
ffw.DisplayOnlyField(
name='enddate',
attrs={'value': enddate.strftime('%d/%m/%Y')},
show_errors=False),
ew.SubmitButton(
attrs={'value': 'Remove'},
show_errors=False)])]
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveInactivePeriodForm, self).to_python(kw, state)
d['startdate'] = V.convertDate(kw.get('startdate', ''))
d['enddate'] = V.convertDate(kw.get('enddate', ''))
return d
class AddTimeSlotForm(ForgeForm):
class fields(ew_core.NameList):
weekday = ew.SingleSelectField(
label='Weekday',
options=[ew.Option(py_value=wd, label=wd)
for wd in weekdays],
validator=formencode.All(
V.OneOfValidator(weekdays),
fev.UnicodeString(not_empty=True)))
starttime = ew.TextField(
label='Start time',
validator=formencode.All(
V.TimeValidator(),
fev.UnicodeString(not_empty=True)))
endtime = ew.TextField(
label='End time',
validator=formencode.All(
V.TimeValidator(),
fev.UnicodeString(not_empty=True)))
@ew_core.core.validator
def to_python(self, kw, state):
d = super(AddTimeSlotForm, self).to_python(kw, state)
if (d['starttime']['h'], d['starttime']['m']) > \
(d['endtime']['h'], d['endtime']['m']):
raise formencode.Invalid(
'Invalid period: start time greater than end time.',
kw, state)
return d
class RemoveTimeSlotForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
weekday = kw.get('weekday', '')
starttime = kw.get('starttime')
endtime = kw.get('endtime')
self.fields = [
ew.RowField(
show_errors=False,
show_label=False,
fields=[
ffw.DisplayOnlyField(
name='weekday',
attrs={'value': weekday},
show_errors=False),
ffw.DisplayOnlyField(
name='starttime',
attrs={'value': starttime.strftime('%H:%M')},
show_errors=False),
ffw.DisplayOnlyField(
name='endtime',
attrs={'value': endtime.strftime('%H:%M')},
show_errors=False),
ew.SubmitButton(
show_errors=False,
attrs={'value': 'Remove'})])]
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveTimeSlotForm, self).to_python(kw, state)
d["weekday"] = kw.get('weekday', None)
d['starttime'] = V.convertTime(kw.get('starttime', ''))
d['endtime'] = V.convertTime(kw.get('endtime', ''))
return d
class RemoveTroveCategoryForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
cat = kw.get('category')
self.fields = [
ew.RowField(
show_errors=False,
show_label=False,
fields=[
ew.LinkField(
text=cat.fullname,
href="/categories/%s" % cat.shortname),
ew.SubmitButton(
show_errors=False,
attrs={'value': 'Remove'})],
hidden_fields=[
ew.HiddenField(
name='categoryid',
attrs={'value': cat.trove_cat_id})])]
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveTroveCategoryForm, self).to_python(kw, state)
d["categoryid"] = kw.get('categoryid')
if d["categoryid"]:
d["categoryid"] = int(d['categoryid'])
return d
class AddTroveCategoryForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
class fields(ew_core.NameList):
uppercategory_id = ew.HiddenField(
attrs={'value': ''},
show_errors=False)
categoryname = ew.TextField(
label="Category name",
validator=fev.UnicodeString(not_empty=True))
def display(self, **kw):
upper_category = kw.get('uppercategory_id', 0)
self.fields['uppercategory_id'].attrs['value'] = upper_category
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(AddTroveCategoryForm, self).to_python(kw, state)
d["uppercategory_id"] = kw.get('uppercategory_id', 0)
return d
class AddUserSkillForm(ForgeForm):
defaults = dict(ForgeForm.defaults)
class fields(ew_core.NameList):
selected_skill = ew.HiddenField(
attrs={'value': ''},
show_errors=False,
validator=fev.UnicodeString(not_empty=True))
level = ew.SingleSelectField(
label="Level of knowledge",
options=[
ew.Option(py_value="low", label="Low level"),
ew.Option(py_value="medium", label="Medium level"),
ew.Option(py_value="high", label="Advanced level")],
validator=formencode.All(
V.OneOfValidator(['low', 'medium', 'high']),
fev.UnicodeString(not_empty=True)))
comment = ew.TextArea(
label="Additional comments",
validator=fev.UnicodeString(not_empty=False),
attrs={'rows': 5, 'cols': 30})
def display(self, **kw):
category = kw.get('selected_skill')
self.fields["selected_skill"].attrs['value'] = category
return super(ForgeForm, self).display(**kw)
class SelectSubCategoryForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text="Continue")
class fields(ew_core.NameList):
selected_category = ew.SingleSelectField(
name="selected_category",
label="Available categories",
options=[])
def display(self, **kw):
categories = kw.get('categories')
self.fields['selected_category'].options = \
[ew.Option(py_value=el.trove_cat_id, label=el.fullname)
for el in categories]
self.fields['selected_category'].validator = \
validator = formencode.All(
V.OneOfValidator(categories),
fev.UnicodeString(not_empty=True))
return super(ForgeForm, self).display(**kw)
class RemoveSkillForm(ForgeForm):
defaults = dict(ForgeForm.defaults, submit_text=None, show_errors=False)
def display(self, **kw):
skill = kw.get('skill')
comment = skill['comment']
if not comment:
comment = "&nbsp;"
self.fields = [
ew.RowField(
show_errors=False,
hidden_fields=[
ew.HiddenField(
name="categoryid",
attrs={'value': skill['skill'].trove_cat_id},
show_errors=False)
],
fields=[
ffw.DisplayOnlyField(text=skill['skill'].fullpath),
ffw.DisplayOnlyField(text=skill['level']),
ffw.DisplayOnlyField(text=comment),
ew.SubmitButton(
show_label=False,
attrs={'value': 'Remove'},
show_errors=False)])]
return super(ForgeForm, self).display(**kw)
@ew_core.core.validator
def to_python(self, kw, state):
d = super(RemoveSkillForm, self).to_python(kw, state)
d["categoryid"] = kw.get('categoryid', None)
return d
class UploadKeyForm(ForgeForm):
class fields(ew_core.NameList):
key = ew.TextArea(label='SSH Public Key')
class RegistrationForm(ForgeForm):
@property
def fields(self):
username = ew.TextField(
name='username',
label='Desired Username',
validator=fev.Regex(
h.re_project_name))
username.validator._messages['invalid'] = (
'Usernames must include only letters, numbers, and dashes.'
' They must also start with a letter and be at least 3 characters'
' long.')
return [
ew.TextField(
name='display_name',
label='Displayed Name',
validator=fev.UnicodeString(not_empty=True)),
username,
ew.PasswordField(
name='pw',
label='New Password',
validator=fev.UnicodeString(
not_empty=True,
min=asint(tg.config.get('auth.min_password_len', 6)),
max=asint(tg.config.get('auth.max_password_len', 30)))),
ew.PasswordField(
name='pw2',
label='New Password (again)',
validator=fev.UnicodeString(not_empty=True)),
]
@ew_core.core.validator
def to_python(self, value, state):
d = super(RegistrationForm, self).to_python(value, state)
value['username'] = username = value['username'].lower()
if M.User.by_username(username):
raise formencode.Invalid(
'That username is already taken. Please choose another.',
value, state)
if d['pw'] != d['pw2']:
raise formencode.Invalid('Passwords must match', value, state)
return d
class AdminForm(ForgeForm):
template = 'jinja:allura:templates/widgets/admin_form.html'
class NeighborhoodOverviewForm(ForgeForm):
template = 'jinja:allura:templates/widgets/neighborhood_overview_form.html'
class fields(ew_core.NameList):
name = ew.TextField()
redirect = ew.TextField()
homepage = ffw.AutoResizeTextarea()
allow_browse = ew.Checkbox(label='')
show_title = ew.Checkbox(label='')
css = ffw.AutoResizeTextarea()
project_template = ffw.AutoResizeTextarea(
validator=V.JsonValidator(if_empty=''))
icon = ew.FileField()
tracking_id = ew.TextField()
project_list_url = ew.TextField(validator=fev.URL())
anchored_tools = ffw.AutoResizeTextarea()
prohibited_tools = ffw.AutoResizeTextarea()
def from_python(self, value, state):
if value.features['css'] == "picker":
self.list_color_inputs = True
self.color_inputs = value.get_css_for_picker()
else:
self.list_color_inputs = False
self.color_inputs = []
return super(NeighborhoodOverviewForm, self).from_python(value, state)
def display_field(self, field, ignore_errors=False):
if field.name == "css" and self.list_color_inputs:
display = '<table class="table_class">'
ctx = self.context_for(field)
for inp in self.color_inputs:
additional_inputs = inp.get('additional', '')
empty_val = False
if inp['value'] is None or inp['value'] == '':
empty_val = True
display += '<tr><td class="left"><label>%(label)s</label></td>'\
'<td><input type="checkbox" name="%(ctx_name)s-%(inp_name)s-def" %(def_checked)s>default</td>'\
'<td class="right"><div class="%(ctx_name)s-%(inp_name)s-inp"><table class="input_inner">'\
'<tr><td><input type="text" class="%(inp_type)s" name="%(ctx_name)s-%(inp_name)s" '\
'value="%(inp_value)s"></td><td>%(inp_additional)s</td></tr></table></div></td></tr>\n' % {'ctx_id': ctx['id'],
'ctx_name': ctx['name'],
'inp_name': inp['name'],
'inp_value': inp['value'],
'label': inp['label'],
'inp_type': inp['type'],
'def_checked': 'checked="checked"' if empty_val else '',
'inp_additional': additional_inputs}
display += '</table>'
if ctx['errors'] and field.show_errors and not ignore_errors:
display = "%s<div class='error'>%s</div>" % (display,
ctx['errors'])
return h.html.literal(display)
else:
return super(NeighborhoodOverviewForm, self).display_field(field, ignore_errors)
@ew_core.core.validator
def to_python(self, value, state):
d = super(NeighborhoodOverviewForm, self).to_python(value, state)
neighborhood = M.Neighborhood.query.get(name=d.get('name', None))
if neighborhood and neighborhood.features['css'] == "picker":
css_form_dict = {}
for key in value.keys():
def_key = "%s-def" % (key)
if key[:4] == "css-" and def_key not in value:
css_form_dict[key[4:]] = value[key]
d['css'] = M.Neighborhood.compile_css_for_picker(css_form_dict)
return d
def resources(self):
for r in super(NeighborhoodOverviewForm, self).resources():
yield r
yield ew.CSSLink('css/colorPicker.css')
yield ew.CSSLink('css/jqfontselector.css')
yield ew.CSSScript('''
table.table_class, table.input_inner{
margin: 0;
padding: 0;
width: 99%;
}
table.table_class .left{ text-align: left; }
table.table_class .right{ text-align: right; width: 50%;}
table.table_class tbody tr td { border: none; }
table.table_class select.add_opt {width: 5em; margin:0; padding: 0;}
''')
yield ew.JSLink('js/jquery.colorPicker.js')
yield ew.JSLink('js/jqfontselector.js')
yield ew.JSScript('''
$(function(){
$('.table_class').find('input[type="checkbox"]').each(function(index, element) {
var cb_name = $(this).attr('name');
var inp_name = cb_name.substr(0, cb_name.length-4);
var inp_el = $('div[class="'+inp_name+'-inp"]');
if ($(this).attr('checked')) {
inp_el.hide();
}
$(element).click(function(e) {
if ($(this).attr('checked')) {
inp_el.hide();
} else {
inp_el.show();
}
});
});
$('.table_class').find('input.color').each(function(index, element) {
$(element).colorPicker();
});
$('.table_class').find('input.font').each(function(index, element) {
$(element).fontSelector();
});
});
''')
class NeighborhoodAddProjectForm(ForgeForm):
template = 'jinja:allura:templates/widgets/neighborhood_add_project.html'
antispam = True
defaults = dict(
ForgeForm.defaults,
method='post',
submit_text='Start',
neighborhood=None)
@property
def fields(self):
provider = plugin.ProjectRegistrationProvider.get()
tools_options = []
for ep, tool in g.entry_points["tool"].iteritems():
if tool.status == 'production' and tool._installable(tool_name=ep,
nbhd=c.project.neighborhood,
project_tools=[]):
tools_options.append(ew.Option(label=tool.tool_label, html_value=ep))
return ew_core.NameList([
ew.HiddenField(name='project_description', label='Public Description'),
ew.HiddenField(name='neighborhood', label='Neighborhood'),
ew.Checkbox(name='private_project', label="", attrs={'class': 'unlabeled'}),
ew.InputField(name='project_name', label='Project Name',
field_type='text',
validator=formencode.All(
fev.UnicodeString(not_empty=True, max=40),
V.MaxBytesValidator(max=40)),
),
ew.InputField(name='project_unixname',
label='Short Name', field_type='text',
validator=provider.shortname_validator),
ew.CheckboxSet(name='tools', options=tools_options),
])
def resources(self):
for r in super(NeighborhoodAddProjectForm, self).resources():
yield r
yield ew.CSSLink('css/add_project.css')
neighborhood = g.antispam.enc('neighborhood')
project_name = g.antispam.enc('project_name')
project_unixname = g.antispam.enc('project_unixname')
yield ew.JSScript('''
$(function(){
var $scms = $('input[type=checkbox].scm');
var $nbhd_input = $('input[name="%(neighborhood)s"]');
var $name_input = $('input[name="%(project_name)s"]');
var $unixname_input = $('input[name="%(project_unixname)s"]');
var $url_fragment = $('#url_fragment');
var $form = $name_input.closest('form');
var delay = (function(){
var timers = {};
return function(callback, ms){
clearTimeout (timers[callback]);
timers[callback] = setTimeout(callback, ms);
};
})();
$name_input.focus();
var update_icon = function($input) {
var $success_icon = $input.parent().next().find('.success_icon');
var $error_icon = $input.parent().next().find('.error_icon');
var is_error = $input.nextAll('.error').is(':visible');
$success_icon.toggle(!is_error);
$error_icon.toggle(is_error);
};
if ($name_input.val() !== '') {
update_icon($name_input);
}
if ($unixname_input.val() !== '') {
update_icon($unixname_input);
}
var handle_error = function($input, message) {
var $error_field = $input.nextAll('.error');
if ($error_field.length === 0) {
$error_field = $('<div class="error" style="display: none"></div>').insertAfter($input);
}
$error_field.text(message).toggle(!!message);
update_icon($input);
};
$form.submit(function(e) {
var has_errors = $name_input.add($unixname_input).nextAll('.error').is(':visible');
if (has_errors || $name_input.val() === '' || $unixname_input.val() === '') {
e.preventDefault();
alert('You must resolve the issues with the project name.');
return false;
}
});
$scms.change(function(){
if ( $(this).attr('checked') ) {
var on = this;
$scms.each(function(){
if ( this !== on ) {
$(this).removeAttr('checked');
}
});
}
});
var check_names = function() {
var data = {
'neighborhood': $nbhd_input.val(),
'project_name': $name_input.val(),
'project_unixname': $unixname_input.val()
};
$.getJSON('check_names', data, function(result){
handle_error($name_input, result.project_name);
handle_error($unixname_input, result.project_unixname);
});
};
var manual = false;
$name_input.keyup(function(){
delay(function() {
if (!manual) {
var data = {
'project_name':$name_input.val()
};
$.getJSON('suggest_name', data, function(result){
$unixname_input.val(result.suggested_name);
$url_fragment.text(result.suggested_name);
check_names();
});
} else {
check_names();
}
}, 500);
});
$unixname_input.change(function() {
manual = true;
});
$unixname_input.keyup(function(){
$url_fragment.text($unixname_input.val());
delay(check_names, 500);
});
});
''' % dict(neighborhood=neighborhood, project_name=project_name, project_unixname=project_unixname))
class MoveTicketForm(ForgeForm):
defaults = dict(
ForgeForm.defaults,
action='',
method='post',
submit_text='Move')
class fields(ew_core.NameList):
tracker = ew.SingleSelectField(
label='Tracker mount point',
options=[])
def __init__(self, *args, **kwargs):
trackers = kwargs.pop('trackers', [])
super(MoveTicketForm, self).__init__(*args, **kwargs)
self.fields.tracker.options = (
[ew.Option(py_value=v, label=l, selected=s)
for v, l, s in sorted(trackers, key=lambda x: x[1])])
class CsrfForm(ew.SimpleForm):
@property
def hidden_fields(self):
return [ew.HiddenField(name='_session_id')]
def context_for(self, field):
ctx = super(CsrfForm, self).context_for(field)
if field.name == '_session_id':
ctx['value'] = tg.request.cookies.get('_session_id')
return ctx
class AwardGrantForm(ForgeForm):
def __init__(self, *args, **kw):
self._awards = kw.pop('awards', [])
self._project_select_url = kw.pop('project_select_url', '')
super(AwardGrantForm, self).__init__(*args, **kw)
def award_options(self):
return [ew.Option(py_value=a.short, label=a.short) for a in self._awards]
@property
def fields(self):
return [
ew.SingleSelectField(
name='grant',
label='Award',
options=self.award_options()),
ffw.NeighborhoodProjectSelect(
self._project_select_url,
name='recipient'),
ew.TextField(
name='url',
label='Award URL',
validator=fev.URL()),
ew.TextArea(
name='comment',
label='Comment',
validator=fev.UnicodeString(not_empty=False),
attrs={'rows': 5, 'cols': 30}),
]
class AdminSearchForm(ForgeForm):
defaults = dict(
ForgeForm.defaults,
action='',
method='get',
style='wide',
submit_text=None)
def __init__(self, fields, *args, **kw):
super(AdminSearchForm, self).__init__(*args, **kw)
self._fields = fields
@property
def fields(self):
search_fields = [ew.Option(py_value=v, label=l) for v, l in self._fields]
search_fields.append(ew.Option(py_value='__custom__', label='custom query'))
return [
ew.RowField(fields=[
ew.SingleSelectField(
name='f',
show_label=False,
options=search_fields),
ew.InputField(name='q', show_label=False, attrs={'style': 'width: 600px'}),
ew.SubmitButton(
show_label=False,
attrs={
'value': 'Search',
'style': 'float:none; margin-top:3px;',
},
show_errors=False),
])]
def context_for(self, field):
ctx = super(AdminSearchForm, self).context_for(field)
if field.name is None and not ctx.get('value'):
# RowField does not pass context down to the children :(
render_ctx = ew_core.widget_context.render_context
ctx['value'] = {'q': render_ctx.get('q'), 'f': render_ctx.get('f')}
return ctx