apps: déplacement du AppConfig

This commit is contained in:
Benjamin Dauvergne 2017-07-12 13:02:09 +02:00
parent e8886498a6
commit f894cb2b3c
3 changed files with 367 additions and 330 deletions

View File

@ -16,310 +16,7 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import django.apps
class AppConfig(django.apps.AppConfig):
name = 'authentic2_cut'
def post_migrate(self, **kwargs):
# create custom operations
from django_rbac.models import Operation
from django_rbac.utils import get_operation
FC_MANAGE_OP = Operation(name=u'Gérer France Connect',
slug='fc_manage')
get_operation(FC_MANAGE_OP)
def ready(self):
from django.db.models.signals import post_migrate, post_save
from django_rbac.utils import get_ou_model
post_migrate.connect(
self.post_migrate,
sender=self)
post_save.connect(
self.ou_post_save,
sender=get_ou_model())
def ou_post_save(self, sender, instance, raw, created, **kwargs):
from .utils import update_roles
update_roles()
def a2_hook_manager_other_actions(self, model=None, **kwargs):
'''Retourne des actions utilisateurs pour la gestion France Connect'''
from django.contrib.auth import get_user_model
from .actions import FranceConnect
if issubclass(model, get_user_model()):
return [FranceConnect]
return []
def a2_hook_manager_user_data(self, view, user):
'''Retourne des objets pour afficher la fédération France Connect'''
from .user_datas import FranceConnectUserData, ValidationUserData
user_datas = []
if view.__class__.__name__ == 'UserDetailView':
user_datas.append(
FranceConnectUserData(user, view.request),
)
if user.attributes.validated:
user_datas.append(
ValidationUserData(user)
)
return user_datas
def a2_hook_manager_modify_form(self, view, form):
from django.forms.widgets import DateTimeInput, HiddenInput
from authentic2.passwords import generate_password
from . import models
if view.__class__.__name__ == 'UserAddView':
# Les usagers CUT n'ont pas d'identifiant
ou = getattr(form, 'ou', None)
if ou:
password = generate_password()
form.fields['password1'].initial = password
form.fields['password1'].widget = HiddenInput()
form.fields['password2'].initial = password
form.fields['password2'].widget = HiddenInput()
if ou.slug == 'usagers':
del form.fields['username']
for field_name in ['is_superuser', 'validated',
'validation_context', 'validation_date']:
if field_name in form.fields:
del form.fields[field_name]
form.fields['generate_password'].initial = False
form.fields['generate_password'].widget = HiddenInput()
form.fields['reset_password_at_next_login'].initial = False
form.fields['reset_password_at_next_login'].widget = HiddenInput()
form.fields['send_mail'].initial = False
form.fields['send_mail'].widget = HiddenInput()
form.fields['send_password_reset'].initial = True
form.fields['send_password_reset'].widget = HiddenInput()
else:
for field_name in form.fields:
if field_name not in ['username',
'first_name',
'last_name',
'email',
'generate_password']:
del form.fields[field_name]
form.fields['email'].required = True
form.fields['generate_password'].initial = True
form.fields['generate_password'].widget.attrs = {'readonly': ''}
form.fields['send_password_reset'].initial = True
form.fields['send_password_reset'].widget = HiddenInput()
old_save = form.save
def new_save(*args, **kwargs):
response = old_save(*args, **kwargs)
models.Journal.objects.create(
actor=form.request.user,
subject=form.instance,
message='création du compte')
return response
form.save = new_save
if view.__class__.__name__ == 'UserEditView':
# Les usagers CUT n'ont pas d'identifiant
if form.instance.ou:
if form.instance.ou.slug == 'usagers':
form.fields['email'].required = True
del form.fields['username']
for field_name in ['password1', 'password2', 'is_superuser', 'validated',
'validation_context', 'validation_date']:
if field_name in form.fields:
del form.fields[field_name]
else:
for field_name in form.fields:
if field_name not in ['username',
'first_name',
'last_name',
'email',
'is_superuser',
'generate_password']:
del form.fields[field_name]
form.fields['email'].required = True
old_save = form.save
def new_save(*args, **kwargs):
response = old_save(*args, **kwargs)
models.Journal.objects.create(
actor=form.request.user,
subject=form.instance,
message='modification des données')
return response
form.save = new_save
# Si un compte est validé, on interdit la modification des attributs coeurs
if form.instance.attributes.validated:
for field_name in form.fields:
if field_name in ['first_name',
'last_name',
'birthcountry_insee',
'birthplace_insee',
'birthcountry',
'birthplace',
'gender', 'title',
'birthdate']:
# del form.fields[field_name]
field = form.fields[field_name]
field.required = False
if field_name == 'birthdate':
field.widget = DateTimeInput(attrs={'readonly': ''})
attrs = field.widget.attrs or {}
attrs['disabled'] = ''
attrs['title'] = u'Champ validé'
field.widget.attrs = attrs
def new_clean(self, field_name):
def clean():
self.instance.refresh_from_db()
if hasattr(self.instance, field_name):
return getattr(self.instance, field_name)
else:
return getattr(self.instance.attributes, field_name)
return clean
setattr(form, 'clean_' + field_name, new_clean(form, field_name))
if field_name in ['generate_password']:
del form.fields[field_name]
if view.__class__.__name__ == 'UserDetailView':
if form.instance.ou:
if form.instance.ou.slug == 'usagers':
for field_name in ['username', 'is_superuser', 'validated',
'validation_context', 'validation_date']:
if field_name in form.fields:
del form.fields[field_name]
else:
for field_name in form.fields:
if field_name not in ['username', 'first_name', 'last_name', 'email']:
del form.fields[field_name]
if view.__class__.__name__ in ['OrganizationalUnitEditView', 'OrganizationalUnitAddView']:
del form.fields['default']
del form.fields['email_is_unique']
del form.fields['username_is_unique']
def a2_hook_manager_modify_table(self, view, table):
import django_tables2 as tables
if view.__class__.__name__ == 'UsersView':
ou = view.search_form.cleaned_data['ou']
sequence = list(table.sequence)
if ou and ou.slug == 'usagers':
for column_name in ['username', 'link']:
if column_name in table.base_columns:
del table.base_columns[column_name]
if column_name in sequence:
sequence.remove(column_name)
sequence.remove('email')
sequence.insert(2, 'email')
table.base_columns['preferred_username'] = tables.Column(
accessor='attributes.preferred_username', verbose_name=u'Nom d\'usage')
sequence.insert(2, 'preferred_username')
table.base_columns['validated'] = tables.BooleanColumn(
accessor='attributes.validated', verbose_name=u'Validé')
sequence += ['validated']
else:
del table.base_columns['link']
sequence.remove('link')
table.columns = tables.columns.BoundColumns(table)
table.sequence = sequence
return table
def a2_hook_api_modify_serializer(self, view, original_serializer):
from rest_framework import serializers
if hasattr(original_serializer, 'child'):
serializer = original_serializer.child
else:
serializer = original_serializer
if view.__class__.__name__ == 'UsersAPI':
del serializer.fields['id']
del serializer.fields['uuid']
del serializer.fields['is_superuser']
del serializer.fields['is_staff']
del serializer.fields['password']
serializer.fields['ou'].write_only = True
serializer.fields['ou'].read_only = True
del serializer.fields['username']
del serializer.fields['last_login']
def get_gender(obj):
title = obj.attributes.title
return {'Monsieur': 'male', 'Madame': 'female'}.get(title)
serializer.get_gender = get_gender
serializer.fields['gender'] = serializers.SerializerMethodField()
serializer.fields['sub'] = serializers.UUIDField(read_only=True, source='uuid',
label='IDCut')
serializer.fields['given_name'] = serializers.CharField(read_only=True,
source='first_name')
serializer.fields['family_name'] = serializers.CharField(read_only=True,
source='last_name')
serializer.fields['email_verified'].read_only = True
def a2_hook_modify_context_data(self, view, context):
from .custom_settings import CORE_ATTRIBUTES, CROWN_ATTRIBUTES
if view.__class__.__name__ == 'ProfileView':
context['cut_core_filled'] = all(getattr(view.request.user.attributes, a, None) for a in
CORE_ATTRIBUTES)
context['cut_crown_filled'] = any(getattr(view.request.user.attributes, a, None) for a
in CROWN_ATTRIBUTES)
def a2_hook_manager_modify_other_actions(self, view, other_actions):
from authentic2.manager.views import Action
class CUTValidate(Action):
name = 'cut-validate'
title = 'Valider le compte'
permission = 'custom_user.cut_validate_user'
url_name = 'cut-manager-user-edit-core'
popup = False
def display(self, user, request):
if user.ou and user.ou.slug != 'usagers':
return False
if user.attributes.validated and user.attributes.validation_context == 'fc':
return False
if user.attributes.validated:
self.title = u'Modifier les données coeur'
self.user = user
return super(CUTValidate, self).display(user, request)
class CUTJournalActions(Action):
name = 'cut-journal-actions'
title = 'Journal des actions'
permission = 'custom_user.view_user'
url_name = 'cut-manager-user-actions-journal'
popup = False
def display(self, user, request):
if user.ou and user.ou.slug == 'usagers':
return False
return super(CUTJournalActions, self).display(user, request)
class CUTJournalModifications(Action):
name = 'cut-journal-modifications'
title = 'Journal des modifications'
permission = 'custom_user.view_user'
url_name = 'cut-manager-user-modifications-journal'
popup = False
if view.__class__.__name__ == 'UserDetailView':
other_actions.append(CUTValidate())
other_actions.append(CUTJournalActions())
other_actions.append(CUTJournalModifications())
default_app_config = 'authentic2_cut.AppConfig'
default_app_config = 'authentic2_cut.apps.AppConfig'
class Plugin(object):

