Files
herolib/lib/biz/planner/models/chat.v
2025-07-19 15:54:23 +02:00

704 lines
16 KiB
V

module models
import time
// Chat represents a communication channel or conversation
pub struct Chat {
BaseModel
pub mut:
name string @[required]
description string
chat_type ChatType
status ChatStatus
visibility ChatVisibility
owner_id int // User who owns/created the chat
members []ChatMember
messages []Message
project_id int // Links to Project (optional)
team_id int // Links to Team (optional)
customer_id int // Links to Customer (optional)
task_id int // Links to Task (optional)
issue_id int // Links to Issue (optional)
milestone_id int // Links to Milestone (optional)
sprint_id int // Links to Sprint (optional)
agenda_id int // Links to Agenda (optional)
settings ChatSettings
integrations []ChatIntegration
pinned_messages []int // Message IDs that are pinned
archived_at time.Time
last_activity time.Time
message_count int
file_count int
custom_fields map[string]string
}
// ChatType for categorizing chats
pub enum ChatType {
direct_message
group_chat
channel
announcement
support
project_chat
team_chat
customer_chat
incident_chat
meeting_chat
thread
}
// ChatStatus for chat lifecycle
pub enum ChatStatus {
active
archived
locked
deleted
suspended
}
// ChatVisibility for access control
pub enum ChatVisibility {
public
private
restricted
invite_only
}
// ChatMember represents a member of a chat
pub struct ChatMember {
pub mut:
user_id int
chat_id int
role ChatRole
permissions []ChatPermission
joined_at time.Time
last_read_at time.Time
last_read_message_id int
notification_settings NotificationSettings
status MemberStatus
invited_by int
muted bool
muted_until time.Time
custom_title string
}
// ChatRole for member roles in chat
pub enum ChatRole {
member
moderator
admin
owner
guest
bot
}
// ChatPermission for granular permissions
pub enum ChatPermission {
read_messages
send_messages
send_files
send_links
mention_all
delete_messages
edit_messages
pin_messages
invite_members
remove_members
manage_settings
manage_integrations
}
// Message represents a chat message
pub struct Message {
BaseModel
pub mut:
chat_id int
sender_id int
content string
message_type MessageType
thread_id int // For threaded conversations
reply_to_id int // Message this is replying to
mentions []int // User IDs mentioned in message
attachments []Attachment
reactions []Reaction
edited_at time.Time
edited_by int
deleted_at time.Time
deleted_by int
pinned bool
pinned_at time.Time
pinned_by int
forwarded_from int // Original message ID if forwarded
scheduled_at time.Time // For scheduled messages
delivery_status MessageDeliveryStatus
read_by []MessageRead
priority MessagePriority
expires_at time.Time // For ephemeral messages
rich_content RichContent
system_message bool // Is this a system-generated message?
bot_message bool // Is this from a bot?
external_id string // ID from external system (Slack, Teams, etc.)
}
// MessageType for categorizing messages
pub enum MessageType {
text
file
image
video
audio
link
code
quote
poll
announcement
system
bot_response
task_update
issue_update
project_update
meeting_summary
reminder
}
// MessageDeliveryStatus for tracking message delivery
pub enum MessageDeliveryStatus {
sending
sent
delivered
read
failed
}
// MessagePriority for message importance
pub enum MessagePriority {
low
normal
high
urgent
}
// MessageRead tracks who has read a message
pub struct MessageRead {
pub mut:
user_id int
message_id int
read_at time.Time
device string
}
// Reaction represents an emoji reaction to a message
pub struct Reaction {
pub mut:
id int
message_id int
user_id int
emoji string
created_at time.Time
}
// RichContent for rich message formatting
pub struct RichContent {
pub mut:
formatted_text string // HTML or markdown
embeds []Embed
buttons []ActionButton
cards []Card
polls []Poll
}
// Embed for rich content embeds
pub struct Embed {
pub mut:
title string
description string
url string
thumbnail_url string
image_url string
video_url string
author_name string
author_url string
color string
fields []EmbedField
footer_text string
timestamp time.Time
}
// EmbedField for structured embed data
pub struct EmbedField {
pub mut:
name string
value string
inline bool
}
// ActionButton for interactive messages
pub struct ActionButton {
pub mut:
id string
label string
style ButtonStyle
action string
url string
confirmation string
}
// ButtonStyle for button appearance
pub enum ButtonStyle {
default
primary
success
warning
danger
link
}
// Card for rich card content
pub struct Card {
pub mut:
title string
subtitle string
text string
image_url string
actions []ActionButton
facts []CardFact
}
// CardFact for key-value pairs in cards
pub struct CardFact {
pub mut:
name string
value string
}
// Poll for interactive polls
pub struct Poll {
pub mut:
id int
question string
options []PollOption
multiple_choice bool
anonymous bool
expires_at time.Time
created_by int
created_at time.Time
}
// PollOption for poll choices
pub struct PollOption {
pub mut:
id int
text string
votes []PollVote
vote_count int
}
// PollVote for tracking poll votes
pub struct PollVote {
pub mut:
user_id int
option_id int
voted_at time.Time
}
// ChatSettings for chat configuration
pub struct ChatSettings {
pub mut:
allow_guests bool
require_approval bool
message_retention_days int
file_retention_days int
max_members int
slow_mode_seconds int
profanity_filter bool
link_preview bool
emoji_reactions bool
threading bool
message_editing bool
message_deletion bool
file_uploads bool
external_sharing bool
read_receipts bool
typing_indicators bool
welcome_message string
rules []string
auto_moderation AutoModerationSettings
}
// AutoModerationSettings for automated moderation
pub struct AutoModerationSettings {
pub mut:
enabled bool
spam_detection bool
profanity_filter bool
link_filtering bool
caps_limit int
rate_limit_messages int
rate_limit_seconds int
auto_timeout_duration int
escalation_threshold int
}
// NotificationSettings for member notification preferences
pub struct NotificationSettings {
pub mut:
all_messages bool
mentions_only bool
direct_messages bool
keywords []string
mute_until time.Time
email_notifications bool
push_notifications bool
desktop_notifications bool
sound_enabled bool
vibration_enabled bool
}
// ChatIntegration for external service integrations
pub struct ChatIntegration {
pub mut:
id int
chat_id int
integration_type IntegrationType
name string
description string
webhook_url string
api_key string
settings map[string]string
enabled bool
created_by int
created_at time.Time
last_used time.Time
error_count int
last_error string
}
// IntegrationType for different integrations
pub enum IntegrationType {
webhook
slack
teams
discord
telegram
email
sms
jira
github
gitlab
jenkins
monitoring
custom
}
// get_unread_count returns unread message count for a user
pub fn (c Chat) get_unread_count(user_id int) int {
// Find member's last read message
mut last_read_id := 0
for member in c.members {
if member.user_id == user_id {
last_read_id = member.last_read_message_id
break
}
}
// Count messages after last read
return c.messages.filter(it.id > last_read_id && !it.system_message).len
}
// is_member checks if a user is a member of the chat
pub fn (c Chat) is_member(user_id int) bool {
for member in c.members {
if member.user_id == user_id && member.status == .active {
return true
}
}
return false
}
// has_permission checks if a user has a specific permission
pub fn (c Chat) has_permission(user_id int, permission ChatPermission) bool {
for member in c.members {
if member.user_id == user_id && member.status == .active {
return permission in member.permissions
}
}
return false
}
// get_member_role returns a user's role in the chat
pub fn (c Chat) get_member_role(user_id int) ?ChatRole {
for member in c.members {
if member.user_id == user_id {
return member.role
}
}
return none
}
// add_member adds a member to the chat
pub fn (mut c Chat) add_member(user_id int, role ChatRole, permissions []ChatPermission, invited_by int, by_user_id int) {
// Check if member already exists
for i, member in c.members {
if member.user_id == user_id {
// Update existing member
c.members[i].role = role
c.members[i].permissions = permissions
c.members[i].status = .active
c.update_timestamp(by_user_id)
return
}
}
// Add new member
c.members << ChatMember{
user_id: user_id
chat_id: c.id
role: role
permissions: permissions
joined_at: time.now()
invited_by: invited_by
status: .active
notification_settings: NotificationSettings{
all_messages: true
mentions_only: false
direct_messages: true
email_notifications: true
push_notifications: true
}
}
c.update_timestamp(by_user_id)
}
// remove_member removes a member from the chat
pub fn (mut c Chat) remove_member(user_id int, by_user_id int) {
for i, member in c.members {
if member.user_id == user_id {
c.members[i].status = .inactive
c.update_timestamp(by_user_id)
return
}
}
}
// send_message sends a message to the chat
pub fn (mut c Chat) send_message(sender_id int, content string, message_type MessageType, thread_id int, reply_to_id int, mentions []int, attachments []Attachment, by_user_id int) int {
message := Message{
id: c.messages.len + 1
chat_id: c.id
sender_id: sender_id
content: content
message_type: message_type
thread_id: thread_id
reply_to_id: reply_to_id
mentions: mentions
attachments: attachments
delivery_status: .sent
priority: .normal
created_at: time.now()
created_by: by_user_id
}
c.messages << message
c.message_count++
c.last_activity = time.now()
c.update_timestamp(by_user_id)
return message.id
}
// edit_message edits an existing message
pub fn (mut c Chat) edit_message(message_id int, new_content string, by_user_id int) bool {
for i, mut message in c.messages {
if message.id == message_id {
c.messages[i].content = new_content
c.messages[i].edited_at = time.now()
c.messages[i].edited_by = by_user_id
c.update_timestamp(by_user_id)
return true
}
}
return false
}
// delete_message deletes a message
pub fn (mut c Chat) delete_message(message_id int, by_user_id int) bool {
for i, mut message in c.messages {
if message.id == message_id {
c.messages[i].deleted_at = time.now()
c.messages[i].deleted_by = by_user_id
c.update_timestamp(by_user_id)
return true
}
}
return false
}
// pin_message pins a message
pub fn (mut c Chat) pin_message(message_id int, by_user_id int) bool {
for i, mut message in c.messages {
if message.id == message_id {
c.messages[i].pinned = true
c.messages[i].pinned_at = time.now()
c.messages[i].pinned_by = by_user_id
if message_id !in c.pinned_messages {
c.pinned_messages << message_id
}
c.update_timestamp(by_user_id)
return true
}
}
return false
}
// add_reaction adds a reaction to a message
pub fn (mut c Chat) add_reaction(message_id int, user_id int, emoji string, by_user_id int) {
for i, mut message in c.messages {
if message.id == message_id {
// Check if user already reacted with this emoji
for reaction in message.reactions {
if reaction.user_id == user_id && reaction.emoji == emoji {
return
}
}
c.messages[i].reactions << Reaction{
id: message.reactions.len + 1
message_id: message_id
user_id: user_id
emoji: emoji
created_at: time.now()
}
c.update_timestamp(by_user_id)
return
}
}
}
// mark_as_read marks messages as read for a user
pub fn (mut c Chat) mark_as_read(user_id int, message_id int, by_user_id int) {
// Update member's last read message
for i, mut member in c.members {
if member.user_id == user_id {
c.members[i].last_read_at = time.now()
c.members[i].last_read_message_id = message_id
break
}
}
// Add read receipt to message
for i, mut message in c.messages {
if message.id == message_id {
// Check if already marked as read
for read in message.read_by {
if read.user_id == user_id {
return
}
}
c.messages[i].read_by << MessageRead{
user_id: user_id
message_id: message_id
read_at: time.now()
}
break
}
}
c.update_timestamp(by_user_id)
}
// mute_chat mutes the chat for a user
pub fn (mut c Chat) mute_chat(user_id int, until time.Time, by_user_id int) {
for i, mut member in c.members {
if member.user_id == user_id {
c.members[i].muted = true
c.members[i].muted_until = until
c.update_timestamp(by_user_id)
return
}
}
}
// archive_chat archives the chat
pub fn (mut c Chat) archive_chat(by_user_id int) {
c.status = .archived
c.archived_at = time.now()
c.update_timestamp(by_user_id)
}
// add_integration adds an external integration
pub fn (mut c Chat) add_integration(integration_type IntegrationType, name string, webhook_url string, settings map[string]string, by_user_id int) {
c.integrations << ChatIntegration{
id: c.integrations.len + 1
chat_id: c.id
integration_type: integration_type
name: name
webhook_url: webhook_url
settings: settings
enabled: true
created_by: by_user_id
created_at: time.now()
}
c.update_timestamp(by_user_id)
}
// get_activity_level returns chat activity level
pub fn (c Chat) get_activity_level() string {
if c.messages.len == 0 {
return 'Inactive'
}
// Messages in last 24 hours
day_ago := time.now().unix - 86400
recent_messages := c.messages.filter(it.created_at.unix > day_ago).len
if recent_messages > 50 {
return 'Very Active'
} else if recent_messages > 20 {
return 'Active'
} else if recent_messages > 5 {
return 'Moderate'
} else if recent_messages > 0 {
return 'Low'
} else {
return 'Inactive'
}
}
// get_engagement_score calculates engagement score
pub fn (c Chat) get_engagement_score() f32 {
if c.members.len == 0 || c.messages.len == 0 {
return 0
}
// Calculate unique participants in last 7 days
week_ago := time.now().unix - (86400 * 7)
recent_messages := c.messages.filter(it.created_at.unix > week_ago)
mut unique_senders := map[int]bool{}
for message in recent_messages {
unique_senders[message.sender_id] = true
}
participation_rate := f32(unique_senders.len) / f32(c.members.len)
// Calculate message frequency
messages_per_day := f32(recent_messages.len) / 7.0
frequency_score := if messages_per_day > 10 { 1.0 } else { messages_per_day / 10.0 }
// Calculate reaction engagement
mut total_reactions := 0
for message in recent_messages {
total_reactions += message.reactions.len
}
reaction_rate := if recent_messages.len > 0 {
f32(total_reactions) / f32(recent_messages.len)
} else {
0
}
reaction_score := if reaction_rate > 2 { 1.0 } else { reaction_rate / 2.0 }
// Weighted average
return (participation_rate * 0.5) + (frequency_score * 0.3) + (reaction_score * 0.2)
}