|
@@ -1,6 +1,6 @@
|
|
from functools import partial
|
|
from functools import partial
|
|
import itertools
|
|
import itertools
|
|
-import urlparse
|
|
|
|
|
|
+import urllib.parse
|
|
import json
|
|
import json
|
|
import collections
|
|
import collections
|
|
from flask import current_app
|
|
from flask import current_app
|
|
@@ -46,7 +46,7 @@ class MyFormField(FormField):
|
|
|
|
|
|
@property
|
|
@property
|
|
def flattened_errors(self):
|
|
def flattened_errors(self):
|
|
- return list(itertools.chain.from_iterable(self.errors.values()))
|
|
|
|
|
|
+ return list(itertools.chain.from_iterable(list(self.errors.values())))
|
|
|
|
|
|
|
|
|
|
class GeoJSONField(TextField):
|
|
class GeoJSONField(TextField):
|
|
@@ -56,12 +56,12 @@ class GeoJSONField(TextField):
|
|
if valuelist and valuelist[0]:
|
|
if valuelist and valuelist[0]:
|
|
max_size = current_app.config['ISP_FORM_GEOJSON_MAX_SIZE']
|
|
max_size = current_app.config['ISP_FORM_GEOJSON_MAX_SIZE']
|
|
if len(valuelist[0]) > max_size:
|
|
if len(valuelist[0]) > max_size:
|
|
- raise ValueError(_(u'JSON value too big, must be less than %(max_size)s',
|
|
|
|
|
|
+ raise ValueError(_('JSON value too big, must be less than %(max_size)s',
|
|
max_size=filesize_fmt(max_size)))
|
|
max_size=filesize_fmt(max_size)))
|
|
try:
|
|
try:
|
|
self.data = json.loads(valuelist[0], object_pairs_hook=collections.OrderedDict)
|
|
self.data = json.loads(valuelist[0], object_pairs_hook=collections.OrderedDict)
|
|
except Exception as e:
|
|
except Exception as e:
|
|
- raise ValueError(_(u'Not a valid JSON value'))
|
|
|
|
|
|
+ raise ValueError(_('Not a valid JSON value'))
|
|
elif valuelist and valuelist[0].strip() == '':
|
|
elif valuelist and valuelist[0].strip() == '':
|
|
self.data = None # if an empty string was passed, set data as None
|
|
self.data = None # if an empty string was passed, set data as None
|
|
|
|
|
|
@@ -76,10 +76,10 @@ class GeoJSONField(TextField):
|
|
def pre_validate(self, form):
|
|
def pre_validate(self, form):
|
|
if self.data is not None:
|
|
if self.data is not None:
|
|
if not validate_geojson(self.data):
|
|
if not validate_geojson(self.data):
|
|
- raise StopValidation(_(u'Invalid GeoJSON, please check it'))
|
|
|
|
|
|
+ raise StopValidation(_('Invalid GeoJSON, please check it'))
|
|
if not check_geojson_spatialite(self.data):
|
|
if not check_geojson_spatialite(self.data):
|
|
current_app.logger.error('Spatialite could not decode the following GeoJSON: %s', self.data)
|
|
current_app.logger.error('Spatialite could not decode the following GeoJSON: %s', self.data)
|
|
- raise StopValidation(_(u'Unable to store GeoJSON in database'))
|
|
|
|
|
|
+ raise StopValidation(_('Unable to store GeoJSON in database'))
|
|
|
|
|
|
|
|
|
|
class Unique(object):
|
|
class Unique(object):
|
|
@@ -89,7 +89,7 @@ class Unique(object):
|
|
self.model = model
|
|
self.model = model
|
|
self.field = field
|
|
self.field = field
|
|
if not message:
|
|
if not message:
|
|
- message = _(u'this element already exists')
|
|
|
|
|
|
+ message = _('this element already exists')
|
|
self.message = message
|
|
self.message = message
|
|
|
|
|
|
def __call__(self, form, field):
|
|
def __call__(self, form, field):
|
|
@@ -112,59 +112,59 @@ TECHNOLOGIES_CHOICES = (
|
|
|
|
|
|
|
|
|
|
class CoveredArea(InsecureForm):
|
|
class CoveredArea(InsecureForm):
|
|
- name = TextField(_(u'name'), widget=partial(TextInput(), class_='input-medium', placeholder=_(u'Area')))
|
|
|
|
- technologies = SelectMultipleField(_(u'technologies'), choices=TECHNOLOGIES_CHOICES,
|
|
|
|
- widget=partial(Select(True), **{'class': 'selectpicker', 'data-title': _(u'Technologies deployed')}))
|
|
|
|
|
|
+ name = TextField(_('name'), widget=partial(TextInput(), class_='input-medium', placeholder=_('Area')))
|
|
|
|
+ technologies = SelectMultipleField(_('technologies'), choices=TECHNOLOGIES_CHOICES,
|
|
|
|
+ widget=partial(Select(True), **{'class': 'selectpicker', 'data-title': _('Technologies deployed')}))
|
|
area = GeoJSONField(_('area'), widget=partial(TextArea(), class_='geoinput'))
|
|
area = GeoJSONField(_('area'), widget=partial(TextArea(), class_='geoinput'))
|
|
|
|
|
|
def validate(self, *args, **kwargs):
|
|
def validate(self, *args, **kwargs):
|
|
r = super(CoveredArea, self).validate(*args, **kwargs)
|
|
r = super(CoveredArea, self).validate(*args, **kwargs)
|
|
if bool(self.name.data) != bool(self.technologies.data):
|
|
if bool(self.name.data) != bool(self.technologies.data):
|
|
- self._fields['name'].errors += [_(u'You must fill both fields')]
|
|
|
|
|
|
+ self._fields['name'].errors += [_('You must fill both fields')]
|
|
r = False
|
|
r = False
|
|
return r
|
|
return r
|
|
|
|
|
|
|
|
|
|
class OtherWebsites(InsecureForm):
|
|
class OtherWebsites(InsecureForm):
|
|
- name = TextField(_(u'name'), widget=partial(TextInput(), class_='input-small', placeholder=_(u'Name')))
|
|
|
|
- url = TextField(_(u'url'), widget=partial(TextInput(), class_='input-medium', placeholder=_(u'URL')),
|
|
|
|
|
|
+ name = TextField(_('name'), widget=partial(TextInput(), class_='input-small', placeholder=_('Name')))
|
|
|
|
+ url = TextField(_('url'), widget=partial(TextInput(), class_='input-medium', placeholder=_('URL')),
|
|
validators=[Optional(), URL(require_tld=True)])
|
|
validators=[Optional(), URL(require_tld=True)])
|
|
|
|
|
|
|
|
|
|
-STEP_CHOICES = [(k, LazyProxy(lambda k, s: u'%u - %s' % (k, s), k, STEPS[k], enable_cache=False)) for k in STEPS]
|
|
|
|
|
|
+STEP_CHOICES = [(k, LazyProxy(lambda k, s: '%u - %s' % (k, s), k, STEPS[k], enable_cache=False)) for k in STEPS]
|
|
|
|
|
|
|
|
|
|
class ProjectForm(Form):
|
|
class ProjectForm(Form):
|
|
- name = TextField(_(u'full name'), description=[_(u'E.g. French Data Network')],
|
|
|
|
|
|
+ name = TextField(_('full name'), description=[_('E.g. French Data Network')],
|
|
validators=[DataRequired(), Length(min=2), Unique(ISP, ISP.name)])
|
|
validators=[DataRequired(), Length(min=2), Unique(ISP, ISP.name)])
|
|
- shortname = TextField(_(u'short name'), description=[_(u'E.g. FDN')],
|
|
|
|
|
|
+ shortname = TextField(_('short name'), description=[_('E.g. FDN')],
|
|
validators=[Optional(), Length(min=2, max=15), Unique(ISP, ISP.shortname)])
|
|
validators=[Optional(), Length(min=2, max=15), Unique(ISP, ISP.shortname)])
|
|
- description = TextField(_(u'description'), description=[None, _(u'Short text describing the project')])
|
|
|
|
- logo_url = TextField(_(u'logo url'), validators=[Optional(), URL(require_tld=True)])
|
|
|
|
- website = TextField(_(u'website'), validators=[Optional(), URL(require_tld=True)])
|
|
|
|
|
|
+ description = TextField(_('description'), description=[None, _('Short text describing the project')])
|
|
|
|
+ logo_url = TextField(_('logo url'), validators=[Optional(), URL(require_tld=True)])
|
|
|
|
+ website = TextField(_('website'), validators=[Optional(), URL(require_tld=True)])
|
|
other_websites = FieldList(MyFormField(OtherWebsites, widget=partial(InputListWidget(), class_='formfield')),
|
|
other_websites = FieldList(MyFormField(OtherWebsites, widget=partial(InputListWidget(), class_='formfield')),
|
|
min_entries=1, widget=InputListWidget(),
|
|
min_entries=1, widget=InputListWidget(),
|
|
- description=[None, _(u'Additional websites that you host (e.g. wiki, etherpad...)')])
|
|
|
|
- contact_email = TextField(_(u'contact email'), validators=[Optional(), Email()],
|
|
|
|
- description=[None, _(u'General contact email address')])
|
|
|
|
- main_ml = TextField(_(u'main mailing list'), validators=[Optional(), Email()],
|
|
|
|
- description=[None, _(u'Address of your main mailing list')])
|
|
|
|
- creation_date = DateField(_(u'creation date'), validators=[Optional()], widget=partial(TextInput(), placeholder=_(u'YYYY-mm-dd')),
|
|
|
|
- description=[None, _(u'Date at which the legal structure for your project was created')])
|
|
|
|
- chatrooms = FieldList(TextField(_(u'chatrooms')), min_entries=1, widget=InputListWidget(),
|
|
|
|
- description=[None, _(u'In URI form, e.g. <code>irc://irc.isp.net/#isp</code> or ' +
|
|
|
|
|
|
+ description=[None, _('Additional websites that you host (e.g. wiki, etherpad...)')])
|
|
|
|
+ contact_email = TextField(_('contact email'), validators=[Optional(), Email()],
|
|
|
|
+ description=[None, _('General contact email address')])
|
|
|
|
+ main_ml = TextField(_('main mailing list'), validators=[Optional(), Email()],
|
|
|
|
+ description=[None, _('Address of your main mailing list')])
|
|
|
|
+ creation_date = DateField(_('creation date'), validators=[Optional()], widget=partial(TextInput(), placeholder=_('YYYY-mm-dd')),
|
|
|
|
+ description=[None, _('Date at which the legal structure for your project was created')])
|
|
|
|
+ chatrooms = FieldList(TextField(_('chatrooms')), min_entries=1, widget=InputListWidget(),
|
|
|
|
+ description=[None, _('In URI form, e.g. <code>irc://irc.isp.net/#isp</code> or ' +
|
|
'<code>xmpp:isp@chat.isp.net?join</code>')])
|
|
'<code>xmpp:isp@chat.isp.net?join</code>')])
|
|
covered_areas = FieldList(MyFormField(CoveredArea, _('Covered Areas'), widget=partial(InputListWidget(), class_='formfield')),
|
|
covered_areas = FieldList(MyFormField(CoveredArea, _('Covered Areas'), widget=partial(InputListWidget(), class_='formfield')),
|
|
min_entries=1, widget=InputListWidget(),
|
|
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'Coordinates of your registered office or usual meeting location. '
|
|
|
|
|
|
+ description=[None, _('Descriptive name of the covered areas and technologies deployed')])
|
|
|
|
+ latitude = DecimalField(_('latitude'), validators=[Optional(), NumberRange(min=-90, max=90)],
|
|
|
|
+ description=[None, _('Coordinates of your registered office or usual meeting location. '
|
|
'<strong>Required in order to appear on the map.</strong>')])
|
|
'<strong>Required in order to appear on the map.</strong>')])
|
|
- longitude = DecimalField(_(u'longitude'), validators=[Optional(), NumberRange(min=-180, max=180)])
|
|
|
|
- step = SelectField(_(u'progress step'), choices=STEP_CHOICES, coerce=int)
|
|
|
|
- member_count = IntegerField(_(u'members'), validators=[Optional(), NumberRange(min=0)],
|
|
|
|
|
|
+ longitude = DecimalField(_('longitude'), validators=[Optional(), NumberRange(min=-180, max=180)])
|
|
|
|
+ step = SelectField(_('progress step'), choices=STEP_CHOICES, coerce=int)
|
|
|
|
+ member_count = IntegerField(_('members'), validators=[Optional(), NumberRange(min=0)],
|
|
description=[None, _('Number of members')])
|
|
description=[None, _('Number of members')])
|
|
- subscriber_count = IntegerField(_(u'subscribers'), validators=[Optional(), NumberRange(min=0)],
|
|
|
|
|
|
+ subscriber_count = IntegerField(_('subscribers'), validators=[Optional(), NumberRange(min=0)],
|
|
description=[None, _('Number of subscribers to an internet access')])
|
|
description=[None, _('Number of subscribers to an internet access')])
|
|
|
|
|
|
tech_email = TextField(_('Email'), validators=[Email(), DataRequired()], description=[None,
|
|
tech_email = TextField(_('Email'), validators=[Email(), DataRequired()], description=[None,
|
|
@@ -173,20 +173,20 @@ class ProjectForm(Form):
|
|
def validate(self, *args, **kwargs):
|
|
def validate(self, *args, **kwargs):
|
|
r = super(ProjectForm, self).validate(*args, **kwargs)
|
|
r = super(ProjectForm, self).validate(*args, **kwargs)
|
|
if (self.latitude.data is None) != (self.longitude.data is None):
|
|
if (self.latitude.data is None) != (self.longitude.data is None):
|
|
- self._fields['longitude'].errors += [_(u'You must fill both fields')]
|
|
|
|
|
|
+ self._fields['longitude'].errors += [_('You must fill both fields')]
|
|
r = False
|
|
r = False
|
|
return r
|
|
return r
|
|
|
|
|
|
def validate_covered_areas(self, field):
|
|
def validate_covered_areas(self, field):
|
|
- if len(filter(lambda e: e['name'], field.data)) == 0:
|
|
|
|
|
|
+ if len([e for e in field.data if e['name']]) == 0:
|
|
# not printed, whatever..
|
|
# not printed, whatever..
|
|
- raise ValidationError(_(u'You must specify at least one area'))
|
|
|
|
|
|
+ raise ValidationError(_('You must specify at least one area'))
|
|
|
|
|
|
geojson_size = sum([len(ca.area.raw_data[0]) for ca in self.covered_areas if ca.area.raw_data])
|
|
geojson_size = sum([len(ca.area.raw_data[0]) for ca in self.covered_areas if ca.area.raw_data])
|
|
max_size = current_app.config['ISP_FORM_GEOJSON_MAX_SIZE_TOTAL']
|
|
max_size = current_app.config['ISP_FORM_GEOJSON_MAX_SIZE_TOTAL']
|
|
if geojson_size > max_size:
|
|
if geojson_size > max_size:
|
|
# TODO: XXX This is not printed !
|
|
# TODO: XXX This is not printed !
|
|
- raise ValidationError(gettext(u'The size of all GeoJSON data combined must not exceed %(max_size)s',
|
|
|
|
|
|
+ raise ValidationError(gettext('The size of all GeoJSON data combined must not exceed %(max_size)s',
|
|
max_size=filesize_fmt(max_size)))
|
|
max_size=filesize_fmt(max_size)))
|
|
|
|
|
|
def to_json(self, json=None):
|
|
def to_json(self, json=None):
|
|
@@ -222,7 +222,7 @@ class ProjectForm(Form):
|
|
optstr('progressStatus', self.step.data)
|
|
optstr('progressStatus', self.step.data)
|
|
optstr('memberCount', self.member_count.data)
|
|
optstr('memberCount', self.member_count.data)
|
|
optstr('subscriberCount', self.subscriber_count.data)
|
|
optstr('subscriberCount', self.subscriber_count.data)
|
|
- optlist('chatrooms', filter(bool, self.chatrooms.data)) # remove empty strings
|
|
|
|
|
|
+ optlist('chatrooms', list(filter(bool, self.chatrooms.data))) # remove empty strings
|
|
optstr('coordinates', {'latitude': self.latitude.data, 'longitude': self.longitude.data}
|
|
optstr('coordinates', {'latitude': self.latitude.data, 'longitude': self.longitude.data}
|
|
if self.latitude.data else {})
|
|
if self.latitude.data else {})
|
|
optlist('coveredAreas', list(transform_covered_areas(self.covered_areas.data)))
|
|
optlist('coveredAreas', list(transform_covered_areas(self.covered_areas.data)))
|
|
@@ -256,7 +256,7 @@ class ProjectForm(Form):
|
|
set_attr('latitude', d=json['coordinates'])
|
|
set_attr('latitude', d=json['coordinates'])
|
|
set_attr('longitude', d=json['coordinates'])
|
|
set_attr('longitude', d=json['coordinates'])
|
|
if 'otherWebsites' in json:
|
|
if 'otherWebsites' in json:
|
|
- setattr(obj, 'other_websites', [{'name': n, 'url': w} for n, w in json['otherWebsites'].iteritems()])
|
|
|
|
|
|
+ setattr(obj, 'other_websites', [{'name': n, 'url': w} for n, w in json['otherWebsites'].items()])
|
|
set_attr('covered_areas', 'coveredAreas')
|
|
set_attr('covered_areas', 'coveredAreas')
|
|
obj.tech_email = isp.tech_email
|
|
obj.tech_email = isp.tech_email
|
|
return cls(obj=obj)
|
|
return cls(obj=obj)
|
|
@@ -265,53 +265,53 @@ class ProjectForm(Form):
|
|
class URLField(TextField):
|
|
class URLField(TextField):
|
|
|
|
|
|
def _value(self):
|
|
def _value(self):
|
|
- if isinstance(self.data, basestring):
|
|
|
|
|
|
+ if isinstance(self.data, str):
|
|
return self.data
|
|
return self.data
|
|
elif self.data is None:
|
|
elif self.data is None:
|
|
return ''
|
|
return ''
|
|
else:
|
|
else:
|
|
- return urlparse.urlunsplit(self.data)
|
|
|
|
|
|
+ return urllib.parse.urlunsplit(self.data)
|
|
|
|
|
|
def process_formdata(self, valuelist):
|
|
def process_formdata(self, valuelist):
|
|
if valuelist:
|
|
if valuelist:
|
|
try:
|
|
try:
|
|
- self.data = urlparse.urlsplit(valuelist[0])
|
|
|
|
|
|
+ self.data = urllib.parse.urlsplit(valuelist[0])
|
|
except:
|
|
except:
|
|
self.data = None
|
|
self.data = None
|
|
- raise ValidationError(_(u'Invalid URL'))
|
|
|
|
|
|
+ raise ValidationError(_('Invalid URL'))
|
|
|
|
|
|
|
|
|
|
def is_url_unique(url):
|
|
def is_url_unique(url):
|
|
- if isinstance(url, basestring):
|
|
|
|
- url = urlparse.urlsplit(url)
|
|
|
|
|
|
+ if isinstance(url, str):
|
|
|
|
+ url = urllib.parse.urlsplit(url)
|
|
t = list(url)
|
|
t = list(url)
|
|
t[2] = ''
|
|
t[2] = ''
|
|
- u1 = urlparse.urlunsplit(t)
|
|
|
|
|
|
+ u1 = urllib.parse.urlunsplit(t)
|
|
t[0] = 'http' if t[0] == 'https' else 'https'
|
|
t[0] = 'http' if t[0] == 'https' else 'https'
|
|
- u2 = urlparse.urlunsplit(t)
|
|
|
|
|
|
+ u2 = urllib.parse.urlunsplit(t)
|
|
if ISP.query.filter(ISP.json_url.startswith(u1) | ISP.json_url.startswith(u2)).count() > 0:
|
|
if ISP.query.filter(ISP.json_url.startswith(u1) | ISP.json_url.startswith(u2)).count() > 0:
|
|
return False
|
|
return False
|
|
return True
|
|
return True
|
|
|
|
|
|
|
|
|
|
class ProjectJSONForm(Form):
|
|
class ProjectJSONForm(Form):
|
|
- json_url = URLField(_(u'base url'), description=[_(u'E.g. https://isp.com/'),
|
|
|
|
- _(u'A ressource implementing our JSON-Schema specification ' +
|
|
|
|
|
|
+ json_url = URLField(_('base url'), description=[_('E.g. https://isp.com/'),
|
|
|
|
+ _('A ressource implementing our JSON-Schema specification ' +
|
|
'must exist at path /isp.json')])
|
|
'must exist at path /isp.json')])
|
|
- tech_email = TextField(_(u'Email'), validators=[Email()], description=[None,
|
|
|
|
- _(u'Technical contact, in case of problems')])
|
|
|
|
|
|
+ tech_email = TextField(_('Email'), validators=[Email()], description=[None,
|
|
|
|
+ _('Technical contact, in case of problems')])
|
|
|
|
|
|
def validate_json_url(self, field):
|
|
def validate_json_url(self, field):
|
|
if not field.data.netloc:
|
|
if not field.data.netloc:
|
|
- raise ValidationError(_(u'Invalid URL'))
|
|
|
|
|
|
+ raise ValidationError(_('Invalid URL'))
|
|
|
|
|
|
if field.data.scheme not in ('http', 'https'):
|
|
if field.data.scheme not in ('http', 'https'):
|
|
- raise ValidationError(_(u'Invalid URL (must be HTTP(S))'))
|
|
|
|
|
|
+ raise ValidationError(_('Invalid URL (must be HTTP(S))'))
|
|
|
|
|
|
if not field.object_data and not is_url_unique(field.data):
|
|
if not field.object_data and not is_url_unique(field.data):
|
|
- raise ValidationError(_(u'This URL is already in our database'))
|
|
|
|
|
|
+ raise ValidationError(_('This URL is already in our database'))
|
|
|
|
|
|
|
|
|
|
class RequestEditToken(Form):
|
|
class RequestEditToken(Form):
|
|
- tech_email = TextField(_(u'Tech Email'), validators=[Email()], description=[None,
|
|
|
|
- _(u'The Technical contact you provided while registering')])
|
|
|
|
|
|
+ tech_email = TextField(_('Tech Email'), validators=[Email()], description=[None,
|
|
|
|
+ _('The Technical contact you provided while registering')])
|