Premier commit
This commit is contained in:
commit
9f2ad26f86
|
@ -0,0 +1 @@
|
|||
authentic2-pratic is distributed under the license AGPLv3 or later.
|
|
@ -0,0 +1,3 @@
|
|||
include COPYING
|
||||
recursive-include src/authentic2_pratic/templates *.html
|
||||
recursive-include src/authentic2_pratic/static *.js *.css *.png
|
|
@ -0,0 +1,18 @@
|
|||
Authentic2 Pr@tic
|
||||
=================
|
||||
|
||||
Remplacement pour les pages de gestion d'Authentic2:
|
||||
- gestion des collectivités
|
||||
- gestion des utilisateurs
|
||||
- gestion des services
|
||||
- gestion des droits d'accès
|
||||
|
||||
|
||||
URLs
|
||||
====
|
||||
|
||||
/manage/ - liste des collectivités
|
||||
/manage/<collectivite>/ - menu services, utilisateurs et autorisations
|
||||
/manage/<collectivite>/services/ - services
|
||||
/manage/<collectivite>/utilisateurs/ - utilisateurs
|
||||
/manage/<collectivite>/autorisations/ - autorisations
|
|
@ -0,0 +1,193 @@
|
|||
# Schéma LDAP
|
||||
#
|
||||
|
||||
objectIdentifier Cdg59Root 1.1
|
||||
objectIdentifier Cdg59LDAP Cdg59Root:2
|
||||
objectIdentifier Cdg59LDAPAttribute Cdg59LDAP:1
|
||||
objectIdentifier Cdg59LDAPObjectClass Cdg59LDAP:2
|
||||
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:1 NAME 'cdg59siretCode'
|
||||
DESC 'Collectivity SIRET code'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SINGLE-VALUE)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:2 NAME 'cdg59direction'
|
||||
DESC 'Collectivity Direction'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:3 NAME 'cdg59isAdmin'
|
||||
DESC 'Admin or not'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:4 NAME 'cdg59isDisabled'
|
||||
DESC 'Acccount disabled or not'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:5 NAME 'cdg59sid'
|
||||
DESC 'Service Id'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:6 NAME 'cdg59siid'
|
||||
DESC 'Service Instance Id'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:7 NAME 'cdg59serviceType'
|
||||
DESC 'Service Type'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:8 NAME 'cdg59URL'
|
||||
DESC 'Generic URL'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:9 NAME 'cdg59metadataURL'
|
||||
DESC 'Service Metadata URL'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:10 NAME 'cdg59serviceAccesses'
|
||||
DESC 'Services an agent can access'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:11 NAME 'cdg59collectivitySirhCode'
|
||||
DESC 'Collectivity SIRH code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
SINGLE-VALUE)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:12 NAME 'cdg59collectivitySirhLabel'
|
||||
DESC 'Collectivity SIRH Label'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:13 NAME 'cdg59regionCode'
|
||||
DESC 'Collectivity "Region" Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:14 NAME 'cdg59departementCode'
|
||||
DESC 'Collectivity "Departement" Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:15 NAME 'cdg59arrondissementCode'
|
||||
DESC 'Collectivity "Arrondissement" Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:16 NAME 'cdg59cantonCode'
|
||||
DESC 'Collectivity "Canton" Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:17 NAME 'cdg59inseeCode'
|
||||
DESC 'Collectivity INSEE Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:18 NAME 'cdg59streetNumber'
|
||||
DESC 'Collectivity street number'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256})
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:19 NAME 'cdg59distOffice'
|
||||
DESC 'Collectivity distribution office'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:20 NAME 'cdg59addressCompl'
|
||||
DESC 'Collectivity complementary address infomation'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:21 NAME 'cdg59addressMention'
|
||||
DESC 'Collectivity particular mention on address'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:22 NAME 'cdg59agentSirhCode'
|
||||
DESC 'Collectivity SIRH code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
SINGLE-VALUE)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:23 NAME 'cdg59isGlobal'
|
||||
DESC 'Global service, or not'
|
||||
EQUALITY booleanMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:24 NAME 'cdg59ssoRelayState'
|
||||
DESC 'URL for redirection after a single sign on'
|
||||
EQUALITY caseIgnoreMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:25 NAME 'cdg59lastConnectionTime'
|
||||
DESC 'Last connection time'
|
||||
EQUALITY integerMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:26 NAME 'cdg59lastConnectionDuration'
|
||||
DESC 'Last connection duration'
|
||||
EQUALITY integerMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.27)
|
||||
|
||||
attributetype ( Cdg59LDAPAttribute:28 NAME 'cdg59collectivityId'
|
||||
DESC 'Id Code'
|
||||
EQUALITY caseIgnoreIA5Match
|
||||
SUBSTR caseIgnoreIA5SubstringsMatch
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256}
|
||||
SINGLE-VALUE)
|
||||
|
||||
# CDG 59 Collectivity
|
||||
objectclass ( Cdg59LDAPObjectClass:1
|
||||
NAME 'cdg59collectivity'
|
||||
DESC 'CDG 59 Collectivity Objectclass'
|
||||
STRUCTURAL
|
||||
SUP organizationalUnit
|
||||
MAY ( cdg59siretCode $ cdg59collectivitySirhCode $ cdg59collectivitySirhLabel $ cn $ mail $ cdg59URL $ cdg59regionCode $ cdg59departementCode $ cdg59arrondissementCode $ cdg59cantonCode $ cdg59inseeCode $ cdg59streetNumber $ cdg59distOffice $ cdg59addressCompl $ cdg59addressMention $ cdg59collectivityId ))
|
||||
|
||||
# CDG 59 Agent
|
||||
objectclass (Cdg59LDAPObjectClass:2
|
||||
NAME 'cdg59agent'
|
||||
DESC 'CDG 59 Agent Objectclass'
|
||||
STRUCTURAL
|
||||
SUP inetOrgPerson
|
||||
MUST ( uid )
|
||||
MAY ( cdg59isAdmin $ cdg59direction $ cdg59isDisabled $ cdg59serviceAccesses $ cdg59agentSirhCode $ cdg59lastConnectionTime $ cdg59lastConnectionDuration ))
|
||||
|
||||
# CDG 59 Service
|
||||
objectclass ( Cdg59LDAPObjectClass:3
|
||||
NAME 'cdg59service'
|
||||
DESC 'CDG 59 Service Objectclass'
|
||||
STRUCTURAL
|
||||
MUST ( cdg59sid )
|
||||
MAY ( cn $ description $ cdg59URL $ cdg59isGlobal $ cdg59metadataURL $ cdg59ssoRelayState ))
|
||||
|
||||
# CDG 59 Service Instance
|
||||
objectclass ( Cdg59LDAPObjectClass:4
|
||||
NAME 'cdg59serviceInstance'
|
||||
DESC 'CDG 59 Service Instance Objectclass'
|
||||
STRUCTURAL
|
||||
MUST ( cdg59siid )
|
||||
MAY ( cdg59serviceType $ cdg59URL $ cdg59metadataURL $ cdg59ssoRelayState ))
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
#!/usr/bin/python
|
||||
from setuptools import setup, find_packages
|
||||
import os
|
||||
|
||||
def get_version():
|
||||
import glob
|
||||
import re
|
||||
import os
|
||||
|
||||
version = None
|
||||
for d in glob.glob('src/*'):
|
||||
if not os.path.isdir(d):
|
||||
continue
|
||||
module_file = os.path.join(d, '__init__.py')
|
||||
if not os.path.exists(module_file):
|
||||
continue
|
||||
for v in re.findall("""__version__ *= *['"](.*)['"]""",
|
||||
open(module_file).read()):
|
||||
assert version is None
|
||||
version = v
|
||||
if version:
|
||||
break
|
||||
assert version is not None
|
||||
if os.path.exists('.git'):
|
||||
import subprocess
|
||||
p = subprocess.Popen(['git','describe','--dirty','--match=v*'],
|
||||
stdout=subprocess.PIPE)
|
||||
result = p.communicate()[0]
|
||||
assert p.returncode == 0, 'git returned non-zero'
|
||||
new_version = result.split()[0][1:]
|
||||
assert new_version.split('-')[0] == version, '__version__ must match the last git annotated tag'
|
||||
version = new_version.replace('-', '.')
|
||||
return version
|
||||
|
||||
README = file(os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
'README')).read()
|
||||
|
||||
setup(name='authentic2-pratic',
|
||||
version=get_version(),
|
||||
license='AGPLv3',
|
||||
description='Authentic2 Pr@tic',
|
||||
long_description=README,
|
||||
author="Entr'ouvert",
|
||||
author_email="info@entrouvert.com",
|
||||
packages=find_packages('src'),
|
||||
package_dir={
|
||||
'': 'src',
|
||||
},
|
||||
package_data={
|
||||
'authentic2_pratic': [
|
||||
'templates/authentic2_pratic/*.html',
|
||||
'static/authentic2_pratic/js/*.js',
|
||||
'static/authentic2_pratic/css/*.css',
|
||||
'static/authentic2_pratic/img/*.png',
|
||||
],
|
||||
},
|
||||
install_requires=[
|
||||
'authentic2',
|
||||
],
|
||||
entry_points={
|
||||
'authentic2.plugin': [
|
||||
'authentic2-pratic = authentic2_pratic:Plugin',
|
||||
],
|
||||
},
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
__version__ = '1.0.0b1'
|
||||
|
||||
class Plugin(object):
|
||||
def get_before_urls(self):
|
||||
from . import urls
|
||||
return urls.urlpatterns
|
||||
|
||||
def get_apps(self):
|
||||
return [__name__]
|
||||
|
||||
def get_authentication_backends(self):
|
||||
return ['authentic2_pratic.backends.PraticBackend']
|
||||
|
||||
def get_auth_frontends(self):
|
||||
return ['authentic2_pratic.auth_frontends.PraticFrontend']
|
|
@ -0,0 +1,22 @@
|
|||
class AppSettings(object):
|
||||
__DEFAULTS = {
|
||||
}
|
||||
|
||||
def __init__(self, prefix):
|
||||
self.prefix = prefix
|
||||
|
||||
def _setting(self, name, dflt):
|
||||
from django.conf import settings
|
||||
return getattr(settings, self.prefix+name, dflt)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name not in self.__DEFAULTS:
|
||||
raise AttributeError(name)
|
||||
return self._setting(name, self.__DEFAULTS[name])
|
||||
|
||||
# Ugly? Guido recommends this himself ...
|
||||
# http://mail.python.org/pipermail/python-ideas/2012-May/014969.html
|
||||
import sys
|
||||
app_settings = AppSettings('A2_PRATIC_')
|
||||
app_settings.__name__ = __name__
|
||||
sys.modules[__name__] = app_settings
|
|
@ -0,0 +1,21 @@
|
|||
from django.utils.translation import gettext_noop
|
||||
from django import forms
|
||||
|
||||
class PraticFrontend(object):
|
||||
def enabled(self):
|
||||
True
|
||||
|
||||
def name(self):
|
||||
return gettext_noop('Pr@tic')
|
||||
|
||||
def id(self):
|
||||
return 'pratic'
|
||||
|
||||
def form(self):
|
||||
return forms.Form
|
||||
|
||||
def post(self, request, form, nonce, next):
|
||||
raise NotImplemented
|
||||
|
||||
def template(self):
|
||||
return 'authentic2_pratic/login.html'
|
|
@ -0,0 +1,8 @@
|
|||
import logging
|
||||
|
||||
class PraticBackend(object):
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger(__name__)
|
||||
|
||||
def authenticate(self, **kwargs):
|
||||
raise NotImplemented
|
|
@ -0,0 +1,11 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from admin_tools.dashboard import modules
|
||||
|
||||
|
||||
def get_admin_modules():
|
||||
'''Show models in authentic2 admin'''
|
||||
model_list = modules.ModelList(_('Pr@tic'),
|
||||
models=('authentic2_pratic.models.*',))
|
||||
return (model_list,)
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
from django import forms
|
||||
|
||||
from . import models
|
||||
|
||||
class BaseForm(forms.ModelForm):
|
||||
required_css_class = 'required'
|
||||
error_css_class = 'error'
|
||||
|
||||
class ServiceForm(BaseForm):
|
||||
class Meta:
|
||||
model = models.Service
|
||||
|
||||
class CollectivityForm(BaseForm):
|
||||
class Meta:
|
||||
model = models.Collectivity
|
||||
|
||||
class ServiceInstanceForm(BaseForm):
|
||||
class Meta:
|
||||
model = models.ServiceInstance
|
||||
exclude = ('collectivity',)
|
||||
|
||||
class AccessForm(BaseForm):
|
||||
def __init__(self, *args, **kwargs):
|
||||
collectivity = kwargs.pop('collectivity')
|
||||
super(AccessForm, self).__init__(*args, **kwargs)
|
||||
self.fields['user'].queryset = self.fields['user'].queryset.filter(collectivity=collectivity)
|
||||
self.fields['service_instance'].queryset = self.fields['service_instance'].queryset.filter(collectivity=collectivity)
|
||||
|
||||
class Meta:
|
||||
model = models.Access
|
||||
|
||||
class UserForm(BaseForm):
|
||||
class Meta:
|
||||
model = models.User
|
||||
fields = ('uid', 'first_name', 'last_name', 'email')
|
|
@ -0,0 +1,296 @@
|
|||
from django.db.models import (Model, TextField, CharField, EmailField,
|
||||
URLField, BooleanField, IntegerField, ForeignKey, SlugField)
|
||||
from django.contrib.auth.models import User as AuthUser
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
class User(AuthUser):
|
||||
# givenName -> first_name
|
||||
# sn -> last_name
|
||||
# userPassword -> password
|
||||
# mail -> email
|
||||
# cdg59isDisabled -> ! active
|
||||
# cdg59lastConnectionTime -> last_login
|
||||
# cn -> get_full_name()
|
||||
# ou -> collectivity
|
||||
# username = uid + '@' + collectivity.slug
|
||||
uid = CharField(
|
||||
verbose_name=_('identifier'),
|
||||
max_length=128)
|
||||
collectivity = ForeignKey(
|
||||
'Collectivity',
|
||||
verbose_name=_('collectivity'))
|
||||
# cdg59isAdmin
|
||||
is_admin = BooleanField(
|
||||
verbose_name=_('is admin'),
|
||||
default=False,
|
||||
blank=True)
|
||||
# cdg59agentSirhCode
|
||||
sirh_code = CharField(
|
||||
verbose_name=_('SIRH Code'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
# cdg59direction
|
||||
direction = CharField(
|
||||
verbose_name=_('direction'),
|
||||
max_length=32,
|
||||
blank=True)
|
||||
# cdg59lastConnectionDuration
|
||||
last_login_duration = IntegerField(
|
||||
verbose_name=_('last connection duration'),
|
||||
default=0,
|
||||
blank=True)
|
||||
# cdg59serviceAccesses -> convert to ACLs
|
||||
# employeeType
|
||||
employee_type = CharField(
|
||||
verbose_name=_('employee type'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# postalAddress
|
||||
postal_address = TextField(
|
||||
verbose_name=_('postal address'),
|
||||
blank=True)
|
||||
# facsimileTelephoneNumber
|
||||
fax = CharField(
|
||||
verbose_name=_('fax'),
|
||||
max_length=32)
|
||||
# mobile
|
||||
mobile = CharField(
|
||||
verbose_name=_('mobile'),
|
||||
max_length=16,
|
||||
blank=True)
|
||||
# telephoneNumber
|
||||
phone = CharField(
|
||||
verbose_name=_('phone'),
|
||||
max_length=32)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('agent')
|
||||
verbose_name_plural = _('agents')
|
||||
# enforce unicity of login by collectivity
|
||||
unique_together = (('uid', 'collectivity'),)
|
||||
|
||||
def clean(self):
|
||||
# prevent collisions between users from multiple collectivities
|
||||
if self.uid and not self.username and self.collectivity:
|
||||
self.username = u'%s@%s' % (self.uid, self.collectivity.slug)
|
||||
super(User, self).clean()
|
||||
|
||||
# Fields to support
|
||||
class Collectivity(Model):
|
||||
# Identifiers
|
||||
# cn = ou
|
||||
name = CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=64,
|
||||
unique=True)
|
||||
slug = SlugField(
|
||||
verbose_name=_('identifier'),
|
||||
max_length=64,
|
||||
unique=True)
|
||||
# cdg59collectivityId
|
||||
collectivity_id = CharField(
|
||||
verbose_name=_('collectivity id'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
# cdg59collectivitySirhCode
|
||||
sirh_code = CharField(
|
||||
verbose_name=_('SIRH Code'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
# cdg59collectivitySirhLabel
|
||||
sirh_label = CharField(
|
||||
verbose_name=_('SIRH Code'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59inseeCode
|
||||
insee_code = CharField(
|
||||
verbose_name=_('INSEE Code'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
# cdg59siretCode
|
||||
siret_code = CharField(
|
||||
verbose_name=_('SIRET Code'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
|
||||
|
||||
# Postal addresse
|
||||
# postalAddress
|
||||
postal_address = TextField(
|
||||
verbose_name=_('postal address'),
|
||||
blank=True)
|
||||
# cdg59streetNumber
|
||||
street_number = CharField(
|
||||
verbose_name=_('street number'),
|
||||
max_length=8,
|
||||
blank=True)
|
||||
# street
|
||||
street = CharField(
|
||||
verbose_name=_('street'),
|
||||
max_length=128,
|
||||
blank=True)
|
||||
# postalCode
|
||||
postal_code = CharField(
|
||||
verbose_name=_('postal code'),
|
||||
max_length=16,
|
||||
blank=True)
|
||||
# cdg59addressCompl
|
||||
address_complementary = CharField(
|
||||
verbose_name=_('complementary address'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59addressMention
|
||||
address_mention = CharField(
|
||||
verbose_name=_('address mention'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59arrondissementCode
|
||||
arrondissement_code = CharField(
|
||||
verbose_name=_('arrondissement code'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59cantonCode
|
||||
canton_code = CharField(
|
||||
verbose_name=_('canton code'),
|
||||
max_length=4,
|
||||
blank=True)
|
||||
# cdg59departementCode
|
||||
departement_code = CharField(
|
||||
verbose_name=_('departement code'),
|
||||
max_length=2,
|
||||
blank=True)
|
||||
# cdg59distOffice
|
||||
dist_office = CharField(
|
||||
verbose_name=_('distribution office'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59regionCode
|
||||
region_code = CharField(
|
||||
verbose_name=_('distribution office'),
|
||||
max_length=4,
|
||||
blank=True)
|
||||
|
||||
|
||||
# Contact
|
||||
# telephoneNumber
|
||||
phone = CharField(
|
||||
verbose_name=_('phone'),
|
||||
max_length=32,
|
||||
blank=True)
|
||||
# facsimileTelephoneNumber
|
||||
fax = CharField(
|
||||
verbose_name=_('fax'),
|
||||
max_length=32,
|
||||
blank=True)
|
||||
# mail
|
||||
email = EmailField(
|
||||
verbose_name=_('email'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
# cdg59URL
|
||||
url = URLField(
|
||||
verbose_name=_('URL'),
|
||||
max_length=128,
|
||||
blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('collectivity')
|
||||
verbose_name_plural = _('collectivities')
|
||||
ordering = ('name',)
|
||||
|
||||
|
||||
class Service(Model):
|
||||
# Services without a collectivity are global
|
||||
# cn
|
||||
name = CharField(
|
||||
verbose_name=_('name'),
|
||||
max_length=32,
|
||||
unique=True)
|
||||
# cdg59sid
|
||||
slug = SlugField(
|
||||
verbose_name=('identifier'),
|
||||
unique=True)
|
||||
is_global = BooleanField(
|
||||
verbose_name=_('is global'),
|
||||
default=False,
|
||||
blank=True)
|
||||
service_url = URLField(
|
||||
verbose_name=_('URL'))
|
||||
metadata_url = URLField(
|
||||
verbose_name=_('SAML Metadata URL'),
|
||||
blank=True)
|
||||
oauth2_url = URLField(
|
||||
verbose_name=_('OAuth2 URL'),
|
||||
blank=True)
|
||||
oauth2_key = CharField(
|
||||
verbose_name=_('OAuth2 Key'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('service')
|
||||
verbose_name_plural = _('services')
|
||||
ordering = ('name',)
|
||||
|
||||
class ServiceInstance(Model):
|
||||
# cdg59sid
|
||||
slug = SlugField(
|
||||
verbose_name=('identifier'))
|
||||
service = ForeignKey(
|
||||
'Service',
|
||||
verbose_name=_('service'))
|
||||
collectivity = ForeignKey(
|
||||
'Collectivity',
|
||||
verbose_name=_('collectivity'))
|
||||
service_url = URLField(
|
||||
verbose_name=_('URL'),
|
||||
blank=True)
|
||||
metadata_url = URLField(
|
||||
verbose_name=_('SAML Metadata URL'),
|
||||
blank=True)
|
||||
oauth2_url = URLField(
|
||||
verbose_name=_('OAuth2 URL'),
|
||||
blank=True)
|
||||
oauth2_key = CharField(
|
||||
verbose_name=_('OAuth2 Key'),
|
||||
max_length=64,
|
||||
blank=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return unicode(self.service)
|
||||
|
||||
def clean(self):
|
||||
if self.collectivity and self.service and self.service.is_global:
|
||||
qs = ServiceInstance.objects.exclude(id=self.id)
|
||||
qs = qs.filter(collectivity=self.collectivity,
|
||||
service=self.service)
|
||||
if qs.exists():
|
||||
raise ValidationError(_('There can be only one instance of a global service by collectivity'))
|
||||
if not self.service.is_global and not self.service_url:
|
||||
raise ValidationError(_('Service URL field is required'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('service instance')
|
||||
verbose_name = _('service instances')
|
||||
unique_together = (('slug', 'service', 'collectivity'),)
|
||||
ordering = ('service__name', 'slug')
|
||||
|
||||
class Access(Model):
|
||||
user = ForeignKey('User',
|
||||
verbose_name=_('user'))
|
||||
service_instance = ForeignKey('ServiceInstance',
|
||||
verbose_name=_('service instance'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('access')
|
||||
verbose_name = _('accesses')
|
||||
unique_together = (('user', 'service_instance'),)
|
||||
ordering = ('user__last_name', 'user__first_name', 'service_instance__service__name')
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from ...models import Attribute, AttributeValue
|
||||
|
||||
from ...decorators import to_list
|
||||
from ...compat import get_user_model
|
||||
|
||||
@to_list
|
||||
def get_instances(ctx):
|
||||
'''
|
||||
Retrieve instances from settings
|
||||
'''
|
||||
return [None]
|
||||
|
||||
@to_list
|
||||
def get_attribute_names(instance, ctx):
|
||||
User = get_user_model()
|
||||
for field in User._meta.fields:
|
||||
name = 'django_user_' + str(field.name)
|
||||
description = field.verbose_name + u' (%s)' % name
|
||||
yield name, description
|
||||
for attribute in Attribute.objects.all():
|
||||
name = 'django_user_' + str(attribute.name)
|
||||
description = attribute.label + u' (%s)' % name
|
||||
yield name, description
|
||||
yield 'django_user_groups', User._meta.get_field_by_name('groups')[0].verbose_name + u' (django_user_groups)'
|
||||
yield 'django_user_group_names', User._meta.get_field_by_name('groups')[0].verbose_name + u' (django_user_group_names)'
|
||||
yield 'django_user_domain', _('User domain') + u' (django_user_domain)'
|
||||
yield 'django_user_identifier', _('User identifier') + u' (django_user_identifier)'
|
||||
|
||||
def get_dependencies(instance, ctx):
|
||||
return ('user',)
|
||||
|
||||
def get_attributes(instance, ctx):
|
||||
user = ctx.get('user')
|
||||
User = get_user_model()
|
||||
if not user or not isinstance(user, User):
|
||||
return ctx
|
||||
for field in User._meta.fields:
|
||||
ctx['django_user_' + str(field.name)] = getattr(user, field.name)
|
||||
for av in AttributeValue.objects.with_owner(user):
|
||||
ctx['django_user_' + str(av.attribute.name)] = av.to_python()
|
||||
ctx['django_user_groups'] = [group for group in user.groups.all()]
|
||||
ctx['django_user_group_names'] = [unicode(group) for group in user.groups.all()]
|
||||
ctx['django_user_domain'] = user.username.rsplit('@', 1)[1] if '@' in user.username else ''
|
||||
ctx['django_user_identifier'] = user.username.rsplit('@', 1)[0] if '@' in user.username else ''
|
||||
return ctx
|
|
@ -0,0 +1,68 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
import django_tables2 as tables
|
||||
|
||||
from . import models
|
||||
|
||||
class ServiceTable(tables.Table):
|
||||
name = tables.TemplateColumn(
|
||||
'<a rel="popup" href="{% url "a2-pratic-service-edit" pk=record.pk %}">{{ record.name }}</a>',
|
||||
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'))
|
||||
|
||||
class Meta:
|
||||
model = models.Service
|
||||
attrs = {'class': 'main', 'id': 'services-table'}
|
||||
fields = ('name', 'slug', 'is_global', 'service_url', 'delete')
|
||||
|
||||
class CollectivityTable(tables.Table):
|
||||
name = tables.TemplateColumn(
|
||||
'<a href="{% url "a2-pratic-collectivity-edit" collectivity_pk=record.pk %}">{{ record.name }}</a>',
|
||||
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'))
|
||||
|
||||
class Meta:
|
||||
model = models.Collectivity
|
||||
attrs = {'class': 'main', 'id': 'collectivities-table'}
|
||||
fields = ('name', 'insee_code', 'postal_code', 'delete')
|
||||
|
||||
class UserTable(tables.Table):
|
||||
uid = tables.TemplateColumn(
|
||||
'<a rel="popup" href="{% url "a2-pratic-user-edit" collectivity_pk=record.collectivity.pk pk=record.pk %}">{{ record.uid }}</a>',
|
||||
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'))
|
||||
|
||||
class Meta:
|
||||
model = models.User
|
||||
attrs = {'class': 'main', 'id': 'users-table'}
|
||||
fields = ('first_name', 'last_name', 'uid', 'is_admin', 'is_active', 'delete')
|
||||
|
||||
class ServiceInstanceTable(tables.Table):
|
||||
slug = tables.TemplateColumn(
|
||||
'<a rel="popup" href="{% url "a2-pratic-service-instance-edit" collectivity_pk=record.collectivity.pk pk=record.pk %}">{{ record.slug}}</a>',
|
||||
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'))
|
||||
|
||||
class Meta:
|
||||
model = models.User
|
||||
attrs = {'class': 'main', 'id': 'users-table'}
|
||||
fields = ('slug', 'service_url')
|
||||
|
||||
class AccessTable(tables.Table):
|
||||
last_name = tables.TemplateColumn('{{ record.user.last_name}}',
|
||||
verbose_name=_('Last name'))
|
||||
first_name = tables.TemplateColumn('{{ record.user.first_name }}',
|
||||
verbose_name=_('First name'))
|
||||
|
||||
class Meta:
|
||||
model = models.Access
|
||||
attrs = {'class': 'main', 'id': 'accesses-table'}
|
||||
fields = ('last_name', 'first_name', 'service_instance')
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "authentic2_pratic/collectivity_sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page-title %}{{ block.super }} - {% trans "Accesses management" %}{% endblock %}
|
||||
|
||||
{% block page_title %}{{ block.super }} {% trans "Accesses management" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{{ block.super }}
|
||||
<a rel="popup" href="{% url "a2-pratic-access-add" collectivity_pk=collectivity.pk %}" id="add-user-btn">{% trans "Add access" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} accesses{% plural %}{{ count }} access{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% render_table table "authentic2_pratic/table.html" %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,35 @@
|
|||
{% extends "gadjo/base.html" %}
|
||||
{% load i18n staticfiles %}
|
||||
|
||||
{% block page-title %}{% trans "Management" %}{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link rel="stylesheet" type="text/css" media="all" href="{% static "authentic2/manager/css/style.css" %}"/>
|
||||
{% endblock %}
|
||||
|
||||
{% block extrascripts %}
|
||||
{% if debug %}
|
||||
<script src="{% static "jquery/js/jquery.form.js" %}"></script>
|
||||
{% else %}
|
||||
<script src="{% static "jquery/js/jquery.form.min.js" %}"></script>
|
||||
{% endif %}
|
||||
<script type="text/javascript" src="{% static "authentic2/js/purl.js" %}"></script>
|
||||
<script type="text/javascript" src="{% static "authentic2/manager/js/manager.js" %}"></script>
|
||||
<script type="text/javascript" src="/static/js/select2.js"></script>
|
||||
<script type="text/javascript" src="/static/js/heavy_data.js"></script>
|
||||
<script>
|
||||
window.csrf_token = '{{ csrf_token }}';
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% block site-url %}/{% endblock %}
|
||||
{% block site-title %}{% trans "Management" %}{% endblock %}
|
||||
|
||||
{% block logout-url %}{% url "auth_logout" %}{% endblock %}
|
||||
|
||||
{% block homepage-url %}{% url "a2-pratic-homepage" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% block page_title %}{% endblock %}</h2>
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page-title %}{{ block.super }} - {% trans "Collectivities management" %}{% endblock %}
|
||||
|
||||
{% block page_title %}{% trans "Collectivities management" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{{ block.super }}
|
||||
<a rel="popup" href="{% url "a2-pratic-collectivity-add" %}" id="add-user-btn">{% trans "Add collectivity" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} collectivities{% plural %}{{ count }} collectivity{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% render_table table "authentic2_pratic/table.html" %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,54 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block messages %}
|
||||
{% endblock %}
|
||||
|
||||
{% block page_title %}
|
||||
<a href="{% url "a2-pratic-collectivities" %}">{% trans "Collectivities management" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p><a href="users/">{% trans "Users management" %}</a></p>
|
||||
<p><a href="services/">{% trans "Service instances management" %}</a></p>
|
||||
<p><a href="accesses/">{% trans "Accesses management" %}</a></p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="content">
|
||||
{% 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 %}
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
|
||||
{{ message }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button>{% if action %}{{ action }}{% else %}{% trans "Save" %}{% endif %}</button>
|
||||
<a class="cancel" href="..">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,8 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page_title %}
|
||||
<a href="{% url "a2-pratic-collectivity-edit" collectivity_pk=collectivity.pk %}">
|
||||
{{ collectivity }}
|
||||
</a>
|
||||
{% endblock %}
|
|
@ -0,0 +1,33 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block messages %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="content">
|
||||
{% if title %}
|
||||
<div id="appbar"><h2>{{ title }}</h2></div>
|
||||
{% endif %}
|
||||
<form method="post">
|
||||
<div class="form-inner-container">
|
||||
{% if messages %}
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
|
||||
{{ message }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
<p>{% blocktrans %}Do you really want to delete « {{ object }} » ?{% endblocktrans %}</p>
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button>{% if action %}{{ action }}{% else %}{% trans "Delete" %}{% endif %}</button>
|
||||
<a class="cancel" href="..">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,44 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block messages %}
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
<div class="content">
|
||||
{% 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 %}
|
||||
<ul class="messages">
|
||||
{% for message in messages %}
|
||||
<li{% if message.tags %} class="{{ message.tags }}"{% endif %}>
|
||||
{{ message }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
<div class="buttons">
|
||||
<button>{% if action %}{{ action }}{% else %}{% trans "Save" %}{% endif %}</button>
|
||||
<a class="cancel" href="..">{% trans "Cancel" %}</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,24 @@
|
|||
{% extends "authentic2_pratic/base.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block beforecontent %}
|
||||
{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
<h2>{% trans "Welcome" %}</h2>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div id="content">
|
||||
<div id="user-info">
|
||||
{{ user.get_full_name }}
|
||||
(<a href="{% url "auth_password_change" %}">{% trans "Password change" %}</a>)
|
||||
</div>
|
||||
|
||||
<ul class="apps">
|
||||
<li id="collectivities"><a href="{% url "a2-pratic-collectivities" %}">{% trans "Collectivities" %}</a></li>
|
||||
<li id="services"><a href="{% url "a2-pratic-services" %}">{% trans "Services" %}</a></li>
|
||||
</ul>
|
||||
<br style="clear: both;"/>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "authentic2_pratic/collectivity_sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page-title %}{{ block.super }} - {% trans "Service instances management" %}{% endblock %}
|
||||
|
||||
{% block page_title %}{{ block.super }}{% trans "Service instances management" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{{ block.super }}
|
||||
<a rel="popup" href="{% url "a2-pratic-service-instance-add" collectivity_pk=collectivity.pk %}" id="add-user-btn">{% trans "Add service-instance" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} services instances{% plural %}{{ count }} service instance{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% render_table table "authentic2_pratic/table.html" %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
|||
{% extends "authentic2_pratic/sidebar.html" %}
|
||||
{% load i18n staticfiles django_tables2 %}
|
||||
|
||||
{% block page-title %}{{ block.super }} - {% trans "Services management" %}{% endblock %}
|
||||
|
||||
{% block page_title %}{% trans "Services management" %}{% endblock %}
|
||||
|
||||
{% block appbar %}
|
||||
{{ block.super }}
|
||||
<a rel="popup" href="{% url "a2-pratic-service-add" %}" id="add-user-btn">{% trans "Add service" %}</a>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} services{% plural %}{{ count }} service{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% render_table table "authentic2_pratic/table.html" %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "authentic2_pratic/base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div id="sidebar">
|
||||
{% block sidebar %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
<div class="content">
|
||||
{% block main %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,58 @@
|
|||
{% extends "django_tables2/table.html" %}
|
||||
|
||||
{% load django_tables2 %}
|
||||
|
||||
{% block table.thead %}
|
||||
<thead>
|
||||
<tr>
|
||||
{% for column in table.columns %}
|
||||
{% if column.orderable %}
|
||||
<th {{ column.attrs.th.as_html }}><a href="{% querystring table.prefixed_order_by_field=column.order_by_alias.next %}">{{ column.header }}</a></th>
|
||||
{% else %}
|
||||
<th {{ column.attrs.th.as_html }}>{{ column.header }}</th>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% block table.head.last.column %}
|
||||
{% endblock %}
|
||||
</tr>
|
||||
</thead>
|
||||
{% endblock table.thead %}
|
||||
|
||||
{% block table.tbody.row %}
|
||||
<tr data-ref="{{ row.record.id }}" class="{{ forloop.counter|divisibleby:2|yesno:"even,odd" }}"> {# avoid cycle for Django 1.2-1.6 compatibility #}
|
||||
{% for column, cell in row.items %}
|
||||
<td {{ column.attrs.td.as_html }}>{% if column.localize == None %}{{ cell }}{% else %}{% if column.localize %}{{ cell|localize }}{% else %}{{ cell|unlocalize }}{% endif %}{% endif %}</td>
|
||||
{% endfor %}
|
||||
{% block table.tbody.last.column %}
|
||||
{% endblock %}
|
||||
</tr>
|
||||
{% endblock table.tbody.row %}
|
||||
|
||||
{% block pagination %}
|
||||
<p class="paginator">
|
||||
{% if table.page.number > 1 %}
|
||||
{% if table.page.previous_page_number != 1 %}
|
||||
<a href="{% querystring table.prefixed_page_field=1 %}">1</a>
|
||||
...
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if table.page.has_previous %}
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.previous_page_number %}">{{ table.page.previous_page_number }}</a>
|
||||
{% endif %}
|
||||
|
||||
<span class="this-page">{{ table.page.number }}</span>
|
||||
|
||||
{% if table.page.has_next %}
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.next_page_number %}">{{ table.page.next_page_number }}</a>
|
||||
{% endif %}
|
||||
{% if table.page.number != table.page.paginator.num_pages %}
|
||||
{% if table.page.paginator.num_pages > 1 %}
|
||||
{% if table.page.next_page_number != table.page.paginator.num_pages %}
|
||||
...
|
||||
<a href="{% querystring table.prefixed_page_field=table.page.paginator.num_pages %}">{{ table.page.paginator.num_pages }}</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% endblock %}
|
|
@ -0,0 +1,19 @@
|
|||
{% 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 "Users 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>
|
||||
{% endblock %}
|
||||
|
||||
{% block sidebar %}
|
||||
<p>{% blocktrans count count=object_list.count %}{{ count }} users{% plural %}{{ count }} user{% endblocktrans %}</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% render_table table "authentic2_pratic/table.html" %}
|
||||
{% endblock %}
|
|
@ -0,0 +1,61 @@
|
|||
from django.conf.urls import patterns, url, include
|
||||
|
||||
from . import views
|
||||
|
||||
access_urlpatterns = patterns('',
|
||||
url('^$',
|
||||
views.access_edit,
|
||||
name='a2-pratic-access-edit'),
|
||||
url('^delete/$',
|
||||
views.access_delete,
|
||||
name='a2-pratic-access-delete'))
|
||||
|
||||
service_instance_urlpatterns = patterns('',
|
||||
url('^$',
|
||||
views.service_instance_edit,
|
||||
name='a2-pratic-service-instance-edit'),
|
||||
url('^delete/$',
|
||||
views.service_instance_delete,
|
||||
name='a2-pratic-service-instance-delete'))
|
||||
|
||||
user_urlpatterns = patterns('',
|
||||
url('^$', views.user_edit, name='a2-pratic-user-edit'),
|
||||
url('^delete/$', views.user_delete, name='a2-pratic-user-delete'))
|
||||
|
||||
collectivity_urlpatterns = patterns('',
|
||||
url('^$', views.collectivity_edit, name='a2-pratic-collectivity-edit'),
|
||||
url('^delete/$', views.collectivity_delete, name='a2-pratic-collectivity-delete'),
|
||||
url('^users/$', views.collectivity_users, name='a2-pratic-users'),
|
||||
url('^users/add/$',
|
||||
views.user_add,
|
||||
name='a2-pratic-user-add'),
|
||||
url('^users/(?P<pk>\d+)/',
|
||||
include(user_urlpatterns)),
|
||||
url('^services/$',
|
||||
views.collectivity_service_instances,
|
||||
name='a2-pratic-service-instances'),
|
||||
url('^services/add/$',
|
||||
views.service_instance_add,
|
||||
name='a2-pratic-service-instance-add'),
|
||||
url('^services/(?P<pk>\d+)/',
|
||||
include(service_instance_urlpatterns)),
|
||||
url('^accesses/$',
|
||||
views.collectivity_accesses,
|
||||
name='a2-pratic-accesses'),
|
||||
url('^accesses/add/$',
|
||||
views.access_add,
|
||||
name='a2-pratic-access-add'),
|
||||
url('^accesses/(?P<pk>\d+)/$',
|
||||
include(access_urlpatterns)),
|
||||
)
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url('^manage/$', views.homepage, name='a2-pratic-homepage'),
|
||||
url('^manage/services/$', views.services, name='a2-pratic-services'),
|
||||
url('^manage/services/add/$', views.service_add, name='a2-pratic-service-add'),
|
||||
url('^manage/services/(?P<pk>\d+)/delete/$', views.service_delete, name='a2-pratic-service-delete'),
|
||||
url('^manage/services/(?P<pk>\d+)/$', views.service_edit, name='a2-pratic-service-edit'),
|
||||
url('^manage/collectivities/$', views.collectivities, name='a2-pratic-collectivities'),
|
||||
url('^manage/collectivities/add/$', views.collectivity_add, name='a2-pratic-collectivity-add'),
|
||||
url('^manage/collectivities/(?P<collectivity_pk>\d+)/', include(collectivity_urlpatterns)),
|
||||
)
|
|
@ -0,0 +1,239 @@
|
|||
import logging
|
||||
from django.contrib.auth.decorators import login_required, user_passes_test
|
||||
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.views.generic import (TemplateView, FormView, UpdateView,
|
||||
CreateView, DeleteView, View, ListView)
|
||||
from django_tables2 import SingleTableView
|
||||
|
||||
from authentic2.manager.views import (AjaxFormViewMixin,
|
||||
ActionMixin, OtherActionsMixin, TitleMixin, Action, UserEditView)
|
||||
|
||||
from . import models, tables, forms
|
||||
|
||||
def is_pratic_admin(user):
|
||||
if user.is_superuser:
|
||||
return True
|
||||
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)
|
||||
|
||||
def action_delete(self, request, *args, **kwargs):
|
||||
self.object.delete()
|
||||
return HttpResponseRedirect('.')
|
||||
|
||||
class HomepageView(TemplateView):
|
||||
template_name = 'authentic2_pratic/homepage.html'
|
||||
|
||||
# Services
|
||||
|
||||
class ServicesView(SingleTableView):
|
||||
template_name = 'authentic2_pratic/services.html'
|
||||
model = models.Service
|
||||
table_class = tables.ServiceTable
|
||||
|
||||
class ServiceAddView(TitleMixin, ActionMixin, AjaxFormViewMixin, CreateView):
|
||||
model = models.Service
|
||||
form_class = forms.ServiceForm
|
||||
title = _('Add service')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
|
||||
class ServiceView(DeleteActionMixin, TitleMixin, OtherActionsMixin,
|
||||
AjaxFormViewMixin, UpdateView):
|
||||
model = models.Service
|
||||
title = _('Edit service')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
form_class = forms.ServiceForm
|
||||
|
||||
class ServiceDeleteView(TitleMixin, AjaxFormViewMixin, DeleteView):
|
||||
model = models.Service
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete service')
|
||||
success_url = 'a2-pratic-services'
|
||||
|
||||
# Collectivities
|
||||
class CollectivitiesView(SingleTableView):
|
||||
template_name = 'authentic2_pratic/collectivities.html'
|
||||
model = models.Collectivity
|
||||
table_class = tables.CollectivityTable
|
||||
|
||||
class CollectivityAddView(TitleMixin, ActionMixin, AjaxFormViewMixin, CreateView):
|
||||
model = models.Collectivity
|
||||
title = _('Add collectivity')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
|
||||
class CollectivityView(DeleteActionMixin, TitleMixin, OtherActionsMixin,
|
||||
AjaxFormViewMixin, UpdateView):
|
||||
model = models.Collectivity
|
||||
title = _('Edit collectivity')
|
||||
template_name = 'authentic2_pratic/collectivity_edit.html'
|
||||
form_class = forms.CollectivityForm
|
||||
pk_url_kwarg = 'collectivity_pk'
|
||||
|
||||
class CollectivityDeleteView(TitleMixin, AjaxFormViewMixin, DeleteView):
|
||||
model = models.Service
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete collectivity')
|
||||
success_url = 'a2-pratic-collectivities'
|
||||
pk_url_kwarg = 'collectivity_pk'
|
||||
|
||||
class CollectivityMixin(object):
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
self.collectivity = get_object_or_404(models.Collectivity,
|
||||
pk=kwargs['collectivity_pk'])
|
||||
return super(CollectivityMixin, self).dispatch(request, *args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super(CollectivityMixin, self).get_context_data(**kwargs)
|
||||
ctx['collectivity'] = self.collectivity
|
||||
return ctx
|
||||
|
||||
class CollectivityChildMixin(CollectivityMixin):
|
||||
def get_queryset(self):
|
||||
qs = super(CollectivityMixin, self).get_queryset()
|
||||
return qs.filter(collectivity=self.collectivity)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(CollectivityMixin, self).get_form_kwargs()
|
||||
if not kwargs.get('instance'):
|
||||
kwargs['instance'] = self.model(collectivity=self.collectivity)
|
||||
return kwargs
|
||||
|
||||
# users
|
||||
class UsersView(CollectivityChildMixin, SingleTableView):
|
||||
template_name = 'authentic2_pratic/users.html'
|
||||
model = models.User
|
||||
table_class = tables.UserTable
|
||||
|
||||
class UserAddView(CollectivityChildMixin, TitleMixin, ActionMixin,
|
||||
AjaxFormViewMixin, CreateView):
|
||||
model = models.User
|
||||
title = _('Add user')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
form_class = forms.UserForm
|
||||
|
||||
class UserView(CollectivityChildMixin, UserEditView):
|
||||
model = models.User
|
||||
title = _('Edit user')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
form_class = forms.UserForm
|
||||
|
||||
class UserDeleteView(CollectivityChildMixin, TitleMixin, AjaxFormViewMixin,
|
||||
DeleteView):
|
||||
model = models.Service
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete user')
|
||||
success_url = 'a2-pratic-users'
|
||||
|
||||
# service instances
|
||||
class ServiceInstancesView(CollectivityChildMixin, SingleTableView):
|
||||
template_name = 'authentic2_pratic/service_instances.html'
|
||||
model = models.ServiceInstance
|
||||
table_class = tables.ServiceInstanceTable
|
||||
|
||||
class ServiceInstanceAddView(CollectivityChildMixin, TitleMixin, ActionMixin,
|
||||
AjaxFormViewMixin, CreateView):
|
||||
model = models.ServiceInstance
|
||||
title = _('Add service instance')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
form_class = forms.ServiceInstanceForm
|
||||
|
||||
class ServiceInstanceView(CollectivityChildMixin, DeleteActionMixin, TitleMixin,
|
||||
OtherActionsMixin, AjaxFormViewMixin, UpdateView):
|
||||
model = models.ServiceInstance
|
||||
title = _('Edit service instance')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
form_class = forms.ServiceInstanceForm
|
||||
|
||||
class ServiceInstanceDeleteView(CollectivityChildMixin, TitleMixin,
|
||||
AjaxFormViewMixin, DeleteView):
|
||||
model = models.ServiceInstance
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete service instance')
|
||||
success_url = 'a2-pratic-users'
|
||||
|
||||
# accesses
|
||||
class AccessMixin(object):
|
||||
def get_queryset(self):
|
||||
qs = self.model.objects.all()
|
||||
return qs.filter(user__collectivity=self.collectivity,
|
||||
service_instance__collectivity=self.collectivity)
|
||||
|
||||
def get_form_kwargs(self):
|
||||
kwargs = super(CollectivityMixin, self).get_form_kwargs()
|
||||
kwargs['collectivity'] = self.collectivity
|
||||
return kwargs
|
||||
|
||||
class AccessesView(AccessMixin, CollectivityMixin, SingleTableView):
|
||||
template_name = 'authentic2_pratic/accesses.html'
|
||||
model = models.Access
|
||||
table_class = tables.AccessTable
|
||||
|
||||
class AccessAddView(AccessMixin, CollectivityMixin, TitleMixin, ActionMixin,
|
||||
AjaxFormViewMixin, CreateView):
|
||||
model = models.Access
|
||||
title = _('Add service instance')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
action = _('Add')
|
||||
form_class = forms.AccessForm
|
||||
|
||||
class AccessView(AccessMixin, CollectivityMixin, DeleteActionMixin, TitleMixin,
|
||||
OtherActionsMixin, AjaxFormViewMixin, UpdateView):
|
||||
model = models.Access
|
||||
title = _('Edit service instance')
|
||||
template_name = 'authentic2_pratic/form.html'
|
||||
form_class = forms.AccessForm
|
||||
|
||||
class AccessDeleteView(AccessMixin, CollectivityMixin, TitleMixin,
|
||||
AjaxFormViewMixin, DeleteView):
|
||||
model = models.Access
|
||||
template_name = 'authentic2_pratic/delete.html'
|
||||
title = _('Delete service instance')
|
||||
success_url = 'a2-pratic-users'
|
||||
|
||||
# general views
|
||||
homepage = pratic_admin(HomepageView.as_view())
|
||||
|
||||
# services
|
||||
services = pratic_admin(ServicesView.as_view())
|
||||
service_edit = pratic_admin(ServiceView.as_view())
|
||||
service_add = pratic_admin(ServiceAddView.as_view())
|
||||
service_delete = pratic_admin(ServiceDeleteView.as_view())
|
||||
|
||||
# collectivities
|
||||
collectivities = pratic_admin(CollectivitiesView.as_view())
|
||||
collectivity_edit = pratic_admin(CollectivityView.as_view())
|
||||
collectivity_add = pratic_admin(CollectivityAddView.as_view())
|
||||
collectivity_delete = pratic_admin(CollectivityDeleteView.as_view())
|
||||
|
||||
# collectivity users
|
||||
collectivity_users = pratic_admin(UsersView.as_view())
|
||||
user_add = pratic_admin(UserAddView.as_view())
|
||||
user_edit = pratic_admin(UserView.as_view())
|
||||
user_delete = pratic_admin(UserDeleteView.as_view())
|
||||
|
||||
# service instances
|
||||
collectivity_service_instances = pratic_admin(ServiceInstancesView.as_view())
|
||||
service_instance_add = pratic_admin(ServiceInstanceAddView.as_view())
|
||||
service_instance_edit = pratic_admin(ServiceInstanceView.as_view())
|
||||
service_instance_delete = pratic_admin(ServiceInstanceDeleteView.as_view())
|
||||
|
||||
# accesses
|
||||
collectivity_accesses = pratic_admin(AccessesView.as_view())
|
||||
access_add = pratic_admin(AccessAddView.as_view())
|
||||
access_edit = pratic_admin(AccessView.as_view())
|
||||
access_delete = pratic_admin(AccessDeleteView.as_view())
|
||||
|
Reference in New Issue