blob: 5776c59e0609734b0f5a0d121adb490618f0d494 [file] [log] [blame]
simon26e79f72022-10-05 22:16:08 -04001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
simon20076982022-10-11 15:04:13 -040018import { Contact } from './Contact.js';
simond8ca2f22022-10-11 23:30:55 -040019import { PromiseExecutor } from './util.js';
simon06527b02022-10-01 15:01:47 -040020
21export interface ConversationMember {
22 contact: Contact;
23 role?: 'admin' | 'member' | 'invited' | 'banned' | 'left';
24}
25
26type ConversationInfos = Record<string, unknown>;
27
idillon-sfl9d956ab2022-10-20 16:33:24 -040028export type Message = {
29 id: string;
30 author: string;
31 timestamp: string;
32 type:
33 | 'application/call-history+json'
34 | 'application/data-transfer+json'
35 | 'application/update-profile'
36 | 'initial'
37 | 'member'
38 | 'merge'
39 | 'text/plain'
40 | 'vote';
41 linearizedParent: string;
42 parents: string;
43 body?: string;
44 duration?: string;
45 to?: string;
46 invited?: string;
47};
48
simon06527b02022-10-01 15:01:47 -040049type ConversationRequest = PromiseExecutor<Message[]>;
50
51type ConversationListeners = Record<
52 string,
53 {
simond8ca2f22022-10-11 23:30:55 -040054 socket: any; // TODO: Improve typing
55 session: any;
simon06527b02022-10-01 15:01:47 -040056 }
57>;
58
simon20076982022-10-11 15:04:13 -040059export class Conversation {
simon06527b02022-10-01 15:01:47 -040060 private readonly id: string | undefined;
61 private readonly accountId: string;
62 private readonly members: ConversationMember[];
simon5e32f742022-10-04 18:03:12 -040063 private messages: Message[];
64 private _infos: ConversationInfos;
65 private _requests: Record<string, ConversationRequest>;
66 private _listeners: ConversationListeners;
simon06527b02022-10-01 15:01:47 -040067
68 constructor(id: string | undefined, accountId: string, members?: ConversationMember[]) {
69 this.id = id;
70 this.accountId = accountId;
71 this.members = members || [];
simon5e32f742022-10-04 18:03:12 -040072
73 this.messages = [];
74 this._infos = {};
75 this._requests = {};
76 this._listeners = {};
simon06527b02022-10-01 15:01:47 -040077 }
78
simon5e32f742022-10-04 18:03:12 -040079 static from(accountId: string, object: any) {
simon06527b02022-10-01 15:01:47 -040080 const conversation = new Conversation(
81 object.id,
82 accountId,
simon5e32f742022-10-04 18:03:12 -040083 object.members.map((member: any) => {
simon06527b02022-10-01 15:01:47 -040084 member.contact = Contact.from(member.contact);
85 return member;
86 })
87 );
88 conversation.messages = object.messages;
idillonae655dd2022-10-14 18:11:02 -040089 conversation.infos = object.infos;
simon06527b02022-10-01 15:01:47 -040090 return conversation;
91 }
92 static fromSingleContact(accountId: string, contact: Contact) {
93 return new Conversation(undefined, accountId, [{ contact }]);
94 }
95
96 getId() {
97 return this.id;
98 }
99
100 getAccountId() {
101 return this.accountId;
102 }
103
104 getDisplayName() {
105 if (this.members.length !== 0) {
106 return this.members[0].contact.getDisplayName();
107 }
108 return this.getDisplayUri();
109 }
110
111 getDisplayNameNoFallback() {
112 if (this.members.length !== 0) {
113 return this.members[0].contact.getDisplayNameNoFallback();
114 }
115 }
116
117 async getObject(params?: {
118 memberFilter: (value: ConversationMember, index: number, array: ConversationMember[]) => boolean;
119 }) {
120 const members = params?.memberFilter ? this.members.filter(params.memberFilter) : this.members;
121 return {
122 id: this.id,
123 messages: this.messages,
124 members: await Promise.all(
125 members.map(async (member) => {
126 //Object.assign({}, member);
127 return {
128 role: member.role,
129 contact: await member.contact.getObject(),
130 };
131 })
132 ),
idillonae655dd2022-10-14 18:11:02 -0400133 infos: this._infos,
simon06527b02022-10-01 15:01:47 -0400134 };
135 }
136
137 getSummary() {
138 return this.getObject();
139 }
140
141 getDisplayUri() {
142 return this.getId() || this.getFirstMember().contact.getUri();
143 }
144
145 getFirstMember() {
146 return this.members[0];
147 }
148
149 getMembers() {
150 return this.members;
151 }
152
153 addMessage(message: Message) {
154 if (this.messages.length === 0) this.messages.push(message);
155 else if (message.id === this.messages[this.messages.length - 1].linearizedParent) {
156 this.messages.push(message);
157 } else if (message.linearizedParent === this.messages[0].id) {
158 this.messages.unshift(message);
159 } else {
160 console.log("Can't insert message " + message.id);
161 }
162 }
163
164 addLoadedMessages(messages: Message[]) {
165 messages.forEach((message) => this.addMessage(message));
166 }
167
168 getMessages() {
169 return this.messages;
170 }
171
idillonae655dd2022-10-14 18:11:02 -0400172 get infos() {
173 return this._infos;
174 }
175
simon06527b02022-10-01 15:01:47 -0400176 set infos(infos: ConversationInfos) {
177 this._infos = infos;
178 }
179
180 get requests(): Record<string, ConversationRequest> {
181 return this._requests;
182 }
183
184 set requests(value: Record<string, ConversationRequest>) {
185 this._requests = value;
186 }
187
188 get listeners(): ConversationListeners {
189 return this._listeners;
190 }
191
192 set listeners(listeners: ConversationListeners) {
193 this._listeners = listeners;
194 }
195}