Diverses améliorations
- ajout commande pour recharger l'ancienne base LDAP, - améliorations dans les template, - ajout des traductions, - ajout de clé naturelles aux modèles, - correction au caractère optionnel de certains champs.
This commit is contained in:
parent
9f2ad26f86
commit
4557734b9d
|
@ -32,4 +32,17 @@ class AccessForm(BaseForm):
|
|||
class UserForm(BaseForm):
|
||||
class Meta:
|
||||
model = models.User
|
||||
fields = ('uid', 'first_name', 'last_name', 'email')
|
||||
fields = (
|
||||
'uid',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'is_admin',
|
||||
'direction',
|
||||
'employee_type',
|
||||
'postal_address',
|
||||
'fax',
|
||||
'mobile',
|
||||
'phone'
|
||||
|
||||
)
|
||||
|
|
|
@ -0,0 +1,402 @@
|
|||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2014-10-30 17:20+0100\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: auth_frontends.py:9 dashboard.py:8
|
||||
msgid "Pr@tic"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:20 models.py:92 tables.py:36 tables.py:49
|
||||
msgid "identifier"
|
||||
msgstr "identifiant"
|
||||
|
||||
#: models.py:24 models.py:212 models.py:279
|
||||
msgid "collectivity"
|
||||
msgstr "collectivité"
|
||||
|
||||
#: models.py:27
|
||||
msgid "is admin"
|
||||
msgstr "Administrateur?"
|
||||
|
||||
#: models.py:32 models.py:106 models.py:111
|
||||
msgid "SIRH Code"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:37
|
||||
msgid "direction"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:42
|
||||
msgid "last connection duration"
|
||||
msgstr "durée de la dernière connexion"
|
||||
|
||||
#: models.py:48
|
||||
msgid "employee type"
|
||||
msgstr "type de poste"
|
||||
|
||||
#: models.py:53 models.py:129
|
||||
msgid "postal address"
|
||||
msgstr "Adresse postale"
|
||||
|
||||
#: models.py:57 models.py:189
|
||||
msgid "fax"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:62
|
||||
msgid "mobile"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:67 models.py:184
|
||||
msgid "phone"
|
||||
msgstr "téléphone"
|
||||
|
||||
#: models.py:72
|
||||
msgid "agent"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:73
|
||||
msgid "agents"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:88 models.py:221 tables.py:10 tables.py:23
|
||||
msgid "name"
|
||||
msgstr "nom"
|
||||
|
||||
#: models.py:96
|
||||
msgid "is superuser"
|
||||
msgstr "Tous les utilisateurs sont des super-administrateurs?"
|
||||
|
||||
#: models.py:101
|
||||
msgid "collectivity id"
|
||||
msgstr "identifiant de la collectivité"
|
||||
|
||||
#: models.py:116
|
||||
msgid "INSEE Code"
|
||||
msgstr "code INSEE"
|
||||
|
||||
#: models.py:121
|
||||
msgid "SIRET Code"
|
||||
msgstr "code SIRET"
|
||||
|
||||
#: models.py:133
|
||||
msgid "street number"
|
||||
msgstr "numéro dans la rue"
|
||||
|
||||
#: models.py:138
|
||||
msgid "street"
|
||||
msgstr "rue"
|
||||
|
||||
#: models.py:143
|
||||
msgid "postal code"
|
||||
msgstr "code postal"
|
||||
|
||||
#: models.py:148
|
||||
msgid "complementary address"
|
||||
msgstr "adresse complémentaire"
|
||||
|
||||
#: models.py:153
|
||||
msgid "address mention"
|
||||
msgstr "adresse (mention complémentaire)"
|
||||
|
||||
#: models.py:158
|
||||
msgid "arrondissement code"
|
||||
msgstr "code d'arrondissement"
|
||||
|
||||
#: models.py:163
|
||||
msgid "canton code"
|
||||
msgstr "numéro de canton"
|
||||
|
||||
#: models.py:168
|
||||
msgid "departement code"
|
||||
msgstr "numéro de département"
|
||||
|
||||
#: models.py:173 models.py:178
|
||||
msgid "distribution office"
|
||||
msgstr "centre de distribution du courrier"
|
||||
|
||||
#: models.py:194
|
||||
msgid "email"
|
||||
msgstr "courriel"
|
||||
|
||||
#: models.py:199 models.py:233 models.py:281
|
||||
msgid "URL"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:213
|
||||
msgid "collectivities"
|
||||
msgstr "collectivités"
|
||||
|
||||
#: models.py:229
|
||||
msgid "is global"
|
||||
msgstr "service global?"
|
||||
|
||||
#: models.py:235 models.py:284
|
||||
msgid "SAML Metadata URL"
|
||||
msgstr "URL des métadonnées SAML"
|
||||
|
||||
#: models.py:238 models.py:287
|
||||
msgid "OAuth2 URL"
|
||||
msgstr "URL du point d'accès OAuth2"
|
||||
|
||||
#: models.py:241 models.py:290
|
||||
msgid "OAuth2 Key"
|
||||
msgstr "Clé OAuth2"
|
||||
|
||||
#: models.py:254 models.py:276
|
||||
msgid "service"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:255
|
||||
msgid "services"
|
||||
msgstr ""
|
||||
|
||||
#: models.py:308
|
||||
msgid "There can be only one instance of a global service by collectivity"
|
||||
msgstr ""
|
||||
"Il ne peut y avoir qu'une seule instance d'un service global par collectivité"
|
||||
|
||||
#: models.py:315
|
||||
msgid "Service URL field is required"
|
||||
msgstr "L'URL de service est requise pour un service non global"
|
||||
|
||||
#: models.py:318 models.py:339
|
||||
msgid "service instance"
|
||||
msgstr "instance de service"
|
||||
|
||||
#: models.py:319
|
||||
msgid "service instances"
|
||||
msgstr "instances de service"
|
||||
|
||||
#: models.py:337
|
||||
msgid "user"
|
||||
msgstr "agent"
|
||||
|
||||
#: models.py:347
|
||||
msgid "access"
|
||||
msgstr "accréditation"
|
||||
|
||||
#: models.py:348
|
||||
msgid "accesses"
|
||||
msgstr "accréditations"
|
||||
|
||||
#: pratic_attribute_source.py:28
|
||||
msgid "User domain"
|
||||
msgstr ""
|
||||
|
||||
#: pratic_attribute_source.py:29
|
||||
msgid "User identifier"
|
||||
msgstr ""
|
||||
|
||||
#: tables.py:13 tables.py:26 tables.py:39 tables.py:52
|
||||
msgid "delete"
|
||||
msgstr "supprimer"
|
||||
|
||||
#: tables.py:61
|
||||
msgid "Last name"
|
||||
msgstr "Nom"
|
||||
|
||||
#: tables.py:63
|
||||
msgid "First name"
|
||||
msgstr "Prénom"
|
||||
|
||||
#: views.py:28 templates/authentic2_pratic/delete.html:27
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: views.py:29
|
||||
#, python-format
|
||||
msgid "Do you really want to delete \"%s\" ?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer \"%s\" ?"
|
||||
|
||||
#: views.py:63 templates/authentic2_pratic/services.html:10
|
||||
msgid "Add service"
|
||||
msgstr "Ajouter un service"
|
||||
|
||||
#: views.py:65 views.py:91 views.py:141 views.py:168 views.py:207
|
||||
msgid "Add"
|
||||
msgstr "Ajouter"
|
||||
|
||||
#: views.py:70
|
||||
msgid "Edit service"
|
||||
msgstr "Éditer un service"
|
||||
|
||||
#: views.py:77
|
||||
msgid "Delete service"
|
||||
msgstr "Supprimer un service"
|
||||
|
||||
#: views.py:89 templates/authentic2_pratic/collectivities.html:10
|
||||
msgid "Add collectivity"
|
||||
msgstr "Ajouter une collectivité"
|
||||
|
||||
#: views.py:96
|
||||
msgid "Edit collectivity"
|
||||
msgstr "Éditer une collectivité"
|
||||
|
||||
#: views.py:104
|
||||
msgid "Delete collectivity"
|
||||
msgstr "Supprimer une collectivité"
|
||||
|
||||
#: views.py:139 templates/authentic2_pratic/users.html:10
|
||||
msgid "Add agent"
|
||||
msgstr "Ajouter un agent"
|
||||
|
||||
#: views.py:146
|
||||
msgid "Edit agent"
|
||||
msgstr "Éditer un agent"
|
||||
|
||||
#: views.py:154
|
||||
msgid "Delete agent"
|
||||
msgstr "Supprimer un agent"
|
||||
|
||||
#: views.py:166 views.py:205
|
||||
msgid "Add service instance"
|
||||
msgstr "Ajouter une instance de service"
|
||||
|
||||
#: views.py:174 views.py:213
|
||||
msgid "Edit service instance"
|
||||
msgstr "Éditer une instance de service"
|
||||
|
||||
#: views.py:182 views.py:221
|
||||
msgid "Delete service instance"
|
||||
msgstr "Supprimer une instance de service"
|
||||
|
||||
#: templates/authentic2_pratic/accesses.html:4
|
||||
#: templates/authentic2_pratic/accesses.html:6
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:14
|
||||
msgid "Accesses management"
|
||||
msgstr "Gestion des accréditations"
|
||||
|
||||
#: templates/authentic2_pratic/accesses.html:10
|
||||
msgid "Add access"
|
||||
msgstr "Ajouter une accréditation"
|
||||
|
||||
#: templates/authentic2_pratic/accesses.html:14
|
||||
#, python-format
|
||||
msgid "%(count)s accesses"
|
||||
msgid_plural "%(count)s access"
|
||||
msgstr[0] "%(count)s accréditation"
|
||||
msgstr[1] "%(count)s accréditations"
|
||||
|
||||
#: templates/authentic2_pratic/base.html:4
|
||||
#: templates/authentic2_pratic/base.html:26
|
||||
msgid "Management"
|
||||
msgstr "Gestion"
|
||||
|
||||
#: templates/authentic2_pratic/collectivities.html:4
|
||||
#: templates/authentic2_pratic/collectivities.html:6
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:8
|
||||
msgid "Collectivities management"
|
||||
msgstr "Gestion des collectivités"
|
||||
|
||||
#: templates/authentic2_pratic/collectivities.html:15
|
||||
#: templates/authentic2_pratic/collectivities.html:18
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#: templates/authentic2_pratic/collectivities.html:21
|
||||
#, python-format
|
||||
msgid "%(count)s collectivities"
|
||||
msgid_plural "%(count)s collectivity"
|
||||
msgstr[0] "%(count)s collectivité"
|
||||
msgstr[1] "%(count)s collectivités"
|
||||
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:12
|
||||
#: templates/authentic2_pratic/users.html:4
|
||||
#: templates/authentic2_pratic/users.html:6
|
||||
msgid "Agents management"
|
||||
msgstr "Gestion des agents"
|
||||
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:13
|
||||
#: templates/authentic2_pratic/service_instances.html:4
|
||||
#: templates/authentic2_pratic/service_instances.html:6
|
||||
msgid "Service instances management"
|
||||
msgstr "Gestion des instances de service"
|
||||
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:24
|
||||
#: templates/authentic2_pratic/form.html:31
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:48
|
||||
#: templates/authentic2_pratic/form.html:26
|
||||
msgid "Save"
|
||||
msgstr "Sauvegarder"
|
||||
|
||||
#: templates/authentic2_pratic/collectivity_edit.html:49
|
||||
#: templates/authentic2_pratic/delete.html:28
|
||||
#: templates/authentic2_pratic/form.html:27
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: templates/authentic2_pratic/delete.html:23
|
||||
#, python-format
|
||||
msgid "Do you really want to delete « %(object)s » ?"
|
||||
msgstr "Êtez-vous sûr de vouloir supprimer « %(object)s » ?"
|
||||
|
||||
#: templates/authentic2_pratic/homepage.html:8
|
||||
msgid "Welcome"
|
||||
msgstr "Bievenue"
|
||||
|
||||
#: templates/authentic2_pratic/homepage.html:15
|
||||
msgid "Password change"
|
||||
msgstr "Changer de mot de passe"
|
||||
|
||||
#: templates/authentic2_pratic/homepage.html:19
|
||||
msgid "Collectivities"
|
||||
msgstr "Collectivités"
|
||||
|
||||
#: templates/authentic2_pratic/homepage.html:20
|
||||
msgid "Services"
|
||||
msgstr ""
|
||||
|
||||
#: templates/authentic2_pratic/service_instances.html:10
|
||||
msgid "Add service-instance"
|
||||
msgstr "Ajouter une instance de service"
|
||||
|
||||
#: templates/authentic2_pratic/service_instances.html:14
|
||||
#, python-format
|
||||
msgid "%(count)s services instances"
|
||||
msgid_plural "%(count)s service instance"
|
||||
msgstr[0] "%(count)s instance de service"
|
||||
msgstr[1] "%(count)s instances de service"
|
||||
|
||||
#: templates/authentic2_pratic/services.html:4
|
||||
#: templates/authentic2_pratic/services.html:6
|
||||
msgid "Services management"
|
||||
msgstr "Gestion des services"
|
||||
|
||||
#: templates/authentic2_pratic/services.html:14
|
||||
#, python-format
|
||||
msgid "%(count)s services"
|
||||
msgid_plural "%(count)s service"
|
||||
msgstr[0] "%(count)s service"
|
||||
msgstr[1] "%(count)s services"
|
||||
|
||||
#: templates/authentic2_pratic/users.html:14
|
||||
#, python-format
|
||||
msgid "%(count)s agent"
|
||||
msgid_plural "%(count)s agents"
|
||||
msgstr[0] "%(count)s agent"
|
||||
msgstr[1] "%(count)s agents"
|
||||
|
||||
#~ msgid "Add user"
|
||||
#~ msgstr "Ajouter un agent"
|
||||
|
||||
#~ msgid "Edit user"
|
||||
#~ msgstr "Éditer un agent"
|
|
@ -0,0 +1,242 @@
|
|||
import logging
|
||||
from optparse import make_option
|
||||
from datetime import datetime
|
||||
from itertools import chain
|
||||
|
||||
import ldif
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import transaction
|
||||
from django.utils.timezone import get_default_timezone, make_aware
|
||||
|
||||
from authentic2.hashers import olap_password_to_dj
|
||||
|
||||
from authentic2_pratic.models import (Service, Collectivity, ServiceInstance,
|
||||
User, Access)
|
||||
|
||||
|
||||
class PraticLDIFParser(ldif.LDIFParser):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.services = {}
|
||||
self.service_instances = {}
|
||||
self.accesses = []
|
||||
self.collectivities = {}
|
||||
self.users = []
|
||||
self.log = logging.getLogger(__name__)
|
||||
ldif.LDIFParser.__init__(self, *args, **kwargs)
|
||||
|
||||
def convert_to_utf8(self, entry):
|
||||
for key in entry:
|
||||
new_values = []
|
||||
for value in entry[key]:
|
||||
try:
|
||||
value = unicode(value, 'utf-8')
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
new_values.append(value)
|
||||
entry[key] = new_values
|
||||
|
||||
def handle(self, dn, entry):
|
||||
objectclass = entry['objectClass']
|
||||
self.convert_to_utf8(entry)
|
||||
if 'cdg59serviceInstance' in objectclass:
|
||||
self.handle_service_instance(dn, entry)
|
||||
elif 'cdg59service' in objectclass:
|
||||
self.handle_service(dn, entry)
|
||||
elif 'cdg59collectivity' in objectclass:
|
||||
self.handle_collectivity(dn, entry)
|
||||
elif 'cdg59agent' in objectclass:
|
||||
self.handle_user(dn, entry)
|
||||
|
||||
def resolve_attribute(self, entry, key):
|
||||
return entry.get(key, [''])[0]
|
||||
|
||||
def resolve_mapping(self, mapping, entry):
|
||||
d = {}
|
||||
for key in mapping:
|
||||
ldap_name = mapping[key]
|
||||
if ldap_name in entry:
|
||||
d[key] = entry[ldap_name][0]
|
||||
return d
|
||||
|
||||
def handle_collectivity(self, dn, entry):
|
||||
slug = entry['ou'][0]
|
||||
name = entry.get('cn', ['slug'])[0]
|
||||
mapping = {
|
||||
'collectivity_id': 'cdg59collectivityId',
|
||||
'sirh_code': 'cdg59collectivitySirhCode',
|
||||
'sirh_label': 'cdg59collectivitySirhLabel',
|
||||
'siret_code': 'cdg59siretCode',
|
||||
'postal_address': 'postalAddress',
|
||||
'street_number': 'cdg59streetNumber',
|
||||
'street': 'street',
|
||||
'postal_code': 'postalCode',
|
||||
'address_complementary': 'cdg59addressCompl',
|
||||
'address_mention': 'cdg59addressMention',
|
||||
'arrondissement_code': 'cdg59arrondissementCode',
|
||||
'canton_code': 'cdg59cantonCode',
|
||||
'departement_code': 'cdg59departementCode',
|
||||
'dist_office': 'cdg59distOffice',
|
||||
'region_code': 'cdg59regionCode',
|
||||
'phone': 'telephoneNumber',
|
||||
'fax': 'facsimileTelephoneNumber',
|
||||
'email': 'email',
|
||||
'url': 'cdg59URL',
|
||||
}
|
||||
others = self.resolve_mapping(mapping, entry)
|
||||
collectivity = Collectivity(name=name, slug=slug, **others)
|
||||
collectivity.clean()
|
||||
self.collectivities[dn] = collectivity
|
||||
|
||||
def handle_service(self, dn, entry):
|
||||
# services
|
||||
# dn: cdg59sid=agirhe,dc=pratic59,dc=fr
|
||||
# cn: Agirhe
|
||||
# cdg59isGlobal: TRUE
|
||||
# objectClass: cdg59service
|
||||
# cdg59metadataURL: https://agirhe.pratic59.fr/liberty/agirhe/saml/metadata.xml
|
||||
# cdg59URL: https://agirhe.pratic59.fr/
|
||||
# cdg59sid: agirhe
|
||||
# structuralObjectClass: cdg59service
|
||||
# entryUUID: c8a4a0fc-7813-102d-97eb-a7725ef3fb45
|
||||
# creatorsName: uid=cdg59,ou=admin,dc=pratic59,dc=fr
|
||||
# createTimestamp: 20090116122019Z
|
||||
# entryCSN: 20090116122019.000000Z#000000#000#000000
|
||||
# modifiersName: uid=cdg59,ou=admin,dc=pratic59,dc=fr
|
||||
# modifyTimestamp: 20090116122019Z
|
||||
slug = entry['cdg59sid'][0]
|
||||
name = entry.get('cn', [slug])[0]
|
||||
service_url = entry.get('cdg59URL', [''])[0]
|
||||
metadata_url = entry.get('cdg59metadataURL', [''])[0]
|
||||
is_global = entry.get('cdg59isGlobal', ['FALSE'])[0] == 'TRUE'
|
||||
service = Service(
|
||||
name=name,
|
||||
slug=slug,
|
||||
is_global=is_global,
|
||||
service_url=service_url,
|
||||
metadata_url=metadata_url)
|
||||
service.clean()
|
||||
self.services[slug] = service
|
||||
|
||||
def handle_service_instance(self, dn, entry):
|
||||
collectivity_dn = dn.split(',', 1)[1]
|
||||
collectivity = self.collectivities[collectivity_dn]
|
||||
mapping = {
|
||||
'slug': 'cdg59siid',
|
||||
'service_url': 'cdg59URL',
|
||||
'metadata_url': 'cdg59metadataURL',
|
||||
}
|
||||
others = self.resolve_mapping(mapping, entry)
|
||||
def resolve():
|
||||
service = self.services[entry['cdg59serviceType'][0]]
|
||||
if not service.is_global and 'service_url' not in others:
|
||||
others['service_url'] = 'http://missing-url-%s.com' % others['slug']
|
||||
service_instance = ServiceInstance(
|
||||
collectivity=collectivity,
|
||||
service=service,
|
||||
**others)
|
||||
service_instance.clean()
|
||||
return service_instance
|
||||
self.service_instances[(collectivity.slug, others['slug'])] = resolve
|
||||
|
||||
def handle_user(self, dn, entry):
|
||||
collectivity_dn = dn.split(',', 1)[1]
|
||||
collectivity = self.collectivities[collectivity_dn]
|
||||
is_active = entry.get('cdg59isDisabled', ['FALSE'])[0] == 'FALSE'
|
||||
mapping = {
|
||||
'first_name': 'givenName',
|
||||
'last_name': 'sn',
|
||||
'email': 'mail',
|
||||
'uid': 'uid',
|
||||
'sirh_code': 'cdg59agentSirhCode',
|
||||
'direction': 'cdg59direction',
|
||||
'employee_type': 'employeeType',
|
||||
'postal_address': 'postalAddress',
|
||||
'fax': 'facsimileTelephoneNumber',
|
||||
'mobile': 'mobile',
|
||||
'phone': 'telephoneNumber',
|
||||
}
|
||||
others = self.resolve_mapping(mapping, entry)
|
||||
last_login_duration = int(entry.get('cdg59lastConnectionDuration', [0])[0])
|
||||
is_admin = entry.get('cdg59isAdmin', ['FALSE'])[0] == 'TRUE'
|
||||
user = User(
|
||||
collectivity=collectivity,
|
||||
is_active=is_active,
|
||||
last_login_duration=last_login_duration,
|
||||
is_admin=is_admin,
|
||||
**others)
|
||||
if 'cdg59lastConnectionTime' in entry:
|
||||
last_login = datetime.fromtimestamp(int(entry['cdg59lastConnectionTime'][0]))
|
||||
last_login = make_aware(last_login, get_default_timezone())
|
||||
user.last_login = last_login
|
||||
if 'userPassword' in entry:
|
||||
password = olap_password_to_dj(entry['userPassword'][0])
|
||||
user.password = password
|
||||
user.clean()
|
||||
self.users.append(user)
|
||||
#accesses
|
||||
for siid in entry.get('cdg59serviceAccesses', []):
|
||||
def f():
|
||||
try:
|
||||
service_instance = self.service_instances[(collectivity.slug, siid)]
|
||||
access = Access(
|
||||
user=user,
|
||||
service_instance=service_instance)
|
||||
return access
|
||||
except KeyError:
|
||||
pass
|
||||
self.accesses.append(f)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
'''Load LDAP ldif file'''
|
||||
can_import_django_settings = True
|
||||
requires_model_validation = True
|
||||
option_list = BaseCommand.option_list + (
|
||||
make_option('--fake',
|
||||
action='store_true',
|
||||
help='file to store a JSON log of created users'),
|
||||
)
|
||||
args = '<ldif_file...>'
|
||||
help = 'Load/update LDIF files as users'
|
||||
|
||||
def save_object(self, obj):
|
||||
# set fk
|
||||
if not obj:
|
||||
return
|
||||
for attr in ('collectivity', 'service', 'service_instance', 'user'):
|
||||
if hasattr(obj, attr):
|
||||
setattr(obj, attr, getattr(obj, attr))
|
||||
try:
|
||||
# link to existing object
|
||||
already = obj.__class__.objects.get_by_natural_key(*obj.natural_key())
|
||||
obj.pk = already.pk
|
||||
except obj.__class__.DoesNotExist:
|
||||
pass
|
||||
obj.save()
|
||||
|
||||
@transaction.commit_on_success
|
||||
def handle(self, *args, **options):
|
||||
options['verbosity'] = int(options['verbosity'])
|
||||
for arg in args:
|
||||
f = file(arg)
|
||||
parser = PraticLDIFParser(f)
|
||||
parser.parse()
|
||||
print 'Parsed:'
|
||||
print '', '-', len(parser.collectivities), 'collectivities'
|
||||
print '', '-', len(parser.services), 'services'
|
||||
print '', '-', len(parser.users), 'users'
|
||||
print '', '-', len(parser.service_instances), 'service instances'
|
||||
print '', '-', len(parser.accesses), 'accesses'
|
||||
for key in parser.service_instances:
|
||||
parser.service_instances[key] = parser.service_instances[key]()
|
||||
parser.accesses = [resolve() for resolve in parser.accesses]
|
||||
for obj in chain(parser.collectivities.itervalues(),
|
||||
parser.services.itervalues(),
|
||||
parser.service_instances.itervalues(),
|
||||
parser.users,
|
||||
parser.accesses):
|
||||
self.save_object(obj)
|
||||
|
||||
if options['fake']:
|
||||
raise Exception('Fake execution')
|
|
@ -1,9 +1,11 @@
|
|||
from django.db.models import (Model, TextField, CharField, EmailField,
|
||||
URLField, BooleanField, IntegerField, ForeignKey, SlugField)
|
||||
URLField, BooleanField, IntegerField, ForeignKey, SlugField, Manager)
|
||||
from django.contrib.auth.models import User as AuthUser
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from authentic2 import managers
|
||||
|
||||
class User(AuthUser):
|
||||
# givenName -> first_name
|
||||
# sn -> last_name
|
||||
|
@ -53,7 +55,8 @@ class User(AuthUser):
|
|||
# facsimileTelephoneNumber
|
||||
fax = CharField(
|
||||
verbose_name=_('fax'),
|
||||
max_length=32)
|
||||
max_length=32,
|
||||
blank=True)
|
||||
# mobile
|
||||
mobile = CharField(
|
||||
verbose_name=_('mobile'),
|
||||
|
@ -62,7 +65,11 @@ class User(AuthUser):
|
|||
# telephoneNumber
|
||||
phone = CharField(
|
||||
verbose_name=_('phone'),
|
||||
max_length=32)
|
||||
max_length=32,
|
||||
blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.get_full_name().strip() or self.uid
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('agent')
|
||||
|
@ -88,6 +95,10 @@ class Collectivity(Model):
|
|||
verbose_name=_('identifier'),
|
||||
max_length=64,
|
||||
unique=True)
|
||||
is_superuser = BooleanField(
|
||||
verbose_name=_('is superuser'),
|
||||
default=False,
|
||||
blank=True)
|
||||
# cdg59collectivityId
|
||||
collectivity_id = CharField(
|
||||
verbose_name=_('collectivity id'),
|
||||
|
@ -170,8 +181,6 @@ class Collectivity(Model):
|
|||
verbose_name=_('distribution office'),
|
||||
max_length=4,
|
||||
blank=True)
|
||||
|
||||
|
||||
# Contact
|
||||
# telephoneNumber
|
||||
phone = CharField(
|
||||
|
@ -194,6 +203,11 @@ class Collectivity(Model):
|
|||
max_length=128,
|
||||
blank=True)
|
||||
|
||||
objects = managers.GetByNameManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.name,)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
|
@ -234,11 +248,28 @@ class Service(Model):
|
|||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
objects = managers.GetByNameManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.name,)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('service')
|
||||
verbose_name_plural = _('services')
|
||||
ordering = ('name',)
|
||||
|
||||
class ServiceInstanceManager(Manager):
|
||||
def get_by_natural_key(self, slug, service_nk, collectivity_nk):
|
||||
try:
|
||||
service = Service.objects.get_by_natural_key(*service_nk)
|
||||
except Service.DoesNotExist:
|
||||
raise ServiceInstance.DoesNotExist
|
||||
try:
|
||||
collectivity = Collectivity.objects.get_by_natural_key(*collectivity_nk)
|
||||
except Collectivity.DoesNotExist:
|
||||
raise ServiceInstance.DoesNotExist
|
||||
return self.get(slug=slug, service=service, collectivity=collectivity)
|
||||
|
||||
class ServiceInstance(Model):
|
||||
# cdg59sid
|
||||
slug = SlugField(
|
||||
|
@ -266,6 +297,11 @@ class ServiceInstance(Model):
|
|||
def __unicode__(self):
|
||||
return unicode(self.service)
|
||||
|
||||
objects = ServiceInstanceManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.slug, self.service.natural_key(), self.collectivity.natural_key())
|
||||
|
||||
def clean(self):
|
||||
if self.collectivity and self.service and self.service.is_global:
|
||||
qs = ServiceInstance.objects.exclude(id=self.id)
|
||||
|
@ -273,21 +309,45 @@ class ServiceInstance(Model):
|
|||
service=self.service)
|
||||
if qs.exists():
|
||||
raise ValidationError(_('There can be only one instance of a global service by collectivity'))
|
||||
if self.service and self.service.is_global:
|
||||
self.service_url = self.service.service_url
|
||||
self.metadata_url = self.service.metadata_url
|
||||
self.oauth2_url = self.service.oauth2_url
|
||||
self.oauth2_key = self.oauth2_key
|
||||
if not self.service.is_global and not self.service_url:
|
||||
import pdb
|
||||
pdb.set_trace()
|
||||
raise ValidationError(_('Service URL field is required'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('service instance')
|
||||
verbose_name = _('service instances')
|
||||
unique_together = (('slug', 'service', 'collectivity'),)
|
||||
unique_together = (('slug', 'collectivity'),)
|
||||
ordering = ('service__name', 'slug')
|
||||
|
||||
class AccessManager(Manager):
|
||||
def get_by_natural_key(self, user_nk, service_instance_nk):
|
||||
try:
|
||||
user = User.objects.get_by_natural_key(*user_nk)
|
||||
except User.DoesNotExist:
|
||||
raise ServiceInstance.DoesNotExist
|
||||
try:
|
||||
service_instance = ServiceInstance.objects.get_by_natural_key(*service_instance_nk)
|
||||
except ServiceInstance.DoesNotExist:
|
||||
raise Access.DoesNotExist
|
||||
return self.get(user=user, service_instance=service_instance)
|
||||
|
||||
class Access(Model):
|
||||
user = ForeignKey('User',
|
||||
verbose_name=_('user'))
|
||||
service_instance = ForeignKey('ServiceInstance',
|
||||
verbose_name=_('service instance'))
|
||||
|
||||
objects = AccessManager()
|
||||
|
||||
def natural_key(self):
|
||||
return (self.user.natural_key(), self.service_instance.natural_key())
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('access')
|
||||
verbose_name = _('accesses')
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
import django_tables2 as tables
|
||||
|
||||
|
@ -10,7 +11,7 @@ class ServiceTable(tables.Table):
|
|||
verbose_name=_('name'))
|
||||
delete = tables.TemplateColumn(
|
||||
'{% load i18n %}<a rel="popup" href="{% url "a2-pratic-service-delete" pk=record.pk %}">{% trans "Delete" %}</a>',
|
||||
verbose_name=_('delete'))
|
||||
verbose_name=mark_safe(' '))
|
||||
|
||||
class Meta:
|
||||
model = models.Service
|
||||
|
@ -23,7 +24,7 @@ class CollectivityTable(tables.Table):
|
|||
verbose_name=_('name'))
|
||||
delete = tables.TemplateColumn(
|
||||
'{% load i18n %}<a rel="popup" href="{% url "a2-pratic-collectivity-delete" collectivity_pk=record.pk %}">{% trans "Delete" %}</a>',
|
||||
verbose_name=_('delete'))
|
||||
verbose_name=mark_safe(' '))
|
||||
|
||||
class Meta:
|
||||
model = models.Collectivity
|
||||
|
@ -36,7 +37,7 @@ class UserTable(tables.Table):
|
|||
verbose_name=_('identifier'))
|
||||
delete = tables.TemplateColumn(
|
||||
'{% load i18n %}<a rel="popup" href="{% url "a2-pratic-user-delete" collectivity_pk=record.collectivity.pk pk=record.pk %}">{% trans "Delete" %}</a>',
|
||||
verbose_name=_('delete'))
|
||||
verbose_name=mark_safe(' '))
|
||||
|
||||
class Meta:
|
||||
model = models.User
|
||||
|
@ -49,18 +50,18 @@ class ServiceInstanceTable(tables.Table):
|
|||
verbose_name=_('identifier'))
|
||||
delete = tables.TemplateColumn(
|
||||
'{% load i18n %}<a rel="popup" href="{% url "a2-pratic-service-instance-delete" collectivity_pk=record.collectivity.pk pk=record.pk %}">{% trans "Delete" %}</a>',
|
||||
verbose_name=_('delete'))
|
||||
verbose_name=mark_safe(' '))
|
||||
|
||||
class Meta:
|
||||
model = models.User
|
||||
attrs = {'class': 'main', 'id': 'users-table'}
|
||||
fields = ('slug', 'service_url')
|
||||
fields = ('service', 'slug', 'service_url')
|
||||
|
||||
class AccessTable(tables.Table):
|
||||
last_name = tables.TemplateColumn('{{ record.user.last_name}}',
|
||||
verbose_name=_('Last name'))
|
||||
verbose_name=_('Last name'), order_by=('user__last_name',))
|
||||
first_name = tables.TemplateColumn('{{ record.user.first_name }}',
|
||||
verbose_name=_('First name'))
|
||||
verbose_name=_('First name'), order_by=('user__first_name',))
|
||||
|
||||
class Meta:
|
||||
model = models.Access
|
||||
|
|
|
@ -11,6 +11,13 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<div>
|
||||
<h3>{% trans "Search" %}</h3>
|
||||
<div id="search-form">
|
||||
<input id="search-input" type="search" value="{{ request.GET.search }}">
|
||||
<button>{% trans "Search" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} collectivities{% plural %}{{ count }} collectivity{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p><a href="users/">{% trans "Users management" %}</a></p>
|
||||
<p><a href="users/">{% trans "Agents management" %}</a></p>
|
||||
<p><a href="services/">{% trans "Service instances management" %}</a></p>
|
||||
<p><a href="accesses/">{% trans "Accesses management" %}</a></p>
|
||||
{% endblock %}
|
||||
|
|
|
@ -9,18 +9,6 @@
|
|||
{% if title %}
|
||||
<div id="appbar"><h2>{{ title }}</h2></div>
|
||||
{% endif %}
|
||||
{% if other_actions %}
|
||||
<div class="other_actions">
|
||||
<strong>{% trans "Actions" %}</strong>
|
||||
<form method="post">
|
||||
{% for action in other_actions %}
|
||||
<input type="submit" name="{{ action.name }}" value="{{ action.title }}"
|
||||
{% if action.confirm %}data-confirm="{{ action.confirm }}"{% endif %}
|
||||
/>
|
||||
{% endfor %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
<form method="post">
|
||||
<div class="form-inner-container">
|
||||
{% if messages %}
|
||||
|
@ -38,6 +26,18 @@
|
|||
<button>{% if action %}{{ action }}{% else %}{% trans "Save" %}{% endif %}</button>
|
||||
<a class="cancel" href="..">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
{% if other_actions %}
|
||||
<div class="other_actions">
|
||||
<strong>{% trans "Actions" %}</strong>
|
||||
<form method="post">
|
||||
{% for action in other_actions %}
|
||||
<input type="submit" name="{{ action.name }}" value="{{ action.title }}"
|
||||
{% if action.confirm %}data-confirm="{{ action.confirm }}"{% endif %}
|
||||
/>
|
||||
{% endfor %}
|
||||
</form>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
{% extends "authentic2_pratic/collectivity_sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page-title %}{{ block.super }} - {% trans "Users management" %}{% endblock %}
|
||||
{% block page-title %}{{ block.super }} - {% trans "Agents management" %}{% endblock %}
|
||||
|
||||
{% block page_title %}{{ block.super }}{% trans "Users management" %}{% endblock %}
|
||||
{% block page_title %}{{ block.super }}{% trans "Agents management" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{{ block.super }}
|
||||
<a rel="popup" href="{% url "a2-pratic-user-add" collectivity_pk=collectivity.pk %}" id="add-user-btn">{% trans "Add user" %}</a>
|
||||
<a rel="popup" href="{% url "a2-pratic-user-add" collectivity_pk=collectivity.pk %}" id="add-user-btn">{% trans "Add agent" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} users{% plural %}{{ count }} user{% endblocktrans %}</p>
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} agent{% plural %}{{ count }} agents{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.contrib import messages
|
||||
from django.db.models.query import Q
|
||||
|
||||
from django.views.generic import (TemplateView, FormView, UpdateView,
|
||||
CreateView, DeleteView, View, ListView)
|
||||
|
@ -20,16 +21,21 @@ def is_pratic_admin(user):
|
|||
return getattr(user, 'is_admin', False)
|
||||
|
||||
pratic_admin = user_passes_test(is_pratic_admin)
|
||||
class DeleteActionMixin(object):
|
||||
|
||||
def get_other_actions(self):
|
||||
yield Action('delete',
|
||||
_('Delete'),
|
||||
_(u'Do you really want to delete "%s" ?') % self.object)
|
||||
class SearchMixin(object):
|
||||
search_filter = []
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super(SearchMixin, self).get_queryset()
|
||||
search = self.request.GET.get('search')
|
||||
if search:
|
||||
filters = []
|
||||
for name in self.search_filter:
|
||||
filters.append(Q(**{'%s__contains' % name: search}))
|
||||
filters = reduce(Q.__or__, filters)
|
||||
qs = qs.filter(filters)
|
||||
return qs
|
||||
|
||||
def action_delete(self, request, *args, **kwargs):
|
||||
self.object.delete()
|
||||
return HttpResponseRedirect('.')
|
||||
|
||||
class HomepageView(TemplateView):
|
||||
template_name = 'authentic2_pratic/homepage.html'
|
||||
|
@ -48,7 +54,7 @@ class ServiceAddView(TitleMixin, ActionMixin, AjaxFormViewMixin, CreateView):
|
|||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
|
||||
class ServiceView(DeleteActionMixin, TitleMixin, OtherActionsMixin,
|
||||
class ServiceView(TitleMixin, OtherActionsMixin,
|
||||
AjaxFormViewMixin, UpdateView):
|
||||
model = models.Service
|
||||
title = _('Edit service')
|
||||
|
@ -62,7 +68,8 @@ class ServiceDeleteView(TitleMixin, AjaxFormViewMixin, DeleteView):
|
|||
success_url = 'a2-pratic-services'
|
||||
|
||||
# Collectivities
|
||||
class CollectivitiesView(SingleTableView):
|
||||
class CollectivitiesView(SearchMixin, SingleTableView):
|
||||
search_filter = ('name', 'slug', 'sirh_label', 'postal_code')
|
||||
template_name = 'authentic2_pratic/collectivities.html'
|
||||
model = models.Collectivity
|
||||
table_class = tables.CollectivityTable
|
||||
|
@ -73,7 +80,7 @@ class CollectivityAddView(TitleMixin, ActionMixin, AjaxFormViewMixin, CreateView
|
|||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
|
||||
class CollectivityView(DeleteActionMixin, TitleMixin, OtherActionsMixin,
|
||||
class CollectivityView(TitleMixin, OtherActionsMixin,
|
||||
AjaxFormViewMixin, UpdateView):
|
||||
model = models.Collectivity
|
||||
title = _('Edit collectivity')
|
||||
|
@ -119,22 +126,29 @@ class UsersView(CollectivityChildMixin, SingleTableView):
|
|||
class UserAddView(CollectivityChildMixin, TitleMixin, ActionMixin,
|
||||
AjaxFormViewMixin, CreateView):
|
||||
model = models.User
|
||||
title = _('Add user')
|
||||
title = _('Add agent')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
form_class = forms.UserForm
|
||||
|
||||
class UserView(CollectivityChildMixin, UserEditView):
|
||||
model = models.User
|
||||
title = _('Edit user')
|
||||
title = _('Edit agent')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
form_class = forms.UserForm
|
||||
|
||||
def get_other_actions(self):
|
||||
yield Action('password_reset', _('Reset password'))
|
||||
if self.object.is_active:
|
||||
yield Action('deactivate', _('Deactivate'))
|
||||
else:
|
||||
yield Action('activate', _('Activate'))
|
||||
|
||||
class UserDeleteView(CollectivityChildMixin, TitleMixin, AjaxFormViewMixin,
|
||||
DeleteView):
|
||||
model = models.Service
|
||||
model = models.User
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete user')
|
||||
title = _('Delete agent')
|
||||
success_url = 'a2-pratic-users'
|
||||
|
||||
# service instances
|
||||
|
@ -151,7 +165,7 @@ class ServiceInstanceAddView(CollectivityChildMixin, TitleMixin, ActionMixin,
|
|||
action = _('Add')
|
||||
form_class = forms.ServiceInstanceForm
|
||||
|
||||
class ServiceInstanceView(CollectivityChildMixin, DeleteActionMixin, TitleMixin,
|
||||
class ServiceInstanceView(CollectivityChildMixin, TitleMixin,
|
||||
OtherActionsMixin, AjaxFormViewMixin, UpdateView):
|
||||
model = models.ServiceInstance
|
||||
title = _('Edit service instance')
|
||||
|
@ -190,7 +204,7 @@ class AccessAddView(AccessMixin, CollectivityMixin, TitleMixin, ActionMixin,
|
|||
action = _('Add')
|
||||
form_class = forms.AccessForm
|
||||
|
||||
class AccessView(AccessMixin, CollectivityMixin, DeleteActionMixin, TitleMixin,
|
||||
class AccessView(AccessMixin, CollectivityMixin, TitleMixin,
|
||||
OtherActionsMixin, AjaxFormViewMixin, UpdateView):
|
||||
model = models.Access
|
||||
title = _('Edit service instance')
|
||||
|
|
Reference in New Issue