From cd83870ab4eecc7c0074d7aad042f4546f8afdac Mon Sep 17 00:00:00 2001 From: slawk0 Date: Sat, 1 Feb 2025 17:05:43 +0100 Subject: [PATCH] added delete contact route --- .idea/dataSources.xml | 17 ------- .idea/sqldialects.xml | 2 +- database/{db.go => auth.go} | 7 ++- database/contacts.go | 88 +++++++++++++++++++++++++++++++++++++ handlers/auth.go | 29 +++++++++--- handlers/contacts.go | 42 ++++++++++++++++++ model/model.go | 10 ----- router/router.go | 5 +++ 8 files changed, 163 insertions(+), 37 deletions(-) delete mode 100644 .idea/dataSources.xml rename database/{db.go => auth.go} (91%) create mode 100644 database/contacts.go create mode 100644 handlers/contacts.go diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml deleted file mode 100644 index 65494e9..0000000 --- a/.idea/dataSources.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - postgresql - true - org.postgresql.Driver - jdbc:postgresql://192.168.0.47:5432/postgres - - - - - - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/.idea/sqldialects.xml b/.idea/sqldialects.xml index 39e591e..d39012b 100644 --- a/.idea/sqldialects.xml +++ b/.idea/sqldialects.xml @@ -1,7 +1,7 @@ - + \ No newline at end of file diff --git a/database/db.go b/database/auth.go similarity index 91% rename from database/db.go rename to database/auth.go index 62f0934..5e2a64f 100644 --- a/database/db.go +++ b/database/auth.go @@ -52,6 +52,9 @@ func InsertUser(db *sql.DB, username string, passwordHash string) (string, error if err != nil { return "", fmt.Errorf("error inserting user: %v", err) } + + log.Printf("Inserted user: %v", username) + return userId, err } @@ -64,8 +67,8 @@ func GetPasswordHash(db *sql.DB, username string) (string, error) { var passwordHash string err := db.QueryRow(query, username).Scan(&passwordHash) if err != nil { - fmt.Printf("error getting password: %v\n", err) - return "", fmt.Errorf("error getting password: %v", err) + fmt.Printf("error getting password hash: %v\n", err) + return "", fmt.Errorf("error getting password hash: %v", err) } return passwordHash, err diff --git a/database/contacts.go b/database/contacts.go new file mode 100644 index 0000000..9e5c67a --- /dev/null +++ b/database/contacts.go @@ -0,0 +1,88 @@ +package database + +import ( + "database/sql" + "errors" + "fmt" + "github.com/google/uuid" + "log" +) + +func DeleteContact(db *sql.DB, userID uuid.UUID, conversationID uuid.UUID) (string, error) { + // Check conversation type + var conversationType string + err := db.QueryRow( + "SELECT conversation_type FROM Conversations WHERE conversation_id = $1", + conversationID, + ).Scan(&conversationType) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return "no conversation found for this id", nil + } + return "", fmt.Errorf("error checking conversation type: %w", err) + } + + if conversationType == "group" { + // Delete from Contacts + res, err := db.Exec( + "DELETE FROM Contacts WHERE conversation_id = $1 AND user_id = $2", + conversationID, + userID, + ) + if err != nil { + return "", fmt.Errorf("error deleting contact: %w", err) + } + + rowsAffected, err := res.RowsAffected() + if err != nil { + return "", fmt.Errorf("error checking contact deletion: %w", err) + } + if rowsAffected == 0 { + return fmt.Sprintf("no matching contact found with conversation id: %s, user id: %s", conversationID, userID), nil + } + + // Delete from Memberships + res, err = db.Exec( + "DELETE FROM Memberships WHERE conversation_id = $1 AND user_id = $2", + conversationID, + userID, + ) + if err != nil { + return "", fmt.Errorf("error deleting membership: %w", err) + } + + rowsAffected, err = res.RowsAffected() + if err != nil { + return "", fmt.Errorf("error checking membership deletion: %w", err) + } + if rowsAffected == 0 { + return "", fmt.Errorf("no matching membership found with conversation id: %s, user id: %s", conversationID, userID) + } + + log.Printf("Successfully removed user %s from group %s", userID, conversationID) + } else { + // Handle direct conversation + res, err := db.Exec( + "DELETE FROM Contacts WHERE user_id = $1 AND conversation_id = $2", + userID, + conversationID, + ) + if err != nil { + log.Printf("Error deleting contact: %v", err) + return "", fmt.Errorf("error deleting contact: %w", err) + } + + rowsAffected, err := res.RowsAffected() + if err != nil { + log.Printf("Error checking contact deletion: %v", err) + return "", fmt.Errorf("error checking contact deletion: %w", err) + } + if rowsAffected == 0 { + return fmt.Sprintf("no matching contact found with user id: %s, conversation id: %s", userID, conversationID), nil + } + + log.Printf("Successfully deleted contact for user %s in conversation %s", userID, conversationID) + } + + return "", nil +} diff --git a/handlers/auth.go b/handlers/auth.go index 3f73949..3c2b67a 100644 --- a/handlers/auth.go +++ b/handlers/auth.go @@ -9,27 +9,34 @@ import ( "relay-server/config" "relay-server/database" "relay-server/helpers" - "relay-server/model" "time" ) func Signup(c *fiber.Ctx) error { + + type SignupStruct struct { + Username string `json:"username" xml:"username" form:"username"` + Password string `json:"password" xml:"password" form:"password"` + } + db := database.DB - u := new(model.SignupStruct) + u := new(SignupStruct) if err := c.BodyParser(u); err != nil { return err } // Checks if username or passwords are empty if u.Username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"}) - } else if u.Password == "" { + } + if u.Password == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"}) } // Checks if passwords or username have valid length and characters if !helpers.IsValidPassword(u.Password) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid password"}) - } else if !helpers.IsValidUsername(u.Username) { + } + if !helpers.IsValidUsername(u.Username) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid username"}) } @@ -74,8 +81,14 @@ func Signup(c *fiber.Ctx) error { } func Login(c *fiber.Ctx) error { + + type loginStruct struct { + Username string `json:"username" xml:"username" form:"username"` + Password string `json:"password" xml:"password" form:"password"` + } + db := database.DB - u := new(model.LoginStruct) + u := new(loginStruct) if err := c.BodyParser(u); err != nil { return err @@ -84,14 +97,16 @@ func Login(c *fiber.Ctx) error { // Checks if username or passwords are empty if u.Username == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"}) - } else if u.Password == "" { + } + if u.Password == "" { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"}) } // Checks if username or passwords have valid length and characters if !helpers.IsValidUsername(u.Username) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid username"}) - } else if !helpers.IsValidPassword(u.Password) { + } + if !helpers.IsValidPassword(u.Password) { return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid password"}) } diff --git a/handlers/contacts.go b/handlers/contacts.go new file mode 100644 index 0000000..ff7614e --- /dev/null +++ b/handlers/contacts.go @@ -0,0 +1,42 @@ +package handlers + +import ( + "github.com/gofiber/fiber/v2" + "github.com/google/uuid" + "log" + "relay-server/database" +) + +func DeleteContact(c *fiber.Ctx) error { + + type params struct { + ContactId uuid.UUID `params:"contact_id"` + ConversationId uuid.UUID `params:"conversation_id"` + } + + p := new(params) + if err := c.ParamsParser(p); err != nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid params"}) + } + + db := database.DB + + if p.ContactId == uuid.Nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"message": "contact_id is empty"}) + } + if p.ConversationId == uuid.Nil { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"message": "conversation_id is empty"}) + } + + msg, err := database.DeleteContact(db, p.ContactId, p.ConversationId) + if err != nil { + log.Println(err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Failed to delete contact"}) + } + if msg != "" { + return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"message": msg}) + } + log.Println("Contact deleted") + + return c.Status(fiber.StatusOK).JSON(fiber.Map{"message": "Contact deleted"}) +} diff --git a/model/model.go b/model/model.go index 88b1910..c60c6ac 100644 --- a/model/model.go +++ b/model/model.go @@ -2,16 +2,6 @@ package model import "github.com/golang-jwt/jwt/v5" -type LoginStruct struct { - Username string `json:"username" xml:"username" form:"username"` - Password string `json:"password" xml:"password" form:"password"` -} - -type SignupStruct struct { - Username string `json:"username" xml:"username" form:"username"` - Password string `json:"password" xml:"password" form:"password"` -} - type UserClaims struct { Username string `json:"username"` UserId string `json:"user_id"` diff --git a/router/router.go b/router/router.go index b3cb6e3..550b180 100644 --- a/router/router.go +++ b/router/router.go @@ -12,10 +12,15 @@ func SetupRoutes(app *fiber.App) { return c.SendString("Hello, World!") }) api := app.Group("/api", logger.New()) + chat := api.Group("/chat", middleware.Protected(), logger.New()) // Auth group auth := api.Group("/auth", middleware.Protected(), handlers.ValidateToken) auth.Post("/signup", handlers.Signup) auth.Post("/login", handlers.Login) auth.Get("/validate", handlers.ValidateToken) + + // Contacts group + contacts := chat.Group("/contacts", middleware.Protected(), logger.New()) + contacts.Delete("/:contact_id/:conversation_id", handlers.DeleteContact) }