rework of hubs
This commit is contained in:
@@ -65,20 +65,20 @@ func getHubByIdStr(ctx context.Context, hubId string) (*types.Hub, error) {
|
||||
return hub, nil
|
||||
}
|
||||
|
||||
func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.ResponseWriter, token string, hubId string) (
|
||||
func getHubUserIfValidWithResponseOnFail(ctx context.Context, response http.ResponseWriter, request *http.Request) (
|
||||
*types.User, *types.HubUser, *types.Hub, error) {
|
||||
hub, err := getHubByIdStr(ctx, hubId)
|
||||
if err != nil {
|
||||
http.Error(response, "invalid hubid", http.StatusBadRequest)
|
||||
return nil, nil, nil, errors.New("no such hub")
|
||||
}
|
||||
|
||||
user, err := getUserByToken(ctx, token)
|
||||
user, err := getUserByToken(ctx, request.Header.Get("token"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid token", http.StatusBadRequest)
|
||||
return nil, nil, nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
hub, err := getHubByIdStr(ctx, request.Header.Get("hubid"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid hubid", http.StatusBadRequest)
|
||||
return nil, nil, nil, errors.New("no such hub")
|
||||
}
|
||||
|
||||
hub.Mu.RLock()
|
||||
hubUser, ok := hub.Users[user.Id]
|
||||
hub.Mu.RUnlock()
|
||||
@@ -103,7 +103,7 @@ func getHubChannelIfValidWithResponseOnFail(ctx context.Context, response http.R
|
||||
return nil, errors.New("invalid channelid")
|
||||
}
|
||||
|
||||
if !haveHubUserPermissionsOnChannel(types.CachedUserCanView, hubUser, channel) {
|
||||
if !haveHubUserCachedPermissions(types.CachedUserCanView, hubUser, channel) {
|
||||
return nil, errors.New("invalid channelid")
|
||||
}
|
||||
|
||||
|
||||
@@ -8,16 +8,16 @@ import (
|
||||
"go-socket/packages/config"
|
||||
)
|
||||
|
||||
type postType uint8
|
||||
type requestType uint8
|
||||
|
||||
const (
|
||||
normal postType = iota
|
||||
normal requestType = iota
|
||||
file
|
||||
avatar
|
||||
profileBg
|
||||
)
|
||||
|
||||
func validCheckWithResponseOnFail(response *http.ResponseWriter, request *http.Request, pt postType) bool {
|
||||
func validCheckWithResponseOnFail(response *http.ResponseWriter, request *http.Request, pt requestType) bool {
|
||||
var maxSize int64
|
||||
switch pt {
|
||||
case file:
|
||||
|
||||
+55
-283
@@ -2,7 +2,6 @@ package httpRequest
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"go-socket/packages/convertions"
|
||||
"maps"
|
||||
"net/http"
|
||||
"slices"
|
||||
@@ -16,7 +15,24 @@ import (
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func haveHubUserPermissionsOnChannel(needed types.CachedUserPermissions, user *types.HubUser, channel *types.HubChannel) bool {
|
||||
func haveHubUserPermission(u *types.HubUser, h *types.Hub, needed types.Permissions) bool {
|
||||
h.Mu.Lock()
|
||||
defer h.Mu.Unlock()
|
||||
for _, role := range h.Roles {
|
||||
if role == nil {
|
||||
continue
|
||||
}
|
||||
if !u.Roles.Has(role.Id) {
|
||||
continue
|
||||
}
|
||||
if (needed & role.Permissions) == needed {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func haveHubUserCachedPermissions(needed types.CachedUserPermissions, user *types.HubUser, channel *types.HubChannel) bool {
|
||||
channel.Mu.RLock()
|
||||
checkAgainst, ok := channel.UsersCachedPermissions[user.OriginalId]
|
||||
channel.Mu.RUnlock()
|
||||
@@ -26,61 +42,6 @@ func haveHubUserPermissionsOnChannel(needed types.CachedUserPermissions, user *t
|
||||
return true
|
||||
}
|
||||
|
||||
func haveUserPermissions(needed types.Permissions, scope uint8, hu *types.HubUser, h *types.Hub) bool {
|
||||
h.Mu.RLock()
|
||||
defer h.Mu.RUnlock()
|
||||
|
||||
for _, role := range h.Roles {
|
||||
if role == nil {
|
||||
continue
|
||||
}
|
||||
if scope != 0 && role.BoundedGroup != scope {
|
||||
continue
|
||||
}
|
||||
if !hu.Roles.Has(role.Id) {
|
||||
continue
|
||||
}
|
||||
if (needed & role.Permissions) != needed {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func addHubUserToPermissionCache(hub *types.Hub, user *types.HubUser) {
|
||||
user.Mu.RLock()
|
||||
roles := user.Roles
|
||||
userId := user.OriginalId
|
||||
user.Mu.RUnlock()
|
||||
|
||||
for _, group := range hub.Groups {
|
||||
if group == nil {
|
||||
continue
|
||||
}
|
||||
if !roles.HasSameId(group.RolesCanView) {
|
||||
continue
|
||||
}
|
||||
group.UsersCachedPermissions[userId] = types.CachedUserCanView
|
||||
|
||||
for _, channel := range group.Channels {
|
||||
var perms types.CachedUserPermissions
|
||||
|
||||
if roles.HasSameId(channel.RolesCanView) {
|
||||
perms |= types.CachedUserCanView
|
||||
if roles.HasSameId(channel.RolesCanReadHistory) {
|
||||
perms |= types.CachedUserCanReadHistory
|
||||
}
|
||||
if roles.HasSameId(channel.RolesCanMessage) {
|
||||
perms |= types.CachedUserCanMessage
|
||||
}
|
||||
}
|
||||
channel.Mu.Lock()
|
||||
channel.UsersCachedPermissions[userId] = perms
|
||||
channel.Mu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
@@ -132,31 +93,20 @@ func HandleHubCreate(response http.ResponseWriter, request *http.Request) {
|
||||
hub.Roles[memberRole.Id] = memberRole
|
||||
creator.Roles.Add(memberRole.Id)
|
||||
|
||||
rootGroup := types.NewHubGroup()
|
||||
rootGroup.Name = "root"
|
||||
rootGroup.Id = uint8(1)
|
||||
rootGroup.Color = types.Rgba{}.GetRandom()
|
||||
rootGroup.CreatedAt = hub.CreatedAt
|
||||
rootGroup.RolesCanView.Add(rootRole.Id)
|
||||
rootGroup.RolesCanView.Add(memberRole.Id)
|
||||
hub.Groups[rootGroup.Id] = rootGroup
|
||||
|
||||
channel := types.NewHubChannel()
|
||||
channel.Name = "main channel"
|
||||
channel.Position = uint8(0)
|
||||
channel.Id = uuid.New()
|
||||
channel.ParentId = rootGroup.Id
|
||||
channel.Description = "The fist channel!"
|
||||
channel.CreatedAt = hub.CreatedAt
|
||||
channel.RolesCanMessage.Add(rootGroup.Id)
|
||||
channel.RolesCanMessage.Add(rootRole.Id)
|
||||
channel.RolesCanMessage.Add(memberRole.Id)
|
||||
channel.RolesCanView.Add(rootGroup.Id)
|
||||
channel.RolesCanView.Add(rootRole.Id)
|
||||
channel.RolesCanView.Add(memberRole.Id)
|
||||
channel.RolesCanReadHistory.Add(rootGroup.Id)
|
||||
channel.RolesCanReadHistory.Add(rootRole.Id)
|
||||
channel.RolesCanReadHistory.Add(memberRole.Id)
|
||||
channel.UsersCachedPermissions[creator.OriginalId] = types.CachedUserPermissionsAll
|
||||
hub.Channels[channel.Id] = channel
|
||||
rootGroup.Channels[channel.Id] = channel
|
||||
|
||||
cache.SaveHub(hub)
|
||||
}
|
||||
@@ -182,7 +132,6 @@ func HandleHubJoin(response http.ResponseWriter, request *http.Request) {
|
||||
hubUser.Roles.Add(hub.JoinRole.Id)
|
||||
hubUser.CreatedAt = time.Now()
|
||||
hub.Users[hubUser.OriginalId] = hubUser
|
||||
addHubUserToPermissionCache(hub, hubUser)
|
||||
}
|
||||
|
||||
func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
||||
@@ -190,7 +139,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
user, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
user, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -199,7 +148,7 @@ func HandleHubMessage(response http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if hubUser.IsGlobalMuted {
|
||||
if hubUser.IsMuted {
|
||||
http.Error(response, "muted", http.StatusForbidden)
|
||||
}
|
||||
|
||||
@@ -269,215 +218,38 @@ func HandleGetHubs(response http.ResponseWriter, request *http.Request) {
|
||||
response.Write(converted)
|
||||
}
|
||||
|
||||
func HandleHubPermissionActionCore(
|
||||
response http.ResponseWriter, request *http.Request,
|
||||
takenVarName string, rt requestType, needed types.Permissions,
|
||||
performedAction func(usr *types.HubUser, hub *types.Hub, takenVar *string)) {
|
||||
if !validCheckWithResponseOnFail(&response, request, rt) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !haveHubUserPermission(hubUser, hub, needed) {
|
||||
http.Error(response, "", http.StatusForbidden)
|
||||
}
|
||||
|
||||
var takenVar *string = nil
|
||||
|
||||
if takenVarName != "" {
|
||||
takenVar = new(request.FormValue(takenVarName))
|
||||
}
|
||||
performedAction(hubUser, hub, takenVar)
|
||||
}
|
||||
|
||||
func HandleHubSetName(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newName := request.FormValue("name")
|
||||
if newName == "" {
|
||||
http.Error(response, "empty name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !haveUserPermissions(types.PermissionSetHubName, 0, hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Name = newName
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubSetColor(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
newColor, err := convertions.StringToRgba(request.FormValue("color"))
|
||||
if err != nil {
|
||||
http.Error(response, "bad color", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if !haveUserPermissions(types.PermissionSetHubColor, 0, hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Color = newColor
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubRemove(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !haveUserPermissions(types.PermissionRemoveHub, 0, hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
cache.DeleteHub(hub)
|
||||
}
|
||||
|
||||
func HandleHubSetAllowUserColor(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if !haveUserPermissions(types.PermissionSetUserColorAllowed, 0, hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
cache.DeleteHub(hub)
|
||||
}
|
||||
|
||||
func HandleHubRemoveUser(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
targetId, err := convertions.StringToUuid(request.FormValue("target"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid targetid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
hub.Mu.RLock()
|
||||
_, ok := hub.Users[targetId]
|
||||
if !ok {
|
||||
http.Error(response, "target not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if !haveUserPermissions(types.PermissionRemoveUser, 0, hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.Lock()
|
||||
delete(hub.Users, targetId)
|
||||
hub.Mu.Unlock()
|
||||
response.WriteHeader(http.StatusAccepted)
|
||||
}
|
||||
|
||||
func HandleHubMuteUserToggle(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
targetId, err := convertions.StringToUuid(request.FormValue("target"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid targetid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
scope, err := convertions.StringToUint32(request.FormValue("scope"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid scope (set 0 for no scope)", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
hub.Mu.RUnlock()
|
||||
if !ok {
|
||||
http.Error(response, "target not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if !haveUserPermissions(types.PermissionMuteUser, uint8(scope), hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if scope == 0 {
|
||||
target.IsGlobalMuted = !target.IsGlobalMuted
|
||||
} else {
|
||||
hub.Mu.Lock()
|
||||
users := hub.Groups[scope].MutedUsers
|
||||
_, ok = users[targetId]
|
||||
if ok {
|
||||
delete(users, targetId)
|
||||
} else {
|
||||
users[targetId] = struct{}{}
|
||||
HandleHubPermissionActionCore(response, request, "newname", normal, types.PermissionSetHubName, func(usr *types.HubUser, hub *types.Hub, takenVar *string) {
|
||||
newName := *takenVar
|
||||
if newName == "" {
|
||||
http.Error(response, "empty name", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func HandleHubMuteUserToggle(response http.ResponseWriter, request *http.Request) {
|
||||
if !validCheckWithResponseOnFail(&response, request, normal) {
|
||||
return
|
||||
}
|
||||
ctx := request.Context()
|
||||
_, hubUser, hub, err := getHubUserIfValidWithResponseOnFail(ctx, response, request.Header.Get("token"), request.FormValue("hubid"))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
targetId, err := convertions.StringToUuid(request.FormValue("target"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid targetid", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
scope, err := convertions.StringToUint32(request.FormValue("scope"))
|
||||
if err != nil {
|
||||
http.Error(response, "invalid scope (set 0 for no scope)", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hub.Mu.RLock()
|
||||
target, ok := hub.Users[targetId]
|
||||
hub.Mu.RUnlock()
|
||||
if !ok {
|
||||
http.Error(response, "target not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if !haveUserPermissions(types.PermissionMuteUser, uint8(scope), hubUser, hub) {
|
||||
http.Error(response, "no permission", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
|
||||
if scope == 0 {
|
||||
target.IsGlobalMuted = !target.IsGlobalMuted
|
||||
} else {
|
||||
hub.Mu.Lock()
|
||||
users := hub.Groups[scope].MutedUsers
|
||||
_, ok = users[targetId]
|
||||
if ok {
|
||||
delete(users, targetId)
|
||||
} else {
|
||||
users[targetId] = struct{}{}
|
||||
}
|
||||
}
|
||||
hub.Name = newName
|
||||
})
|
||||
}
|
||||
|
||||
@@ -86,8 +86,8 @@ func HandleUserNew(response http.ResponseWriter, request *http.Request) {
|
||||
}
|
||||
|
||||
username := request.FormValue("username")
|
||||
if len(username) < 4 {
|
||||
http.Error(response, "no or short username", http.StatusBadRequest)
|
||||
if len(username) < 4 || len(username) > 30 {
|
||||
http.Error(response, "no or short/too long username", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+11
-37
@@ -152,25 +152,18 @@ const (
|
||||
PermissionAddUser
|
||||
PermissionRemoveUser
|
||||
PermissionRenameUser
|
||||
PermissionSelfRename
|
||||
PermissionMuteUser
|
||||
|
||||
// Role permissions
|
||||
PermissionAddRole
|
||||
PermissionRemoveRole
|
||||
PermissionChangeRoleName
|
||||
PermissionChangeRoleColor
|
||||
PermissionChangeRoleGlobals
|
||||
PermissionSetRoleName
|
||||
PermissionSetRoleColor
|
||||
|
||||
PermissionNoSelfRoleRemove
|
||||
PermissionSelfRoleRemove
|
||||
PermissionOnlySelfRoleRemove
|
||||
|
||||
// Channel group permissions
|
||||
PermissionAddChannelGroup
|
||||
PermissionRemoveChannelGroup
|
||||
PermissionSetChannelGroupName
|
||||
PermissionSetChannelGroupColor
|
||||
PermissionSetChannelGroupPermittedVisibleRoles
|
||||
|
||||
// Channel permissions
|
||||
PermissionAddChannel
|
||||
PermissionRemoveChannel
|
||||
@@ -238,7 +231,6 @@ type Hub struct {
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Roles [256]*HubRole `json:"-"`
|
||||
Users map[uuid.UUID]*HubUser `json:"-"`
|
||||
Groups [256]*HubGroup `json:"-"`
|
||||
Channels map[uuid.UUID]*HubChannel `json:"-"`
|
||||
Name string `json:"name"`
|
||||
IconUrl string `json:"iconUrl"`
|
||||
@@ -264,6 +256,7 @@ type HubRole struct {
|
||||
Color Rgba `json:"color"`
|
||||
Id uint8 `json:"id"`
|
||||
BoundedGroup uint8 `json:"boundedGroup"` // BoundedGroup 0 for global
|
||||
IsDeleted bool `json:"-"`
|
||||
}
|
||||
|
||||
func (h *HubRole) GrantPermission(r Permissions) {
|
||||
@@ -277,36 +270,18 @@ func (h *HubRole) HasPermission(r Permissions) bool {
|
||||
}
|
||||
|
||||
type HubUser struct {
|
||||
Mu sync.RWMutex `json:"mu"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Roles HubBoundRoles `json:"-"`
|
||||
Name string `json:"name"` // Name empty = original name
|
||||
OriginalId uuid.UUID `json:"originalId"`
|
||||
IsGlobalMuted bool `json:"isGlobalMuted"`
|
||||
Mu sync.RWMutex `json:"mu"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Roles HubBoundRoles `json:"-"`
|
||||
Name string `json:"name"` // Name empty = original name
|
||||
OriginalId uuid.UUID `json:"originalId"`
|
||||
IsMuted bool `json:"isMuted"`
|
||||
}
|
||||
|
||||
func NewHubUser() *HubUser {
|
||||
return &HubUser{}
|
||||
}
|
||||
|
||||
type HubGroup struct {
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Color Rgba `json:"color"`
|
||||
RolesCanView HubBoundRoles `json:"rolesCanView"`
|
||||
UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"`
|
||||
Channels map[uuid.UUID]*HubChannel `json:"-"`
|
||||
MutedUsers map[uuid.UUID]struct{} `json:"-"`
|
||||
Id uint8 `json:"id"` // Id 0 for unused
|
||||
}
|
||||
|
||||
func NewHubGroup() *HubGroup {
|
||||
return &HubGroup{
|
||||
UsersCachedPermissions: make(map[uuid.UUID]CachedUserPermissions),
|
||||
Channels: make(map[uuid.UUID]*HubChannel),
|
||||
}
|
||||
}
|
||||
|
||||
type HubChannel struct {
|
||||
Mu sync.RWMutex `json:"-"`
|
||||
MessagesBuff []*Message `json:"-"`
|
||||
@@ -320,7 +295,6 @@ type HubChannel struct {
|
||||
UsersCachedPermissions map[uuid.UUID]CachedUserPermissions `json:"-"`
|
||||
NextBuffIdx uint32 `json:"-"`
|
||||
Id uuid.UUID `json:"id"`
|
||||
ParentId uint8 `json:"parentId"`
|
||||
Position uint8 `json:"position"`
|
||||
HaveOverflowed bool `json:"-"`
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user