Merge branch 'master' into debian

This commit is contained in:
Jérôme Schneider 2013-08-28 14:30:16 +02:00
commit 84813e197d
16 changed files with 316 additions and 89 deletions

View File

@ -6,3 +6,5 @@ recursive-include compte_agglo_montpellier/apps/feed_plugin/templates *.html
recursive-include compte_agglo_montpellier/apps/feed_plugin/locale *.po *.mo
include local_settings.py.example
include requirements.txt
include MANIFEST.in
include VERSION

View File

@ -13,6 +13,10 @@ from cms.plugin_pool import plugin_pool
from . import models
from . import forms
logger = logging.getLogger(__name__)
class SelectUserFeedPlugin(CMSPluginBase):
model = models.SelectUserFeed
name = _('select user feeds')
@ -45,6 +49,7 @@ class ShowUserFeedPlugin(CMSPluginBase):
def get_feeds(self, instance, user):
entries = []
logger.debug('loading RSS feeds of user %s', user.username)
for pref in models.FeedPreference.objects.filter(user=user):
feed = feedparser.parse(pref.feed.url)
for entry in feed.entries:
@ -55,6 +60,7 @@ class ShowUserFeedPlugin(CMSPluginBase):
break
entries.append((date, entry.title, entry.link, pref.feed.name,
pref.feed.color_hex, pref.feed.css_classes))
logger.debug('loading finished of %s entries', len(entries))
entries.sort(reverse=True)
entries = entries[:instance.limit]
return [dict(title=title, link=link, feed_name=feed_name,

View File

@ -1,8 +1,10 @@
from django import forms
from django.utils.translation import ugettext as _
import models
from . import models
from . import widgets
class FeedForm(forms.Form):
feeds = forms.ModelMultipleChoiceField(queryset=models.Feed.objects.all(),
label=_('Your feeds'), widget=forms.CheckboxSelectMultiple)
label=_('Your feeds'), widget=widgets.CheckboxMultipleSelect,
required=False)

View File

@ -1,6 +1,15 @@
{% load i18n %}
<form method="post">
<form method="post" class="feed-form">
{% csrf_token %}
{{ form.feeds }}
<ul class='feed-list'>
{% for subwidget in form.feeds %}
<li class='feed-list-item'>
{{ subwidget.tag }}
<label for="{{subwidget.attrs.id}}_{{subwidget.index}}">
{{subwidget.choice_label}}
</label>
</li>
{% endfor %}
</ul>
<input type="submit" value="{% trans "Validate" %}" name="{{ submit }}">
</form>

View File

@ -0,0 +1,104 @@
from itertools import chain
from django.forms.widgets import SubWidget, SelectMultiple
from django.forms.util import flatatt
from django.utils.html import conditional_escape
from django.utils.encoding import StrAndUnicode, force_unicode
from django.utils.safestring import mark_safe
class CheckboxInput(SubWidget):
"""
An object used by CheckboxRenderer that represents a single
<input type='checkbox'>.
"""
def __init__(self, name, value, attrs, choice, index):
self.name, self.value = name, value
self.attrs = attrs
self.choice_value = force_unicode(choice[0])
self.choice_label = force_unicode(choice[1])
self.index = index
def __unicode__(self):
return self.render()
def render(self, name=None, value=None, attrs=None, choices=()):
name = name or self.name
value = value or self.value
attrs = attrs or self.attrs
if 'id' in self.attrs:
label_for = ' for="%s_%s"' % (self.attrs['id'], self.index)
else:
label_for = ''
choice_label = conditional_escape(force_unicode(self.choice_label))
return mark_safe(u'<label%s>%s %s</label>' % (label_for, self.tag(), choice_label))
def is_checked(self):
return self.choice_value in self.value
def tag(self):
if 'id' in self.attrs:
self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index)
final_attrs = dict(self.attrs, type='checkbox', name=self.name, value=self.choice_value)
if self.is_checked():
final_attrs['checked'] = 'checked'
return mark_safe(u'<input%s />' % flatatt(final_attrs))
class CheckboxRenderer(StrAndUnicode):
def __init__(self, name, value, attrs, choices):
self.name, self.value, self.attrs = name, value, attrs
self.choices = choices
def __iter__(self):
for i, choice in enumerate(self.choices):
yield CheckboxInput(self.name, self.value, self.attrs.copy(), choice, i)
def __getitem__(self, idx):
choice = self.choices[idx] # Let the IndexError propogate
return CheckboxInput(self.name, self.value, self.attrs.copy(), choice, idx)
def __unicode__(self):
return self.render()
def render(self):
"""Outputs a <ul> for this set of checkbox fields."""
return mark_safe(u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>'
% force_unicode(w) for w in self]))
class CheckboxMultipleSelect(SelectMultiple):
"""
Checkbox multi select field that enables iteration of each checkbox
Similar to django.forms.widgets.RadioSelect
"""
renderer = CheckboxRenderer
def __init__(self, *args, **kwargs):
# Override the default renderer if we were passed one.
renderer = kwargs.pop('renderer', None)
if renderer:
self.renderer = renderer
super(CheckboxMultipleSelect, self).__init__(*args, **kwargs)
def subwidgets(self, name, value, attrs=None, choices=()):
for widget in self.get_renderer(name, value, attrs, choices):
yield widget
def get_renderer(self, name, value, attrs=None, choices=()):
"""Returns an instance of the renderer."""
if value is None: value = ''
str_values = set([force_unicode(v) for v in value]) # Normalize to string.
if attrs is None:
attrs = {}
if 'id' not in attrs:
attrs['id'] = name
final_attrs = self.build_attrs(attrs)
choices = list(chain(self.choices, choices))
return self.renderer(name, str_values, final_attrs, choices)
def render(self, name, value, attrs=None, choices=()):
return self.get_renderer(name, value, attrs, choices).render()
def id_for_label(self, id_):
if id_:
id_ += '_0'
return id_

