diff --git a/MANIFEST.in b/MANIFEST.in index 11b7d77..ef41f52 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -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 diff --git a/compte_agglo_montpellier/apps/feed_plugin/cms_plugins.py b/compte_agglo_montpellier/apps/feed_plugin/cms_plugins.py index c9684d9..403aa19 100644 --- a/compte_agglo_montpellier/apps/feed_plugin/cms_plugins.py +++ b/compte_agglo_montpellier/apps/feed_plugin/cms_plugins.py @@ -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, diff --git a/compte_agglo_montpellier/apps/feed_plugin/forms.py b/compte_agglo_montpellier/apps/feed_plugin/forms.py index c7ab439..5506fd4 100644 --- a/compte_agglo_montpellier/apps/feed_plugin/forms.py +++ b/compte_agglo_montpellier/apps/feed_plugin/forms.py @@ -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) diff --git a/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html b/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html index cc6de55..41ec1aa 100644 --- a/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html +++ b/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html @@ -1,6 +1,15 @@ {% load i18n %} -
diff --git a/compte_agglo_montpellier/apps/feed_plugin/widgets.py b/compte_agglo_montpellier/apps/feed_plugin/widgets.py new file mode 100644 index 0000000..30a7262 --- /dev/null +++ b/compte_agglo_montpellier/apps/feed_plugin/widgets.py @@ -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 + . + """ + 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_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'' % 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 aCliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.
", + { "fields" : { "body" : "Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.
", "wrapper" : "block" }, "model" : "cmsplugin_text_wrapper.textwrapper", @@ -5792,7 +5792,7 @@ "model" : "cmsplugin_text_wrapper.textwrapper", "pk" : 1640 }, - { "fields" : { "body" : "Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.
", + { "fields" : { "body" : "Cliquez sur une newsletter pour vous (dés)abonner et sauvegardez les changements avec le bouton Modifier.
", "wrapper" : "block" }, "model" : "cmsplugin_text_wrapper.textwrapper", diff --git a/compte_agglo_montpellier/settings.py b/compte_agglo_montpellier/settings.py index 77b349c..f0d6742 100644 --- a/compte_agglo_montpellier/settings.py +++ b/compte_agglo_montpellier/settings.py @@ -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', diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/Annulation.png b/compte_agglo_montpellier/static/themes/django-montpellier/Annulation.png new file mode 100644 index 0000000..1d9b526 Binary files /dev/null and b/compte_agglo_montpellier/static/themes/django-montpellier/Annulation.png differ diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/Picto-Bulle.png b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-Bulle.png new file mode 100644 index 0000000..23f443f Binary files /dev/null and b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-Bulle.png differ diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/Picto-EServices.png b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-EServices.png new file mode 100644 index 0000000..02919a6 Binary files /dev/null and b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-EServices.png differ diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/Picto-coeur.png b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-coeur.png new file mode 100644 index 0000000..d9c556c Binary files /dev/null and b/compte_agglo_montpellier/static/themes/django-montpellier/Picto-coeur.png differ diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/Validation.png b/compte_agglo_montpellier/static/themes/django-montpellier/Validation.png new file mode 100644 index 0000000..963b182 Binary files /dev/null and b/compte_agglo_montpellier/static/themes/django-montpellier/Validation.png differ diff --git a/compte_agglo_montpellier/static/themes/django-montpellier/style.css b/compte_agglo_montpellier/static/themes/django-montpellier/style.css index c7f139f..fa90e38 100644 --- a/compte_agglo_montpellier/static/themes/django-montpellier/style.css +++ b/compte_agglo_montpellier/static/themes/django-montpellier/style.css @@ -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; +} diff --git a/compte_agglo_montpellier/templates/auth/login.html b/compte_agglo_montpellier/templates/auth/login.html index a87d9fe..63511c5 100644 --- a/compte_agglo_montpellier/templates/auth/login.html +++ b/compte_agglo_montpellier/templates/auth/login.html @@ -15,38 +15,51 @@ class="narrow-page" {% block content %}+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 d’intérêts et de ses envies ! +
+ ++E-services accessibles 24h/24 et 7jrs/7 en un clic, navigation qui s’adapte à +l’internaute… 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 +d’informations à découvrir au fil de votre parcours ou de vos recherches. +
+ +
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 ?
-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 ». -
- -
-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 ».
-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 ».
-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.