add hub function

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