Files
relay-server/database/messages.go

110 lines
3.4 KiB
Go

package database
import (
"database/sql"
"fmt"
"github.com/google/uuid"
"relay-server/helpers"
"relay-server/model"
)
func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit int, cursor int) ([]*model.Message, error) {
_, err := checkMembership(db, userID, conversationID)
if err != nil {
return nil, err
}
var query string
var messages []*model.Message
if cursor != 0 {
query = `
SELECT
m.message_id,
m.content AS message,
m.sent_at,
m.attachment_urls,
a.username AS sender
FROM Messages m
JOIN Accounts a ON m.user_id = a.user_id
WHERE m.conversation_id = $1
AND m.message_id < $2
ORDER BY m.message_id DESC
LIMIT $3;
`
rows, err := db.Query(query, conversationID, cursor, limit)
if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
}
for rows.Next() {
message := &model.Message{}
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
}
messages = append(messages, message)
}
if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
}
} else {
query = `
SELECT
m.message_id,
m.content AS message,
m.sent_at,
m.attachment_urls,
a.username AS sender
FROM Messages m
JOIN Accounts a ON m.user_id = a.user_id
WHERE m.conversation_id = $1
ORDER BY m.message_id DESC
LIMIT $2;
`
rows, err := db.Query(query, conversationID, cursor, limit)
if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
}
for rows.Next() {
message := &model.Message{}
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
if err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
}
messages = append(messages, message)
}
if err = rows.Err(); err != nil {
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
}
}
if cursor != 0 {
// Reverse first messages
for i, j := 0, len(messages)-1; i < j; i, j = i+1, j-1 {
messages[i], messages[j] = messages[j], messages[i]
}
}
return messages, nil
}
func checkMembership(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (bool, error) {
query := `
SELECT EXISTS (
SELECT 1
FROM Memberships
WHERE user_id = $1
AND conversation_id = $2
) AS is_member;
`
var isMember bool
err := db.QueryRow(query, userID, conversationID).Scan(&isMember)
if err != nil {
return false, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check membership: %w", err))
}
if !isMember {
return false, helpers.NewError(helpers.ErrForbidden, "You are member of the conversation", nil)
}
return isMember, nil
}