Source code for organisations.views.club_menu_tabs.access

from django.http import HttpResponse
from django.shortcuts import get_object_or_404, render
from django.urls import reverse

from accounts.models import User, UserAdditionalInfo
from organisations.decorators import check_club_menu_access
from organisations.models import ORGS_RBAC_GROUPS_AND_ROLES, ClubLog
from organisations.views.admin import (
    admin_club_rbac_convert_advanced_to_basic_sub,
    admin_club_rbac_convert_basic_to_advanced_sub,
)
from organisations.views.club_menu_tabs.utils import (
    _menu_rbac_advanced_is_admin,
    _menu_rbac_has_access,
)
from rbac.core import (
    rbac_get_group_by_name,
    rbac_add_user_to_group,
    rbac_get_admin_group_by_name,
    rbac_add_user_to_admin_group,
    rbac_get_users_in_group,
    rbac_remove_user_from_group,
    rbac_remove_admin_user_from_group,
    rbac_get_admin_users_in_group,
)
from rbac.models import RBACUserGroup, RBACAdminUserGroup


@check_club_menu_access()
def basic_add_user_htmx(request, club):
    """Add a user to club rbac basic group. Returns HTMX"""

    # Get user
    user_id = request.POST.get("user_id")
    user = get_object_or_404(User, pk=user_id)

    # Get group
    group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.basic")

    # Add user to group
    rbac_add_user_to_group(user, group)

    # All users are admins
    admin_group = rbac_get_admin_group_by_name(
        f"{club.rbac_admin_name_qualifier}.admin"
    )
    rbac_add_user_to_admin_group(user, admin_group)

    # log it
    ClubLog(
        organisation=club,
        actor=request.user,
        action=f"Added {user} as administrator",
    ).save()

    return access_basic(request, club)


@check_club_menu_access()
def advanced_add_user_htmx(request, club):
    """Add a user to club rbac advanced group. Returns HTMX"""

    # Get user
    user_id = request.POST.get("user_id")
    user = get_object_or_404(User, pk=user_id)

    # Get group
    group_name_item = request.POST.get("group_name_item")

    group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.{group_name_item}")

    errors = {}
    if RBACUserGroup.objects.filter(group=group, member=user).exists():
        errors[group_name_item] = f"{user.first_name} is already in this group"
    else:
        rbac_add_user_to_group(user, group)
        # log it
        ClubLog(
            organisation=club,
            actor=request.user,
            action=f"Added {user} to {group.description}",
        ).save()

    return access_advanced(request, club, errors)


def _invalidate_last_club_visited(user, club):
    """
    Check whether the user still has access to a club
    If not, make sure that the club is not their last club visited
    COB-779 - avoid user getting RBAC block when access to last club visisted is removed
    """

    allowed, role = _menu_rbac_has_access(club, user)
    if allowed:
        # still has access so, no need to check further
        return

    try:
        additional_info = UserAdditionalInfo.objects.get(user=user)
        if (
            additional_info.last_club_visited
            and additional_info.last_club_visited == club.id
        ):
            additional_info.last_club_visited = None
            additional_info.save()
    except UserAdditionalInfo.DoesNotExist:
        pass


@check_club_menu_access()
def basic_delete_user_htmx(request, club):
    """Remove a user from club rbac basic group. Returns HTMX"""

    user = get_object_or_404(User, pk=request.POST.get("user_id"))

    group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.basic")

    # Check for last user
    if rbac_get_users_in_group(group).count() == 1:
        return access_basic(request, club, "Cannot remove last administrator")

    rbac_remove_user_from_group(user, group)

    # Also remove admin
    admin_group = rbac_get_admin_group_by_name(
        f"{club.rbac_admin_name_qualifier}.admin"
    )
    rbac_remove_admin_user_from_group(user, admin_group)

    _invalidate_last_club_visited(user, club)

    # log it
    ClubLog(
        organisation=club,
        actor=request.user,
        action=f"Removed {user} as an administrator",
    ).save()

    return access_basic(request, club)


@check_club_menu_access()
def advanced_delete_user_htmx(request, club):
    """Remove a user from club rbac advanced group. Returns HTMX"""

    # Check if this use is an admin (in RBAC admin group or has higher access)
    if not _menu_rbac_advanced_is_admin(club, request.user):
        return HttpResponse("Access denied")

    user = get_object_or_404(User, pk=request.POST.get("user_id"))
    group_name_item = request.POST.get("group_name_item")

    group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.{group_name_item}")
    rbac_remove_user_from_group(user, group)

    _invalidate_last_club_visited(user, club)

    # log it
    ClubLog(
        organisation=club,
        actor=request.user,
        action=f"Removed {user} from {group.description}",
    ).save()

    return access_advanced(request, club)


