Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion todo/models/audit_log.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
52 changes: 51 additions & 1 deletion todo/services/team_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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),
Expand All @@ -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
3 changes: 2 additions & 1 deletion todo/views/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading