import hashlib
import logging

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http.response import Http404
from django.shortcuts import render
from django.utils import timezone
from django.utils.translation import gettext as _

from rr.forms.testuser import TestUserDataForm, TestUserForm, TestUserUpdateForm
from rr.models.attribute import Attribute
from rr.models.serviceprovider import ServiceProvider
from rr.models.testuser import TestUser, TestUserData
from rr.utils.serviceprovider import get_service_provider
from rr.utils.testuser_generator import generate_user_data

logger = logging.getLogger(__name__)


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=["oidc", "saml"])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == "POST":
        if "add_testuser" in request.POST:
            form = _add_testuser(request, sp)
        elif "remove_testuser" in request.POST:
            _remove_testusers(request, sp)
        elif "remove_testuser_external" in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(
        request,
        "rr/testuser.html",
        {"object_list": testusers, "object_list_external": testusers_external, "form": form, "object": sp},
    )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data["firstname"]
        lastname = form.cleaned_data["lastname"]
        valid_for = form.cleaned_data["valid_for"]
        userdata = form.cleaned_data["userdata"]
        otherdata = form.cleaned_data["otherdata"]
        scope = form.cleaned_data["scope"] if form.cleaned_data["scope"] else "example.org"
        number_of_users = int(form.cleaned_data["number_of_users"])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data["username"]
                password = hashlib.sha256(form.cleaned_data["password"].encode("utf-8")).hexdigest()
            else:
                username = form.cleaned_data["username"] + str(number)
                password = hashlib.sha256((form.cleaned_data["password"] + str(number)).encode("utf-8")).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None).exists():
                testuser = TestUser.objects.create(
                    sp=sp, username=username, password=password, firstname=firstname, lastname=lastname, end_at=None
                )

                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info("Test user {username} added for {sp}".format(username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _("Test user added: ") + username)
            else:
                messages.add_message(request, messages.WARNING, _("Username already exists: ") + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == "on":
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info("Test user {username} removed from {sp}".format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _("Test user removed: ") + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == "on":
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info(
                    "External test user {username} removed from {sp}".format(username=testuser.username, sp=sp)
                )
                messages.add_message(request, messages.INFO, _("External test user removed: ") + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_("Test user does not exist or you don't have permission to view it"))
    if (
        not request.user.is_superuser
        and not ServiceProvider.objects.filter(
            (Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all())), pk=testuser.sp.pk, end_at=None
        )
        .distinct()
        .last()
    ):
        raise Http404(_("Test user does not exist or you don't have permission to view it"))
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp, admin=request.user)
    if request.method == "POST":
        if "save_data" in request.POST:
            form = _save_user_data(request, testuser)
        if "reset_userdata" in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(
                request, messages.INFO, _("Name based data reset for test user: ") + testuser.username
            )
        if "reset_otherdata" in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _("User data reset for test user: ") + testuser.username)
        if "update_user" in request.POST:
            user_update_form = _update_user(request, testuser)

    return render(
        request,
        "rr/testuser_attribute_data.html",
        {"form": form, "user_update_form": user_update_form, "object": testuser.sp, "testuser": testuser},
    )


def _save_user_data(request, testuser):
    form = TestUserDataForm(request.POST, user=testuser)
    if form.is_valid():
        for field in form:
            data = form.cleaned_data.get(field.name)
            values = data.split(";")
            TestUserData.objects.filter(user=testuser, attribute__friendlyname=field.name).delete()
            for value in values:
                if value:
                    attribute = Attribute.objects.filter(friendlyname=field.name).first()
                    TestUserData.objects.create(user=testuser, attribute=attribute, value=value)
        messages.add_message(request, messages.INFO, _("Test user attributes updated: ") + testuser.username)
    return form


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser, sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data["firstname"]
        testuser.lastname = user_update_form.cleaned_data["lastname"]
        testuser.valid_for.set(user_update_form.cleaned_data["valid_for"])
        password = user_update_form.cleaned_data["password"]
        if password:
            testuser.password = hashlib.sha256(password.encode("utf-8")).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _("User info updated: ") + testuser.username)
    return user_update_form

