atagen

malice

public
Star0
Watch0
48af827771081b0e3b68719cf046485aaab65304
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git
web/src/lib/mention-profiles.tsTypescript45 lines2.2 KB
1
import type { EventContext, MemberSummary, Sender, TimelineItem } from './types';
2
3
export type RoomProfiles = Record<string, Record<string, MemberSummary>>;
4
5
export function lacksProfile(sender: Sender): boolean {
6
  return !sender.display_name && !sender.avatar;
7
}
8
9
/** Rooms holding a sender or reply sender that came back with no name and no avatar. */
10
export function roomsLackingProfiles(items: { roomId: string; item: TimelineItem }[]): Set<string> {
11
  const rooms = new Set<string>();
12
  for (const { roomId, item } of items) {
13
    if (item.kind !== 'event') continue;
14
    const reply = item.event.reply_to?.details;
15
    if (lacksProfile(item.event.sender) || (reply?.kind === 'Ready' && lacksProfile(reply.sender))) rooms.add(roomId);
16
  }
17
  return rooms;
18
}
19
20
function filled(sender: Sender, members: Record<string, MemberSummary> | undefined): Sender {
21
  const member = members?.[sender.user_id];
22
  if (!member || !lacksProfile(sender) || (!member.display_name && !member.avatar)) return sender;
23
  return { ...sender, display_name: member.display_name, avatar: member.avatar, name_ambiguous: member.name_ambiguous };
24
}
25
26
export function withProfiles(item: TimelineItem, members: Record<string, MemberSummary> | undefined): TimelineItem {
27
  if (item.kind !== 'event' || !members) return item;
28
  const { reply_to: reply } = item.event;
29
  const details = reply?.details;
30
  const sender = filled(item.event.sender, members);
31
  const replySender = details?.kind === 'Ready' ? filled(details.sender, members) : null;
32
  if (sender === item.event.sender && (details?.kind !== 'Ready' || replySender === details.sender)) return item;
33
  const reply_to = reply && details?.kind === 'Ready' && replySender ? { ...reply, details: { ...details, sender: replySender } } : reply;
34
  return { ...item, event: { ...item.event, sender, reply_to } };
35
}
36
37
export function contextWithProfiles(context: EventContext, members: Record<string, MemberSummary> | undefined): EventContext {
38
  if (!members) return context;
39
  return {
40
    ...context,
41
    events_before: context.events_before.map((item) => withProfiles(item, members)),
42
    event: withProfiles(context.event, members),
43
    events_after: context.events_after.map((item) => withProfiles(item, members))
44
  };
45
}