[SILO-348] fix: on Project save, add app bots as members (#3550)

This commit is contained in:
Surya Prashanth
2025-07-01 19:38:59 +05:30
committed by GitHub
parent 9696b50a06
commit a943e94014
4 changed files with 100 additions and 4 deletions

View File

@@ -0,0 +1,28 @@
# Generated by Django 4.2.22 on 2025-07-01 13:03
from django.db import migrations
from plane.authentication.utils.oauth_utils import add_app_bots_to_existing_projects
def add_app_bots_to_existing_projects_migration(apps, schema_editor):
app_installation_model = apps.get_model("authentication", "WorkspaceAppInstallation")
project_model = apps.get_model("db", "Project")
project_member_model = apps.get_model("db", "ProjectMember")
add_app_bots_to_existing_projects(
workspace_app_installation_model=app_installation_model,
project_model=project_model,
project_member_model=project_member_model,
)
class Migration(migrations.Migration):
dependencies = [
('authentication', '0006_auto_20250625_1426'),
("db", "__first__"),
]
operations = [
# rollback is not needed as we are running this in atomic transaction
migrations.RunPython(add_app_bots_to_existing_projects_migration, reverse_code=migrations.RunPython.noop),
]

View File

@@ -17,6 +17,7 @@ def update_bot_user_type(
based on the application is_mentionable field.
"""
from django.db import transaction
from plane.db.models.user import BotTypeEnum
if not application_model:
@@ -42,3 +43,62 @@ def update_bot_user_type(
else None
)
bot_user.save()
def add_app_bots_to_existing_projects(
workspace_app_installation_model=None, project_model=None, project_member_model=None
):
from django.db import transaction
from plane.app.permissions.base import ROLE
if not workspace_app_installation_model:
from plane.authentication.models import WorkspaceAppInstallation
workspace_app_installation_model = WorkspaceAppInstallation
if not project_model:
from plane.db.models.project import Project
project_model = Project
if not project_member_model:
from plane.db.models.project import ProjectMember
project_member_model = ProjectMember
with transaction.atomic():
installations = workspace_app_installation_model.objects.filter(
status="installed",
deleted_at__isnull=True,
)
for installation in installations:
bot_user = installation.app_bot
existing_project_ids = project_member_model.objects.filter(
workspace=installation.workspace,
member=bot_user,
deleted_at__isnull=True,
).values_list("project_id", flat=True)
missing_projects = (
project_model.objects.filter(
workspace=installation.workspace,
deleted_at__isnull=True,
)
.exclude(id__in=existing_project_ids)
.values_list("id", flat=True)
)
# let's bulk create project members
project_members = []
for project_id in missing_projects:
project_members.append(
project_member_model(
project_id=project_id,
workspace=installation.workspace,
member=installation.app_bot,
role=ROLE.MEMBER.value,
)
)
project_member_model.objects.bulk_create(
project_members, ignore_conflicts=True
)

View File

@@ -225,9 +225,11 @@ class Project(BaseModel):
def save(self, *args, **kwargs):
self.identifier = self.identifier.strip().upper()
# check is_adding value before calling super().save()
is_adding = self._state.adding
project = super().save(*args, **kwargs)
# Add app bots to the newly created project
if self._state.adding:
if is_adding:
self.add_app_bots_to_project()
return project

View File

@@ -1,11 +1,16 @@
# Third party imports
import logging
from typing import List, Optional
from celery import shared_task
from typing import Optional, List
# Module imports
from plane.app.permissions.base import ROLE
from plane.authentication.models.oauth import WorkspaceAppInstallation
from plane.db.models.project import Project, ProjectMember
from plane.utils.exception_logger import log_exception
logger = logging.getLogger("plane.worker")
@shared_task
@@ -15,11 +20,12 @@ def add_app_bots_to_project(project_id: str, user_id: Optional[str] = None) -> N
This ensures any workspace app bot is automatically added as a project member.
"""
try:
logger.info(f"Adding app bots to project {project_id}")
# Get the project
try:
project = Project.objects.get(id=project_id)
except Project.DoesNotExist:
print(f"Project with ID {project_id} does not exist")
logger.info(f"Project with ID {project_id} does not exist")
return
# Find all active app installations for this project's workspace
@@ -49,4 +55,4 @@ def add_app_bots_to_project(project_id: str, user_id: Optional[str] = None) -> N
if project_members:
ProjectMember.objects.bulk_create(project_members, ignore_conflicts=True)
except Exception as e:
print(f"Error adding app bots to project {project_id}: {str(e)}")
log_exception(e)