Send notification when your contact invites you to group chat (#2361)
This commit is contained in:
parent
da63894a5a
commit
d65494d1f8
|
@ -465,6 +465,9 @@ func (m *Message) GetSimplifiedText(identity string, canonicalNames map[string]s
|
||||||
if m.ContentType == protobuf.ChatMessage_COMMUNITY {
|
if m.ContentType == protobuf.ChatMessage_COMMUNITY {
|
||||||
return "Community", nil
|
return "Community", nil
|
||||||
}
|
}
|
||||||
|
if m.ContentType == protobuf.ChatMessage_SYSTEM_MESSAGE_CONTENT_PRIVATE_GROUP {
|
||||||
|
return "Group", nil
|
||||||
|
}
|
||||||
|
|
||||||
if m.ParsedTextAst == nil {
|
if m.ParsedTextAst == nil {
|
||||||
err := m.PrepareContent(identity)
|
err := m.PrepareContent(identity)
|
||||||
|
|
|
@ -74,6 +74,15 @@ func NewCommunityRequestToJoinNotification(id string, community *communities.Com
|
||||||
return body.toCommunityRequestToJoinNotification(id)
|
return body.toCommunityRequestToJoinNotification(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewPrivateGroupInviteNotification(id string, chat *Chat, contact *Contact) *localnotifications.Notification {
|
||||||
|
body := &NotificationBody{
|
||||||
|
Chat: chat,
|
||||||
|
Contact: contact,
|
||||||
|
}
|
||||||
|
|
||||||
|
return body.toPrivateGroupInviteNotification(id)
|
||||||
|
}
|
||||||
|
|
||||||
func (n NotificationBody) toMessageNotification(id string, contacts *contactMap) (*localnotifications.Notification, error) {
|
func (n NotificationBody) toMessageNotification(id string, contacts *contactMap) (*localnotifications.Notification, error) {
|
||||||
var title string
|
var title string
|
||||||
if n.Chat.PrivateGroupChat() || n.Chat.Public() || n.Chat.CommunityChat() {
|
if n.Chat.PrivateGroupChat() || n.Chat.Public() || n.Chat.CommunityChat() {
|
||||||
|
@ -123,6 +132,24 @@ func (n NotificationBody) toMessageNotification(id string, contacts *contactMap)
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (n NotificationBody) toPrivateGroupInviteNotification(id string) *localnotifications.Notification {
|
||||||
|
return &localnotifications.Notification{
|
||||||
|
ID: gethcommon.HexToHash(id),
|
||||||
|
Body: n,
|
||||||
|
Title: n.Contact.CanonicalName() + " invited you to " + n.Chat.Name,
|
||||||
|
Message: n.Contact.CanonicalName() + " wants you to join group " + n.Chat.Name,
|
||||||
|
BodyType: localnotifications.TypeMessage,
|
||||||
|
Category: localnotifications.CategoryGroupInvite,
|
||||||
|
Deeplink: n.Chat.DeepLink(),
|
||||||
|
Author: localnotifications.NotificationAuthor{
|
||||||
|
Name: n.Contact.CanonicalName(),
|
||||||
|
Icon: n.Contact.CanonicalImage(),
|
||||||
|
ID: n.Contact.ID,
|
||||||
|
},
|
||||||
|
Image: "",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (n NotificationBody) toCommunityRequestToJoinNotification(id string) *localnotifications.Notification {
|
func (n NotificationBody) toCommunityRequestToJoinNotification(id string) *localnotifications.Notification {
|
||||||
return &localnotifications.Notification{
|
return &localnotifications.Notification{
|
||||||
ID: gethcommon.HexToHash(id),
|
ID: gethcommon.HexToHash(id),
|
||||||
|
|
|
@ -60,6 +60,7 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c
|
||||||
//if chat.InvitationAdmin exists means we are waiting for invitation request approvement, and in that case
|
//if chat.InvitationAdmin exists means we are waiting for invitation request approvement, and in that case
|
||||||
//we need to create a new chat instance like we don't have a chat and just use a regular invitation flow
|
//we need to create a new chat instance like we don't have a chat and just use a regular invitation flow
|
||||||
waitingForApproval := chat != nil && len(chat.InvitationAdmin) > 0
|
waitingForApproval := chat != nil && len(chat.InvitationAdmin) > 0
|
||||||
|
ourKey := contactIDFromPublicKey(&m.identity.PublicKey)
|
||||||
|
|
||||||
if chat == nil || waitingForApproval {
|
if chat == nil || waitingForApproval {
|
||||||
if len(message.Events) == 0 {
|
if len(message.Events) == 0 {
|
||||||
|
@ -96,7 +97,6 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
ourKey := contactIDFromPublicKey(&m.identity.PublicKey)
|
|
||||||
// A new chat must contain us
|
// A new chat must contain us
|
||||||
if !group.IsMember(ourKey) {
|
if !group.IsMember(ourKey) {
|
||||||
return errors.New("can't create a new group chat without us being a member")
|
return errors.New("can't create a new group chat without us being a member")
|
||||||
|
@ -107,6 +107,16 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c
|
||||||
isActive := messageState.CurrentMessageState.Contact.IsAdded() || messageState.CurrentMessageState.Contact.ID == ourKey || waitingForApproval
|
isActive := messageState.CurrentMessageState.Contact.IsAdded() || messageState.CurrentMessageState.Contact.ID == ourKey || waitingForApproval
|
||||||
newChat.Active = isActive
|
newChat.Active = isActive
|
||||||
chat = &newChat
|
chat = &newChat
|
||||||
|
|
||||||
|
chat.updateChatFromGroupMembershipChanges(group)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get group creator")
|
||||||
|
}
|
||||||
|
|
||||||
|
if chat.Active && messageState.CurrentMessageState.Contact.ID != ourKey {
|
||||||
|
messageState.Response.AddNotification(NewPrivateGroupInviteNotification(chat.ID, chat, messageState.CurrentMessageState.Contact))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
existingGroup, err := newProtocolGroupFromChat(chat)
|
existingGroup, err := newProtocolGroupFromChat(chat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -121,9 +131,8 @@ func (m *Messenger) HandleMembershipUpdate(messageState *ReceivedMessageState, c
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to create a group with new membership updates")
|
return errors.Wrap(err, "failed to create a group with new membership updates")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
chat.updateChatFromGroupMembershipChanges(group)
|
chat.updateChatFromGroupMembershipChanges(group)
|
||||||
|
}
|
||||||
|
|
||||||
if !chat.Active {
|
if !chat.Active {
|
||||||
m.createMessageNotification(chat, messageState)
|
m.createMessageNotification(chat, messageState)
|
||||||
|
@ -181,6 +190,7 @@ func (m *Messenger) createMessageNotification(chat *Chat, messageState *Received
|
||||||
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
|
Timestamp: messageState.CurrentMessageState.WhisperTimestamp,
|
||||||
ChatID: chat.ID,
|
ChatID: chat.ID,
|
||||||
}
|
}
|
||||||
|
|
||||||
err := m.addActivityCenterNotification(messageState, notification)
|
err := m.addActivityCenterNotification(messageState, notification)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
m.logger.Warn("failed to create activity center notification", zap.Error(err))
|
m.logger.Warn("failed to create activity center notification", zap.Error(err))
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
package protocol
|
package protocol
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/suite"
|
"github.com/stretchr/testify/suite"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
|
||||||
|
gethbridge "github.com/status-im/status-go/eth-node/bridge/geth"
|
||||||
|
"github.com/status-im/status-go/eth-node/crypto"
|
||||||
|
"github.com/status-im/status-go/eth-node/types"
|
||||||
|
"github.com/status-im/status-go/protocol/protobuf"
|
||||||
|
"github.com/status-im/status-go/protocol/tt"
|
||||||
v1protocol "github.com/status-im/status-go/protocol/v1"
|
v1protocol "github.com/status-im/status-go/protocol/v1"
|
||||||
|
localnotifications "github.com/status-im/status-go/services/local-notifications"
|
||||||
|
"github.com/status-im/status-go/waku"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestEventToSystemMessageSuite(t *testing.T) {
|
func TestEventToSystemMessageSuite(t *testing.T) {
|
||||||
|
@ -14,6 +23,37 @@ func TestEventToSystemMessageSuite(t *testing.T) {
|
||||||
|
|
||||||
type EventToSystemMessageSuite struct {
|
type EventToSystemMessageSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
m *Messenger // main instance of Messenger
|
||||||
|
privateKey *ecdsa.PrivateKey // private key for the main instance of Messenger
|
||||||
|
// If one wants to send messages between different instances of Messenger,
|
||||||
|
// a single waku service should be shared.
|
||||||
|
shh types.Waku
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *EventToSystemMessageSuite) newMessenger() *Messenger {
|
||||||
|
privateKey, err := crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
messenger, err := newMessengerWithKey(s.shh, privateKey, s.logger, nil)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
return messenger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *EventToSystemMessageSuite) SetupTest() {
|
||||||
|
s.logger = tt.MustCreateTestLogger()
|
||||||
|
|
||||||
|
config := waku.DefaultConfig
|
||||||
|
config.MinimumAcceptedPoW = 0
|
||||||
|
shh := waku.New(&config, s.logger)
|
||||||
|
s.shh = gethbridge.NewGethWakuWrapper(shh)
|
||||||
|
s.Require().NoError(shh.Start())
|
||||||
|
|
||||||
|
s.m = s.newMessenger()
|
||||||
|
s.privateKey = s.m.identity
|
||||||
|
|
||||||
|
_, err := s.m.Start()
|
||||||
|
s.Require().NoError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *EventToSystemMessageSuite) TestRun() {
|
func (s *EventToSystemMessageSuite) TestRun() {
|
||||||
|
@ -78,3 +118,62 @@ func (s *EventToSystemMessageSuite) TestRun() {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *EventToSystemMessageSuite) TestHandleMembershipUpdate() {
|
||||||
|
adminPrivateKey, err := crypto.GenerateKey()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
adminPublicKey := types.EncodeHex(crypto.FromECDSAPub(&adminPrivateKey.PublicKey))
|
||||||
|
ourPublicKey := types.EncodeHex(crypto.FromECDSAPub(&s.m.identity.PublicKey))
|
||||||
|
|
||||||
|
event1 := v1protocol.MembershipUpdateEvent{
|
||||||
|
Type: protobuf.MembershipUpdateEvent_CHAT_CREATED,
|
||||||
|
Name: "test",
|
||||||
|
ChatID: "test-" + adminPublicKey,
|
||||||
|
ClockValue: 100,
|
||||||
|
}
|
||||||
|
err = event1.Sign(adminPrivateKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
event2 := v1protocol.MembershipUpdateEvent{
|
||||||
|
Type: protobuf.MembershipUpdateEvent_MEMBERS_ADDED,
|
||||||
|
Members: []string{adminPublicKey, ourPublicKey},
|
||||||
|
ChatID: "test-" + adminPublicKey,
|
||||||
|
ClockValue: 100,
|
||||||
|
}
|
||||||
|
err = event2.Sign(adminPrivateKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
testMembershipUpdateMessageStruct2 := v1protocol.MembershipUpdateMessage{
|
||||||
|
ChatID: "test-" + adminPublicKey,
|
||||||
|
Events: []v1protocol.MembershipUpdateEvent{
|
||||||
|
event1,
|
||||||
|
event2,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
rawMembershipUpdateMessage2, err := testMembershipUpdateMessageStruct2.ToProtobuf()
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
contact, err := BuildContactFromPublicKey(&adminPrivateKey.PublicKey)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
|
||||||
|
contact.SystemTags = []string{contactAdded}
|
||||||
|
|
||||||
|
currentMessageState := &CurrentMessageState{
|
||||||
|
Contact: contact,
|
||||||
|
}
|
||||||
|
|
||||||
|
state := &ReceivedMessageState{
|
||||||
|
Response: &MessengerResponse{},
|
||||||
|
Timesource: s.m.transport,
|
||||||
|
CurrentMessageState: currentMessageState,
|
||||||
|
ExistingMessagesMap: map[string]bool{},
|
||||||
|
AllChats: s.m.allChats,
|
||||||
|
}
|
||||||
|
|
||||||
|
err = s.m.HandleMembershipUpdate(state, nil, *rawMembershipUpdateMessage2, defaultSystemMessagesTranslations)
|
||||||
|
s.Require().NoError(err)
|
||||||
|
s.Require().Len(state.Response.Notifications(), 1)
|
||||||
|
s.Require().Equal(state.Response.Notifications()[0].Category, localnotifications.CategoryGroupInvite)
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package localnotifications
|
||||||
const (
|
const (
|
||||||
CategoryTransaction PushCategory = "transaction"
|
CategoryTransaction PushCategory = "transaction"
|
||||||
CategoryMessage PushCategory = "newMessage"
|
CategoryMessage PushCategory = "newMessage"
|
||||||
|
CategoryGroupInvite PushCategory = "groupInvite"
|
||||||
CategoryCommunityRequestToJoin = "communityRequestToJoin"
|
CategoryCommunityRequestToJoin = "communityRequestToJoin"
|
||||||
|
|
||||||
TypeTransaction NotificationType = "transaction"
|
TypeTransaction NotificationType = "transaction"
|
||||||
|
|
Loading…
Reference in New Issue