7531478bc449dfe18372b7c42ee1a3024337e3cb
<mask token>


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=['oidc', 'saml'])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == 'POST':
        if 'add_testuser' in request.POST:
            form = _add_testuser(request, sp)
        elif 'remove_testuser' in request.POST:
            _remove_testusers(request, sp)
        elif 'remove_testuser_external' in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(request, 'rr/testuser.html', {'object_list': testusers,
        'object_list_external': testusers_external, 'form': form, 'object': sp}
        )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data['firstname']
        lastname = form.cleaned_data['lastname']
        valid_for = form.cleaned_data['valid_for']
        userdata = form.cleaned_data['userdata']
        otherdata = form.cleaned_data['otherdata']
        scope = form.cleaned_data['scope'] if form.cleaned_data['scope'
            ] else 'example.org'
        number_of_users = int(form.cleaned_data['number_of_users'])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data['username']
                password = hashlib.sha256(form.cleaned_data['password'].
                    encode('utf-8')).hexdigest()
            else:
                username = form.cleaned_data['username'] + str(number)
                password = hashlib.sha256((form.cleaned_data['password'] +
                    str(number)).encode('utf-8')).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None
                ).exists():
                testuser = TestUser.objects.create(sp=sp, username=username,
                    password=password, firstname=firstname, lastname=
                    lastname, end_at=None)
                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info('Test user {username} added for {sp}'.format(
                    username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _(
                    'Test user added: ') + username)
            else:
                messages.add_message(request, messages.WARNING, _(
                    'Username already exists: ') + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info('Test user {username} removed from {sp}'.format
                    (username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'Test user removed: ') + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info('External test user {username} removed from {sp}'
                    .format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'External test user removed: ') + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    if not request.user.is_superuser and not ServiceProvider.objects.filter(
        Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all
        ()), pk=testuser.sp.pk, end_at=None).distinct().last():
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp,
        admin=request.user)
    if request.method == 'POST':
        if 'save_data' in request.POST:
            form = _save_user_data(request, testuser)
        if 'reset_userdata' in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'Name based data reset for test user: ') + testuser.username)
        if 'reset_otherdata' in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'User data reset for test user: ') + testuser.username)
        if 'update_user' in request.POST:
            user_update_form = _update_user(request, testuser)
    return render(request, 'rr/testuser_attribute_data.html', {'form': form,
        'user_update_form': user_update_form, 'object': testuser.sp,
        'testuser': testuser})


<mask token>


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser,
        sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data['firstname']
        testuser.lastname = user_update_form.cleaned_data['lastname']
        testuser.valid_for.set(user_update_form.cleaned_data['valid_for'])
        password = user_update_form.cleaned_data['password']
        if password:
            testuser.password = hashlib.sha256(password.encode('utf-8')
                ).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=
            testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _(
            'User info updated: ') + testuser.username)
    return user_update_form

<mask token>


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=['oidc', 'saml'])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == 'POST':
        if 'add_testuser' in request.POST:
            form = _add_testuser(request, sp)
        elif 'remove_testuser' in request.POST:
            _remove_testusers(request, sp)
        elif 'remove_testuser_external' in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(request, 'rr/testuser.html', {'object_list': testusers,
        'object_list_external': testusers_external, 'form': form, 'object': sp}
        )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data['firstname']
        lastname = form.cleaned_data['lastname']
        valid_for = form.cleaned_data['valid_for']
        userdata = form.cleaned_data['userdata']
        otherdata = form.cleaned_data['otherdata']
        scope = form.cleaned_data['scope'] if form.cleaned_data['scope'
            ] else 'example.org'
        number_of_users = int(form.cleaned_data['number_of_users'])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data['username']
                password = hashlib.sha256(form.cleaned_data['password'].
                    encode('utf-8')).hexdigest()
            else:
                username = form.cleaned_data['username'] + str(number)
                password = hashlib.sha256((form.cleaned_data['password'] +
                    str(number)).encode('utf-8')).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None
                ).exists():
                testuser = TestUser.objects.create(sp=sp, username=username,
                    password=password, firstname=firstname, lastname=
                    lastname, end_at=None)
                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info('Test user {username} added for {sp}'.format(
                    username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _(
                    'Test user added: ') + username)
            else:
                messages.add_message(request, messages.WARNING, _(
                    'Username already exists: ') + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info('Test user {username} removed from {sp}'.format
                    (username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'Test user removed: ') + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info('External test user {username} removed from {sp}'
                    .format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'External test user removed: ') + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    if not request.user.is_superuser and not ServiceProvider.objects.filter(
        Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all
        ()), pk=testuser.sp.pk, end_at=None).distinct().last():
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp,
        admin=request.user)
    if request.method == 'POST':
        if 'save_data' in request.POST:
            form = _save_user_data(request, testuser)
        if 'reset_userdata' in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'Name based data reset for test user: ') + testuser.username)
        if 'reset_otherdata' in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'User data reset for test user: ') + testuser.username)
        if 'update_user' in request.POST:
            user_update_form = _update_user(request, testuser)
    return render(request, 'rr/testuser_attribute_data.html', {'form': form,
        'user_update_form': user_update_form, 'object': testuser.sp,
        'testuser': testuser})


