added proper types to structs, return empty arrays instead of null
This commit is contained in:
@@ -94,7 +94,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
`, userID).Scan(&conversationID)
|
`, userID).Scan(&conversationID)
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if conversationID == uuid.Nil {
|
if conversationID == uuid.Nil {
|
||||||
@@ -104,7 +104,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
RETURNING conversation_id;
|
RETURNING conversation_id;
|
||||||
`).Scan(&conversationID)
|
`).Scan(&conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Exec(`
|
_, err = db.Exec(`
|
||||||
@@ -113,7 +113,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
ON CONFLICT (conversation_id, user_id) DO NOTHING;
|
ON CONFLICT (conversation_id, user_id) DO NOTHING;
|
||||||
`, conversationID, userID)
|
`, conversationID, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create membership: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create membership: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -128,7 +128,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
`, userID, contactID).Scan(&conversationID)
|
`, userID, contactID).Scan(&conversationID)
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check existing conversation %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if conversationID == uuid.Nil {
|
if conversationID == uuid.Nil {
|
||||||
@@ -138,7 +138,7 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
RETURNING conversation_id;
|
RETURNING conversation_id;
|
||||||
`).Scan(&conversationID)
|
`).Scan(&conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create conversation: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = db.Exec(`
|
_, err = db.Exec(`
|
||||||
@@ -147,19 +147,19 @@ func InsertContact(db *sql.DB, userID uuid.UUID, contactID uuid.UUID, contactUse
|
|||||||
ON CONFLICT (conversation_id, user_id) DO NOTHING;
|
ON CONFLICT (conversation_id, user_id) DO NOTHING;
|
||||||
`, conversationID, userID, contactID)
|
`, conversationID, userID, contactID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create memberships: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to create memberships: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
insertedContact, err := InsertContactByID(db, contactID, conversationID)
|
insertedContact, err := InsertContactByID(db, contactID, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &model.Contact{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
latestMessage, err := GetLatestMessage(db, conversationID)
|
latestMessage, err := GetLatestMessage(db, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return &model.Contact{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contact := model.Contact{
|
contact := model.Contact{
|
||||||
@@ -186,9 +186,9 @@ func InsertContactByID(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (
|
|||||||
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
|
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInvalidInput, "Contact already exists", nil)
|
return &model.Contact{}, helpers.NewError(helpers.ErrInvalidInput, "Contact already exists", nil)
|
||||||
} else if !errors.Is(err, sql.ErrNoRows) {
|
} else if !errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check contact existence: %w", err))
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to check contact existence: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert new contact
|
// Insert new contact
|
||||||
@@ -199,7 +199,7 @@ func InsertContactByID(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (
|
|||||||
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
|
`, userID, conversationID).Scan(&contact.ID, &contact.ConversationID, &contact.UserID)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to create contact", err)
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to create contact", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &contact, nil
|
return &contact, nil
|
||||||
@@ -228,9 +228,9 @@ func GetLatestMessage(db *sql.DB, conversationId uuid.UUID) (*model.Contact, err
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return &model.Contact{}, nil // Return empty contact if no messages
|
return &model.Contact{}, nil
|
||||||
}
|
}
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get latest message", err)
|
return &model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to get latest message", fmt.Errorf("failed to get latest message: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return &latestMessage, nil
|
return &latestMessage, nil
|
||||||
@@ -287,21 +287,20 @@ func GetContacts(db *sql.DB, userID uuid.UUID) ([]*model.Contact, error) {
|
|||||||
|
|
||||||
rows, err := db.Query(contactsQuery, userID)
|
rows, err := db.Query(contactsQuery, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get contacts", err)
|
return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "Failed to get contacts", fmt.Errorf("failed to get contacts: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
var contacts []*model.Contact
|
var contacts []*model.Contact
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
contact := &model.Contact{}
|
contact := &model.Contact{}
|
||||||
err := rows.Scan(&contact.ID, &contact.UserID, &contact.Username,
|
err := rows.Scan(&contact.ID, &contact.UserID, &contact.Username, &contact.LastActive, &contact.ConversationID, &contact.Type, &contact.LastReadMessageID)
|
||||||
&contact.ConversationID, &contact.Type)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", err)
|
return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to scan contact: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
latestMessage, err := GetLatestMessage(db, contact.ConversationID)
|
latestMessage, err := GetLatestMessage(db, contact.ConversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return []*model.Contact{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
contact.LastMessageID = latestMessage.LastMessageID
|
contact.LastMessageID = latestMessage.LastMessageID
|
||||||
@@ -313,7 +312,7 @@ func GetContacts(db *sql.DB, userID uuid.UUID) ([]*model.Contact, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process contacts: %w", err))
|
return []*model.Contact{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process contacts: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
return contacts, nil
|
return contacts, nil
|
||||||
@@ -329,7 +328,7 @@ func ContactSuggestion(db *sql.DB, contactUsername string) ([]string, error) {
|
|||||||
rows, err := db.Query(query, "%"+strings.ToLower(contactUsername)+"%")
|
rows, err := db.Query(query, "%"+strings.ToLower(contactUsername)+"%")
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get contact suggestions", err)
|
return []string{}, helpers.NewError(helpers.ErrInternal, "Failed to get contact suggestions", fmt.Errorf("failed to get contact suggestions: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
var suggestions []string
|
var suggestions []string
|
||||||
@@ -337,12 +336,12 @@ func ContactSuggestion(db *sql.DB, contactUsername string) ([]string, error) {
|
|||||||
var suggestion string
|
var suggestion string
|
||||||
err := rows.Scan(&suggestion)
|
err := rows.Scan(&suggestion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", err)
|
return []string{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to scan contact suggestion: %w", err))
|
||||||
}
|
}
|
||||||
suggestions = append(suggestions, suggestion)
|
suggestions = append(suggestions, suggestion)
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process suggestions"))
|
return []string{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process suggestions: %w", err))
|
||||||
}
|
}
|
||||||
return suggestions, nil
|
return suggestions, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit int, cursor int) ([]*model.Message, error) {
|
func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit int, cursor int) ([]*model.Message, error) {
|
||||||
_, err := checkMembership(db, userID, conversationID)
|
_, err := checkMembership(db, userID, conversationID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return []*model.Message{}, err
|
||||||
}
|
}
|
||||||
var query string
|
var query string
|
||||||
var messages []*model.Message
|
var messages []*model.Message
|
||||||
@@ -33,19 +33,19 @@ func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit i
|
|||||||
`
|
`
|
||||||
rows, err := db.Query(query, conversationID, cursor, limit)
|
rows, err := db.Query(query, conversationID, cursor, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
message := &model.Message{}
|
message := &model.Message{}
|
||||||
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
|
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
|
||||||
}
|
}
|
||||||
messages = append(messages, message)
|
messages = append(messages, message)
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@@ -64,19 +64,19 @@ func GetMessages(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID, limit i
|
|||||||
`
|
`
|
||||||
rows, err := db.Query(query, conversationID, cursor, limit)
|
rows, err := db.Query(query, conversationID, cursor, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to get messages: %w", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
message := &model.Message{}
|
message := &model.Message{}
|
||||||
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
|
err = rows.Scan(&message.MessageID, &message.Message, &message.SentAt, &message.AttachmentUrl, &message.Sender)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "Failed to get messages", fmt.Errorf("failed to scan message: %w", err))
|
||||||
}
|
}
|
||||||
messages = append(messages, message)
|
messages = append(messages, message)
|
||||||
}
|
}
|
||||||
if err = rows.Err(); err != nil {
|
if err = rows.Err(); err != nil {
|
||||||
return nil, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
|
return []*model.Message{}, helpers.NewError(helpers.ErrInternal, "internal server error", fmt.Errorf("failed to process messages: %w", err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cursor != 0 {
|
if cursor != 0 {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UserClaims struct {
|
type UserClaims struct {
|
||||||
@@ -11,15 +12,17 @@ type UserClaims struct {
|
|||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
}
|
}
|
||||||
type Contact struct {
|
type Contact struct {
|
||||||
ID int `json:"contact_id"`
|
ID int `json:"contact_id"`
|
||||||
ConversationID uuid.UUID `json:"conversation_id"`
|
ConversationID uuid.UUID `json:"conversation_id"`
|
||||||
UserID uuid.UUID `json:"user_id"`
|
UserID uuid.UUID `json:"user_id"`
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
Type string `json:"type"`
|
LastActive *time.Time `json:"last_active"`
|
||||||
LastMessageID int `json:"last_message_id"`
|
Type string `json:"type"`
|
||||||
LastMessage string `json:"last_message"`
|
LastReadMessageID *int `json:"last_read_message_id"`
|
||||||
LastMessageTime string `json:"last_message_time"`
|
LastMessageID *int `json:"last_message_id"`
|
||||||
LastMessageSender string `json:"last_message_sender"`
|
LastMessage *time.Time `json:"last_message"`
|
||||||
|
LastMessageTime *string `json:"last_message_time"`
|
||||||
|
LastMessageSender *string `json:"last_message_sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ContactSuggestion struct {
|
type ContactSuggestion struct {
|
||||||
@@ -27,9 +30,9 @@ type ContactSuggestion struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Message struct {
|
type Message struct {
|
||||||
MessageID int `json:"message_id"`
|
MessageID int `json:"message_id"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
SentAt string `json:"sent_at"`
|
SentAt time.Time `json:"sent_at"`
|
||||||
Sender string `json:"sender"`
|
Sender string `json:"sender"`
|
||||||
AttachmentUrl string `json:"attachment_url"`
|
AttachmentUrl *string `json:"attachment_url"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ func SetupRoutes(app *fiber.App) {
|
|||||||
auth.Get("/validate", middleware.Protected(), handlers.ValidateToken)
|
auth.Get("/validate", middleware.Protected(), handlers.ValidateToken)
|
||||||
|
|
||||||
// Contacts group
|
// Contacts group
|
||||||
contacts := chat.Group("/contact", middleware.Protected(), logger.New())
|
contacts := chat.Group("/contacts", middleware.Protected(), logger.New())
|
||||||
contacts.Delete("/:contactID/:conversation_id", handlers.DeleteContact)
|
contacts.Delete("/:contactID/:conversation_id", handlers.DeleteContact)
|
||||||
contacts.Post("/:contactUsername", handlers.InsertContact)
|
contacts.Post("/:contactUsername", handlers.InsertContact)
|
||||||
contacts.Get("/", handlers.GetContacts)
|
contacts.Get("/", handlers.GetContacts)
|
||||||
|
|||||||
Reference in New Issue
Block a user