366
src/authentic2_cut/apps.py Normal file
View File

@ -0,0 +1,366 @@
# -*- coding: utf-8 -*-
#
# authentic2_cut - Authentic2 plugin for CUT
# Copyright (C) 2016 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import django.apps
class AppConfig(django.apps.AppConfig):
name = 'authentic2_cut'
def post_migrate(self, **kwargs):
# create custom operations
from django_rbac.models import Operation
from django_rbac.utils import get_operation
FC_MANAGE_OP = Operation(name=u'Gérer France Connect',
slug='fc_manage')
get_operation(FC_MANAGE_OP)
def ready(self):
from django.db.models.signals import post_migrate, post_save
from django_rbac.utils import get_ou_model
post_migrate.connect(
self.post_migrate,
sender=self)
post_save.connect(
self.ou_post_save,
sender=get_ou_model())
def ou_post_save(self, sender, instance, raw, created, **kwargs):
from .utils import update_roles
update_roles()
def a2_hook_manager_other_actions(self, model=None, **kwargs):
'''Retourne des actions utilisateurs pour la gestion France Connect'''
from django.contrib.auth import get_user_model
from .actions import FranceConnect
if issubclass(model, get_user_model()):
return [FranceConnect]
return []
def a2_hook_manager_user_data(self, view, user):
'''Retourne des objets pour afficher la fédération France Connect'''
from .user_datas import FranceConnectUserData, ValidationUserData
user_datas = []
if view.__class__.__name__ == 'UserDetailView':
user_datas.append(
FranceConnectUserData(user, view.request),
)
if user.attributes.validated:
user_datas.append(
ValidationUserData(user)
)
return user_datas
def a2_hook_manager_modify_form(self, view, form):
from django.forms.widgets import DateTimeInput, HiddenInput
from authentic2.passwords import generate_password
from . import models
if view.__class__.__name__ == 'UserAddView':
# Les usagers CUT n'ont pas d'identifiant
ou = getattr(form, 'ou', None)
if ou:
password = generate_password()
form.fields['password1'].initial = password
form.fields['password1'].widget = HiddenInput()
form.fields['password2'].initial = password
form.fields['password2'].widget = HiddenInput()
if ou.slug == 'usagers':
del form.fields['username']
for field_name in ['is_superuser', 'validated',
'validation_context', 'validation_date']:
if field_name in form.fields:
del form.fields[field_name]
form.fields['generate_password'].initial = False
form.fields['generate_password'].widget = HiddenInput()
form.fields['reset_password_at_next_login'].initial = False
form.fields['reset_password_at_next_login'].widget = HiddenInput()
form.fields['send_mail'].initial = False
form.fields['send_mail'].widget = HiddenInput()
form.fields['send_password_reset'].initial = True
form.fields['send_password_reset'].widget = HiddenInput()
form.fields['creation_mode'].initial = 'backoffice'
form.fields['creation_mode'].widget = HiddenInput()
form.fields['creation_partner'].initial = view.request.user.ou.name
form.fields['creation_partner'].widget = HiddenInput()
del form.fields['creation_domain']
else:
del form.fields['creation_domain']
for field_name in form.fields:
if field_name not in ['username',
'first_name',
'last_name',
'email',
'generate_password']:
del form.fields[field_name]
form.fields['email'].required = True
form.fields['generate_password'].initial = True
form.fields['generate_password'].widget.attrs = {'readonly': ''}
form.fields['send_password_reset'].initial = True
form.fields['send_password_reset'].widget = HiddenInput()
old_save = form.save
def new_save(*args, **kwargs):
response = old_save(*args, **kwargs)
models.Journal.objects.create(
actor=form.request.user,
subject=form.instance,
message='création du compte')
return response
form.save = new_save
if view.__class__.__name__ == 'UserEditView':
# Les usagers CUT n'ont pas d'identifiant
del form.fields['creation_mode']
del form.fields['creation_partner']
del form.fields['creation_domain']
if form.instance.ou:
if form.instance.ou.slug == 'usagers':
form.fields['email'].required = True
del form.fields['username']
for field_name in ['password1', 'password2', 'is_superuser', 'validated',
'validation_context', 'validation_date']:
if field_name in form.fields:
del form.fields[field_name]
else:
for field_name in form.fields:
if field_name not in ['username',
'first_name',
'last_name',
'email',
'is_superuser',
'generate_password']:
del form.fields[field_name]
form.fields['email'].required = True
old_save = form.save
def new_save(*args, **kwargs):
response = old_save(*args, **kwargs)
models.Journal.objects.create(
actor=form.request.user,
subject=form.instance,
message='modification des données')
return response
form.save = new_save
# Si un compte est validé, on interdit la modification des attributs coeurs
if form.instance.attributes.validated:
for field_name in form.fields:
if field_name in ['first_name',
'last_name',
'birthcountry_insee',
'birthplace_insee',
'birthcountry',
'birthplace',
'gender', 'title',
'birthdate']:
# del form.fields[field_name]
field = form.fields[field_name]
field.required = False
if field_name == 'birthdate':
field.widget = DateTimeInput(attrs={'readonly': ''})
attrs = field.widget.attrs or {}
attrs['disabled'] = ''
attrs['title'] = u'Champ validé'
field.widget.attrs = attrs
def new_clean(self, field_name):
def clean():
self.instance.refresh_from_db()
if hasattr(self.instance, field_name):
return getattr(self.instance, field_name)
else:
return getattr(self.instance.attributes, field_name)
return clean
setattr(form, 'clean_' + field_name, new_clean(form, field_name))
if field_name in ['generate_password']:
del form.fields[field_name]
if view.__class__.__name__ == 'UserDetailView':
if form.instance.ou:
if form.instance.ou.slug == 'usagers':
for field_name in ['username', 'is_superuser', 'validated',
'validation_context', 'validation_date', 'creation_mode',
'creation_partner', 'creation_domain']:
if field_name in form.fields:
del form.fields[field_name]
else:
for field_name in form.fields:
if field_name not in ['username', 'first_name', 'last_name', 'email']:
del form.fields[field_name]
if view.__class__.__name__ in ['OrganizationalUnitDetailView', 'OrganizationalUnitEditView',
'OrganizationalUnitAddView']:
del form.fields['default']
del form.fields['email_is_unique']
del form.fields['username_is_unique']
def a2_hook_manager_modify_table(self, view, table):
import django_tables2 as tables
if view.__class__.__name__ == 'UsersView':
ou = view.search_form.cleaned_data['ou']
sequence = list(table.sequence)
if ou and ou.slug == 'usagers':
for column_name in ['username', 'link']:
if column_name in table.base_columns:
del table.base_columns[column_name]
if column_name in sequence:
sequence.remove(column_name)
sequence.remove('email')
sequence.insert(2, 'email')
table.base_columns['preferred_username'] = tables.Column(
accessor='attributes.preferred_username', verbose_name=u'Nom d\'usage')
sequence.insert(2, 'preferred_username')
table.base_columns['validated'] = tables.BooleanColumn(
accessor='attributes.validated', verbose_name=u'Validé')
sequence += ['validated']
else:
del table.base_columns['link']
sequence.remove('link')
table.columns = tables.columns.BoundColumns(table)
table.sequence = sequence
return table
def a2_hook_api_modify_serializer(self, view, original_serializer):
from rest_framework import serializers
if hasattr(original_serializer, 'child'):
serializer = original_serializer.child
else:
serializer = original_serializer
if view.__class__.__name__ == 'UsersAPI':
del serializer.fields['id']
del serializer.fields['uuid']
del serializer.fields['is_superuser']
del serializer.fields['is_staff']
del serializer.fields['password']
serializer.fields['email'].read_only = True
serializer.fields['email_verified'].read_only = True
serializer.fields['ou'].write_only = True
serializer.fields['ou'].read_only = True
del serializer.fields['username']
del serializer.fields['last_login']
def get_gender(obj):
title = obj.attributes.title
return {'Monsieur': 'male', 'Madame': 'female'}.get(title)
serializer.get_gender = get_gender
serializer.fields['gender'] = serializers.SerializerMethodField()
serializer.fields['sub'] = serializers.UUIDField(read_only=True, source='uuid',
label='IDCut')
serializer.fields['given_name'] = serializers.CharField(read_only=True,
source='first_name')
serializer.fields['family_name'] = serializers.CharField(read_only=True,
source='last_name')
serializer.fields['email_verified'].read_only = True
serializer.fields['validation_context'].read_only = True
serializer.fields['validation_date'].read_only = True
serializer.fields['creation_mode'].read_only = True
serializer.fields['creation_partner'].read_only = True
serializer.fields['creation_domain'].read_only = True
def a2_hook_modify_context_data(self, view, context):
from .custom_settings import CORE_ATTRIBUTES, CROWN_ATTRIBUTES
if view.__class__.__name__ == 'ProfileView':
context['cut_core_filled'] = all(getattr(view.request.user.attributes, a, None) for a in
CORE_ATTRIBUTES)
context['cut_crown_filled'] = any(getattr(view.request.user.attributes, a, None) for a
in CROWN_ATTRIBUTES)
def a2_hook_manager_modify_other_actions(self, view, other_actions):
from authentic2.manager.views import Action
class CUTValidate(Action):
name = 'cut-validate'
title = 'Valider le compte'
permission = 'custom_user.cut_validate_user'
url_name = 'cut-manager-user-edit-core'
popup = False
def display(self, user, request):
if user.ou and user.ou.slug != 'usagers':
return False
if user.attributes.validated and user.attributes.validation_context == 'fc':
return False
if user.attributes.validated:
self.title = u'Modifier les données coeur'
self.user = user
return super(CUTValidate, self).display(user, request)
class CUTJournalActions(Action):
name = 'cut-journal-actions'
title = 'Journal des actions'
permission = 'custom_user.view_user'
url_name = 'cut-manager-user-actions-journal'
popup = False
def display(self, user, request):
if user.ou and user.ou.slug == 'usagers':
return False
return super(CUTJournalActions, self).display(user, request)
class CUTJournalModifications(Action):
name = 'cut-journal-modifications'
title = 'Journal des modifications'
permission = 'custom_user.view_user'
url_name = 'cut-manager-user-modifications-journal'
popup = False
if view.__class__.__name__ == 'UserDetailView':
other_actions.append(CUTValidate())
other_actions.append(CUTJournalActions())
other_actions.append(CUTJournalModifications())
def a2_hook_front_modify_form(self, view, form):
if view.__class__.__name__ == 'EditProfile':
if form.instance and form.instance.attributes.validated:
for field in ('first_name', 'last_name', 'birthdate', 'title',
'birthplace', 'birthcountry'):
form.fields.pop(field, None)
for field in form.fields.values():
if hasattr(field, 'max_length'):
if field.max_length is None:
field.max_length = 128
field.widget.attrs['maxlength'] = 128
def a2_hook_api_modify_queryset(self, view, queryset):
if view.__class__.__name__ == 'UsersAPI':
if hasattr(view.request.user, 'oidc_client'):
return queryset.filter(ou__slug='usagers')
def modify_profile_form(form):
if form.instance and form.instance.attributes.validated:
for field in ('first_name', 'last_name', 'birthdate', 'title',
'birthplace', 'birthcountry'):
form.fields.pop(field, None)
return form
A2_MODIFY_PROFILE_FORM = modify_profile_form

View File

@ -52,22 +52,6 @@ class RemoveFranceConnect(object):
A2_MANAGER_USER_ACTIONS = [RemoveFranceConnect()]
class FranceConnectUserData(object):
def __init__(self, user, request):
self.user = user
self.request = request
def __unicode__(self):
from authentic2_auth_fc.models import FcAccount
try:
FcAccount.objects.get(user=self.user)
return u'Utilisateur relié à un compte FranceConnect'
except FcAccount.DoesNotExist:
return u''
A2_MANAGER_USER_DATA = [FranceConnectUserData]
def modify_user_info(user, user_info, scope_set):
import logging
@ -110,16 +94,6 @@ def modify_user_info(user, user_info, scope_set):
A2_IDP_OIDC_MODIFY_USER_INFO = modify_user_info
def modify_profile_form(form):
if form.instance and form.instance.attributes.validated:
for field in ('first_name', 'last_name', 'birthdate', 'title',
'birthplace', 'birthcountry'):
form.fields.pop(field, None)
return form
A2_MODIFY_PROFILE_FORM = modify_profile_form
A2_PROFILE_FIELDS = [
u'email',
u'title',