add group color, owner manipulation
This commit is contained in:
+21
-1
@@ -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
@@ -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
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user