2023-06-14 14:15:46 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-06-23 07:02:12 +00:00
|
|
|
if copy.IsMemberOwnerOrAdmin(pk) {
|
|
|
|
return nil, errors.New("attempt to kick an owner or admin of the community from the admin side")
|
2023-06-14 14:15:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
copy.removeMemberFromOrg(pk)
|
|
|
|
|
|
|
|
case protobuf.CommunityAdminEvent_COMMUNITY_MEMBER_BAN:
|
|
|
|
pk, err := common.HexToPubkey(adminEvent.MemberToAction)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-06-23 07:02:12 +00:00
|
|
|
if copy.IsMemberOwnerOrAdmin(pk) {
|
|
|
|
return nil, errors.New("attempt to ban an owner or admin of the community from the admin side")
|
2023-06-14 14:15:46 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|