ФУНКЦИИ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: блокировка и удаление участников воркспейса в God Mode
This commit is contained in:
@@ -9,6 +9,8 @@ from rest_framework import status
|
||||
|
||||
from enum import Enum
|
||||
|
||||
from plane.utils.workspace_bans import release_expired_workspace_bans
|
||||
|
||||
|
||||
class ROLE(Enum):
|
||||
ADMIN = 20
|
||||
@@ -20,6 +22,9 @@ def allow_permission(allowed_roles, level="PROJECT", creator=False, model=None):
|
||||
def decorator(view_func):
|
||||
@wraps(view_func)
|
||||
def _wrapped_view(instance, request, *args, **kwargs):
|
||||
if not request.user.is_anonymous and kwargs.get("slug"):
|
||||
release_expired_workspace_bans(member=request.user, workspace_slug=kwargs["slug"])
|
||||
|
||||
# Check for creator if required
|
||||
if creator and model:
|
||||
# check if the user is part of the workspace or not
|
||||
|
||||
@@ -8,6 +8,12 @@ from rest_framework.permissions import SAFE_METHODS, BasePermission
|
||||
# Module import
|
||||
from plane.db.models import ProjectMember, WorkspaceMember
|
||||
from plane.db.models.project import ROLE
|
||||
from plane.utils.workspace_bans import release_expired_workspace_bans
|
||||
|
||||
|
||||
def release_request_workspace_ban(request, view):
|
||||
if hasattr(view, "workspace_slug") and view.workspace_slug:
|
||||
release_expired_workspace_bans(member=request.user, workspace_slug=view.workspace_slug)
|
||||
|
||||
|
||||
class ProjectBasePermission(BasePermission):
|
||||
@@ -15,6 +21,8 @@ class ProjectBasePermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
## Safe Methods -> Handle the filtering logic in queryset
|
||||
if request.method in SAFE_METHODS:
|
||||
return WorkspaceMember.objects.filter(
|
||||
@@ -58,6 +66,8 @@ class ProjectMemberPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
## Safe Methods -> Handle the filtering logic in queryset
|
||||
if request.method in SAFE_METHODS:
|
||||
return ProjectMember.objects.filter(
|
||||
@@ -87,6 +97,8 @@ class ProjectEntityPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
# Handle requests based on project__identifier
|
||||
if hasattr(view, "project_identifier") and view.project_identifier:
|
||||
if request.method in SAFE_METHODS:
|
||||
@@ -121,6 +133,8 @@ class ProjectAdminPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return ProjectMember.objects.filter(
|
||||
workspace__slug=view.workspace_slug,
|
||||
member=request.user,
|
||||
@@ -135,6 +149,8 @@ class ProjectLitePermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return ProjectMember.objects.filter(
|
||||
workspace__slug=view.workspace_slug,
|
||||
member=request.user,
|
||||
|
||||
@@ -7,6 +7,7 @@ from rest_framework.permissions import BasePermission, SAFE_METHODS
|
||||
|
||||
# Module imports
|
||||
from plane.db.models import WorkspaceMember
|
||||
from plane.utils.workspace_bans import release_expired_workspace_bans
|
||||
|
||||
|
||||
# Permission Mappings
|
||||
@@ -15,6 +16,11 @@ Member = 15
|
||||
Guest = 5
|
||||
|
||||
|
||||
def release_request_workspace_ban(request, view):
|
||||
if hasattr(view, "workspace_slug") and view.workspace_slug:
|
||||
release_expired_workspace_bans(member=request.user, workspace_slug=view.workspace_slug)
|
||||
|
||||
|
||||
# TODO: Move the below logic to python match - python v3.10
|
||||
class WorkSpaceBasePermission(BasePermission):
|
||||
def has_permission(self, request, view):
|
||||
@@ -25,6 +31,8 @@ class WorkSpaceBasePermission(BasePermission):
|
||||
if request.method == "POST":
|
||||
return True
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
## Safe Methods
|
||||
if request.method in SAFE_METHODS:
|
||||
return True
|
||||
@@ -53,6 +61,8 @@ class WorkspaceOwnerPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return WorkspaceMember.objects.filter(
|
||||
workspace__slug=view.workspace_slug, member=request.user, role=Admin
|
||||
).exists()
|
||||
@@ -63,6 +73,8 @@ class WorkSpaceAdminPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return WorkspaceMember.objects.filter(
|
||||
member=request.user,
|
||||
workspace__slug=view.workspace_slug,
|
||||
@@ -76,6 +88,8 @@ class WorkspaceEntityPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
## Safe Methods -> Handle the filtering logic in queryset
|
||||
if request.method in SAFE_METHODS:
|
||||
return WorkspaceMember.objects.filter(
|
||||
@@ -95,6 +109,8 @@ class WorkspaceViewerPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return WorkspaceMember.objects.filter(
|
||||
member=request.user, workspace__slug=view.workspace_slug, is_active=True
|
||||
).exists()
|
||||
@@ -105,6 +121,8 @@ class WorkspaceUserPermission(BasePermission):
|
||||
if request.user.is_anonymous:
|
||||
return False
|
||||
|
||||
release_request_workspace_ban(request, view)
|
||||
|
||||
return WorkspaceMember.objects.filter(
|
||||
member=request.user, workspace__slug=view.workspace_slug, is_active=True
|
||||
).exists()
|
||||
|
||||
@@ -32,6 +32,7 @@ from plane.db.models import (
|
||||
)
|
||||
from plane.db.models.project import ProjectNetwork
|
||||
from plane.utils.host import base_host
|
||||
from plane.utils.workspace_bans import is_workspace_member_currently_banned, release_workspace_member_ban
|
||||
|
||||
|
||||
class ProjectInvitationsViewset(BaseViewSet):
|
||||
@@ -195,7 +196,19 @@ class ProjectJoinEndpoint(BaseAPIView):
|
||||
)
|
||||
|
||||
if project_invite.responded_at is None:
|
||||
project_invite.accepted = request.data.get("accepted", False)
|
||||
accepted = request.data.get("accepted", False)
|
||||
if accepted:
|
||||
user = User.objects.filter(email=email).first()
|
||||
workspace_member = WorkspaceMember.objects.filter(workspace__slug=slug, member=user).first()
|
||||
if is_workspace_member_currently_banned(workspace_member):
|
||||
return Response(
|
||||
{"error": "You are banned from this workspace"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if workspace_member is not None and workspace_member.is_banned:
|
||||
release_workspace_member_ban(workspace_member)
|
||||
|
||||
project_invite.accepted = accepted
|
||||
project_invite.responded_at = timezone.now()
|
||||
project_invite.save()
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ from plane.bgtasks.event_tracking_task import track_event
|
||||
from plane.utils.url import contains_url
|
||||
from plane.utils.analytics_events import WORKSPACE_CREATED, WORKSPACE_DELETED
|
||||
from plane.utils.csv_utils import sanitize_csv_row
|
||||
from plane.utils.workspace_bans import release_expired_workspace_bans
|
||||
|
||||
|
||||
class WorkSpaceViewSet(BaseViewSet):
|
||||
@@ -207,6 +208,8 @@ class UserWorkSpacesEndpoint(BaseAPIView):
|
||||
use_read_replica = True
|
||||
|
||||
def get(self, request):
|
||||
release_expired_workspace_bans(member=request.user)
|
||||
|
||||
fields = [field for field in request.GET.get("fields", "").split(",") if field]
|
||||
member_count = (
|
||||
WorkspaceMember.objects.filter(workspace=OuterRef("id"), member__is_bot=False, is_active=True)
|
||||
|
||||
@@ -31,6 +31,7 @@ from plane.db.models import User, Workspace, WorkspaceMember, WorkspaceMemberInv
|
||||
from plane.utils.cache import invalidate_cache, invalidate_cache_directly
|
||||
from plane.utils.host import base_host
|
||||
from plane.utils.analytics_events import USER_JOINED_WORKSPACE, USER_INVITED_TO_WORKSPACE
|
||||
from plane.utils.workspace_bans import is_workspace_member_currently_banned, release_workspace_member_ban
|
||||
from .. import BaseViewSet
|
||||
|
||||
|
||||
@@ -85,6 +86,17 @@ class WorkspaceInvitationsViewset(BaseViewSet):
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
banned_workspace_members = WorkspaceMember.objects.filter(
|
||||
workspace_id=workspace.id,
|
||||
member__email__in=[email.get("email") for email in emails],
|
||||
is_banned=True,
|
||||
).select_related("member")
|
||||
if any(is_workspace_member_currently_banned(workspace_member) for workspace_member in banned_workspace_members):
|
||||
return Response(
|
||||
{"error": "Some users are banned from this workspace"},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
workspace_invitations = []
|
||||
for email in emails:
|
||||
try:
|
||||
@@ -174,7 +186,23 @@ class WorkspaceJoinEndpoint(BaseAPIView):
|
||||
|
||||
# If already responded then return error
|
||||
if workspace_invite.responded_at is None:
|
||||
workspace_invite.accepted = request.data.get("accepted", False)
|
||||
accepted = request.data.get("accepted", False)
|
||||
if accepted:
|
||||
user = User.objects.filter(email=workspace_invite.email).first()
|
||||
workspace_member = (
|
||||
WorkspaceMember.objects.filter(workspace=workspace_invite.workspace, member=user).first()
|
||||
if user is not None
|
||||
else None
|
||||
)
|
||||
if is_workspace_member_currently_banned(workspace_member):
|
||||
return Response(
|
||||
{"error": "You are banned from this workspace"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if workspace_member is not None and workspace_member.is_banned:
|
||||
release_workspace_member_ban(workspace_member)
|
||||
|
||||
workspace_invite.accepted = accepted
|
||||
workspace_invite.responded_at = timezone.now()
|
||||
workspace_invite.save()
|
||||
|
||||
@@ -260,6 +288,17 @@ class UserWorkspaceInvitationsViewSet(BaseViewSet):
|
||||
|
||||
# If the user is already a member of workspace and was deactivated then activate the user
|
||||
for invitation in workspace_invitations:
|
||||
workspace_member = WorkspaceMember.objects.filter(
|
||||
workspace_id=invitation.workspace_id, member=request.user
|
||||
).first()
|
||||
if is_workspace_member_currently_banned(workspace_member):
|
||||
return Response(
|
||||
{"error": "You are banned from one or more invited workspaces"},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if workspace_member is not None and workspace_member.is_banned:
|
||||
release_workspace_member_ban(workspace_member)
|
||||
|
||||
invalidate_cache_directly(
|
||||
path=f"/api/workspaces/{invitation.workspace.slug}/members/",
|
||||
user=False,
|
||||
|
||||
Reference in New Issue
Block a user