ADMIN_ROLE = 20 AUTO_ADMIN_COMMENT = "nodedc:workspace-admin" AUTO_ADMIN_CREATED_COMMENT = f"{AUTO_ADMIN_COMMENT}:created" AUTO_ADMIN_PREVIOUS_PREFIX = f"{AUTO_ADMIN_COMMENT}:previous:" def get_auto_admin_previous_role(comment): if not isinstance(comment, str) or not comment.startswith(AUTO_ADMIN_PREVIOUS_PREFIX): return None try: previous_role = int(comment.replace(AUTO_ADMIN_PREVIOUS_PREFIX, "", 1)) except ValueError: return None return previous_role if previous_role in {5, 15, ADMIN_ROLE} else None def ensure_project_admin_membership(project, user): from plane.db.models import ProjectMember project_member = ProjectMember.objects.filter( project=project, member=user, deleted_at__isnull=True, ).first() if project_member is None: ProjectMember.objects.create( workspace=project.workspace, project=project, member=user, role=ADMIN_ROLE, is_active=True, comment=AUTO_ADMIN_CREATED_COMMENT, ) return 1 update_fields = [] if project_member.role != ADMIN_ROLE: project_member.comment = f"{AUTO_ADMIN_PREVIOUS_PREFIX}{project_member.role}" project_member.role = ADMIN_ROLE update_fields.extend(["comment", "role"]) if not project_member.is_active: project_member.is_active = True update_fields.append("is_active") if update_fields: update_fields.append("updated_at") project_member.save(update_fields=update_fields) return 1 return 0 def revoke_auto_project_admin_memberships(workspace, user): from plane.db.models import ProjectMember revoked = 0 project_memberships = ProjectMember.objects.filter( project__workspace=workspace, member=user, role=ADMIN_ROLE, deleted_at__isnull=True, comment__startswith=AUTO_ADMIN_COMMENT, ) for project_member in project_memberships: previous_role = get_auto_admin_previous_role(project_member.comment) if project_member.comment == AUTO_ADMIN_CREATED_COMMENT or previous_role is None: project_member.is_active = False project_member.save(update_fields=["is_active", "updated_at"]) else: project_member.role = previous_role project_member.comment = None project_member.is_active = True project_member.save(update_fields=["role", "comment", "is_active", "updated_at"]) revoked += 1 return revoked def ensure_user_admin_project_memberships(workspace, user): from plane.db.models import Project restored = 0 for project in Project.objects.filter(workspace=workspace, deleted_at__isnull=True).select_related("workspace"): restored += ensure_project_admin_membership(project, user) return restored def ensure_workspace_admin_project_memberships(workspace, project=None): from plane.db.models import WorkspaceMember admin_memberships = ( WorkspaceMember.objects.filter( workspace=workspace, role=ADMIN_ROLE, is_active=True, deleted_at__isnull=True, member__is_bot=False, ) .select_related("member") .order_by("created_at") ) restored = 0 for workspace_member in admin_memberships: if project is not None: restored += ensure_project_admin_membership(project, workspace_member.member) else: restored += ensure_user_admin_project_memberships(workspace, workspace_member.member) return restored