add join role endpoint and persistency for hubs

This commit is contained in:
2026-05-06 19:08:18 +02:00
parent 03c13a6e8a
commit f68a249268
12 changed files with 991 additions and 206 deletions
BIN
View File
Binary file not shown.
+3
View File
@@ -72,6 +72,7 @@ func main() {
http.HandleFunc("PATCH /hub/icon", withCORS(httpRequest.HandleHubSetIcon)) http.HandleFunc("PATCH /hub/icon", withCORS(httpRequest.HandleHubSetIcon))
http.HandleFunc("GET /hub/icon", withCORS(httpRequest.HandleGetHubIcon)) http.HandleFunc("GET /hub/icon", withCORS(httpRequest.HandleGetHubIcon))
http.HandleFunc("PATCH /hub/bg", withCORS(httpRequest.HandleHubSetBg)) http.HandleFunc("PATCH /hub/bg", withCORS(httpRequest.HandleHubSetBg))
http.HandleFunc("PATCH /hub/joinrole", withCORS(httpRequest.HandleSetHubJoinRole))
http.HandleFunc("GET /hub/bg", withCORS(httpRequest.HandleGetHubBg)) http.HandleFunc("GET /hub/bg", withCORS(httpRequest.HandleGetHubBg))
http.HandleFunc("DELETE /hub", withCORS(httpRequest.HandleHubRemove)) http.HandleFunc("DELETE /hub", withCORS(httpRequest.HandleHubRemove))
http.HandleFunc("PATCH /hub/usercolorallowed", withCORS(httpRequest.HandleHubToggleUserColorAllowed)) http.HandleFunc("PATCH /hub/usercolorallowed", withCORS(httpRequest.HandleHubToggleUserColorAllowed))
@@ -94,6 +95,8 @@ func main() {
http.HandleFunc("PATCH /hub/channel/roles/view", withCORS(httpRequest.HandleChannelSetPermittedVisibleRole)) http.HandleFunc("PATCH /hub/channel/roles/view", withCORS(httpRequest.HandleChannelSetPermittedVisibleRole))
http.HandleFunc("PATCH /hub/channel/roles/send", withCORS(httpRequest.HandleChannelSetPermittedSendRole)) http.HandleFunc("PATCH /hub/channel/roles/send", withCORS(httpRequest.HandleChannelSetPermittedSendRole))
http.HandleFunc("PATCH /hub/channel/roles/history", withCORS(httpRequest.HandleChannelSetPermittedHistoryRole)) http.HandleFunc("PATCH /hub/channel/roles/history", withCORS(httpRequest.HandleChannelSetPermittedHistoryRole))
http.HandleFunc("PATCH /hub/channel/icon", withCORS(httpRequest.HandleChannelSetIcon))
http.HandleFunc("GET /hub/channel/icon", withCORS(httpRequest.HandleGetChannelIcon))
http.HandleFunc("POST /connection/message", withCORS(httpRequest.HandleDm)) http.HandleFunc("POST /connection/message", withCORS(httpRequest.HandleDm))
http.HandleFunc("GET /ws", wsServer.ServeWsConnection) http.HandleFunc("GET /ws", wsServer.ServeWsConnection)
+263 -2
View File
@@ -127,7 +127,7 @@ func HandleSetUserAvatar(response http.ResponseWriter, request *http.Request) {
} }
} }
user.AvatarKey = key user.AvatarKey = key
err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{Avatar: true}) err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdate{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.AvatarKey) minio.Delete(ctx, user.AvatarKey)
@@ -249,7 +249,7 @@ func HandleSetUserProfileBg(response http.ResponseWriter, request *http.Request)
} }
} }
user.ProfileBgKey = key user.ProfileBgKey = key
err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdateList{ProfileBg: true}) err = postgresql.UserUpdateProfile(ctx, user, &types.UserProfileUpdate{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.ProfileBgKey) minio.Delete(ctx, user.ProfileBgKey)
@@ -324,6 +324,267 @@ func HandleGetUserProfileBg(response http.ResponseWriter, request *http.Request)
response.Write(profileBgData) response.Write(profileBgData)
} }
func HandleHubSetIcon(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, hubIcon, types.PermissionSetHubIcon)
if !ok {
return
}
file, header, err := request.FormFile("file")
if err != nil {
http.Error(response, "missing file", http.StatusBadRequest)
return
}
defer file.Close()
isImg, contentType, err := isImage(file)
if err != nil || !isImg {
http.Error(response, "invalid file", http.StatusBadRequest)
return
}
key := minio.GetKey(&minio.GetKeyOptions{
MimeType: contentType,
UploadType: minio.HubIcon,
HubId: hub.Id,
})
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
"originalName": header.Filename,
}); err != nil {
http.Error(response, "upload failed", http.StatusInternalServerError)
return
}
if hub.IconUrl != "" {
if err = minio.Delete(ctx, hub.IconUrl); err != nil {
minio.Delete(ctx, key)
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
}
hub.IconUrl = key
response.WriteHeader(http.StatusCreated)
}
func HandleHubSetBg(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, hubBackground, types.PermissionSetHubBg)
if !ok {
return
}
file, header, err := request.FormFile("file")
if err != nil {
http.Error(response, "missing file", http.StatusBadRequest)
return
}
defer file.Close()
isImg, contentType, err := isImage(file)
if err != nil || !isImg {
http.Error(response, "invalid file", http.StatusBadRequest)
return
}
key := minio.GetKey(&minio.GetKeyOptions{
MimeType: contentType,
UploadType: minio.HubBackground,
HubId: hub.Id,
})
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
"originalName": header.Filename,
}); err != nil {
http.Error(response, "upload failed", http.StatusInternalServerError)
return
}
if hub.BgUrl != "" {
if err = minio.Delete(ctx, hub.BgUrl); err != nil {
minio.Delete(ctx, key)
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
}
hub.BgUrl = key
response.WriteHeader(http.StatusCreated)
}
func HandleGetHubIcon(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(response, request, normal) {
return
}
ctx := request.Context()
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
if err != nil {
return
}
if hub.IconUrl == "" {
http.Error(response, "hub has no icon", http.StatusNoContent)
return
}
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, hub.IconUrl)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
iconData, 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(iconData)
}
func HandleGetHubBg(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(response, request, normal) {
return
}
ctx := request.Context()
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
if err != nil {
return
}
if hub.BgUrl == "" {
http.Error(response, "hub has no background", http.StatusNoContent)
return
}
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, hub.BgUrl)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
bgData, 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(bgData)
}
func HandleChannelSetIcon(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, channelIcon, types.PermissionSetChannelIcon)
if !ok {
return
}
channelId, err := convertions.StringToUuid(request.FormValue("channel_id"))
if err != nil {
http.Error(response, "invalid channel_id", http.StatusBadRequest)
return
}
hub.Mu.RLock()
channel, ok := hub.Channels[channelId]
hub.Mu.RUnlock()
if !ok {
http.Error(response, "channel not found", http.StatusNotFound)
return
}
file, header, err := request.FormFile("file")
if err != nil {
http.Error(response, "missing file", http.StatusBadRequest)
return
}
defer file.Close()
isImg, contentType, err := isImage(file)
if err != nil || !isImg {
http.Error(response, "invalid file", http.StatusBadRequest)
return
}
key := minio.GetKey(&minio.GetKeyOptions{
MimeType: contentType,
UploadType: minio.ChannelIcon,
ChannelId: channel.Id,
})
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
"originalName": header.Filename,
}); err != nil {
http.Error(response, "upload failed", http.StatusInternalServerError)
return
}
if channel.IconUrl != "" {
if err = minio.Delete(ctx, channel.IconUrl); err != nil {
minio.Delete(ctx, key)
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
}
channel.IconUrl = key
response.WriteHeader(http.StatusCreated)
}
func HandleGetChannelIcon(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(response, request, normal) {
return
}
ctx := request.Context()
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
if err != nil {
return
}
channelId, err := convertions.StringToUuid(request.URL.Query().Get("channel_id"))
if err != nil {
http.Error(response, "invalid channel_id", http.StatusBadRequest)
return
}
hub.Mu.RLock()
channel, ok := hub.Channels[channelId]
hub.Mu.RUnlock()
if !ok {
http.Error(response, "channel not found", http.StatusNotFound)
return
}
if !haveHubUserCachedPermissions(types.CachedUserCanView, hubUser, channel) {
http.Error(response, "forbidden", http.StatusForbidden)
return
}
if channel.IconUrl == "" {
http.Error(response, "channel has no icon", http.StatusNoContent)
return
}
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, channel.IconUrl)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
iconData, 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(iconData)
}
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
+6 -3
View File
@@ -19,7 +19,7 @@ func getUserById(ctx context.Context, userId uuid.UUID) (*types.User, error) {
user, err := cache.GetUserById(userId) user, err := cache.GetUserById(userId)
if err != nil { if err != nil {
user = &types.User{Id: userId, Hubs: make(map[uuid.UUID]*types.Hub)} user = &types.User{Id: userId, Hubs: make(map[uuid.UUID]*types.Hub)}
err = postgresql.GetWholeUser(ctx, user) err = postgresql.UserGetWhole(ctx, user)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -96,9 +96,12 @@ func getHubByIdStr(ctx context.Context, hubId string) (*types.Hub, error) {
} }
hub, ok := cache.GetHubById(hubUuid) hub, ok := cache.GetHubById(hubUuid)
if !ok { if !ok {
return nil, errors.New("hub not found") hub = &types.Hub{Id: hubUuid}
err = postgresql.HubGetWhole(ctx, hub)
if err != nil {
return nil, err
}
} }
return hub, nil return hub, nil
+4
View File
@@ -17,6 +17,7 @@ const (
profileBg profileBg
hubIcon hubIcon
hubBackground hubBackground
channelIcon
) )
func validCheckWithResponseOnFail(response http.ResponseWriter, request *http.Request, pt bodyLimit) bool { func validCheckWithResponseOnFail(response http.ResponseWriter, request *http.Request, pt bodyLimit) bool {
@@ -37,6 +38,9 @@ func validCheckWithResponseOnFail(response http.ResponseWriter, request *http.Re
case hubBackground: case hubBackground:
maxSize = int64(config.MaxRequestWithHubBackgroundBytes) maxSize = int64(config.MaxRequestWithHubBackgroundBytes)
break break
case channelIcon:
maxSize = int64(config.MaxRequestWithHubIconBytes)
break
default: default:
maxSize = int64(config.MaxRequestBytes) maxSize = int64(config.MaxRequestBytes)
} }
+166 -180
View File
@@ -8,6 +8,7 @@ import (
"time" "time"
"go-socket/packages/convertions" "go-socket/packages/convertions"
"go-socket/packages/postgresql"
"go-socket/packages/cache" "go-socket/packages/cache"
"go-socket/packages/minio" "go-socket/packages/minio"
@@ -187,6 +188,31 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
hub.Channels[channel.Id] = channel hub.Channels[channel.Id] = channel
cache.SaveHub(hub) cache.SaveHub(hub)
err = postgresql.HubSave(ctx, hub)
if err != nil {
http.Error(response, "failed to save hub", http.StatusInternalServerError)
return
}
err = postgresql.HubUserSave(ctx, hub.Id, creator)
if err != nil {
http.Error(response, "failed to save hub user", http.StatusInternalServerError)
return
}
err = postgresql.HubRoleSave(ctx, hub.Id, rootRole)
if err != nil {
http.Error(response, "failed to save hub role", http.StatusInternalServerError)
return
}
err = postgresql.HubRoleSave(ctx, hub.Id, memberRole)
if err != nil {
http.Error(response, "failed to save hub role", http.StatusInternalServerError)
return
}
err = postgresql.HubChannelSave(ctx, hub.Id, channel)
if err != nil {
http.Error(response, "failed to save hub channel", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusCreated) response.WriteHeader(http.StatusCreated)
response.Write([]byte(hub.Id.String())) response.Write([]byte(hub.Id.String()))
@@ -224,6 +250,10 @@ func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
hub.Users[hubUser.OriginalId] = hubUser hub.Users[hubUser.OriginalId] = hubUser
updateChannelCacheForSpecUser(hubUser, hub) updateChannelCacheForSpecUser(hubUser, hub)
if err = postgresql.HubUserSave(ctx, hub.Id, hubUser); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusCreated) response.WriteHeader(http.StatusCreated)
} }
@@ -254,7 +284,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
return return
} }
if attachedFile != "" && !strings.HasPrefix(attachedFile, channel.Id.String()+"/") { if attachedFile != "" && !strings.HasPrefix(attachedFile, string(minio.HubChannelFilePrefix)+channel.Id.String()+"/") {
http.Error(response, "invalid attachedFile", http.StatusBadRequest) http.Error(response, "invalid attachedFile", http.StatusBadRequest)
return return
} }
@@ -440,7 +470,7 @@ func hubPermissionContext(response http.ResponseWriter, request *http.Request, r
} }
func HandleHubSetName(response http.ResponseWriter, request *http.Request) { func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubName) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubName)
if !ok { if !ok {
return return
} }
@@ -450,11 +480,15 @@ func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
return return
} }
hub.Name = newName hub.Name = newName
if err := postgresql.HubUpdate(ctx, hub, &types.HubUpdate{Name: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubSetColor(response http.ResponseWriter, request *http.Request) { func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubColor) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubColor)
if !ok { if !ok {
return return
} }
@@ -464,181 +498,64 @@ func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
return return
} }
hub.Color = color hub.Color = color
if err = postgresql.HubUpdate(ctx, hub, &types.HubUpdate{Color: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubSetIcon(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, hubIcon, types.PermissionSetHubIcon)
if !ok {
return
}
file, header, err := request.FormFile("file")
if err != nil {
http.Error(response, "missing file", http.StatusBadRequest)
return
}
defer file.Close()
isImg, contentType, err := isImage(file)
if err != nil || !isImg {
http.Error(response, "invalid file", http.StatusBadRequest)
return
}
key := minio.GetKey(&minio.GetKeyOptions{
MimeType: contentType,
UploadType: minio.HubIcon,
HubId: hub.Id,
})
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
"originalName": header.Filename,
}); err != nil {
http.Error(response, "upload failed", http.StatusInternalServerError)
return
}
if hub.IconUrl != "" {
if err = minio.Delete(ctx, hub.IconUrl); err != nil {
minio.Delete(ctx, key)
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
}
hub.IconUrl = key
response.WriteHeader(http.StatusCreated)
}
func HandleHubSetBg(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, hubBackground, types.PermissionSetHubBg)
if !ok {
return
}
file, header, err := request.FormFile("file")
if err != nil {
http.Error(response, "missing file", http.StatusBadRequest)
return
}
defer file.Close()
isImg, contentType, err := isImage(file)
if err != nil || !isImg {
http.Error(response, "invalid file", http.StatusBadRequest)
return
}
key := minio.GetKey(&minio.GetKeyOptions{
MimeType: contentType,
UploadType: minio.HubBackground,
HubId: hub.Id,
})
if err = minio.Upload(ctx, key, file, header.Size, contentType, map[string]string{
"originalName": header.Filename,
}); err != nil {
http.Error(response, "upload failed", http.StatusInternalServerError)
return
}
if hub.BgUrl != "" {
if err = minio.Delete(ctx, hub.BgUrl); err != nil {
minio.Delete(ctx, key)
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
}
hub.BgUrl = key
response.WriteHeader(http.StatusCreated)
}
func HandleGetHubIcon(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(response, request, normal) {
return
}
ctx := request.Context()
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
if err != nil {
return
}
if hub.IconUrl == "" {
http.Error(response, "hub has no icon", http.StatusNoContent)
return
}
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, hub.IconUrl)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
iconData, 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(iconData)
}
func HandleGetHubBg(response http.ResponseWriter, request *http.Request) {
if !validCheckWithResponseOnFail(response, request, normal) {
return
}
ctx := request.Context()
_, _, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
if err != nil {
return
}
if hub.BgUrl == "" {
http.Error(response, "hub has no background", http.StatusNoContent)
return
}
url, meta, err := minio.GetDownloadUrlAndMetadata(ctx, hub.BgUrl)
if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError)
return
}
bgData, 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(bgData)
}
func HandleHubRemove(response http.ResponseWriter, request *http.Request) { func HandleHubRemove(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveHub) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveHub)
if !ok { if !ok {
return return
} }
if err := postgresql.HubDelete(ctx, hub.Id); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
cache.DeleteHub(hub) cache.DeleteHub(hub)
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubToggleUserColorAllowed(response http.ResponseWriter, request *http.Request) { func HandleHubToggleUserColorAllowed(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetUserColorAllowed) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetUserColorAllowed)
if !ok { if !ok {
return return
} }
hub.UserColorAllowed = !hub.UserColorAllowed hub.UserColorAllowed = !hub.UserColorAllowed
if err := postgresql.HubUpdate(ctx, hub, &types.HubUpdate{UserColorAllowed: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted)
}
func HandleSetHubJoinRole(response http.ResponseWriter, request *http.Request) {
_, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetHubJoinRole)
if !ok {
return
}
newRoleId, err := convertions.StringToUint8(request.FormValue("new_role_id"))
if err != nil {
http.Error(response, "bad role_id", http.StatusBadRequest)
return
}
newRole := hub.Roles[newRoleId]
if newRole == nil {
http.Error(response, "bad role_id", http.StatusNotFound)
return
}
hub.JoinRole = newRole
if err = postgresql.HubUpdate(ctx, hub, &types.HubUpdate{JoinRole: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) { func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveUser) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveUser)
if !ok { if !ok {
return return
} }
@@ -669,6 +586,10 @@ func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
delete(target.Hubs, hub.Id) delete(target.Hubs, hub.Id)
target.Mu.Unlock() target.Mu.Unlock()
if err = postgresql.HubUserDelete(ctx, hub.Id, targetId); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
hub.Mu.Lock() hub.Mu.Lock()
delete(hub.Users, targetId) delete(hub.Users, targetId)
hub.Mu.Unlock() hub.Mu.Unlock()
@@ -677,7 +598,7 @@ func HandleHubUserRemove(response http.ResponseWriter, request *http.Request) {
} }
func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) { func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRenameUser) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRenameUser)
if !ok { if !ok {
return return
} }
@@ -700,20 +621,28 @@ func HandleHubRenameUser(response http.ResponseWriter, request *http.Request) {
return return
} }
target.Name = newName target.Name = newName
if err = postgresql.HubUserUpdate(ctx, hub.Id, target, &types.HubUserUpdate{Name: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubRenameSelf(response http.ResponseWriter, request *http.Request) { func HandleHubRenameSelf(response http.ResponseWriter, request *http.Request) {
requestor, _, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSelfRename) requestor, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSelfRename)
if !ok { if !ok {
return return
} }
requestor.Name = request.FormValue("new_name") requestor.Name = request.FormValue("new_name")
if err := postgresql.HubUserUpdate(ctx, hub.Id, requestor, &types.HubUserUpdate{Name: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request) { func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionMuteUser) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionMuteUser)
if !ok { if !ok {
return return
} }
@@ -735,11 +664,15 @@ func HandleHubToggleMuteUser(response http.ResponseWriter, request *http.Request
return return
} }
target.IsMuted = !target.IsMuted target.IsMuted = !target.IsMuted
if err = postgresql.HubUserUpdate(ctx, hub.Id, target, &types.HubUserUpdate{IsMuted: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) { func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserAddRole) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserAddRole)
if !ok { if !ok {
return return
} }
@@ -772,11 +705,15 @@ func HandleHubUserAddRole(response http.ResponseWriter, request *http.Request) {
} }
target.Roles.Add(roleId) target.Roles.Add(roleId)
updateChannelCacheForSpecUser(target, hub) updateChannelCacheForSpecUser(target, hub)
if err = postgresql.HubUserUpdate(ctx, hub.Id, target, &types.HubUserUpdate{Roles: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request) { func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserRemoveRole) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserRemoveRole)
if !ok { if !ok {
return return
} }
@@ -804,11 +741,15 @@ func HandleHubUserRemoveRole(response http.ResponseWriter, request *http.Request
} }
target.Roles.Remove(roleId) target.Roles.Remove(roleId)
updateChannelCacheForSpecUser(target, hub) updateChannelCacheForSpecUser(target, hub)
if err = postgresql.HubUserUpdate(ctx, hub.Id, target, &types.HubUserUpdate{Roles: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) { func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionCreateRole) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionCreateRole)
if !ok { if !ok {
return return
} }
@@ -832,18 +773,23 @@ func HandleHubCreateRole(response http.ResponseWriter, request *http.Request) {
http.Error(response, "no role slots available", http.StatusConflict) http.Error(response, "no role slots available", http.StatusConflict)
return return
} }
hub.Roles[freeId] = &types.HubRole{ newRole := &types.HubRole{
Id: freeId, Id: freeId,
Name: name, Name: name,
Color: types.RandomRgba(), Color: types.RandomRgba(),
CreatedAt: time.Now(), CreatedAt: time.Now(),
} }
hub.Roles[freeId] = newRole
hub.Mu.Unlock() hub.Mu.Unlock()
if err := postgresql.HubRoleSave(ctx, hub.Id, newRole); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusCreated) response.WriteHeader(http.StatusCreated)
} }
func HandleHubRemoveRole(response http.ResponseWriter, request *http.Request) { func HandleHubRemoveRole(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveRole) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveRole)
if !ok { if !ok {
return return
} }
@@ -869,11 +815,15 @@ func HandleHubRemoveRole(response http.ResponseWriter, request *http.Request) {
} }
hub.Roles[targetRoleId] = nil hub.Roles[targetRoleId] = nil
hub.Mu.Unlock() hub.Mu.Unlock()
if err := postgresql.HubRoleDelete(ctx, hub.Id, targetRoleId); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleRoleSetName(response http.ResponseWriter, request *http.Request) { func HandleRoleSetName(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleName) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleName)
if !ok { if !ok {
return return
} }
@@ -901,11 +851,15 @@ func HandleRoleSetName(response http.ResponseWriter, request *http.Request) {
} }
role.Name = newName role.Name = newName
hub.Mu.Unlock() hub.Mu.Unlock()
if err = postgresql.HubRoleUpdate(ctx, hub.Id, role, &types.HubRoleUpdate{Name: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleRoleSetColor(response http.ResponseWriter, request *http.Request) { func HandleRoleSetColor(response http.ResponseWriter, request *http.Request) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleColor) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRoleColor)
if !ok { if !ok {
return return
} }
@@ -933,11 +887,15 @@ func HandleRoleSetColor(response http.ResponseWriter, request *http.Request) {
} }
role.Color = color role.Color = color
hub.Mu.Unlock() hub.Mu.Unlock()
if err = postgresql.HubRoleUpdate(ctx, hub.Id, role, &types.HubRoleUpdate{Color: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleRoleSetPermissions(response http.ResponseWriter, request *http.Request) { func HandleRoleSetPermissions(response http.ResponseWriter, request *http.Request) {
requestor, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRolePermissions) requestor, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionSetRolePermissions)
if !ok { if !ok {
return return
} }
@@ -994,21 +952,29 @@ func HandleRoleSetPermissions(response http.ResponseWriter, request *http.Reques
} }
updateChannelCacheForSpecRole(targetRole, hub) updateChannelCacheForSpecRole(targetRole, hub)
if err := postgresql.HubRoleUpdate(ctx, hub.Id, targetRole, &types.HubRoleUpdate{Permissions: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleRoleSelfRemove(response http.ResponseWriter, request *http.Request) { func HandleRoleSelfRemove(response http.ResponseWriter, request *http.Request) {
requestor, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserSelfRoleRemove) requestor, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionUserSelfRoleRemove)
if !ok { if !ok {
return return
} }
requestor.Roles.Remove(usedRoleId) requestor.Roles.Remove(usedRoleId)
updateChannelCacheForSpecUser(requestor, hub) updateChannelCacheForSpecUser(requestor, hub)
if err := postgresql.HubUserUpdate(ctx, hub.Id, requestor, &types.HubUserUpdate{Roles: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleChannelCreate(response http.ResponseWriter, request *http.Request) { func HandleChannelCreate(response http.ResponseWriter, request *http.Request) {
requestor, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionCreateChannel) requestor, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, types.PermissionCreateChannel)
if !ok { if !ok {
return return
} }
@@ -1046,11 +1012,15 @@ func HandleChannelCreate(response http.ResponseWriter, request *http.Request) {
hub.Mu.Unlock() hub.Mu.Unlock()
updateChannelCacheForSpecChannel(newHubChannel, hub) updateChannelCacheForSpecChannel(newHubChannel, hub)
if err := postgresql.HubChannelSave(ctx, hub.Id, newHubChannel); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleChannelRemove(response http.ResponseWriter, request *http.Request) { func HandleChannelRemove(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveChannel) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionRemoveChannel)
if !ok { if !ok {
return return
} }
@@ -1061,17 +1031,21 @@ func HandleChannelRemove(response http.ResponseWriter, request *http.Request) {
} }
hub.Mu.Lock() hub.Mu.Lock()
if _, ok := hub.Channels[channelId]; !ok { if _, ok = hub.Channels[channelId]; !ok {
hub.Mu.Unlock() hub.Mu.Unlock()
http.Error(response, "no such channel", http.StatusNotFound) http.Error(response, "no such channel", http.StatusNotFound)
return return
} }
delete(hub.Channels, channelId) delete(hub.Channels, channelId)
hub.Mu.Unlock() hub.Mu.Unlock()
if err = postgresql.HubChannelDelete(ctx, channelId); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleChannelSetName(response http.ResponseWriter, request *http.Request) { func HandleChannelSetName(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetChannelName) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetChannelName)
if !ok { if !ok {
return return
} }
@@ -1095,11 +1069,15 @@ func HandleChannelSetName(response http.ResponseWriter, request *http.Request) {
} }
channel.Name = newName channel.Name = newName
hub.Mu.Unlock() hub.Mu.Unlock()
if err = postgresql.HubChannelUpdate(ctx, channel, &types.HubChannelUpdate{Name: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleChannelSetDescription(response http.ResponseWriter, request *http.Request) { func HandleChannelSetDescription(response http.ResponseWriter, request *http.Request) {
_, hub, _, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetChannelDescription) _, hub, ctx, _, ok := hubPermissionContext(response, request, normal, types.PermissionSetChannelDescription)
if !ok { if !ok {
return return
} }
@@ -1119,11 +1097,15 @@ func HandleChannelSetDescription(response http.ResponseWriter, request *http.Req
} }
channel.Description = newDescription channel.Description = newDescription
hub.Mu.Unlock() hub.Mu.Unlock()
if err = postgresql.HubChannelUpdate(ctx, channel, &types.HubChannelUpdate{Description: true}); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func handleChannelRolePermission(response http.ResponseWriter, request *http.Request, perm types.Permissions, modify func(*types.HubChannel, uint8, bool)) { func handleChannelRolePermission(response http.ResponseWriter, request *http.Request, perm types.Permissions, updateList *types.HubChannelUpdate, modify func(*types.HubChannel, uint8, bool)) {
_, hub, _, usedRoleId, ok := hubPermissionContext(response, request, normal, perm) _, hub, ctx, usedRoleId, ok := hubPermissionContext(response, request, normal, perm)
if !ok { if !ok {
return return
} }
@@ -1154,11 +1136,15 @@ func handleChannelRolePermission(response http.ResponseWriter, request *http.Req
hub.Mu.Unlock() hub.Mu.Unlock()
updateChannelCacheForSpecChannel(channel, hub) updateChannelCacheForSpecChannel(channel, hub)
if err = postgresql.HubChannelUpdate(ctx, channel, updateList); err != nil {
http.Error(response, "db error", http.StatusInternalServerError)
return
}
response.WriteHeader(http.StatusAccepted) response.WriteHeader(http.StatusAccepted)
} }
func HandleChannelSetPermittedVisibleRole(response http.ResponseWriter, request *http.Request) { func HandleChannelSetPermittedVisibleRole(response http.ResponseWriter, request *http.Request) {
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedVisibleRoles, func(c *types.HubChannel, roleId uint8, allow bool) { handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedVisibleRoles, &types.HubChannelUpdate{RolesCanView: true}, func(c *types.HubChannel, roleId uint8, allow bool) {
if allow { if allow {
c.RolesCanView.Add(roleId) c.RolesCanView.Add(roleId)
} else { } else {
@@ -1168,7 +1154,7 @@ func HandleChannelSetPermittedVisibleRole(response http.ResponseWriter, request
} }
func HandleChannelSetPermittedSendRole(response http.ResponseWriter, request *http.Request) { func HandleChannelSetPermittedSendRole(response http.ResponseWriter, request *http.Request) {
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedSendMessageRoles, func(c *types.HubChannel, roleId uint8, allow bool) { handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedSendMessageRoles, &types.HubChannelUpdate{RolesCanMessage: true}, func(c *types.HubChannel, roleId uint8, allow bool) {
if allow { if allow {
c.RolesCanMessage.Add(roleId) c.RolesCanMessage.Add(roleId)
} else { } else {
@@ -1178,7 +1164,7 @@ func HandleChannelSetPermittedSendRole(response http.ResponseWriter, request *ht
} }
func HandleChannelSetPermittedHistoryRole(response http.ResponseWriter, request *http.Request) { func HandleChannelSetPermittedHistoryRole(response http.ResponseWriter, request *http.Request) {
handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedReadHistoryRoles, func(c *types.HubChannel, roleId uint8, allow bool) { handleChannelRolePermission(response, request, types.PermissionSetChannelPermittedReadHistoryRoles, &types.HubChannelUpdate{RolesCanReadHistory: true}, func(c *types.HubChannel, roleId uint8, allow bool) {
if allow { if allow {
c.RolesCanReadHistory.Add(roleId) c.RolesCanReadHistory.Add(roleId)
} else { } else {
+4 -2
View File
@@ -52,7 +52,7 @@ func HandleUserNewToken(response http.ResponseWriter, request *http.Request) {
http.Error(response, "bad login", http.StatusUnauthorized) http.Error(response, "bad login", http.StatusUnauthorized)
return return
} }
if err = postgresql.GetWholeUser(ctx, user); err != nil { if err = postgresql.UserGetWhole(ctx, user); err != nil {
http.Error(response, err.Error(), http.StatusInternalServerError) http.Error(response, err.Error(), http.StatusInternalServerError)
return return
} }
@@ -64,6 +64,8 @@ func HandleUserNewToken(response http.ResponseWriter, request *http.Request) {
return return
} }
cache.SaveUser(user)
token, err := tokens.TokenCreate(user.Id) token, err := tokens.TokenCreate(user.Id)
if err != nil { if err != nil {
http.Error(response, "internal server error", http.StatusInternalServerError) http.Error(response, "internal server error", http.StatusInternalServerError)
@@ -155,7 +157,7 @@ func HandleUserModProfile(response http.ResponseWriter, request *http.Request) {
return return
} }
updateList := &types.UserProfileUpdateList{} updateList := &types.UserProfileUpdate{}
updatedValues := map[string]any{} updatedValues := map[string]any{}
if pronouns := request.FormValue("pronouns"); pronouns != "" { if pronouns := request.FormValue("pronouns"); pronouns != "" {
+2
View File
@@ -69,6 +69,8 @@ func GetKey(opts *GetKeyOptions) string {
return string(HubIconPrefix) + opts.HubId.String() + key return string(HubIconPrefix) + opts.HubId.String() + key
case HubBackground: case HubBackground:
return string(HubBackgroundPrefix) + opts.HubId.String() + key return string(HubBackgroundPrefix) + opts.HubId.String() + key
case ChannelIcon:
return string(ChannelIconPrefix) + opts.ChannelId.String() + key
default: default:
return string(ConnectionFilePrefix) + opts.ConnectionId.String() + key return string(ConnectionFilePrefix) + opts.ConnectionId.String() + key
} }
+464 -13
View File
@@ -6,7 +6,6 @@ import (
"strings" "strings"
"time" "time"
"go-socket/packages/cache"
"go-socket/packages/convertions" "go-socket/packages/convertions"
"go-socket/packages/types" "go-socket/packages/types"
@@ -79,10 +78,10 @@ func Init(ctx context.Context) {
icon_url TEXT, icon_url TEXT,
background_url TEXT, background_url TEXT,
creator UUID NOT NULL REFERENCES users(id), creator UUID NOT NULL REFERENCES users(id),
join_role, // TODO set role uuid join_role SMALLINT,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295), rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295),
user_color_allowed BOOLEAN DEAFAULT FALSE, user_color_allowed BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW()
) )
`) `)
if err != nil { if err != nil {
@@ -91,12 +90,13 @@ func Init(ctx context.Context) {
_, err = dbConn.Exec(ctx, ` _, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_roles ( CREATE TABLE IF NOT EXISTS hub_roles (
id TINYINT PRIMARY KEY, id SMALLINT NOT NULL,
parent_id UUID NOT NULL REFERACES hubs(id) ON DELETE CASCADE hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL, name TEXT NOT NULL,
permissions INT NOT NULL DEFAULT 0, permissions BIGINT NOT NULL DEFAULT 0,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295), rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295),
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (id, hub_id)
) )
`) `)
if err != nil { if err != nil {
@@ -105,11 +105,53 @@ func Init(ctx context.Context) {
_, err = dbConn.Exec(ctx, ` _, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_channel ( CREATE TABLE IF NOT EXISTS hub_channel (
id TINYINT PRIMARY KEY, id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL, name TEXT NOT NULL,
permissions INT NOT NULL DEFAULT 0, description TEXT,
rgba BIGINT NOT NULL DEFAULT 0 CHECK (rgba BETWEEN 0 AND 4294967295), icon_url TEXT,
position SMALLINT NOT NULL DEFAULT 0,
created_at TIMESTAMP NOT NULL DEFAULT NOW(), created_at TIMESTAMP NOT NULL DEFAULT NOW(),
roles_can_view_0 BIGINT NOT NULL DEFAULT 0,
roles_can_view_1 BIGINT NOT NULL DEFAULT 0,
roles_can_view_2 BIGINT NOT NULL DEFAULT 0,
roles_can_message_0 BIGINT NOT NULL DEFAULT 0,
roles_can_message_1 BIGINT NOT NULL DEFAULT 0,
roles_can_message_2 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_0 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_1 BIGINT NOT NULL DEFAULT 0,
roles_can_read_history_2 BIGINT NOT NULL DEFAULT 0
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_users (
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
hub_id UUID NOT NULL REFERENCES hubs(id) ON DELETE CASCADE,
name TEXT NOT NULL DEFAULT '',
roles_0 BIGINT NOT NULL DEFAULT 0,
roles_1 BIGINT NOT NULL DEFAULT 0,
roles_2 BIGINT NOT NULL DEFAULT 0,
is_muted BOOLEAN NOT NULL DEFAULT FALSE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
PRIMARY KEY (user_id, hub_id)
)
`)
if err != nil {
panic(err)
}
_, err = dbConn.Exec(ctx, `
CREATE TABLE IF NOT EXISTS hub_channel_messages (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
sender_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
receiver_id UUID NOT NULL REFERENCES hub_channel(id) ON DELETE CASCADE,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
content TEXT NOT NULL,
attached_file TEXT NOT NULL DEFAULT ''
) )
`) `)
if err != nil { if err != nil {
@@ -156,7 +198,7 @@ func UserGetById(ctx context.Context, user *types.User) error {
return err return err
} }
func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types.UserProfileUpdateList) error { func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types.UserProfileUpdate) error {
setClauses := make([]string, 0, 3) setClauses := make([]string, 0, 3)
args := make([]any, 0, 4) args := make([]any, 0, 4)
argIdx := 1 argIdx := 1
@@ -198,15 +240,49 @@ func UserUpdateProfile(ctx context.Context, user *types.User, updateList *types.
return err return err
} }
func GetWholeUser(ctx context.Context, user *types.User) error { func UserGetBelongingHubs(ctx context.Context, user *types.User) error {
rows, err := dbConn.Query(ctx, `
SELECT h.id, h.name, COALESCE(h.icon_url, ''), COALESCE(h.background_url, ''), h.creator, h.join_role, h.rgba, h.user_color_allowed, h.created_at
FROM hubs h
INNER JOIN hub_users hu ON hu.hub_id = h.id
WHERE hu.user_id = $1
`, user.Id)
if err != nil {
return err
}
defer rows.Close()
if user.Hubs == nil {
user.Hubs = make(map[uuid.UUID]*types.Hub)
}
for rows.Next() {
hub := types.NewHub()
var joinRoleId *int16
var rgba int64
if err = rows.Scan(&hub.Id, &hub.Name, &hub.IconUrl, &hub.BgUrl, &hub.Creator, &joinRoleId, &rgba, &hub.UserColorAllowed, &hub.CreatedAt); err != nil {
return fmt.Errorf("scanning hub row: %w", err)
}
hub.Color = convertions.Uint32ToRgba(uint32(rgba))
if joinRoleId != nil {
hub.JoinRole = &types.HubRole{Id: uint8(*joinRoleId)}
}
user.Hubs[hub.Id] = hub
}
return rows.Err()
}
func UserGetWhole(ctx context.Context, user *types.User) error {
if err := UserGetById(ctx, user); err != nil { if err := UserGetById(ctx, user); err != nil {
return err return err
} }
if err := ConnectionsGetBelongingToUser(ctx, user); err != nil { if err := ConnectionsGetBelongingToUser(ctx, user); err != nil {
return err return err
} }
if err := UserGetBelongingHubs(ctx, user); err != nil {
return err
}
cache.SaveUser(user)
return nil return nil
} }
@@ -310,3 +386,378 @@ func ConnectionGetMessagesBefore(ctx context.Context, before time.Time, connecti
} }
return messages, rows.Err() return messages, rows.Err()
} }
func HubGet(ctx context.Context, hub *types.Hub) error {
var joinRoleId *int16
var rgba int64
err := dbConn.QueryRow(ctx, `
SELECT name, COALESCE(icon_url, ''), COALESCE(background_url, ''), creator, join_role, rgba, user_color_allowed, created_at
FROM hubs WHERE id = $1
`, hub.Id).Scan(&hub.Name, &hub.IconUrl, &hub.BgUrl, &hub.Creator, &joinRoleId, &rgba, &hub.UserColorAllowed, &hub.CreatedAt)
if err != nil {
return err
}
hub.Color = convertions.Uint32ToRgba(uint32(rgba))
if joinRoleId != nil {
hub.JoinRole = &types.HubRole{Id: uint8(*joinRoleId)}
}
return nil
}
func HubGetWhole(ctx context.Context, hub *types.Hub) error {
if err := HubGet(ctx, hub); err != nil {
return err
}
if err := HubRolesGet(ctx, hub); err != nil {
return err
}
if err := HubChannelsGet(ctx, hub); err != nil {
return err
}
if err := HubUsersGet(ctx, hub); err != nil {
return err
}
return nil
}
func HubRolesGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT id, name, permissions, rgba, created_at FROM hub_roles WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
role := &types.HubRole{}
var id int16
var permissions, rgba int64
if err = rows.Scan(&id, &role.Name, &permissions, &rgba, &role.CreatedAt); err != nil {
return fmt.Errorf("scanning hub_role row: %w", err)
}
role.Id = uint8(id)
role.Permissions = types.Permissions(uint32(permissions))
role.Color = convertions.Uint32ToRgba(uint32(rgba))
hub.Roles[role.Id] = role
}
return rows.Err()
}
func HubUsersGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT user_id, name, roles_0, roles_1, roles_2, is_muted, created_at FROM hub_users WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
if hub.Users == nil {
hub.Users = make(map[uuid.UUID]*types.HubUser)
}
for rows.Next() {
user := types.NewHubUser()
var r0, r1, r2 int64
if err = rows.Scan(&user.OriginalId, &user.Name, &r0, &r1, &r2, &user.IsMuted, &user.CreatedAt); err != nil {
return fmt.Errorf("scanning hub_user row: %w", err)
}
user.Roles[0] = uint64(r0)
user.Roles[1] = uint64(r1)
user.Roles[2] = uint64(r2)
hub.Users[user.OriginalId] = user
}
return rows.Err()
}
func HubChannelsGet(ctx context.Context, hub *types.Hub) error {
rows, err := dbConn.Query(ctx, `
SELECT id, name, COALESCE(description, ''), COALESCE(icon_url, ''), position, created_at,
roles_can_view_0, roles_can_view_1, roles_can_view_2,
roles_can_message_0, roles_can_message_1, roles_can_message_2,
roles_can_read_history_0, roles_can_read_history_1, roles_can_read_history_2
FROM hub_channel WHERE hub_id = $1
`, hub.Id)
if err != nil {
return err
}
defer rows.Close()
if hub.Channels == nil {
hub.Channels = make(map[uuid.UUID]*types.HubChannel)
}
for rows.Next() {
channel := types.NewHubChannel()
var pos int16
var v0, v1, v2, m0, m1, m2, rh0, rh1, rh2 int64
if err = rows.Scan(
&channel.Id, &channel.Name, &channel.Description, &channel.IconUrl, &pos, &channel.CreatedAt,
&v0, &v1, &v2, &m0, &m1, &m2, &rh0, &rh1, &rh2,
); err != nil {
return fmt.Errorf("scanning hub_channel row: %w", err)
}
channel.Position = uint8(pos)
channel.RolesCanView = types.HubBoundRoles{uint64(v0), uint64(v1), uint64(v2)}
channel.RolesCanMessage = types.HubBoundRoles{uint64(m0), uint64(m1), uint64(m2)}
channel.RolesCanReadHistory = types.HubBoundRoles{uint64(rh0), uint64(rh1), uint64(rh2)}
hub.Channels[channel.Id] = channel
}
return rows.Err()
}
func HubSave(ctx context.Context, hub *types.Hub) error {
var joinRoleId *int16
if hub.JoinRole != nil {
id := int16(hub.JoinRole.Id)
joinRoleId = &id
}
_, err := dbConn.Exec(ctx, `
INSERT INTO hubs (id, name, icon_url, background_url, creator, join_role, rgba, user_color_allowed, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
`, hub.Id, hub.Name, hub.IconUrl, hub.BgUrl, hub.Creator, joinRoleId,
convertions.RgbaToUint32(hub.Color), hub.UserColorAllowed, hub.CreatedAt)
return err
}
func HubRoleSave(ctx context.Context, hubId uuid.UUID, role *types.HubRole) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_roles (id, hub_id, name, permissions, rgba, created_at)
VALUES ($1, $2, $3, $4, $5, $6)
`, int16(role.Id), hubId, role.Name, int64(role.Permissions),
convertions.RgbaToUint32(role.Color), role.CreatedAt)
return err
}
func HubChannelSave(ctx context.Context, hubId uuid.UUID, channel *types.HubChannel) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_channel (
id, hub_id, name, description, icon_url, position, created_at,
roles_can_view_0, roles_can_view_1, roles_can_view_2,
roles_can_message_0, roles_can_message_1, roles_can_message_2,
roles_can_read_history_0, roles_can_read_history_1, roles_can_read_history_2
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16)
`, channel.Id, hubId, channel.Name, channel.Description, channel.IconUrl, channel.Position, channel.CreatedAt,
int64(channel.RolesCanView[0]), int64(channel.RolesCanView[1]), int64(channel.RolesCanView[2]),
int64(channel.RolesCanMessage[0]), int64(channel.RolesCanMessage[1]), int64(channel.RolesCanMessage[2]),
int64(channel.RolesCanReadHistory[0]), int64(channel.RolesCanReadHistory[1]), int64(channel.RolesCanReadHistory[2]))
return err
}
func HubUserSave(ctx context.Context, hubId uuid.UUID, hubUser *types.HubUser) error {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_users (user_id, hub_id, name, roles_0, roles_1, roles_2, is_muted, created_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
`, hubUser.OriginalId, hubId, hubUser.Name,
int64(hubUser.Roles[0]), int64(hubUser.Roles[1]), int64(hubUser.Roles[2]),
hubUser.IsMuted, hubUser.CreatedAt)
return err
}
func HubChannelMessageSave(ctx context.Context, message *types.Message) error {
if message.Id != (uuid.UUID{}) {
_, err := dbConn.Exec(ctx, `
INSERT INTO hub_channel_messages (id, sender_id, receiver_id, created_at, content, attached_file)
VALUES ($1, $2, $3, $4, $5, $6)
`, message.Id, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile)
return err
}
return dbConn.QueryRow(ctx, `
INSERT INTO hub_channel_messages (sender_id, receiver_id, created_at, content, attached_file)
VALUES ($1, $2, $3, $4, $5)
RETURNING id
`, message.Sender, message.Receiver, message.CreatedAt, message.Content, message.AttachedFile).Scan(&message.Id)
}
func HubChannelMessageGet(ctx context.Context, message *types.Message) error {
return dbConn.QueryRow(ctx, `
SELECT sender_id, receiver_id, created_at, content, attached_file
FROM hub_channel_messages
WHERE id = $1
`, message.Id).Scan(&message.Sender, &message.Receiver, &message.CreatedAt, &message.Content, &message.AttachedFile)
}
func HubUpdate(ctx context.Context, hub *types.Hub, updateList *types.HubUpdate) error {
setClauses := make([]string, 0, 6)
args := make([]any, 0, 7)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, hub.Name)
argIdx++
}
if updateList.IconUrl {
setClauses = append(setClauses, fmt.Sprintf("icon_url = $%d", argIdx))
args = append(args, hub.IconUrl)
argIdx++
}
if updateList.BgUrl {
setClauses = append(setClauses, fmt.Sprintf("background_url = $%d", argIdx))
args = append(args, hub.BgUrl)
argIdx++
}
if updateList.JoinRole {
var joinRoleId *int16
if hub.JoinRole != nil {
id := int16(hub.JoinRole.Id)
joinRoleId = &id
}
setClauses = append(setClauses, fmt.Sprintf("join_role = $%d", argIdx))
args = append(args, joinRoleId)
argIdx++
}
if updateList.Color {
setClauses = append(setClauses, fmt.Sprintf("rgba = $%d", argIdx))
args = append(args, convertions.RgbaToUint32(hub.Color))
argIdx++
}
if updateList.UserColorAllowed {
setClauses = append(setClauses, fmt.Sprintf("user_color_allowed = $%d", argIdx))
args = append(args, hub.UserColorAllowed)
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hubs SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
args = append(args, hub.Id)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubRoleUpdate(ctx context.Context, hubId uuid.UUID, role *types.HubRole, updateList *types.HubRoleUpdate) error {
setClauses := make([]string, 0, 3)
args := make([]any, 0, 5)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, role.Name)
argIdx++
}
if updateList.Permissions {
setClauses = append(setClauses, fmt.Sprintf("permissions = $%d", argIdx))
args = append(args, int64(role.Permissions))
argIdx++
}
if updateList.Color {
setClauses = append(setClauses, fmt.Sprintf("rgba = $%d", argIdx))
args = append(args, convertions.RgbaToUint32(role.Color))
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_roles SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d AND hub_id = $%d", argIdx, argIdx+1)
args = append(args, int16(role.Id), hubId)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubChannelUpdate(ctx context.Context, channel *types.HubChannel, updateList *types.HubChannelUpdate) error {
setClauses := make([]string, 0, 13)
args := make([]any, 0, 15)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, channel.Name)
argIdx++
}
if updateList.Description {
setClauses = append(setClauses, fmt.Sprintf("description = $%d", argIdx))
args = append(args, channel.Description)
argIdx++
}
if updateList.IconUrl {
setClauses = append(setClauses, fmt.Sprintf("icon_url = $%d", argIdx))
args = append(args, channel.IconUrl)
argIdx++
}
if updateList.Position {
setClauses = append(setClauses, fmt.Sprintf("position = $%d", argIdx))
args = append(args, channel.Position)
argIdx++
}
if updateList.RolesCanView {
setClauses = append(setClauses, fmt.Sprintf("roles_can_view_0 = $%d, roles_can_view_1 = $%d, roles_can_view_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanView[0]), int64(channel.RolesCanView[1]), int64(channel.RolesCanView[2]))
argIdx += 3
}
if updateList.RolesCanMessage {
setClauses = append(setClauses, fmt.Sprintf("roles_can_message_0 = $%d, roles_can_message_1 = $%d, roles_can_message_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanMessage[0]), int64(channel.RolesCanMessage[1]), int64(channel.RolesCanMessage[2]))
argIdx += 3
}
if updateList.RolesCanReadHistory {
setClauses = append(setClauses, fmt.Sprintf("roles_can_read_history_0 = $%d, roles_can_read_history_1 = $%d, roles_can_read_history_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(channel.RolesCanReadHistory[0]), int64(channel.RolesCanReadHistory[1]), int64(channel.RolesCanReadHistory[2]))
argIdx += 3
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_channel SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE id = $%d", argIdx)
args = append(args, channel.Id)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubUserUpdate(ctx context.Context, hubId uuid.UUID, hubUser *types.HubUser, updateList *types.HubUserUpdate) error {
setClauses := make([]string, 0, 5)
args := make([]any, 0, 7)
argIdx := 1
if updateList.Name {
setClauses = append(setClauses, fmt.Sprintf("name = $%d", argIdx))
args = append(args, hubUser.Name)
argIdx++
}
if updateList.Roles {
setClauses = append(setClauses, fmt.Sprintf("roles_0 = $%d, roles_1 = $%d, roles_2 = $%d", argIdx, argIdx+1, argIdx+2))
args = append(args, int64(hubUser.Roles[0]), int64(hubUser.Roles[1]), int64(hubUser.Roles[2]))
argIdx += 3
}
if updateList.IsMuted {
setClauses = append(setClauses, fmt.Sprintf("is_muted = $%d", argIdx))
args = append(args, hubUser.IsMuted)
argIdx++
}
if len(setClauses) == 0 {
return nil
}
query := "UPDATE hub_users SET " + strings.Join(setClauses, ", ") + fmt.Sprintf(" WHERE user_id = $%d AND hub_id = $%d", argIdx, argIdx+1)
args = append(args, hubUser.OriginalId, hubId)
_, err := dbConn.Exec(ctx, query, args...)
return err
}
func HubDelete(ctx context.Context, hubId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hubs WHERE id = $1`, hubId)
return err
}
func HubUserDelete(ctx context.Context, hubId uuid.UUID, userId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_users WHERE user_id = $1 AND hub_id = $2`, userId, hubId)
return err
}
func HubRoleDelete(ctx context.Context, hubId uuid.UUID, roleId uint8) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_roles WHERE id = $1 AND hub_id = $2`, int16(roleId), hubId)
return err
}
func HubChannelDelete(ctx context.Context, channelId uuid.UUID) error {
_, err := dbConn.Exec(ctx, `DELETE FROM hub_channel WHERE id = $1`, channelId)
return err
}
+38 -1
View File
@@ -42,7 +42,7 @@ type User struct {
Color Rgba `json:"color"` Color Rgba `json:"color"`
} }
type UserProfileUpdateList struct { type UserProfileUpdate struct {
Pronouns bool Pronouns bool
Description bool Description bool
Color bool Color bool
@@ -148,6 +148,7 @@ const (
PermissionSetHubColor PermissionSetHubColor
PermissionRemoveHub PermissionRemoveHub
PermissionSetUserColorAllowed PermissionSetUserColorAllowed
PermissionSetHubJoinRole
// User permissions // User permissions
PermissionInviteUser PermissionInviteUser
@@ -184,6 +185,7 @@ var permissionRegistry = map[string]Permissions{
"set_hub_color": PermissionSetHubColor, "set_hub_color": PermissionSetHubColor,
"remove_hub": PermissionRemoveHub, "remove_hub": PermissionRemoveHub,
"set_user_color_allowed": PermissionSetUserColorAllowed, "set_user_color_allowed": PermissionSetUserColorAllowed,
"set_hub_join_role": PermissionSetHubJoinRole,
"invite_user": PermissionInviteUser, "invite_user": PermissionInviteUser,
"remove_user": PermissionRemoveUser, "remove_user": PermissionRemoveUser,
"rename_user": PermissionRenameUser, "rename_user": PermissionRenameUser,
@@ -263,6 +265,17 @@ func (p *CachedUserPermissions) SetCanMessage() { *p |= CachedUserCanMessage }
func (p *CachedUserPermissions) ClearCanMessage() { *p &^= CachedUserCanMessage } func (p *CachedUserPermissions) ClearCanMessage() { *p &^= CachedUserCanMessage }
func (p CachedUserPermissions) CanMessage() bool { return p&CachedUserCanMessage != 0 } func (p CachedUserPermissions) CanMessage() bool { return p&CachedUserCanMessage != 0 }
type HubUpdate struct {
Name bool
IconUrl bool
BgUrl bool
JoinRole bool
Id bool
Creator bool
Color bool
UserColorAllowed bool
}
type Hub struct { type Hub struct {
Mu sync.RWMutex `json:"-"` Mu sync.RWMutex `json:"-"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
@@ -286,6 +299,13 @@ func NewHub() *Hub {
} }
} }
type HubRoleUpdate struct {
Name bool
Permissions bool
Color bool
Id bool
}
type HubRole struct { type HubRole struct {
Name string `json:"role"` Name string `json:"role"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
@@ -304,6 +324,12 @@ func (h *HubRole) HasPermission(r Permissions) bool {
return h.Permissions&r != 0 return h.Permissions&r != 0
} }
type HubUserUpdate struct {
Roles bool
Name bool
IsMuted bool
}
type HubUser struct { type HubUser struct {
Mu sync.RWMutex `json:"-"` Mu sync.RWMutex `json:"-"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
@@ -317,6 +343,17 @@ func NewHubUser() *HubUser {
return &HubUser{} return &HubUser{}
} }
type HubChannelUpdate struct {
Name bool
Description bool
IconUrl bool
CreatedAt bool
RolesCanView bool
RolesCanMessage bool
RolesCanReadHistory bool
Position bool
}
type HubChannel struct { type HubChannel struct {
Mu sync.RWMutex `json:"-"` Mu sync.RWMutex `json:"-"`
MessagesBuff []*Message `json:"-"` MessagesBuff []*Message `json:"-"`
+41 -3
View File
@@ -69,6 +69,8 @@
<button data-form="hub-channel-role-view" onclick="showForm('hub-channel-role-view')">PATCH /hub/channel/roles/view</button> <button data-form="hub-channel-role-view" onclick="showForm('hub-channel-role-view')">PATCH /hub/channel/roles/view</button>
<button data-form="hub-channel-role-send" onclick="showForm('hub-channel-role-send')">PATCH /hub/channel/roles/send</button> <button data-form="hub-channel-role-send" onclick="showForm('hub-channel-role-send')">PATCH /hub/channel/roles/send</button>
<button data-form="hub-channel-role-history" onclick="showForm('hub-channel-role-history')">PATCH /hub/channel/roles/history</button> <button data-form="hub-channel-role-history" onclick="showForm('hub-channel-role-history')">PATCH /hub/channel/roles/history</button>
<button data-form="hub-channel-set-icon" onclick="showForm('hub-channel-set-icon')">PATCH /hub/channel/icon</button>
<button data-form="get-hub-channel-icon" onclick="showForm('get-hub-channel-icon')">GET /hub/channel/icon</button>
<button data-form="hub-user-add-role" onclick="showForm('hub-user-add-role')">PUT /hub/user/role</button> <button data-form="hub-user-add-role" onclick="showForm('hub-user-add-role')">PUT /hub/user/role</button>
<button data-form="hub-role-create" onclick="showForm('hub-role-create')">PUT /hub/role</button> <button data-form="hub-role-create" onclick="showForm('hub-role-create')">PUT /hub/role</button>
<button data-form="hub-channel-create" onclick="showForm('hub-channel-create')">PUT /hub/channel</button> <button data-form="hub-channel-create" onclick="showForm('hub-channel-create')">PUT /hub/channel</button>
@@ -108,7 +110,7 @@
<!-- POST /file --> <!-- POST /file -->
<div class="form-content" id="fc-file-upload"> <div class="form-content" id="fc-file-upload">
<div class="field"><label>token</label><input id="fu-token" placeholder=""></div> <div class="field"><label>token</label><input id="fu-token" placeholder=""></div>
<div class="field"><label>connectionid</label><input id="fu-connectionid" placeholder="UUID"></div> <div class="field"><label>target_id</label><input id="fu-connectionid" placeholder="UUID (connection or channel)"></div>
<div class="field"><label>file</label><input id="fu-file" type="file"></div> <div class="field"><label>file</label><input id="fu-file" type="file"></div>
<div class="form-actions"><button class="send" onclick="submitFileUpload()">Send</button></div> <div class="form-actions"><button class="send" onclick="submitFileUpload()">Send</button></div>
</div> </div>
@@ -320,6 +322,23 @@
<div class="form-actions"><button class="send" onclick="submit('get-hub-bg')">Send</button></div> <div class="form-actions"><button class="send" onclick="submit('get-hub-bg')">Send</button></div>
</div> </div>
<!-- PATCH /hub/channel/icon -->
<div class="form-content" id="fc-hub-channel-set-icon">
<div class="field"><label>token</label><input id="hcsi-token" placeholder=""></div>
<div class="field"><label>hubid</label><input id="hcsi-hubid" placeholder="UUID"></div>
<div class="field"><label>channel_id</label><input id="hcsi-channelid" placeholder="UUID"></div>
<div class="field"><label>file</label><input id="hcsi-file" type="file"></div>
<div class="form-actions"><button class="send" onclick="submitChannelIconUpload()">Send</button></div>
</div>
<!-- GET /hub/channel/icon -->
<div class="form-content" id="fc-get-hub-channel-icon">
<div class="field"><label>token</label><input id="ghci-token" placeholder=""></div>
<div class="field"><label>hubid</label><input id="ghci-hubid" placeholder="UUID"></div>
<div class="field"><label>channel_id</label><input id="ghci-channelid" placeholder="UUID"></div>
<div class="form-actions"><button class="send" onclick="submit('get-hub-channel-icon')">Send</button></div>
</div>
<!-- DELETE /hub --> <!-- DELETE /hub -->
<div class="form-content" id="fc-hub-remove"> <div class="form-content" id="fc-hub-remove">
<div class="field"><label>token</label><input id="hr-token" placeholder=""></div> <div class="field"><label>token</label><input id="hr-token" placeholder=""></div>
@@ -579,6 +598,8 @@
'get-hub-icon': { method:'GET', path:'/hub/icon', title:'GET /hub/icon — get hub icon URL', fields:[{id:'ghi-token',dest:'header',name:'token'},{id:'ghi-hubid',dest:'header',name:'hub_id'}] }, 'get-hub-icon': { method:'GET', path:'/hub/icon', title:'GET /hub/icon — get hub icon URL', fields:[{id:'ghi-token',dest:'header',name:'token'},{id:'ghi-hubid',dest:'header',name:'hub_id'}] },
'hub-set-bg': { title:'PATCH /hub/bg — set hub background image' }, 'hub-set-bg': { title:'PATCH /hub/bg — set hub background image' },
'get-hub-bg': { method:'GET', path:'/hub/bg', title:'GET /hub/bg — get hub background URL', fields:[{id:'ghbg-token',dest:'header',name:'token'},{id:'ghbg-hubid',dest:'header',name:'hub_id'}] }, 'get-hub-bg': { method:'GET', path:'/hub/bg', title:'GET /hub/bg — get hub background URL', fields:[{id:'ghbg-token',dest:'header',name:'token'},{id:'ghbg-hubid',dest:'header',name:'hub_id'}] },
'hub-channel-set-icon': { title:'PATCH /hub/channel/icon — set channel icon image' },
'get-hub-channel-icon': { method:'GET', path:'/hub/channel/icon', title:'GET /hub/channel/icon — get channel icon URL', fields:[{id:'ghci-token',dest:'header',name:'token'},{id:'ghci-hubid',dest:'header',name:'hub_id'},{id:'ghci-channelid',dest:'query',name:'channel_id'}] },
'hub-remove': { method:'DELETE', path:'/hub', title:'DELETE /hub — remove hub', fields:[{id:'hr-token',dest:'header',name:'token'},{id:'hr-hubid',dest:'header',name:'hub_id'}] }, 'hub-remove': { method:'DELETE', path:'/hub', title:'DELETE /hub — remove hub', fields:[{id:'hr-token',dest:'header',name:'token'},{id:'hr-hubid',dest:'header',name:'hub_id'}] },
'hub-toggle-color': { method:'PATCH', path:'/hub/usercolorallowed', title:'PATCH /hub/usercolorallowed — toggle user color allowed', fields:[{id:'htc-token',dest:'header',name:'token'},{id:'htc-hubid',dest:'header',name:'hub_id'}] }, 'hub-toggle-color': { method:'PATCH', path:'/hub/usercolorallowed', title:'PATCH /hub/usercolorallowed — toggle user color allowed', fields:[{id:'htc-token',dest:'header',name:'token'},{id:'htc-hubid',dest:'header',name:'hub_id'}] },
'hub-user-remove': { method:'DELETE', path:'/hub/user', title:'DELETE /hub/user — remove user from hub', fields:[{id:'hur-token',dest:'header',name:'token'},{id:'hur-hubid',dest:'header',name:'hub_id'},{id:'hur-targetid',dest:'query',name:'target_id'}] }, 'hub-user-remove': { method:'DELETE', path:'/hub/user', title:'DELETE /hub/user — remove user from hub', fields:[{id:'hur-token',dest:'header',name:'token'},{id:'hur-hubid',dest:'header',name:'hub_id'},{id:'hur-targetid',dest:'query',name:'target_id'}] },
@@ -798,9 +819,9 @@
const fileInput = document.getElementById('fu-file'); const fileInput = document.getElementById('fu-file');
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; } if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
const form = new FormData(); const form = new FormData();
form.append('connection_id', connectionid); form.append('target_id', connectionid);
form.append('file', fileInput.files[0]); form.append('file', fileInput.files[0]);
log('POST /file', 'connection_id=' + connectionid + ' file=' + fileInput.files[0].name, 'log-info'); log('POST /file', 'target_id=' + connectionid + ' file=' + fileInput.files[0].name, 'log-info');
try { try {
const resp = await fetch(baseUrl() + '/file', { method: 'POST', headers: { token }, body: form }); const resp = await fetch(baseUrl() + '/file', { method: 'POST', headers: { token }, body: form });
const text = await resp.text(); const text = await resp.text();
@@ -913,6 +934,23 @@
} catch(e) { log('HTTP ERR', e.message, 'log-err'); } } catch(e) { log('HTTP ERR', e.message, 'log-err'); }
} }
async function submitChannelIconUpload() {
const token = document.getElementById('hcsi-token').value;
const hubid = document.getElementById('hcsi-hubid').value;
const channelid = document.getElementById('hcsi-channelid').value;
const fileInput = document.getElementById('hcsi-file');
if (!fileInput.files.length) { log('HTTP ERR', 'no file selected', 'log-err'); return; }
const form = new FormData();
form.append('channel_id', channelid);
form.append('file', fileInput.files[0]);
log('PATCH /hub/channel/icon', 'channel_id=' + channelid + ' file=' + fileInput.files[0].name, 'log-info');
try {
const resp = await fetch(baseUrl() + '/hub/channel/icon', { method: 'PATCH', headers: { token, hub_id: hubid }, body: form });
const text = await resp.text();
log('HTTP ' + resp.status, text, resp.ok ? 'log-http' : 'log-err');
} catch(e) { log('HTTP ERR', e.message, 'log-err'); }
}
async function submitGetUserProfileBg() { async function submitGetUserProfileBg() {
const token = document.getElementById('gpb-token').value; const token = document.getElementById('gpb-token').value;
const userid = document.getElementById('gpb-userid').value; const userid = document.getElementById('gpb-userid').value;
-2
View File
@@ -1,8 +1,6 @@
check hubs attachment working
add option to change join role add option to change join role
add channel icons add channel icons
make hub persistent
when user not ws connected collect count of unread messages for each conn (add db table in future) when user not ws connected collect count of unread messages for each conn (add db table in future)
fix cache fix cache