Félix Baylac-Jacqué 6 years ago
parent
commit
62699422a3
3 changed files with 180 additions and 35 deletions
  1. 7 0
      ffdnispdb/constants.py
  2. 161 34
      ffdnispdb/forms.py
  3. 12 1
      ffdnispdb/templates/project_form_generic.html

+ 7 - 0
ffdnispdb/constants.py

@@ -26,3 +26,10 @@ LOCALES_FLAGS = {
     'en': 'GB',
     'en': 'GB',
     'fr': 'FR',
     'fr': 'FR',
 }
 }
+
+IPV6_SUPPORT = {
+    1: _('none'),
+    2: _('partial'),
+    3: _('quite good'),
+    4: _('full')
+} 

+ 161 - 34
ffdnispdb/forms.py

@@ -7,7 +7,7 @@ from flask import current_app
 from flask.ext.wtf import Form
 from flask.ext.wtf import Form
 from wtforms import Form as InsecureForm
 from wtforms import Form as InsecureForm
 from wtforms import (TextField, DateField, DecimalField, IntegerField,
 from wtforms import (TextField, DateField, DecimalField, IntegerField,
-                     SelectField, SelectMultipleField, FieldList, FormField)
+                     SelectField, SelectMultipleField, FieldList, FormField, BooleanField)
 from wtforms.widgets import (TextInput, ListWidget, html_params, HTMLString,
 from wtforms.widgets import (TextInput, ListWidget, html_params, HTMLString,
                              CheckboxInput, Select, TextArea)
                              CheckboxInput, Select, TextArea)
 from wtforms.validators import (DataRequired, Optional, URL, Email, Length,
 from wtforms.validators import (DataRequired, Optional, URL, Email, Length,
@@ -15,7 +15,7 @@ from wtforms.validators import (DataRequired, Optional, URL, Email, Length,
 from flask.ext.babel import lazy_gettext as _, gettext
 from flask.ext.babel import lazy_gettext as _, gettext
 from babel.support import LazyProxy
 from babel.support import LazyProxy
 from ispformat.validator import validate_geojson
 from ispformat.validator import validate_geojson
-from .constants import STEPS
+from .constants import STEPS, IPV6_SUPPORT
 from .models import ISP
 from .models import ISP
 from .utils import check_geojson_spatialite, filesize_fmt
 from .utils import check_geojson_spatialite, filesize_fmt
 
 
@@ -135,40 +135,123 @@ STEP_CHOICES = [(k, LazyProxy(lambda k, s: u'%u - %s' % (k, s), k, STEPS[k], ena
 
 
 
 
 class ProjectForm(Form):
 class ProjectForm(Form):
-    name = TextField(_(u'full name'), description=[_(u'E.g. French Data Network')],
-                     validators=[DataRequired(), Length(min=2), Unique(ISP, ISP.name)])
-    shortname = TextField(_(u'short name'), description=[_(u'E.g. FDN')],
-                          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)])
-    other_websites = FieldList(MyFormField(OtherWebsites, widget=partial(InputListWidget(), class_='formfield')),
-                               min_entries=1, widget=InputListWidget(),
-                               description=[None, _(u'Additional websites that you host (e.g. wiki, etherpad...)')])
+    name = TextField(_(u'full name'),
+        description=[_(u'E.g. French Data Network')],
+        validators=[DataRequired(), Length(min=2),
+        Unique(ISP, ISP.name)])
+
+    shortname = TextField(_(u'short name'),
+        description=[_(u'E.g. FDN')],
+        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)])
+    other_websites = FieldList(MyFormField(OtherWebsites,
+        widget=partial(InputListWidget(), class_='formfield')),
+        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()],
     contact_email = TextField(_(u'contact email'), validators=[Optional(), Email()],
-                              description=[None, _(u'General contact email address')])
+        description=[None, _(u'General contact email address')])
+
     main_ml = TextField(_(u'main mailing list'), validators=[Optional(), Email()],
     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')])
+        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(),
     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 ' +
-                          '<code>xmpp:isp@chat.isp.net?join</code>')])
-    covered_areas = FieldList(MyFormField(CoveredArea, _('Covered Areas'), 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'Coordinates of your registered office or usual meeting location. '
-                            '<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)],
-                                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')])
+        description=[None, _(u'In URI form, e.g. <code>irc://irc.isp.net/#isp</code> or ' +
+        '<code>xmpp:isp@chat.isp.net?join</code>')])
+
+    covered_areas = FieldList(MyFormField(CoveredArea, _('Covered Areas'),
+        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'Coordinates of your registered office or usual meeting location. '
+        '<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)],
+        description=[None, _(u'Number of members')])
+
+    subscriber_count = IntegerField(_(u'subscribers'),
+        validators=[Optional(), NumberRange(min=0)],
+        description=[None, _(u'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')])
+
+    ########################################
+    # Fields introduced by ISP format V0.2 #
+    ########################################
+    asn = IntegerField(_(u'asn'), validators=[Optional(), NumberRange(min=0)],
+        description=[None, _('Autonomous System (AS) number.')])
+
+    arcep_code = TextField(_(u'arcep code'),
+        validators=[Optional()],
+        description=[None, _(u'The identifier assigned by the ARCEP')])
+
+    xdsl = IntegerField(_(u'xdsl subscribers'),
+        validators=[Optional(), NumberRange(min=0)],
+        description=[None, _(u'Number of xdsl subscribers')])
+
+    vpn = IntegerField(_(u'vpn subscribers'),
+        validators=[Optional(), NumberRange(min=0)],
+        description=[None, _(u'Number of vpn subscribers')])
+
+    wifi = IntegerField(_(u'wifi subscribers'),
+        validators=[Optional(), NumberRange(min=0)],
+        description=[None, _(u'Number of wifi subscribers')])
+
+    fiber = IntegerField(_(u'fiber subscribers'),
+        validators=[Optional(), NumberRange(min=0)],
+        description=[None, _(u'Number of fiber subscribers')])
+
+    statutes = TextField(_(u'statutes',
+        validators=[Optional(), URL(require_tld=True)],
+        description=[None, _(u'URL pointing to the organisation statutes.')]))
+
+    internal_rules = TextField(_(u'internal rules',
+        validators=[Optional(), URL(require_tld=True)],
+        description=[None, _(u'URL pointing to the organisation internal rules.')]))
+
+    internet_cube = BooleanField(_(u'internet cube'),
+        validators=[Optional()],
+        description=[None, _(u'Participating to the internetcube project (collective purchases, install parties)')])
+
+    nlnog_participant = BooleanField(_(u'nlnog participant'),
+        validators=[Optional()],
+        description=[None, _(u'Participating to the NL-NOG RING? See <code>https://ring.nlnog.net/</code>')])
+
+    ipv6_servers = SelectField(_(u'ipv6 servers'),
+        choices=IPV6_SUPPORT,
+        coerce=int,
+        validators=[Optional()],
+        description=[None, _(u'Servers can be reached in IPV6?')])
+
+    ipv6_subscribers = SelectField(_(u'ipv6 subscribers'),
+        choices=IPV6_SUPPORT, validators=[Optional()],
+        coerce=int,
+        description=[None, _(u'Subscribers are provided with IPV6 connectivity?')])
 
 
     def validate(self, *args, **kwargs):
     def validate(self, *args, **kwargs):
         r = super(ProjectForm, self).validate(*args, **kwargs)
         r = super(ProjectForm, self).validate(*args, **kwargs)
@@ -195,6 +278,11 @@ class ProjectForm(Form):
 
 
         json['name'] = self.name.data
         json['name'] = self.name.data
 
 
+        def optobj(k, d):
+            filtered_none = {k: v for k,v in d.iteritems() if v != None}
+            if filtered_none != {}:
+                json[k] = filtered_none
+
         def optstr(k, v):
         def optstr(k, v):
             if k in json or v:
             if k in json or v:
                 json[k] = v
                 json[k] = v
@@ -221,11 +309,27 @@ class ProjectForm(Form):
         optstr('creationDate', self.creation_date.data.isoformat() if self.creation_date.data else None)
         optstr('creationDate', self.creation_date.data.isoformat() if self.creation_date.data else None)
         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)
         optlist('chatrooms', filter(bool, self.chatrooms.data))  # remove empty strings
         optlist('chatrooms', 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)))
