From 8b01ccf04657bdf3e4d5b566b4df5c54cbecb0c7 Mon Sep 17 00:00:00 2001 From: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> Date: Sun, 27 Jul 2025 01:58:04 +0530 Subject: [PATCH 1/5] feat: enhance audit logging for team management actions - Updated AuditLogModel to include additional action types: "team_created", "member_joined_team", "member_added_to_team", "member_removed_from_team", and "team_updated". - Implemented audit logging in TeamService for team creation, member joining, member addition, member removal, and team updates to improve tracking of team activities. - Modified RemoveTeamMemberView to pass the user performing the removal for better audit trail. These changes improve accountability and traceability of team management actions. --- todo/models/audit_log.py | 2 +- todo/services/team_service.py | 52 ++++++++++++++++++++++++++++++++++- todo/views/team.py | 3 +- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/todo/models/audit_log.py b/todo/models/audit_log.py index e419ac0f..aa17809c 100644 --- a/todo/models/audit_log.py +++ b/todo/models/audit_log.py @@ -13,7 +13,7 @@ class AuditLogModel(Document): previous_executor_id: PyObjectId | None = None new_executor_id: PyObjectId | None = None spoc_id: PyObjectId | None = None - action: str # e.g., "assigned_to_team", "unassigned_from_team", "status_changed", "reassign_executor" + action: str # e.g., "assigned_to_team", "unassigned_from_team", "status_changed", "reassign_executor", "team_created", "member_joined_team", "member_added_to_team", "member_removed_from_team", "team_updated" timestamp: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) # For status changes status_from: str | None = None diff --git a/todo/services/team_service.py b/todo/services/team_service.py index df4fd0d0..1e936562 100644 --- a/todo/services/team_service.py +++ b/todo/services/team_service.py @@ -8,6 +8,9 @@ from todo.constants.messages import AppMessages from todo.utils.invite_code_utils import generate_invite_code from typing import List +from datetime import datetime, timezone +from todo.models.audit_log import AuditLogModel +from todo.repositories.audit_log_repository import AuditLogRepository DEFAULT_ROLE_ID = "1" @@ -90,6 +93,15 @@ def create_team(cls, dto: CreateTeamDTO, created_by_user_id: str) -> CreateTeamR if user_teams: UserTeamDetailsRepository.create_many(user_teams) + # Audit log for team creation + AuditLogRepository.create( + AuditLogModel( + team_id=created_team.id, + action="team_created", + performed_by=PyObjectId(created_by_user_id), + ) + ) + # Convert to DTO team_dto = TeamDTO( id=str(created_team.id), @@ -226,6 +238,15 @@ def join_team_by_invite_code(cls, invite_code: str, user_id: str) -> TeamDTO: ) UserTeamDetailsRepository.create(user_team) + # Audit log for team join + AuditLogRepository.create( + AuditLogModel( + team_id=team.id, + action="member_joined_team", + performed_by=PyObjectId(user_id), + ) + ) + # 4. Return team details return TeamDTO( id=str(team.id), @@ -283,6 +304,15 @@ def update_team(cls, team_id: str, dto: UpdateTeamDTO, updated_by_user_id: str) if not success: raise ValueError(f"Failed to update team members for team with id {team_id}") + # Audit log for team update + AuditLogRepository.create( + AuditLogModel( + team_id=PyObjectId(team_id), + action="team_updated", + performed_by=PyObjectId(updated_by_user_id), + ) + ) + # Convert to DTO return TeamDTO( id=str(updated_team.id), @@ -364,6 +394,16 @@ def add_team_members(cls, team_id: str, member_ids: List[str], added_by_user_id: if new_user_teams: UserTeamDetailsRepository.create_many(new_user_teams) + # Audit log for team member addition + for member_id in member_ids: + AuditLogRepository.create( + AuditLogModel( + team_id=team.id, + action="member_added_to_team", + performed_by=PyObjectId(added_by_user_id), + ) + ) + # Return updated team details return TeamDTO( id=str(team.id), @@ -384,10 +424,20 @@ class TeamOrUserNotFound(Exception): pass @classmethod - def remove_member_from_team(cls, user_id: str, team_id: str): + def remove_member_from_team(cls, user_id: str, team_id: str, removed_by_user_id: str = None): from todo.repositories.user_team_details_repository import UserTeamDetailsRepository success = UserTeamDetailsRepository.remove_member_from_team(user_id=user_id, team_id=team_id) if not success: raise cls.TeamOrUserNotFound() + + # Audit log for team member removal + AuditLogRepository.create( + AuditLogModel( + team_id=PyObjectId(team_id), + action="member_removed_from_team", + performed_by=PyObjectId(removed_by_user_id) if removed_by_user_id else PyObjectId(user_id), + ) + ) + return True diff --git a/todo/views/team.py b/todo/views/team.py index c2d44d7f..e50304b2 100644 --- a/todo/views/team.py +++ b/todo/views/team.py @@ -473,7 +473,8 @@ def delete(self, request, team_id, user_id): from todo.services.team_service import TeamService try: - TeamService.remove_member_from_team(user_id=user_id, team_id=team_id) + # Pass the user performing the removal (request.user_id) and the user being removed (user_id) + TeamService.remove_member_from_team(user_id=user_id, team_id=team_id, removed_by_user_id=request.user_id) return Response(status=status.HTTP_204_NO_CONTENT) except TeamService.TeamOrUserNotFound: return Response({"detail": "Team or user not found."}, status=status.HTTP_404_NOT_FOUND) From 01c8cfec7aa3eb6e78b08d0d3e1eeb903e1f1861 Mon Sep 17 00:00:00 2001 From: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> Date: Sun, 27 Jul 2025 02:00:32 +0530 Subject: [PATCH 2/5] refactor: clean up unused import in team_service.py - Removed the unused datetime and timezone import from team_service.py to streamline the code and improve maintainability. This change contributes to a cleaner and more organized codebase. --- todo/services/team_service.py | 1 - 1 file changed, 1 deletion(-) diff --git a/todo/services/team_service.py b/todo/services/team_service.py index 1e936562..b0f03b7d 100644 --- a/todo/services/team_service.py +++ b/todo/services/team_service.py @@ -8,7 +8,6 @@ from todo.constants.messages import AppMessages from todo.utils.invite_code_utils import generate_invite_code from typing import List -from datetime import datetime, timezone from todo.models.audit_log import AuditLogModel from todo.repositories.audit_log_repository import AuditLogRepository From 9038905f31e45ec5212b5e20f05d11c4181ae361 Mon Sep 17 00:00:00 2001 From: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> Date: Sun, 27 Jul 2025 02:01:03 +0530 Subject: [PATCH 3/5] refactor: clean up whitespace in team_service.py - Removed unnecessary blank lines in the team_service.py file to improve code readability and maintainability. This change contributes to a cleaner and more organized codebase. --- todo/services/team_service.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/todo/services/team_service.py b/todo/services/team_service.py index b0f03b7d..1eb89149 100644 --- a/todo/services/team_service.py +++ b/todo/services/team_service.py @@ -429,7 +429,7 @@ def remove_member_from_team(cls, user_id: str, team_id: str, removed_by_user_id: success = UserTeamDetailsRepository.remove_member_from_team(user_id=user_id, team_id=team_id) if not success: raise cls.TeamOrUserNotFound() - + # Audit log for team member removal AuditLogRepository.create( AuditLogModel( @@ -438,5 +438,5 @@ def remove_member_from_team(cls, user_id: str, team_id: str, removed_by_user_id: performed_by=PyObjectId(removed_by_user_id) if removed_by_user_id else PyObjectId(user_id), ) ) - + return True From 1c9447316f817266596bf93224f85633b812c574 Mon Sep 17 00:00:00 2001 From: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> Date: Sun, 27 Jul 2025 02:02:57 +0530 Subject: [PATCH 4/5] feat: enhance audit logging by adding member ID details - Updated the audit logging in TeamService to include the added member's ID in the details of the "member_added_to_team" action. This change improves the traceability of team member additions, enhancing accountability in team management activities. --- todo/services/team_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/todo/services/team_service.py b/todo/services/team_service.py index 1eb89149..d70fdb20 100644 --- a/todo/services/team_service.py +++ b/todo/services/team_service.py @@ -400,6 +400,7 @@ def add_team_members(cls, team_id: str, member_ids: List[str], added_by_user_id: team_id=team.id, action="member_added_to_team", performed_by=PyObjectId(added_by_user_id), + details={"added_member_id": member_id} ) ) From 9c80976272f6e52af3d0821bc28d3e7cff724d83 Mon Sep 17 00:00:00 2001 From: Amit Prakash <34869115+iamitprakash@users.noreply.github.com> Date: Sun, 27 Jul 2025 02:07:13 +0530 Subject: [PATCH 5/5] fix: add missing comma in audit logging details - Added a missing comma in the details dictionary of the "member_added_to_team" action in TeamService. This minor fix ensures proper syntax and prevents potential issues in the logging functionality. --- todo/services/team_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/todo/services/team_service.py b/todo/services/team_service.py index d70fdb20..36010209 100644 --- a/todo/services/team_service.py +++ b/todo/services/team_service.py @@ -400,7 +400,7 @@ def add_team_members(cls, team_id: str, member_ids: List[str], added_by_user_id: team_id=team.id, action="member_added_to_team", performed_by=PyObjectId(added_by_user_id), - details={"added_member_id": member_id} + details={"added_member_id": member_id}, ) )