mirror of
https://github.com/makeplane/plane.git
synced 2026-07-12 21:40:18 +02:00
[SILO-348] fix: on Project save, add app bots as members (#3550)
This commit is contained in:
@@ -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),
|
||||
]
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user