110 lines
3.5 KiB
Go
110 lines
3.5 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 []*model.Message{}, 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 []*model.Message{}, 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 []*model.Message{}, 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 []*model.Message{}, 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 []*model.Message{}, 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 []*model.Message{}, 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 []*model.Message{}, 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
|
|
}
|