+
+        optstr('asn', self.asn.data)
+        optstr('arcepCode', self.arcep_code.data)
+        optstr('internetcube', self.internet_cube.data)
+        optstr('nlnogParticipant', self.nlnog_participant)
+        optobj('publicDocuments', {
+            'statutes': self.statutes.data,
+            'internalRules': self.internal_rules.data})
+        optobj('subscriberCount', {
+            'xdsl': self.xdsl.data,
+            'vpn': self.vpn.data,
+            'wifi': self.wifi.data,
+            'fiber': self.fiber.data})
+        optobj('ipv6Support', {
+            'infra': self.ipv6_servers.data,
+            'subscribers': self.ipv6_subscribers.data})
+
         return json
         return json
 
 
     @classmethod
     @classmethod
@@ -258,6 +362,29 @@ class ProjectForm(Form):
         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'].iteritems()])
         set_attr('covered_areas', 'coveredAreas')
         set_attr('covered_areas', 'coveredAreas')
+
+        # V0.2
+        set_attr('asn')
+        set_attr('arcep_code', 'arcepCode')
+        set_attr('internet_cube', 'internetcube')
+        set_attr('nlnog_participant', 'nlnogParticipant')
+        # TODO: refactor that. I don't know python enough to find it but I'm
+        #       sure there's a clever trick to make set_attr support nested structures.
+        if 'publicDocuments' in json:
+            pubd = json['publicDocuments']
+            set_attr('statutes', 'statutes', pubd)
+            set_attr('internal_rules', 'internalRules', pubd)
+        if 'ipv6Support' in json:
+            ipd = json['ipv6Support']
+            set_attr('ipv6_servers', 'infra', ipd)
+            set_attr('ipv6_sibscribers', 'subscribers', ipd)
+        if 'subscriberCount' in json:
+            scd = json['subscriberCount']
+            set_attr('xdsl', None, scd)
+            set_attr('vpn', None, scd)
+            set_attr('wifi', None, scd)
+            set_attr('fiber', None, scd)
+
         obj.tech_email = isp.tech_email
         obj.tech_email = isp.tech_email
         return cls(obj=obj)
         return cls(obj=obj)
 
 

