From fc14987d6ddce1c3e3cf38242780e4dd9124b26e Mon Sep 17 00:00:00 2001 From: Sisi Date: Sat, 4 Apr 2026 12:55:35 +0200 Subject: [PATCH] add db function for user connections --- database.go | 74 +++++++++++++++++++++++++++++++++++++++++++++++------ http.go | 14 ++++++++-- main.go | 10 +++++--- structs.go | 20 ++++++++++----- wsServer.go | 2 +- 5 files changed, 100 insertions(+), 20 deletions(-) diff --git a/database.go b/database.go index 18b8758..bf10051 100644 --- a/database.go +++ b/database.go @@ -33,6 +33,15 @@ func DbInit(ctx context.Context) { panic(err) } + _, err = dbConn.Exec(ctx, ` + CREATE TABLE IF NOT EXISTS user_connections ( + requestor_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + recipient_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE, + is_accepted BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMP NOT NULL DEFAULT NOW() + ) + `) + _, err = dbConn.Exec(ctx, ` CREATE TABLE IF NOT EXISTS chat_groups ( id SERIAL PRIMARY KEY, @@ -63,9 +72,9 @@ func DbInit(ctx context.Context) { } } -// DbUserSaveWithoutGroups saves user in db without groups and sets its id +// DbUserSaveWithoutGroupsConnections saves user in db without groups and sets its id // return: error if not successful -func DbUserSaveWithoutGroups(ctx context.Context, user *User) error { +func DbUserSaveWithoutGroupsConnections(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` INSERT INTO users (name, pass_hash, pronouns, color_red, color_green, color_blue, created_at) VALUES ($1, $2, $3, $4, $5, $6, $7) @@ -84,7 +93,7 @@ func DbUserDelete(ctx context.Context, id uint32) error { return err } -// DbUserSetByName sets all fields of given struct with database's data using name +// DbUserSetByName sets all fields of given struct with database's data // return: error if not successful func DbUserSetByName(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` @@ -93,12 +102,16 @@ func DbUserSetByName(ctx context.Context, user *User) error { if err != nil { return err } - return DbUserSetGroups(ctx, user) + err = DbUserSetGroups(ctx, user) + if err != nil { + return err + } + return DbUserSetConnections(ctx, user) } -// DbUserSetByIdWithoutGroups sets all fields of given struct with database's data using id, excluding groups +// DbUserSetByIdWithoutGroupsConnections sets all fields of given struct with database's data using id, excluding groups // return: error if not successful -func DbUserSetByIdWithoutGroups(ctx context.Context, user *User) error { +func DbUserSetByIdWithoutGroupsConnections(ctx context.Context, user *User) error { err := dbConn.QueryRow(ctx, ` SELECT name, pass_hash, pronouns, color_red, color_green, color_blue, created_at FROM users WHERE id = $1 `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &user.Color[0], &user.Color[1], &user.Color[2], &user.CreatedAt) @@ -108,11 +121,15 @@ func DbUserSetByIdWithoutGroups(ctx context.Context, user *User) error { // DbUserSetById sets all fields of given struct with database's data using id, including groups // return: error if not successful func DbUserSetById(ctx context.Context, user *User) error { - err := DbUserSetByIdWithoutGroups(ctx, user) + err := DbUserSetByIdWithoutGroupsConnections(ctx, user) if err != nil { return err } - return DbUserSetGroups(ctx, user) + err = DbUserSetGroups(ctx, user) + if err != nil { + return err + } + return DbUserSetConnections(ctx, user) } // DbUserSetGroups populates user's Groups map with ids of all groups the user belongs to from database @@ -137,6 +154,47 @@ func DbUserSetGroups(ctx context.Context, user *User) error { return rows.Err() } +func DbUserSetConnections(ctx context.Context, user *User) error { + rows, err := dbConn.Query(ctx, ` + SELECT requestor_id, recipient_id, is_accepted, created_at FROM user_connections WHERE requestor_id = $1 or recipient_id = $1 + `) + if err != nil { + return err + } + + defer rows.Close() + for rows.Next() { + var ( + requestorId uint32 + recipientId uint32 + isAccepted bool + createdAt time.Time + ) + err = rows.Scan(&requestorId, &recipientId, &isAccepted, &createdAt) + if err != nil { + return err + } + + if requestorId == user.Id { + user.Connections[recipientId] = &Connection{ + CreatedAt: createdAt, + With: recipientId, + IsFromUser: true, + IsAccepted: isAccepted, + } + } else { + user.Connections[requestorId] = &Connection{ + CreatedAt: createdAt, + With: requestorId, + IsFromUser: false, + IsAccepted: isAccepted, + } + } + } + + return rows.Err() +} + // DbUserSetColor set user's color based on id // return: error if not successful func DbUserSetColor(ctx context.Context, user *User) error { diff --git a/http.go b/http.go index 5256613..cbe2b57 100644 --- a/http.go +++ b/http.go @@ -125,7 +125,7 @@ func HttpHandleUserNew(response http.ResponseWriter, request *http.Request) { ctx := request.Context() - err = DbUserSaveWithoutGroups(ctx, newUser) + err = DbUserSaveWithoutGroupsConnections(ctx, newUser) if err != nil { http.Error(response, "name taken", http.StatusUnauthorized) return @@ -199,6 +199,16 @@ func HttpHandleUserModifyAbout(response http.ResponseWriter, request *http.Reque response.WriteHeader(http.StatusAccepted) } +func HttpHandleUserMessage(response http.ResponseWriter, request *http.Request) { + ctx := request.Context() + user, err := getUser(ctx, request.FormValue("token")) + if err != nil { + http.Error(response, "invalid token", http.StatusUnauthorized) + return + } + +} + func HttpHandleNewToken(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return @@ -488,7 +498,7 @@ func HttpHandleGroupChangeOwner(response http.ResponseWriter, request *http.Requ response.WriteHeader(http.StatusAccepted) } -func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) { +func HttpHandleGroupMessage(response http.ResponseWriter, request *http.Request) { if !isMethodAllowed(&response, request) { return } diff --git a/main.go b/main.go index ae8bdfe..a511fdf 100644 --- a/main.go +++ b/main.go @@ -20,16 +20,20 @@ func main() { http.HandleFunc("/new/user", withCORS(HttpHandleUserNew)) http.HandleFunc("/new/token", withCORS(HttpHandleNewToken)) http.HandleFunc("/new/group", withCORS(HttpHandeGroupCreate)) - http.HandleFunc("/new/message", withCORS(HttpHandleNewMessage)) - http.HandleFunc("mod/user/appearence", withCORS(HttpHandleUserModifyAppearance)) - http.HandleFunc("mod/user/about", withCORS(HttpHandleUserModifyAbout)) + + http.HandleFunc("/mod/user/appearence", withCORS(HttpHandleUserModifyAppearance)) + http.HandleFunc("/mod/user/about", withCORS(HttpHandleUserModifyAbout)) http.HandleFunc("/mod/group/addusers", withCORS(HttpHandleGroupAddUser)) http.HandleFunc("/mod/group/removeusers", withCORS(HttpHandleGroupRemoveUser)) http.HandleFunc("/mod/group/color", withCORS(HttpHandleGroupChangeColor)) http.HandleFunc("/mod/group/owner", withCORS(HttpHandleGroupChangeOwner)) + http.HandleFunc("/get/groups", withCORS(HttpHandleGroupsGetWithoutMembers)) + http.HandleFunc("/get/group/members", withCORS(HttpHandleGroupMembersGet)) http.HandleFunc("/del/group", withCORS(HttpHandleGroupDelete)) + + http.HandleFunc("/msg/group", withCORS(HttpHandleGroupMessage)) http.HandleFunc("/ws", ServeWsConnection) log.Println("listening on :8080") diff --git a/structs.go b/structs.go index 24800e7..b68b887 100644 --- a/structs.go +++ b/structs.go @@ -14,9 +14,17 @@ type User struct { WsConn *websocket.Conn Id uint32 Groups map[uint32]struct{} + Connections map[uint32]*Connection Color [3]uint8 } +type Connection struct { + CreatedAt time.Time + With uint32 + IsFromUser bool + IsAccepted bool +} + type Group struct { Name string CreatedAt time.Time @@ -29,11 +37,11 @@ type Group struct { } type GroupNoMembers struct { - Name string `json:"name"` - CreatedAt time.Time `json:"createdAt"` - Id uint32 `json:"id"` - CreatorId uint32 `json:"creatorId"` - OwnerId uint32 `json:"ownerId"` - Color [3]uint8 `json:"color"` + Name string `json:"name"` + CreatedAt time.Time `json:"createdAt"` + Id uint32 `json:"id"` + CreatorId uint32 `json:"creatorId"` + OwnerId uint32 `json:"ownerId"` + Color [3]uint8 `json:"color"` EnableUsersColors bool `json:"enableUsersColors"` } diff --git a/wsServer.go b/wsServer.go index 60d4487..b8387b6 100644 --- a/wsServer.go +++ b/wsServer.go @@ -138,7 +138,7 @@ func handleUnauthenticatedMessage(ctx context.Context, user *User, userMessage * userFromCache, err := CacheGetUserById(userId) if err != nil { dbUser := &User{Id: userId} - err = DbUserSetByIdWithoutGroups(ctx, dbUser) + err = DbUserSetByIdWithoutGroupsConnections(ctx, dbUser) if err != nil { var msg = map[string]any{ "from": "server",