def _save_user_data(request, testuser):
    form = TestUserDataForm(request.POST, user=testuser)
    if form.is_valid():
        for field in form:
            data = form.cleaned_data.get(field.name)
            values = data.split(';')
            TestUserData.objects.filter(user=testuser,
                attribute__friendlyname=field.name).delete()
            for value in values:
                if value:
                    attribute = Attribute.objects.filter(friendlyname=field
                        .name).first()
                    TestUserData.objects.create(user=testuser, attribute=
                        attribute, value=value)
        messages.add_message(request, messages.INFO, _(
            'Test user attributes updated: ') + testuser.username)
    return form


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser,
        sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data['firstname']
        testuser.lastname = user_update_form.cleaned_data['lastname']
        testuser.valid_for.set(user_update_form.cleaned_data['valid_for'])
        password = user_update_form.cleaned_data['password']
        if password:
            testuser.password = hashlib.sha256(password.encode('utf-8')
                ).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=
            testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _(
            'User info updated: ') + testuser.username)
    return user_update_form

<mask token>
logger = logging.getLogger(__name__)


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=['oidc', 'saml'])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == 'POST':
        if 'add_testuser' in request.POST:
            form = _add_testuser(request, sp)
        elif 'remove_testuser' in request.POST:
            _remove_testusers(request, sp)
        elif 'remove_testuser_external' in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(request, 'rr/testuser.html', {'object_list': testusers,
        'object_list_external': testusers_external, 'form': form, 'object': sp}
        )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data['firstname']
        lastname = form.cleaned_data['lastname']
        valid_for = form.cleaned_data['valid_for']
        userdata = form.cleaned_data['userdata']
        otherdata = form.cleaned_data['otherdata']
        scope = form.cleaned_data['scope'] if form.cleaned_data['scope'
            ] else 'example.org'
        number_of_users = int(form.cleaned_data['number_of_users'])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data['username']
                password = hashlib.sha256(form.cleaned_data['password'].
                    encode('utf-8')).hexdigest()
            else:
                username = form.cleaned_data['username'] + str(number)
                password = hashlib.sha256((form.cleaned_data['password'] +
                    str(number)).encode('utf-8')).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None
                ).exists():
                testuser = TestUser.objects.create(sp=sp, username=username,
                    password=password, firstname=firstname, lastname=
                    lastname, end_at=None)
                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info('Test user {username} added for {sp}'.format(
                    username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _(
                    'Test user added: ') + username)
            else:
                messages.add_message(request, messages.WARNING, _(
                    'Username already exists: ') + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info('Test user {username} removed from {sp}'.format
                    (username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'Test user removed: ') + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info('External test user {username} removed from {sp}'
                    .format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'External test user removed: ') + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    if not request.user.is_superuser and not ServiceProvider.objects.filter(
        Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all
        ()), pk=testuser.sp.pk, end_at=None).distinct().last():
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp,
        admin=request.user)
    if request.method == 'POST':
        if 'save_data' in request.POST:
            form = _save_user_data(request, testuser)
        if 'reset_userdata' in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'Name based data reset for test user: ') + testuser.username)
        if 'reset_otherdata' in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'User data reset for test user: ') + testuser.username)
        if 'update_user' in request.POST:
            user_update_form = _update_user(request, testuser)
    return render(request, 'rr/testuser_attribute_data.html', {'form': form,
        'user_update_form': user_update_form, 'object': testuser.sp,
        'testuser': testuser})


