add group color, owner manipulation

This commit is contained in:
2026-04-02 14:00:21 +02:00
parent 8459975f0c
commit b8690f5093
4 changed files with 178 additions and 99 deletions
+21 -1
View File
@@ -1,8 +1,28 @@
package main package main
import "strconv" import (
"fmt"
"strconv"
"strings"
)
func ConvertStringUint32(s string) (uint32, error) { func ConvertStringUint32(s string) (uint32, error) {
v, err := strconv.ParseUint(s, 10, 32) v, err := strconv.ParseUint(s, 10, 32)
return uint32(v), err return uint32(v), err
} }
func ConvertStringToRgb(str string) ([3]uint8, error) {
parts := strings.SplitN(str, ",", 4)
if len(parts) != 3 {
return [3]uint8{}, fmt.Errorf("invalid rgb")
}
var rgb [3]uint8
for i, p := range parts {
n, err := strconv.ParseUint(strings.TrimSpace(p), 10, 8)
if err != nil {
return [3]uint8{}, fmt.Errorf("invalid component %d: %w", i, err)
}
rgb[i] = uint8(n)
}
return rgb, nil
}
+20
View File
@@ -261,3 +261,23 @@ func DbSetClientGroups(ctx context.Context, client *Client) error {
} }
return rows.Err() return rows.Err()
} }
// DbSetGroupColor set group's color based on id
// return: error if not successful
func DbSetGroupColor(ctx context.Context, group *Group) error {
_, err := dbConn.Exec(ctx, `
UPDATE chat_groups SET color_red = $1, color_green = $2, color_blue = $3 WHERE id = $4
`, group.Color[0], group.Color[1], group.Color[2], group.Id)
return err
}
// DbSetGroupOwnerId set group's owner based on id
// return: error if not successful
func DbSetGroupOwnerId(ctx context.Context, group *Group) error {
_, err := dbConn.Exec(ctx, `
UPDATE chat_groups SET owner_id = $1 WHERE id = $2
`, group.OwnerId, group.Id)
return err
}
+138 -95
View File
@@ -4,7 +4,6 @@ import (
"context" "context"
"encoding/binary" "encoding/binary"
json2 "encoding/json" json2 "encoding/json"
"fmt"
"maps" "maps"
"net/http" "net/http"
"slices" "slices"
@@ -23,20 +22,69 @@ func isMethodAllowed(response *http.ResponseWriter, request *http.Request) bool
return true return true
} }
func parseRgb(str string) ([3]uint8, error) { func getClient(ctx context.Context, token string) (*Client, error) {
parts := strings.SplitN(str, ",", 4) clientId, err := TokenValidateGetId(token)
if len(parts) != 3 {
return [3]uint8{}, fmt.Errorf("invalid rgb")
}
var rgb [3]uint8
for i, p := range parts {
n, err := strconv.ParseUint(strings.TrimSpace(p), 10, 8)
if err != nil { if err != nil {
return [3]uint8{}, fmt.Errorf("invalid component %d: %w", i, err) return nil, err
} }
rgb[i] = uint8(n)
client, err := CacheGetClientById(clientId)
if err != nil {
client = &Client{Id: clientId}
err = DbSetClientById(ctx, client)
if err != nil {
return nil, err
} }
return rgb, nil CacheSaveClient(client)
}
return client, nil
}
func getGroup(ctx context.Context, groupId uint32) (*Group, error) {
group, err := CacheGetGroup(groupId)
if err != nil {
group = &Group{Id: groupId}
err = DbSetGroupById(ctx, group)
if err != nil {
return nil, err
}
CacheSaveGroup(group)
}
return group, nil
}
func isOwner(client *Client, group *Group) bool {
if group.OwnerId == client.Id {
return true
}
return false
}
func getIfOwnerClientAndGroup(ctx context.Context, response *http.ResponseWriter, request *http.Request) (*Client, *Group, error) {
client, err := getClient(ctx, request.FormValue("token"))
if err != nil {
http.Error(*response, "invalid token", http.StatusUnauthorized)
return nil, nil, err
}
affectedGroupId, err := ConvertStringUint32(request.FormValue("groupid"))
if err != nil {
http.Error(*response, "no such group", http.StatusUnauthorized)
return nil, nil, err
}
group, err := getGroup(ctx, affectedGroupId)
if err != nil {
http.Error(*response, "no such group", http.StatusUnauthorized)
return nil, nil, err
}
if !isOwner(client, group) {
http.Error(*response, "no such group", http.StatusUnauthorized)
return nil, nil, err
}
return client, group, nil
} }
func HttpHandleNewUser(response http.ResponseWriter, request *http.Request) { func HttpHandleNewUser(response http.ResponseWriter, request *http.Request) {
@@ -56,7 +104,7 @@ func HttpHandleNewUser(response http.ResponseWriter, request *http.Request) {
return return
} }
color, err := parseRgb(request.FormValue("color")) color, err := ConvertStringToRgb(request.FormValue("color"))
if err != nil { if err != nil {
http.Error(response, "bad color", http.StatusBadRequest) http.Error(response, "bad color", http.StatusBadRequest)
return return
@@ -158,7 +206,7 @@ func HttpHandeNewGroup(response http.ResponseWriter, request *http.Request) {
} }
colorString := request.FormValue("color") colorString := request.FormValue("color")
color, err := parseRgb(colorString) color, err := ConvertStringToRgb(colorString)
if err != nil { if err != nil {
var ok bool var ok bool
color, ok = Colors[colorString] color, ok = Colors[colorString]
@@ -193,66 +241,15 @@ func HttpHandeNewGroup(response http.ResponseWriter, request *http.Request) {
response.Write(groupIdBytes) response.Write(groupIdBytes)
} }
func getClient(ctx context.Context, token string) (*Client, error) {
clientId, err := TokenValidateGetId(token)
if err != nil {
return nil, err
}
client, err := CacheGetClientById(clientId)
if err != nil {
client = &Client{Id: clientId}
err = DbSetClientById(ctx, client)
if err != nil {
return nil, err
}
CacheSaveClient(client)
}
return client, nil
}
func getGroup(ctx context.Context, groupId uint32) (*Group, error) {
group, err := CacheGetGroup(groupId)
if err != nil {
group = &Group{Id: groupId}
err = DbSetGroupById(ctx, group)
if err != nil {
return nil, err
}
CacheSaveGroup(group)
}
return group, nil
}
func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Request) { func HttpHandleGroupAddClient(response http.ResponseWriter, request *http.Request) {
if !isMethodAllowed(&response, request) { if !isMethodAllowed(&response, request) {
return return
} }
token := request.FormValue("token")
clientId, err := TokenValidateGetId(token)
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
affectedGroupId, err := ConvertStringUint32(request.FormValue("groupid"))
if err != nil {
http.Error(response, "no such group", http.StatusUnauthorized)
return
}
ctx := request.Context() ctx := request.Context()
group, err := getGroup(ctx, affectedGroupId) _, group, err := getIfOwnerClientAndGroup(ctx, &response, request)
if err != nil { if err != nil {
http.Error(response, "no such group", http.StatusUnauthorized)
return
}
if group.OwnerId != clientId {
http.Error(response, "no such group", http.StatusUnauthorized)
return return
} }
@@ -310,29 +307,10 @@ func HttpHandleGroupRemoveClient(response http.ResponseWriter, request *http.Req
return return
} }
token := request.FormValue("token")
clientId, err := TokenValidateGetId(token)
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
affectedGroupId, err := ConvertStringUint32(request.FormValue("groupid"))
if err != nil {
http.Error(response, "no such group", http.StatusUnauthorized)
return
}
ctx := request.Context() ctx := request.Context()
group, err := getGroup(ctx, affectedGroupId) _, group, err := getIfOwnerClientAndGroup(ctx, &response, request)
if err != nil { if err != nil {
http.Error(response, "no such group", http.StatusUnauthorized)
return
}
if group.OwnerId != clientId {
http.Error(response, "no such group", http.StatusUnauthorized)
return return
} }
@@ -372,13 +350,84 @@ func HttpHandleGroupRemoveClient(response http.ResponseWriter, request *http.Req
response.Write([]byte(strconv.Itoa(count))) response.Write([]byte(strconv.Itoa(count)))
} }
func HttpHandleGroupChangeColor(response http.ResponseWriter, request *http.Request) {
if !isMethodAllowed(&response, request) {
return
}
ctx := request.Context()
_, group, err := getIfOwnerClientAndGroup(ctx, &response, request)
if err != nil {
return
}
color, err := ConvertStringToRgb(request.FormValue("color"))
if err != nil {
http.Error(response, "invalid color", http.StatusBadRequest)
return
}
group.Color = color
err = DbSetGroupColor(ctx, group)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted)
response.Write([]byte("changed"))
}
func HttpHandleGroupChangeOwner(response http.ResponseWriter, request *http.Request) {
if !isMethodAllowed(&response, request) {
return
}
ctx := request.Context()
client, group, err := getIfOwnerClientAndGroup(ctx, &response, request)
if err != nil {
return
}
newOwnerName := request.FormValue("newOwner")
newOwner, err := CacheGetClientByName(newOwnerName)
if err != nil {
newOwner = &Client{Name: newOwnerName}
err = DbSetClientByName(ctx, newOwner)
if err != nil {
http.Error(response, "client not in group", http.StatusBadRequest)
return
}
CacheSaveClient(client)
}
_, ok := group.Clients[newOwner.Id]
if !ok {
http.Error(response, "client not in group", http.StatusBadRequest)
return
}
group.OwnerId = newOwner.Id
err = DbSetGroupOwnerId(ctx, group)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted)
response.Write([]byte("changed"))
}
func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) { func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) {
if !isMethodAllowed(&response, request) { if !isMethodAllowed(&response, request) {
return return
} }
token := request.FormValue("token") ctx := request.Context()
if token == "" { client, err := getClient(ctx, request.FormValue("token"))
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized) http.Error(response, "invalid token", http.StatusUnauthorized)
return return
} }
@@ -400,13 +449,7 @@ func HttpHandleNewMessage(response http.ResponseWriter, request *http.Request) {
return return
} }
clientId, err := TokenValidateGetId(token) err = WsSendToGroup(ctx, targetId, client.Id, content)
if err != nil {
http.Error(response, "invalid token", http.StatusUnauthorized)
return
}
ctx := request.Context()
err = WsSendToGroup(ctx, targetId, clientId, content)
if err != nil { if err != nil {
http.Error(response, err.Error(), http.StatusBadRequest) http.Error(response, err.Error(), http.StatusBadRequest)
return return
-4
View File
@@ -1,6 +1,2 @@
group manipulation:
- color
- owner
debug gui debug gui
chat history chat history