Init Repo

This commit is contained in:
2026-02-28 03:22:04 +08:00
commit de59b57ee7
883 changed files with 156857 additions and 0 deletions
+259
View File
@@ -0,0 +1,259 @@
from typing import Optional
from sqlalchemy.orm import Session
from models.user import User
from models.task import Task, Submission, Review
from models.notification import Notification, UserNotificationPreference, NotificationType, NotificationPriority
import logging
# Set up logging for notifications
logger = logging.getLogger(__name__)
class NotificationService:
"""Notification service for creating and managing notifications."""
def _create_notification(
self,
db: Session,
user_id: int,
type: NotificationType,
title: str,
message: str,
priority: NotificationPriority = NotificationPriority.NORMAL,
project_id: Optional[int] = None,
task_id: Optional[int] = None,
submission_id: Optional[int] = None
) -> Notification:
"""Create a notification in the database."""
try:
# Check user preferences
preferences = db.query(UserNotificationPreference).filter(
UserNotificationPreference.user_id == user_id
).first()
# Create default preferences if they don't exist
if not preferences:
preferences = UserNotificationPreference(user_id=user_id)
db.add(preferences)
db.commit()
# Check if in-app notifications are enabled for this type
if not preferences.inapp_enabled:
return None
type_pref_map = {
NotificationType.TASK_ASSIGNED: preferences.inapp_task_assigned,
NotificationType.TASK_STATUS_CHANGED: preferences.inapp_task_status_changed,
NotificationType.SUBMISSION_REVIEWED: preferences.inapp_submission_reviewed,
NotificationType.WORK_SUBMITTED: preferences.inapp_work_submitted,
NotificationType.DEADLINE_APPROACHING: preferences.inapp_deadline_approaching,
NotificationType.PROJECT_UPDATE: preferences.inapp_project_update,
NotificationType.COMMENT_ADDED: preferences.inapp_comment_added,
}
if not type_pref_map.get(type, True):
return None
# Create notification
notification = Notification(
user_id=user_id,
type=type,
priority=priority,
title=title,
message=message,
project_id=project_id,
task_id=task_id,
submission_id=submission_id
)
db.add(notification)
db.commit()
db.refresh(notification)
logger.info(f"Created notification {notification.id} for user {user_id}: {title}")
# TODO: Send email if email notifications are enabled
if preferences.email_enabled and type_pref_map.get(type, True):
self._send_email_notification(notification, preferences)
return notification
except Exception as e:
logger.error(f"Failed to create notification: {str(e)}")
db.rollback()
return None
def _send_email_notification(self, notification: Notification, preferences: UserNotificationPreference):
"""Send email notification (placeholder for future implementation)."""
# TODO: Implement actual email sending
logger.info(f"Email notification would be sent for notification {notification.id}")
def notify_submission_reviewed(
self,
db: Session,
submission: Submission,
review: Review,
reviewer: User
):
"""Notify artist when their submission is reviewed."""
try:
artist = submission.user
decision_text = "approved" if review.decision == "approved" else "requires retakes"
title = f"Submission {decision_text}"
message = f"Your submission for task '{submission.task.name}' has been {decision_text} by {reviewer.first_name} {reviewer.last_name}"
if review.feedback:
message += f"\n\nFeedback: {review.feedback}"
priority = NotificationPriority.HIGH if review.decision == "retake" else NotificationPriority.NORMAL
self._create_notification(
db=db,
user_id=artist.id,
type=NotificationType.SUBMISSION_REVIEWED,
title=title,
message=message,
priority=priority,
project_id=submission.task.project_id,
task_id=submission.task_id,
submission_id=submission.id
)
except Exception as e:
logger.error(f"Failed to send notification for submission {submission.id}: {str(e)}")
def notify_task_assigned(
self,
db: Session,
task: Task,
assigned_user: User,
assigner: User
):
"""Notify user when they are assigned a task."""
try:
title = "New Task Assigned"
message = f"You have been assigned a new task: '{task.name}' by {assigner.first_name} {assigner.last_name}"
if task.deadline:
message += f"\nDeadline: {task.deadline.strftime('%Y-%m-%d')}"
if task.description:
message += f"\nDescription: {task.description}"
self._create_notification(
db=db,
user_id=assigned_user.id,
type=NotificationType.TASK_ASSIGNED,
title=title,
message=message,
priority=NotificationPriority.NORMAL,
project_id=task.project_id,
task_id=task.id
)
except Exception as e:
logger.error(f"Failed to send task assignment notification for task {task.id}: {str(e)}")
def notify_work_submitted(
self,
db: Session,
submission: Submission,
task: Task
):
"""Notify directors/coordinators when work is submitted for review."""
try:
from models.project import ProjectMember
project_members = db.query(ProjectMember).join(User).filter(
ProjectMember.project_id == task.project_id,
User.role.in_(["director", "coordinator"])
).all()
artist_name = f"{submission.user.first_name} {submission.user.last_name}"
title = "New Submission for Review"
message = f"New submission ready for review: '{task.name}' by {artist_name} (Version {submission.version_number})"
if submission.notes:
message += f"\nArtist notes: {submission.notes}"
for member in project_members:
self._create_notification(
db=db,
user_id=member.user_id,
type=NotificationType.WORK_SUBMITTED,
title=title,
message=message,
priority=NotificationPriority.NORMAL,
project_id=task.project_id,
task_id=task.id,
submission_id=submission.id
)
except Exception as e:
logger.error(f"Failed to send submission notification for submission {submission.id}: {str(e)}")
def notify_task_status_changed(
self,
db: Session,
task: Task,
old_status: str,
new_status: str,
changed_by: User
):
"""Notify relevant users when task status changes."""
try:
# Notify task owner if someone else changed the status
if task.assigned_user_id and task.assigned_user_id != changed_by.id:
title = "Task Status Updated"
message = f"Task '{task.name}' status changed from {old_status} to {new_status} by {changed_by.first_name} {changed_by.last_name}"
self._create_notification(
db=db,
user_id=task.assigned_user_id,
type=NotificationType.TASK_STATUS_CHANGED,
title=title,
message=message,
priority=NotificationPriority.NORMAL,
project_id=task.project_id,
task_id=task.id
)
except Exception as e:
logger.error(f"Failed to send task status change notification for task {task.id}: {str(e)}")
def notify_comment_added(
self,
db: Session,
task: Task,
comment_author: User,
comment_text: str
):
"""Notify task assignee when a comment is added."""
try:
if task.assigned_user_id and task.assigned_user_id != comment_author.id:
title = "New Comment on Task"
message = f"{comment_author.first_name} {comment_author.last_name} commented on task '{task.name}'"
if len(comment_text) > 100:
message += f"\n\n{comment_text[:100]}..."
else:
message += f"\n\n{comment_text}"
self._create_notification(
db=db,
user_id=task.assigned_user_id,
type=NotificationType.COMMENT_ADDED,
title=title,
message=message,
priority=NotificationPriority.LOW,
project_id=task.project_id,
task_id=task.id
)
except Exception as e:
logger.error(f"Failed to send comment notification for task {task.id}: {str(e)}")
# Global notification service instance
notification_service = NotificationService()