github.com/status-im/status-go@v1.1.0/protocol/messenger_group_chat.go (about) 1 package protocol 2 3 import ( 4 "context" 5 "crypto/ecdsa" 6 "encoding/hex" 7 "errors" 8 9 "github.com/golang/protobuf/proto" 10 "go.uber.org/zap" 11 12 "github.com/status-im/status-go/eth-node/crypto" 13 "github.com/status-im/status-go/eth-node/types" 14 "github.com/status-im/status-go/images" 15 "github.com/status-im/status-go/protocol/common" 16 "github.com/status-im/status-go/protocol/protobuf" 17 "github.com/status-im/status-go/protocol/requests" 18 v1protocol "github.com/status-im/status-go/protocol/v1" 19 ) 20 21 var ErrGroupChatAddedContacts = errors.New("group-chat: can't add members who are not mutual contacts") 22 23 func (m *Messenger) validateAddedGroupMembers(members []string) error { 24 for _, memberPubkey := range members { 25 contactID, err := contactIDFromPublicKeyString(memberPubkey) 26 if err != nil { 27 return err 28 } 29 30 contact, _ := m.allContacts.Load(contactID) 31 if contact == nil || !contact.mutual() { 32 return ErrGroupChatAddedContacts 33 } 34 } 35 return nil 36 } 37 38 func (m *Messenger) CreateGroupChatWithMembers(ctx context.Context, name string, members []string) (*MessengerResponse, error) { 39 var convertedKeyMembers []string 40 for _, m := range members { 41 k, err := requests.ConvertCompressedToLegacyKey(m) 42 if err != nil { 43 return nil, err 44 } 45 convertedKeyMembers = append(convertedKeyMembers, k) 46 47 } 48 if err := m.validateAddedGroupMembers(convertedKeyMembers); err != nil { 49 return nil, err 50 } 51 52 var response MessengerResponse 53 logger := m.logger.With(zap.String("site", "CreateGroupChatWithMembers")) 54 logger.Info("Creating group chat", zap.String("name", name), zap.Any("members", convertedKeyMembers)) 55 chat := CreateGroupChat(m.getTimesource()) 56 57 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 58 59 group, err := v1protocol.NewGroupWithCreator(name, chat.Color, clock, m.identity) 60 if err != nil { 61 return nil, err 62 } 63 chat.LastClockValue = clock 64 65 chat.updateChatFromGroupMembershipChanges(group) 66 chat.Joined = int64(m.getTimesource().GetCurrentTime()) 67 68 clock, _ = chat.NextClockAndTimestamp(m.getTimesource()) 69 70 // Add members 71 if len(convertedKeyMembers) > 0 { 72 event := v1protocol.NewMembersAddedEvent(convertedKeyMembers, clock) 73 event.ChatID = chat.ID 74 err = event.Sign(m.identity) 75 if err != nil { 76 return nil, err 77 } 78 79 err = group.ProcessEvent(event) 80 if err != nil { 81 return nil, err 82 } 83 } 84 85 recipients, err := stringSliceToPublicKeys(group.Members()) 86 87 if err != nil { 88 return nil, err 89 } 90 91 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 92 if err != nil { 93 return nil, err 94 } 95 96 m.allChats.Store(chat.ID, &chat) 97 98 _, err = m.dispatchMessage(ctx, common.RawMessage{ 99 LocalChatID: chat.ID, 100 Payload: encodedMessage, 101 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 102 Recipients: recipients, 103 }) 104 105 if err != nil { 106 return nil, err 107 } 108 109 chat.updateChatFromGroupMembershipChanges(group) 110 111 return m.addMessagesAndChat(&chat, buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations), &response) 112 } 113 114 func (m *Messenger) CreateGroupChatFromInvitation(name string, chatID string, adminPK string) (*MessengerResponse, error) { 115 var response MessengerResponse 116 logger := m.logger.With(zap.String("site", "CreateGroupChatFromInvitation")) 117 logger.Info("Creating group chat from invitation", zap.String("name", name)) 118 chat := CreateGroupChat(m.getTimesource()) 119 chat.ID = chatID 120 chat.Name = name 121 chat.InvitationAdmin = adminPK 122 123 response.AddChat(&chat) 124 125 return &response, m.saveChat(&chat) 126 } 127 128 type removeMembersFromGroupChatResponse struct { 129 oldRecipients []*ecdsa.PublicKey 130 group *v1protocol.Group 131 encodedProtobuf []byte 132 } 133 134 func (m *Messenger) removeMembersFromGroupChat(ctx context.Context, chat *Chat, members []string) (*removeMembersFromGroupChatResponse, error) { 135 chatID := chat.ID 136 logger := m.logger.With(zap.String("site", "RemoveMembersFromGroupChat")) 137 logger.Info("Removing members form group chat", zap.String("chatID", chatID), zap.Any("members", members)) 138 group, err := newProtocolGroupFromChat(chat) 139 if err != nil { 140 return nil, err 141 } 142 143 // We save the initial recipients as we want to send updates to also 144 // the members kicked out 145 oldRecipients, err := stringSliceToPublicKeys(group.Members()) 146 if err != nil { 147 return nil, err 148 } 149 150 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 151 152 for _, member := range members { 153 // Remove member 154 event := v1protocol.NewMemberRemovedEvent(member, clock) 155 event.ChatID = chat.ID 156 err = event.Sign(m.identity) 157 if err != nil { 158 return nil, err 159 } 160 161 err = group.ProcessEvent(event) 162 if err != nil { 163 return nil, err 164 } 165 } 166 167 encoded, err := m.sender.EncodeMembershipUpdate(group, nil) 168 if err != nil { 169 return nil, err 170 } 171 172 return &removeMembersFromGroupChatResponse{ 173 oldRecipients: oldRecipients, 174 group: group, 175 encodedProtobuf: encoded, 176 }, nil 177 } 178 179 func (m *Messenger) RemoveMembersFromGroupChat(ctx context.Context, chatID string, members []string) (*MessengerResponse, error) { 180 var response MessengerResponse 181 182 chat, ok := m.allChats.Load(chatID) 183 if !ok { 184 return nil, ErrChatNotFound 185 } 186 187 removeMembersResponse, err := m.removeMembersFromGroupChat(ctx, chat, members) 188 if err != nil { 189 return nil, err 190 } 191 192 _, err = m.dispatchMessage(ctx, common.RawMessage{ 193 LocalChatID: chat.ID, 194 Payload: removeMembersResponse.encodedProtobuf, 195 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 196 Recipients: removeMembersResponse.oldRecipients, 197 }) 198 if err != nil { 199 return nil, err 200 } 201 202 chat.updateChatFromGroupMembershipChanges(removeMembersResponse.group) 203 204 return m.addMessagesAndChat(chat, buildSystemMessages(chat.MembershipUpdates, m.systemMessagesTranslations), &response) 205 } 206 207 func (m *Messenger) AddMembersToGroupChat(ctx context.Context, chatID string, members []string) (*MessengerResponse, error) { 208 if err := m.validateAddedGroupMembers(members); err != nil { 209 return nil, err 210 } 211 212 var response MessengerResponse 213 logger := m.logger.With(zap.String("site", "AddMembersFromGroupChat")) 214 logger.Info("Adding members form group chat", zap.String("chatID", chatID), zap.Any("members", members)) 215 chat, ok := m.allChats.Load(chatID) 216 if !ok { 217 return nil, ErrChatNotFound 218 } 219 220 group, err := newProtocolGroupFromChat(chat) 221 if err != nil { 222 return nil, err 223 } 224 225 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 226 // Add members 227 event := v1protocol.NewMembersAddedEvent(members, clock) 228 event.ChatID = chat.ID 229 err = event.Sign(m.identity) 230 if err != nil { 231 return nil, err 232 } 233 234 //approve invitations 235 for _, member := range members { 236 logger.Info("ApproveInvitationByChatIdAndFrom", zap.String("chatID", chatID), zap.Any("member", member)) 237 238 groupChatInvitation := &GroupChatInvitation{ 239 GroupChatInvitation: &protobuf.GroupChatInvitation{ 240 ChatId: chat.ID, 241 }, 242 From: member, 243 } 244 245 groupChatInvitation, err = m.persistence.InvitationByID(groupChatInvitation.ID()) 246 if err != nil && err != common.ErrRecordNotFound { 247 return nil, err 248 } 249 if groupChatInvitation != nil { 250 groupChatInvitation.State = protobuf.GroupChatInvitation_APPROVED 251 252 err := m.persistence.SaveInvitation(groupChatInvitation) 253 if err != nil { 254 return nil, err 255 } 256 response.Invitations = append(response.Invitations, groupChatInvitation) 257 } 258 } 259 260 err = group.ProcessEvent(event) 261 if err != nil { 262 return nil, err 263 } 264 265 recipients, err := stringSliceToPublicKeys(group.Members()) 266 if err != nil { 267 return nil, err 268 } 269 270 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 271 if err != nil { 272 return nil, err 273 } 274 _, err = m.dispatchMessage(ctx, common.RawMessage{ 275 LocalChatID: chat.ID, 276 Payload: encodedMessage, 277 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 278 Recipients: recipients, 279 }) 280 281 if err != nil { 282 return nil, err 283 } 284 285 chat.updateChatFromGroupMembershipChanges(group) 286 287 return m.addMessagesAndChat(chat, buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations), &response) 288 } 289 290 func (m *Messenger) ChangeGroupChatName(ctx context.Context, chatID string, name string) (*MessengerResponse, error) { 291 logger := m.logger.With(zap.String("site", "ChangeGroupChatName")) 292 logger.Info("Changing group chat name", zap.String("chatID", chatID), zap.String("name", name)) 293 294 chat, ok := m.allChats.Load(chatID) 295 if !ok { 296 return nil, ErrChatNotFound 297 } 298 299 group, err := newProtocolGroupFromChat(chat) 300 if err != nil { 301 return nil, err 302 } 303 304 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 305 // Change name 306 event := v1protocol.NewNameChangedEvent(name, clock) 307 event.ChatID = chat.ID 308 err = event.Sign(m.identity) 309 if err != nil { 310 return nil, err 311 } 312 313 // Update in-memory group 314 err = group.ProcessEvent(event) 315 if err != nil { 316 return nil, err 317 } 318 319 recipients, err := stringSliceToPublicKeys(group.Members()) 320 if err != nil { 321 return nil, err 322 } 323 324 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 325 if err != nil { 326 return nil, err 327 } 328 _, err = m.dispatchMessage(ctx, common.RawMessage{ 329 LocalChatID: chat.ID, 330 Payload: encodedMessage, 331 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 332 Recipients: recipients, 333 }) 334 335 if err != nil { 336 return nil, err 337 } 338 339 chat.updateChatFromGroupMembershipChanges(group) 340 341 var response MessengerResponse 342 343 return m.addMessagesAndChat(chat, buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations), &response) 344 } 345 346 func (m *Messenger) EditGroupChat(ctx context.Context, chatID string, name string, color string, image images.CroppedImage) (*MessengerResponse, error) { 347 logger := m.logger.With(zap.String("site", "EditGroupChat")) 348 logger.Info("Editing group chat details", zap.String("chatID", chatID), zap.String("name", name), zap.String("color", color)) 349 350 chat, ok := m.allChats.Load(chatID) 351 if !ok { 352 return nil, ErrChatNotFound 353 } 354 355 group, err := newProtocolGroupFromChat(chat) 356 if err != nil { 357 return nil, err 358 } 359 360 signAndProcessEvent := func(m *Messenger, event *v1protocol.MembershipUpdateEvent) error { 361 err := event.Sign(m.identity) 362 if err != nil { 363 return err 364 } 365 366 err = group.ProcessEvent(*event) 367 if err != nil { 368 return err 369 } 370 371 return nil 372 } 373 374 var events []v1protocol.MembershipUpdateEvent 375 376 if chat.Name != name { 377 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 378 event := v1protocol.NewNameChangedEvent(name, clock) 379 event.ChatID = chat.ID 380 err = signAndProcessEvent(m, &event) 381 if err != nil { 382 return nil, err 383 } 384 events = append(events, event) 385 } 386 387 if chat.Color != color { 388 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 389 event := v1protocol.NewColorChangedEvent(color, clock) 390 event.ChatID = chat.ID 391 err = signAndProcessEvent(m, &event) 392 if err != nil { 393 return nil, err 394 } 395 events = append(events, event) 396 } 397 398 if len(image.ImagePath) > 0 { 399 payload, err := images.OpenAndAdjustImage(image, true) 400 401 if err != nil { 402 return nil, err 403 } 404 405 // prepare event 406 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 407 event := v1protocol.NewImageChangedEvent(payload, clock) 408 event.ChatID = chat.ID 409 err = signAndProcessEvent(m, &event) 410 if err != nil { 411 return nil, err 412 } 413 events = append(events, event) 414 } 415 416 recipients, err := stringSliceToPublicKeys(group.Members()) 417 if err != nil { 418 return nil, err 419 } 420 421 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 422 if err != nil { 423 return nil, err 424 } 425 _, err = m.dispatchMessage(ctx, common.RawMessage{ 426 LocalChatID: chat.ID, 427 Payload: encodedMessage, 428 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 429 Recipients: recipients, 430 }) 431 432 if err != nil { 433 return nil, err 434 } 435 436 chat.updateChatFromGroupMembershipChanges(group) 437 438 var response MessengerResponse 439 440 return m.addMessagesAndChat(chat, buildSystemMessages(events, m.systemMessagesTranslations), &response) 441 } 442 443 func (m *Messenger) SendGroupChatInvitationRequest(ctx context.Context, chatID string, adminPK string, 444 message string) (*MessengerResponse, error) { 445 logger := m.logger.With(zap.String("site", "SendGroupChatInvitationRequest")) 446 logger.Info("Sending group chat invitation request", zap.String("chatID", chatID), 447 zap.String("adminPK", adminPK), zap.String("message", message)) 448 449 var response MessengerResponse 450 451 // Get chat and clock 452 chat, ok := m.allChats.Load(chatID) 453 if !ok { 454 return nil, ErrChatNotFound 455 } 456 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 457 458 invitationR := &GroupChatInvitation{ 459 GroupChatInvitation: &protobuf.GroupChatInvitation{ 460 Clock: clock, 461 ChatId: chatID, 462 IntroductionMessage: message, 463 State: protobuf.GroupChatInvitation_REQUEST, 464 }, 465 From: types.EncodeHex(crypto.FromECDSAPub(&m.identity.PublicKey)), 466 } 467 468 encodedMessage, err := proto.Marshal(invitationR.GetProtobuf()) 469 if err != nil { 470 return nil, err 471 } 472 473 spec := common.RawMessage{ 474 LocalChatID: adminPK, 475 Payload: encodedMessage, 476 MessageType: protobuf.ApplicationMetadataMessage_GROUP_CHAT_INVITATION, 477 ResendType: common.ResendTypeDataSync, 478 } 479 480 pkey, err := hex.DecodeString(adminPK[2:]) 481 if err != nil { 482 return nil, err 483 } 484 // Safety check, make sure is well formed 485 adminpk, err := crypto.UnmarshalPubkey(pkey) 486 if err != nil { 487 return nil, err 488 } 489 490 id, err := m.sender.SendPrivate(ctx, adminpk, &spec) 491 if err != nil { 492 return nil, err 493 } 494 495 spec.ID = types.EncodeHex(id) 496 spec.SendCount++ 497 err = m.persistence.SaveRawMessage(&spec) 498 if err != nil { 499 return nil, err 500 } 501 502 response.Invitations = []*GroupChatInvitation{invitationR} 503 504 err = m.persistence.SaveInvitation(invitationR) 505 if err != nil { 506 return nil, err 507 } 508 509 return &response, nil 510 } 511 512 func (m *Messenger) GetGroupChatInvitations() ([]*GroupChatInvitation, error) { 513 return m.persistence.GetGroupChatInvitations() 514 } 515 516 func (m *Messenger) SendGroupChatInvitationRejection(ctx context.Context, invitationRequestID string) (*MessengerResponse, error) { 517 logger := m.logger.With(zap.String("site", "SendGroupChatInvitationRejection")) 518 logger.Info("Sending group chat invitation reject", zap.String("invitationRequestID", invitationRequestID)) 519 520 invitationR, err := m.persistence.InvitationByID(invitationRequestID) 521 if err != nil { 522 return nil, err 523 } 524 525 invitationR.State = protobuf.GroupChatInvitation_REJECTED 526 527 // Get chat and clock 528 chat, ok := m.allChats.Load(invitationR.ChatId) 529 if !ok { 530 return nil, ErrChatNotFound 531 } 532 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 533 534 invitationR.Clock = clock 535 536 encodedMessage, err := proto.Marshal(invitationR.GetProtobuf()) 537 if err != nil { 538 return nil, err 539 } 540 541 spec := common.RawMessage{ 542 LocalChatID: invitationR.From, 543 Payload: encodedMessage, 544 MessageType: protobuf.ApplicationMetadataMessage_GROUP_CHAT_INVITATION, 545 ResendType: common.ResendTypeDataSync, 546 } 547 548 pkey, err := hex.DecodeString(invitationR.From[2:]) 549 if err != nil { 550 return nil, err 551 } 552 // Safety check, make sure is well formed 553 userpk, err := crypto.UnmarshalPubkey(pkey) 554 if err != nil { 555 return nil, err 556 } 557 558 id, err := m.sender.SendPrivate(ctx, userpk, &spec) 559 if err != nil { 560 return nil, err 561 } 562 563 spec.ID = types.EncodeHex(id) 564 spec.SendCount++ 565 err = m.persistence.SaveRawMessage(&spec) 566 if err != nil { 567 return nil, err 568 } 569 570 var response MessengerResponse 571 572 response.Invitations = []*GroupChatInvitation{invitationR} 573 574 err = m.persistence.SaveInvitation(invitationR) 575 if err != nil { 576 return nil, err 577 } 578 579 return &response, nil 580 } 581 582 func (m *Messenger) AddAdminsToGroupChat(ctx context.Context, chatID string, members []string) (*MessengerResponse, error) { 583 var response MessengerResponse 584 logger := m.logger.With(zap.String("site", "AddAdminsToGroupChat")) 585 logger.Info("Add admins to group chat", zap.String("chatID", chatID), zap.Any("members", members)) 586 587 chat, ok := m.allChats.Load(chatID) 588 if !ok { 589 return nil, ErrChatNotFound 590 } 591 592 group, err := newProtocolGroupFromChat(chat) 593 if err != nil { 594 return nil, err 595 } 596 597 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 598 // Add members 599 event := v1protocol.NewAdminsAddedEvent(members, clock) 600 event.ChatID = chat.ID 601 err = event.Sign(m.identity) 602 if err != nil { 603 return nil, err 604 } 605 606 err = group.ProcessEvent(event) 607 if err != nil { 608 return nil, err 609 } 610 611 recipients, err := stringSliceToPublicKeys(group.Members()) 612 if err != nil { 613 return nil, err 614 } 615 616 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 617 if err != nil { 618 return nil, err 619 } 620 _, err = m.dispatchMessage(ctx, common.RawMessage{ 621 LocalChatID: chat.ID, 622 Payload: encodedMessage, 623 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 624 Recipients: recipients, 625 }) 626 627 if err != nil { 628 return nil, err 629 } 630 631 chat.updateChatFromGroupMembershipChanges(group) 632 return m.addMessagesAndChat(chat, buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations), &response) 633 } 634 635 // Kept only for backward compatibility (auto-join), explicit join has been removed 636 func (m *Messenger) ConfirmJoiningGroup(ctx context.Context, chatID string) (*MessengerResponse, error) { 637 var response MessengerResponse 638 639 chat, ok := m.allChats.Load(chatID) 640 if !ok { 641 return nil, ErrChatNotFound 642 } 643 644 _, err := m.Join(chat) 645 if err != nil { 646 return nil, err 647 } 648 649 group, err := newProtocolGroupFromChat(chat) 650 if err != nil { 651 return nil, err 652 } 653 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 654 event := v1protocol.NewMemberJoinedEvent( 655 clock, 656 ) 657 event.ChatID = chat.ID 658 err = event.Sign(m.identity) 659 if err != nil { 660 return nil, err 661 } 662 663 err = group.ProcessEvent(event) 664 if err != nil { 665 return nil, err 666 } 667 668 recipients, err := stringSliceToPublicKeys(group.Members()) 669 if err != nil { 670 return nil, err 671 } 672 673 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 674 if err != nil { 675 return nil, err 676 } 677 _, err = m.dispatchMessage(ctx, common.RawMessage{ 678 LocalChatID: chat.ID, 679 Payload: encodedMessage, 680 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 681 Recipients: recipients, 682 }) 683 if err != nil { 684 return nil, err 685 } 686 687 chat.updateChatFromGroupMembershipChanges(group) 688 chat.Joined = int64(m.getTimesource().GetCurrentTime()) 689 690 return m.addMessagesAndChat(chat, buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations), &response) 691 } 692 693 func (m *Messenger) leaveGroupChat(ctx context.Context, response *MessengerResponse, chatID string, remove bool, shouldBeSynced bool) (*MessengerResponse, error) { 694 chat, ok := m.allChats.Load(chatID) 695 if !ok { 696 return nil, ErrChatNotFound 697 } 698 699 amIMember := chat.HasMember(common.PubkeyToHex(&m.identity.PublicKey)) 700 701 if amIMember { 702 chat.RemoveMember(common.PubkeyToHex(&m.identity.PublicKey)) 703 704 group, err := newProtocolGroupFromChat(chat) 705 if err != nil { 706 return nil, err 707 } 708 clock, _ := chat.NextClockAndTimestamp(m.getTimesource()) 709 event := v1protocol.NewMemberRemovedEvent( 710 contactIDFromPublicKey(&m.identity.PublicKey), 711 clock, 712 ) 713 event.ChatID = chat.ID 714 err = event.Sign(m.identity) 715 if err != nil { 716 return nil, err 717 } 718 719 err = group.ProcessEvent(event) 720 if err != nil { 721 return nil, err 722 } 723 724 recipients, err := stringSliceToPublicKeys(group.Members()) 725 if err != nil { 726 return nil, err 727 } 728 729 encodedMessage, err := m.sender.EncodeMembershipUpdate(group, nil) 730 if err != nil { 731 return nil, err 732 } 733 734 // shouldBeSynced is false if we got here because a synced client has already 735 // sent the leave group message. In that case we don't need to send it again. 736 if shouldBeSynced { 737 _, err = m.dispatchMessage(ctx, common.RawMessage{ 738 LocalChatID: chat.ID, 739 Payload: encodedMessage, 740 MessageType: protobuf.ApplicationMetadataMessage_MEMBERSHIP_UPDATE_MESSAGE, 741 Recipients: recipients, 742 }) 743 if err != nil { 744 return nil, err 745 } 746 } 747 748 chat.updateChatFromGroupMembershipChanges(group) 749 response.AddMessages(buildSystemMessages([]v1protocol.MembershipUpdateEvent{event}, m.systemMessagesTranslations)) 750 err = m.persistence.SaveMessages(response.Messages()) 751 if err != nil { 752 return nil, err 753 } 754 } 755 756 if remove { 757 chat.Active = false 758 } 759 760 if remove && shouldBeSynced { 761 err := m.syncChatRemoving(ctx, chat.ID, m.dispatchMessage) 762 if err != nil { 763 return nil, err 764 } 765 } 766 767 response.AddChat(chat) 768 769 return response, m.saveChat(chat) 770 } 771 772 func (m *Messenger) LeaveGroupChat(ctx context.Context, chatID string, remove bool) (*MessengerResponse, error) { 773 _, err := m.DismissAllActivityCenterNotificationsFromChatID(ctx, chatID, m.GetCurrentTimeInMillis()) 774 if err != nil { 775 return nil, err 776 } 777 var response MessengerResponse 778 return m.leaveGroupChat(ctx, &response, chatID, remove, true) 779 } 780 781 // Decline all pending group invites from a user 782 func (m *Messenger) DeclineAllPendingGroupInvitesFromUser(ctx context.Context, response *MessengerResponse, userPublicKey string) (*MessengerResponse, error) { 783 784 // Decline group invites from active chats 785 chats, err := m.persistence.Chats() 786 if err != nil { 787 return nil, err 788 } 789 790 for _, chat := range chats { 791 if chat.ChatType == ChatTypePrivateGroupChat && 792 chat.ReceivedInvitationAdmin == userPublicKey && 793 chat.Joined == 0 && chat.Active { 794 response, err = m.leaveGroupChat(ctx, response, chat.ID, true, true) 795 if err != nil { 796 return nil, err 797 } 798 } 799 } 800 801 // Decline group invites from activity center notifications 802 notifications, err := m.AcceptActivityCenterNotificationsForInvitesFromUser(ctx, userPublicKey, m.GetCurrentTimeInMillis()) 803 if err != nil { 804 return nil, err 805 } 806 807 for _, notification := range notifications { 808 response, err = m.leaveGroupChat(ctx, response, notification.ChatID, true, true) 809 if err != nil { 810 return nil, err 811 } 812 } 813 return response, nil 814 }