+ 12 - 1
ffdnispdb/templates/project_form_generic.html

@@ -35,12 +35,23 @@
           </div>
           </div>
         </div>
         </div>
         {{ fm.render_field(form.contact_email) }}
         {{ fm.render_field(form.contact_email) }}
+        {{ fm.render_field(form.chatrooms, class="fieldlist") }}
         {{ fm.render_field(form.main_ml) }}
         {{ fm.render_field(form.main_ml) }}
         {{ fm.render_field(form.creation_date) }}
         {{ fm.render_field(form.creation_date) }}
         {{ fm.render_field(form.step) }}
         {{ fm.render_field(form.step) }}
+        {{ fm.render_field(form.asn) }}
+        {{ fm.render_field(form.arcep_code) }}
+        {{ fm.render_field(form.statutes) }}
+        {{ fm.render_field(form.internal_rules) }}
+        {{ fm.render_field(form.internet_cube) }}
+
         {{ fm.render_field(form.member_count, class_="input-small") }}
         {{ fm.render_field(form.member_count, class_="input-small") }}
         {{ fm.render_field(form.subscriber_count, class_="input-small") }}
         {{ fm.render_field(form.subscriber_count, class_="input-small") }}
-        {{ fm.render_field(form.chatrooms, class="fieldlist") }}
+        {{ fm.render_field(form.xdsl, class_="input-small") }}
+        {{ fm.render_field(form.vpn, class_="input-small") }}
+        {{ fm.render_field(form.wifi, class_="input-small") }}
+        {{ fm.render_field(form.fiber, class_="input-small") }}
+        {{ fm.render_field(form.nlnog_participant) }}
         <div class="control-group required{% if form.covered_areas.errors %} error{% endif %}">
         <div class="control-group required{% if form.covered_areas.errors %} error{% endif %}">
           <label class="control-label" for="coordinates">{{ form.covered_areas.label.text }}</label>
           <label class="control-label" for="coordinates">{{ form.covered_areas.label.text }}</label>
           <div class="controls">
           <div class="controls">