status-go/protocol/communities/community_categories.go

360 lines
9.7 KiB
Go

package communities
import (
"sort"
"github.com/status-im/status-go/protocol/protobuf"
)
func (o *Community) CreateCategory(categoryID string, categoryName string, chatIDs []string) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.config.PrivateKey == nil {
return nil, ErrNotAdmin
}
if o.config.CommunityDescription.Categories == nil {
o.config.CommunityDescription.Categories = make(map[string]*protobuf.CommunityCategory)
}
if _, ok := o.config.CommunityDescription.Categories[categoryID]; ok {
return nil, ErrCategoryAlreadyExists
}
for _, cid := range chatIDs {
c, exists := o.config.CommunityDescription.Chats[cid]
if !exists {
return nil, ErrChatNotFound
}
if exists && c.CategoryId != categoryID && c.CategoryId != "" {
return nil, ErrChatAlreadyAssigned
}
}
changes := o.emptyCommunityChanges()
o.config.CommunityDescription.Categories[categoryID] = &protobuf.CommunityCategory{
CategoryId: categoryID,
Name: categoryName,
Position: int32(len(o.config.CommunityDescription.Categories)),
}
for i, cid := range chatIDs {
o.config.CommunityDescription.Chats[cid].CategoryId = categoryID
o.config.CommunityDescription.Chats[cid].Position = int32(i)
}
o.SortCategoryChats(changes, "")
o.increaseClock()
changes.CategoriesAdded[categoryID] = o.config.CommunityDescription.Categories[categoryID]
for i, cid := range chatIDs {
changes.ChatsModified[cid] = &CommunityChatChanges{
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
CategoryModified: categoryID,
PositionModified: i,
}
}
return changes, nil
}
func (o *Community) EditCategory(categoryID string, categoryName string, chatIDs []string) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.config.PrivateKey == nil {
return nil, ErrNotAdmin
}
if o.config.CommunityDescription.Categories == nil {
o.config.CommunityDescription.Categories = make(map[string]*protobuf.CommunityCategory)
}
if _, ok := o.config.CommunityDescription.Categories[categoryID]; !ok {
return nil, ErrCategoryNotFound
}
for _, cid := range chatIDs {
c, exists := o.config.CommunityDescription.Chats[cid]
if !exists {
return nil, ErrChatNotFound
}
if exists && c.CategoryId != categoryID && c.CategoryId != "" {
return nil, ErrChatAlreadyAssigned
}
}
changes := o.emptyCommunityChanges()
emptyCatLen := o.getCategoryChatCount("")
// remove any chat that might have been assigned before and now it's not part of the category
var chatsToRemove []string
for k, chat := range o.config.CommunityDescription.Chats {
if chat.CategoryId == categoryID {
found := false
for _, c := range chatIDs {
if k == c {
found = true
}
}
if !found {
chat.CategoryId = ""
chatsToRemove = append(chatsToRemove, k)
}
}
}
o.config.CommunityDescription.Categories[categoryID].Name = categoryName
for i, cid := range chatIDs {
o.config.CommunityDescription.Chats[cid].CategoryId = categoryID
o.config.CommunityDescription.Chats[cid].Position = int32(i)
}
for i, cid := range chatsToRemove {
o.config.CommunityDescription.Chats[cid].Position = int32(emptyCatLen + i)
changes.ChatsModified[cid] = &CommunityChatChanges{
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
CategoryModified: "",
PositionModified: int(o.config.CommunityDescription.Chats[cid].Position),
}
}
o.SortCategoryChats(changes, "")
o.increaseClock()
changes.CategoriesModified[categoryID] = o.config.CommunityDescription.Categories[categoryID]
for i, cid := range chatIDs {
changes.ChatsModified[cid] = &CommunityChatChanges{
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
CategoryModified: categoryID,
PositionModified: i,
}
}
return changes, nil
}
func (o *Community) ReorderCategories(categoryID string, newPosition int) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.config.PrivateKey == nil {
return nil, ErrNotAdmin
}
if newPosition > 0 && newPosition >= len(o.config.CommunityDescription.Categories) {
newPosition = len(o.config.CommunityDescription.Categories) - 1
} else if newPosition < 0 {
newPosition = 0
}
o.config.CommunityDescription.Categories[categoryID].Position = int32(newPosition)
s := make(sortSlice, 0, len(o.config.CommunityDescription.Categories))
for catID, category := range o.config.CommunityDescription.Categories {
position := category.Position
if category.CategoryId != categoryID && position >= int32(newPosition) {
position = position + 1
}
s = append(s, sorterHelperIdx{
pos: position,
catID: catID,
})
}
changes := o.emptyCommunityChanges()
o.setModifiedCategories(changes, s)
o.increaseClock()
return changes, nil
}
func (o *Community) setModifiedCategories(changes *CommunityChanges, s sortSlice) {
sort.Sort(s)
for i, catSortHelper := range s {
if o.config.CommunityDescription.Categories[catSortHelper.catID].Position != int32(i) {
o.config.CommunityDescription.Categories[catSortHelper.catID].Position = int32(i)
changes.CategoriesModified[catSortHelper.catID] = o.config.CommunityDescription.Categories[catSortHelper.catID]
}
}
}
func (o *Community) ReorderChat(categoryID string, chatID string, newPosition int) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.config.PrivateKey == nil {
return nil, ErrNotAdmin
}
if _, exists := o.config.CommunityDescription.Categories[categoryID]; !exists {
return nil, ErrCategoryNotFound
}
var chat *protobuf.CommunityChat
var exists bool
if chat, exists = o.config.CommunityDescription.Chats[chatID]; !exists {
return nil, ErrChatNotFound
}
oldCategoryID := chat.CategoryId
chat.CategoryId = categoryID
changes := o.emptyCommunityChanges()
o.SortCategoryChats(changes, oldCategoryID)
o.insertAndSort(changes, categoryID, chat, newPosition)
o.increaseClock()
return changes, nil
}
func (o *Community) SortCategoryChats(changes *CommunityChanges, categoryID string) {
var catChats []string
for k, c := range o.config.CommunityDescription.Chats {
if c.CategoryId == categoryID {
catChats = append(catChats, k)
}
}
sortedChats := make(sortSlice, 0, len(catChats))
for _, k := range catChats {
sortedChats = append(sortedChats, sorterHelperIdx{
pos: o.config.CommunityDescription.Chats[k].Position,
chatID: k,
})
}
sort.Sort(sortedChats)
for i, chatSortHelper := range sortedChats {
if o.config.CommunityDescription.Chats[chatSortHelper.chatID].Position != int32(i) {
o.config.CommunityDescription.Chats[chatSortHelper.chatID].Position = int32(i)
if changes.ChatsModified[chatSortHelper.chatID] != nil {
changes.ChatsModified[chatSortHelper.chatID].PositionModified = i
} else {
changes.ChatsModified[chatSortHelper.chatID] = &CommunityChatChanges{
PositionModified: i,
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
}
}
}
}
}
func (o *Community) insertAndSort(changes *CommunityChanges, categoryID string, chat *protobuf.CommunityChat, newPosition int) {
var catChats []string
for k, c := range o.config.CommunityDescription.Chats {
if c.CategoryId == categoryID {
catChats = append(catChats, k)
}
}
if newPosition > 0 && newPosition >= len(catChats) {
newPosition = len(catChats) - 1
} else if newPosition < 0 {
newPosition = 0
}
sortedChats := make(sortSlice, 0, len(catChats))
for _, k := range catChats {
position := chat.Position
if o.config.CommunityDescription.Chats[k] != chat && position >= int32(newPosition) {
position = position + 1
}
sortedChats = append(sortedChats, sorterHelperIdx{
pos: position,
chatID: k,
})
}
sort.Sort(sortedChats)
for i, chatSortHelper := range sortedChats {
if o.config.CommunityDescription.Chats[chatSortHelper.chatID].Position != int32(i) {
o.config.CommunityDescription.Chats[chatSortHelper.chatID].Position = int32(i)
if changes.ChatsModified[chatSortHelper.chatID] != nil {
changes.ChatsModified[chatSortHelper.chatID].PositionModified = i
} else {
changes.ChatsModified[chatSortHelper.chatID] = &CommunityChatChanges{
MembersAdded: make(map[string]*protobuf.CommunityMember),
MembersRemoved: make(map[string]*protobuf.CommunityMember),
PositionModified: i,
}
}
}
}
}
func (o *Community) getCategoryChatCount(categoryID string) int {
result := 0
for _, chat := range o.config.CommunityDescription.Chats {
if chat.CategoryId == categoryID {
result = result + 1
}
}
return result
}
func (o *Community) DeleteCategory(categoryID string) (*CommunityChanges, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if o.config.PrivateKey == nil {
return nil, ErrNotAdmin
}
if _, exists := o.config.CommunityDescription.Categories[categoryID]; !exists {
return nil, ErrCategoryNotFound
}
changes := o.emptyCommunityChanges()
emptyCategoryChatCount := o.getCategoryChatCount("")
i := 0
for _, chat := range o.config.CommunityDescription.Chats {
if chat.CategoryId == categoryID {
i++
chat.CategoryId = ""
chat.Position = int32(emptyCategoryChatCount + i)
}
}
o.SortCategoryChats(changes, "")
delete(o.config.CommunityDescription.Categories, categoryID)
changes.CategoriesRemoved = append(changes.CategoriesRemoved, categoryID)
// Reorder
s := make(sortSlice, 0, len(o.config.CommunityDescription.Categories))
for _, cat := range o.config.CommunityDescription.Categories {
s = append(s, sorterHelperIdx{
pos: cat.Position,
catID: cat.CategoryId,
})
}
o.setModifiedCategories(changes, s)
o.increaseClock()
return changes, nil
}