github.com/status-im/status-go@v1.1.0/protocol/messenger_activity_center.go (about)

     1  package protocol
     2  
     3  import (
     4  	"context"
     5  
     6  	"github.com/golang/protobuf/proto"
     7  	"github.com/pkg/errors"
     8  	"go.uber.org/zap"
     9  
    10  	v1protocol "github.com/status-im/status-go/protocol/v1"
    11  
    12  	"github.com/status-im/status-go/eth-node/types"
    13  	"github.com/status-im/status-go/protocol/common"
    14  	"github.com/status-im/status-go/protocol/protobuf"
    15  	"github.com/status-im/status-go/protocol/requests"
    16  )
    17  
    18  var errOnlyOneNotificationID = errors.New("only one notification id is supported")
    19  
    20  func toHexBytes(b [][]byte) []types.HexBytes {
    21  	hb := make([]types.HexBytes, len(b))
    22  
    23  	for i, v := range b {
    24  		hb[i] = types.HexBytes(v)
    25  	}
    26  
    27  	return hb
    28  }
    29  
    30  func fromHexBytes(hb []types.HexBytes) [][]byte {
    31  	b := make([][]byte, len(hb))
    32  
    33  	for i, v := range hb {
    34  		b[i] = v
    35  	}
    36  
    37  	return b
    38  }
    39  
    40  func (m *Messenger) ActivityCenterNotifications(request ActivityCenterNotificationsRequest) (*ActivityCenterPaginationResponse, error) {
    41  	cursor, notifications, err := m.persistence.ActivityCenterNotifications(request.Cursor, request.Limit, request.ActivityTypes, request.ReadType, true)
    42  	if err != nil {
    43  		return nil, err
    44  	}
    45  
    46  	if m.httpServer != nil {
    47  		for _, notification := range notifications {
    48  			if notification.Message != nil {
    49  				err = m.prepareMessage(notification.Message, m.httpServer)
    50  
    51  				if err != nil {
    52  					return nil, err
    53  				}
    54  
    55  				image := notification.Message.GetImage()
    56  				if image != nil && image.AlbumId != "" {
    57  					album, err := m.persistence.albumMessages(notification.Message.LocalChatID, image.AlbumId)
    58  					if err != nil {
    59  						return nil, err
    60  					}
    61  					notification.AlbumMessages = album
    62  				}
    63  			}
    64  			if notification.AlbumMessages != nil {
    65  				for _, message := range notification.AlbumMessages {
    66  					err = m.prepareMessage(message, m.httpServer)
    67  
    68  					if err != nil {
    69  						return nil, err
    70  					}
    71  				}
    72  			}
    73  			if notification.TokenData != nil {
    74  				if notification.Type == ActivityCenterNotificationTypeCommunityTokenReceived || notification.Type == ActivityCenterNotificationTypeFirstCommunityTokenReceived {
    75  					err = m.prepareTokenData(notification.TokenData, m.httpServer)
    76  					if err != nil {
    77  						return nil, err
    78  					}
    79  				}
    80  			}
    81  		}
    82  	}
    83  
    84  	return &ActivityCenterPaginationResponse{
    85  		Cursor:        cursor,
    86  		Notifications: notifications,
    87  	}, nil
    88  }
    89  
    90  func (m *Messenger) ActivityCenterNotificationsCount(request ActivityCenterCountRequest) (*ActivityCenterCountResponse, error) {
    91  	response := make(ActivityCenterCountResponse)
    92  
    93  	for _, activityType := range request.ActivityTypes {
    94  		count, err := m.persistence.ActivityCenterNotificationsCount([]ActivityCenterType{activityType}, request.ReadType, true)
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  
    99  		response[activityType] = count
   100  	}
   101  
   102  	return &response, nil
   103  }
   104  
   105  func (m *Messenger) HasUnseenActivityCenterNotifications() (bool, error) {
   106  	seen, _, err := m.persistence.HasUnseenActivityCenterNotifications()
   107  	return seen, err
   108  }
   109  
   110  func (m *Messenger) GetActivityCenterState() (*ActivityCenterState, error) {
   111  	return m.persistence.GetActivityCenterState()
   112  }
   113  
   114  func (m *Messenger) MarkAsSeenActivityCenterNotifications() (*MessengerResponse, error) {
   115  	response := &MessengerResponse{}
   116  	s := &ActivityCenterState{
   117  		UpdatedAt: m.GetCurrentTimeInMillis(),
   118  		HasSeen:   true,
   119  	}
   120  	_, err := m.persistence.UpdateActivityCenterNotificationState(s)
   121  	if err != nil {
   122  		return nil, err
   123  	}
   124  
   125  	state, err := m.persistence.GetActivityCenterState()
   126  	if err != nil {
   127  		return nil, err
   128  	}
   129  
   130  	response.SetActivityCenterState(state)
   131  	return response, nil
   132  }
   133  
   134  func (m *Messenger) MarkAllActivityCenterNotificationsRead(ctx context.Context) (*MessengerResponse, error) {
   135  	ids, err := m.persistence.GetNotReadActivityCenterNotificationIds()
   136  	if err != nil {
   137  		return nil, err
   138  	}
   139  
   140  	updateAt := m.GetCurrentTimeInMillis()
   141  	return m.MarkActivityCenterNotificationsRead(ctx, toHexBytes(ids), updateAt, true)
   142  }
   143  
   144  func (m *Messenger) MarkActivityCenterNotificationsRead(ctx context.Context, ids []types.HexBytes, updatedAt uint64, sync bool) (*MessengerResponse, error) {
   145  	// Mark notifications as read in the database
   146  	if updatedAt == 0 {
   147  		updatedAt = m.GetCurrentTimeInMillis()
   148  	}
   149  	err := m.persistence.MarkActivityCenterNotificationsRead(ids, updatedAt)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	notifications, err := m.persistence.GetActivityCenterNotificationsByID(ids)
   155  	if err != nil {
   156  		return nil, err
   157  	}
   158  
   159  	response := &MessengerResponse{}
   160  	repliesAndMentions := make(map[string][]string)
   161  
   162  	// When marking as read Mention or Reply notification, the corresponding chat message should also be seen.
   163  	for _, notification := range notifications {
   164  		response.AddActivityCenterNotification(notification)
   165  
   166  		if notification.Message != nil &&
   167  			(notification.Type == ActivityCenterNotificationTypeMention || notification.Type == ActivityCenterNotificationTypeReply) {
   168  			repliesAndMentions[notification.ChatID] = append(repliesAndMentions[notification.ChatID], notification.Message.ID)
   169  		}
   170  	}
   171  
   172  	// Mark messages as seen
   173  	for chatID, messageIDs := range repliesAndMentions {
   174  		count, countWithMentions, chat, err := m.markMessagesSeenImpl(chatID, messageIDs)
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  		response.AddChat(chat)
   179  		response.AddSeenAndUnseenMessages(&SeenUnseenMessages{
   180  			ChatID:            chatID,
   181  			Count:             count,
   182  			CountWithMentions: countWithMentions,
   183  			Seen:              true,
   184  		})
   185  	}
   186  
   187  	state, err := m.persistence.GetActivityCenterState()
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	response.SetActivityCenterState(state)
   193  
   194  	if !sync {
   195  		response2, err := m.processActivityCenterNotifications(notifications, true)
   196  		if err != nil {
   197  			return nil, err
   198  		}
   199  		if err = response2.Merge(response); err != nil {
   200  			return nil, err
   201  		}
   202  		return response2, nil
   203  	}
   204  	return response, m.syncActivityCenterReadByIDs(ctx, ids, updatedAt)
   205  }
   206  
   207  func (m *Messenger) MarkActivityCenterNotificationsUnread(ctx context.Context, ids []types.HexBytes, updatedAt uint64, sync bool) (*MessengerResponse, error) {
   208  	notifications, err := m.persistence.MarkActivityCenterNotificationsUnread(ids, updatedAt)
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  
   213  	response := &MessengerResponse{}
   214  	response.AddActivityCenterNotifications(notifications)
   215  
   216  	// Don't mark messages unseen in chat, that looks weird
   217  
   218  	state, err := m.persistence.GetActivityCenterState()
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	response.SetActivityCenterState(state)
   223  
   224  	if sync && len(notifications) > 0 {
   225  		err = m.syncActivityCenterUnreadByIDs(ctx, ids, updatedAt)
   226  	}
   227  	return response, err
   228  }
   229  
   230  func (m *Messenger) MarkActivityCenterNotificationsDeleted(ctx context.Context, ids []types.HexBytes, updatedAt uint64, sync bool) (*MessengerResponse, error) {
   231  	response := &MessengerResponse{}
   232  	notifications, err := m.persistence.MarkActivityCenterNotificationsDeleted(ids, updatedAt)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  	response.AddActivityCenterNotifications(notifications)
   237  	state, err := m.persistence.GetActivityCenterState()
   238  	if err != nil {
   239  		return nil, err
   240  	}
   241  	response.SetActivityCenterState(state)
   242  	if sync {
   243  		err = m.syncActivityCenterDeletedByIDs(ctx, ids, updatedAt)
   244  		if err != nil {
   245  			m.logger.Error("MarkActivityCenterNotificationsDeleted, failed to sync activity center notifications as deleted", zap.Error(err))
   246  			return nil, err
   247  		}
   248  	}
   249  	return response, nil
   250  }
   251  
   252  func (m *Messenger) addActivityCenterNotification(response *MessengerResponse, notification *ActivityCenterNotification, syncAction func(context.Context, []types.HexBytes, uint64) error) error {
   253  	_, err := m.persistence.SaveActivityCenterNotification(notification, true)
   254  	if err != nil {
   255  		m.logger.Error("failed to save notification", zap.Error(err))
   256  		return err
   257  	}
   258  
   259  	state, err := m.persistence.GetActivityCenterState()
   260  	if err != nil {
   261  		m.logger.Error("failed to obtain activity center state", zap.Error(err))
   262  		return err
   263  	}
   264  	response.AddActivityCenterNotification(notification)
   265  	response.SetActivityCenterState(state)
   266  
   267  	if syncAction != nil {
   268  		//TODO a way to pass context
   269  		err = syncAction(context.TODO(), []types.HexBytes{notification.ID}, notification.UpdatedAt)
   270  		if err != nil {
   271  			m.logger.Error("[addActivityCenterNotification] failed to sync activity center notification", zap.Error(err))
   272  			return err
   273  		}
   274  	}
   275  	return nil
   276  }
   277  
   278  func (m *Messenger) syncActivityCenterReadByIDs(ctx context.Context, ids []types.HexBytes, clock uint64) error {
   279  	syncMessage := &protobuf.SyncActivityCenterRead{
   280  		Clock: clock,
   281  		Ids:   fromHexBytes(ids),
   282  	}
   283  
   284  	encodedMessage, err := proto.Marshal(syncMessage)
   285  	if err != nil {
   286  		return err
   287  	}
   288  
   289  	return m.sendToPairedDevices(ctx, common.RawMessage{
   290  		Payload:     encodedMessage,
   291  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_READ,
   292  		ResendType:  common.ResendTypeDataSync,
   293  	})
   294  }
   295  
   296  func (m *Messenger) syncActivityCenterUnreadByIDs(ctx context.Context, ids []types.HexBytes, clock uint64) error {
   297  	syncMessage := &protobuf.SyncActivityCenterUnread{
   298  		Clock: clock,
   299  		Ids:   fromHexBytes(ids),
   300  	}
   301  
   302  	encodedMessage, err := proto.Marshal(syncMessage)
   303  	if err != nil {
   304  		return err
   305  	}
   306  
   307  	return m.sendToPairedDevices(ctx, common.RawMessage{
   308  		Payload:     encodedMessage,
   309  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_UNREAD,
   310  		ResendType:  common.ResendTypeDataSync,
   311  	})
   312  }
   313  
   314  func (m *Messenger) processActivityCenterNotifications(notifications []*ActivityCenterNotification, addNotifications bool) (*MessengerResponse, error) {
   315  	response := &MessengerResponse{}
   316  	var chats []*Chat
   317  	for _, notification := range notifications {
   318  		if notification.ChatID != "" {
   319  			chat, ok := m.allChats.Load(notification.ChatID)
   320  			if !ok {
   321  				// This should not really happen, but ignore just in case it was deleted in the meantime
   322  				m.logger.Warn("chat not found")
   323  				continue
   324  			}
   325  			chat.Active = true
   326  
   327  			if chat.PrivateGroupChat() {
   328  				// Send Joined message for backward compatibility
   329  				_, err := m.ConfirmJoiningGroup(context.Background(), chat.ID)
   330  				if err != nil {
   331  					m.logger.Error("failed to join group", zap.Error(err))
   332  					return nil, err
   333  				}
   334  			}
   335  
   336  			chats = append(chats, chat)
   337  			response.AddChat(chat)
   338  		}
   339  
   340  		if addNotifications {
   341  			response.AddActivityCenterNotification(notification)
   342  		}
   343  	}
   344  	if len(chats) != 0 {
   345  		err := m.saveChats(chats)
   346  		if err != nil {
   347  			return nil, err
   348  		}
   349  	}
   350  	return response, nil
   351  }
   352  
   353  func (m *Messenger) processAcceptedActivityCenterNotifications(ctx context.Context, notifications []*ActivityCenterNotification, sync bool) (*MessengerResponse, error) {
   354  	ids := make([]types.HexBytes, len(notifications))
   355  
   356  	for i := range notifications {
   357  		ids[i] = notifications[i].ID
   358  	}
   359  
   360  	state, err := m.persistence.GetActivityCenterState()
   361  	if err != nil {
   362  		return nil, err
   363  	}
   364  
   365  	if sync {
   366  		err = m.syncActivityCenterAcceptedByIDs(ctx, ids, m.GetCurrentTimeInMillis())
   367  		if err != nil {
   368  			return nil, err
   369  		}
   370  	}
   371  
   372  	response, err := m.processActivityCenterNotifications(notifications, !sync)
   373  	if err != nil {
   374  		return nil, err
   375  	}
   376  	response.SetActivityCenterState(state)
   377  	return response, nil
   378  }
   379  
   380  func (m *Messenger) AcceptActivityCenterNotificationsForInvitesFromUser(ctx context.Context, userPublicKey string, updatedAt uint64) ([]*ActivityCenterNotification, error) {
   381  	notifications, err := m.persistence.AcceptActivityCenterNotificationsForInvitesFromUser(userPublicKey, updatedAt)
   382  	if err != nil {
   383  		return nil, err
   384  	}
   385  	if len(notifications) > 0 {
   386  		err = m.syncActivityCenterAccepted(ctx, notifications, updatedAt)
   387  	}
   388  	return notifications, err
   389  }
   390  
   391  func (m *Messenger) syncActivityCenterAccepted(ctx context.Context, notifications []*ActivityCenterNotification, updatedAt uint64) error {
   392  	ids := make([]types.HexBytes, len(notifications))
   393  	for _, notification := range notifications {
   394  		ids = append(ids, notification.ID)
   395  	}
   396  	return m.syncActivityCenterAcceptedByIDs(ctx, ids, updatedAt)
   397  }
   398  
   399  func (m *Messenger) syncActivityCenterAcceptedByIDs(ctx context.Context, ids []types.HexBytes, clock uint64) error {
   400  	syncMessage := &protobuf.SyncActivityCenterAccepted{
   401  		Clock: clock,
   402  		Ids:   fromHexBytes(ids),
   403  	}
   404  
   405  	encodedMessage, err := proto.Marshal(syncMessage)
   406  	if err != nil {
   407  		return err
   408  	}
   409  
   410  	return m.sendToPairedDevices(ctx, common.RawMessage{
   411  		Payload:     encodedMessage,
   412  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_ACCEPTED,
   413  		ResendType:  common.ResendTypeDataSync,
   414  	})
   415  }
   416  
   417  func (m *Messenger) syncActivityCenterCommunityRequestDecisionAdapter(ctx context.Context, ids []types.HexBytes, _ uint64) error {
   418  	if len(ids) != 1 {
   419  		return errOnlyOneNotificationID
   420  	}
   421  	id := ids[0]
   422  	notification, err := m.persistence.GetActivityCenterNotificationByID(id)
   423  	if err != nil {
   424  		return err
   425  	}
   426  
   427  	return m.syncActivityCenterCommunityRequestDecision(ctx, notification)
   428  }
   429  
   430  func (m *Messenger) syncActivityCenterCommunityRequestDecision(ctx context.Context, notification *ActivityCenterNotification) error {
   431  	var decision protobuf.SyncActivityCenterCommunityRequestDecisionCommunityRequestDecision
   432  	if notification.Accepted {
   433  		decision = protobuf.SyncActivityCenterCommunityRequestDecision_ACCEPTED
   434  	} else if notification.Dismissed {
   435  		decision = protobuf.SyncActivityCenterCommunityRequestDecision_DECLINED
   436  	} else {
   437  		return errors.New("[syncActivityCenterCommunityRequestDecision] notification is not accepted or dismissed")
   438  	}
   439  
   440  	syncMessage := &protobuf.SyncActivityCenterCommunityRequestDecision{
   441  		Clock:            notification.UpdatedAt,
   442  		Id:               notification.ID,
   443  		MembershipStatus: uint32(notification.MembershipStatus),
   444  		Decision:         decision,
   445  	}
   446  
   447  	encodedMessage, err := proto.Marshal(syncMessage)
   448  	if err != nil {
   449  		return err
   450  	}
   451  
   452  	return m.sendToPairedDevices(ctx, common.RawMessage{
   453  		Payload:     encodedMessage,
   454  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_COMMUNITY_REQUEST_DECISION,
   455  		ResendType:  common.ResendTypeDataSync,
   456  	})
   457  }
   458  
   459  func (m *Messenger) AcceptActivityCenterNotifications(ctx context.Context, ids []types.HexBytes, updatedAt uint64, sync bool) (*MessengerResponse, error) {
   460  	if len(ids) == 0 {
   461  		return nil, errors.New("notifications ids are not provided")
   462  	}
   463  
   464  	notifications, err := m.persistence.AcceptActivityCenterNotifications(ids, updatedAt)
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  
   469  	return m.processAcceptedActivityCenterNotifications(ctx, notifications, sync)
   470  }
   471  
   472  func (m *Messenger) DismissAllActivityCenterNotificationsFromUser(ctx context.Context, userPublicKey string, updatedAt uint64) ([]*ActivityCenterNotification, error) {
   473  	notifications, err := m.persistence.DismissAllActivityCenterNotificationsFromUser(userPublicKey, updatedAt)
   474  	if err != nil {
   475  		return nil, err
   476  	}
   477  	if notifications == nil {
   478  		return nil, nil
   479  	}
   480  	return notifications, m.syncActivityCenterDismissed(ctx, notifications, updatedAt)
   481  }
   482  
   483  func (m *Messenger) DismissActivityCenterNotificationsByCommunity(ctx context.Context, request *requests.DismissCommunityNotifications) error {
   484  	err := request.Validate()
   485  	if err != nil {
   486  		return err
   487  	}
   488  
   489  	updatedAt := m.GetCurrentTimeInMillis()
   490  	notifications, err := m.persistence.DismissActivityCenterNotificationsByCommunity(request.CommunityID.String(), updatedAt)
   491  	if err != nil {
   492  		return err
   493  	}
   494  	return m.syncActivityCenterDismissed(ctx, notifications, updatedAt)
   495  }
   496  
   497  func (m *Messenger) DismissAllActivityCenterNotificationsFromCommunity(ctx context.Context, communityID string, updatedAt uint64) ([]*ActivityCenterNotification, error) {
   498  	notifications, err := m.persistence.DismissAllActivityCenterNotificationsFromCommunity(communityID, updatedAt)
   499  	if err != nil {
   500  		return nil, err
   501  	}
   502  	return notifications, m.syncActivityCenterDismissed(ctx, notifications, updatedAt)
   503  }
   504  
   505  func (m *Messenger) DismissAllActivityCenterNotificationsFromChatID(ctx context.Context, chatID string, updatedAt uint64) ([]*ActivityCenterNotification, error) {
   506  	notifications, err := m.persistence.DismissAllActivityCenterNotificationsFromChatID(chatID, updatedAt)
   507  	if err != nil {
   508  		return nil, err
   509  	}
   510  	return notifications, m.syncActivityCenterDismissed(ctx, notifications, updatedAt)
   511  }
   512  
   513  func (m *Messenger) syncActivityCenterDeleted(ctx context.Context, notifications []*ActivityCenterNotification, updatedAt uint64) error {
   514  	ids := make([]types.HexBytes, len(notifications))
   515  	for _, notification := range notifications {
   516  		ids = append(ids, notification.ID)
   517  	}
   518  	return m.syncActivityCenterDeletedByIDs(ctx, ids, updatedAt)
   519  }
   520  
   521  func (m *Messenger) syncActivityCenterDeletedByIDs(ctx context.Context, ids []types.HexBytes, clock uint64) error {
   522  	syncMessage := &protobuf.SyncActivityCenterDeleted{
   523  		Clock: clock,
   524  		Ids:   fromHexBytes(ids),
   525  	}
   526  
   527  	encodedMessage, err := proto.Marshal(syncMessage)
   528  	if err != nil {
   529  		return err
   530  	}
   531  
   532  	return m.sendToPairedDevices(ctx, common.RawMessage{
   533  		Payload:     encodedMessage,
   534  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_DELETED,
   535  		ResendType:  common.ResendTypeDataSync,
   536  	})
   537  }
   538  
   539  func (m *Messenger) syncActivityCenterDismissed(ctx context.Context, notifications []*ActivityCenterNotification, updatedAt uint64) error {
   540  	ids := make([]types.HexBytes, len(notifications))
   541  	for _, notification := range notifications {
   542  		ids = append(ids, notification.ID)
   543  	}
   544  	return m.syncActivityCenterDismissedByIDs(ctx, ids, updatedAt)
   545  }
   546  
   547  func (m *Messenger) syncActivityCenterDismissedByIDs(ctx context.Context, ids []types.HexBytes, clock uint64) error {
   548  	syncMessage := &protobuf.SyncActivityCenterDismissed{
   549  		Clock: clock,
   550  		Ids:   fromHexBytes(ids),
   551  	}
   552  
   553  	encodedMessage, err := proto.Marshal(syncMessage)
   554  	if err != nil {
   555  		return err
   556  	}
   557  
   558  	return m.sendToPairedDevices(ctx, common.RawMessage{
   559  		Payload:     encodedMessage,
   560  		MessageType: protobuf.ApplicationMetadataMessage_SYNC_ACTIVITY_CENTER_DISMISSED,
   561  		ResendType:  common.ResendTypeDataSync,
   562  	})
   563  }
   564  
   565  func (m *Messenger) DismissActivityCenterNotifications(ctx context.Context, ids []types.HexBytes, updatedAt uint64, sync bool) (*MessengerResponse, error) {
   566  	if updatedAt == 0 {
   567  		updatedAt = m.GetCurrentTimeInMillis()
   568  	}
   569  	err := m.persistence.DismissActivityCenterNotifications(ids, updatedAt)
   570  	if err != nil {
   571  		return nil, err
   572  	}
   573  
   574  	state, err := m.persistence.GetActivityCenterState()
   575  	if err != nil {
   576  		return nil, err
   577  	}
   578  
   579  	response := &MessengerResponse{}
   580  	response.SetActivityCenterState(state)
   581  	if !sync {
   582  		notifications, err := m.persistence.GetActivityCenterNotificationsByID(ids)
   583  		if err != nil {
   584  			return nil, err
   585  		}
   586  		response2, err := m.processActivityCenterNotifications(notifications, true)
   587  		if err != nil {
   588  			return nil, err
   589  		}
   590  		err = response2.Merge(response)
   591  		return response, err
   592  	}
   593  	return response, m.syncActivityCenterDismissedByIDs(ctx, ids, updatedAt)
   594  }
   595  
   596  func (m *Messenger) ActivityCenterNotification(id types.HexBytes) (*ActivityCenterNotification, error) {
   597  	notification, err := m.persistence.GetActivityCenterNotificationByID(id)
   598  	if err != nil {
   599  		return nil, err
   600  	}
   601  
   602  	if notification.Message != nil {
   603  		image := notification.Message.GetImage()
   604  		if image != nil && image.AlbumId != "" {
   605  			album, err := m.persistence.albumMessages(notification.Message.LocalChatID, image.AlbumId)
   606  			if err != nil {
   607  				return nil, err
   608  			}
   609  			notification.AlbumMessages = album
   610  		}
   611  	}
   612  
   613  	return notification, nil
   614  }
   615  
   616  func (m *Messenger) HandleSyncActivityCenterRead(state *ReceivedMessageState, message *protobuf.SyncActivityCenterRead, statusMessage *v1protocol.StatusMessage) error {
   617  	resp, err := m.MarkActivityCenterNotificationsRead(context.TODO(), toHexBytes(message.Ids), message.Clock, false)
   618  
   619  	if err != nil {
   620  		return err
   621  	}
   622  
   623  	return state.Response.Merge(resp)
   624  }
   625  
   626  func (m *Messenger) HandleSyncActivityCenterUnread(state *ReceivedMessageState, message *protobuf.SyncActivityCenterUnread, statusMessage *v1protocol.StatusMessage) error {
   627  	resp, err := m.MarkActivityCenterNotificationsUnread(context.TODO(), toHexBytes(message.Ids), message.Clock, false)
   628  
   629  	if err != nil {
   630  		return err
   631  	}
   632  
   633  	return state.Response.Merge(resp)
   634  }
   635  
   636  func (m *Messenger) HandleSyncActivityCenterDeleted(state *ReceivedMessageState, message *protobuf.SyncActivityCenterDeleted, statusMessage *v1protocol.StatusMessage) error {
   637  	response, err := m.MarkActivityCenterNotificationsDeleted(context.TODO(), toHexBytes(message.Ids), message.Clock, false)
   638  	if err != nil {
   639  		return err
   640  	}
   641  	return state.Response.Merge(response)
   642  }
   643  
   644  func (m *Messenger) HandleSyncActivityCenterAccepted(state *ReceivedMessageState, message *protobuf.SyncActivityCenterAccepted, statusMessage *v1protocol.StatusMessage) error {
   645  	resp, err := m.AcceptActivityCenterNotifications(context.TODO(), toHexBytes(message.Ids), message.Clock, false)
   646  
   647  	if err != nil {
   648  		return err
   649  	}
   650  
   651  	return state.Response.Merge(resp)
   652  }
   653  
   654  func (m *Messenger) HandleSyncActivityCenterDismissed(state *ReceivedMessageState, message *protobuf.SyncActivityCenterDismissed, statusMessage *v1protocol.StatusMessage) error {
   655  	resp, err := m.DismissActivityCenterNotifications(context.TODO(), toHexBytes(message.Ids), message.Clock, false)
   656  
   657  	if err != nil {
   658  		return err
   659  	}
   660  
   661  	return state.Response.Merge(resp)
   662  }
   663  
   664  func (m *Messenger) HandleSyncActivityCenterCommunityRequestDecision(state *ReceivedMessageState, a *protobuf.SyncActivityCenterCommunityRequestDecision, statusMessage *v1protocol.StatusMessage) error {
   665  	notification, err := m.persistence.GetActivityCenterNotificationByID(a.Id)
   666  	if err != nil {
   667  		return err
   668  	}
   669  	if notification == nil {
   670  		return errors.New("[HandleSyncActivityCenterCommunityRequestDecision] notification not found")
   671  	}
   672  
   673  	notification.MembershipStatus = ActivityCenterMembershipStatus(a.MembershipStatus)
   674  	notification.UpdatedAt = a.Clock
   675  	if a.Decision == protobuf.SyncActivityCenterCommunityRequestDecision_DECLINED {
   676  		notification.Dismissed = true
   677  	} else if a.Decision == protobuf.SyncActivityCenterCommunityRequestDecision_ACCEPTED {
   678  		notification.Accepted = true
   679  	} else {
   680  		return errors.New("[HandleSyncActivityCenterCommunityRequestDecision] invalid decision")
   681  	}
   682  	_, err = m.persistence.SaveActivityCenterNotification(notification, false)
   683  	if err != nil {
   684  		return err
   685  	}
   686  
   687  	resp := state.Response
   688  	resp.AddActivityCenterNotification(notification)
   689  
   690  	s, err := m.persistence.UpdateActivityCenterState(notification.UpdatedAt)
   691  	if err != nil {
   692  		return err
   693  	}
   694  	resp.SetActivityCenterState(s)
   695  	return nil
   696  }