def _save_user_data(request, testuser):
    form = TestUserDataForm(request.POST, user=testuser)
    if form.is_valid():
        for field in form:
            data = form.cleaned_data.get(field.name)
            values = data.split(';')
            TestUserData.objects.filter(user=testuser,
                attribute__friendlyname=field.name).delete()
            for value in values:
                if value:
                    attribute = Attribute.objects.filter(friendlyname=field
                        .name).first()
                    TestUserData.objects.create(user=testuser, attribute=
                        attribute, value=value)
        messages.add_message(request, messages.INFO, _(
            'Test user attributes updated: ') + testuser.username)
    return form


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser,
        sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data['firstname']
        testuser.lastname = user_update_form.cleaned_data['lastname']
        testuser.valid_for.set(user_update_form.cleaned_data['valid_for'])
        password = user_update_form.cleaned_data['password']
        if password:
            testuser.password = hashlib.sha256(password.encode('utf-8')
                ).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=
            testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _(
            'User info updated: ') + testuser.username)
    return user_update_form

import hashlib
import logging
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http.response import Http404
from django.shortcuts import render
from django.utils import timezone
from django.utils.translation import gettext as _
from rr.forms.testuser import TestUserDataForm, TestUserForm, TestUserUpdateForm
from rr.models.attribute import Attribute
from rr.models.serviceprovider import ServiceProvider
from rr.models.testuser import TestUser, TestUserData
from rr.utils.serviceprovider import get_service_provider
from rr.utils.testuser_generator import generate_user_data
logger = logging.getLogger(__name__)


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=['oidc', 'saml'])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == 'POST':
        if 'add_testuser' in request.POST:
            form = _add_testuser(request, sp)
        elif 'remove_testuser' in request.POST:
            _remove_testusers(request, sp)
        elif 'remove_testuser_external' in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(request, 'rr/testuser.html', {'object_list': testusers,
        'object_list_external': testusers_external, 'form': form, 'object': sp}
        )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data['firstname']
        lastname = form.cleaned_data['lastname']
        valid_for = form.cleaned_data['valid_for']
        userdata = form.cleaned_data['userdata']
        otherdata = form.cleaned_data['otherdata']
        scope = form.cleaned_data['scope'] if form.cleaned_data['scope'
            ] else 'example.org'
        number_of_users = int(form.cleaned_data['number_of_users'])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data['username']
                password = hashlib.sha256(form.cleaned_data['password'].
                    encode('utf-8')).hexdigest()
            else:
                username = form.cleaned_data['username'] + str(number)
                password = hashlib.sha256((form.cleaned_data['password'] +
                    str(number)).encode('utf-8')).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None
                ).exists():
                testuser = TestUser.objects.create(sp=sp, username=username,
                    password=password, firstname=firstname, lastname=
                    lastname, end_at=None)
                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info('Test user {username} added for {sp}'.format(
                    username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _(
                    'Test user added: ') + username)
            else:
                messages.add_message(request, messages.WARNING, _(
                    'Username already exists: ') + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info('Test user {username} removed from {sp}'.format
                    (username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'Test user removed: ') + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == 'on':
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info('External test user {username} removed from {sp}'
                    .format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _(
                    'External test user removed: ') + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    if not request.user.is_superuser and not ServiceProvider.objects.filter(
        Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all
        ()), pk=testuser.sp.pk, end_at=None).distinct().last():
        raise Http404(_(
            "Test user does not exist or you don't have permission to view it")
            )
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp,
        admin=request.user)
    if request.method == 'POST':
        if 'save_data' in request.POST:
            form = _save_user_data(request, testuser)
        if 'reset_userdata' in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'Name based data reset for test user: ') + testuser.username)
        if 'reset_otherdata' in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _(
                'User data reset for test user: ') + testuser.username)
        if 'update_user' in request.POST:
            user_update_form = _update_user(request, testuser)
    return render(request, 'rr/testuser_attribute_data.html', {'form': form,
        'user_update_form': user_update_form, 'object': testuser.sp,
        'testuser': testuser})


