Skip to content

Commit

Permalink
refactor(matrix-client/notification-saga): remove outdated notificati…
Browse files Browse the repository at this point in the history
…on processing (#2484)

* feat(notifications): use room unread count to process notifications

* refactor(matrix-client/notification-saga): remove outdated notification processing

* refactor: remove unused utils
  • Loading branch information
domw30 authored Dec 4, 2024
1 parent ad24c08 commit 3280d51
Show file tree
Hide file tree
Showing 9 changed files with 4 additions and 487 deletions.
62 changes: 0 additions & 62 deletions src/components/notifications-feed/notification-item/utils.test.ts

This file was deleted.

18 changes: 0 additions & 18 deletions src/components/notifications-feed/notification-item/utils.ts

This file was deleted.

12 changes: 0 additions & 12 deletions src/lib/chat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,3 @@ export function getProfileInfo(userId: string): Promise<{
}> {
return chat.get().matrix.getProfileInfo(userId);
}

export function getNotifications(): Promise<any[]> {
return chat.get().matrix.getNotifications();
}

export async function getNotificationReadStatus() {
return await chat.get().matrix.getNotificationReadStatus();
}

export async function setNotificationReadStatus(roomId: string) {
return await chat.get().matrix.setNotificationReadStatus(roomId);
}
121 changes: 0 additions & 121 deletions src/lib/chat/matrix-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import {
import { RealtimeChatEvents, IChatClient } from './';
import {
mapEventToAdminMessage,
mapEventToNotification,
mapEventToPostMessage,
mapMatrixMessage,
mapToLiveRoomEvent,
Expand Down Expand Up @@ -69,8 +68,6 @@ export class MatrixClient implements IChatClient {
private initializationTimestamp: number;
private secretStorageKey: string;

private readonly NOTIFICATION_READ_EVENT = 'org.zero.notifications.read';

constructor(private sdk = { createClient }, private sessionStorage = new SessionStorage()) {
this.addConnectionAwaiter();
}
Expand Down Expand Up @@ -345,34 +342,6 @@ export class MatrixClient implements IChatClient {
.then((response) => response?.body || []);
}

async getNotificationReadStatus(): Promise<Record<string, number>> {
await this.waitForConnection();
try {
const event = await this.matrix.getAccountData(this.NOTIFICATION_READ_EVENT);
return event?.getContent()?.readNotifications || {};
} catch (error) {
console.error('Error getting notification read status:', error);
return {};
}
}

async setNotificationReadStatus(roomId: string): Promise<void> {
await this.waitForConnection();
try {
const currentContent = await this.getNotificationReadStatus();
const updatedContent = {
readNotifications: {
...currentContent,
[roomId]: Date.now(),
},
};

await this.matrix.setAccountData(this.NOTIFICATION_READ_EVENT, updatedContent);
} catch (error) {
console.error('Error setting notification read status:', error);
}
}

async searchMentionableUsersForChannel(channelId: string, search: string, channelMembers: UserModel[]) {
const searchResults = await getFilteredMembersForAutoComplete(channelMembers, search);
return searchResults.map((u) => ({
Expand Down Expand Up @@ -636,50 +605,6 @@ export class MatrixClient implements IChatClient {
return result;
}

async getNotifications(): Promise<any[]> {
await this.waitForConnection();
const rooms = await this.getRoomsUserIsIn();
const CUTOFF_DAYS = 30;
const CUTOFF_TIMESTAMP = Date.now() - CUTOFF_DAYS * 24 * 60 * 60 * 1000;
let allNotifications = [];

let readStatus = {};
if (featureFlags.enableNotificationsReadStatus) {
readStatus = await this.getNotificationReadStatus();
}

const roomNotifications = await Promise.all(
rooms.map(async (room) => {
const timeline = room.getLiveTimeline();
const events = timeline.getEvents();

const mostRecentEvent = events[events.length - 1];
const oldestEvent = events[0];

if (!oldestEvent || !mostRecentEvent || (oldestEvent.getTs() > CUTOFF_TIMESTAMP && events.length < 50)) {
await this.matrix.paginateEventTimeline(timeline, {
backwards: true,
limit: 50,
});
}

if (room.hasEncryptionStateEvent() && events.some((e) => e.getTs() > CUTOFF_TIMESTAMP)) {
await room.decryptAllEvents();
}

const filteredEvents = timeline
.getEvents()
.filter((event) => event.getTs() > CUTOFF_TIMESTAMP)
.map((event) => event.getEffectiveEvent());

return this.getNotificationsFromRoom(filteredEvents, readStatus);
})
);

allNotifications = roomNotifications.flat();
return allNotifications.sort((a, b) => b.createdAt - a.createdAt);
}

async getMessageByRoomId(channelId: string, messageId: string) {
await this.waitForConnection();
const newMessage = await this.matrix.fetchRoomEvent(channelId, messageId);
Expand Down Expand Up @@ -1719,52 +1644,6 @@ export class MatrixClient implements IChatClient {
return event.type === CustomEventType.ROOM_POST;
}

private async getNotificationsFromRoom(events, readStatus = {}): Promise<any[]> {
const currentUserId = this.matrix.getUserId();
const currentUserUuid = currentUserId.split(':')[0].substring(1);

const filteredEvents = events.filter((event) => {
const relatesTo = event.content && event.content['m.relates_to'];
const isDM = this.matrix.getRoom(event.room_id)?.getMembers().length === 2;
const isFromCurrentUser = event.sender === currentUserId;

// Don't process notifications from the current user
if (isFromCurrentUser) return false;

if (
event.type === 'm.room.message' &&
event.content?.body?.includes('@[') &&
event.content?.body?.includes('](user:') &&
event.content.body.includes(currentUserUuid)
) {
return true;
}

if (relatesTo?.['m.in_reply_to']) {
const originalEvent = events.find((e) => e.event_id === relatesTo['m.in_reply_to'].event_id);
return originalEvent?.sender === currentUserId;
}

if (event.type === MatrixConstants.REACTION && !event?.unsigned?.redacted_because) {
const targetEvent = events.find((e) => e.event_id === relatesTo.event_id);
return targetEvent?.sender === currentUserId;
}

return isDM && event.type === 'm.room.message';
});

const notifications = await Promise.all(
filteredEvents.map((event) => {
const roomReadTimestamp = readStatus[event.room_id] || 0;
const isRead = featureFlags.enableNotificationsReadStatus ? event.origin_server_ts <= roomReadTimestamp : false;

return mapEventToNotification(event, isRead);
})
);

return notifications.filter((notification) => notification !== null);
}

// Performance improvement: Fetches only the latest user message to avoid processing large image files and other attachments
// that are not needed for the initial loading of the conversation list
private async getUpToLatestUserMessageFromRoom(room: Room): Promise<any[]> {
Expand Down
71 changes: 0 additions & 71 deletions src/lib/chat/matrix/chat-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,77 +142,6 @@ export async function mapEventToPostMessage(matrixMessage, sdkMatrixClient: SDKM
};
}

export async function mapEventToNotification(event, isRead: boolean = false) {
const { event_id, room_id, origin_server_ts, sender, content, type } = event;

const baseNotification = {
id: event_id,
roomId: room_id,
createdAt: origin_server_ts,
isRead,
sender: {
userId: sender,
},
};

if (type === 'm.room.message' && content?.body?.includes('@[')) {
return {
...baseNotification,
type: 'mention',
content: {
body: content.body,
mentions: extractMentionsFromBody(content.body),
notificationType: 'mention',
},
};
}

if (type === MatrixConstants.REACTION && !event?.unsigned?.redacted_because) {
const isMeowReaction = content['m.relates_to'].key.startsWith('MEOW_');
if (isMeowReaction) return null;

return {
...baseNotification,
type: 'reaction',
content: {
reactionKey: content['m.relates_to'].key,
targetEventId: content['m.relates_to'].event_id,
},
};
}

if (content['m.relates_to']?.['m.in_reply_to']) {
return {
...baseNotification,
type: 'reply',
content: {
body: content.body,
replyToEventId: content['m.relates_to']['m.in_reply_to'].event_id,
notificationType: 'reply',
},
};
}

if (type === 'm.room.message') {
return {
...baseNotification,
type: 'direct_message',
content: {
body: content.body,
notificationType: 'direct_message',
},
};
}

return null;
}

export function extractMentionsFromBody(body: string) {
const mentionRegex = /@\[.*?\]\(user:(.*?)\)/g;
const matches = [...body?.matchAll(mentionRegex)];
return matches.map((match) => match[1]);
}

function getAdminDataFromEventType(type, content, sender, targetUserId, previousContent) {
switch (type) {
case EventType.RoomMember:
Expand Down
Loading

0 comments on commit 3280d51

Please sign in to comment.