package model // NotificationSetting represents per-user per-account notification preferences. // Reference: Chatwoot app/models/notification_setting.rb // // Uses bitmask flags for email_flags and push_flags columns. // Chatwoot uses FlagShihTzu gem for single-column multi-flag storage. // FlagShihTzu bit positions: bit_value = 2^(enum_value - 1) // // Table name: notification_settings // // id uint primaryKey autoIncrement // account_id uint not null; unique index with user_id // user_id uint not null; unique index with account_id // email_flags int default:0 not null; bitmask // push_flags int default:0 not null; bitmask // created_at time // updated_at time type NotificationSetting struct { Base `gorm:"embedded"` AccountID uint `gorm:"not null;uniqueIndex:by_account_user"` UserID uint `gorm:"not null;uniqueIndex:by_account_user"` EmailFlags int `gorm:"default:0;not null"` PushFlags int `gorm:"default:0;not null"` } // TableName returns the database table name. func (NotificationSetting) TableName() string { return "notification_settings" } // Chatwoot NOTIFICATION_TYPES enum values and FlagShihTzu bit positions. // Reference: Chatwoot Notification::NOTIFICATION_TYPES // FlagShihTzu: has_flags key = "email_{type}" / "push_{type}", bit_value = 2^(enum_value - 1) // // Enum value → Flag name → Bit position → Bit value: // 1 → conversation_creation → bit 0 → 1 // 2 → conversation_assignment → bit 1 → 2 // 3 → assigned_conversation_new_message → bit 2 → 4 // 4 → conversation_mention → bit 3 → 8 // 5 → participating_conversation_new_message → bit 4 → 16 // 6 → sla_missed_first_response → bit 5 → 32 // 7 → sla_missed_next_response → bit 6 → 64 // 8 → sla_missed_resolution → bit 7 → 128 const ( // Email notification flags (bit values match Chatwoot FlagShihTzu) EmailFlagConversationCreation = 1 // 2^0 EmailFlagConversationAssignment = 2 // 2^1 EmailFlagAssignedConversationNewMessage = 4 // 2^2 EmailFlagConversationMention = 8 // 2^3 EmailFlagParticipatingConversationNewMessage = 16 // 2^4 EmailFlagSLAMissedFirstResponse = 32 // 2^5 EmailFlagSLAMissedNextResponse = 64 // 2^6 EmailFlagSLAMissedResolution = 128 // 2^7 // Push notification flags (same bit values, separate column) PushFlagConversationCreation = 1 PushFlagConversationAssignment = 2 PushFlagAssignedConversationNewMessage = 4 PushFlagConversationMention = 8 PushFlagParticipatingConversationNewMessage = 16 PushFlagSLAMissedFirstResponse = 32 PushFlagSLAMissedNextResponse = 64 PushFlagSLAMissedResolution = 128 ) // AllEmailFlags returns the bitmask of all email notification types. func AllEmailFlags() int { return EmailFlagConversationCreation | EmailFlagConversationAssignment | EmailFlagAssignedConversationNewMessage | EmailFlagConversationMention | EmailFlagParticipatingConversationNewMessage | EmailFlagSLAMissedFirstResponse | EmailFlagSLAMissedNextResponse | EmailFlagSLAMissedResolution } // AllPushFlags returns the bitmask of all push notification types. func AllPushFlags() int { return PushFlagConversationCreation | PushFlagConversationAssignment | PushFlagAssignedConversationNewMessage | PushFlagConversationMention | PushFlagParticipatingConversationNewMessage | PushFlagSLAMissedFirstResponse | PushFlagSLAMissedNextResponse | PushFlagSLAMissedResolution } // AllEmailFlagNames returns all available email notification flag names. // Matches Chatwoot FlagShihTzu generated flag names: "email_{type}". func AllEmailFlagNames() []string { return []string{ "email_conversation_creation", "email_conversation_assignment", "email_assigned_conversation_new_message", "email_conversation_mention", "email_participating_conversation_new_message", "email_sla_missed_first_response", "email_sla_missed_next_response", "email_sla_missed_resolution", } } // AllPushFlagNames returns all available push notification flag names. // Matches Chatwoot FlagShihTzu generated flag names: "push_{type}". func AllPushFlagNames() []string { return []string{ "push_conversation_creation", "push_conversation_assignment", "push_assigned_conversation_new_message", "push_conversation_mention", "push_participating_conversation_new_message", "push_sla_missed_first_response", "push_sla_missed_next_response", "push_sla_missed_resolution", } } // Email flag name → bit value mapping for selected_email_flags parsing. var emailFlagNameToValue = map[string]int{ "email_conversation_creation": EmailFlagConversationCreation, "email_conversation_assignment": EmailFlagConversationAssignment, "email_assigned_conversation_new_message": EmailFlagAssignedConversationNewMessage, "email_conversation_mention": EmailFlagConversationMention, "email_participating_conversation_new_message": EmailFlagParticipatingConversationNewMessage, "email_sla_missed_first_response": EmailFlagSLAMissedFirstResponse, "email_sla_missed_next_response": EmailFlagSLAMissedNextResponse, "email_sla_missed_resolution": EmailFlagSLAMissedResolution, } // Push flag name → bit value mapping for selected_push_flags parsing. var pushFlagNameToValue = map[string]int{ "push_conversation_creation": PushFlagConversationCreation, "push_conversation_assignment": PushFlagConversationAssignment, "push_assigned_conversation_new_message": PushFlagAssignedConversationNewMessage, "push_conversation_mention": PushFlagConversationMention, "push_participating_conversation_new_message": PushFlagParticipatingConversationNewMessage, "push_sla_missed_first_response": PushFlagSLAMissedFirstResponse, "push_sla_missed_next_response": PushFlagSLAMissedNextResponse, "push_sla_missed_resolution": PushFlagSLAMissedResolution, } // Email bit value → flag name mapping. var emailValueToFlagName = map[int]string{ EmailFlagConversationCreation: "email_conversation_creation", EmailFlagConversationAssignment: "email_conversation_assignment", EmailFlagAssignedConversationNewMessage: "email_assigned_conversation_new_message", EmailFlagConversationMention: "email_conversation_mention", EmailFlagParticipatingConversationNewMessage: "email_participating_conversation_new_message", EmailFlagSLAMissedFirstResponse: "email_sla_missed_first_response", EmailFlagSLAMissedNextResponse: "email_sla_missed_next_response", EmailFlagSLAMissedResolution: "email_sla_missed_resolution", } // Push bit value → flag name mapping. var pushValueToFlagName = map[int]string{ PushFlagConversationCreation: "push_conversation_creation", PushFlagConversationAssignment: "push_conversation_assignment", PushFlagAssignedConversationNewMessage: "push_assigned_conversation_new_message", PushFlagConversationMention: "push_conversation_mention", PushFlagParticipatingConversationNewMessage: "push_participating_conversation_new_message", PushFlagSLAMissedFirstResponse: "push_sla_missed_first_response", PushFlagSLAMissedNextResponse: "push_sla_missed_next_response", PushFlagSLAMissedResolution: "push_sla_missed_resolution", } // HasEmailFlag checks if a specific email flag is enabled. func (ns *NotificationSetting) HasEmailFlag(flag int) bool { return ns.EmailFlags&flag != 0 } // HasPushFlag checks if a specific push flag is enabled. func (ns *NotificationSetting) HasPushFlag(flag int) bool { return ns.PushFlags&flag != 0 } // SetEmailFlagsFromNames sets email flags from a list of flag names. // Reference: Chatwoot selected_email_flags (FlagShihTzu flag names like "email_conversation_creation") func (ns *NotificationSetting) SetEmailFlagsFromNames(names []string) { ns.EmailFlags = 0 for _, name := range names { if v, ok := emailFlagNameToValue[name]; ok { ns.EmailFlags |= v } } } // SetPushFlagsFromNames sets push flags from a list of flag names. // Reference: Chatwoot selected_push_flags func (ns *NotificationSetting) SetPushFlagsFromNames(names []string) { ns.PushFlags = 0 for _, name := range names { if v, ok := pushFlagNameToValue[name]; ok { ns.PushFlags |= v } } } // SelectedEmailFlagNames returns the names of enabled email flags. // Matches Chatwoot FlagShihTzu: returns "email_{type}" format names. func (ns *NotificationSetting) SelectedEmailFlagNames() []string { names := []string{} for _, bitValue := range []int{ EmailFlagConversationCreation, EmailFlagConversationAssignment, EmailFlagAssignedConversationNewMessage, EmailFlagConversationMention, EmailFlagParticipatingConversationNewMessage, EmailFlagSLAMissedFirstResponse, EmailFlagSLAMissedNextResponse, EmailFlagSLAMissedResolution, } { if ns.EmailFlags&bitValue != 0 { names = append(names, emailValueToFlagName[bitValue]) } } return names } // SelectedPushFlagNames returns the names of enabled push flags. // Matches Chatwoot FlagShihTzu: returns "push_{type}" format names. func (ns *NotificationSetting) SelectedPushFlagNames() []string { names := []string{} for _, bitValue := range []int{ PushFlagConversationCreation, PushFlagConversationAssignment, PushFlagAssignedConversationNewMessage, PushFlagConversationMention, PushFlagParticipatingConversationNewMessage, PushFlagSLAMissedFirstResponse, PushFlagSLAMissedNextResponse, PushFlagSLAMissedResolution, } { if ns.PushFlags&bitValue != 0 { names = append(names, pushValueToFlagName[bitValue]) } } return names }