def _save_user_data(request, testuser):
    form = TestUserDataForm(request.POST, user=testuser)
    if form.is_valid():
        for field in form:
            data = form.cleaned_data.get(field.name)
            values = data.split(';')
            TestUserData.objects.filter(user=testuser,
                attribute__friendlyname=field.name).delete()
            for value in values:
                if value:
                    attribute = Attribute.objects.filter(friendlyname=field
                        .name).first()
                    TestUserData.objects.create(user=testuser, attribute=
                        attribute, value=value)
        messages.add_message(request, messages.INFO, _(
            'Test user attributes updated: ') + testuser.username)
    return form


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser,
        sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data['firstname']
        testuser.lastname = user_update_form.cleaned_data['lastname']
        testuser.valid_for.set(user_update_form.cleaned_data['valid_for'])
        password = user_update_form.cleaned_data['password']
        if password:
            testuser.password = hashlib.sha256(password.encode('utf-8')
                ).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=
            testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _(
            'User info updated: ') + testuser.username)
    return user_update_form

import hashlib
import logging

from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http.response import Http404
from django.shortcuts import render
from django.utils import timezone
from django.utils.translation import gettext as _

from rr.forms.testuser import TestUserDataForm, TestUserForm, TestUserUpdateForm
from rr.models.attribute import Attribute
from rr.models.serviceprovider import ServiceProvider
from rr.models.testuser import TestUser, TestUserData
from rr.utils.serviceprovider import get_service_provider
from rr.utils.testuser_generator import generate_user_data

logger = logging.getLogger(__name__)


@login_required
def testuser_list(request, pk):
    """
    Displays a list of :model:`rr.TestUser` linked to
    :model:`rr.ServiceProvider`.

    Includes a ModelForm for adding :model:`rr.TestUser` to
    :model:`rr.ServiceProvider`.

    **Context**

    ``object_list``
        List of :model:`rr.TestUser`.

    ``object_list_external``
        List of :model:`rr.TestUser`.

    ``form``
        ModelForm for creating a :model:`rr.TestUser`

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    **Template:**

    :template:`rr/testuser.html`
    """
    sp = get_service_provider(pk, request.user, service_type=["oidc", "saml"])
    form = TestUserForm(sp=sp, admin=request.user)
    if request.method == "POST":
        if "add_testuser" in request.POST:
            form = _add_testuser(request, sp)
        elif "remove_testuser" in request.POST:
            _remove_testusers(request, sp)
        elif "remove_testuser_external" in request.POST:
            _remove_external_testusers(request, sp)
    testusers = TestUser.objects.filter(sp=sp, end_at=None)
    testusers_external = TestUser.objects.filter(valid_for=sp).exclude(sp=sp)
    return render(
        request,
        "rr/testuser.html",
        {"object_list": testusers, "object_list_external": testusers_external, "form": form, "object": sp},
    )


def _add_testuser(request, sp):
    form = TestUserForm(request.POST, sp=sp, admin=request.user)
    if form.is_valid():
        firstname = form.cleaned_data["firstname"]
        lastname = form.cleaned_data["lastname"]
        valid_for = form.cleaned_data["valid_for"]
        userdata = form.cleaned_data["userdata"]
        otherdata = form.cleaned_data["otherdata"]
        scope = form.cleaned_data["scope"] if form.cleaned_data["scope"] else "example.org"
        number_of_users = int(form.cleaned_data["number_of_users"])
        for number in range(1, number_of_users + 1):
            if number_of_users == 1:
                username = form.cleaned_data["username"]
                password = hashlib.sha256(form.cleaned_data["password"].encode("utf-8")).hexdigest()
            else:
                username = form.cleaned_data["username"] + str(number)
                password = hashlib.sha256((form.cleaned_data["password"] + str(number)).encode("utf-8")).hexdigest()
            if not TestUser.objects.filter(username=username, end_at=None).exists():
                testuser = TestUser.objects.create(
                    sp=sp, username=username, password=password, firstname=firstname, lastname=lastname, end_at=None
                )

                testuser.valid_for.add(*valid_for)
                testuser.valid_for.add(sp)
                logger.info("Test user {username} added for {sp}".format(username=username, sp=sp))
                generate_user_data(testuser, userdata, otherdata, scope)
                messages.add_message(request, messages.INFO, _("Test user added: ") + username)
            else:
                messages.add_message(request, messages.WARNING, _("Username already exists: ") + username)
        form = TestUserForm(sp=sp, admin=request.user)
    return form


def _remove_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == "on":
            testuser = TestUser.objects.get(pk=key)
            if testuser.sp == sp:
                testuser.end_at = timezone.now()
                testuser.save()
                logger.info("Test user {username} removed from {sp}".format(username=testuser.username, sp=sp))
                messages.add_message(request, messages.INFO, _("Test user removed: ") + testuser.username)