@check_club_menu_access()
def advanced_delete_admin_htmx(request, club):
    """Remove an admin from club rbac advanced group. Returns HTMX"""

    # Check if this user is an admin (in RBAC admin group or has higher access)
    if not _menu_rbac_advanced_is_admin(club, request.user):
        return HttpResponse("Access denied")

    user = get_object_or_404(User, pk=request.POST.get("user_id"))

    admin_group = rbac_get_admin_group_by_name(
        f"{club.rbac_admin_name_qualifier}.admin"
    )

    # Don't allow the last admin to be removed
    errors = {}

    if RBACAdminUserGroup.objects.filter(group=admin_group).count() > 1:
        rbac_remove_admin_user_from_group(user, admin_group)
        _invalidate_last_club_visited(user, club)
        # log it
        ClubLog(
            organisation=club,
            actor=request.user,
            action=f"Removed {user} as an administrator",
        ).save()
    else:
        errors["admin"] = "Cannot delete the last admin user"

    return access_advanced(request, club, errors)


@check_club_menu_access()
def advanced_add_admin_htmx(request, club):
    """Add an admin to club rbac advanced group. Returns HTMX"""

    # Check if this use is an admin (in RBAC admin group or has higher access)
    if not _menu_rbac_advanced_is_admin(club, request.user):
        return HttpResponse("Access denied")

    # Get user
    user_id = request.POST.get("user_id")
    user = get_object_or_404(User, pk=user_id)

    admin_group = rbac_get_admin_group_by_name(
        f"{club.rbac_admin_name_qualifier}.admin"
    )

    rbac_add_user_to_admin_group(user, admin_group)

    # log it
    ClubLog(
        organisation=club,
        actor=request.user,
        action=f"Added {user} as an administrator",
    ).save()

    return access_advanced(request, club)


[docs] def access_basic(request, club, message=None): # sourcery skip: list-comprehension """Do the work for the Access tab on the club menu for basic RBAC.""" group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.basic") # Get users users = rbac_get_users_in_group(group) for user in users: user.hx_post = reverse("organisations:club_admin_access_basic_delete_user_htmx") user.hx_vars = f"club_id:{club.id},user_id:{user.id}" # Get roles roles = [] for rule in ORGS_RBAC_GROUPS_AND_ROLES: roles.append(f"{ORGS_RBAC_GROUPS_AND_ROLES[rule]['description']} for {club}") change_to_advanced = reverse( "organisations:club_admin_access_change_rbac_to_advanced_htmx" ) change_to_advanced_hx_vars = f"club_id:{club.id}" return render( request, "organisations/club_menu/access/basic.html", { "club": club, "setup": "basic", "users": users, "roles": roles, "message": message, "change_to_advanced": change_to_advanced, "change_to_advanced_hx_vars": change_to_advanced_hx_vars, }, )
[docs] def access_advanced(request, club, errors={}): """Do the work for the Access tab on the club menu for advanced RBAC.""" # We have multiple groups to handle so we get a dictionary for users with the role as the key user_roles = {} admin_list = [] for rule in ORGS_RBAC_GROUPS_AND_ROLES: # get group group = rbac_get_group_by_name(f"{club.rbac_name_qualifier}.{rule}") # Get users users = rbac_get_users_in_group(group) user_list = [] for user in users: # link for HTMX hx_post to go to user.hx_post = reverse( "organisations:club_admin_access_advanced_delete_user_htmx" ) user.hx_vars = ( f"club_id:{club.id},user_id:{user.id},group_name_item:'{rule}'" ) # unique id for this user and group user.delete_id = f"{rule}-{user.id}" user_list.append(user) desc = f"{ORGS_RBAC_GROUPS_AND_ROLES[rule]['description']}" user_roles[rule] = [desc, user_list] # Get admins admin_group = rbac_get_admin_group_by_name( f"{club.rbac_admin_name_qualifier}.admin" ) admins = rbac_get_admin_users_in_group(admin_group) admin_list = [] for admin in admins: admin.hx_post = reverse("organisations:access_advanced_delete_admin_htmx") admin.hx_vars = f"club_id:{club.id},user_id:{admin.id}" admin_list.append(admin) # Check if this use is an admin (in RBAC admin group or has higher access) user_is_admin = _menu_rbac_advanced_is_admin(club, request.user) # disable buttons (still show them) if user not admin disable_buttons = "" if user_is_admin else "disabled" change_to_basic = reverse( "organisations:club_admin_access_change_rbac_to_basic_htmx" ) change_to_basic_hx_vars = f"club_id:{club.id}" return render( request, "organisations/club_menu/access/advanced.html", { "club": club, "user_is_admin": user_is_admin, "disable_buttons": disable_buttons, "user_roles": user_roles, "admin_list": admin_list, "errors": errors, "change_to_basic": change_to_basic, "change_to_basic_hx_vars": change_to_basic_hx_vars, }, )
@check_club_menu_access() def change_rbac_to_advanced_htmx(request, club): """Allow admin to change RBAC mode to advanced from basic""" # TODO: Work out best security check to perform _, msg = admin_club_rbac_convert_basic_to_advanced_sub(club) # log it ClubLog( organisation=club, actor=request.user, action="Changed RBAC to Advanced mode", ).save() return access_advanced(request, club, msg) @check_club_menu_access() def change_rbac_to_basic_htmx(request, club): """Allow admin to change RBAC mode to basic from advanced""" if _menu_rbac_advanced_is_admin(club, request.user): _, msg = admin_club_rbac_convert_advanced_to_basic_sub(club) # log it ClubLog( organisation=club, actor=request.user, action="Changed RBAC to Basic mode", ).save() else: msg = "Access denied" return access_basic(request, club, msg)