154 lines
4.8 KiB
Go
154 lines
4.8 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))
|
|
}
|
|
defer rows.Close()
|
|
|
|
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))
|
|
}
|
|
defer rows.Close()
|
|
|
|
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
|
|
}
|
|
|
|
func DeleteMessage(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, messageID int) error {
|
|
checkMessageOwnershipQuery := `
|
|
SELECT user_id FROM Messages WHERE message_id = $1;
|
|
`
|
|
deleteMessageQuery := `
|
|
DELETE FROM Messages WHERE message_id = $1;
|
|
`
|
|
|
|
var messageOwnerID uuid.UUID
|
|
err := db.QueryRow(checkMessageOwnershipQuery, messageID).Scan(&messageOwnerID)
|
|
if err != nil {
|
|
return helpers.NewError(helpers.ErrInternal, "Failed to delete message", fmt.Errorf("failed to check message ownership: %w", err))
|
|
}
|
|
|
|
var isSelfMessage bool
|
|
if messageOwnerID == userID {
|
|
isSelfMessage = true
|
|
}
|
|
|
|
isAdmin, err := IsAdmin(db, userID, conversationID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !isSelfMessage && !isAdmin {
|
|
return helpers.NewError(helpers.ErrForbidden, "You don't have permissions to delete that message ", nil)
|
|
}
|
|
|
|
row, err := db.Exec(deleteMessageQuery, messageID)
|
|
if err != nil {
|
|
return helpers.NewError(helpers.ErrInternal, "Failed to delete message", fmt.Errorf("failed to delete message: %w", err))
|
|
}
|
|
rowsAffected, err := row.RowsAffected()
|
|
if err != nil {
|
|
return helpers.NewError(helpers.ErrInternal, "Failed to delete message", fmt.Errorf("failed to get rows affected: %w", err))
|
|
}
|
|
if rowsAffected == 0 {
|
|
return helpers.NewError(helpers.ErrNotFound, "Message not found", nil)
|
|
}
|
|
return nil
|
|
|
|
}
|