Skip to content

Commit cf9997b

Browse files
feat: add assignee details to watchlist tasks (#211)
- Introduced AssigneeDTO to encapsulate assignee information, including id, name, email, and type (user or team). - Updated WatchlistDTO to include an optional assignee field. - Enhanced WatchlistRepository to fetch and include assignee details when retrieving watchlisted tasks. - Implemented fallback logic to retrieve assignee information if not present in the initial query. - Updated WatchlistService to handle assignee data during task preparation. - Added unit tests to verify functionality for tasks with and without assignees. This update improves task management by clearly associating tasks with their respective assignees, enhancing user experience and task ownership visibility. Co-authored-by: Amit Prakash <[email protected]>
1 parent fe4a68b commit cf9997b

File tree

7 files changed

+611
-5
lines changed

7 files changed

+611
-5
lines changed

debug_assignee.py

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Debug script to help identify why assignee details might be showing as null.
4+
Run this script to check the data structure and identify issues.
5+
"""
6+
7+
import os
8+
import sys
9+
import django
10+
from bson import ObjectId
11+
12+
# Add the project root to the Python path
13+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
14+
15+
# Setup Django
16+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todo_project.settings.development')
17+
django.setup()
18+
19+
from todo.repositories.watchlist_repository import WatchlistRepository
20+
from todo.repositories.task_assignment_repository import TaskAssignmentRepository
21+
from todo.repositories.user_repository import UserRepository
22+
from todo.repositories.team_repository import TeamRepository
23+
from todo.repositories.task_repository import TaskRepository
24+
25+
26+
def debug_assignee_issue():
27+
"""Debug function to identify assignee issues"""
28+
29+
print("=== Debugging Assignee Issue ===\n")
30+
31+
# 1. Check if there are any watchlist entries
32+
print("1. Checking watchlist entries...")
33+
watchlist_collection = WatchlistRepository.get_collection()
34+
watchlist_count = watchlist_collection.count_documents({})
35+
print(f" Total watchlist entries: {watchlist_count}")
36+
37+
if watchlist_count > 0:
38+
sample_watchlist = watchlist_collection.find_one()
39+
print(f" Sample watchlist entry: {sample_watchlist}")
40+
41+
# 2. Check if there are any task assignments
42+
print("\n2. Checking task assignments...")
43+
task_details_collection = TaskAssignmentRepository.get_collection()
44+
assignment_count = task_details_collection.count_documents({})
45+
print(f" Total task assignments: {assignment_count}")
46+
47+
if assignment_count > 0:
48+
sample_assignment = task_details_collection.find_one()
49+
print(f" Sample task assignment: {sample_assignment}")
50+
51+
# 3. Check if there are any tasks
52+
print("\n3. Checking tasks...")
53+
task_collection = TaskRepository.get_collection()
54+
task_count = task_collection.count_documents({})
55+
print(f" Total tasks: {task_count}")
56+
57+
if task_count > 0:
58+
sample_task = task_collection.find_one()
59+
print(f" Sample task: {sample_task}")
60+
61+
# 4. Check if there are any users
62+
print("\n4. Checking users...")
63+
user_collection = UserRepository._get_collection()
64+
user_count = user_collection.count_documents({})
65+
print(f" Total users: {user_count}")
66+
67+
if user_count > 0:
68+
sample_user = user_collection.find_one()
69+
print(f" Sample user: {sample_user}")
70+
71+
# 5. Check if there are any teams
72+
print("\n5. Checking teams...")
73+
team_collection = TeamRepository.get_collection()
74+
team_count = team_collection.count_documents({})
75+
print(f" Total teams: {team_count}")
76+
77+
if team_count > 0:
78+
sample_team = team_collection.find_one()
79+
print(f" Sample team: {sample_team}")
80+
81+
# 6. Test the aggregation pipeline
82+
print("\n6. Testing aggregation pipeline...")
83+
if watchlist_count > 0:
84+
try:
85+
# Get a sample user_id from watchlist
86+
sample_watchlist = watchlist_collection.find_one()
87+
if sample_watchlist:
88+
user_id = sample_watchlist.get('userId')
89+
print(f" Testing with user_id: {user_id}")
90+
91+
# Run the aggregation pipeline
92+
count, tasks = WatchlistRepository.get_watchlisted_tasks(1, 10, user_id)
93+
print(f" Found {count} tasks for user {user_id}")
94+
95+
if tasks:
96+
print(f" First task: {tasks[0].model_dump() if hasattr(tasks[0], 'model_dump') else tasks[0]}")
97+
else:
98+
print(" No tasks found")
99+
100+
except Exception as e:
101+
print(f" Error in aggregation: {e}")
102+
103+
# 7. Test the fallback method
104+
print("\n7. Testing fallback method...")
105+
if task_count > 0:
106+
try:
107+
sample_task = task_collection.find_one()
108+
if sample_task:
109+
task_id = str(sample_task['_id'])
110+
print(f" Testing fallback with task_id: {task_id}")
111+
112+
assignee = WatchlistRepository._get_assignee_for_task(task_id)
113+
print(f" Fallback assignee result: {assignee}")
114+
115+
except Exception as e:
116+
print(f" Error in fallback method: {e}")
117+
118+
print("\n=== Debug Complete ===")
119+
120+
121+
if __name__ == "__main__":
122+
debug_assignee_issue()

test_assignee_with_data.py

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test script to create sample data and test the assignee functionality.
4+
This will help verify that the assignee details are working correctly.
5+
"""
6+
7+
import os
8+
import sys
9+
import django
10+
from bson import ObjectId
11+
from datetime import datetime, timezone
12+
13+
# Add the project root to the Python path
14+
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
15+
16+
# Setup Django
17+
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'todo_project.settings.development')
18+
django.setup()
19+
20+
from todo.models.user import UserModel
21+
from todo.models.team import TeamModel
22+
from todo.models.task import TaskModel
23+
from todo.models.task_assignment import TaskAssignmentModel
24+
from todo.models.watchlist import WatchlistModel
25+
from todo.repositories.user_repository import UserRepository
26+
from todo.repositories.team_repository import TeamRepository
27+
from todo.repositories.task_repository import TaskRepository
28+
from todo.repositories.task_assignment_repository import TaskAssignmentRepository
29+
from todo.repositories.watchlist_repository import WatchlistRepository
30+
31+
32+
def create_sample_data():
33+
"""Create sample data for testing assignee functionality"""
34+
35+
print("=== Creating Sample Data ===\n")
36+
37+
# 1. Create a sample user
38+
print("1. Creating sample user...")
39+
user_data = {
40+
"google_id": "test_google_id_123",
41+
"email": "[email protected]",
42+
"name": "Test User",
43+
"picture": "https://example.com/picture.jpg"
44+
}
45+
user = UserRepository.create_or_update(user_data)
46+
print(f" Created user: {user.name} ({user.email_id})")
47+
48+
# 2. Create a sample team
49+
print("\n2. Creating sample team...")
50+
team = TeamModel(
51+
name="Test Team",
52+
description="A test team for assignee testing",
53+
invite_code="TEST123",
54+
created_by=user.id,
55+
updated_by=user.id
56+
)
57+
team = TeamRepository.create(team)
58+
print(f" Created team: {team.name}")
59+
60+
# 3. Create a sample task
61+
print("\n3. Creating sample task...")
62+
task = TaskModel(
63+
title="Test Task with Assignee",
64+
description="This is a test task to verify assignee functionality",
65+
priority="HIGH",
66+
status="TODO",
67+
created_by=user.id
68+
)
69+
task = TaskRepository.create(task)
70+
print(f" Created task: {task.title}")
71+
72+
# 4. Create a task assignment (assign task to user)
73+
print("\n4. Creating task assignment (user assignee)...")
74+
assignment = TaskAssignmentModel(
75+
task_id=task.id,
76+
assignee_id=user.id,
77+
user_type="user",
78+
created_by=user.id
79+
)
80+
assignment = TaskAssignmentRepository.create(assignment)
81+
print(f" Assigned task to user: {user.name}")
82+
83+
# 5. Create another task assigned to team
84+
print("\n5. Creating task assigned to team...")
85+
team_task = TaskModel(
86+
title="Team Task",
87+
description="This task is assigned to a team",
88+
priority="MEDIUM",
89+
status="IN_PROGRESS",
90+
created_by=user.id
91+
)
92+
team_task = TaskRepository.create(team_task)
93+
print(f" Created team task: {team_task.title}")
94+
95+
team_assignment = TaskAssignmentModel(
96+
task_id=team_task.id,
97+
assignee_id=team.id,
98+
user_type="team",
99+
created_by=user.id
100+
)
101+
team_assignment = TaskAssignmentRepository.create(team_assignment)
102+
print(f" Assigned task to team: {team.name}")
103+
104+
# 6. Create an unassigned task
105+
print("\n6. Creating unassigned task...")
106+
unassigned_task = TaskModel(
107+
title="Unassigned Task",
108+
description="This task has no assignee",
109+
priority="LOW",
110+
status="TODO",
111+
created_by=user.id
112+
)
113+
unassigned_task = TaskRepository.create(unassigned_task)
114+
print(f" Created unassigned task: {unassigned_task.title}")
115+
116+
# 7. Add tasks to watchlist
117+
print("\n7. Adding tasks to watchlist...")
118+
119+
# Add user-assigned task to watchlist
120+
user_watchlist = WatchlistModel(
121+
taskId=str(task.id),
122+
userId=str(user.id),
123+
createdBy=str(user.id)
124+
)
125+
user_watchlist = WatchlistRepository.create(user_watchlist)
126+
print(f" Added user task to watchlist")
127+
128+
# Add team-assigned task to watchlist
129+
team_watchlist = WatchlistModel(
130+
taskId=str(team_task.id),
131+
userId=str(user.id),
132+
createdBy=str(user.id)
133+
)
134+
team_watchlist = WatchlistRepository.create(team_watchlist)
135+
print(f" Added team task to watchlist")
136+
137+
# Add unassigned task to watchlist
138+
unassigned_watchlist = WatchlistModel(
139+
taskId=str(unassigned_task.id),
140+
userId=str(user.id),
141+
createdBy=str(user.id)
142+
)
143+
unassigned_watchlist = WatchlistRepository.create(unassigned_watchlist)
144+
print(f" Added unassigned task to watchlist")
145+
146+
return user.id, task.id, team_task.id, unassigned_task.id
147+
148+
149+
def test_assignee_functionality(user_id, task_id, team_task_id, unassigned_task_id):
150+
"""Test the assignee functionality with the created data"""
151+
152+
print("\n=== Testing Assignee Functionality ===\n")
153+
154+
# Test the watchlist endpoint
155+
print("1. Testing watchlist with assignee details...")
156+
try:
157+
count, tasks = WatchlistRepository.get_watchlisted_tasks(1, 10, str(user_id))
158+
print(f" Found {count} watchlisted tasks")
159+
160+
for i, task in enumerate(tasks, 1):
161+
print(f"\n Task {i}:")
162+
print(f" Title: {task.title}")
163+
print(f" Task ID: {task.taskId}")
164+
print(f" Assignee: {task.assignee}")
165+
166+
if task.assignee:
167+
print(f" Assignee Type: {task.assignee.type}")
168+
print(f" Assignee Name: {task.assignee.name}")
169+
print(f" Assignee Email: {task.assignee.email}")
170+
else:
171+
print(f" Assignee: None (unassigned task)")
172+
173+
except Exception as e:
174+
print(f" Error testing watchlist: {e}")
175+
176+
# Test the fallback method
177+
print("\n2. Testing fallback method...")
178+
try:
179+
user_assignee = WatchlistRepository._get_assignee_for_task(str(task_id))
180+
print(f" User task assignee: {user_assignee}")
181+
182+
team_assignee = WatchlistRepository._get_assignee_for_task(str(team_task_id))
183+
print(f" Team task assignee: {team_assignee}")
184+
185+
unassigned_assignee = WatchlistRepository._get_assignee_for_task(str(unassigned_task_id))
186+
print(f" Unassigned task assignee: {unassigned_assignee}")
187+
188+
except Exception as e:
189+
print(f" Error testing fallback: {e}")
190+
191+
192+
def cleanup_sample_data():
193+
"""Clean up the sample data"""
194+
print("\n=== Cleaning Up Sample Data ===\n")
195+
196+
try:
197+
# Clean up watchlist
198+
watchlist_collection = WatchlistRepository.get_collection()
199+
watchlist_collection.delete_many({"userId": {"$regex": "test"}})
200+
print(" Cleaned up watchlist entries")
201+
202+
# Clean up task assignments
203+
task_details_collection = TaskAssignmentRepository.get_collection()
204+
task_details_collection.delete_many({"created_by": {"$regex": "test"}})
205+
print(" Cleaned up task assignments")
206+
207+
# Clean up tasks
208+
task_collection = TaskRepository.get_collection()
209+
task_collection.delete_many({"title": {"$regex": "Test"}})
210+
print(" Cleaned up tasks")
211+
212+
# Clean up teams
213+
team_collection = TeamRepository.get_collection()
214+
team_collection.delete_many({"name": "Test Team"})
215+
print(" Cleaned up teams")
216+
217+
# Clean up users
218+
user_collection = UserRepository._get_collection()
219+
user_collection.delete_many({"email_id": "[email protected]"})
220+
print(" Cleaned up users")
221+
222+
except Exception as e:
223+
print(f" Error during cleanup: {e}")
224+
225+
226+
if __name__ == "__main__":
227+
try:
228+
# Create sample data
229+
user_id, task_id, team_task_id, unassigned_task_id = create_sample_data()
230+
231+
# Test the functionality
232+
test_assignee_functionality(user_id, task_id, team_task_id, unassigned_task_id)
233+
234+
# Ask if user wants to clean up
235+
response = input("\nDo you want to clean up the sample data? (y/n): ")
236+
if response.lower() == 'y':
237+
cleanup_sample_data()
238+
print(" Cleanup completed!")
239+
else:
240+
print(" Sample data left in database for further testing")
241+
242+
except Exception as e:
243+
print(f"Error: {e}")
244+
import traceback
245+
traceback.print_exc()

todo/dto/watchlist_dto.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@
55
from todo.constants.task import TaskPriority, TaskStatus
66

77

8+
class AssigneeDTO(BaseModel):
9+
id: str
10+
name: str
11+
email: str
12+
type: str # "user" or "team"
13+
14+
815
class WatchlistDTO(BaseModel):
916
taskId: str
1017
displayId: str
@@ -19,6 +26,7 @@ class WatchlistDTO(BaseModel):
1926
createdAt: datetime
2027
createdBy: str
2128
watchlistId: str
29+
assignee: Optional[AssigneeDTO] = None
2230

2331
class Config:
2432
json_encoders = {TaskPriority: lambda x: x.name}

0 commit comments

Comments
 (0)