From bf8539deef73e12924535fb14e558ea235892ce5 Mon Sep 17 00:00:00 2001 From: Achintya-Chatterjee Date: Sat, 26 Jul 2025 00:51:27 +0530 Subject: [PATCH 1/3] fix: show tasks assigned to team members in team todo list - Updated TaskRepository to include tasks assigned to team members in team's todo list - Modified _get_assigned_task_ids_for_team to aggregate both direct team and member assignments - Ensured team task queries now reflect all relevant tasks for the team --- todo/repositories/task_repository.py | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/todo/repositories/task_repository.py b/todo/repositories/task_repository.py index 10b97363..56c29cd4 100644 --- a/todo/repositories/task_repository.py +++ b/todo/repositories/task_repository.py @@ -46,8 +46,7 @@ def list( if team_id: logger.debug(f"TaskRepository.list: team_id={team_id}") - team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - team_task_ids = [assignment.task_id for assignment in team_assignments] + team_task_ids = cls._get_assigned_task_ids_for_team(team_id) logger.debug(f"TaskRepository.list: team_task_ids={team_task_ids}") query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} logger.debug(f"TaskRepository.list: query_filter={query_filter}") @@ -91,6 +90,24 @@ def _get_assigned_task_ids_for_user(cls, user_id: str) -> List[ObjectId]: return direct_task_ids + team_task_ids + @classmethod + def _get_assigned_task_ids_for_team(cls, team_id: str) -> List[ObjectId]: + """Get task IDs where team is assigned (either directly or via team members).""" + + direct_team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") + direct_team_task_ids = [assignment.task_id for assignment in direct_team_assignments] + + from todo.repositories.team_repository import UserTeamDetailsRepository + + team_member_ids = UserTeamDetailsRepository.get_users_by_team_id(team_id) + + member_task_ids = [] + for member_id in team_member_ids: + member_assignments = TaskAssignmentRepository.get_by_assignee_id(member_id, "user") + member_task_ids.extend([assignment.task_id for assignment in member_assignments]) + + return direct_team_task_ids + member_task_ids + @classmethod def count(cls, user_id: str = None, team_id: str = None, status_filter: str = None) -> int: tasks_collection = cls.get_collection() @@ -98,8 +115,7 @@ def count(cls, user_id: str = None, team_id: str = None, status_filter: str = No base_filter = cls._build_status_filter(status_filter) if team_id: - team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - team_task_ids = [assignment.task_id for assignment in team_assignments] + team_task_ids = cls._get_assigned_task_ids_for_team(team_id) query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} elif user_id: assigned_task_ids = cls._get_assigned_task_ids_for_user(user_id) From c5f9be8c0ee18f0c009552775021d698545c48f2 Mon Sep 17 00:00:00 2001 From: Achintya-Chatterjee Date: Wed, 30 Jul 2025 02:35:50 +0530 Subject: [PATCH 2/3] chore: remove unnecessary code --- todo/repositories/task_repository.py | 44 ++++++++++++---------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/todo/repositories/task_repository.py b/todo/repositories/task_repository.py index 56c29cd4..eb27c0b2 100644 --- a/todo/repositories/task_repository.py +++ b/todo/repositories/task_repository.py @@ -46,7 +46,8 @@ def list( if team_id: logger.debug(f"TaskRepository.list: team_id={team_id}") - team_task_ids = cls._get_assigned_task_ids_for_team(team_id) + team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") + team_task_ids = [assignment.task_id for assignment in team_assignments] logger.debug(f"TaskRepository.list: team_task_ids={team_task_ids}") query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} logger.debug(f"TaskRepository.list: query_filter={query_filter}") @@ -77,37 +78,29 @@ def _get_assigned_task_ids_for_user(cls, user_id: str) -> List[ObjectId]: direct_task_ids = [assignment.task_id for assignment in direct_assignments] # Get teams where user is a member - from todo.repositories.team_repository import UserTeamDetailsRepository + from todo.repositories.team_repository import UserTeamDetailsRepository, TeamRepository user_teams = UserTeamDetailsRepository.get_by_user_id(user_id) team_ids = [str(team.team_id) for team in user_teams] - # Get tasks assigned to those teams + # Get tasks assigned to those teams (only if user is POC) team_task_ids = [] - for team_id in team_ids: - team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - team_task_ids.extend([assignment.task_id for assignment in team_assignments]) + if team_ids: + # Get teams where user is POC + poc_teams = TeamRepository.get_collection().find( + {"_id": {"$in": [ObjectId(team_id) for team_id in team_ids]}, "is_deleted": False, "poc_id": user_id} + ) + poc_team_ids = [str(team["_id"]) for team in poc_teams] + + # Get team assignments for POC teams + if poc_team_ids: + team_assignments = TaskAssignmentRepository.get_collection().find( + {"assignee_id": {"$in": poc_team_ids}, "user_type": "team", "is_active": True} + ) + team_task_ids = [ObjectId(assignment["task_id"]) for assignment in team_assignments] return direct_task_ids + team_task_ids - @classmethod - def _get_assigned_task_ids_for_team(cls, team_id: str) -> List[ObjectId]: - """Get task IDs where team is assigned (either directly or via team members).""" - - direct_team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - direct_team_task_ids = [assignment.task_id for assignment in direct_team_assignments] - - from todo.repositories.team_repository import UserTeamDetailsRepository - - team_member_ids = UserTeamDetailsRepository.get_users_by_team_id(team_id) - - member_task_ids = [] - for member_id in team_member_ids: - member_assignments = TaskAssignmentRepository.get_by_assignee_id(member_id, "user") - member_task_ids.extend([assignment.task_id for assignment in member_assignments]) - - return direct_team_task_ids + member_task_ids - @classmethod def count(cls, user_id: str = None, team_id: str = None, status_filter: str = None) -> int: tasks_collection = cls.get_collection() @@ -115,7 +108,8 @@ def count(cls, user_id: str = None, team_id: str = None, status_filter: str = No base_filter = cls._build_status_filter(status_filter) if team_id: - team_task_ids = cls._get_assigned_task_ids_for_team(team_id) + team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") + team_task_ids = [assignment.task_id for assignment in team_assignments] query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} elif user_id: assigned_task_ids = cls._get_assigned_task_ids_for_user(user_id) From c70183bb358d4f781fa490072ffefe19f0d761d5 Mon Sep 17 00:00:00 2001 From: Achintya-Chatterjee Date: Thu, 31 Jul 2025 01:38:37 +0530 Subject: [PATCH 3/3] refactor: Optimize team todo list to include member assignments - Replace inefficient for loops with MongoDB aggregation pipeline - Fix ObjectId/string data type mismatch in task queries - Ensure tasks assigned to team members appear in team todo list - Improve performance by reducing database round trips from N+1 to 1 query - Add proper ObjectId conversion for MongoDB _id field queries --- todo/repositories/task_repository.py | 38 +++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/todo/repositories/task_repository.py b/todo/repositories/task_repository.py index eb27c0b2..801f78f1 100644 --- a/todo/repositories/task_repository.py +++ b/todo/repositories/task_repository.py @@ -46,10 +46,10 @@ def list( if team_id: logger.debug(f"TaskRepository.list: team_id={team_id}") - team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - team_task_ids = [assignment.task_id for assignment in team_assignments] - logger.debug(f"TaskRepository.list: team_task_ids={team_task_ids}") - query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} + + all_task_object_ids = cls._get_team_task_ids(team_id) + + query_filter = {"$and": [base_filter, {"_id": {"$in": all_task_object_ids}}]} logger.debug(f"TaskRepository.list: query_filter={query_filter}") elif user_id: assigned_task_ids = cls._get_assigned_task_ids_for_user(user_id) @@ -101,6 +101,31 @@ def _get_assigned_task_ids_for_user(cls, user_id: str) -> List[ObjectId]: return direct_task_ids + team_task_ids + @classmethod + def _get_team_task_ids(cls, team_id: str) -> List[ObjectId]: + """Get task IDs for a team (both team assignments and member assignments).""" + from todo.repositories.team_repository import UserTeamDetailsRepository + from bson import ObjectId + + team_members = UserTeamDetailsRepository.get_users_by_team_id(team_id) + + pipeline = [ + { + "$match": { + "$or": [ + {"assignee_id": team_id, "user_type": "team", "is_active": True}, + {"assignee_id": {"$in": team_members}, "user_type": "user", "is_active": True}, + ] + } + }, + {"$project": {"task_id": 1}}, + ] + + assignments = TaskAssignmentRepository.get_collection().aggregate(pipeline) + all_task_ids = [assignment["task_id"] for assignment in assignments] + + return [ObjectId(task_id) for task_id in all_task_ids] + @classmethod def count(cls, user_id: str = None, team_id: str = None, status_filter: str = None) -> int: tasks_collection = cls.get_collection() @@ -108,9 +133,8 @@ def count(cls, user_id: str = None, team_id: str = None, status_filter: str = No base_filter = cls._build_status_filter(status_filter) if team_id: - team_assignments = TaskAssignmentRepository.get_by_assignee_id(team_id, "team") - team_task_ids = [assignment.task_id for assignment in team_assignments] - query_filter = {"$and": [base_filter, {"_id": {"$in": team_task_ids}}]} + all_task_object_ids = cls._get_team_task_ids(team_id) + query_filter = {"$and": [base_filter, {"_id": {"$in": all_task_object_ids}}]} elif user_id: assigned_task_ids = cls._get_assigned_task_ids_for_user(user_id) query_filter = {