View File

@ -45,7 +45,6 @@ class CustomIndexDashboard(Dashboard):
'cms.models.pagemodel.Page',
'data_source_plugin.models.DataSource',
'feed_plugin.models.Feed',
'auquotidien_plugin.models.AuQuotidienAPI',
),
))

View File

@ -5750,7 +5750,7 @@
"model" : "cmsplugin_text_wrapper.textwrapper",
"pk" : 1588
},
{ "fields" : { "body" : "<h2>Newsletters</h2><p>Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.</p><p><img alt=\"passerelle register plugin - &amp;lt;PasserelleRegisterPlugin http://passerelle-montpellier.entrouvert.org/register/newsletter/json&amp;gt;\" id=\"plugin_obj_1591\" title=\"passerelle register plugin - &amp;lt;PasserelleRegisterPlugin http://passerelle-montpellier.entrouvert.org/register/newsletter/json&amp;gt;\"></p>",
{ "fields" : { "body" : "<h2>Newsletters</h2><p>Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.</p><p><img alt=\"passerelle register plugin - &amp;lt;PasserelleRegisterPlugin https://passerelle-test-entrouvert.montpellier-agglo.com/register/newsletter/json&amp;gt;\" id=\"plugin_obj_1591\" title=\"passerelle register plugin - &amp;lt;PasserelleRegisterPlugin https://passerelle-test-entrouvert.montpellier-agglo.com/register/newsletter/json&amp;gt;\"></p>",
"wrapper" : "block"
},
"model" : "cmsplugin_text_wrapper.textwrapper",
@ -5792,7 +5792,7 @@
"model" : "cmsplugin_text_wrapper.textwrapper",
"pk" : 1640
},
{ "fields" : { "body" : "<h2>Newsletters</h2><p>Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.</p><p><img src=\"\" alt=\"passerelle register plugin - &lt;PasserelleRegisterPlugin http://passerelle-montpellier.entrouvert.org/register/newsletter/json&gt;\" title=\"passerelle register plugin - &lt;PasserelleRegisterPlugin http://passerelle-montpellier.entrouvert.org/register/newsletter/json&gt;\" id=\"plugin_obj_1643\" /></p>",
{ "fields" : { "body" : "<h2>Newsletters</h2><p>Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.</p><p><img src=\"\" alt=\"passerelle register plugin - &lt;PasserelleRegisterPlugin https://passerelle-test-entrouvert.montpellier-agglo.com/register/newsletter/json&gt;\" title=\"passerelle register plugin - &lt;PasserelleRegisterPlugin https://passerelle-test-entrouvert.montpellier-agglo.com/register/newsletter/json&gt;\" id=\"plugin_obj_1643\" /></p>",
"wrapper" : "block"
},
"model" : "cmsplugin_text_wrapper.textwrapper",

View File

@ -1,3 +1,4 @@
import json
import os
import logging.handlers
from django.conf.global_settings import PASSWORD_HASHERS
@ -110,7 +111,6 @@ INSTALLED_APPS = (
'portail_citoyen_announces',
'login_plugin',
'data_source_plugin',
'auquotidien_plugin',
'a2_service_list_plugin',
'passerelle_register_plugin',
'portail_citoyen',
@ -198,6 +198,15 @@ if 'INTERNAL_IPS' in os.environ:
else:
INTERNAL_IPS = ('127.0.0.1',)
# cache
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
},
}
if 'CACHE_BACKEND' in os.environ:
CACHES['default'] = json.loads(os.environ['CACHE_BACKEND'])
# misc
SECRET_KEY = os.environ.get('SECRET_KEY', '0!=(1kc6kri-ui+tmj@mr+*0bvj!(p*r0duu2n=)7@!p=pvf9n')
DEBUG_TOOLBAR_CONFIG = {'INTERCEPT_REDIRECTS': False}
@ -229,8 +238,8 @@ AUTHENTICATION_EVENT_EXPIRATION = int(os.environ.get('AUTHENTICATION_EVENT_EXPIR
# of user, and to handle SLO for each protocols
IDP_BACKENDS = [ ]
LOCAL_METADATA_CACHE_TIMEOUT = int(os.environ.get('LOCAL_METADATA_CACHE_TIMEOUT', 600))
# You MUST changes these keys, they are just for testing !
LOCAL_METADATA_CACHE_TIMEOUT = int(os.environ.get('LOCAL_METADATA_CACHE_TIMEOUT', 600))
SAML_SIGNATURE_PUBLIC_KEY = os.environ.get('SAML_SIGNATURE_PUBLIC_KEY', '''-----BEGIN CERTIFICATE-----
MIIDIzCCAgugAwIBAgIJANUBoick1pDpMA0GCSqGSIb3DQEBBQUAMBUxEzARBgNV
BAoTCkVudHJvdXZlcnQwHhcNMTAxMjE0MTUzMzAyWhcNMTEwMTEzMTUzMzAyWjAV
@ -279,7 +288,6 @@ wRiVcNacaP+BivkrMjr4BlsUM6yH4MOBsNhLURiiCL+tLJV7U0DWlCse/doWij4U
TKX6tp6oI+7MIJE6ySZ0cBqOiydAkBePZhu57j6ToBkTa0dbHjn1WA==
-----END RSA PRIVATE KEY-----''')
SAML_METADATA_ROOT = 'metadata'
# Whether to autoload SAML 2.0 identity providers and services metadata
# Only https URLS are accepted.
# Can be none, sp, idp or both
@ -319,6 +327,7 @@ LOGGING = {
'level': 'ERROR',
'class': 'django.utils.log.AdminEmailHandler',
'filters': ['cleaning'],
'include_html': True,
},
'console': {
'class': 'logging.StreamHandler',

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 518 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 332 B

View File

@ -54,6 +54,10 @@ div#top h1 a {
text-shadow: #6374AB 0px 0px 3px;
}
div#top a img {
border: 0;
}
div#main-content-wrapper {
position: relative;
z-index: 100;
@ -164,24 +168,38 @@ br.clear {
#error-404, #error-500, #content .block, #password-changed {
background: white;
font-size: 110%;
margin-bottom: 1em;
}
#content .block h2 {
background: #e6e6d6 url(toptitle.png) no-repeat left top;
background: #e87b1c url(Picto-EServices.png) 5px 50% no-repeat;
font-weight: normal;
color: #f68423;
color: white;
text-transform: uppercase;
padding: 6px 10px 6px 50px;
font-size: 130%;
cursor: default; /* someday, perhaps, cursor: move */
}
#content .demarches ul {
#content .block h2.feeds {
background-image: url(Picto-Bulle.png);
}
#content .block h2.newsletters {
background-image: url(Picto-coeur.png);
}
#content .demarches ul,
#content ul.mes-demarches {
list-style: none;
padding-left: 0px;
margin: 0px;
-webkit-column-count: 2;
-moz-column-count: 2;
column-count: 2;
}
#content ul.mes-demarches a,
#content .demarches ul a {
color: inherit;
font-weight: bold;
@ -189,13 +207,18 @@ br.clear {
padding-left: 10px;
}
#content ul.mes-demarches a:hover,
#content .demarches ul a:hover {
color: #f68423;
}
#content ul.mes-demarches li,
#content .demarches ul li {
margin: 1ex 0 10px 1ex;
padding-left: 10px;
-webkit-column-break-inside: avoid;
-moz-column-break-inside: avoid;
column-break-inside: avoid;
}
#content .demarches .toutes-les-demarches {
@ -230,35 +253,36 @@ br.clear {
display: block;
}
body.narrow-page #main-content-wrapper {
width: 800px;
}
div#single-title {
font-size: 130%;
padding: 5px;
background: #f4bc03;
border: 5px solid #f4bc03;
background: #f68423 url(Picto-EServices.png) 5px 50% no-repeat;
border: 1px solid #f68423;
color: white;
text-transform: uppercase;
text-align: center;
padding-left: 50px;
}
body.narrow-page #main-content {
background: white;
margin-top: 20px;
margin-top: 0;
padding: 10px 10px 0 10px;
}
body.narrow-page #main-content form div input {
display: block;
margin-left: 10px;
margin-bottom: 2ex;
}
div#welcome {
width: 48%;
float: left;
text-align: justify;
margin: 0 1em;
}
div#welcome h2 {
text-align: center;
margin: 1ex 0;
}
span.helptext {
@ -267,10 +291,45 @@ span.helptext {
body.narrow-page div.right {
padding-top: 2em;
float: right;
width: 49%;
width: 35em;
margin: 1ex auto;
}
body.narrow-page div.right form {
border: 1px solid #f68423;
padding: 1em;
}
body.narrow-page div.right form div label {
font-weight: bold;
width: 14em;
display: block;
float: left;
padding-top: 3px;
}
body.narrow-page div.right form div input {
width: 17em;
}
body.narrow-page div.right form div.form-field-required label:after {
content: "";
}
body.narrow-page div.right form > input {
display: block;
margin: 1em auto 0 auto;
background: #f68423;
color: white;
border: none;
padding: 3px 1em;
}
div.login-actions {
text-align: center;
}
.region-header {
width: 1000px;
position: absolute;
@ -337,21 +396,16 @@ ul.newsList li.abonne {
padding: 0;
}
.abonne:before {
content: "\2713 ";
width: 1em;
display: inline-block;
}
.nonAbonne:before {
content: " ";
width: 1em;
display: inline-block;
}
.abonne {
color: green;
padding-left: 20px;
background: transparent url(Validation.png) center left no-repeat;
}
.nonAbonne {
padding-left: 20px;
background: transparent url(Annulation.png) center left no-repeat;
}
/* page de profil */
#my-informations {
margin-bottom: 15px;
@ -396,22 +450,20 @@ ul.errorlist + p {
width: 50%;
}
.passerelle-register-plugin input:checked + label:before {
content: "\2713 ";
width: 1em;
display: inline-block;
margin-left: -2ex;
.passerelle-register-plugin input + label {
background: transparent url(Annulation.png) center left no-repeat;
}
.passerelle-register-plugin input:checked + label {
background: transparent url(Validation.png) center left no-repeat;
}
.passerelle-register-plugin td input {
display: none
}
.passerelle-register-plugin td label {
padding-left: 2em;
}
.passerelle-register-plugin input:checked + label {
color: green;
}
div.block form {
padding: 0 1ex;
@ -624,3 +676,16 @@ table.announces tbody th {
color: rgb(58, 58, 58);
text-decoration: none;
}
#my-password {
padding-bottom: 1ex;
}
#my-password p {
font-weight: bold;
}
#my-password p a {
color: inherit;
padding: 1ex;
}

View File

@ -15,38 +15,51 @@ class="narrow-page"
{% block content %}
<div id="welcome">
<h2>Bienvenue dans le portail « Mes e-services » de Montpellier Agglo !</h2>
<h2>Bienvenue sur le portail Internet de Montpellier Agglomération</h2>
<h3>Un site Internet pour et par lusager</h3>
<p>
Innovante, Montpellier Agglomération lance un site inédit, personnalisable à
volonté, pour que chaque internaute puisse créer sa propre version en fonction
de ses centres dintérêts et de ses envies !
</p>
<p>
E-services accessibles 24h/24 et 7jrs/7 en un clic, navigation qui sadapte à
linternaute… avec la nouvelle version de son site lancée en septembre 2012,
vous avez accès à un graphisme épuré pour plus de confort de lecture, des
présentations ludiques et interactives, des photos, des vidéos… et une mine
dinformations à découvrir au fil de votre parcours ou de vos recherches.
<p>
<h3>Une offre de services performante</h3>
<p>
Contacter une piscine ou le service des déchets ? Réaliser une modification de
votre abonnement à la téléalarme ? Effectuer une demande de raccordement au
réseau d'assainissement ? Répondre à une offre d'emploi ou déposer une
candidature spontannée ?
candidature spontanée ?
</p>
<p>
Ce portail vous permet d'accomplir vos démarches auprès de Montpellier Agglo
24h/24, de suivre le traitement de vos démarches en ligne et d'utiliser
l'ensemble des services en ligne mis en place par la collectivité, les
« e-services ».
<p>
<p>
Il vous suffit de vous connecter avec votre compte citoyen de Montpellier Agglo
pour accéder au portail et à ses « e-services ».
La plate-forme de services dématérialisés évolue et vous permet d'accomplir la
plupart de vos démarches en ligne, 24h/24 et 7j/7, de suivre le traitement de
vos demandes de « e-services ».
</p>
<p>
Vous ne disposez pas encore de compte citoyen de Montpellier Agglo ? Alors
n'hésitez plus…
Pour cela il vous suffit de vous connecter avec votre compte citoyen de
Montpellier Agglo pour accéder au portail et à ses « e-services ».
</p>
<p>
Si vous possédez un compte lecteur à la Médiathèque, un compte famille à
l'écolothèque ou un compte élève au conservatoire, ce compte citoyen
Montpellier Agglo vous permettra également à terme d'accéder directement à ces
espaces personnalisés, sans avoir à re-saisir vos identifiants et mots de
passe.
Si vous ne disposez pas encore de compte citoyen de Montpellier Agglo ?
N'hésitez plus et inscrivez-vous dès maintenant, votre compte vous donnera
également accès à votre compte lecteur du réseau des Médiathèque, à votre
compte famille à l'Ecolothèque ou le compte élève au Conservatoire, et enfin
d'accéder directement à vos espaces personnalisés, sans avoir à re-saisir vos
identifiants et mots de passe.
</p>
</div>

View File

@ -1,11 +1,15 @@
#! /usr/bin/env python
import glob
import re
import sys
import os
from setuptools import setup, find_packages
from setuptools.command.install_lib import install_lib as _install_lib
from distutils.command.build import build as _build
from distutils.command.sdist import sdist as _sdist
from distutils.command.sdist import sdist
from distutils.cmd import Command
import glob
class compile_translations(Command):
description = 'compile message catalogs to MO files via django compilemessages'
@ -18,36 +22,53 @@ class compile_translations(Command):
pass
def run(self):
import os
import sys
from django.core.management.commands.compilemessages import \
compile_messages
for path in ['compte_agglo_montpellier'] + glob.glob('compte_agglo_montpellier/apps/*'):
if not os.path.exists(os.path.join(path, 'locale')):
continue
curdir = os.getcwd()
os.chdir(os.path.realpath(path))
compile_messages(stderr=sys.stderr)
os.chdir(curdir)
try:
from django.core.management.commands.compilemessages import \
compile_messages
for path in ['compte_agglo_montpellier'] + glob.glob('compte_agglo_montpellier/apps/*'):
if not os.path.exists(os.path.join(path, 'locale')):
continue
curdir = os.getcwd()
os.chdir(os.path.realpath(path))
compile_messages(stderr=sys.stderr)
os.chdir(curdir)
except ImportError:
print
sys.stderr.write('!!! Please install Django >= 1.4 to build translations')
print
print
class build(_build):
sub_commands = [('compile_translations', None)] + _build.sub_commands
class sdist(_sdist):
sub_commands = [('compile_translations', None)] + _sdist.sub_commands
class eo_sdist(sdist):
def run(self):
print "creating VERSION file"
if os.path.exists('VERSION'):
os.remove('VERSION')
version = get_version()
version_file = open('VERSION', 'w')
version_file.write(version)
version_file.close()
sdist.run(self)
print "removing VERSION file"
if os.path.exists('VERSION'):
os.remove('VERSION')
class install_lib(_install_lib):
def run(self):
self.run_command('compile_translations')
_install_lib.run(self)
def get_version():
import glob
import re
import os
version = None
if os.path.exists('VERSION'):
version_file = open('VERSION', 'r')
version = version_file.read()
version_file.close()
return version
for d in glob.glob('*'):
if not os.path.isdir(d):
continue
@ -92,7 +113,7 @@ setup(name="compte-agglo-montpellier",
'static/**.gif',
'static/**.css',
'static/**.js',
'locale/**.mo',
'locale/**.mo',
'fixtures/*.json',
]
},
@ -106,14 +127,11 @@ setup(name="compte-agglo-montpellier",
'gunicorn',
'demjson',
],
setup_requires=[
'django>=1.4',
],
dependency_links = [
'git+git://repos.entrouvert.org/portail-citoyen#egg=portail-citoyen-0.1.99999',
'git+git://repos.entrouvert.org/portail-citoyen-announces#egg=portail-citoyen-announces-0.1.99999',
],
cmdclass={'build': build, 'install_lib': install_lib,
'compile_translations': compile_translations,
'sdist': sdist},
'sdist': eo_sdist},
)