Add email notification preference for task completion
- Add EmailTaskCompleted field to NotificationPreference model - Update notification repository to include email preference in queries - Check email preference before sending task completion emails - Add email preference toggle to admin panel notification-prefs page - Update API types for email preference support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -33,8 +33,12 @@ type NotificationPrefResponse struct {
|
||||
TaskAssigned bool `json:"task_assigned"`
|
||||
ResidenceShared bool `json:"residence_shared"`
|
||||
WarrantyExpiring bool `json:"warranty_expiring"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
|
||||
// Email preferences
|
||||
EmailTaskCompleted bool `json:"email_task_completed"`
|
||||
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
// List handles GET /api/admin/notification-prefs
|
||||
@@ -98,18 +102,19 @@ func (h *AdminNotificationPrefsHandler) List(c *gin.Context) {
|
||||
for i, pref := range prefs {
|
||||
user := userMap[pref.UserID]
|
||||
responses[i] = NotificationPrefResponse{
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
EmailTaskCompleted: pref.EmailTaskCompleted,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,18 +143,19 @@ func (h *AdminNotificationPrefsHandler) Get(c *gin.Context) {
|
||||
h.db.First(&user, pref.UserID)
|
||||
|
||||
c.JSON(http.StatusOK, NotificationPrefResponse{
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
EmailTaskCompleted: pref.EmailTaskCompleted,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -161,6 +167,9 @@ type UpdateNotificationPrefRequest struct {
|
||||
TaskAssigned *bool `json:"task_assigned"`
|
||||
ResidenceShared *bool `json:"residence_shared"`
|
||||
WarrantyExpiring *bool `json:"warranty_expiring"`
|
||||
|
||||
// Email preferences
|
||||
EmailTaskCompleted *bool `json:"email_task_completed"`
|
||||
}
|
||||
|
||||
// Update handles PUT /api/admin/notification-prefs/:id
|
||||
@@ -206,6 +215,9 @@ func (h *AdminNotificationPrefsHandler) Update(c *gin.Context) {
|
||||
if req.WarrantyExpiring != nil {
|
||||
pref.WarrantyExpiring = *req.WarrantyExpiring
|
||||
}
|
||||
if req.EmailTaskCompleted != nil {
|
||||
pref.EmailTaskCompleted = *req.EmailTaskCompleted
|
||||
}
|
||||
|
||||
if err := h.db.Save(&pref).Error; err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to update notification preference"})
|
||||
@@ -216,18 +228,19 @@ func (h *AdminNotificationPrefsHandler) Update(c *gin.Context) {
|
||||
h.db.First(&user, pref.UserID)
|
||||
|
||||
c.JSON(http.StatusOK, NotificationPrefResponse{
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
EmailTaskCompleted: pref.EmailTaskCompleted,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -274,17 +287,18 @@ func (h *AdminNotificationPrefsHandler) GetByUser(c *gin.Context) {
|
||||
h.db.First(&user, pref.UserID)
|
||||
|
||||
c.JSON(http.StatusOK, NotificationPrefResponse{
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
ID: pref.ID,
|
||||
UserID: pref.UserID,
|
||||
Username: user.Username,
|
||||
Email: user.Email,
|
||||
TaskDueSoon: pref.TaskDueSoon,
|
||||
TaskOverdue: pref.TaskOverdue,
|
||||
TaskCompleted: pref.TaskCompleted,
|
||||
TaskAssigned: pref.TaskAssigned,
|
||||
ResidenceShared: pref.ResidenceShared,
|
||||
WarrantyExpiring: pref.WarrantyExpiring,
|
||||
EmailTaskCompleted: pref.EmailTaskCompleted,
|
||||
CreatedAt: pref.CreatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
UpdatedAt: pref.UpdatedAt.Format("2006-01-02T15:04:05Z"),
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user