Parcourir la source

Continue porting code to SQLAlchemy (project list and detail pages)

Make the ISP.json field a JSONEncodeDict
Gu1 il y a 11 ans
Parent
commit
a360faee3d

+ 28 - 3
ffdnispdb/forms.py

@@ -46,7 +46,6 @@ class Unique(object):
 
     def __call__(self, form, field):
         check = self.model.query.filter(self.field == field.data).first()
-        print "lol", check, self.field, field.data
         if check:
             raise ValidationError(self.message)
 
@@ -86,7 +85,33 @@ class ProjectForm(Form):
                              description=[None, _(u'Geographical coordinates of your registered office or usual meeting location.')])
     longitude     = DecimalField(_(u'longitude'), validators=[Optional()])
     step          = SelectField(_(u'step'), choices=[(k, u'%u - %s' % (k, STEPS[k])) for k in STEPS], coerce=int)
-    member_count     = DecimalField(_(u'Members'), validators=[Optional(), NumberRange(min=0)],
+    member_count     = DecimalField(_(u'members'), validators=[Optional(), NumberRange(min=0)],
                                     description=[None, _('Number of members')])
-    subscriber_count = DecimalField(_(u'Subscribers'), validators=[Optional(), NumberRange(min=0)],
+    subscriber_count = DecimalField(_(u'subscribers'), validators=[Optional(), NumberRange(min=0)],
                                     description=[None, _('Number of subscribers to an internet access')])
+
+    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('email', self.contact_email.data)
+        optstr('mainMailingList', self.main_ml.data)
+        optstr('creationDate', self.creation_date.data)
+        optstr('progressStatus', self.step.data)
+        optlist('chatrooms', filter(bool, self.chatrooms.data)) # remove empty strings
+        return json
+

+ 34 - 8
ffdnispdb/models.py

@@ -1,20 +1,46 @@
+# -*- coding: utf-8 -*-
 
+import json
 from . import db
+from sqlalchemy.types import TypeDecorator, VARCHAR
+from sqlalchemy.ext.mutable import MutableDict
+
+
+class JSONEncodedDict(TypeDecorator):
+    "Represents an immutable structure as a json-encoded string."
+
+    impl = VARCHAR
+
+    def process_bind_param(self, value, dialect):
+        if value is not None:
+            value = json.dumps(value)
+        return value
+
+    def process_result_value(self, value, dialect):
+        if value is not None:
+            value = json.loads(value)
+        return value
 
 
 class ISP(db.Model):
     id = db.Column(db.Integer, primary_key=True)
     name = db.Column(db.String, nullable=False, index=True, unique=True)
     shortname = db.Column(db.String(12), index=True, unique=True)
+    is_ffdn_member = db.Column(db.Boolean, default=False)
+    is_disabled = db.Column(db.Boolean, default=False) # True = ISP will not appear
     url = db.Column(db.String)
-    lastSuccessfulUpdate = db.Column(db.DateTime)
-    lastUpdateAttempt = db.Column(db.DateTime)
-    isUpdatable = db.Column(db.Boolean, default=True) # set to False to disable JSON updates
-    techEmailContact = db.Column(db.String)
-    cacheInfo = db.Column(db.Text)
-    json = db.Column(db.Text)
+    last_update_success = db.Column(db.DateTime)
+    last_update_attempt = db.Column(db.DateTime)
+    is_updatable = db.Column(db.Boolean, default=True) # set to False to disable JSON-URL updates
+    tech_email = db.Column(db.String)
+    cache_info = db.Column(db.Text)
+    json = db.Column(MutableDict.as_mutable(JSONEncodedDict))
+
+    def __init__(self, *args, **kwargs):
+        super(ISP, self).__init__(*args, **kwargs)
+        self.json={}
 
     def __repr__(self):
-        return '<ISP %r>' % self.shortname if self.shortname else self.name
+        return '<ISP %r>' % (self.shortname if self.shortname else self.name,)
+
 
-        

+ 0 - 24
ffdnispdb/templates/project.html

@@ -1,24 +0,0 @@
-{% extends "layout.html" %}
-{% block subtitle %}
-{% endblock %}
-{% block body %}
-<!--<div class="row">-->
-<!--<div class="span9">-->
-  <a class="pull-right btn btn-success btn-small" href="{{ url_for('edit_project', projectid=project.id) }}"><i class="icon-edit icon-white"></i> Éditer</a>
-  {% if project.name != project.shortname %}
-  <h1 class='page-header'>{{ project.name }} ({{ project.shortname }})</h1> 
-  {% else %}
-  <h1 class='page-header'>{{ project.name }} <small> &nbsp;-&nbsp; {{ project.description }}</small></h1> 
-  {% endif %}
-  <dl class="dl-horizontal">
-    <dt>Zone<dd>{{ project.zone }}
-    <dt>Services<dd>{{ project.services }}
-    <dt>Website<dd><a href="{{ project.website }}">{{ project.website }}</a>
-    <dt>Email<dd><code>{{ project.email }}</code>
-    <dt>IRC<dd>Canal <code>{{ project.irc_channel }}</code>, Serveur <code>{{ project.irc_server }}</code>
-    {% autoescape false %}
-    <dt>Étape<dd>{{ project.step | step_to_label }}
-    {% endautoescape %}
-<!--</div>-->
-<!--</div>-->
-{% endblock %}

+ 40 - 0
ffdnispdb/templates/project_detail.html

@@ -0,0 +1,40 @@
+{% extends "layout.html" %}
+{% block page_title -%}
+{% trans project_name=project.name -%}
+<small>Project:</small> {{ project_name }}
+{%- endtrans %}
+{%- endblock %}
+{% block body %}
+  <div class="pull-right">
+    <div class="text-right">
+      <a class="btn btn-success btn-small" href="{{ url_for('edit_project', projectid=project.id) }}"><i class="icon-edit icon-white"></i> {{ _("Edit") }}</a>
+    </div>
+    <a href="{{ project.website }}"><img alt="{{ project.name }}" src="{{ project.logoURL }}" style="max-width: 300px;" /></a>
+  </div>
+  <dl class="dl-horizontal">
+    <dt>{{ _("name")|capitalize }}</dt>
+      <dd>{{ project.name }}</dd>
+    <dt>{{ _("short name")|capitalize }}</dt>
+      <dd>{{ project.shortname }}</dd>
+    <dt>{{ _("description")|capitalize }}</dt>
+      <dd>{{ project.description|default(_("<em>None yet</em>")) }}</dd>
+    <dt>{{ _("covered areas")|capitalize }}</dt>
+      <dd>{{ project.zone|default(_("<em>None yet</em>")) }}</dd>
+    <dt>{{ _("website")|capitalize }}</dt>
+      <dd>{% if project.website %}<a href="{{ project.website }}">{{ project.website }}</a>{% else %}<em>None</em>{% endif %}</dd>
+    <dt>{{ _("email")|capitalize }}</dt>
+      <dd>{{ project.email|default(_("<em>None given</em>"), True) }}</dd>
+    <dt>{{ _("main mailing list")|capitalize }}</dt>
+      <dd>{{ project.email|default(_("<em>None given</em>"), True) }}</dd>
+    <dt>{{ _("chatrooms")|capitalize }}</dt>
+      {%- for c in project.chatrooms -%}
+      <dd><code>{{ c }}</code></dd>
+      {%- else -%}
+      <dd><em>None</em></dd>
+      {%- endfor -%}
+    {% autoescape false %}
+    <dt>{{ _("step")|capitalize }}</dt>
+      <dd>{{ project.progressStatus | step_to_label }}</dd>
+    {% endautoescape %}
+  </dl>
+{% endblock %}

+ 30 - 0
ffdnispdb/templates/project_list.html

@@ -0,0 +1,30 @@
+{% extends "layout.html" %}
+{% block page_title %}{{ _("Project List") }}{% endblock %}
+{% block body %}
+<div>
+<table class="table table-condensed table-striped table-hover">
+  <thead>
+    <tr>
+      <th>{{ _("Name") }}</th>
+      <th>{{ _("Areas") }}</th>
+      <th>{{ _("Step")}}</th>
+      <th></th>
+    </tr>
+  </thead>
+  <tbody>
+    {% for project in projects -%}
+    <tr>
+      <td>{% autoescape false %}{{ project.isFFDNMember | member_to_label }}{% endautoescape %} &nbsp;
+        <a href="{{ url_for('project', projectid=project.id) }}">{{ project.name }}</a></td>
+      <td>{{ project.zone }}</td>
+      {% autoescape false -%}
+      <td>{{ project.json.progressStatus|step_to_label }}</td>
+      {%- endautoescape %}
+      <td><a class="pull-right btn btn-small" href="{{ url_for('project', projectid=project.id) }}"><i class="icon-search"></i></a>
+    </tr>
+    {% endfor -%}
+  </tbody>
+</table>
+<a class="pull-right btn btn-primary btn-small" href="{{ url_for('add_project') }}">{{ _("Add your project") }}</a>
+</div>
+{% endblock %}

+ 0 - 35
ffdnispdb/templates/projects.html

@@ -1,35 +0,0 @@
-{% extends "layout.html" %}
-{% block page_title %}
-Liste des projets recencés
-{% endblock %}
-{% block body %}
-<div>
-<a class="pull-right btn btn-primary btn-small" href="{{ url_for('create_project') }}">Ajoutez le votre !</a>
-<table class="table table-condensed table-striped table-hover">
-  <thead>
-    <tr>
-      <th>Nom</th>
-      <th>Zone</th>
-      <th>Services</th>
-      <th>Étape</th>
-      <th></th>
-    </tr>
-  </thead>
-  <tbody>
-    {% for project in projects %}
-    <tr>
-      <td>{% autoescape false %}{{ project.is_member | member_to_label }}{% endautoescape %} &nbsp;
-        <a href="{{ url_for('project', projectid=project.id) }}">{{ project.name }}</a></td>
-      <td>{{ project.zone }}</td>
-      <td>{{ project.services }}</td>
-      {% autoescape false %}
-      <td>{{ project.step | step_to_label }}</td>
-      {% endautoescape %}
-      <td><a class="pull-right btn btn-small" href="{{ url_for('project', projectid=project.id) }}"><i class="icon-search"></i></a>
-    </tr>
-    {% endfor %}
-  </tbody>
-</table>
-<a class="pull-right btn btn-primary btn-small" href="{{ url_for('create_project') }}">Ajoutez le votre !</a>
-</div>
-{% endblock %}

+ 10 - 12
ffdnispdb/views.py

@@ -25,19 +25,14 @@ def members():
 
 @app.route('/projects')
 def project_list():
-    projects = list()
-    for project in query_db('select * from fai order by is_member desc,step desc,name'):
-        project['stepname'] = STEPS[project['step']]
-        projects.append(project)
-    return render_template('projects.html', projects=projects)
+    return render_template('project_list.html', projects=ISP.query.filter_by(is_disabled=False))
 
 @app.route('/fai/<projectid>')
 def project(projectid):
-    project = query_db('select * from fai where id = ?', [projectid], one=True) 
-    if project is None:
+    p=ISP.query.get(projectid)
+    if not p:
         abort(404)
-    project['stepname'] = STEPS[project['step']]
-    return render_template('project.html', project=project)
+    return render_template('project_detail.html', project_row=p, project=p.json)
 
 @app.route('/edit/<projectid>', methods=['GET', 'POST'])
 def edit_project(projectid):
@@ -102,11 +97,11 @@ def create_project():
         isp=ISP()
         isp.name = form.name.data
         isp.shortname = form.shortname.data or None
-        isp.json='TODO'
+        isp.json=form.to_json(isp.json)
 
         db.session.add(isp)
         db.session.commit()
-        flash(_(u'Project created'))
+        flash(_(u'Project created'), 'info')
         return redirect(url_for('project', projectid=isp.id))
     return render_template('project_form.html', form=form)
 
@@ -141,7 +136,10 @@ def members_drupal():
 
 @app.template_filter('step_to_label')
 def step_to_label(step):
-    return u"<a href='#' rel='tooltip' data-placement='right' title='" + STEPS[step] + "'><span class='badge badge-" + STEPS_LABELS[step] + "'>" + str(step) + "</span></a>"
+    if step:
+        return u"<a href='#' rel='tooltip' data-placement='right' title='" + STEPS[step] + "'><span class='badge badge-" + STEPS_LABELS[step] + "'>" + str(step) + "</span></a>"
+    else:
+        return u'-'
 
 @app.template_filter('member_to_label')
 def member_to_label(is_member):