Skip to content
138 changes: 138 additions & 0 deletions todo/migrations/0004_backfill_user_role_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Generated by Django 5.1.5 on 2025-09-23 07:25

from django.db import migrations
import logging
import sys
from todo.repositories.user_role_repository import UserRoleRepository
from todo.repositories.team_repository import TeamRepository, UserTeamDetailsRepository
from todo.constants.role import RoleScope, RoleName
from datetime import datetime, timezone
from todo.services.enhanced_dual_write_service import EnhancedDualWriteService

logger = logging.getLogger(__name__)


def fix_team_roles(apps, schema_editor):
logger.info("\n--- Starting Team Roles Fix Script ---")
if "test" in sys.argv:
logger.info("\n--- Skipping Team Roles Fix Script in test environment ---")
return
teams_data = TeamRepository.get_collection().find({"is_deleted": False})
roles_scope = RoleScope.TEAM.value

roles_ensured = 0
roles_deactivated = 0
dual_write_service = EnhancedDualWriteService()

roles_to_assign = []
roles_to_remove = []
postgres_operations = []

for team in teams_data:
team_id = str(team["_id"])
team_owner = team["created_by"]
team_members = list(UserTeamDetailsRepository.get_by_team_id(team_id))
for member in team_members:
member_id = str(member.user_id)
if member_id == team_owner:
member_roles = UserRoleRepository.get_user_roles(member_id, roles_scope, team_id)
existing_roles = [role.role_name for role in member_roles]
for role in (RoleName.OWNER.value, RoleName.ADMIN.value, RoleName.MEMBER.value):
if role not in existing_roles:
roles_to_assign.append(
{
"user_id": member_id,
"role_name": role,
"scope": roles_scope,
"team_id": team_id,
"is_active": True,
"created_at": datetime.now(timezone.utc),
"created_by": "system",
}
)
else:
member_roles = UserRoleRepository.get_user_roles(member_id, roles_scope, team_id)
has_member_role = False
for role in member_roles:
if role.role_name == RoleName.MEMBER.value:
has_member_role = True
else:
roles_to_remove.append(
{
"mongo_id": role.id,
"user_id": member_id,
"role_name": role.role_name,
"scope": roles_scope,
"team_id": role.team_id,
"is_active": role.is_active,
"created_by": role.created_by,
"created_at": role.created_at,
}
)
if not has_member_role:
roles_to_assign.append(
{
"user_id": member_id,
"role_name": RoleName.MEMBER.value,
"scope": roles_scope,
"team_id": team_id,
"is_active": True,
"created_at": datetime.now(timezone.utc),
"created_by": "system",
}
)
if roles_to_assign:
result = UserRoleRepository.get_collection().insert_many(roles_to_assign)
roles_ensured = len(result.inserted_ids)
logger.info(f"Successfully inserted {roles_ensured} new roles.")

for role_data, mongo_id in zip(roles_to_assign, result.inserted_ids):
postgres_operations.append(
{
"operation": "create",
"collection_name": "user_roles",
"mongo_id": str(mongo_id),
"data": role_data,
}
)

if roles_to_remove:
for role in roles_to_remove:
mongo_id = str(role["mongo_id"])
postgres_operations.append(
{
"operation": "update",
"collection_name": "user_roles",
"mongo_id": mongo_id,
"data": {
"user_id": role["user_id"],
"role_name": role["role_name"],
"scope": role["scope"],
"team_id": role["team_id"],
"is_active": False,
"created_at": role["created_at"],
"created_by": role["created_by"],
},
}
)
role_ids_to_remove = [roles["mongo_id"] for roles in roles_to_remove]
result = UserRoleRepository.get_collection().update_many(
{"_id": {"$in": role_ids_to_remove}}, {"$set": {"is_active": False}}
)
roles_deactivated = result.modified_count
logger.info(f"Successfully deactivated {roles_deactivated} roles.")
if postgres_operations:
logger.info(f"\nStarting sync of {len(postgres_operations)} operations to PostgreSQL...")
success = dual_write_service.batch_operations(postgres_operations)
if success:
logger.info("PostgreSQL sync completed successfully.")
else:
logger.warning("PostgreSQL sync encountered errors. Check logs for details.")


class Migration(migrations.Migration):
dependencies = [
("todo", "0003_alter_postgresuserrole_unique_together_and_more"),
]

operations = [migrations.RunPython(fix_team_roles, migrations.RunPython.noop)]