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)
}