def _remove_external_testusers(request, sp):
    for key, value in request.POST.dict().items():
        if value == "on":
            testuser = TestUser.objects.get(pk=key)
            if sp in testuser.valid_for.all() and testuser.sp != sp:
                testuser.valid_for.remove(sp)
                logger.info(
                    "External test user {username} removed from {sp}".format(username=testuser.username, sp=sp)
                )
                messages.add_message(request, messages.INFO, _("External test user removed: ") + testuser.username)


@login_required
def testuser_attribute_data(request, pk):
    """
    Displays a form including :model:`rr.Attribute` that
    are linked to :model:`rr.ServiceProvider` and values
    for

    If value is given, creates :model:`rr.TestUserData`

    If reason is removed, remove :model:`rr.TestUserData`

    **Context**

    ``form``
        List of :model:`rr.Attribute`.

    ``user_update_form``
        List of :model:`rr.TestUser`.

    ``object``
        An instance of :model:`rr.ServiceProvider`.

    ``testuser``
        An instance of :model:`rr.TestUser`.

    **Template:**

    :template:`rr/attribute_list.html`
    """
    try:
        testuser = TestUser.objects.get(pk=pk, end_at=None)
    except TestUser.DoesNotExist:
        raise Http404(_("Test user does not exist or you don't have permission to view it"))
    if (
        not request.user.is_superuser
        and not ServiceProvider.objects.filter(
            (Q(admins=request.user) | Q(admin_groups__in=request.user.groups.all())), pk=testuser.sp.pk, end_at=None
        )
        .distinct()
        .last()
    ):
        raise Http404(_("Test user does not exist or you don't have permission to view it"))
    form = TestUserDataForm(user=testuser)
    user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp, admin=request.user)
    if request.method == "POST":
        if "save_data" in request.POST:
            form = _save_user_data(request, testuser)
        if "reset_userdata" in request.POST:
            generate_user_data(testuser, userdata=True, otherdata=False)
            form = TestUserDataForm(user=testuser)
            messages.add_message(
                request, messages.INFO, _("Name based data reset for test user: ") + testuser.username
            )
        if "reset_otherdata" in request.POST:
            generate_user_data(testuser, userdata=False, otherdata=True)
            form = TestUserDataForm(user=testuser)
            messages.add_message(request, messages.INFO, _("User data reset for test user: ") + testuser.username)
        if "update_user" in request.POST:
            user_update_form = _update_user(request, testuser)

    return render(
        request,
        "rr/testuser_attribute_data.html",
        {"form": form, "user_update_form": user_update_form, "object": testuser.sp, "testuser": testuser},
    )


def _save_user_data(request, testuser):
    form = TestUserDataForm(request.POST, user=testuser)
    if form.is_valid():
        for field in form:
            data = form.cleaned_data.get(field.name)
            values = data.split(";")
            TestUserData.objects.filter(user=testuser, attribute__friendlyname=field.name).delete()
            for value in values:
                if value:
                    attribute = Attribute.objects.filter(friendlyname=field.name).first()
                    TestUserData.objects.create(user=testuser, attribute=attribute, value=value)
        messages.add_message(request, messages.INFO, _("Test user attributes updated: ") + testuser.username)
    return form


def _update_user(request, testuser):
    temp_password = testuser.password
    user_update_form = TestUserUpdateForm(request.POST, instance=testuser, sp=testuser.sp, admin=request.user)
    if user_update_form.is_valid():
        testuser.firstname = user_update_form.cleaned_data["firstname"]
        testuser.lastname = user_update_form.cleaned_data["lastname"]
        testuser.valid_for.set(user_update_form.cleaned_data["valid_for"])
        password = user_update_form.cleaned_data["password"]
        if password:
            testuser.password = hashlib.sha256(password.encode("utf-8")).hexdigest()
        else:
            testuser.password = temp_password
        testuser.save()
        testuser.valid_for.add(testuser.sp)
        user_update_form = TestUserUpdateForm(instance=testuser, sp=testuser.sp, admin=request.user)
        messages.add_message(request, messages.INFO, _("User info updated: ") + testuser.username)
    return user_update_form
