156 lines
4.5 KiB
Go
156 lines
4.5 KiB
Go
package models
|
|
|
|
import (
|
|
"database/sql"
|
|
"time"
|
|
"log"
|
|
"regexp"
|
|
)
|
|
|
|
type ChatMessage struct {
|
|
ID int
|
|
UserID int
|
|
Content string
|
|
ReplyTo int // -1 if not a reply
|
|
Timestamp time.Time
|
|
Username string // For display, fetched from user
|
|
PfpURL string // For display, fetched from user
|
|
Mentions []string // List of mentioned usernames (not directly used for display, but for notifications)
|
|
}
|
|
|
|
// extractMentions finds all @username mentions in content and returns a slice of unique usernames.
|
|
func extractMentions(content string) []string {
|
|
r := regexp.MustCompile(`@([a-zA-Z0-9_]+)`) // Matches @ followed by one or more word characters
|
|
matches := r.FindAllStringSubmatch(content, -1)
|
|
uniqueMentions := make(map[string]struct{})
|
|
for _, match := range matches {
|
|
if len(match) > 1 {
|
|
uniqueMentions[match[1]] = struct{}{}
|
|
}
|
|
}
|
|
var result []string
|
|
for username := range uniqueMentions { // Corrected: uniqueMentions
|
|
result = append(result, username)
|
|
}
|
|
return result
|
|
}
|
|
|
|
// CreateChatMessage inserts a new chat message and creates notifications for mentioned users.
|
|
func CreateChatMessage(db *sql.DB, msg ChatMessage) (int, error) {
|
|
query := "INSERT INTO chat_messages (user_id, content, reply_to, timestamp) VALUES (?, ?, ?, NOW())"
|
|
result, err := db.Exec(query, msg.UserID, msg.Content, msg.ReplyTo)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Get the ID of the newly inserted message
|
|
msgID64, err := result.LastInsertId()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
msgID := int(msgID64)
|
|
|
|
// Create notifications for mentioned users
|
|
mentionedUsernames := extractMentions(msg.Content)
|
|
for _, username := range mentionedUsernames {
|
|
mentionedUser, err := GetUserByUsername(db, username) // models/user.go GetUserByUsername
|
|
if err != nil {
|
|
// Log error but don't fail message creation for non-existent users
|
|
log.Printf("Warning: Could not find mentioned user '%s' for notification: %v", username, err)
|
|
continue
|
|
}
|
|
if mentionedUser != nil && mentionedUser.ID != msg.UserID { // Don't notify self
|
|
notification := Notification{
|
|
UserID: mentionedUser.ID,
|
|
Type: "chat_mention",
|
|
RelatedID: msgID, // The ID of the newly created chat message
|
|
Read: false,
|
|
}
|
|
err := CreateNotification(db, notification) // models/notification.go CreateNotification
|
|
if err != nil {
|
|
log.Printf("Error creating chat mention notification for user %d: %v", mentionedUser.ID, err)
|
|
}
|
|
}
|
|
}
|
|
return msgID, nil
|
|
}
|
|
|
|
func GetRecentChatMessages(db *sql.DB, limit int) ([]ChatMessage, error) {
|
|
query := `
|
|
SELECT cm.id, cm.user_id, cm.content, cm.reply_to, cm.timestamp, u.username, u.pfp_url
|
|
FROM chat_messages cm
|
|
JOIN users u ON cm.user_id = u.id
|
|
ORDER BY cm.timestamp DESC
|
|
LIMIT ?`
|
|
rows, err := db.Query(query, limit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var messages []ChatMessage
|
|
for rows.Next() {
|
|
var msg ChatMessage
|
|
var timestampStr string
|
|
var pfpURL sql.NullString
|
|
err := rows.Scan(&msg.ID, &msg.UserID, &msg.Content, &msg.ReplyTo, ×tampStr, &msg.Username, &pfpURL)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
msg.Timestamp, err = time.Parse("2006-01-02 15:04:05", timestampStr)
|
|
if err != nil {
|
|
msg.Timestamp = time.Time{}
|
|
}
|
|
if pfpURL.Valid {
|
|
msg.PfpURL = pfpURL.String
|
|
}
|
|
messages = append(messages, msg)
|
|
}
|
|
return messages, nil
|
|
}
|
|
|
|
func GetChatMessageByID(db *sql.DB, id int) (*ChatMessage, error) {
|
|
query := `
|
|
SELECT cm.id, cm.user_id, cm.content, cm.reply_to, cm.timestamp, u.username, u.pfp_url
|
|
FROM chat_messages cm
|
|
JOIN users u ON cm.user_id = u.id
|
|
WHERE cm.id = ?`
|
|
row := db.QueryRow(query, id)
|
|
var msg ChatMessage
|
|
var timestampStr string
|
|
var pfpURL sql.NullString
|
|
err := row.Scan(&msg.ID, &msg.UserID, &msg.Content, &msg.ReplyTo, ×tampStr, &msg.Username, &pfpURL)
|
|
if err == sql.ErrNoRows {
|
|
return nil, nil
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
msg.Timestamp, err = time.Parse("2006-01-02 15:04:05", timestampStr)
|
|
if err != nil {
|
|
msg.Timestamp = time.Time{}
|
|
}
|
|
if pfpURL.Valid {
|
|
msg.PfpURL = pfpURL.String
|
|
}
|
|
return &msg, nil
|
|
}
|
|
|
|
func GetUsernamesMatching(db *sql.DB, prefix string) ([]string, error) {
|
|
query := "SELECT username FROM users WHERE username LIKE ? LIMIT 10"
|
|
rows, err := db.Query(query, prefix+"%")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
|
|
var usernames []string
|
|
for rows.Next() {
|
|
var username string
|
|
if err := rows.Scan(&username); err != nil {
|
|
return nil, err
|
|
}
|
|
usernames = append(usernames, username)
|
|
}
|
|
return usernames, nil
|
|
} |