blob: c38e46d1b6cc8e369999ca2df4f135f1ff9e2bf8 [file] [log] [blame]
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -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 */
18import { Request, Router } from 'express';
19import asyncHandler from 'express-async-handler';
20import { ParamsDictionary } from 'express-serve-static-core';
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050021import {
22 ContactDetails,
23 HttpStatusCode,
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050024 IConversationMember,
25 NewConversationRequestBody,
26 NewMessageRequestBody,
27} from 'jami-web-common';
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040028import { Container } from 'typedi';
29
30import { Jamid } from '../jamid/jamid.js';
31import { authenticateToken } from '../middleware/auth.js';
idillon18283ac2023-01-07 12:06:42 -050032import { ConversationService } from '../services/ConversationService.js';
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040033
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040034const jamid = Container.get(Jamid);
idillon18283ac2023-01-07 12:06:42 -050035const conversationService = Container.get(ConversationService);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040036
37export const conversationRouter = Router();
38
39conversationRouter.use(authenticateToken);
40
41conversationRouter.get(
42 '/',
43 asyncHandler(async (_req, res) => {
44 const accountId = res.locals.accountId;
45
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040046 const conversationIds = jamid.getConversationIds(accountId);
47
idillon07d31cc2022-12-06 22:40:14 -050048 const conversationsSummaries = [];
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040049 for (const conversationId of conversationIds) {
idillon18283ac2023-01-07 12:06:42 -050050 const conversationSummary = await conversationService.createConversationSummary(accountId, conversationId);
idillon07d31cc2022-12-06 22:40:14 -050051 conversationsSummaries.push(conversationSummary);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040052 }
53
idillon07d31cc2022-12-06 22:40:14 -050054 res.send(conversationsSummaries);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040055 })
56);
57
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050058conversationRouter.post(
59 '/',
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -050060 (req: Request<ParamsDictionary, ContactDetails | string, Partial<NewConversationRequestBody>>, res) => {
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050061 const { members } = req.body;
62 if (members === undefined || members.length !== 1) {
63 res.status(HttpStatusCode.BadRequest).send('Missing members or more than one member in body');
64 return;
65 }
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040066
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050067 const accountId = res.locals.accountId;
68
69 const contactId = members[0];
70 jamid.addContact(accountId, contactId);
Michelle Sepkap Simedd82cbf2022-11-17 23:31:49 -050071 // We need to manually send a conversation request
72 jamid.sendTrustRequest(accountId, contactId);
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050073
74 const contactDetails = jamid.getContactDetails(accountId, contactId);
75 if (Object.keys(contactDetails).length === 0) {
76 res.status(HttpStatusCode.NotFound).send('No such member found');
77 return;
78 }
79
80 res.send(contactDetails);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040081 }
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050082);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040083
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040084conversationRouter.get(
85 '/:conversationId',
86 asyncHandler(async (req, res) => {
87 const accountId = res.locals.accountId;
88 const conversationId = req.params.conversationId;
89
idillon18283ac2023-01-07 12:06:42 -050090 const conversationSummary = await conversationService.createConversationSummary(accountId, conversationId);
idillon07d31cc2022-12-06 22:40:14 -050091 if (conversationSummary === undefined) {
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -050092 res.status(HttpStatusCode.NotFound).send('No such conversation found');
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -040093 return;
94 }
95
idillon07d31cc2022-12-06 22:40:14 -050096 res.send(conversationSummary);
97 })
98);
99
100conversationRouter.get(
101 '/:conversationId/infos',
102 asyncHandler(async (req, res) => {
103 const accountId = res.locals.accountId;
104 const conversationId = req.params.conversationId;
105
106 const infos = jamid.getConversationInfos(accountId, conversationId);
107 if (Object.keys(infos).length === 0) {
108 res.status(HttpStatusCode.NotFound).send('No such conversation found');
109 }
110
111 res.send(infos);
112 })
113);
114
115conversationRouter.get(
116 '/:conversationId/members',
117 asyncHandler(async (req, res) => {
118 const accountId = res.locals.accountId;
119 const conversationId = req.params.conversationId;
120
121 // Retrieve the URI of the current account (Account.username actually stores the URI rather than the username)
122 const accountUri = jamid.getAccountDetails(accountId)['Account.username'];
123
124 const infos = jamid.getConversationInfos(accountId, conversationId);
125 if (Object.keys(infos).length === 0) {
126 res.status(HttpStatusCode.NotFound).send('No such conversation found');
127 return;
128 }
129
130 const members = jamid.getConversationMembers(accountId, conversationId);
131
132 const namedMembers: IConversationMember[] = [];
133 for (const member of members) {
134 // Exclude current user from returned conversation members
135 if (member.uri === accountUri) {
136 continue;
137 }
138
139 // Add usernames for conversation members
140 const { username } = await jamid.lookupAddress(member.uri, accountId);
141 namedMembers.push({
142 role: member.role,
143 contact: {
144 uri: member.uri,
145 registeredName: username,
146 },
147 });
148 }
149
150 res.send(namedMembers);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400151 })
152);
153
154conversationRouter.get(
155 '/:conversationId/messages',
156 asyncHandler(async (req, res) => {
157 const accountId = res.locals.accountId;
158 const conversationId = req.params.conversationId;
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500159 const infos = jamid.getConversationInfos(accountId, conversationId);
160 if (Object.keys(infos).length === 0) {
161 res.status(HttpStatusCode.NotFound).send('No such conversation found');
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400162 return;
163 }
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400164 const messages = await jamid.getConversationMessages(accountId, conversationId);
165 res.send(messages);
166 })
167);
168
169conversationRouter.post(
170 '/:conversationId/messages',
Misha Krieger-Raynauldcfa44302022-11-30 18:36:36 -0500171 (req: Request<ParamsDictionary, string, Partial<NewMessageRequestBody>>, res) => {
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400172 const { message } = req.body;
173 if (message === undefined) {
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500174 res.status(HttpStatusCode.BadRequest).send('Missing message in body');
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400175 return;
176 }
177
Misha Krieger-Raynauldcb11bba2022-11-11 18:08:33 -0500178 const accountId = res.locals.accountId;
179 const conversationId = req.params.conversationId;
180
181 const infos = jamid.getConversationInfos(accountId, conversationId);
182 if (Object.keys(infos).length === 0) {
183 res.status(HttpStatusCode.NotFound).send('No such conversation found');
184 return;
185 }
186
187 jamid.sendConversationMessage(accountId, conversationId, message);
188 res.sendStatus(HttpStatusCode.NoContent);
Misha Krieger-Raynauld8a381da2022-11-03 17:37:51 -0400189 }
190);
idillon07d31cc2022-12-06 22:40:14 -0500191
192conversationRouter.delete('/:conversationId', (req, res) => {
193 jamid.removeConversation(res.locals.accountId, req.params.conversationId);
194 res.sendStatus(HttpStatusCode.NoContent);
195});