diff --git a/Access/group_helper.py b/Access/group_helper.py index 8f07a706..31543d9a 100644 --- a/Access/group_helper.py +++ b/Access/group_helper.py @@ -1,4 +1,4 @@ -from Access.models import User, GroupV2, MembershipV2, AccessV2 +from Access.models import GroupAccessMapping, User, GroupV2, MembershipV2, AccessV2 from Access import helpers, views_helper, notifications, accessrequest_helper from django.db import transaction import datetime @@ -24,6 +24,9 @@ "msg": "Error Occured while loading the page. Please contact admin", } +USER_UNAUTHORIZED_MESSAGE = "User unauthorised to perform the action." +GROUP_ACCESS_MAPPING_NOT_FOUND = "Group Access Mapping not found in the database." + NEW_GROUP_CREATE_ERROR_GROUP_EXISTS = { "error_msg": "Invalid Group Name", "msg": "A group with name {group_name} already exists. Please choose a new name.", @@ -745,6 +748,14 @@ def validate_group_access_create_request(group, auth_user): return None +def revoke_user_access(user, access, revoker, decline_message): + user_identity = user.get_active_identity(access.access_tag) + user_identity.decline_non_approved_access_mapping(access, decline_message) + access_mapping = user_identity.get_granted_access_mapping(access).first() + if not access_mapping: + return False + revoke_request(access_mapping, revoker) + def remove_member(request): try: membership_id = request.POST.get("membershipId") @@ -763,7 +774,7 @@ def remove_member(request): ] other_memberships_groups = ( - user.get_all_memberships() + user.get_all_approved_memberships() .exclude(group=membership.group) .values_list("group", flat=True) ) @@ -775,16 +786,59 @@ def remove_member(request): accesses = list(set(group_accesses) - set(other_group_accesses)) - for access in accesses: - user_identity = user.get_active_identity(access.access_tag) - user_identity.decline_non_approved_access_mapping(access) - user_identity.offboarding_approved_access_mapping(access) - revoke_request(user_access_mapping=access, revoker=request.user.user) + with transaction.atomic(): + for access in accesses: + revoke_user_access(user, access, request.user.user, "User removed from the group") membership.revoke_membership() return {"message": "Successfully removed user from group"} +def access_exist_in_other_groups_of_user(membership, group, access): + other_memberships = ( + membership.user.get_all_approved_memberships() + .exclude(group=membership.group) + ) + for membership in other_memberships: + if membership.group.check_access_exist(access): + return True + + return False + + +def revoke_access_from_group(request): + try: + request_id = request.POST.get("request_id") + if not request_id: + logger.debug("Cannot find request_id in the http request.") + return {"error": ERROR_MESSAGE} + + mapping = GroupAccessMapping.get_by_id(request_id) + if not mapping: + logger.debug("Group Access Mapping not found in the database") + return {"error": GROUP_ACCESS_MAPPING_NOT_FOUND} + except Exception as e: + logger.exception(str(e)) + return {"error": ERROR_MESSAGE} + + group = mapping.group + auth_user = request.user + if not (auth_user.user.has_permission("ALLOW_USER_OFFBOARD") or group.member_is_owner(auth_user.user)): + return {"error": USER_UNAUTHORIZED_MESSAGE} + + revoke_access_memberships = [] + for membership in group.get_all_approved_members(): + if access_exist_in_other_groups_of_user(membership, group, mapping.access): + continue + revoke_access_memberships.append(membership) + + with transaction.atomic(): + for membership in revoke_access_memberships: + revoke_user_access(membership.user, mapping.access, auth_user.user, "Access revoked for the group") + + mapping.mark_revoked(auth_user.user) + + return {"message": "Successfully initiated the revoke"} def get_selected_users_by_email(user_emails): selected_users = User.get_users_by_emails(emails=user_emails) diff --git a/Access/models.py b/Access/models.py index 5af381db..e8c76625 100644 --- a/Access/models.py +++ b/Access/models.py @@ -191,8 +191,8 @@ def getOwnedGroups(self): def isAdminOrOps(self): return self.is_ops or self.user.is_superuser - def get_all_memberships(self): - return self.membership_user.all() + def get_all_approved_memberships(self): + return self.membership_user.filter(status="Approved") def is_allowed_admin_actions_on_group(self, group): return ( @@ -1026,6 +1026,19 @@ def getAccessRequestDetails(self, access_module): access_request_data["grantOwner"] = ",".join(access_module.grant_owner()) return access_request_data + + def get_by_id(request_id): + try: + return GroupAccessMapping.objects.get(request_id=request_id) + except GroupAccessMapping.DoesNotExist: + return None + + def mark_revoked(self, revoker): + self.status = "Revoked" + self.revoker = revoker + self.save() + + @staticmethod def get_by_request_id(request_id): diff --git a/Access/views.py b/Access/views.py index b540e888..fa3fc675 100644 --- a/Access/views.py +++ b/Access/views.py @@ -208,6 +208,7 @@ def request_access(request): HTTPResponse: Access request form template or the status of access save request. """ if request.POST: + print((request.POST)) context = create_request( auth_user=request.user, access_request_form=request.POST ) @@ -639,3 +640,15 @@ def individual_resolve(request): logger.exception(str(e)) json_response['error'] = {'error_msg': "Bad request", 'msg': "Error in request not found OR Invalid request type"} return render(request,'BSOps/accessStatus.html',json_response) + +def revoke_group_access(request): + try: + response = group_helper.revoke_access_from_group(request) + if("error" in response): + return JsonResponse(response, status=400) + + return JsonResponse(response) + except Exception as e: + logger.exception(str(e)) + logger.debug("Something went wrong while revoking group access") + return JsonResponse({"message": "Failed to revoke group Access"}, status=400) diff --git a/BrowserStackAutomation/urls.py b/BrowserStackAutomation/urls.py index 64147a50..1e606766 100644 --- a/BrowserStackAutomation/urls.py +++ b/BrowserStackAutomation/urls.py @@ -18,6 +18,7 @@ from django.contrib.auth import views as auth_views from django.urls import re_path, include from Access.views import ( + revoke_group_access, user_offboarding, show_access_history, pending_requests, @@ -91,6 +92,7 @@ re_path( r"^group/removeGroupMember$", remove_group_member, name="remove_group_member" ), + re_path(r"^group/revokeAccess", revoke_group_access, name="revoke_group_access"), re_path(r"^individual_resolve$", individual_resolve, name="individual_resolve") ] diff --git a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html index eb86f558..5075235a 100644 --- a/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html +++ b/templates/BSOps/group_access_list_tabs/generic_accesses_tab.html @@ -28,22 +28,16 @@ $(document).on('click', '.group-revoke-button', function(){ id = $(this).attr("id"); - urlBuilder = "/group/markGroupAccessRevoked?requestId="+id - $.ajax({url: urlBuilder, - success: function(result){ - document.getElementById("inactive-"+id+"-revoke-button").innerHTML = "Access Marked Revoked"; - }, - error: function(result){ - alert("Error occured while marking revoke! - "+result["responseJSON"]["error"]) - }}); - }); - $(document).on('click', '.inactive-access-button', function(){ - id = $(this).attr("id"); - urlBuilder = "/group/markGroupAccessInactive?requestId="+id + urlBuilder = "/group/revokeAccess" $.ajax({url: urlBuilder, + method: "POST", + data: { + request_id: id, + csrfmiddlewaretoken: '{{ csrf_token }}' + }, success: function(result){ - document.getElementById(id+"-revoke-button").innerHTML = "Access Marked Inactive"; + document.getElementById("inactive-"+id+"-revoke-button").innerHTML = "Access Marked Revoked"; }, error: function(result){ alert("Error occured while marking revoke! - "+result["responseJSON"]["error"]) @@ -72,12 +66,8 @@