Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c46d84b023 | |||
| 48abf000fc | |||
| a635d16a8a | |||
| df298dc6e0 | |||
| 8523ce0825 | |||
| b82c610a9f | |||
| b9b23d6627 | |||
| 47034c9eb6 | |||
| 55ed18967c | |||
| 6fa1ffbdff | |||
| 7b0bd4f17e | |||
| eca52bec63 | |||
| a63426d1ea | |||
| 09c422ed15 | |||
|
|
15ab8b2ab6 | ||
| 2237e35770 | |||
| 8aca00e943 | |||
| 62d7b9fe8a | |||
| 604f7af5ff | |||
| b00ecd576b | |||
| 7734a0d36f | |||
| fac000e39c | |||
| ee67e23e5f | |||
| 16722682aa | |||
| fb960855f0 | |||
| 94dd1dd7a3 | |||
| c1d7c2b914 | |||
| b8416e7f8b | |||
| a614b1f160 | |||
| c2955968bc | |||
| 00cea530ab | |||
| 6cd5753056 | |||
| 0dc9ee0991 | |||
| 95a18884bb | |||
| 10cda0783a | |||
| f453d5745c | |||
| 815fff4094 | |||
| 6a23e196ac | |||
| ab9052bcac | |||
| 62ffd04fbd |
1
.gitignore
vendored
1
.gitignore
vendored
@ -118,5 +118,6 @@ dmypy.json
|
|||||||
migrations/
|
migrations/
|
||||||
logs/
|
logs/
|
||||||
db/
|
db/
|
||||||
|
data/
|
||||||
!docker/ldap/data/var/
|
!docker/ldap/data/var/
|
||||||
*.mdb
|
*.mdb
|
||||||
|
|||||||
@ -28,3 +28,15 @@ LDAP_GROUP_NAME_ATTR=cn
|
|||||||
EMAIL_BACKEND=file
|
EMAIL_BACKEND=file
|
||||||
DEFAULT_FROM_EMAIL=
|
DEFAULT_FROM_EMAIL=
|
||||||
SERVER_EMAIL=
|
SERVER_EMAIL=
|
||||||
|
|
||||||
|
DELETION_WAIT_DAYS=14
|
||||||
|
|
||||||
|
|
||||||
|
#EMAIL_BACKEND=smtp
|
||||||
|
#EMAIL_HOST=smtp.uni-bamberg.de
|
||||||
|
#EMAIL_PORT=587
|
||||||
|
#EMAIL_USE_TLS=False
|
||||||
|
#EMAIL_USE_SSL=False
|
||||||
|
#DEFAULT_FROM_EMAIL=vergesslich@uni-bamberg.de
|
||||||
|
##DEFAULT_FROM_EMAIL=fachschaft-wiai.stuve@uni-bamberg.de
|
||||||
|
#SERVER_EMAIL=fachschaft-wiai.stuve@uni-bamberg.de
|
||||||
|
|||||||
32
example.env
Normal file
32
example.env
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
DJANGO_SETTINGS_MODULE=core.docker_settings
|
||||||
|
DOMAIN=localhost
|
||||||
|
|
||||||
|
SITE_NAME=LAMa
|
||||||
|
|
||||||
|
SECRET_KEY=supersecret
|
||||||
|
ALLOWED_HOSTS=localhost
|
||||||
|
|
||||||
|
DATABASE_HOST=dblama
|
||||||
|
DATABASE_PORT=5432
|
||||||
|
|
||||||
|
POSTGRES_USER=lama
|
||||||
|
POSTGRES_PASSWORD=secret
|
||||||
|
|
||||||
|
DEBUG=True
|
||||||
|
|
||||||
|
LDAP_SERVER_URI=ldap://ldap:389
|
||||||
|
LDAP_ADMIN_USER_NAME=cn=admin,dc=test,dc=de
|
||||||
|
LDAP_ADMIN_USER_PASSWORD=secret
|
||||||
|
|
||||||
|
LDAP_USER_ENTRY=dc=test,dc=de
|
||||||
|
LDAP_USER_SELECTOR=(uid=%(user)s)
|
||||||
|
|
||||||
|
LDAP_GROUP_ENTRY=dc=test,dc=de
|
||||||
|
LDAP_GROUP_SELECTOR=(objectClass=groupOfNames)
|
||||||
|
LDAP_GROUP_NAME_ATTR=cn
|
||||||
|
|
||||||
|
EMAIL_BACKEND=file
|
||||||
|
DEFAULT_FROM_EMAIL=
|
||||||
|
SERVER_EMAIL=
|
||||||
|
|
||||||
|
DELETION_WAIT_DAYS=14
|
||||||
@ -3,4 +3,4 @@ python-ldap==3.2.0
|
|||||||
django-auth-ldap==1.7.0
|
django-auth-ldap==1.7.0
|
||||||
django-ldapdb==1.3.0
|
django-ldapdb==1.3.0
|
||||||
Jinja2==2.10
|
Jinja2==2.10
|
||||||
Pillow==2.2.1
|
Pillow==2.2.1
|
||||||
@ -1,6 +1,6 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from .models import Realm
|
from .models import Realm, DeletedUser
|
||||||
|
|
||||||
# Register your models here.
|
# Register your models here.
|
||||||
admin.site.register(Realm)
|
admin.site.register(Realm)
|
||||||
# admin.site.register(DeletedUser)
|
admin.site.register(DeletedUser)
|
||||||
|
|||||||
0
src/account_helper/management/__init__.py
Normal file
0
src/account_helper/management/__init__.py
Normal file
0
src/account_helper/management/commands/__init__.py
Normal file
0
src/account_helper/management/commands/__init__.py
Normal file
64
src/account_helper/management/commands/deletable.py
Normal file
64
src/account_helper/management/commands/deletable.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
|
from account_helper.models import DeletedUser
|
||||||
|
from account_manager.models import LdapGroup, LdapUser
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Get and delete the deleted marked users'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--delete',
|
||||||
|
action='store_true',
|
||||||
|
help='Delete users which deletion time is lower than the current date',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--json',
|
||||||
|
action='store_true',
|
||||||
|
help='Return an json encoded String',
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--all',
|
||||||
|
action='store_true',
|
||||||
|
help='Delete all marked user, --delete is required',
|
||||||
|
)
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if options['all']:
|
||||||
|
deletables = DeletedUser.objects.all()
|
||||||
|
else:
|
||||||
|
deletables = DeletedUser.objects.filter(deletion_date__lte=timezone.now())
|
||||||
|
output = ""
|
||||||
|
if options['json']:
|
||||||
|
json_output = {'deletables': []}
|
||||||
|
for deletable in deletables:
|
||||||
|
json_output['deletables'].append({'ldap_dn': deletable.ldap_dn, 'username': deletable.user.username})
|
||||||
|
output = json.dumps(json_output)
|
||||||
|
else:
|
||||||
|
for user in deletables:
|
||||||
|
output += f'{user}\n'
|
||||||
|
if options['delete']:
|
||||||
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
|
for user in deletables:
|
||||||
|
ldap_user = LdapUser.objects.get(dn=user.ldap_dn)
|
||||||
|
LdapGroup.remove_user_from_groups(ldap_user.dn)
|
||||||
|
ldap_user.delete()
|
||||||
|
try:
|
||||||
|
user.user.delete()
|
||||||
|
user.delete()
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
pass
|
||||||
|
if not options['json']:
|
||||||
|
output += '\nSuccessfully deleted all listed users'
|
||||||
|
if output:
|
||||||
|
self.stdout.write(self.style.SUCCESS(output))
|
||||||
|
else:
|
||||||
|
for deletable in deletables:
|
||||||
|
self.stdout.write(self.style.SUCCESS(deletable))
|
||||||
|
|
||||||
|
|
||||||
@ -1,5 +1,7 @@
|
|||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
# Create your models here.
|
# Create your models here.
|
||||||
@ -14,9 +16,15 @@ class Realm(models.Model):
|
|||||||
return f'{self.name} - {self.ldap_base_dn}'
|
return f'{self.name} - {self.ldap_base_dn}'
|
||||||
|
|
||||||
|
|
||||||
# class DeletedUser(models.Model):
|
def get_deletion_time():
|
||||||
# deletion_date = models.DateField(auto_now=True)
|
return timezone.now() + timezone.timedelta(settings.DELETION_WAIT_DAYS)
|
||||||
# user = models.ForeignKey(User, on_delete=models.CASCADE)
|
|
||||||
#
|
|
||||||
# def __str__(self):
|
class DeletedUser(models.Model):
|
||||||
# return f'{self.user.username} - {self.deletion_date}'
|
deletion_marker_date = models.DateField(auto_now_add=True)
|
||||||
|
user = models.ForeignKey(User, on_delete=models.CASCADE)
|
||||||
|
ldap_dn = models.CharField(max_length=512, unique=True)
|
||||||
|
deletion_date = models.DateField(default=get_deletion_time)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.user.username} - {self.deletion_marker_date} - {self.deletion_date} - {self.ldap_dn}'
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.forms import PasswordResetForm
|
from django.contrib.auth.forms import PasswordResetForm, PasswordChangeForm
|
||||||
|
|
||||||
|
from account_manager.utils.django_user import update_dajngo_user
|
||||||
from .models import LdapUser, LdapGroup
|
from .models import LdapUser, LdapGroup
|
||||||
from django.forms import modelformset_factory
|
from django.forms import modelformset_factory
|
||||||
import logging
|
import logging
|
||||||
@ -83,6 +84,10 @@ class LdapPasswordResetForm(PasswordResetForm):
|
|||||||
that prevent inactive users and users with unusable passwords from
|
that prevent inactive users and users with unusable passwords from
|
||||||
resetting their password.
|
resetting their password.
|
||||||
"""
|
"""
|
||||||
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
|
ldap_users = LdapUser.objects.filter(email=email)
|
||||||
|
for ldap_user in ldap_users:
|
||||||
|
update_dajngo_user(ldap_user)
|
||||||
logger.debug('Pasword reset get users')
|
logger.debug('Pasword reset get users')
|
||||||
active_users = UserModel._default_manager.filter(**{
|
active_users = UserModel._default_manager.filter(**{
|
||||||
'%s__iexact' % UserModel.get_email_field_name(): email,
|
'%s__iexact' % UserModel.get_email_field_name(): email,
|
||||||
@ -90,3 +95,11 @@ class LdapPasswordResetForm(PasswordResetForm):
|
|||||||
})
|
})
|
||||||
logger.debug((u for u in active_users))
|
logger.debug((u for u in active_users))
|
||||||
return (u for u in active_users)
|
return (u for u in active_users)
|
||||||
|
|
||||||
|
|
||||||
|
class LdapPasswordChangeForm(PasswordChangeForm):
|
||||||
|
def clean_old_password(self):
|
||||||
|
"""
|
||||||
|
Validates that the old_password field is correct.
|
||||||
|
"""
|
||||||
|
return "ralf"
|
||||||
|
|||||||
@ -1,20 +1,19 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
|
||||||
from smtplib import SMTPAuthenticationError, SMTPConnectError, SMTPException
|
from smtplib import SMTPAuthenticationError, SMTPConnectError, SMTPException
|
||||||
from socket import timeout
|
from socket import timeout
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import Group, User
|
from django.contrib.auth.models import Group, User
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
|
||||||
from django.db import IntegrityError
|
from django.db import IntegrityError
|
||||||
from django.shortcuts import render, redirect, HttpResponse
|
from django.shortcuts import render, redirect
|
||||||
from datetime import datetime, timedelta
|
from ldap import LDAPError
|
||||||
|
|
||||||
from account_helper.models import Realm
|
from account_helper.models import Realm
|
||||||
from account_manager.utils.mail_utils import realm_send_mail
|
from account_manager.utils.mail_utils import realm_send_mail
|
||||||
|
from account_manager.utils.main_views import render_permission_denied_view, render_realm_detail_view, \
|
||||||
|
get_users_home_view
|
||||||
from .forms import RealmAddForm, RealmUpdateForm
|
from .forms import RealmAddForm, RealmUpdateForm
|
||||||
from .models import LdapGroup, LdapUser
|
from .models import LdapGroup, LdapUser
|
||||||
from ldap import LDAPError
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -27,44 +26,20 @@ def is_realm_admin(view_func):
|
|||||||
admin_group__user__username__contains=request.user.username)) > 0):
|
admin_group__user__username__contains=request.user.username)) > 0):
|
||||||
return view_func(request, *args, **kwargs)
|
return view_func(request, *args, **kwargs)
|
||||||
else:
|
else:
|
||||||
return redirect('permission-denied')
|
return render_permission_denied_view(request)
|
||||||
|
|
||||||
return decorator
|
return decorator
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def realm_list(request):
|
def realm_list(request):
|
||||||
user = request.user
|
django_user = request.user
|
||||||
if user.is_superuser:
|
if django_user.is_superuser:
|
||||||
realms = Realm.objects.order_by('name').all()
|
realms = Realm.objects.order_by('name').all()
|
||||||
else:
|
else:
|
||||||
realms = Realm.objects.filter(admin_group__user__username__contains=user.username).order_by('name').order_by(
|
realms = Realm.objects.filter(admin_group__user__username__contains=django_user.username).order_by('name')
|
||||||
'name')
|
|
||||||
show_user = request.GET.get('show_user', False)
|
|
||||||
if show_user or (len(realms) == 0 and not user.is_superuser):
|
|
||||||
try:
|
|
||||||
LdapUser.base_dn = LdapUser.ROOT_DN
|
|
||||||
user = LdapUser.objects.get(username=user.username)
|
|
||||||
realm_base_dn = re.compile('(uid=[a-zA-Z0-9_]*),(ou=[a-zA-Z_]*),(.*)').match(user.dn).group(3)
|
|
||||||
realm = Realm.objects.get(ldap_base_dn=realm_base_dn)
|
|
||||||
|
|
||||||
return redirect('user-detail', realm.id, user.dn)
|
return get_users_home_view(request, django_user, realms)
|
||||||
except ObjectDoesNotExist as err:
|
|
||||||
logger.info('Anmeldung fehlgeschlagen', err)
|
|
||||||
return HttpResponse("Invalid login. Please try again.")
|
|
||||||
elif len(realms) == 1:
|
|
||||||
return redirect('realm-detail', realms[0].id)
|
|
||||||
else:
|
|
||||||
realm_wrappers = []
|
|
||||||
for realm in realms:
|
|
||||||
realm_wrappers.append(_get_group_user_count_wrapper(realm))
|
|
||||||
return render(request, 'realm/realm_home.jinja2', {'realms': realms, 'realm_wrappers': realm_wrappers})
|
|
||||||
|
|
||||||
|
|
||||||
def _get_group_user_count_wrapper(realm):
|
|
||||||
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
|
||||||
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
|
||||||
return {'realm': realm, 'group_count': LdapGroup.objects.count(), 'user_count': LdapUser.objects.count()}
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -79,21 +54,21 @@ def realm_add(request):
|
|||||||
try:
|
try:
|
||||||
base_dn_available(ldap_base_dn)
|
base_dn_available(ldap_base_dn)
|
||||||
|
|
||||||
realm_obj = Realm.objects.create(name=name, ldap_base_dn=ldap_base_dn)
|
realm = Realm.objects.create(name=name, ldap_base_dn=ldap_base_dn)
|
||||||
realm_obj.save()
|
realm.save()
|
||||||
return redirect('realm-detail', realm_obj.id)
|
return render_realm_detail_view(request, realm.id, status_code=201)
|
||||||
except IntegrityError as err:
|
except IntegrityError as err:
|
||||||
|
# TODO: Load no extra fail view, use current add view
|
||||||
return render(request, 'realm/realm_add_failed.jinja2',
|
return render(request, 'realm/realm_add_failed.jinja2',
|
||||||
{'realm_name': name, 'error': err})
|
{'realm_name': name, 'error': err}, status=409)
|
||||||
except LDAPError as err:
|
except LDAPError as err:
|
||||||
logger.debug("Ldap Error", err)
|
logger.debug("Ldap Error", err)
|
||||||
return render(request, 'realm/realm_add_failed.jinja2',
|
return render(request, 'realm/realm_add_failed.jinja2',
|
||||||
{'realm_name': name})
|
{'realm_name': name}, status=409)
|
||||||
else:
|
else:
|
||||||
form = RealmAddForm()
|
form = RealmAddForm()
|
||||||
return render(request, 'realm/realm_add.jinja2', {'realms': realms, 'form': form})
|
return render(request, 'realm/realm_add.jinja2', {'realms': realms, 'form': form})
|
||||||
else:
|
return render_permission_denied_view(request)
|
||||||
redirect('permission-denied')
|
|
||||||
|
|
||||||
|
|
||||||
def base_dn_available(base_dn):
|
def base_dn_available(base_dn):
|
||||||
@ -105,28 +80,7 @@ def base_dn_available(base_dn):
|
|||||||
@login_required
|
@login_required
|
||||||
@is_realm_admin
|
@is_realm_admin
|
||||||
def realm_detail(request, realm_id):
|
def realm_detail(request, realm_id):
|
||||||
realm = Realm.objects.get(id=realm_id)
|
return render_realm_detail_view(request, realm_id)
|
||||||
LdapUser.base_dn = realm.ldap_base_dn
|
|
||||||
|
|
||||||
inactive_users = LdapUser.get_inactive_users().count()
|
|
||||||
logger.info(inactive_users)
|
|
||||||
ldap_admin_group, ldap_default_group = get_default_admin_group(realm)
|
|
||||||
|
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
|
||||||
{'realm': realm, 'ldap_admin_group': ldap_admin_group, 'ldap_default_group': ldap_default_group,
|
|
||||||
'inactive_user_count': inactive_users, 'users_count': LdapUser.objects.all().count()})
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_admin_group(realm):
|
|
||||||
ldap_admin_group = None
|
|
||||||
ldap_default_group = None
|
|
||||||
if realm.admin_group:
|
|
||||||
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
|
||||||
ldap_admin_group = LdapGroup.objects.get(name=realm.admin_group.name)
|
|
||||||
if realm.default_group:
|
|
||||||
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
|
||||||
ldap_default_group = LdapGroup.objects.get(name=realm.default_group.name)
|
|
||||||
return ldap_admin_group, ldap_default_group
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -134,19 +88,17 @@ def get_default_admin_group(realm):
|
|||||||
def realm_update(request, realm_id):
|
def realm_update(request, realm_id):
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
realm = Realm.objects.get(id=realm_id)
|
realm = Realm.objects.get(id=realm_id)
|
||||||
|
|
||||||
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
ldap_admin_group = None
|
ldap_admin_group = None if not realm.admin_group else LdapGroup.objects.get(name=realm.admin_group.name)
|
||||||
if realm.admin_group:
|
ldap_default_group = None if not realm.default_group else LdapGroup.objects.get(name=realm.default_group.name)
|
||||||
ldap_admin_group = LdapGroup.objects.get(name=realm.admin_group.name)
|
|
||||||
ldap_default_group = None
|
form_data = {'id': realm.id,
|
||||||
if realm.default_group:
|
'ldap_base_dn': realm.ldap_base_dn,
|
||||||
ldap_default_group = LdapGroup.objects.get(name=realm.default_group.name)
|
'name': realm.name,
|
||||||
data = {'id': realm.id,
|
'email': realm.email,
|
||||||
'ldap_base_dn': realm.ldap_base_dn,
|
'admin_group': ldap_admin_group,
|
||||||
'name': realm.name,
|
'default_group': ldap_default_group}
|
||||||
'email': realm.email,
|
|
||||||
'admin_group': ldap_admin_group,
|
|
||||||
'default_group': ldap_default_group}
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
form = RealmUpdateForm(request.POST)
|
form = RealmUpdateForm(request.POST)
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
@ -154,23 +106,16 @@ def realm_update(request, realm_id):
|
|||||||
realm.ldap_base_dn = form.cleaned_data['ldap_base_dn']
|
realm.ldap_base_dn = form.cleaned_data['ldap_base_dn']
|
||||||
realm.email = form.cleaned_data['email']
|
realm.email = form.cleaned_data['email']
|
||||||
admin_ldap_group = form.cleaned_data['admin_group']
|
admin_ldap_group = form.cleaned_data['admin_group']
|
||||||
if admin_ldap_group:
|
realm.admin_group = None if not admin_ldap_group else admin_ldap_group.get_django_group()
|
||||||
realm.admin_group, _ = Group.objects.get_or_create(name=admin_ldap_group.name)
|
|
||||||
else:
|
|
||||||
realm.admin_group = None
|
|
||||||
default_ldap_group = form.cleaned_data['default_group']
|
default_ldap_group = form.cleaned_data['default_group']
|
||||||
if default_ldap_group:
|
realm.default_group = None if not default_ldap_group else default_ldap_group.get_django_group()
|
||||||
realm.default_group, _ = Group.objects.get_or_create(name=default_ldap_group.name)
|
|
||||||
else:
|
|
||||||
realm.default_group = None
|
|
||||||
realm.save()
|
realm.save()
|
||||||
return redirect('realm-detail', realm.id)
|
return render_realm_detail_view(request, realm_id, status_code=200)
|
||||||
|
return render(request, 'realm/realm_update.jinja2', {'realm': realm, 'form': form}, status=422)
|
||||||
else:
|
else:
|
||||||
form = RealmUpdateForm(initial=data)
|
form = RealmUpdateForm(initial=form_data)
|
||||||
return render(request, 'realm/realm_update.jinja2', {'realm': realm, 'form': form})
|
return render(request, 'realm/realm_update.jinja2', {'realm': realm, 'form': form})
|
||||||
else:
|
return render_permission_denied_view(request)
|
||||||
realm = Realm.objects.get(id=realm_id)
|
|
||||||
return render(request, 'realm/realm_update.jinja2', {'realm': realm})
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -209,38 +154,27 @@ def realm_delete(request, realm_id):
|
|||||||
|
|
||||||
|
|
||||||
def permission_denied(request):
|
def permission_denied(request):
|
||||||
return render(request, 'permission_denied.jinja2', {})
|
return render_permission_denied_view(request)
|
||||||
|
|
||||||
|
|
||||||
def realm_email_test(request, realm_id):
|
def realm_email_test(request, realm_id):
|
||||||
realm = Realm.objects.get(id=realm_id)
|
realm = Realm.objects.get(id=realm_id)
|
||||||
ldap_admin_group, ldap_default_group = get_default_admin_group(realm)
|
test_msg = f'Du hast die Mail Konfiguration für {realm.name} erfolgreich abgeschlossen.'
|
||||||
|
success_msg = 'Test erfolgreich'
|
||||||
|
error_msg_auth = f'Mail konnte nicht versendet werden, Anmeldedaten inkorrekt.'
|
||||||
|
error_msg_connect = f'Mail konnte nicht versendet werden. Verbindungsaufbau abgelehnt. ' \
|
||||||
|
f'Bitte überprüfen sie die Server Addresse und den Port'
|
||||||
|
error_msg_timeout = f'Mail konnte nicht versendet werden. Zeitüberschreitung beim Verbindungsaufbau. ' \
|
||||||
|
f'Bitte überprüfen sie die Server Addresse und den Port'
|
||||||
|
error_msg_smtp = f'Mail konnte nicht versendet werden. Bitte kontaktieren sie den Administrator'
|
||||||
try:
|
try:
|
||||||
realm_send_mail(realm, realm.email, f'{realm.name} Test Mail',
|
realm_send_mail(realm, realm.email, f'{realm.name} Test Mail', test_msg)
|
||||||
f'Du hast die Mail Konfiguration für {realm.name} erfolgreich abgeschlossen.')
|
except SMTPAuthenticationError:
|
||||||
except SMTPAuthenticationError as err:
|
return render_realm_detail_view(request, realm_id, error_headline="Testmail", error_text=error_msg_auth)
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
except SMTPConnectError:
|
||||||
{'realm': realm, 'error': f'Mail konnte nicht versendet werden, Anmeldedaten inkorrekt.',
|
return render_realm_detail_view(request, realm_id, error_headline="Testmail", error_text=error_msg_connect)
|
||||||
'ldap_admin_group': ldap_admin_group,
|
except timeout:
|
||||||
'ldap_default_group': ldap_default_group})
|
return render_realm_detail_view(request, realm_id, error_headline="Testmail", error_text=error_msg_timeout)
|
||||||
except SMTPConnectError as err:
|
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
|
||||||
{'realm': realm,
|
|
||||||
'error': f'Mail konnte nicht versendet werden. Verbindungsaufbau abgelehnt. Bitte überprüfen sie die Server Addresse und den Port',
|
|
||||||
'ldap_admin_group': ldap_admin_group,
|
|
||||||
'ldap_default_group': ldap_default_group})
|
|
||||||
except timeout as err:
|
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
|
||||||
{'realm': realm,
|
|
||||||
'error': f'Mail konnte nicht versendet werden. Zeitüberschreitung beim Verbindungsaufbau. Bitte überprüfen sie die Server Addresse und den Port',
|
|
||||||
'ldap_admin_group': ldap_admin_group,
|
|
||||||
'ldap_default_group': ldap_default_group})
|
|
||||||
except SMTPException:
|
except SMTPException:
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
return render_realm_detail_view(request, realm_id, error_headline="Testmail", error_text=error_msg_smtp)
|
||||||
{'realm': realm,
|
return render_realm_detail_view(request, realm_id, success_headline="Testmail", success_text=success_msg)
|
||||||
'error': f'Mail konnte nicht versendet werden. Bitte kontaktieren sie den Administrator',
|
|
||||||
'ldap_admin_group': ldap_admin_group,
|
|
||||||
'ldap_default_group': ldap_default_group})
|
|
||||||
return render(request, 'realm/realm_detailed.jinja2',
|
|
||||||
{'realm': realm, 'notice': 'Test erfolgreich', 'ldap_admin_group': ldap_admin_group,
|
|
||||||
'ldap_default_group': ldap_default_group})
|
|
||||||
|
|||||||
@ -4,17 +4,22 @@ import os
|
|||||||
import re
|
import re
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User, Group
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db import OperationalError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from ldap import NO_SUCH_OBJECT, ALREADY_EXISTS
|
from ldap import NO_SUCH_OBJECT, ALREADY_EXISTS
|
||||||
from ldapdb.models import fields as ldap_fields
|
from ldapdb.models import fields as ldap_fields
|
||||||
from ldapdb.models.base import Model
|
from ldapdb.models.base import Model
|
||||||
|
|
||||||
|
from account_helper.models import DeletedUser
|
||||||
|
from account_manager.utils.dbldap import get_filterstr
|
||||||
from account_manager.utils.mail_utils import send_welcome_mail
|
from account_manager.utils.mail_utils import send_welcome_mail
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
import ldap
|
||||||
|
|
||||||
|
|
||||||
class LdapUser(Model):
|
class LdapUser(Model):
|
||||||
"""
|
"""
|
||||||
@ -57,12 +62,29 @@ class LdapUser(Model):
|
|||||||
else:
|
else:
|
||||||
raise ALREADY_EXISTS('User already exists')
|
raise ALREADY_EXISTS('User already exists')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_extended_user(ldap_user):
|
||||||
|
wrapper = {'user': ldap_user}
|
||||||
|
try:
|
||||||
|
wrapper['deleted_user'] = DeletedUser.objects.get(ldap_dn=ldap_user.dn)
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
wrapper['deleted_user'] = {}
|
||||||
|
try:
|
||||||
|
django_user = User.objects.get(username=ldap_user.username)
|
||||||
|
if django_user.last_login:
|
||||||
|
wrapper['active'] = True
|
||||||
|
else:
|
||||||
|
wrapper['active'] = False
|
||||||
|
except ObjectDoesNotExist:
|
||||||
|
wrapper['active'] = False
|
||||||
|
return wrapper
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def password_reset(user, raw_password):
|
def password_reset(user, raw_password):
|
||||||
LdapUser.base_dn = LdapUser.ROOT_DN
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
ldap_user = LdapUser.objects.get(username=user.username)
|
ldap_user = LdapUser.objects.get(username=user.username)
|
||||||
ldap_user.password = raw_password
|
ldap_user.password = raw_password
|
||||||
LdapUser.base_dn = re.compile('(uid=[a-zA-Z0-9_]*),(.*)').match(ldap_user.dn).group(2)
|
LdapUser.base_dn = re.compile('(uid=[a-zA-Z0-9_-]*),(.*)').match(ldap_user.dn).group(2)
|
||||||
ldap_user.save()
|
ldap_user.save()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -110,6 +132,13 @@ class LdapUser(Model):
|
|||||||
return (LdapUser.objects.filter(last_login__lte=last_semester) | LdapUser.objects.exclude(
|
return (LdapUser.objects.filter(last_login__lte=last_semester) | LdapUser.objects.exclude(
|
||||||
last_login__lte=datetime.now() + timedelta(days=1)))
|
last_login__lte=datetime.now() + timedelta(days=1)))
|
||||||
|
|
||||||
|
def get_users_realm_base_dn(self):
|
||||||
|
return re.compile('(uid=[a-zA-Z0-9_-]*),(ou=[a-zA-Z_-]*),(.*)').match(self.dn).group(3)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_root_dn(realm):
|
||||||
|
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
||||||
|
|
||||||
|
|
||||||
class LdapGroup(Model):
|
class LdapGroup(Model):
|
||||||
"""
|
"""
|
||||||
@ -130,6 +159,24 @@ class LdapGroup(Model):
|
|||||||
LdapGroup.base_dn = group_base_dn
|
LdapGroup.base_dn = group_base_dn
|
||||||
return LdapGroup.objects.filter(members=user.dn)
|
return LdapGroup.objects.filter(members=user.dn)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def remove_user_from_groups(ldap_user_dn, user_groups=None):
|
||||||
|
if not user_groups:
|
||||||
|
LdapGroup.base_dn = LdapGroup.ROOT_DN
|
||||||
|
user_groups = LdapGroup.objects.filter(members__contains=ldap_user_dn)
|
||||||
|
for group in user_groups:
|
||||||
|
LdapGroup.base_dn = re.compile('cn=([a-zA-Z0-9_-]*),(ou=[a-zA-Z_]*.*)').match(group.dn).group(2)
|
||||||
|
group.members.remove(ldap_user_dn)
|
||||||
|
group.save()
|
||||||
|
|
||||||
|
def get_django_group(self):
|
||||||
|
django_group, _ = Group.objects.get_or_create(name=self.name)
|
||||||
|
return django_group
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def set_root_dn(realm):
|
||||||
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|||||||
0
src/account_manager/tests/__init__.py
Normal file
0
src/account_manager/tests/__init__.py
Normal file
0
src/account_manager/tests/test_forms.py
Normal file
0
src/account_manager/tests/test_forms.py
Normal file
@ -1,3 +1,3 @@
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
# Create your tests here.
|
# Create your tests here.
|
||||||
430
src/account_manager/tests/test_views.py
Normal file
430
src/account_manager/tests/test_views.py
Normal file
@ -0,0 +1,430 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from django.contrib.auth.models import User, Group
|
||||||
|
from django.test import TestCase
|
||||||
|
# Create your tests here.
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from account_helper.models import Realm
|
||||||
|
from account_manager.models import LdapUser, LdapGroup
|
||||||
|
|
||||||
|
|
||||||
|
class RealmHomeViewTest(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
# User.objects.get_or_create(username="test", email="test@test.de")
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='test_superuser',
|
||||||
|
password=RealmHomeViewTest.get_password(),
|
||||||
|
email='test@test.de',
|
||||||
|
is_staff=True,
|
||||||
|
is_superuser=True,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_ldap_objects(self):
|
||||||
|
self.realm_1, _ = Realm.objects.get_or_create(name="test_realm_1",
|
||||||
|
ldap_base_dn="ou=test,ou=fachschaften,dc=test,dc=de")
|
||||||
|
self.realm_2, _ = Realm.objects.get_or_create(name="test_realm_2",
|
||||||
|
ldap_base_dn="ou=test2,ou=fachschaften,dc=test,dc=de")
|
||||||
|
LdapUser.set_root_dn(self.realm_1)
|
||||||
|
self.ldap_user_multiple_admin, _ = LdapUser.objects.get_or_create(username="test_multi_admin",
|
||||||
|
email="test@test.de",
|
||||||
|
password=RealmHomeViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
self.ldap_user_admin, _ = LdapUser.objects.get_or_create(username="test_admin", email="test@test.de",
|
||||||
|
password=RealmHomeViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
self.ldap_user, _ = LdapUser.objects.get_or_create(username="test", email="test@test.de",
|
||||||
|
password=RealmHomeViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_1_ldap_group = LdapGroup.objects.create(name="test_realm_1_admin_group",
|
||||||
|
members=[self.ldap_user_multiple_admin.dn,
|
||||||
|
self.ldap_user_admin.dn])
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_2_ldap_group = LdapGroup.objects.create(name="test_realm_2_admin_group",
|
||||||
|
members=[self.ldap_user_multiple_admin.dn])
|
||||||
|
logging.disable(logging.DEBUG)
|
||||||
|
self.realm_1.admin_group = self.realm_1_ldap_group.get_django_group()
|
||||||
|
self.realm_1.save()
|
||||||
|
self.realm_2.admin_group = self.realm_2_ldap_group.get_django_group()
|
||||||
|
self.realm_2.save()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_password(cls):
|
||||||
|
return "12345678"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.create_ldap_objects()
|
||||||
|
self.django_superuser = User.objects.get(username="test_superuser")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.clear_ldap_objects()
|
||||||
|
self.django_superuser.delete()
|
||||||
|
logging.disable(logging.NOTSET)
|
||||||
|
|
||||||
|
def clear_ldap_objects(self):
|
||||||
|
self.realm_1.delete()
|
||||||
|
self.realm_2.delete()
|
||||||
|
self.ldap_user_multiple_admin.delete()
|
||||||
|
self.ldap_user_admin.delete()
|
||||||
|
self.ldap_user.delete()
|
||||||
|
self.realm_1_ldap_group.delete()
|
||||||
|
self.realm_2_ldap_group.delete()
|
||||||
|
|
||||||
|
def test_without_login(self):
|
||||||
|
response = self.client.get(reverse('realm-home'))
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_with_user_login(self):
|
||||||
|
self.client.login(username=self.ldap_user.username, password=RealmHomeViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-home'))
|
||||||
|
self.assertContains(response, 'Profil löschen', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_admin_login(self):
|
||||||
|
self.client.login(username=self.ldap_user_admin.username, password=RealmHomeViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-home'))
|
||||||
|
self.assertContains(response, 'Bereich ', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_admin_multiple_realms_login(self):
|
||||||
|
self.client.login(username=self.ldap_user_multiple_admin.username, password=RealmHomeViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-home'))
|
||||||
|
self.assertContains(response, 'Bereiche', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_superuser_login(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password=RealmHomeViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-home'))
|
||||||
|
self.assertContains(response, 'Bereiche', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
|
||||||
|
class RealmAddViewTest(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
realm, _ = Realm.objects.get_or_create(name="test", ldap_base_dn="ou=test,ou=fachschaften,dc=test,dc=de")
|
||||||
|
LdapUser.set_root_dn(realm)
|
||||||
|
LdapUser.objects.get_or_create(username="test", email="test@test.de",
|
||||||
|
password=RealmAddViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
User.objects.get_or_create(username="test", email="test@test.de")
|
||||||
|
logging.disable(logging.DEBUG)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_password(cls):
|
||||||
|
return "12345678"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.realm = Realm.objects.get(name="test")
|
||||||
|
LdapUser.set_root_dn(self.realm)
|
||||||
|
self.ldap_user = LdapUser.objects.get(username="test")
|
||||||
|
self.django_user = User.objects.get(username="test")
|
||||||
|
self.django_superuser = User.objects.create_superuser(
|
||||||
|
username='superuser_test',
|
||||||
|
password='test',
|
||||||
|
email='test@test.de',
|
||||||
|
is_staff=True,
|
||||||
|
is_superuser=True,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.realm.delete()
|
||||||
|
self.ldap_user.delete()
|
||||||
|
self.django_user.delete()
|
||||||
|
logging.disable(logging.NOTSET)
|
||||||
|
|
||||||
|
def test_without_login(self):
|
||||||
|
response = self.client.get(reverse('realm-add'))
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_with_login(self):
|
||||||
|
self.client.login(username=self.ldap_user.username, password=RealmAddViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-add'))
|
||||||
|
self.assertContains(response, 'Leider hast du keine Rechte', status_code=403)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_login_and_post_valid_form(self):
|
||||||
|
self.client.login(username=self.ldap_user.username, password=RealmAddViewTest.get_password())
|
||||||
|
response = self.client.post(reverse('realm-add'),
|
||||||
|
{'name': 'test', 'ldap_base_dn': 'ou=test,ou=fachschaften,dc=test,dc=de'})
|
||||||
|
self.assertContains(response, 'Leider hast du keine Rechte', status_code=403)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_super_user_login(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password='test')
|
||||||
|
response = self.client.get(reverse('realm-add'))
|
||||||
|
self.assertContains(response, 'Neuen Bereich anlegen', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_super_user_login_add_realm(self):
|
||||||
|
realm = Realm.objects.get(name=self.realm.name)
|
||||||
|
realm.delete()
|
||||||
|
self.client.login(username=self.django_superuser.username, password='test')
|
||||||
|
response = self.client.post(reverse('realm-add'),
|
||||||
|
{'name': 'test', 'ldap_base_dn': 'ou=test,ou=fachschaften,dc=test,dc=de'})
|
||||||
|
self.assertContains(response, 'Bereich test', status_code=201)
|
||||||
|
self.client.logout()
|
||||||
|
self.realm, _ = Realm.objects.get_or_create(name="test", ldap_base_dn="ou=test,ou=fachschaften,dc=test,dc=de")
|
||||||
|
|
||||||
|
def test_with_super_user_login_add_extisting_realm(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password='test')
|
||||||
|
response = self.client.post(reverse('realm-add'),
|
||||||
|
{'name': 'test', 'ldap_base_dn': 'ou=test,ou=fachschaften,dc=test,dc=de'})
|
||||||
|
self.assertContains(response, 'Das hinzufügen des Bereichs ist fehlgeschlagen.', status_code=409)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_super_user_login_add_extisting_realm_with_different_name(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password='test')
|
||||||
|
response = self.client.post(reverse('realm-add'),
|
||||||
|
{'name': 'test_new', 'ldap_base_dn': 'ou=test,ou=fachschaften,dc=test,dc=de'})
|
||||||
|
self.assertContains(response, 'Das hinzufügen des Bereichs ist fehlgeschlagen.', status_code=409)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_super_user_login_add_realm_with_not_existing_ldap_base_dn(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password='test')
|
||||||
|
response = self.client.post(reverse('realm-add'),
|
||||||
|
{'name': 'test_not_extisting_ldap_dn',
|
||||||
|
'ldap_base_dn': 'ou=not_exists,ou=fachschaften,dc=test,dc=de'})
|
||||||
|
|
||||||
|
self.assertContains(response, 'Das hinzufügen des Bereichs ist fehlgeschlagen.', status_code=409)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
|
||||||
|
class RealmDetailViewTest(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
# User.objects.get_or_create(username="test", email="test@test.de")
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='test_superuser',
|
||||||
|
password=RealmDetailViewTest.get_password(),
|
||||||
|
email='test@test.de',
|
||||||
|
is_staff=True,
|
||||||
|
is_superuser=True,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_ldap_objects(self):
|
||||||
|
self.realm_1, _ = Realm.objects.get_or_create(name="test_realm_1",
|
||||||
|
ldap_base_dn="ou=test,ou=fachschaften,dc=test,dc=de")
|
||||||
|
|
||||||
|
LdapUser.set_root_dn(self.realm_1)
|
||||||
|
self.ldap_user_admin, _ = LdapUser.objects.get_or_create(username="test_admin", email="test@test.de",
|
||||||
|
password=RealmDetailViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
self.ldap_user, _ = LdapUser.objects.get_or_create(username="test", email="test@test.de",
|
||||||
|
password=RealmDetailViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_1_ldap_group = LdapGroup.objects.create(name="test_realm_1_admin_group",
|
||||||
|
members=[self.ldap_user_admin.dn])
|
||||||
|
|
||||||
|
logging.disable(logging.DEBUG)
|
||||||
|
self.realm_1.admin_group = self.realm_1_ldap_group.get_django_group()
|
||||||
|
self.realm_1.save()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_password(cls):
|
||||||
|
return "12345678"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.create_ldap_objects()
|
||||||
|
self.django_superuser = User.objects.get(username="test_superuser")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.clear_ldap_objects()
|
||||||
|
self.django_superuser.delete()
|
||||||
|
logging.disable(logging.NOTSET)
|
||||||
|
|
||||||
|
def clear_ldap_objects(self):
|
||||||
|
self.realm_1.delete()
|
||||||
|
self.ldap_user_admin.delete()
|
||||||
|
self.ldap_user.delete()
|
||||||
|
self.realm_1_ldap_group.delete()
|
||||||
|
|
||||||
|
def test_without_login(self):
|
||||||
|
response = self.client.get(reverse('realm-detail', args=[self.realm_1.id]))
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_with_user_login(self):
|
||||||
|
self.client.login(username=self.ldap_user.username, password=RealmDetailViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-detail', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, 'Leider hast du keine Rechte', status_code=403)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_admin_login(self):
|
||||||
|
self.client.login(username=self.ldap_user_admin.username, password=RealmDetailViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-detail', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, 'Bereich ', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_superuser_login(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password=RealmDetailViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-detail', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, 'Bereich', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
|
||||||
|
class RealmUpdateViewTest(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
# User.objects.get_or_create(username="test", email="test@test.de")
|
||||||
|
User.objects.create_superuser(
|
||||||
|
username='test_superuser',
|
||||||
|
password=RealmUpdateViewTest.get_password(),
|
||||||
|
email='test@test.de',
|
||||||
|
is_staff=True,
|
||||||
|
is_superuser=True,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_ldap_objects(self):
|
||||||
|
self.realm_1, _ = Realm.objects.get_or_create(name="test_realm_1",
|
||||||
|
ldap_base_dn="ou=test,ou=fachschaften,dc=test,dc=de",
|
||||||
|
email="test.realm@test.de")
|
||||||
|
self.realm_2, _ = Realm.objects.get_or_create(name="test_realm_2",
|
||||||
|
ldap_base_dn="ou=test2,ou=fachschaften,dc=test,dc=de")
|
||||||
|
LdapUser.set_root_dn(self.realm_1)
|
||||||
|
self.ldap_user_multiple_admin, _ = LdapUser.objects.get_or_create(username="test_multi_admin",
|
||||||
|
email="test@test.de",
|
||||||
|
password=RealmUpdateViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
self.ldap_user_admin, _ = LdapUser.objects.get_or_create(username="test_admin", email="test@test.de",
|
||||||
|
password=RealmUpdateViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
self.ldap_user, _ = LdapUser.objects.get_or_create(username="test", email="test@test.de",
|
||||||
|
password=RealmUpdateViewTest.get_password(),
|
||||||
|
first_name="max",
|
||||||
|
last_name="musterstudent")
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_1_ldap_group = LdapGroup.objects.create(name="test_realm_1_admin_group",
|
||||||
|
members=[self.ldap_user_multiple_admin.dn,
|
||||||
|
self.ldap_user_admin.dn])
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_2_ldap_group = LdapGroup.objects.create(name="test_realm_2_admin_group",
|
||||||
|
members=[self.ldap_user_multiple_admin.dn])
|
||||||
|
LdapGroup.set_root_dn(self.realm_1)
|
||||||
|
self.realm_3_ldap_group = LdapGroup.objects.create(name="test_realm_3_admin_group",
|
||||||
|
members=[self.ldap_user_admin.dn])
|
||||||
|
logging.disable(logging.DEBUG)
|
||||||
|
self.realm_1.admin_group = self.realm_1_ldap_group.get_django_group()
|
||||||
|
self.realm_1.save()
|
||||||
|
self.realm_2.admin_group = self.realm_2_ldap_group.get_django_group()
|
||||||
|
self.realm_2.save()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_password(cls):
|
||||||
|
return "12345678"
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.create_ldap_objects()
|
||||||
|
self.django_superuser = User.objects.get(username="test_superuser")
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
self.clear_ldap_objects()
|
||||||
|
self.django_superuser.delete()
|
||||||
|
logging.disable(logging.NOTSET)
|
||||||
|
|
||||||
|
def clear_ldap_objects(self):
|
||||||
|
self.realm_1.delete()
|
||||||
|
self.realm_2.delete()
|
||||||
|
self.ldap_user_multiple_admin.delete()
|
||||||
|
self.ldap_user_admin.delete()
|
||||||
|
self.ldap_user.delete()
|
||||||
|
self.realm_1_ldap_group.delete()
|
||||||
|
self.realm_2_ldap_group.delete()
|
||||||
|
self.realm_3_ldap_group.delete()
|
||||||
|
|
||||||
|
def test_without_login(self):
|
||||||
|
response = self.client.get(reverse('realm-update', args=[self.realm_1.id]))
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_with_user_login(self):
|
||||||
|
self.client.login(username=self.ldap_user.username, password=RealmUpdateViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-update', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, 'Leider hast du keine Rechte', status_code=403)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_admin_login(self):
|
||||||
|
self.client.login(username=self.ldap_user_admin.username, password=RealmUpdateViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-update', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, 'Leider hast du keine Rechte', status_code=403)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_superuser_login(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password=RealmUpdateViewTest.get_password())
|
||||||
|
response = self.client.get(reverse('realm-update', args=[self.realm_1.id]))
|
||||||
|
self.assertContains(response, '<label for="id_name">Bereichsname</label>', status_code=200)
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_superuser_login_post_single_changes(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password=RealmUpdateViewTest.get_password())
|
||||||
|
new_name = "new test realm"
|
||||||
|
new_email = "newtest@test.de"
|
||||||
|
new_admin_group = self.realm_1_ldap_group
|
||||||
|
new_default_group = self.realm_3_ldap_group
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name, 'email': new_email,
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn})
|
||||||
|
self.assertContains(response, 'Nutzeranzahl', status_code=200)
|
||||||
|
self.realm_1.refresh_from_db()
|
||||||
|
self.assertEqual(self.realm_1.name, new_name)
|
||||||
|
self.assertEqual(self.realm_1.email, new_email)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name, 'email': new_email,
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn, 'admin_group': new_admin_group.name})
|
||||||
|
self.assertContains(response, 'Nutzeranzahl', status_code=200)
|
||||||
|
self.realm_1.refresh_from_db()
|
||||||
|
django_group = Group.objects.get(name=new_admin_group.name)
|
||||||
|
self.assertEqual(self.realm_1.admin_group, django_group)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name, 'email': new_email,
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn,
|
||||||
|
'default_group': new_default_group.name})
|
||||||
|
self.assertContains(response, 'Nutzeranzahl', status_code=200)
|
||||||
|
self.realm_1.refresh_from_db()
|
||||||
|
django_group = Group.objects.get(name=new_default_group.name)
|
||||||
|
self.assertEqual(self.realm_1.default_group, django_group)
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
|
|
||||||
|
def test_with_superuser_login_post_with_missing_data(self):
|
||||||
|
self.client.login(username=self.django_superuser.username, password=RealmUpdateViewTest.get_password())
|
||||||
|
new_name = "new test realm"
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name,
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn})
|
||||||
|
self.assertContains(response, '<label for="id_name">Bereichsname</label>', status_code=422)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'email': "test@test.de",
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn})
|
||||||
|
self.assertContains(response, '<label for="id_name">Bereichsname</label>', status_code=422)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name, 'email': "test@test.de"})
|
||||||
|
self.assertContains(response, '<label for="id_name">Bereichsname</label>', status_code=422)
|
||||||
|
|
||||||
|
response = self.client.post(reverse('realm-update', args=[self.realm_1.id]),
|
||||||
|
{'name': new_name, 'email': "abc",
|
||||||
|
'ldap_base_dn': self.realm_1.ldap_base_dn})
|
||||||
|
self.assertContains(response, '<label for="id_name">Bereichsname</label>', status_code=422)
|
||||||
|
|
||||||
|
self.client.logout()
|
||||||
@ -53,6 +53,8 @@ urlpatterns = [
|
|||||||
name='realm-multiple-user-delete'),
|
name='realm-multiple-user-delete'),
|
||||||
path('realm/<int:realm_id>/user/delete/multiple/inactive/', user_views.realm_multiple_user_delete_inactive,
|
path('realm/<int:realm_id>/user/delete/multiple/inactive/', user_views.realm_multiple_user_delete_inactive,
|
||||||
name='realm-multiple-user-delete-inactive'),
|
name='realm-multiple-user-delete-inactive'),
|
||||||
|
path('realm/<int:realm_id>/user/delete/<str:user_dn>/cancel/', user_views.realm_user_delete_cancel,
|
||||||
|
name='realm-user-delete-cancel'),
|
||||||
|
|
||||||
# Realm Group
|
# Realm Group
|
||||||
path('realm/<int:realm_id>/groups/', group_views.realm_groups, name='realm-group-list'),
|
path('realm/<int:realm_id>/groups/', group_views.realm_groups, name='realm-group-list'),
|
||||||
@ -78,6 +80,8 @@ urlpatterns = [
|
|||||||
name='user-delete'),
|
name='user-delete'),
|
||||||
path('accounts/reset/<uidb64>/<token>/', user_views.LdapPasswordResetConfirmView.as_view(),
|
path('accounts/reset/<uidb64>/<token>/', user_views.LdapPasswordResetConfirmView.as_view(),
|
||||||
name='ldap_password_reset_confirm'),
|
name='ldap_password_reset_confirm'),
|
||||||
|
path('accounts/password_change/secure/', user_views.password_change_controller,
|
||||||
|
name='password_change_controller'),
|
||||||
path('accounts/password_change/', user_views.LdapPasswordChangeView.as_view(),
|
path('accounts/password_change/', user_views.LdapPasswordChangeView.as_view(),
|
||||||
name='password_change'),
|
name='password_change'),
|
||||||
|
|
||||||
|
|||||||
7
src/account_manager/utils/django_user.py
Normal file
7
src/account_manager/utils/django_user.py
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
|
def update_dajngo_user(ldap_user):
|
||||||
|
user, _ = User.objects.get_or_create(username=ldap_user.username)
|
||||||
|
user.email = ldap_user.email
|
||||||
|
user.save()
|
||||||
@ -8,6 +8,7 @@ from django.contrib.auth.tokens import default_token_generator
|
|||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
from django.utils.encoding import force_bytes
|
from django.utils.encoding import force_bytes
|
||||||
from django.utils.http import urlsafe_base64_encode
|
from django.utils.http import urlsafe_base64_encode
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from core.settings import EMAIL_HOST, EMAIL_PORT, EMAIL_USE_SSL, EMAIL_USE_TLS
|
from core.settings import EMAIL_HOST, EMAIL_PORT, EMAIL_USE_SSL, EMAIL_USE_TLS
|
||||||
|
|
||||||
@ -44,3 +45,14 @@ def send_welcome_mail(domain, email, protocol, realm, user):
|
|||||||
# TODO failure handling
|
# TODO failure handling
|
||||||
p1 = Process(target=realm_send_mail, args=(realm, user.email, mail_subject, message))
|
p1 = Process(target=realm_send_mail, args=(realm, user.email, mail_subject, message))
|
||||||
p1.start()
|
p1.start()
|
||||||
|
|
||||||
|
|
||||||
|
def send_deletion_mail(realm, user):
|
||||||
|
mail_subject = 'Aktiviere deinen StuVe Account'
|
||||||
|
message = render_to_string('registration/deletion_information_email.jinja2', {
|
||||||
|
'user': user,
|
||||||
|
'deletion_wait_days': settings.DELETION_WAIT_DAYS,
|
||||||
|
})
|
||||||
|
# TODO failure handling
|
||||||
|
p1 = Process(target=realm_send_mail, args=(realm, user.email, mail_subject, message))
|
||||||
|
p1.start()
|
||||||
|
|||||||
62
src/account_manager/utils/main_views.py
Normal file
62
src/account_manager/utils/main_views.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from account_helper.models import Realm
|
||||||
|
from account_manager.models import LdapUser, LdapGroup
|
||||||
|
from account_manager.utils.user_views import render_user_detail_view
|
||||||
|
|
||||||
|
|
||||||
|
def render_realm_detail_view(request, realm_id, success_headline=None, success_text=None, error_headline=None,
|
||||||
|
error_text=None, status_code=200):
|
||||||
|
realm = Realm.objects.get(id=realm_id)
|
||||||
|
LdapUser.base_dn = realm.ldap_base_dn
|
||||||
|
inactive_users = LdapUser.get_inactive_users().count()
|
||||||
|
ldap_admin_group, ldap_default_group = get_default_admin_group(realm)
|
||||||
|
return render(request, 'realm/realm_detailed.jinja2',
|
||||||
|
{'realm': realm,
|
||||||
|
'ldap_admin_group': ldap_admin_group,
|
||||||
|
'ldap_default_group': ldap_default_group,
|
||||||
|
'inactive_user_count': inactive_users,
|
||||||
|
'users_count': LdapUser.objects.all().count(),
|
||||||
|
'success_headline': success_headline,
|
||||||
|
'success_text': success_text,
|
||||||
|
'error_headline': error_headline,
|
||||||
|
'error_text': error_text}, status=status_code)
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_admin_group(realm):
|
||||||
|
ldap_admin_group = None
|
||||||
|
ldap_default_group = None
|
||||||
|
if realm.admin_group:
|
||||||
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
|
ldap_admin_group = LdapGroup.objects.get(name=realm.admin_group.name)
|
||||||
|
if realm.default_group:
|
||||||
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
|
ldap_default_group = LdapGroup.objects.get(name=realm.default_group.name)
|
||||||
|
return ldap_admin_group, ldap_default_group
|
||||||
|
|
||||||
|
|
||||||
|
def render_permission_denied_view(request):
|
||||||
|
return render(request, 'permission_denied.jinja2', {}, status=403)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_user_count_wrapper(realm):
|
||||||
|
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
||||||
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
|
return {'realm': realm, 'group_count': LdapGroup.objects.count(), 'user_count': LdapUser.objects.count()}
|
||||||
|
|
||||||
|
|
||||||
|
def get_users_home_view(request, django_user, realms):
|
||||||
|
show_user = request.GET.get('show_user', False)
|
||||||
|
if show_user or (len(realms) == 0 and not django_user.is_superuser):
|
||||||
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
|
ldap_user = LdapUser.objects.get(username=django_user.username)
|
||||||
|
realm = Realm.objects.get(ldap_base_dn=ldap_user.get_users_realm_base_dn())
|
||||||
|
|
||||||
|
return render_user_detail_view(request, realm, ldap_user)
|
||||||
|
elif len(realms) == 1:
|
||||||
|
return render_realm_detail_view(request, realms[0].id)
|
||||||
|
else:
|
||||||
|
realm_wrappers = []
|
||||||
|
for realm in realms:
|
||||||
|
realm_wrappers.append(get_group_user_count_wrapper(realm))
|
||||||
|
return render(request, 'realm/realm_home.jinja2', {'realms': realms, 'realm_wrappers': realm_wrappers})
|
||||||
10
src/account_manager/utils/user_views.py
Normal file
10
src/account_manager/utils/user_views.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
from account_manager.models import LdapUser, LdapGroup
|
||||||
|
|
||||||
|
|
||||||
|
def render_user_detail_view(request, realm, ldap_user):
|
||||||
|
user_wrapper = LdapUser.get_extended_user(ldap_user)
|
||||||
|
LdapGroup.base_dn = LdapGroup.ROOT_DN
|
||||||
|
groups = LdapGroup.objects.filter(members=ldap_user.dn)
|
||||||
|
return render(request, 'user/user_detail.jinja2', {'user': user_wrapper, 'groups': groups, 'realm': realm})
|
||||||
@ -1,5 +1,4 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
|
||||||
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.forms import PasswordResetForm
|
from django.contrib.auth.forms import PasswordResetForm
|
||||||
@ -7,17 +6,26 @@ from django.contrib.auth.models import User
|
|||||||
from django.contrib.auth.views import PasswordResetConfirmView, PasswordChangeView
|
from django.contrib.auth.views import PasswordResetConfirmView, PasswordChangeView
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
|
from django.db import IntegrityError
|
||||||
from django.http import HttpRequest
|
from django.http import HttpRequest
|
||||||
from django.shortcuts import render, redirect
|
from django.shortcuts import render, redirect
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from ldap import ALREADY_EXISTS, OBJECT_CLASS_VIOLATION
|
from ldap import ALREADY_EXISTS, OBJECT_CLASS_VIOLATION
|
||||||
|
from django.urls import reverse
|
||||||
|
from urllib.parse import urlencode
|
||||||
|
|
||||||
from account_helper.models import Realm
|
from account_helper.models import Realm, DeletedUser
|
||||||
from account_manager.forms import AddLDAPUserForm, UserDeleteListForm, UpdateLDAPUserForm, AdminUpdateLDAPUserForm, \
|
from account_manager.forms import AddLDAPUserForm, UserDeleteListForm, UpdateLDAPUserForm, AdminUpdateLDAPUserForm, \
|
||||||
UserGroupListForm
|
UserGroupListForm, LdapPasswordChangeForm
|
||||||
from account_manager.main_views import is_realm_admin
|
from account_manager.main_views import is_realm_admin
|
||||||
from account_manager.models import LdapUser, LdapGroup
|
from account_manager.models import LdapUser, LdapGroup
|
||||||
from account_manager.utils.mail_utils import send_welcome_mail
|
from account_manager.utils.django_user import update_dajngo_user
|
||||||
|
from account_manager.utils.mail_utils import send_welcome_mail, send_deletion_mail
|
||||||
|
|
||||||
|
from django.contrib.auth import logout
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
from account_manager.utils.user_views import render_user_detail_view
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -46,14 +54,7 @@ def realm_user(request, realm_id):
|
|||||||
realm_users = LdapUser.objects.all()
|
realm_users = LdapUser.objects.all()
|
||||||
user_wrappers = []
|
user_wrappers = []
|
||||||
for user in realm_users:
|
for user in realm_users:
|
||||||
try:
|
user_wrappers.append(LdapUser.get_extended_user(user))
|
||||||
django_user = User.objects.get(username=user.username)
|
|
||||||
if django_user.last_login:
|
|
||||||
user_wrappers.append({'user': user, 'active': True})
|
|
||||||
else:
|
|
||||||
user_wrappers.append({'user': user, 'active': False})
|
|
||||||
except ObjectDoesNotExist:
|
|
||||||
user_wrappers.append({'user': user, 'active': False})
|
|
||||||
return render(request, 'realm/realm_user.jinja2', {'realm': realm, 'realm_user': user_wrappers})
|
return render(request, 'realm/realm_user.jinja2', {'realm': realm, 'realm_user': user_wrappers})
|
||||||
|
|
||||||
|
|
||||||
@ -61,24 +62,28 @@ def realm_user(request, realm_id):
|
|||||||
@is_realm_admin
|
@is_realm_admin
|
||||||
@protect_cross_realm_user_access
|
@protect_cross_realm_user_access
|
||||||
def realm_user_detail(request, realm_id, user_dn):
|
def realm_user_detail(request, realm_id, user_dn):
|
||||||
|
return get_rendered_user_details(request, realm_id, user_dn)
|
||||||
|
|
||||||
|
|
||||||
|
def get_rendered_user_details(request, realm_id, user_dn, success_headline=None, success_text=None):
|
||||||
realm = Realm.objects.get(id=realm_id)
|
realm = Realm.objects.get(id=realm_id)
|
||||||
LdapUser.base_dn = realm.ldap_base_dn
|
LdapUser.base_dn = realm.ldap_base_dn
|
||||||
LdapGroup.base_dn = LdapGroup.ROOT_DN
|
LdapGroup.base_dn = LdapGroup.ROOT_DN
|
||||||
|
|
||||||
user = LdapUser.objects.get(dn=user_dn)
|
user = LdapUser.objects.get(dn=user_dn)
|
||||||
|
user_wrapper = LdapUser.get_extended_user(user)
|
||||||
groups = LdapGroup.objects.filter(members=user.dn)
|
groups = LdapGroup.objects.filter(members=user.dn)
|
||||||
return render(request, 'user/realm_user_detail.jinja2', {'user': user, 'groups': groups, 'realm': realm})
|
return render(request, 'user/realm_user_detail.jinja2',
|
||||||
|
{'user': user_wrapper, 'groups': groups, 'realm': realm, 'success_headline': success_headline,
|
||||||
|
'success_text': success_text})
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def user_detail(request, realm_id, user_dn):
|
def user_detail(request, realm_id, user_dn):
|
||||||
realm = Realm.objects.get(id=realm_id)
|
realm = Realm.objects.get(id=realm_id)
|
||||||
LdapUser.base_dn = realm.ldap_base_dn
|
LdapUser.base_dn = realm.ldap_base_dn
|
||||||
LdapGroup.base_dn = LdapGroup.ROOT_DN
|
ldap_user = LdapUser.objects.get(dn=user_dn)
|
||||||
|
|
||||||
user = LdapUser.objects.get(dn=user_dn)
|
return render_user_detail_view(request, realm, ldap_user)
|
||||||
groups = LdapGroup.objects.filter(members=user.dn)
|
|
||||||
return render(request, 'user/user_detail.jinja2', {'user': user, 'groups': groups, 'realm': realm})
|
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -149,7 +154,7 @@ def realm_user_resend_password_reset(request, realm_id, user_dn):
|
|||||||
ldap_user = LdapUser.objects.get(dn=user_dn)
|
ldap_user = LdapUser.objects.get(dn=user_dn)
|
||||||
try:
|
try:
|
||||||
if ldap_user.email:
|
if ldap_user.email:
|
||||||
logger.info("Sending email for to this email:", ldap_user.email)
|
logger.info(f"Sending email to {ldap_user.email}")
|
||||||
form = PasswordResetForm({'email': ldap_user.email})
|
form = PasswordResetForm({'email': ldap_user.email})
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
logger.info('CREATE REQUEST')
|
logger.info('CREATE REQUEST')
|
||||||
@ -162,11 +167,11 @@ def realm_user_resend_password_reset(request, realm_id, user_dn):
|
|||||||
form.save(
|
form.save(
|
||||||
request=pw_reset_request,
|
request=pw_reset_request,
|
||||||
use_https=True,
|
use_https=True,
|
||||||
from_email=os.environ.get('DEFAULT_FROM_EMAIL', 'vergesslich@test.de'),
|
from_email=settings.DEFAULT_FROM_EMAIL,
|
||||||
email_template_name='registration/password_reset_email.html')
|
email_template_name='registration/password_reset_email.html')
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.info('Error')
|
logger.error('Error')
|
||||||
return redirect('realm-user-detail', realm_id, user_dn)
|
return redirect('realm-user-detail', realm_id, user_dn)
|
||||||
|
|
||||||
|
|
||||||
@ -177,13 +182,15 @@ def realm_user_resend_welcome_mail(request, realm_id, user_dn):
|
|||||||
realm = Realm.objects.get(id=realm_id)
|
realm = Realm.objects.get(id=realm_id)
|
||||||
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
||||||
ldap_user = LdapUser.objects.get(dn=user_dn)
|
ldap_user = LdapUser.objects.get(dn=user_dn)
|
||||||
|
update_dajngo_user(ldap_user)
|
||||||
current_site = get_current_site(request)
|
current_site = get_current_site(request)
|
||||||
protocol = 'http'
|
protocol = 'http'
|
||||||
if request.is_secure():
|
if request.is_secure():
|
||||||
protocol = 'https'
|
protocol = 'https'
|
||||||
send_welcome_mail(domain=current_site.domain, email=ldap_user.email, protocol=protocol, realm=realm,
|
send_welcome_mail(domain=current_site.domain, email=ldap_user.email, protocol=protocol, realm=realm,
|
||||||
user=User.objects.get(username=ldap_user.username))
|
user=User.objects.get(username=ldap_user.username))
|
||||||
return redirect('realm-user-detail', realm_id, user_dn)
|
return get_rendered_user_details(request, realm_id, user_dn, success_headline="Willkommensmail",
|
||||||
|
success_text="Willkommensmail erfolgreich versendet.")
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -220,7 +227,24 @@ def realm_user_delete_confirm(request, realm_id, user_dn):
|
|||||||
deletion_link = {'name': 'realm-user-delete', 'args': [realm.id, ldap_user.dn]}
|
deletion_link = {'name': 'realm-user-delete', 'args': [realm.id, ldap_user.dn]}
|
||||||
cancel_link = {'name': 'realm-user-detail', 'args': [realm.id, ldap_user.dn]}
|
cancel_link = {'name': 'realm-user-detail', 'args': [realm.id, ldap_user.dn]}
|
||||||
return render(request, 'user/user_confirm_delete.jinja2',
|
return render(request, 'user/user_confirm_delete.jinja2',
|
||||||
{'realm': realm, 'user': ldap_user, 'deletion_link': deletion_link, 'cancel_link': cancel_link})
|
{'realm': realm, 'user': ldap_user, 'deletion_link': deletion_link, 'cancel_link': cancel_link,
|
||||||
|
'deletion_wait_days': settings.DELETION_WAIT_DAYS})
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@is_realm_admin
|
||||||
|
@protect_cross_realm_user_access
|
||||||
|
def realm_user_delete_cancel(request, realm_id, user_dn):
|
||||||
|
realm = Realm.objects.get(id=realm_id)
|
||||||
|
LdapUser.base_dn = f'ou=people,{realm.ldap_base_dn}'
|
||||||
|
ldap_user = LdapUser.objects.get(dn=user_dn)
|
||||||
|
try:
|
||||||
|
deleted_user = DeletedUser.objects.get(ldap_dn=ldap_user.dn)
|
||||||
|
deleted_user.delete()
|
||||||
|
except ObjectDoesNotExist as err:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return redirect('realm-user-detail', realm_id, user_dn)
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@ -417,7 +441,7 @@ def realm_user_group_update_delete(request, realm_id, user_dn):
|
|||||||
for group_name in group_names:
|
for group_name in group_names:
|
||||||
groups.append(LdapGroup.objects.get(name=group_name))
|
groups.append(LdapGroup.objects.get(name=group_name))
|
||||||
try:
|
try:
|
||||||
ldap_remove_user_from_groups(user_dn, groups)
|
LdapGroup.remove_user_from_groups(user_dn, groups)
|
||||||
except OBJECT_CLASS_VIOLATION as err:
|
except OBJECT_CLASS_VIOLATION as err:
|
||||||
ldap_user, realm_groups_available, user_groups = get_available_given_groups(realm, user_dn)
|
ldap_user, realm_groups_available, user_groups = get_available_given_groups(realm, user_dn)
|
||||||
return render(request, 'user/realm_user_update_groups.jinja2',
|
return render(request, 'user/realm_user_update_groups.jinja2',
|
||||||
@ -454,45 +478,56 @@ def user_update_controller(request, realm, ldap_user, redirect_name, update_view
|
|||||||
|
|
||||||
def user_delete_controller(ldap_user, realm):
|
def user_delete_controller(ldap_user, realm):
|
||||||
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
LdapGroup.base_dn = f'ou=groups,{realm.ldap_base_dn}'
|
||||||
user_groups = LdapGroup.objects.filter(members__contains=ldap_user.dn)
|
|
||||||
ldap_remove_user_from_groups(ldap_user.dn, user_groups)
|
|
||||||
ldap_user.delete()
|
|
||||||
try:
|
try:
|
||||||
django_user = User.objects.get(username=ldap_user.username)
|
django_user = User.objects.get(username=ldap_user.username)
|
||||||
django_user.delete()
|
try:
|
||||||
# TODO user deletion cron
|
DeletedUser.objects.create(user=django_user, ldap_dn=ldap_user.dn)
|
||||||
# DeletedUser.objects.create(user=django_user)
|
send_deletion_mail(realm=realm, user=ldap_user)
|
||||||
|
except IntegrityError as err:
|
||||||
|
pass
|
||||||
|
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
pass
|
pass
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def ldap_remove_user_from_groups(ldap_user, user_groups):
|
|
||||||
for group in user_groups:
|
|
||||||
group.members.remove(ldap_user)
|
|
||||||
group.save()
|
|
||||||
|
|
||||||
|
|
||||||
def ldap_add_user_to_groups(ldap_user, user_groups):
|
def ldap_add_user_to_groups(ldap_user, user_groups):
|
||||||
for group in user_groups:
|
for group in user_groups:
|
||||||
group.members.append(ldap_user)
|
group.members.append(ldap_user)
|
||||||
group.save()
|
group.save()
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def password_change_controller(request):
|
||||||
|
logout(request)
|
||||||
|
base_url = reverse('login')
|
||||||
|
next_param = reverse('password_change')
|
||||||
|
query_string = urlencode({'next': next_param})
|
||||||
|
url = '{}?{}'.format(base_url, query_string)
|
||||||
|
return redirect(url)
|
||||||
|
|
||||||
|
|
||||||
class LdapPasswordResetConfirmView(PasswordResetConfirmView):
|
class LdapPasswordResetConfirmView(PasswordResetConfirmView):
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.save()
|
user = form.save()
|
||||||
password = form.cleaned_data['new_password1']
|
password = form.cleaned_data['new_password1']
|
||||||
LdapUser.base_dn = LdapUser.ROOT_DN
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
LdapUser.password_reset(user, password)
|
LdapUser.password_reset(user, password)
|
||||||
return super().form_valid(form)
|
cached_redirect = super().form_valid(form)
|
||||||
|
user.set_unusable_password()
|
||||||
|
user.save()
|
||||||
|
return cached_redirect
|
||||||
|
|
||||||
|
|
||||||
class LdapPasswordChangeView(PasswordChangeView):
|
class LdapPasswordChangeView(PasswordChangeView):
|
||||||
|
form_class = LdapPasswordChangeForm
|
||||||
|
|
||||||
def form_valid(self, form):
|
def form_valid(self, form):
|
||||||
user = form.save()
|
user = form.save()
|
||||||
password = form.cleaned_data['new_password1']
|
password = form.cleaned_data['new_password1']
|
||||||
LdapUser.base_dn = LdapUser.ROOT_DN
|
LdapUser.base_dn = LdapUser.ROOT_DN
|
||||||
LdapUser.password_reset(user, password)
|
LdapUser.password_reset(user, password)
|
||||||
return super().form_valid(form)
|
cached_request = super().form_valid(form)
|
||||||
|
user.set_unusable_password()
|
||||||
|
user.save()
|
||||||
|
return cached_request
|
||||||
|
|||||||
@ -18,8 +18,9 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|||||||
DOMAIN = os.environ['DOMAIN']
|
DOMAIN = os.environ['DOMAIN']
|
||||||
SITE_NAME = os.environ['SITE_NAME']
|
SITE_NAME = os.environ['SITE_NAME']
|
||||||
SECRET_KEY = os.environ['SECRET_KEY']
|
SECRET_KEY = os.environ['SECRET_KEY']
|
||||||
DEBUG = os.environ.get('DEBUG', 'False') =='True'
|
DEBUG = os.environ.get('DEBUG', 'False') == 'True'
|
||||||
ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split()
|
ALLOWED_HOSTS = os.environ['ALLOWED_HOSTS'].split()
|
||||||
|
DELETION_WAIT_DAYS = int(os.environ.get('DELETION_WAIT_DAYS', "14"))
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
INSTALLED_APPS = [
|
INSTALLED_APPS = [
|
||||||
@ -179,6 +180,8 @@ else:
|
|||||||
EMAIL_TIMEOUT = 15
|
EMAIL_TIMEOUT = 15
|
||||||
EMAIL_HOST = os.environ['EMAIL_HOST']
|
EMAIL_HOST = os.environ['EMAIL_HOST']
|
||||||
EMAIL_PORT = int(os.environ['EMAIL_PORT'])
|
EMAIL_PORT = int(os.environ['EMAIL_PORT'])
|
||||||
|
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER','')
|
||||||
|
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD','')
|
||||||
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'False') == 'True'
|
EMAIL_USE_TLS = os.environ.get('EMAIL_USE_TLS', 'False') == 'True'
|
||||||
EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', 'False') == 'True'
|
EMAIL_USE_SSL = os.environ.get('EMAIL_USE_SSL', 'False') == 'True'
|
||||||
|
|
||||||
@ -217,10 +220,14 @@ LOGGING = {
|
|||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
},
|
},
|
||||||
'django_auth_ldap': {
|
'django_auth_ldap': {
|
||||||
'level': 'WARNING',
|
'level': 'DEBUG',
|
||||||
'handlers': ['console'],
|
'handlers': ['console'],
|
||||||
},
|
},
|
||||||
'django': {
|
'django_ldapdb': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
'handlers': ['console'],
|
||||||
|
},
|
||||||
|
'*': {
|
||||||
'handlers': ['console'],
|
'handlers': ['console'],
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,7 @@ from django.urls import path, include
|
|||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.contrib.auth.decorators import user_passes_test
|
from django.contrib.auth.decorators import user_passes_test
|
||||||
from account_manager.forms import LdapPasswordResetForm
|
from account_manager.forms import LdapPasswordResetForm
|
||||||
|
from account_manager.views.user_views import LdapPasswordChangeView
|
||||||
from .views import about
|
from .views import about
|
||||||
|
|
||||||
login_forbidden = user_passes_test(lambda u: u.is_anonymous(), '/')
|
login_forbidden = user_passes_test(lambda u: u.is_anonymous(), '/')
|
||||||
@ -31,5 +32,6 @@ urlpatterns = [
|
|||||||
auth_views.PasswordResetView.as_view(html_email_template_name='registration/password_reset_email.html',
|
auth_views.PasswordResetView.as_view(html_email_template_name='registration/password_reset_email.html',
|
||||||
form_class=LdapPasswordResetForm),
|
form_class=LdapPasswordResetForm),
|
||||||
name='password_reset'),
|
name='password_reset'),
|
||||||
|
|
||||||
path('accounts/', include('django.contrib.auth.urls')),
|
path('accounts/', include('django.contrib.auth.urls')),
|
||||||
]
|
]
|
||||||
|
|||||||
@ -215,6 +215,21 @@
|
|||||||
color: #6c757d;
|
color: #6c757d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
/* -- Toast -- */
|
||||||
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
.toast {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
right: -250px;
|
||||||
|
width: 250px;
|
||||||
|
min-height: 50px;
|
||||||
|
z-index: 1000;
|
||||||
|
transform: translateX(-280px);
|
||||||
|
transition: transform 2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
/* -- Footer -- */
|
/* -- Footer -- */
|
||||||
/* ------------------------------------------------------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------------------------------------------------------ */
|
||||||
|
|||||||
@ -3,6 +3,10 @@ const TABLE_CLASS = '.data-table';
|
|||||||
const TABLE_CLASS_NO_PAGING = '.data-table-npaging';
|
const TABLE_CLASS_NO_PAGING = '.data-table-npaging';
|
||||||
|
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
|
// Bottstrap Toast
|
||||||
|
$('.toast').toast('show');
|
||||||
|
|
||||||
|
//Datatables
|
||||||
const data_table = $(TABLE_CLASS).DataTable({
|
const data_table = $(TABLE_CLASS).DataTable({
|
||||||
"paging": true,
|
"paging": true,
|
||||||
"pageLength": 10,
|
"pageLength": 10,
|
||||||
|
|||||||
@ -65,6 +65,7 @@
|
|||||||
<script src="{{ static('libs/DataTables/DataTables-1.10.18/js/jquery.dataTables.js') }}"></script>
|
<script src="{{ static('libs/DataTables/DataTables-1.10.18/js/jquery.dataTables.js') }}"></script>
|
||||||
<script src="{{ static('libs/DataTables/RowReorder-1.2.4/js/dataTables.rowReorder.min.js') }}"></script>
|
<script src="{{ static('libs/DataTables/RowReorder-1.2.4/js/dataTables.rowReorder.min.js') }}"></script>
|
||||||
<script src="{{ static('libs/DataTables/Responsive-2.2.2/js/dataTables.responsive.min.js') }}"></script>
|
<script src="{{ static('libs/DataTables/Responsive-2.2.2/js/dataTables.responsive.min.js') }}"></script>
|
||||||
|
<script src="{{ static('libs/bootstrap-4.3.1-dist/js/bootstrap.min.js') }}"></script>
|
||||||
<script src="{{ static('js/main.js') }}"></script>
|
<script src="{{ static('js/main.js') }}"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@ -36,11 +36,12 @@
|
|||||||
<th scope="col">Nachname</th>
|
<th scope="col">Nachname</th>
|
||||||
<th scope="col">Aktiv</th>
|
<th scope="col">Aktiv</th>
|
||||||
<th scope="col">Letzer Login</th>
|
<th scope="col">Letzer Login</th>
|
||||||
|
<th scope="col">Löschdatum</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% for user in users %}
|
{% for user in users %}
|
||||||
<tr>
|
<tr class="{% if user.deleted_user %}bg-warning{% endif %}">
|
||||||
<td>
|
<td>
|
||||||
<a href="{{ url('realm-user-detail', args=[realm.id, user.user.dn]) }}">{{ user.user.username }}</a>
|
<a href="{{ url('realm-user-detail', args=[realm.id, user.user.dn]) }}">{{ user.user.username }}</a>
|
||||||
</td>
|
</td>
|
||||||
@ -57,6 +58,11 @@
|
|||||||
<i class="far fa-times-circle text-danger"></i><span class="d-none">+</span>
|
<i class="far fa-times-circle text-danger"></i><span class="d-none">+</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
|
<td class="text-center">
|
||||||
|
{% if user.deleted_user %}
|
||||||
|
{{ user.deleted_user.deletion_date.strftime('%Y-%m-%d') }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -125,6 +131,29 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
{% macro get_success_toast(success_head, success_text, error_headline, error_text) -%}
|
||||||
|
{% if success_text and success_head %}
|
||||||
|
<div class="toast" role="alert" aria-live="polite" aria-atomic="true" data-delay="5000">
|
||||||
|
<div role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
|
<div role="alert" aria-live="assertive" aria-atomic="true" class="" data-autohide="false">
|
||||||
|
<div class="toast-header text-success"><strong class="mr-auto">{{ success_head }}</strong></div>
|
||||||
|
<div class="toast-body">{{ success_text }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if error_text and error_headline %}
|
||||||
|
<div class="toast" role="alert" aria-live="polite" aria-atomic="true" data-delay="5000">
|
||||||
|
<div role="alert" aria-live="assertive" aria-atomic="true">
|
||||||
|
<div role="alert" aria-live="assertive" aria-atomic="true" class="" data-autohide="false">
|
||||||
|
<div class="toast-header text-error"><strong class="mr-auto">{{ error_headline }}</strong></div>
|
||||||
|
<div class="toast-body">{{ error_text }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% endmacro %}
|
||||||
|
|
||||||
{% macro get_data_table_search_field(input_id="data-table-search-input") -%}
|
{% macro get_data_table_search_field(input_id="data-table-search-input") -%}
|
||||||
<div class="form-group w-25 float-right">
|
<div class="form-group w-25 float-right">
|
||||||
<input type="text"
|
<input type="text"
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
{% extends 'base_admin.jinja2' %}
|
{% extends 'base_admin.jinja2' %}
|
||||||
|
{% import 'macros/utils_macros.jinja2' as mutils %}
|
||||||
|
|
||||||
{% block admin_content %}
|
{% block admin_content %}
|
||||||
<div class="row ">
|
<div class="row ">
|
||||||
<div class="col-12 p-3">
|
<div class="col-12 p-3">
|
||||||
@ -19,13 +21,17 @@
|
|||||||
<p style="color: darkred">{{ error }}</p>
|
<p style="color: darkred">{{ error }}</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% block detail_content %}
|
{% block detail_content %}
|
||||||
|
{{ mutils.get_success_toast(success_headline, success_text, error_headline, error_text) }}
|
||||||
<ul class="list-group list-group-flush w-100">
|
<ul class="list-group list-group-flush w-100">
|
||||||
<li class="list-group-item">LDAP Organisationseinheit: {{ realm.ldap_base_dn }}</li>
|
<li class="list-group-item">LDAP Organisationseinheit: {{ realm.ldap_base_dn }}</li>
|
||||||
<li class="list-group-item">Nutzeranzahl: {{ users_count }}</li>
|
<li class="list-group-item">Nutzeranzahl (Aktive/Inaktive): {{ users_count }}
|
||||||
<li class="list-group-item">Inaktive Nutzer: {{ inactive_user_count }} <a
|
({{ users_count-inactive_user_count }}/{{ inactive_user_count }})
|
||||||
href="{{ url('realm-multiple-user-delete-inactive', args=[realm.id]) }}"
|
<a
|
||||||
class="float-right">
|
href="{{ url('realm-multiple-user-delete-inactive', args=[realm.id]) }}"
|
||||||
Inaktive Nutzer löschen</a></li>
|
class="float-right">
|
||||||
|
Inaktive Nutzer löschen
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
{% if realm.email %}
|
{% if realm.email %}
|
||||||
<li class="list-group-item">Email: {{ realm.email }}</li>
|
<li class="list-group-item">Email: {{ realm.email }}</li>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
<h1>StuVe Accountlöschung</h1>
|
||||||
|
<p>Dein Account mit dem Nutzernamen <strong>{{ user.username }}</strong> wurde als gelöscht markiert. Deine Nutzerdaten
|
||||||
|
werden in {{ deletion_wait_days }} Tagen gelöscht. Falls du noch wichtige Daten in den StuVe Services gespeichert
|
||||||
|
hast, bitte kopiere diese noch vor der Löschung. Danach werden diese nicht mehr zugänglich sein. </p>
|
||||||
|
<p>Möchtest du weiter Teil der StuVe Services sein, bitte kontaktiere zuvor deinen Administrator.</p>
|
||||||
|
<p>Wir wünschen dir noch einen schöne Studienzeit</p>
|
||||||
|
<p>Das Fachschaft WIAI Admin Team</p>
|
||||||
|
Kontakt: <a href="mailto:fachschaft-wiai.stuve@uni-bamberg.de?subject=LAMa (Dein Betreff)">fachschaft-wiai.stuve@uni-bamberg.de</a>
|
||||||
|
|
||||||
@ -1,22 +1,33 @@
|
|||||||
{% extends 'base.jinja2' %}
|
{% extends 'base.jinja2' %}
|
||||||
{% import 'macros/form_macros.jinja2' as mform %}
|
{% import 'macros/form_macros.jinja2' as mform %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="col-12 ">
|
<div class="col-12 ">
|
||||||
<div class="row justify-content-center justify-content-sm-center">
|
<div class="row justify-content-center justify-content-sm-center">
|
||||||
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5 border">
|
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5 border">
|
||||||
<h1 class="mb-4">Passwort ändern</h1>
|
<h1 class="mb-4">Passwort ändern</h1>
|
||||||
<form method="post" class="floating-label-form">
|
<form method="post" class="floating-label-form">
|
||||||
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
|
<input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
|
||||||
{{ mform.password_input(form.old_password) }}
|
<!-- {{form.errors}}-->
|
||||||
{{ mform.password_input(form.new_password1) }}
|
<input type="password"
|
||||||
{{ mform.password_input(form.new_password2) }}
|
class="form-control"
|
||||||
<div class="d-flex mt-4">
|
placeholder="Old password"
|
||||||
<button type="submit" class="btn btn-primary mr-auto p-2">Speichern</button>
|
aria-describedby="id_old_password_help"
|
||||||
<a href="{{ url('realm-home')}}"
|
name="old_password"
|
||||||
class="btn btn-secondary p-2">Abbrechen</a>
|
id="id_old_password"
|
||||||
</div>
|
maxlength="None"
|
||||||
</form>
|
value="ralf"
|
||||||
</div>
|
hidden>
|
||||||
|
|
||||||
|
<!-- {{ mform.password_input(form.old_password) }}-->
|
||||||
|
{{ mform.password_input(form.new_password1) }}
|
||||||
|
{{ mform.password_input(form.new_password2) }}
|
||||||
|
<div class="d-flex mt-4">
|
||||||
|
<button type="submit" class="btn btn-primary mr-auto p-2">Speichern</button>
|
||||||
|
<a href="{{ url('realm-home')}}"
|
||||||
|
class="btn btn-secondary p-2">Abbrechen</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1,26 +1,49 @@
|
|||||||
{% extends 'realm/realm_detailed.jinja2' %}
|
{% extends 'realm/realm_detailed.jinja2' %}
|
||||||
{% import 'macros/form_macros.jinja2' as mform %}
|
{% import 'macros/form_macros.jinja2' as mform %}
|
||||||
|
{% import 'macros/utils_macros.jinja2' as mutils %}
|
||||||
|
|
||||||
{% block detail_content %}
|
{% block detail_content %}
|
||||||
<h3>{{ user.username }}</h3>
|
{{ mutils.get_success_toast(success_headline, success_text) }}
|
||||||
|
{% if user.user %}
|
||||||
|
{% if user.deleted_user.deletion_date %}
|
||||||
|
<h3 class="text-danger">{{ user.user.username }}
|
||||||
|
<small>Nutzer wird vorraussichtlich am {{ user.deleted_user.deletion_date.strftime('%d.%m.%Y') }}
|
||||||
|
gelöscht
|
||||||
|
</small>
|
||||||
|
</h3>
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ user.user.username }}</h3>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
<h3>{{ user.username }}</h3>
|
||||||
|
{% endif %}
|
||||||
{% if not form %}
|
{% if not form %}
|
||||||
<ul class="list-group list-group-flush w-100">
|
<ul class="list-group list-group-flush w-100">
|
||||||
<li class="list-group-item">Ldap Domain: {{ user.dn }}</li>
|
<li class="list-group-item">Ldap Domain: {{ user.user.dn }}</li>
|
||||||
<li class="list-group-item"> Anzeigename:
|
<li class="list-group-item"> Anzeigename:
|
||||||
{% if user.display_name %}
|
{% if user.user.display_name %}
|
||||||
{{ user.display_name }}
|
{{ user.user.display_name }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<span class="text-warning"> Noch nicht generiert </span>
|
<span class="text-warning"> Noch nicht generiert </span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">Vorname: {{ user.first_name }}</li>
|
{% if user.user.phone %}
|
||||||
<li class="list-group-item">Nachname: {{ user.last_name }}</li>
|
<li class="list-group-item">Vorname: {{ user.user.first_name }}</li>
|
||||||
<li class="list-group-item">Email: {{ user.email }}</li>
|
{% endif %}
|
||||||
|
{% if user.user.phone %}
|
||||||
|
<li class="list-group-item">Nachname: {{ user.user.last_name }}</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="list-group-item">Email: {{ user.user.email }}</li>
|
||||||
<li class="list-group-item">Passwort: <a
|
<li class="list-group-item">Passwort: <a
|
||||||
href="{{ url('realm-user-password-reset', args = [realm.id, user.dn]) }}" class="float-right">Nutzerpasswort
|
href="{{ url('realm-user-password-reset', args = [realm.id, user.user.dn]) }}" class="float-right">Nutzerpasswort
|
||||||
zurücksetzen</a></li>
|
zurücksetzen</a></li>
|
||||||
<li class="list-group-item">Telefon: {{ user.phone }}</li>
|
{% if user.user.phone %}
|
||||||
<li class="list-group-item">Mobiltelefon: {{ user.mobile_phone }}</li>
|
<li class="list-group-item">Telefon: {{ user.user.phone }}</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if user.user.mobile_phone %}
|
||||||
|
<li class="list-group-item">Mobiltelefon: {{ user.user.mobile_phone }}</li>
|
||||||
|
{% endif %}
|
||||||
<li class="list-group-item">Gruppen:
|
<li class="list-group-item">Gruppen:
|
||||||
{% if groups %}
|
{% if groups %}
|
||||||
{% for group in groups %}
|
{% for group in groups %}
|
||||||
@ -33,29 +56,45 @@
|
|||||||
{% else %}
|
{% else %}
|
||||||
<span class="text-warning">Keine zugewiesen</span>
|
<span class="text-warning">Keine zugewiesen</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ url('realm-user-group-update', args=[realm.id, user.dn]) }}" class="float-right">
|
{% if not user.deleted_user.deletion_date %}
|
||||||
Gruppen zuweisen</a>
|
<a href="{{ url('realm-user-group-update', args=[realm.id, user.user.dn]) }}" class="float-right">
|
||||||
|
Gruppen zuweisen</a>
|
||||||
|
{% endif %}
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item">Zuletzt eingeloggt:
|
<li class="list-group-item">Zuletzt eingeloggt:
|
||||||
{% if user.last_login %}
|
{% if user.user.last_login %}
|
||||||
{{ user.last_login.strftime('%d.%m.%Y') }}
|
{{ user.user.last_login.strftime('%d.%m.%Y') }}
|
||||||
{% else %}
|
{% else %}
|
||||||
<i class="far fa-times-circle text-danger"></i><span class="d-none">+</span>
|
<i class="far fa-times-circle text-danger"></i><span class="d-none">+</span>
|
||||||
{% endif %}</li>
|
{% endif %}</li>
|
||||||
|
{% if user.deleted_user.deletion_date %}
|
||||||
|
<li class="list-group-item text-danger">
|
||||||
|
Löschvorgang: {{ user.deleted_user.deletion_date.strftime('%d.%m.%Y') }}
|
||||||
|
<a href="{{ url('realm-user-delete-cancel', args=[realm.id, user.user.dn]) }}"
|
||||||
|
class="float-right">
|
||||||
|
Löschvorgang abbrechen</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="d-flex mt-3">
|
<div class="d-flex mt-3">
|
||||||
<a href="{{ url('realm-user-update', args = [realm.id, user.dn]) }}" class="btn btn-primary mr-auto p-2">
|
{% if not user.deleted_user.deletion_date %}
|
||||||
<i class="fas fa-user-cog"></i> Nutzer bearbeiten
|
<a href="{{ url('realm-user-update', args = [realm.id, user.user.dn]) }}"
|
||||||
</a>
|
class="btn btn-primary mr-auto p-2">
|
||||||
{% if not user.last_login %}
|
<i class="fas fa-user-cog"></i> Nutzer bearbeiten
|
||||||
<a href="{{ url('realm-user-resend-welcome-mail', args = [realm.id, user.dn]) }}"
|
</a>
|
||||||
class="btn btn-secondary p-2 mr-2">
|
|
||||||
<i class="fas fa-paper-plane"></i> Wilkommensmail erneut senden
|
{% if not user.user.last_login %}
|
||||||
|
<a href="{{ url('realm-user-resend-welcome-mail', args = [realm.id, user.user.dn]) }}"
|
||||||
|
class="btn btn-secondary p-2 mr-2">
|
||||||
|
<i class="fas fa-paper-plane"></i> Wilkommensmail erneut senden
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<a href="{{ url('realm-user-delete-confirm', args = [realm.id, user.user.dn]) }}"
|
||||||
|
class="btn btn-danger p-2">
|
||||||
|
<i class="fas fa-trash"></i> Nutzer löschen
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ url('realm-user-delete-confirm', args = [realm.id, user.dn]) }}" class="btn btn-danger p-2">
|
|
||||||
<i class="fas fa-trash"></i> Nutzer löschen
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<div class="row justify-content-center justify-content-sm-center">
|
<div class="row justify-content-center justify-content-sm-center">
|
||||||
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5">
|
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5">
|
||||||
<div class="alert alert-warning" role="alert">
|
<div class="alert alert-warning" role="alert">
|
||||||
<p>Achtung! Sie sind gerade dabei den Account von <strong>{{ user.username }}</strong> zu schließen.
|
<p><strong>Achtung!</strong> Sie sind gerade dabei den Account von <strong>{{ user.username }}</strong> zu schließen.
|
||||||
</p>
|
</p>
|
||||||
<p>Falls Sie sich sicher sind, dass Sie diesen Nutzer löschen wollen, klicken Sie bitte auf "Nutzer
|
<p>Falls Sie sich sicher sind, dass Sie diesen Nutzer löschen wollen, klicken Sie bitte auf "Nutzer
|
||||||
löschen".
|
löschen".
|
||||||
@ -15,6 +15,9 @@
|
|||||||
Diensten hochgeladen wurden, weiterhin bestehen bleiben.</p>
|
Diensten hochgeladen wurden, weiterhin bestehen bleiben.</p>
|
||||||
<p>Um auch diese zu löschen müssen Sie zuvor Ihre Daten entsprechend löschen. </p>
|
<p>Um auch diese zu löschen müssen Sie zuvor Ihre Daten entsprechend löschen. </p>
|
||||||
<p>Möchten Sie das Löschen der Accountdaten verhindern, klicken Sie auf "Abbrechen"</p>
|
<p>Möchten Sie das Löschen der Accountdaten verhindern, klicken Sie auf "Abbrechen"</p>
|
||||||
|
<p>Der Nutzer wird automatisch über die Löschung informiert.</p>
|
||||||
|
<p><strong>Der Account bleibt noch {{ deletion_wait_days }} Tage (vom heutigen Tag aus) bis zur geplanten Löschung
|
||||||
|
bestehen.</strong></p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
<a href="{{ url(cancel_link.name, args = cancel_link.args) }}"
|
<a href="{{ url(cancel_link.name, args = cancel_link.args) }}"
|
||||||
|
|||||||
@ -8,8 +8,14 @@
|
|||||||
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5">
|
<div class="col-12 col-sm-8 col-md-7 col-lg-5 col-xl-4 bg-white text-dark p-3 mt-5">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">{{ user.username }}</h5>
|
{% if user.deleted_user.deletion_date %}
|
||||||
<h6 class="card-subtitle mb-2 text-muted">{{ user.last_name }}, {{ user.first_name }}</h6>
|
<h5 class="card-title text-danger">{{ user.user.username }}
|
||||||
|
<small>Als gelöscht markiert</small>
|
||||||
|
</h5>
|
||||||
|
{% else %}
|
||||||
|
<h5 class="card-title">{{ user.user.username }}</h5>
|
||||||
|
{% endif %}
|
||||||
|
<h6 class="card-subtitle mb-2 text-muted">{{ user.user.last_name }}, {{ user.user.first_name }}</h6>
|
||||||
<ul class="list-group list-group-flush">
|
<ul class="list-group list-group-flush">
|
||||||
{% if groups %}
|
{% if groups %}
|
||||||
<li class="list-group-item">
|
<li class="list-group-item">
|
||||||
@ -23,21 +29,26 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="list-group-item"><span
|
<li class="list-group-item"><span
|
||||||
class="font-weight-bold">Email:</span> {{ user.email }}</li>
|
class="font-weight-bold">Email:</span> {{ user.user.email }}</li>
|
||||||
<li class="list-group-item"><span
|
<li class="list-group-item"><span
|
||||||
class="font-weight-bold">Passwort:</span> <a
|
class="font-weight-bold">Passwort:</span> <a
|
||||||
href="{{ url('password_change') }}">Passwort ändern</a>
|
href="{{ url('password_change_controller') }}">Passwort ändern</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="list-group-item"><span
|
<li class="list-group-item"><span
|
||||||
class="font-weight-bold">Telefon:</span> {{ user.phone }}</li>
|
class="font-weight-bold">Telefon:</span> {{ user.user.phone }}</li>
|
||||||
<li class="list-group-item"><span
|
<li class="list-group-item"><span
|
||||||
class="font-weight-bold">Mobiltelefon:</span> {{ user.mobile_phone }}</li>
|
class="font-weight-bold">Mobiltelefon:</span> {{ user.user.mobile_phone }}</li>
|
||||||
|
{% if user.deleted_user.deletion_date %}
|
||||||
|
<li class="list-group-item text-danger">
|
||||||
|
Löschvorgang: {{ user.deleted_user.deletion_date.strftime('%d.%m.%Y') }}
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
<div class="card-footer d-flex bg-white">
|
<div class="card-footer d-flex bg-white">
|
||||||
<a href="{{ url('user-update', args = [realm.id, user.dn]) }}"
|
<a href="{{ url('user-update', args = [realm.id, user.user.dn]) }}"
|
||||||
class="btn btn-primary mr-auto p-2"><i class="fas fa-user-edit"></i> Profil
|
class="btn btn-primary mr-auto p-2"><i class="fas fa-user-edit"></i> Profil
|
||||||
bearbeiten</a>
|
bearbeiten</a>
|
||||||
<a href="{{ url('user-delete-confirm', args = [realm.id, user.dn]) }}"
|
<a href="{{ url('user-delete-confirm', args = [realm.id, user.user.dn]) }}"
|
||||||
class="btn btn-danger p-2"><i class="fas fa-trash"></i> Profil löschen</a>
|
class="btn btn-danger p-2"><i class="fas fa-trash"></i> Profil löschen</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user