Skip to content

Instantly share code, notes, and snippets.

@frague59
Created May 26, 2017 12:53
Show Gist options
  • Save frague59/f90ba63bb2548fb27e32576329159543 to your computer and use it in GitHub Desktop.
Save frague59/f90ba63bb2548fb27e32576329159543 to your computer and use it in GitHub Desktop.
people admin
# -*- coding: utf-8 -*-
"""
:class:`directory.models.people.People` admin for :mod:`directory` application
:creationdate: 14/11/16 13:52
:moduleauthor: François GUÉRIN <fguerin@ville-tourcoing.fr>
:modulename: directory.admin.people
"""
from __future__ import unicode_literals
import logging
from django.conf import settings
from django.contrib import messages
from django.contrib.auth import models as a_models
from django.http import HttpResponse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from guardian.admin import GuardedModelAdminMixin
from guardian.shortcuts import get_objects_for_user
from import_export.admin import ImportExportMixin
from reversion.admin import VersionAdmin
from unidecode import unidecode
from directory.admin import utilities, list_filters, forms, resources
from directory.idcards import IdCardGenerator
from directory.models import people, perms, hierarchy
__author__ = 'fguerin'
logger = logging.getLogger('directory.admin.people')
#: Session administrated hierarchies identifier
SESSION_ADMINISTRATED_HIERARCHIES = 'ADMINISTRATED_HIERARCHIES'
class PeopleAdmin(ImportExportMixin, utilities.AdministrableAdminMixin, GuardedModelAdminMixin, VersionAdmin):
"""
Administrate :class:`directory.models.people.People` instances
"""
# Import / Export
resource_class = resources.PeopleResource
skip_admin_log = False
# Common admin attributes
actions = ['action_create_idcards',
'action_delete_idcards',
'action_mutate', ]
list_display = ['full_name', 'rendered_hierarchy',
'job', 'email', 'phone', 'image_thumb',
'idcard', 'display_image']
list_editable = ['display_image', ]
list_display_links = ['full_name']
list_filter = ['civility',
'job',
list_filters.AdditionalRolePeoplesListFilter,
list_filters.PeopleHierarchiesListFilter,
list_filters.PeopleHierarchiesStrictListFilter,
list_filters.ImagePeoplesListFilter,
list_filters.IdCardPeoplesListFilter]
search_fields = ('last_name', 'usage_name', 'first_name', 'hierarchy__name', 'job__label',)
form = forms.PeopleAdminForm
def get_queryset(self, request):
"""
Gets the administrable :class:`directory.models.people.People` items
:param request: Http Request
:returns: QuerySet of administrable :class:`directory.models.people.People` items
"""
queryset = get_objects_for_user(request.user,
perms=[perms.PERM_CHANGE_PEOPLE, perms.PERM_CREATE_IDCARD_PEOPLE],
klass=people.People, any_perm=True)
queryset = (queryset
.exclude(hierarchy=utilities.get_mutation_hierarchy(request))
.select_related('civility', 'hierarchy', 'user_author', 'user_updater', 'image', 'job')
.prefetch_related('additional_role'))
return queryset
def get_fieldsets(self, request, obj=None):
if request.user.is_superuser:
fieldsets= ((_('Identification'), {'fields': ['civility', 'last_name', 'usage_name',
'first_name', 'image', 'display_image']}),
(_('Position'), {'fields': ('hierarchy', 'job', 'comment', 'is_chief', 'additional_role')}),
(_('Id card'), {'fields': ('idcard_guid', 'idcard_date',), # 'idcard_signed',
'description': _('Professional Id card are documents given to each agents in the '
'collectivity. This card is required to access to the city hall and '
'to all the municipal buildings. It is used to identify agents.'),
'classes': ('grp-collapse',)}),
utilities.DATE_IN_OUT_FIELDSET,
utilities.CONTACTABLE_FIELDSET,)
else:
fieldsets = ((_('Identification'), {'fields': ['civility', 'last_name', 'usage_name',
'first_name', 'display_image']}),
(_('Position'), {'fields': ('hierarchy', 'job', 'comment', 'is_chief', 'additional_role')}),
(_('Id card'), {'fields': ('idcard_guid', 'idcard_date',), # 'idcard_signed',
'description': _('Professional Id card are documents given to each agents in the '
'collectivity. This card is required to access to the city hall and '
'to all the municipal buildings. It is used to identify agents.'),
'classes': ('grp-collapse',)}),
utilities.DATE_IN_OUT_FIELDSET,
utilities.CONTACTABLE_FIELDSET,)
return fieldsets
@staticmethod
def _get_administrated_hierarchies(request):
"""
Gets the administrated hierarchies for the current connected user, from session if available, else from db.
:param request: HTTP Request
:returns: administrated hierarchies
"""
hierarchies = request.session.get(SESSION_ADMINISTRATED_HIERARCHIES, None)
if hierarchies is not None:
logger.debug('PeopleAdmin::_get_administrated_hierarchies() from session : len(hierarchies) = %d',
len(hierarchies))
return hierarchies
else:
hierarchies = get_objects_for_user(request.user, perms=perms.PERM_CHANGE_HIERARCHY,
klass=hierarchy.Hierarchy)
logger.debug('PeopleAdmin::_get_administrated_hierarchies() from db : len(hierarchies) = %d',
len(hierarchies))
# Saves the administrated hierarchies into the session
request.session[SESSION_ADMINISTRATED_HIERARCHIES] = hierarchies
return hierarchies
def formfield_for_foreignkey(self, db_field, request=None, **kwargs):
if db_field.name == 'hierarchy' and not request.user.is_superuser:
hierarchies = self._get_administrated_hierarchies(request)
kwargs['queryset'] = hierarchies
return super(PeopleAdmin, self).formfield_for_foreignkey(db_field=db_field, request=request, **kwargs)
def get_form(self, request, obj=None, **kwargs):
"""
Gets the update / create form for a given object
.. note::
This methods diverts the ``form.clean`` method for super admins to ``clean_superuser`` method
:param request: Http request
:param obj: current object
:param kwargs: Additional keyword arguments
:returns: form
"""
# Change form class based on user
if request.user.is_superuser:
self.form = forms.PeopleAdminForm
else:
self.form = forms.EditorPeopleAdminForm
# Builds the form
form = super(PeopleAdmin, self).get_form(request, obj, **kwargs)
return form
def has_change_permission(self, request, obj=None):
"""
Checks whether the connected user has permission to change current instance
:param request: HTTP request
:param obj: current instance
:returns: True if user is allowed, False otherwise
"""
# Gets the connected user
user = request.user
if user.is_superuser:
return True
if obj is not None:
return user.has_perm(perms.PERM_CHANGE_PEOPLE, obj)
allowed = (perms.is_editor(user) and get_objects_for_user(user,
perms=perms.PERM_CHANGE_PEOPLE,
klass=people.People)
or perms.is_idcard_editor(user))
return allowed
def get_list_display(self, request):
"""
Hides the `display_image` field if user is not superuser or has no permissions to update the
:class:`directory.models.people.People`
:param request: Http request
:returns: List of displayed fields
"""
user = request.user
list_display = super(PeopleAdmin, self).get_list_display(request)
if user.is_superuser:
return list_display
user_have_somme_perms = get_objects_for_user(user,
perms=['directory.change_people'],
klass=people.People,
with_superuser=True)
if user_have_somme_perms:
return list_display
if 'display_image' in self.list_editable:
self.list_editable.remove('display_image')
return list_display
def get_list_display_links(self, request, list_display):
"""
Hides the link on `full_name` field if user is not superuser or has no permissions to update the
:class:`directory.models.P
:param request: Http request
:param list_display: list of displayed fields
:returns: list of displayed links
"""
display_links = super(PeopleAdmin, self).get_list_display_links(request, list_display)
user = request.user
settings.DEBUG and logger.debug('PeopleAdmin::get_list_display_links() user = %s', user)
if user.is_superuser:
return display_links
user_have_somme_perms = get_objects_for_user(user,
perms=['directory.change_people', 'directory.delete_people', ],
klass=people.People,
with_superuser=True)
if user_have_somme_perms:
return display_links
if 'full_name' in display_links:
display_links.remove('full_name')
return display_links
def get_actions(self, request):
"""
Removes action `action_create_idcards` for:
+ non-superuser
* users not having the permission `directory.create_idcard_people`
:param request: HTTP request
:returns: Allowed actions
"""
user = request.user
actions = super(PeopleAdmin, self).get_actions(request)
if user.is_superuser:
return actions
if not user.has_perm('directory.delete_people'):
del actions['delete_selected']
return actions
def rendered_hierarchy(self, obj):
"""
Gets the direct hierarchy and the displayed one
:param obj: Current instance
:returns: formatted HTML chunk
"""
direct_hierarchy = obj.hierarchy
displayed_hierarchy = obj.hierarchy.get_displayed_hierarchy()
rendered = render_to_string('directory/snippets/hierarchy.html', {'hierarchy': direct_hierarchy,
'displayed_hierarchy': displayed_hierarchy})
return mark_safe(rendered)
rendered_hierarchy.short_description = _('Hierarchy')
def full_name(self, obj):
"""
Gets the full name of the current :class:`directory.objects.People` instance
:param obj: Current instance
:returns: formatted HTML chunk
"""
return mark_safe(obj.full_name)
full_name.short_description = _('Full name')
def phone(self, obj):
"""
Gets the phone numbers of the current :class:`directory.objects.People` instance, using a template
:param obj: Current instance
:returns: formatted HTML chunk
"""
rendered = render_to_string('directory/snippets/phone.html', {'object': obj})
return mark_safe(rendered)
phone.short_description = _('Phone')
def image_thumb(self, obj):
"""
Gets the photo thumbnail of the current :class:`directory.objects.People` instance
:param obj: Current instance
:returns: formatted HTML chunk
"""
context = {'object': obj}
logger.debug('PeopleAdmin::image_thumb(%s) obj.image__class__.__name__ = %s',
obj, obj.image.__class__.__name__)
rendered = render_to_string('directory/admin/snippets/people/image_thumb.html', context)
return mark_safe(rendered)
image_thumb.short_description = _('Photo')
def idcard(self, obj):
"""
Gets the id card data of the current :class:`directory.objects.People` instance
:param obj: Current instance
:returns: formatted HTML chunk
"""
return mark_safe(render_to_string('directory/admin/snippets/people/idcard.html', {'object': obj}))
idcard.short_description = _('Id Card')
# Actions
def action_mutate(self, request, queryset):
"""
Moves peoples and images from there onw hierarchy to the ``Mutation`` hierarchy, where they can be found to be
re-mutated from by another directory editor.
:param request: HTTP Request
:param queryset: Selected peoples
:returns: Nothing
"""
mutation_hierarchy = utilities.get_mutation_hierarchy(request)
mutation_image_folder = utilities.get_mutation_image_folder(request)
group = a_models.Group.objects.get(name=settings.DIRECTORY_EDITOR_GROUP_NAME)
users = group.user_set.all()
for _people in queryset:
# Moves the people to ``Mutation``
utilities.move_people_to_mutation(_people, request, mutation_hierarchy)
# Moves the people image to ``Mutation``
utilities.move_image_to_mutation(_people, request, mutation_image_folder)
# Deletes th id_card data
utilities.delete_idcard_data(_people, request)
# Change permissions on people
for user in users:
perms.add_perms_on_peoples(user, dry_run=False, wanted_peoples=queryset)
action_mutate.short_description = _('Mutate selected peoples')
def action_delete_idcards(self, request, queryset):
"""
Action to delete id card data for a given queryset
:param request: HTTP Request
:param queryset: Selected peoples
:returns: Nothing
"""
for _people in queryset:
utilities.delete_idcard_data(_people, request)
action_delete_idcards.short_description = _('Delete id cards')
def action_create_idcards(self, request, queryset):
"""
Action to draw some ID cards for a given queryset
:param request: HTTP Request
:param queryset: Selected peoples
:returns: HTTP Response with PDF inside
"""
error_peoples = []
for _people in queryset:
if _people.image is None:
error_peoples.append(_people)
messages.warning(request, _('There is no photo for %(people)s, please add one.') % {'people': _people})
people_list = [_people for _people in queryset if _people.image if not None]
generator = IdCardGenerator()
card_pdf = generator.generate_idcards(people_list=people_list)
response = HttpResponse(content=card_pdf, content_type='application/pdf')
disposition = 'attachment; filename="idcards.pdf"'
response['Content-Disposition'] = disposition
return response
action_create_idcards.short_description = _('Create professional identity cards')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment