status-go/protocol/communities/community_admin_event.go

347 lines
12 KiB
Go

package communities
import (
"errors"
"github.com/status-im/status-go/protocol/common"
"github.com/status-im/status-go/protocol/protobuf"
)
func (o *Community) ToCreateChannelAdminEvent(channelID string, channel *protobuf.CommunityChat) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_CREATE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
}
}
func (o *Community) ToEditChannelAdminEvent(channelID string, channel *protobuf.CommunityChat) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_EDIT,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
Channel: channel,
},
}
}
func (o *Community) ToDeleteChannelAdminEvent(channelID string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_DELETE,
ChannelData: &protobuf.ChannelData{
ChannelId: channelID,
},
}
}
func (o *Community) ToReorderChannelAdminEvent(categoryID string, channelID string, position int) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_REORDER,
ChannelData: &protobuf.ChannelData{
CategoryId: categoryID,
ChannelId: channelID,
Position: int32(position),
},
}
}
func (o *Community) ToCreateCategoryAdminEvent(categoryID string, categoryName string, channelsIds []string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_CREATE,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToEditCategoryAdminEvent(categoryID string, categoryName string, channelsIds []string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_EDIT,
CategoryData: &protobuf.CategoryData{
Name: categoryName,
CategoryId: categoryID,
ChannelsIds: channelsIds,
},
}
}
func (o *Community) ToDeleteCategoryAdminEvent(categoryID string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_DELETE,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
},
}
}
func (o *Community) ToReorderCategoryAdminEvent(categoryID string, position int) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_REORDER,
CategoryData: &protobuf.CategoryData{
CategoryId: categoryID,
Position: int32(position),
},
}
}
func (o *Community) ToBanCommunityMemberAdminEvent(pubkey string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_BAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToUnbanCommunityMemberAdminEvent(pubkey string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_UNBAN,
MemberToAction: pubkey,
}
}
func (o *Community) ToKickCommunityMemberAdminEvent(pubkey string) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_KICK,
MemberToAction: pubkey,
}
}
func (o *Community) ToCommunityEditAdminEvent() *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_EDIT,
CommunityConfig: &protobuf.CommunityConfig{
Identity: o.Identity(),
Permissions: o.Permissions(),
AdminSettings: o.AdminSettings(),
IntroMessage: o.IntroMessage(),
OutroMessage: o.OutroMessage(),
Tags: o.TagsRaw(),
},
}
}
func (o *Community) ToCommunityBecomeMemberTokenPermissionChangeAdminEvent() *protobuf.CommunityAdminEvent {
tokenPermissions := make(map[string]*protobuf.CommunityTokenPermission)
for _, tp := range o.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER) {
tokenPermissions[tp.Id] = tp
}
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE,
TokenPermissions: tokenPermissions,
}
}
func (o *Community) ToCommunityBecomeMemberTokenPermissionDeleteAdminEvent() *protobuf.CommunityAdminEvent {
tokenPermissions := make(map[string]*protobuf.CommunityTokenPermission)
for _, tp := range o.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER) {
tokenPermissions[tp.Id] = tp
}
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE,
TokenPermissions: tokenPermissions,
}
}
func (o *Community) ToCommunityRequestToJoinAcceptAdminEvent(changes *CommunityAdminEventChanges) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT,
MembersAdded: changes.MembersAdded,
AcceptedRequestsToJoin: changes.AcceptedRequestsToJoin,
}
}
func (o *Community) ToCommunityRequestToJoinRejectAdminEvent(changes *CommunityAdminEventChanges) *protobuf.CommunityAdminEvent {
return &protobuf.CommunityAdminEvent{
Clock: o.Clock(),
CommunityId: o.ID(),
Type: protobuf.CommunityAdminEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT,
RejectedRequestsToJoin: changes.RejectedRequestsToJoin,
}
}
func (o *Community) PatchCommunityDescriptionByAdminEvent(adminEvent *protobuf.CommunityAdminEvent) (*protobuf.CommunityDescription, error) {
o.mutex.Lock()
defer o.mutex.Unlock()
if adminEvent.Clock <= o.config.CommunityDescription.Clock {
return nil, errors.New("clock for admin event is outdated")
}
if adminEvent.Type == protobuf.CommunityAdminEvent_UNKNOWN {
return nil, errors.New("unknown admin event")
}
// create a deep copy of current community so we can patch CommunityDescription
copy := o.createDeepCopy()
copy.config.CommunityDescription.Clock = adminEvent.Clock
switch adminEvent.Type {
case protobuf.CommunityAdminEvent_COMMUNITY_EDIT:
if adminEvent.CommunityConfig == nil || adminEvent.CommunityConfig.Identity == nil ||
adminEvent.CommunityConfig.Permissions == nil || adminEvent.CommunityConfig.AdminSettings == nil {
return nil, errors.New("invalid config change admin event")
}
copy.config.CommunityDescription.Identity = adminEvent.CommunityConfig.Identity
copy.config.CommunityDescription.Permissions = adminEvent.CommunityConfig.Permissions
copy.config.CommunityDescription.AdminSettings = adminEvent.CommunityConfig.AdminSettings
copy.config.CommunityDescription.IntroMessage = adminEvent.CommunityConfig.IntroMessage
copy.config.CommunityDescription.OutroMessage = adminEvent.CommunityConfig.OutroMessage
copy.config.CommunityDescription.Tags = adminEvent.CommunityConfig.Tags
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_CHANGE:
prevPermissions := copy.TokenPermissionsByType(protobuf.CommunityTokenPermission_BECOME_MEMBER)
newPermissions := adminEvent.TokenPermissions
if len(newPermissions) < len(prevPermissions) {
// we only handle additions and update in this event type
break
}
if len(newPermissions) > len(prevPermissions) {
copy.addBecomeMemberTokenPermissions(newPermissions)
break
}
// update existing permissions
copy.updateTokenPermissions(newPermissions)
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_TOKEN_PERMISSION_DELETE:
copy.deleteBecomeMemberTokenPermissions(adminEvent.TokenPermissions)
case protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_CREATE:
_, err := copy.createCategory(adminEvent.CategoryData.CategoryId, adminEvent.CategoryData.Name, adminEvent.CategoryData.ChannelsIds)
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_DELETE:
_, err := copy.deleteCategory(adminEvent.CategoryData.CategoryId)
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_EDIT:
_, err := copy.editCategory(adminEvent.CategoryData.CategoryId, adminEvent.CategoryData.Name, adminEvent.CategoryData.ChannelsIds)
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_CREATE:
err := copy.createChat(adminEvent.ChannelData.ChannelId, adminEvent.ChannelData.Channel)
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_DELETE:
copy.deleteChat(adminEvent.ChannelData.ChannelId)
case protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_EDIT:
err := copy.editChat(adminEvent.ChannelData.ChannelId, adminEvent.ChannelData.Channel)
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CHANNEL_REORDER:
_, err := copy.reorderChat(adminEvent.ChannelData.CategoryId, adminEvent.ChannelData.ChannelId, int(adminEvent.ChannelData.Position))
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_CATEGORY_REORDER:
_, err := copy.reorderCategories(adminEvent.CategoryData.CategoryId, int(adminEvent.CategoryData.Position))
if err != nil {
return nil, err
}
case protobuf.CommunityAdminEvent_COMMUNITY_REQUEST_TO_JOIN_ACCEPT:
for pkString, addedMember := range adminEvent.MembersAdded {
pk, err := common.HexToPubkey(pkString)
if err != nil {
return nil, err
}
if !copy.HasMember(pk) {
copy.addCommunityMember(pk, addedMember)
}
}
case protobuf.CommunityAdminEvent_COMMUNITY_REQUEST_TO_JOIN_REJECT:
// Do not remove this case!
//
// if we've received a rejected request to join, there's nothing that needs
// to be done on the `Community`.
//
// However, we need to leave this case here, otherwise it'll end up in
// the default case, which will error out
break
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_KICK:
pk, err := common.HexToPubkey(adminEvent.MemberToAction)
if err != nil {
return nil, err
}
if copy.IsMemberOwnerOrAdmin(pk) {
return nil, errors.New("attempt to kick an owner or admin of the community from the admin side")
}
copy.removeMemberFromOrg(pk)
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_BAN:
pk, err := common.HexToPubkey(adminEvent.MemberToAction)
if err != nil {
return nil, err
}
if copy.IsMemberOwnerOrAdmin(pk) {
return nil, errors.New("attempt to ban an owner or admin of the community from the admin side")
}
copy.banUserFromCommunity(pk)
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_UNBAN:
pk, err := common.HexToPubkey(adminEvent.MemberToAction)
if err != nil {
return nil, err
}
copy.unbanUserFromCommunity(pk)
default:
return nil, errors.New("unknown admin community event")
}
return copy.config.CommunityDescription, nil
}