added delete contact route
This commit is contained in:
17
.idea/dataSources.xml
generated
17
.idea/dataSources.xml
generated
@@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
|
||||||
<data-source source="LOCAL" name="postgres@192.168.0.47" uuid="fc534921-0a7d-4120-bac3-e6f8ac7fb7a1">
|
|
||||||
<driver-ref>postgresql</driver-ref>
|
|
||||||
<synchronize>true</synchronize>
|
|
||||||
<jdbc-driver>org.postgresql.Driver</jdbc-driver>
|
|
||||||
<jdbc-url>jdbc:postgresql://192.168.0.47:5432/postgres</jdbc-url>
|
|
||||||
<jdbc-additional-properties>
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.host.port" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.enabled" value="false" />
|
|
||||||
<property name="com.intellij.clouds.kubernetes.db.container.port" />
|
|
||||||
</jdbc-additional-properties>
|
|
||||||
<working-dir>$ProjectFileDir$</working-dir>
|
|
||||||
</data-source>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
2
.idea/sqldialects.xml
generated
2
.idea/sqldialects.xml
generated
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="SqlDialectMappings">
|
<component name="SqlDialectMappings">
|
||||||
<file url="file://$PROJECT_DIR$/database/db.go" dialect="GenericSQL" />
|
<file url="file://$PROJECT_DIR$/database/auth.go" dialect="PostgreSQL" />
|
||||||
<file url="PROJECT" dialect="PostgreSQL" />
|
<file url="PROJECT" dialect="PostgreSQL" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -52,6 +52,9 @@ func InsertUser(db *sql.DB, username string, passwordHash string) (string, error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error inserting user: %v", err)
|
return "", fmt.Errorf("error inserting user: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Printf("Inserted user: %v", username)
|
||||||
|
|
||||||
return userId, err
|
return userId, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +67,8 @@ func GetPasswordHash(db *sql.DB, username string) (string, error) {
|
|||||||
var passwordHash string
|
var passwordHash string
|
||||||
err := db.QueryRow(query, username).Scan(&passwordHash)
|
err := db.QueryRow(query, username).Scan(&passwordHash)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("error getting password: %v\n", err)
|
fmt.Printf("error getting password hash: %v\n", err)
|
||||||
return "", fmt.Errorf("error getting password: %v", err)
|
return "", fmt.Errorf("error getting password hash: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return passwordHash, err
|
return passwordHash, err
|
||||||
88
database/contacts.go
Normal file
88
database/contacts.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
@@ -9,27 +9,34 @@ import (
|
|||||||
"relay-server/config"
|
"relay-server/config"
|
||||||
"relay-server/database"
|
"relay-server/database"
|
||||||
"relay-server/helpers"
|
"relay-server/helpers"
|
||||||
"relay-server/model"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Signup(c *fiber.Ctx) error {
|
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
|
db := database.DB
|
||||||
u := new(model.SignupStruct)
|
u := new(SignupStruct)
|
||||||
if err := c.BodyParser(u); err != nil {
|
if err := c.BodyParser(u); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Checks if username or passwords are empty
|
// Checks if username or passwords are empty
|
||||||
if u.Username == "" {
|
if u.Username == "" {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"})
|
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"})
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if passwords or username have valid length and characters
|
// Checks if passwords or username have valid length and characters
|
||||||
if !helpers.IsValidPassword(u.Password) {
|
if !helpers.IsValidPassword(u.Password) {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid 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"})
|
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 {
|
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
|
db := database.DB
|
||||||
u := new(model.LoginStruct)
|
u := new(loginStruct)
|
||||||
|
|
||||||
if err := c.BodyParser(u); err != nil {
|
if err := c.BodyParser(u); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -84,14 +97,16 @@ func Login(c *fiber.Ctx) error {
|
|||||||
// Checks if username or passwords are empty
|
// Checks if username or passwords are empty
|
||||||
if u.Username == "" {
|
if u.Username == "" {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "username is empty"})
|
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"})
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "password is empty"})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks if username or passwords have valid length and characters
|
// Checks if username or passwords have valid length and characters
|
||||||
if !helpers.IsValidUsername(u.Username) {
|
if !helpers.IsValidUsername(u.Username) {
|
||||||
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid 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"})
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "invalid password"})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
42
handlers/contacts.go
Normal file
42
handlers/contacts.go
Normal file
@@ -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"})
|
||||||
|
}
|
||||||
@@ -2,16 +2,6 @@ package model
|
|||||||
|
|
||||||
import "github.com/golang-jwt/jwt/v5"
|
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 {
|
type UserClaims struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
UserId string `json:"user_id"`
|
UserId string `json:"user_id"`
|
||||||
|
|||||||
@@ -12,10 +12,15 @@ func SetupRoutes(app *fiber.App) {
|
|||||||
return c.SendString("Hello, World!")
|
return c.SendString("Hello, World!")
|
||||||
})
|
})
|
||||||
api := app.Group("/api", logger.New())
|
api := app.Group("/api", logger.New())
|
||||||
|
chat := api.Group("/chat", middleware.Protected(), logger.New())
|
||||||
|
|
||||||
// Auth group
|
// Auth group
|
||||||
auth := api.Group("/auth", middleware.Protected(), handlers.ValidateToken)
|
auth := api.Group("/auth", middleware.Protected(), handlers.ValidateToken)
|
||||||
auth.Post("/signup", handlers.Signup)
|
auth.Post("/signup", handlers.Signup)
|
||||||
auth.Post("/login", handlers.Login)
|
auth.Post("/login", handlers.Login)
|
||||||
auth.Get("/validate", handlers.ValidateToken)
|
auth.Get("/validate", handlers.ValidateToken)
|
||||||
|
|
||||||
|
// Contacts group
|
||||||
|
contacts := chat.Group("/contacts", middleware.Protected(), logger.New())
|
||||||
|
contacts.Delete("/:contact_id/:conversation_id", handlers.DeleteContact)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user