from functools import partial import itertools import urlparse from flask.ext.wtf import Form from wtforms import Form as InsecureForm from wtforms import (TextField, DateField, DecimalField, IntegerField, SelectField, SelectMultipleField, FieldList, FormField) from wtforms.widgets import TextInput, ListWidget, html_params, HTMLString, CheckboxInput, Select from wtforms.validators import DataRequired, Optional, URL, Email, Length, NumberRange, ValidationError from flask.ext.babel import Babel, gettext as _ from .constants import STEPS from .models import ISP class InputListWidget(ListWidget): def __call__(self, field, **kwargs): kwargs.setdefault('id', field.id) html = ['<%s %s>' % (self.html_tag, html_params(**kwargs))] for subfield in field: html.append('
irc://irc.isp.net/#isp
or '+
'xmpp:isp@chat.isp.net?join
')])
covered_areas = FieldList(MyFormField(CoveredArea, widget=partial(InputListWidget(), class_='formfield')),
min_entries=1, widget=InputListWidget(),
description=[None, _(u'Descriptive name of the covered areas and technologies deployed')])
latitude = DecimalField(_(u'latitude'), validators=[Optional(), NumberRange(min=-90, max=90)],
description=[None, _(u'Geographical coordinates of your registered office or usual meeting location.')])
longitude = DecimalField(_(u'longitude'), validators=[Optional(), NumberRange(min=-180, max=180)])
step = SelectField(_(u'progress step'), choices=[(k, u'%u - %s' % (k, STEPS[k])) for k in STEPS], coerce=int)
member_count = IntegerField(_(u'members'), validators=[Optional(), NumberRange(min=0)],
description=[None, _('Number of members')])
subscriber_count = IntegerField(_(u'subscribers'), validators=[Optional(), NumberRange(min=0)],
description=[None, _('Number of subscribers to an internet access')])
tech_email = TextField(_('Email'), validators=[Email(), DataRequired()], description=[None,
_('Technical contact, in case of problems with your submission')])
def validate(self, *args, **kwargs):
r=super(ProjectForm, self).validate(*args, **kwargs)
if (self.latitude.data is None) != (self.longitude.data is None):
self._fields['longitude'].errors += [_(u'You must fill both fields')]
r=False
return r
def validate_covered_areas(self, field):
if len(filter(lambda e: e['name'], field.data)) == 0:
# not printed, whatever..
raise ValidationError(_(u'You must specify at least one area'))
def to_json(self, json=None):
if json is None:
json={}
json['name'] = self.name.data
def optstr(k, v):
if k in json or v:
json[k]=v
def optlist(k, v):
if k in json or len(v):
json[k]=v
optstr('shortname', self.shortname.data)
optstr('description', self.description.data)
optstr('logoURL', self.logo_url.data)
optstr('website', self.website.data)
optstr('otherWebsites', dict(((w['name'], w['url']) for w in self.other_websites.data if w['name'])))
optstr('email', self.contact_email.data)
optstr('mainMailingList', self.main_ml.data)
optstr('creationDate', self.creation_date.data.isoformat() if self.creation_date.data else None)
optstr('progressStatus', self.step.data)
optstr('memberCount', self.member_count.data)
optstr('subscriberCount', self.subscriber_count.data)
optlist('chatrooms', filter(bool, self.chatrooms.data)) # remove empty strings
optstr('coordinates', {'latitude': self.latitude.data, 'longitude': self.longitude.data}
if self.latitude.data else {})
optlist('coveredAreas', filter(lambda e: e['name'], self.covered_areas.data))
return json
@classmethod
def edit_json(cls, isp):
json=isp.json
obj=type('abject', (object,), {})()
def set_attr(attr, itemk=None, d=json):
if itemk is None:
itemk=attr
if itemk in d:
setattr(obj, attr, d[itemk])
set_attr('name')
set_attr('shortname')
set_attr('description')
set_attr('logo_url', 'logoURL')
set_attr('website')
set_attr('contact_email', 'email')
set_attr('main_ml', 'mainMailingList')
set_attr('creation_date', 'creationDate')
if hasattr(obj, 'creation_date'):
obj.creation_date=ISP.str2date(obj.creation_date)
set_attr('step', 'progressStatus')
set_attr('member_count', 'memberCount')
set_attr('subscriber_count', 'subscriberCount')
set_attr('chatrooms', 'chatrooms')
if 'coordinates' in json:
set_attr('latitude', d=json['coordinates'])
set_attr('longitude', d=json['coordinates'])
if 'otherWebsites' in json:
setattr(obj, 'other_websites', [{'name': n, 'url': w} for n, w in json['otherWebsites'].iteritems()])
set_attr('covered_areas', 'coveredAreas')
obj.tech_email=isp.tech_email
return cls(obj=obj)
class URLField(TextField):
def _value(self):
if isinstance(self.data, basestring):
return self.data
elif self.data is None:
return ''
else:
return urlparse.urlunsplit(self.data)
def process_formdata(self, valuelist):
if valuelist:
try:
self.data = urlparse.urlsplit(valuelist[0])
except:
self.data = None
raise ValidationError(_(u'Invalid URL'))
def is_url_unique(url):
if isinstance(url, basestring):
url=urlparse.urlsplit(url)
t=list(url)
t[2]=''
u1=urlparse.urlunsplit(t)
t[0]='http' if t[0] == 'https' else 'https'
u2=urlparse.urlunsplit(t)
if ISP.query.filter(ISP.json_url.startswith(u1) | ISP.json_url.startswith(u2)).count() > 0:
return False
return True
class ProjectJSONForm(Form):
json_url = URLField(_(u'base url'), description=[_(u'E.g. https://isp.com/'),
_(u'A ressource implementing our JSON-Schema specification '+
'must exist at path /isp.json')])
tech_email = TextField(_(u'Email'), validators=[Email()], description=[None,
_(u'Technical contact, in case of problems')])
def validate_json_url(self, field):
if not field.data.netloc:
raise ValidationError(_(u'Invalid URL'))
if field.data.scheme not in ('http', 'https'):
raise ValidationError(_(u'Invalid URL (must be HTTP(s))'))
if not field.object_data and not is_url_unique(field.data):
raise ValidationError(_(u'This URL is already in our database'))
class RequestEditToken(Form):
tech_email = TextField(_(u'Tech Email'), validators=[Email()], description=[None,
_(u'The Technical contact you provided while registering')])