From 0afed9a32608e5dd8c45d9e835be1efa11ce1157 Mon Sep 17 00:00:00 2001 From: cos Date: Thu, 30 Apr 2026 11:44:54 +0200 Subject: [PATCH] add hub function --- go.mod | 6 +- packages/cache/cache.go | 2 +- packages/httpRequest/connectionsAndDms.go | 46 ++++---- packages/httpRequest/files.go | 56 +++++----- packages/httpRequest/get.go | 11 +- packages/httpRequest/helper.go | 8 +- packages/httpRequest/hubs.go | 129 ++++++++++++++++------ packages/httpRequest/user.go | 28 ++--- packages/postgresql/postgresql.go | 8 +- packages/types/types.go | 37 ++++--- 10 files changed, 203 insertions(+), 128 deletions(-) diff --git a/go.mod b/go.mod index cae97cc..2542770 100644 --- a/go.mod +++ b/go.mod @@ -5,22 +5,24 @@ go 1.26 require ( github.com/BurntSushi/toml v1.6.0 github.com/coder/websocket v1.8.14 + github.com/google/uuid v1.6.0 github.com/jackc/pgx/v5 v5.8.0 + github.com/minio/minio-go/v7 v7.0.100 golang.org/x/crypto v0.49.0 ) require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/go-ini/ini v1.67.0 // indirect - github.com/google/uuid v1.6.0 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/klauspost/compress v1.18.2 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/klauspost/crc32 v1.3.0 // indirect + github.com/kr/text v0.2.0 // indirect github.com/minio/crc64nvme v1.1.1 // indirect github.com/minio/md5-simd v1.1.2 // indirect - github.com/minio/minio-go/v7 v7.0.100 // indirect github.com/philhofer/fwd v1.2.0 // indirect + github.com/rogpeppe/go-internal v1.14.1 // indirect github.com/rs/xid v1.6.0 // indirect github.com/tinylib/msgp v1.6.1 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect diff --git a/packages/cache/cache.go b/packages/cache/cache.go index 0334cbb..26550e8 100644 --- a/packages/cache/cache.go +++ b/packages/cache/cache.go @@ -94,7 +94,7 @@ func IncrementConnectionsUnreadMessages(userId uuid.UUID, connId uuid.UUID) { } connectionsUnreadMessages[connId][userId]++ } -func DeallocateConnectionsUnreadMessages(userId uuid.UUID, connId uuid.UUID) { +func DeleteConnectionsUnreadMessages(userId uuid.UUID, connId uuid.UUID) { Mu.Lock() defer Mu.Unlock() diff --git a/packages/httpRequest/connectionsAndDms.go b/packages/httpRequest/connectionsAndDms.go index 61a3f7d..3fa8673 100644 --- a/packages/httpRequest/connectionsAndDms.go +++ b/packages/httpRequest/connectionsAndDms.go @@ -1,7 +1,7 @@ package httpRequest import ( - json2 "encoding/json" + "encoding/json" "maps" "net/http" "slices" @@ -22,7 +22,7 @@ import ( ) func HandleDm(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -33,7 +33,7 @@ func HandleDm(response http.ResponseWriter, request *http.Request) { return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -87,7 +87,7 @@ func HandleDm(response http.ResponseWriter, request *http.Request) { } func HandleUserGetConnectionsUnreadMessages(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -115,22 +115,22 @@ func HandleUserGetConnectionsUnreadMessages(response http.ResponseWriter, reques for _, connId := range connectionIds { count, _ := cache.GetConnectionsUnreadMessages(user.Id, connId) - cache.DeallocateConnectionsUnreadMessages(user.Id, connId) + cache.DeleteConnectionsUnreadMessages(user.Id, connId) result = append(result, count) } - json, err := json2.Marshal(result) + counts, err := json.Marshal(result) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusAccepted) - response.Write(json) + response.Write(counts) } func HandleUserGetConnectionMessages(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -140,7 +140,7 @@ func HandleUserGetConnectionMessages(response http.ResponseWriter, request *http return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -188,18 +188,18 @@ func HandleUserGetConnectionMessages(response http.ResponseWriter, request *http } } - json, err := json2.Marshal(messages) + data, err := json.Marshal(messages) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusOK) - response.Write(json) + response.Write(data) } func HandleUserNewConnection(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -210,12 +210,12 @@ func HandleUserNewConnection(response http.ResponseWriter, request *http.Request } recipientId, err := convertions.StringToUuid(request.FormValue("recipient")) if err != nil { - http.Error(response, "no such user", http.StatusUnauthorized) + http.Error(response, "invalid recipient", http.StatusBadRequest) return } recipient, err := getUserById(ctx, recipientId) if err != nil { - http.Error(response, "no such user", http.StatusUnauthorized) + http.Error(response, "no such user", http.StatusNotFound) return } @@ -257,7 +257,7 @@ func HandleUserNewConnection(response http.ResponseWriter, request *http.Request } func HandleUserDeleteConnection(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -268,7 +268,7 @@ func HandleUserDeleteConnection(response http.ResponseWriter, request *http.Requ return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -296,7 +296,7 @@ func HandleUserDeleteConnection(response http.ResponseWriter, request *http.Requ } func HandleUserElevateConnection(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -305,7 +305,7 @@ func HandleUserElevateConnection(response http.ResponseWriter, request *http.Req http.Error(response, "invalid token", http.StatusUnauthorized) return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -363,7 +363,7 @@ func HandleUserElevateConnection(response http.ResponseWriter, request *http.Req } func HandleUserDeElevateConnection(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -374,7 +374,7 @@ func HandleUserDeElevateConnection(response http.ResponseWriter, request *http.R return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -409,7 +409,7 @@ func HandleUserDeElevateConnection(response http.ResponseWriter, request *http.R } func HandleUserGetConnections(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -423,12 +423,12 @@ func HandleUserGetConnections(response http.ResponseWriter, request *http.Reques user.Mu.RLock() connections := slices.Collect(maps.Values(user.Connections)) user.Mu.RUnlock() - json, err := json2.Marshal(connections) + data, err := json.Marshal(connections) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusOK) - response.Write(json) + response.Write(data) } diff --git a/packages/httpRequest/files.go b/packages/httpRequest/files.go index 77f35c7..e8290d3 100644 --- a/packages/httpRequest/files.go +++ b/packages/httpRequest/files.go @@ -1,7 +1,7 @@ package httpRequest import ( - json2 "encoding/json" + "encoding/json" "maps" "net/http" "slices" @@ -18,7 +18,7 @@ import ( ) func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, file) { + if !validCheckWithResponseOnFail(response, request, file) { return } ctx := request.Context() @@ -36,7 +36,7 @@ func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Requ return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -68,7 +68,7 @@ func HandleAttachmentFileUpload(response http.ResponseWriter, request *http.Requ } func HandleSetUserAvatar(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, avatar) { + if !validCheckWithResponseOnFail(response, request, avatar) { return } ctx := request.Context() @@ -105,18 +105,18 @@ func HandleSetUserAvatar(response http.ResponseWriter, request *http.Request) { return } - if user.AvatarType != "" { - if err = minio.Delete(ctx, user.AvatarType); err != nil { + if user.AvatarKey != "" { + if err = minio.Delete(ctx, user.AvatarKey); err != nil { minio.Delete(ctx, key) http.Error(response, "internal server error", http.StatusInternalServerError) return } } - user.AvatarType = key + user.AvatarKey = key err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{Avatar: true}) if err != nil { http.Error(response, "failed to update user avatar", http.StatusInternalServerError) - minio.Delete(ctx, user.AvatarType) + minio.Delete(ctx, user.AvatarKey) return } @@ -142,7 +142,7 @@ func HandleSetUserAvatar(response http.ResponseWriter, request *http.Request) { } func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -165,31 +165,32 @@ func HandleGetUserAvatar(response http.ResponseWriter, request *http.Request) { return } - if target.AvatarType == "" { + if target.AvatarKey == "" { http.Error(response, "user have no avatar", http.StatusNoContent) return } - url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarType) + url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.AvatarKey) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - json, err := json2.Marshal(map[string]any{ + avatarData, err := json.Marshal(map[string]any{ "url": url.String(), "metadata": meta, }) if err != nil { http.Error(response, "json error", http.StatusInternalServerError) + return } response.WriteHeader(http.StatusOK) - response.Write(json) + response.Write(avatarData) } func HandleSetUserProfileBg(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, profileBg) { + if !validCheckWithResponseOnFail(response, request, profileBg) { return } ctx := request.Context() @@ -226,18 +227,18 @@ func HandleSetUserProfileBg(response http.ResponseWriter, request *http.Request) return } - if user.ProfileBgType != "" { - if err = minio.Delete(ctx, user.ProfileBgType); err != nil { + if user.ProfileBgKey != "" { + if err = minio.Delete(ctx, user.ProfileBgKey); err != nil { minio.Delete(ctx, key) http.Error(response, "internal server error", http.StatusInternalServerError) return } } - user.ProfileBgType = key + user.ProfileBgKey = key err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{ProfileBg: true}) if err != nil { http.Error(response, "failed to update user profile background", http.StatusInternalServerError) - minio.Delete(ctx, user.ProfileBgType) + minio.Delete(ctx, user.ProfileBgKey) return } @@ -262,7 +263,7 @@ func HandleSetUserProfileBg(response http.ResponseWriter, request *http.Request) } func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -285,31 +286,32 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request) return } - if target.ProfileBgType == "" { + if target.ProfileBgKey == "" { http.Error(response, "user have no profile background", http.StatusNoContent) return } - url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgType) + url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, target.ProfileBgKey) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } - json, err := json2.Marshal(map[string]any{ + profileBgData, err := json.Marshal(map[string]any{ "url": url.String(), "metadata": meta, }) if err != nil { http.Error(response, "json error", http.StatusInternalServerError) + return } response.WriteHeader(http.StatusOK) - response.Write(json) + response.Write(profileBgData) } func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -320,7 +322,7 @@ func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Re return } - conn, ok := getConnectionWithResponseOnFail(&response, request, user) + conn, ok := getConnectionWithResponseOnFail(response, request.FormValue("connectionid"), user) if !ok { return } @@ -337,7 +339,7 @@ func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Re return } - json, err := json2.Marshal(map[string]string{ + fileData, err := json.Marshal(map[string]string{ "url": url.String(), "originalName": meta["originalName"], }) @@ -347,5 +349,5 @@ func HandleAttachmentFileDownload(response http.ResponseWriter, request *http.Re } response.WriteHeader(http.StatusOK) - response.Write(json) + response.Write(fileData) } diff --git a/packages/httpRequest/get.go b/packages/httpRequest/get.go index 0067b2b..e0fe09b 100644 --- a/packages/httpRequest/get.go +++ b/packages/httpRequest/get.go @@ -36,15 +36,15 @@ func getUserByToken(ctx context.Context, token string) (*types.User, error) { return getUserById(ctx, userId) } -func getConnectionWithResponseOnFail(response *http.ResponseWriter, request *http.Request, user *types.User) (*types.Connection, bool) { - connectionId, err := convertions.StringToUuid(request.FormValue("connectionid")) +func getConnectionWithResponseOnFail(response http.ResponseWriter, connectionIdStr string, user *types.User) (*types.Connection, bool) { + connectionId, err := convertions.StringToUuid(connectionIdStr) if err != nil { - http.Error(*response, "invalid connectionid", http.StatusBadRequest) + http.Error(response, "invalid connectionid", http.StatusBadRequest) return nil, false } conn, ok := cache.GetConnection(user, connectionId) if !ok { - http.Error(*response, "invalid connectionid", http.StatusBadRequest) + http.Error(response, "invalid connectionid", http.StatusBadRequest) return nil, false } return conn, true @@ -104,7 +104,8 @@ func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.R } if !haveHubUserCachedPermissions(types.CachedUserCanView, hubUser, channel) { - return nil, errors.New("invalid channelid") + http.Error(response, "forbidden", http.StatusForbidden) + return nil, errors.New("forbidden") } return channel, nil diff --git a/packages/httpRequest/helper.go b/packages/httpRequest/helper.go index 8a58994..93e2e5d 100644 --- a/packages/httpRequest/helper.go +++ b/packages/httpRequest/helper.go @@ -8,16 +8,16 @@ import ( "go-socket/packages/config" ) -type requestType uint8 +type bodyLimit uint8 const ( - normal requestType = iota + normal bodyLimit = iota file avatar profileBg ) -func validCheckWithResponseOnFail(response *http.ResponseWriter, request *http.Request, pt requestType) bool { +func validCheckWithResponseOnFail(response http.ResponseWriter, request *http.Request, pt bodyLimit) bool { var maxSize int64 switch pt { case file: @@ -32,7 +32,7 @@ func validCheckWithResponseOnFail(response *http.ResponseWriter, request *http.R if request.ContentLength > maxSize { io.Copy(io.Discard, request.Body) - http.Error(*response, "Request too large", http.StatusRequestEntityTooLarge) + http.Error(response, "Request too large", http.StatusRequestEntityTooLarge) return false } diff --git a/packages/httpRequest/hubs.go b/packages/httpRequest/hubs.go index fe4c98b..91897b4 100644 --- a/packages/httpRequest/hubs.go +++ b/packages/httpRequest/hubs.go @@ -1,7 +1,9 @@ package httpRequest import ( + "context" "encoding/json" + "go-socket/packages/convertions" "maps" "net/http" "slices" @@ -43,7 +45,7 @@ func haveHubUserCachedPermissions(needed types.CachedUserPermissions, user *type } func HandleHubCreate(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -62,7 +64,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) { hub := types.NewHub() hub.Name = hubName - hub.Color = types.Rgba{}.GetRandom() + hub.Color = types.RandomRgba() hub.Id = uuid.New() hub.Creator = user.Id hub.CreatedAt = time.Now() @@ -77,7 +79,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) { Id: uint8(0), Permissions: types.PermissionAll(), Name: "root", - Color: types.Rgba{}.GetRandom(), + Color: types.RandomRgba(), CreatedAt: hub.CreatedAt, } hub.Roles[rootRole.Id] = rootRole @@ -86,7 +88,7 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) { memberRole := &types.HubRole{ Id: types.HubBoundRolesMax, Name: "member", - Color: types.Rgba{}.GetRandom(), + Color: types.RandomRgba(), CreatedAt: hub.CreatedAt, } hub.JoinRole = memberRole @@ -112,13 +114,13 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) { } func HandleHubJoin(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() user, err := getUserByToken(ctx, request.Header.Get("token")) if err != nil { - http.Error(response, "invalid token", http.StatusBadRequest) + http.Error(response, "invalid token", http.StatusUnauthorized) return } hub, err := getHubByIdStr(ctx, request.Header.Get("hubid")) @@ -135,7 +137,7 @@ func HandleHubJoin(response http.ResponseWriter, request *http.Request) { } func HandleHubMessage(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -150,6 +152,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) { if hubUser.IsMuted { http.Error(response, "muted", http.StatusForbidden) + return } msgContent := request.FormValue("msgContent") @@ -192,7 +195,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) { } func HandleGetHubs(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -208,6 +211,7 @@ func HandleGetHubs(response http.ResponseWriter, request *http.Request) { if len(hubs) == 0 { response.WriteHeader(http.StatusNoContent) response.Write([]byte("no hubs found")) + return } converted, err := json.Marshal(hubs) if err != nil { @@ -218,38 +222,101 @@ func HandleGetHubs(response http.ResponseWriter, request *http.Request) { response.Write(converted) } -func HandleHubPermissionActionCore( - response http.ResponseWriter, request *http.Request, - takenVarName string, rt requestType, needed types.Permissions, - performedAction func(usr *types.HubUser, hub *types.Hub, takenVar *string)) { - if !validCheckWithResponseOnFail(&response, request, rt) { - return +func hubPermissionContext(response http.ResponseWriter, request *http.Request, rt bodyLimit, needed types.Permissions) (*types.HubUser, *types.Hub, context.Context, bool) { + if !validCheckWithResponseOnFail(response, request, rt) { + return nil, nil, nil, false } ctx := request.Context() _, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request) if err != nil { - return + return nil, nil, nil, false } - if !haveHubUserPermission(hubUser, hub, needed) { http.Error(response, "", http.StatusForbidden) + return nil, nil, nil, false } - - var takenVar *string = nil - - if takenVarName != "" { - takenVar = new(request.FormValue(takenVarName)) - } - performedAction(hubUser, hub, takenVar) + return hubUser, hub, ctx, true } func HandleHubSetName(response http.ResponseWriter, request *http.Request) { - HandleHubPermissionActionCore(response, request, "newname", normal, types.PermissionSetHubName, func(usr *types.HubUser, hub *types.Hub, takenVar *string) { - newName := *takenVar - if newName == "" { - http.Error(response, "empty name", http.StatusBadRequest) - return - } - hub.Name = newName - }) + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubName) + if !ok { + return + } + newName := request.FormValue("newname") + if newName == "" { + http.Error(response, "empty name", http.StatusBadRequest) + return + } + hub.Name = newName + response.WriteHeader(http.StatusAccepted) +} + +func HandleHubSetColor(response http.ResponseWriter, request *http.Request) { + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubColor) + if !ok { + return + } + color, err := convertions.StringToRgba(request.FormValue("newname")) + if err != nil { + http.Error(response, "bad color", http.StatusBadRequest) + return + } + hub.Color = color + response.WriteHeader(http.StatusAccepted) +} + +func HandleHubRemove(response http.ResponseWriter, request *http.Request) { + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveHub) + if !ok { + return + } + cache.DeleteHub(hub) + response.WriteHeader(http.StatusAccepted) +} + +func HandleHubToggleUserColorAllowed(response http.ResponseWriter, request *http.Request) { + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetUserColorAllowed) + if !ok { + return + } + hub.UserColorAllowed = !hub.UserColorAllowed + response.WriteHeader(http.StatusAccepted) +} + +func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) { + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveUser) + if !ok { + return + } + color, err := convertions.StringToRgba(request.FormValue("newname")) + if err != nil { + http.Error(response, "bad color", http.StatusBadRequest) + return + } + hub.Color = color + response.WriteHeader(http.StatusAccepted) +} + +func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) { + _, hub, _, ok := hubPermissionContext(response, request, normal, types.PermissionRenameUser) + if !ok { + return + } + newName := request.FormValue("newname") + targetId, err := convertions.StringToUuid(request.FormValue("targetid")) + if err != nil { + http.Error(response, "bad targetid", http.StatusBadRequest) + return + } + hub.Mu.RLock() + target, ok := hub.Users[targetId] + if !ok { + http.Error(response, "no users found", http.StatusNotFound) + return + } + hub.Mu.RUnlock() + target.Name = newName + + response.WriteHeader(http.StatusAccepted) } diff --git a/packages/httpRequest/user.go b/packages/httpRequest/user.go index 18659e7..6c31f41 100644 --- a/packages/httpRequest/user.go +++ b/packages/httpRequest/user.go @@ -1,7 +1,7 @@ package httpRequest import ( - json2 "encoding/json" + "encoding/json" "maps" "net/http" "slices" @@ -22,7 +22,7 @@ import ( ) func HandleUserNewToken(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -70,18 +70,18 @@ func HandleUserNewToken(response http.ResponseWriter, request *http.Request) { return } - json, err := json2.Marshal(types.LoginReturn{Token: token, UserId: user.Id}) + data, err := json.Marshal(types.LoginResponse{Token: token, UserId: user.Id}) if err != nil { http.Error(response, "internal server error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusCreated) - response.Write(json) + response.Write(data) } func HandleUserNew(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -106,7 +106,7 @@ func HandleUserNew(response http.ResponseWriter, request *http.Request) { newUser := &types.User{ Name: username, PasswordHash: hashedPassword, - Color: types.Rgba{}.GetRandom(), + Color: types.RandomRgba(), CreatedAt: time.Now(), } @@ -114,7 +114,7 @@ func HandleUserNew(response http.ResponseWriter, request *http.Request) { err = postgresql.UserSave(ctx, newUser) if err != nil { - http.Error(response, "name taken", http.StatusUnauthorized) + http.Error(response, "name taken", http.StatusConflict) return } @@ -122,7 +122,7 @@ func HandleUserNew(response http.ResponseWriter, request *http.Request) { } func HandleUserDelete(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -144,7 +144,7 @@ func HandleUserDelete(response http.ResponseWriter, request *http.Request) { } func HandleUserModProfile(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } @@ -221,7 +221,7 @@ func HandleUserModProfile(response http.ResponseWriter, request *http.Request) { } func HandleUserGetUser(response http.ResponseWriter, request *http.Request) { - if !validCheckWithResponseOnFail(&response, request, normal) { + if !validCheckWithResponseOnFail(response, request, normal) { return } ctx := request.Context() @@ -234,21 +234,21 @@ func HandleUserGetUser(response http.ResponseWriter, request *http.Request) { targetId, err := convertions.StringToUuid(request.URL.Query().Get("targetid")) if err != nil { - http.Error(response, "invalid userid", http.StatusUnauthorized) + http.Error(response, "invalid userid", http.StatusBadRequest) return } target, err := getUserById(ctx, targetId) if err != nil { - http.Error(response, "invalid userid", http.StatusUnauthorized) + http.Error(response, "user not found", http.StatusNotFound) return } - json, err := json2.Marshal(target) + userData, err := json.Marshal(target) if err != nil { http.Error(response, "json parse error", http.StatusInternalServerError) return } response.WriteHeader(http.StatusAccepted) - response.Write(json) + response.Write(userData) } diff --git a/packages/postgresql/postgresql.go b/packages/postgresql/postgresql.go index 7620345..c01b3e8 100644 --- a/packages/postgresql/postgresql.go +++ b/packages/postgresql/postgresql.go @@ -95,7 +95,7 @@ func UserGetStandardInfoByName(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT id, name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE name = $1 - `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarType, &user.ProfileBgType) + `, user.Name).Scan(&user.Id, &user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarKey, &user.ProfileBgKey) if err == nil { user.Color = convertions.Uint32ToRgba(uint32(rgba)) } @@ -106,7 +106,7 @@ func UserGetById(ctx context.Context, user *types.User) error { var rgba int64 err := dbConn.QueryRow(ctx, ` SELECT name, pass_hash, COALESCE(pronouns, ''), rgba, created_at, COALESCE(avatar, ''), COALESCE(profile_bg, '') FROM users WHERE id = $1 - `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarType, &user.ProfileBgType) + `, user.Id).Scan(&user.Name, &user.PasswordHash, &user.Pronouns, &rgba, &user.CreatedAt, &user.AvatarKey, &user.ProfileBgKey) if err == nil { user.Color = convertions.Uint32ToRgba(uint32(rgba)) } @@ -135,12 +135,12 @@ func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types. } if updateList.Avatar { setClauses = append(setClauses, fmt.Sprintf("avatar = $%d", argIdx)) - args = append(args, user.AvatarType) + args = append(args, user.AvatarKey) argIdx++ } if updateList.ProfileBg { setClauses = append(setClauses, fmt.Sprintf("profile_bg = $%d", argIdx)) - args = append(args, user.ProfileBgType) + args = append(args, user.ProfileBgKey) argIdx++ } diff --git a/packages/types/types.go b/packages/types/types.go index 01aa70c..a5b45fe 100644 --- a/packages/types/types.go +++ b/packages/types/types.go @@ -18,7 +18,8 @@ import ( type Rgba [4]uint8 type Sha256Hash [sha256.Size]byte -func (r Rgba) GetRandom() Rgba { +func RandomRgba() Rgba { + var r Rgba for i := range r { r[i] = uint8(rand.IntN(256)) } @@ -26,19 +27,19 @@ func (r Rgba) GetRandom() Rgba { } type User struct { - Mu sync.RWMutex `json:"-"` - Name string `json:"name"` - Pronouns string `json:"pronouns"` - Description string `json:"description"` - AvatarType string `json:"avatarType"` - ProfileBgType string `json:"profileBackgroundType"` - PasswordHash string `json:"-"` - CreatedAt time.Time `json:"createdAt"` - WsConn *websocket.Conn `json:"-"` - Id uuid.UUID `json:"-"` - Connections map[uuid.UUID]*Connection `json:"-"` - Hubs map[uuid.UUID]*Hub `json:"-"` - Color Rgba `json:"color"` + Mu sync.RWMutex `json:"-"` + Name string `json:"name"` + Pronouns string `json:"pronouns"` + Description string `json:"description"` + AvatarKey string `json:"avatarType"` + ProfileBgKey string `json:"profileBackgroundType"` + PasswordHash string `json:"-"` + CreatedAt time.Time `json:"createdAt"` + WsConn *websocket.Conn `json:"-"` + Id uuid.UUID `json:"-"` + Connections map[uuid.UUID]*Connection `json:"-"` + Hubs map[uuid.UUID]*Hub `json:"-"` + Color Rgba `json:"color"` } type UserProfileUpdateList struct { @@ -122,7 +123,7 @@ type Message struct { Receiver uuid.UUID `json:"receiver"` } -type LoginReturn struct { +type LoginResponse struct { Token string `json:"token"` UserId uuid.UUID `json:"userId"` } @@ -149,14 +150,16 @@ const ( PermissionSetUserColorAllowed // User permissions - PermissionAddUser + PermissionInviteUser PermissionRemoveUser PermissionRenameUser PermissionSelfRename PermissionMuteUser + PermissionUserAddRole + PermissionUserRemoveRole // Role permissions - PermissionAddRole + PermissionCreateRole PermissionRemoveRole PermissionSetRoleName PermissionSetRoleColor