Fix test failures and workload/websocket behavior
This commit is contained in:
@@ -13,9 +13,9 @@ from typing import Optional, List, Dict, Any, Tuple, Set
|
||||
|
||||
from croniter import croniter
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import func
|
||||
|
||||
from app.models import Trigger, TriggerLog, Task, Project
|
||||
from app.models import Trigger, TriggerLog, Task, Project, ProjectMember, User, Role
|
||||
from app.services.notification_service import NotificationService
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -408,41 +408,77 @@ class TriggerSchedulerService:
|
||||
logger.warning(f"Trigger {trigger.id} has no associated project")
|
||||
return
|
||||
|
||||
target_user_id = TriggerSchedulerService._resolve_target(project, target)
|
||||
if not target_user_id:
|
||||
recipient_ids = TriggerSchedulerService._resolve_target(db, project, target)
|
||||
if not recipient_ids:
|
||||
logger.debug(f"No target user resolved for trigger {trigger.id} with target '{target}'")
|
||||
return
|
||||
|
||||
# Format message with variables
|
||||
message = TriggerSchedulerService._format_template(template, trigger, project)
|
||||
|
||||
NotificationService.create_notification(
|
||||
db=db,
|
||||
user_id=target_user_id,
|
||||
notification_type="scheduled_trigger",
|
||||
reference_type="trigger",
|
||||
reference_id=trigger.id,
|
||||
title=f"Scheduled: {trigger.name}",
|
||||
message=message,
|
||||
)
|
||||
for user_id in recipient_ids:
|
||||
NotificationService.create_notification(
|
||||
db=db,
|
||||
user_id=user_id,
|
||||
notification_type="scheduled_trigger",
|
||||
reference_type="trigger",
|
||||
reference_id=trigger.id,
|
||||
title=f"Scheduled: {trigger.name}",
|
||||
message=message,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_target(project: Project, target: str) -> Optional[str]:
|
||||
def _resolve_target(db: Session, project: Project, target: str) -> List[str]:
|
||||
"""
|
||||
Resolve notification target to user ID.
|
||||
Resolve notification target to user IDs.
|
||||
|
||||
Args:
|
||||
project: The project context
|
||||
target: Target specification (e.g., "project_owner", "user:<id>")
|
||||
|
||||
Returns:
|
||||
User ID or None
|
||||
List of user IDs
|
||||
"""
|
||||
recipients: Set[str] = set()
|
||||
|
||||
if target == "project_owner":
|
||||
return project.owner_id
|
||||
if project.owner_id:
|
||||
recipients.add(project.owner_id)
|
||||
elif target == "project_members":
|
||||
if project.owner_id:
|
||||
recipients.add(project.owner_id)
|
||||
member_rows = db.query(ProjectMember.user_id).join(
|
||||
User,
|
||||
User.id == ProjectMember.user_id,
|
||||
).filter(
|
||||
ProjectMember.project_id == project.id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in member_rows if row and row[0])
|
||||
elif target.startswith("department:"):
|
||||
department_id = target.split(":", 1)[1]
|
||||
if department_id:
|
||||
user_rows = db.query(User.id).filter(
|
||||
User.department_id == department_id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in user_rows if row and row[0])
|
||||
elif target.startswith("role:"):
|
||||
role_name = target.split(":", 1)[1].strip()
|
||||
if role_name:
|
||||
role = db.query(Role).filter(func.lower(Role.name) == role_name.lower()).first()
|
||||
if role:
|
||||
user_rows = db.query(User.id).filter(
|
||||
User.role_id == role.id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in user_rows if row and row[0])
|
||||
elif target.startswith("user:"):
|
||||
return target.split(":", 1)[1]
|
||||
return None
|
||||
user_id = target.split(":", 1)[1]
|
||||
if user_id:
|
||||
recipients.add(user_id)
|
||||
|
||||
return list(recipients)
|
||||
|
||||
@staticmethod
|
||||
def _format_template(template: str, trigger: Trigger, project: Project) -> str:
|
||||
@@ -718,8 +754,8 @@ class TriggerSchedulerService:
|
||||
)
|
||||
|
||||
# Resolve target user
|
||||
target_user_id = TriggerSchedulerService._resolve_deadline_target(task, target)
|
||||
if not target_user_id:
|
||||
recipient_ids = TriggerSchedulerService._resolve_deadline_target(db, task, target)
|
||||
if not recipient_ids:
|
||||
logger.debug(
|
||||
f"No target user resolved for deadline reminder, task {task.id}, target '{target}'"
|
||||
)
|
||||
@@ -730,18 +766,19 @@ class TriggerSchedulerService:
|
||||
template, trigger, task, reminder_days
|
||||
)
|
||||
|
||||
NotificationService.create_notification(
|
||||
db=db,
|
||||
user_id=target_user_id,
|
||||
notification_type="deadline_reminder",
|
||||
reference_type="task",
|
||||
reference_id=task.id,
|
||||
title=f"Deadline Reminder: {task.title}",
|
||||
message=message,
|
||||
)
|
||||
for user_id in recipient_ids:
|
||||
NotificationService.create_notification(
|
||||
db=db,
|
||||
user_id=user_id,
|
||||
notification_type="deadline_reminder",
|
||||
reference_type="task",
|
||||
reference_id=task.id,
|
||||
title=f"Deadline Reminder: {task.title}",
|
||||
message=message,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _resolve_deadline_target(task: Task, target: str) -> Optional[str]:
|
||||
def _resolve_deadline_target(db: Session, task: Task, target: str) -> List[str]:
|
||||
"""
|
||||
Resolve notification target for deadline reminders.
|
||||
|
||||
@@ -750,17 +787,55 @@ class TriggerSchedulerService:
|
||||
target: Target specification
|
||||
|
||||
Returns:
|
||||
User ID or None
|
||||
List of user IDs
|
||||
"""
|
||||
recipients: Set[str] = set()
|
||||
|
||||
if target == "assignee":
|
||||
return task.assignee_id
|
||||
if task.assignee_id:
|
||||
recipients.add(task.assignee_id)
|
||||
elif target == "creator":
|
||||
return task.created_by
|
||||
if task.created_by:
|
||||
recipients.add(task.created_by)
|
||||
elif target == "project_owner":
|
||||
return task.project.owner_id if task.project else None
|
||||
if task.project and task.project.owner_id:
|
||||
recipients.add(task.project.owner_id)
|
||||
elif target == "project_members":
|
||||
if task.project:
|
||||
if task.project.owner_id:
|
||||
recipients.add(task.project.owner_id)
|
||||
member_rows = db.query(ProjectMember.user_id).join(
|
||||
User,
|
||||
User.id == ProjectMember.user_id,
|
||||
).filter(
|
||||
ProjectMember.project_id == task.project_id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in member_rows if row and row[0])
|
||||
elif target.startswith("department:"):
|
||||
department_id = target.split(":", 1)[1]
|
||||
if department_id:
|
||||
user_rows = db.query(User.id).filter(
|
||||
User.department_id == department_id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in user_rows if row and row[0])
|
||||
elif target.startswith("role:"):
|
||||
role_name = target.split(":", 1)[1].strip()
|
||||
if role_name:
|
||||
role = db.query(Role).filter(func.lower(Role.name) == role_name.lower()).first()
|
||||
if role:
|
||||
user_rows = db.query(User.id).filter(
|
||||
User.role_id == role.id,
|
||||
User.is_active == True,
|
||||
).all()
|
||||
recipients.update(row[0] for row in user_rows if row and row[0])
|
||||
elif target.startswith("user:"):
|
||||
return target.split(":", 1)[1]
|
||||
return None
|
||||
user_id = target.split(":", 1)[1]
|
||||
if user_id:
|
||||
recipients.add(user_id)
|
||||
|
||||
return list(recipients)
|
||||
|
||||
@staticmethod
|
||||
def _format_deadline_template(
|
||||
|
||||
Reference in New Issue
Block a user