authentic/src/authentic2/manager/tables.py

354 lines
12 KiB
Python

# pylint: skip-file
# authentic2 - versatile identity manager
# Copyright (C) 2010-2019 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_tables2 as tables
from django.contrib.auth import get_user_model
from django.utils import html
from django.utils.safestring import SafeText
from django.utils.translation import gettext_lazy as _
from django.utils.translation import gettext_noop
from django_tables2.utils import A
from authentic2.a2_rbac.models import OrganizationalUnit, Role
from authentic2.middleware import StoreRequestMiddleware
from authentic2.models import Service
from authentic2_idp_oidc.models import OIDCAuthorization
User = get_user_model()
TABLES_MAJOR_VERSION = int(tables.__version__.split('.', maxsplit=1)[0])
class Table(tables.Table):
class Meta:
row_attrs = {'data-pk': lambda record: record.pk}
class PermissionLinkColumn(tables.LinkColumn):
if TABLES_MAJOR_VERSION >= 2:
def render(self, record, value, **kwargs):
request = StoreRequestMiddleware.get_request()
permission = '%s.view_%s' % (record._meta.app_label, record._meta.model_name)
if request and not request.user.has_perm(permission, record):
return value
return super().render(record, value)
else:
def render(self, value, record, bound_column, **kwargs):
request = StoreRequestMiddleware.get_request()
permission = '%s.view_%s' % (record._meta.app_label, record._meta.model_name)
if request and not request.user.has_perm(permission, record):
return value
return super().render(value, record, bound_column)
class VerifiableEmailColumn(tables.Column):
def render(self, **kwargs):
user = kwargs['record']
verified = user.email_verified
value = user.email
if value and verified:
return html.format_html('<span class="verified">{value}</span>', value=value)
return value
class UserLinkColumn(PermissionLinkColumn):
if TABLES_MAJOR_VERSION >= 2:
def render(self, record, value, **kwargs):
value = super().render(record, value, **kwargs)
if isinstance(record, User) and not record.is_active:
value = html.format_html(
'<span class="disabled">{value} ({disabled})</span>', value=value, disabled=_('disabled')
)
return value
else:
def render(self, **kwargs):
record = kwargs['record']
value = super().render(**kwargs)
if isinstance(record, User) and not record.is_active:
value = html.format_html(
'<span class="disabled">{value} ({disabled})</span>', value=value, disabled=_('disabled')
)
return value
class UserTable(Table):
get_full_name = UserLinkColumn(
verbose_name=_('User'),
args=[A('pk')],
order_by=('last_name', 'first_name', 'email', 'username'),
text=lambda record: record.get_full_name(),
attrs={'td': {'class': 'link'}},
)
username = tables.Column(
attrs={
'td': {'class': 'username'},
'th': {'class': 'username orderable'},
}
)
email = VerifiableEmailColumn()
ou = tables.Column()
class Meta(Table.Meta):
model = User
attrs = {'class': 'main clickable-rows', 'id': 'user-table'}
fields = ('username', 'email', 'first_name', 'last_name', 'ou')
sequence = ('get_full_name', '...')
empty_text = _('None')
class RoleMembersTable(UserTable):
direct = tables.BooleanColumn(
verbose_name=_('Direct member'), orderable=False, attrs={'td': {'class': 'direct'}}
)
via = tables.TemplateColumn(
'{% for role in record.via %}<a href="{% url "a2-manager-role-members" pk=role.pk %}">{{ role'
' }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}',
verbose_name=_('Inherited from'),
orderable=False,
attrs={'td': {'class': 'via'}},
)
class Meta(UserTable.Meta):
row_attrs = {'data-pk': lambda record: 'user-%s' % record.pk}
class UserOrRoleColumn(UserLinkColumn):
def render(self, **kwargs):
value = super().render(**kwargs)
if isinstance(kwargs['record'], Role):
value = html.format_html(_('Members of role {value}'), value=value)
return value
class MixedUserRoleTable(Table):
pk = UserOrRoleColumn(
verbose_name=_('Members'),
text=str,
orderable=False,
attrs={'td': {'class': 'name'}},
)
class Meta(Table.Meta):
attrs = {'class': 'main clickable-rows', 'id': 'user-table'}
row_attrs = {
'data-pk': lambda record: '%s-%s' % ('user' if isinstance(record, User) else 'role', record.pk)
}
class RoleTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-role-members',
kwargs={'pk': A('pk')},
accessor='name',
verbose_name=_('label'),
attrs={'td': {'class': 'name'}},
)
ou = tables.Column()
slug = tables.Column(attrs={'td': {'class': 'slug'}})
member_count = tables.Column(
verbose_name=_('Direct member count'), orderable=False, attrs={'td': {'class': 'member_count'}}
)
def render_name(self, record, bound_column):
if TABLES_MAJOR_VERSION >= 2:
content = bound_column.column.render(record, record.name)
else:
content = bound_column.column.render(record.name, record, bound_column)
if not record.can_manage_members:
content = SafeText('%s (%s)' % (content, _('LDAP')))
return content
class Meta(Table.Meta):
model = Role
attrs = {'class': 'main clickable-rows', 'id': 'role-table'}
fields = ('name', 'slug', 'ou', 'member_count')
order_by = ('name',)
class OUTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-ou-detail',
kwargs={'pk': A('pk')},
accessor='name',
verbose_name=_('label'),
attrs={'td': {'class': 'name'}},
)
slug = tables.Column(attrs={'td': {'class': 'slug'}})
default = tables.BooleanColumn(attrs={'td': {'class': 'default'}})
class Meta(Table.Meta):
model = OrganizationalUnit
attrs = {'class': 'main clickable-rows', 'id': 'ou-table'}
fields = ('name', 'slug', 'default')
empty_text = _('None')
class OuUserRolesTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-role-members',
kwargs={'pk': A('pk')},
accessor='name',
verbose_name=_('label'),
attrs={'td': {'class': 'name'}},
)
via = tables.TemplateColumn(
'''{% for rel in record.via %}{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}''',
verbose_name=_('Inherited from'),
orderable=False,
attrs={'td': {'class': 'via'}},
)
member = tables.TemplateColumn(
'{%% load i18n %%}<input class="role-member{%% if not record.member and record.via %%}'
' indeterminate{%% endif %%}" name="role-{{ record.pk }}" type="checkbox" {%% if record.member'
' %%}checked{%% endif %%} {%% if not record.has_perm %%}disabled title="{%% trans "%s" %%}"{%% endif'
' %%} {%% if not record.can_manage_members %%}disabled title="{%% trans "%s" %%}"{%% endif %%}/>'
% (
gettext_noop('You are not authorized to manage this role'),
gettext_noop('This role is synchronised from LDAP, changing members is not allowed.'),
),
verbose_name=_('Member'),
order_by=('member', 'via', 'name'),
attrs={'td': {'class': 'member'}},
)
def render_name(self, record, bound_column):
if TABLES_MAJOR_VERSION >= 2:
content = bound_column.column.render(record, record.name)
else:
content = bound_column.column.render(record.name, record, bound_column)
if not record.can_manage_members:
content = SafeText('%s (%s)' % (content, _('LDAP')))
return content
class Meta(Table.Meta):
model = Role
attrs = {'class': 'main clickable-rows', 'id': 'role-table'}
fields = ('name', 'ou')
empty_text = _('None')
order_by = ('name',)
class UserRolesTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-role-members',
kwargs={'pk': A('pk')},
accessor='name',
verbose_name=_('label'),
attrs={'td': {'class': 'name'}},
)
ou = tables.Column()
via = tables.TemplateColumn(
'{% if not record.member %}{% for rel in record.child_relation.all %}'
'{{ rel.child }} {% if not forloop.last %}, {% endif %}{% endfor %}{% endif %}',
verbose_name=_('Inherited from'),
orderable=False,
attrs={'td': {'class': 'via'}},
)
def render_name(self, record, bound_column):
if TABLES_MAJOR_VERSION >= 2:
content = bound_column.column.render(record, record.name)
else:
content = bound_column.column.render(record.name, record, bound_column)
if not record.can_manage_members:
content = SafeText('%s (%s)' % (content, _('LDAP')))
return content
class Meta(Table.Meta):
model = Role
attrs = {'class': 'main clickable-rows', 'id': 'role-table'}
fields = ('name', 'ou')
empty_text = _('None')
order_by = ('name', 'ou')
class ServiceTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-service',
kwargs={'service_pk': A('pk')},
accessor='name',
verbose_name=_('label'),
)
ou = tables.Column()
slug = tables.Column()
class Meta(Table.Meta):
model = Service
attrs = {'class': 'main clickable-rows', 'id': 'service-table'}
fields = ('name', 'slug', 'ou')
empty_text = _('None')
order_by = ('ou', 'name', 'slug')
class ServiceRolesTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-role-members', kwargs={'pk': A('pk')}, accessor='name', verbose_name=_('label')
)
class Meta(Table.Meta):
model = Role
attrs = {'class': 'main clickable-rows', 'id': 'service-role-table'}
fields = ('name',)
empty_text = _('No access restriction. All users are allowed to connect to this service.')
class UserAuthorizationsTable(Table):
client = tables.Column(orderable=False)
created = tables.Column()
expired = tables.Column()
class Meta(Table.Meta):
model = OIDCAuthorization
attrs = {'class': 'main', 'id': 'user-authorizations-table'}
fields = ('client', 'created', 'expired')
empty_text = _('This user has not granted profile data access to any service yet.')
class InheritanceRolesTable(Table):
name = tables.LinkColumn(
viewname='a2-manager-role-members',
kwargs={'pk': A('pk')},
accessor='name',
verbose_name=_('label'),
attrs={'td': {'class': 'name'}},
)
via = tables.TemplateColumn(
'''{% for rel in record.via %}{{ rel.name }}{% if not forloop.last %}, {% endif %}{% endfor %}''',
verbose_name=_('Inherited from'),
orderable=False,
attrs={'td': {'class': 'via'}},
)
member = tables.TemplateColumn(
'<input class="role-member{% if record.indeterminate %} indeterminate{% endif %}" name="role-{{ record.pk }}" '
'type="checkbox" {% if record.checked %}checked{% endif %}/>',
verbose_name='',
attrs={'td': {'class': 'member'}},
)
class Meta(Table.Meta):
model = Role
attrs = {'class': 'main clickable-rows', 'id': 'inheritance-role-table'}
fields = ('name', 'ou')
empty_text = _('None')