diff options
Diffstat (limited to 'app/Controllers/Http/UserController.ts')
-rw-r--r-- | app/Controllers/Http/UserController.ts | 239 |
1 files changed, 112 insertions, 127 deletions
diff --git a/app/Controllers/Http/UserController.ts b/app/Controllers/Http/UserController.ts index ef7cfdd..088f7b1 100644 --- a/app/Controllers/Http/UserController.ts +++ b/app/Controllers/Http/UserController.ts | |||
@@ -1,134 +1,125 @@ | |||
1 | import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; | 1 | import type { HttpContext } from '@adonisjs/core/http' |
2 | import { schema, rules } from '@ioc:Adonis/Core/Validator'; | 2 | import { schema, rules } from '@adonisjs/validator' |
3 | import User from 'App/Models/User'; | 3 | import User from '#app/Models/User' |
4 | import { connectWithFranz, isRegistrationEnabled } from '../../../config/app'; | 4 | import { connectWithFranz, isRegistrationEnabled } from '../../../config/app.js' |
5 | import crypto from 'node:crypto'; | 5 | import crypto from 'node:crypto' |
6 | import { v4 as uuid } from 'uuid'; | 6 | import { v4 as uuid } from 'uuid' |
7 | import Workspace from 'App/Models/Workspace'; | 7 | import Workspace from '#app/Models/Workspace' |
8 | import Service from 'App/Models/Service'; | 8 | import Service from '#app/Models/Service' |
9 | import fetch from 'node-fetch'; | ||
10 | 9 | ||
11 | // TODO: This file needs to be refactored and cleaned up to include types | 10 | // TODO: This file needs to be refactored and cleaned up to include types |
12 | import { handleVerifyAndReHash } from '../../../helpers/PasswordHash'; | 11 | import { handleVerifyAndReHash } from '../../../helpers/PasswordHash.js' |
13 | 12 | ||
14 | const newPostSchema = schema.create({ | 13 | const newPostSchema = schema.create({ |
15 | firstname: schema.string(), | 14 | firstname: schema.string(), |
16 | lastname: schema.string(), | 15 | lastname: schema.string(), |
17 | email: schema.string([ | 16 | email: schema.string([rules.email(), rules.unique({ table: 'users', column: 'email' })]), |
18 | rules.email(), | ||
19 | rules.unique({ table: 'users', column: 'email' }), | ||
20 | ]), | ||
21 | password: schema.string([rules.minLength(8)]), | 17 | password: schema.string([rules.minLength(8)]), |
22 | }); | 18 | }) |
23 | 19 | ||
24 | const franzImportSchema = schema.create({ | 20 | const franzImportSchema = schema.create({ |
25 | email: schema.string([ | 21 | email: schema.string([rules.email(), rules.unique({ table: 'users', column: 'email' })]), |
26 | rules.email(), | ||
27 | rules.unique({ table: 'users', column: 'email' }), | ||
28 | ]), | ||
29 | password: schema.string([rules.minLength(8)]), | 22 | password: schema.string([rules.minLength(8)]), |
30 | }); | 23 | }) |
31 | 24 | ||
32 | // // TODO: This whole controller needs to be changed such that it can support importing from both Franz and Ferdi | 25 | // // TODO: This whole controller needs to be changed such that it can support importing from both Franz and Ferdi |
33 | // eslint-disable-next-line @typescript-eslint/no-explicit-any | 26 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
34 | const franzRequest = (route: any, method: any, auth: any) => | 27 | const franzRequest = (route: any, method: any, auth: any) => |
35 | new Promise((resolve, reject) => { | 28 | new Promise((resolve, reject) => { |
36 | const base = 'https://api.franzinfra.com/v1/'; | 29 | const base = 'https://api.franzinfra.com/v1/' |
37 | const user = | 30 | const user = |
38 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36'; | 31 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36' |
39 | 32 | ||
40 | try { | 33 | try { |
41 | fetch(base + route, { | 34 | fetch(base + route, { |
42 | method, | 35 | method, |
43 | headers: { | 36 | headers: { |
44 | Authorization: `Bearer ${auth}`, | 37 | 'Authorization': `Bearer ${auth}`, |
45 | 'User-Agent': user, | 38 | 'User-Agent': user, |
46 | }, | 39 | }, |
47 | }) | 40 | }) |
48 | .then(data => data.json()) | 41 | .then((data) => data.json()) |
49 | .then(json => resolve(json)); | 42 | .then((json) => resolve(json)) |
50 | } catch { | 43 | } catch { |
51 | reject(); | 44 | reject() |
52 | } | 45 | } |
53 | }); | 46 | }) |
54 | 47 | ||
55 | export default class UsersController { | 48 | export default class UsersController { |
56 | // Register a new user | 49 | // Register a new user |
57 | public async signup({ request, response, auth }: HttpContextContract) { | 50 | public async signup({ request, response, auth }: HttpContext) { |
58 | if (isRegistrationEnabled === 'false') { | 51 | if (isRegistrationEnabled === 'false') { |
59 | return response.status(401).send({ | 52 | return response.status(401).send({ |
60 | message: 'Registration is disabled on this server', | 53 | message: 'Registration is disabled on this server', |
61 | status: 401, | 54 | status: 401, |
62 | }); | 55 | }) |
63 | } | 56 | } |
64 | 57 | ||
65 | // Validate user input | 58 | // Validate user input |
66 | let data; | 59 | let data |
67 | try { | 60 | try { |
68 | data = await request.validate({ schema: newPostSchema }); | 61 | data = await request.validate({ schema: newPostSchema }) |
69 | } catch (error) { | 62 | } catch (error) { |
70 | return response.status(401).send({ | 63 | return response.status(401).send({ |
71 | message: 'Invalid POST arguments', | 64 | message: 'Invalid POST arguments', |
72 | messages: error.messages, | 65 | messages: error.messages, |
73 | status: 401, | 66 | status: 401, |
74 | }); | 67 | }) |
75 | } | 68 | } |
76 | 69 | ||
77 | // Create user in DB | 70 | // Create user in DB |
78 | let user; | 71 | let user |
79 | try { | 72 | try { |
80 | user = await User.create({ | 73 | user = await User.create({ |
81 | email: data.email, | 74 | email: data.email, |
82 | password: data.password, | 75 | password: data.password, |
83 | username: data.firstname, | 76 | username: data.firstname, |
84 | lastname: data.lastname, | 77 | lastname: data.lastname, |
85 | }); | 78 | }) |
86 | } catch { | 79 | } catch { |
87 | return response.status(401).send({ | 80 | return response.status(401).send({ |
88 | message: 'E-Mail address already in use', | 81 | message: 'E-Mail address already in use', |
89 | status: 401, | 82 | status: 401, |
90 | }); | 83 | }) |
91 | } | 84 | } |
92 | 85 | ||
93 | // Generate new auth token | 86 | // Generate new auth token |
94 | const token = await auth.use('jwt').login(user, { payload: {} }); | 87 | const token = await auth.use('jwt').login(user, { payload: {} }) |
95 | 88 | ||
96 | return response.send({ | 89 | return response.send({ |
97 | message: 'Successfully created account', | 90 | message: 'Successfully created account', |
98 | token: token.accessToken, | 91 | token: token.accessToken, |
99 | }); | 92 | }) |
100 | } | 93 | } |
101 | 94 | ||
102 | // Login using an existing user | 95 | // Login using an existing user |
103 | public async login({ request, response, auth }: HttpContextContract) { | 96 | public async login({ request, response, auth }: HttpContext) { |
104 | if (!request.header('Authorization')) { | 97 | if (!request.header('Authorization')) { |
105 | return response.status(401).send({ | 98 | return response.status(401).send({ |
106 | message: 'Please provide authorization', | 99 | message: 'Please provide authorization', |
107 | status: 401, | 100 | status: 401, |
108 | }); | 101 | }) |
109 | } | 102 | } |
110 | 103 | ||
111 | // Get auth data from auth token | 104 | // Get auth data from auth token |
112 | const authHeader = atob( | 105 | const authHeader = atob(request.header('Authorization')!.replace('Basic ', '')).split(':') |
113 | request.header('Authorization')!.replace('Basic ', ''), | ||
114 | ).split(':'); | ||
115 | 106 | ||
116 | // Check if user with email exists | 107 | // Check if user with email exists |
117 | const user = await User.query().where('email', authHeader[0]).first(); | 108 | const user = await User.query().where('email', authHeader[0]).first() |
118 | if (!user?.email) { | 109 | if (!user?.email) { |
119 | return response.status(401).send({ | 110 | return response.status(401).send({ |
120 | message: 'User credentials not valid', | 111 | message: 'User credentials not valid', |
121 | code: 'invalid-credentials', | 112 | code: 'invalid-credentials', |
122 | status: 401, | 113 | status: 401, |
123 | }); | 114 | }) |
124 | } | 115 | } |
125 | 116 | ||
126 | // Verify password | 117 | // Verify password |
127 | let isMatchedPassword = false; | 118 | let isMatchedPassword = false |
128 | try { | 119 | try { |
129 | isMatchedPassword = await handleVerifyAndReHash(user, authHeader[1]); | 120 | isMatchedPassword = await handleVerifyAndReHash(user, authHeader[1]) |
130 | } catch (error) { | 121 | } catch (error) { |
131 | return response.internalServerError({ message: error.message }); | 122 | return response.internalServerError({ message: error.message }) |
132 | } | 123 | } |
133 | 124 | ||
134 | if (!isMatchedPassword) { | 125 | if (!isMatchedPassword) { |
@@ -136,31 +127,28 @@ export default class UsersController { | |||
136 | message: 'User credentials not valid', | 127 | message: 'User credentials not valid', |
137 | code: 'invalid-credentials', | 128 | code: 'invalid-credentials', |
138 | status: 401, | 129 | status: 401, |
139 | }); | 130 | }) |
140 | } | 131 | } |
141 | 132 | ||
142 | // Generate token | 133 | // Generate token |
143 | const token = await auth.use('jwt').login(user, { payload: {} }); | 134 | const token = await auth.use('jwt').login(user, { payload: {} }) |
144 | 135 | ||
145 | return response.send({ | 136 | return response.send({ |
146 | message: 'Successfully logged in', | 137 | message: 'Successfully logged in', |
147 | token: token.accessToken, | 138 | token: token.accessToken, |
148 | }); | 139 | }) |
149 | } | 140 | } |
150 | 141 | ||
151 | // Return information about the current user | 142 | // Return information about the current user |
152 | public async me({ request, response, auth }: HttpContextContract) { | 143 | public async me({ request, response, auth }: HttpContext) { |
153 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 144 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
154 | const user = auth.user ?? request.user; | 145 | const user = auth.user ?? request.user |
155 | 146 | ||
156 | if (!user) { | 147 | if (!user) { |
157 | return response.send('Missing or invalid api token'); | 148 | return response.send('Missing or invalid api token') |
158 | } | 149 | } |
159 | 150 | ||
160 | const settings = | 151 | const settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings |
161 | typeof user.settings === 'string' | ||
162 | ? JSON.parse(user.settings) | ||
163 | : user.settings; | ||
164 | 152 | ||
165 | return response.send({ | 153 | return response.send({ |
166 | accountType: 'individual', | 154 | accountType: 'individual', |
@@ -176,29 +164,29 @@ export default class UsersController { | |||
176 | lastname: user.lastname, | 164 | lastname: user.lastname, |
177 | locale: 'en-US', | 165 | locale: 'en-US', |
178 | ...settings, | 166 | ...settings, |
179 | }); | 167 | }) |
180 | } | 168 | } |
181 | 169 | ||
182 | public async updateMe({ request, response, auth }: HttpContextContract) { | 170 | public async updateMe({ request, response, auth }: HttpContext) { |
183 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 171 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
184 | const user = auth.user ?? request.user; | 172 | const user = auth.user ?? request.user |
185 | 173 | ||
186 | if (!user) { | 174 | if (!user) { |
187 | return response.send('Missing or invalid api token'); | 175 | return response.send('Missing or invalid api token') |
188 | } | 176 | } |
189 | 177 | ||
190 | let settings = user.settings || {}; | 178 | let settings = user.settings || {} |
191 | if (typeof settings === 'string') { | 179 | if (typeof settings === 'string') { |
192 | settings = JSON.parse(settings); | 180 | settings = JSON.parse(settings) |
193 | } | 181 | } |
194 | 182 | ||
195 | const newSettings = { | 183 | const newSettings = { |
196 | ...settings, | 184 | ...settings, |
197 | ...request.all(), | 185 | ...request.all(), |
198 | }; | 186 | } |
199 | 187 | ||
200 | user.settings = JSON.stringify(newSettings); | 188 | user.settings = JSON.stringify(newSettings) |
201 | await user.save(); | 189 | await user.save() |
202 | 190 | ||
203 | return response.send({ | 191 | return response.send({ |
204 | data: { | 192 | data: { |
@@ -217,140 +205,137 @@ export default class UsersController { | |||
217 | ...newSettings, | 205 | ...newSettings, |
218 | }, | 206 | }, |
219 | status: ['data-updated'], | 207 | status: ['data-updated'], |
220 | }); | 208 | }) |
221 | } | 209 | } |
222 | 210 | ||
223 | public async newToken({ request, response, auth }: HttpContextContract) { | 211 | public async newToken({ request, response, auth }: HttpContext) { |
224 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 212 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
225 | const user = auth.user ?? request.user; | 213 | const user = auth.user ?? request.user |
226 | 214 | ||
227 | if (!user) { | 215 | if (!user) { |
228 | return response.send('Missing or invalid api token'); | 216 | return response.send('Missing or invalid api token') |
229 | } | 217 | } |
230 | 218 | ||
231 | const token = await auth.use('jwt').generate(user, { payload: {} }); | 219 | const token = await auth.use('jwt').generate(user, { payload: {} }) |
232 | 220 | ||
233 | return response.send({ | 221 | return response.send({ |
234 | token: token.accessToken, | 222 | token: token.accessToken, |
235 | }); | 223 | }) |
236 | } | 224 | } |
237 | 225 | ||
238 | public async import({ request, response, view }: HttpContextContract) { | 226 | public async import({ request, response, view }: HttpContext) { |
239 | if (isRegistrationEnabled === 'false') { | 227 | if (isRegistrationEnabled === 'false') { |
240 | return response.status(401).send({ | 228 | return response.status(401).send({ |
241 | message: 'Registration is disabled on this server', | 229 | message: 'Registration is disabled on this server', |
242 | status: 401, | 230 | status: 401, |
243 | }); | 231 | }) |
244 | } | 232 | } |
245 | 233 | ||
246 | if (connectWithFranz === 'false') { | 234 | if (connectWithFranz === 'false') { |
247 | return response.send( | 235 | return response.send( |
248 | 'We could not import your Franz account data.\n\nIf you are the server owner, please set CONNECT_WITH_FRANZ to true to enable account imports.', | 236 | 'We could not import your Franz account data.\n\nIf you are the server owner, please set CONNECT_WITH_FRANZ to true to enable account imports.' |
249 | ); | 237 | ) |
250 | } | 238 | } |
251 | 239 | ||
252 | // Validate user input | 240 | // Validate user input |
253 | let data; | 241 | let data |
254 | try { | 242 | try { |
255 | data = await request.validate({ schema: franzImportSchema }); | 243 | data = await request.validate({ schema: franzImportSchema }) |
256 | } catch (error) { | 244 | } catch (error) { |
257 | return view.render('others.message', { | 245 | return view.render('others.message', { |
258 | heading: 'Error while importing', | 246 | heading: 'Error while importing', |
259 | text: error.messages, | 247 | text: error.messages, |
260 | }); | 248 | }) |
261 | } | 249 | } |
262 | 250 | ||
263 | const { email, password } = data; | 251 | const { email, password } = data |
264 | 252 | ||
265 | const hashedPassword = crypto | 253 | const hashedPassword = crypto.createHash('sha256').update(password).digest('base64') |
266 | .createHash('sha256') | ||
267 | .update(password) | ||
268 | .digest('base64'); | ||
269 | 254 | ||
270 | const base = 'https://api.franzinfra.com/v1/'; | 255 | const base = 'https://api.franzinfra.com/v1/' |
271 | const userAgent = | 256 | const userAgent = |
272 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36'; | 257 | 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Franz/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36' |
273 | 258 | ||
274 | // Try to get an authentication token | 259 | // Try to get an authentication token |
275 | let token; | 260 | let token |
276 | try { | 261 | try { |
277 | const basicToken = btoa(`${email}:${hashedPassword}`); | 262 | const basicToken = btoa(`${email}:${hashedPassword}`) |
278 | const loginBody = { | 263 | const loginBody = { |
279 | isZendeskLogin: false, | 264 | isZendeskLogin: false, |
280 | }; | 265 | } |
281 | 266 | ||
282 | const rawResponse = await fetch(`${base}auth/login`, { | 267 | const rawResponse = await fetch(`${base}auth/login`, { |
283 | method: 'POST', | 268 | method: 'POST', |
284 | body: JSON.stringify(loginBody), | 269 | body: JSON.stringify(loginBody), |
285 | headers: { | 270 | headers: { |
286 | Authorization: `Basic ${basicToken}`, | 271 | 'Authorization': `Basic ${basicToken}`, |
287 | 'User-Agent': userAgent, | 272 | 'User-Agent': userAgent, |
288 | 'Content-Type': 'application/json', | 273 | 'Content-Type': 'application/json', |
289 | accept: '*/*', | 274 | 'accept': '*/*', |
290 | 'x-franz-source': 'Web', | 275 | 'x-franz-source': 'Web', |
291 | }, | 276 | }, |
292 | }); | 277 | }) |
293 | const content = await rawResponse.json(); | 278 | const content = await rawResponse.json() |
294 | 279 | ||
295 | if (!content.message || content.message !== 'Successfully logged in') { | 280 | if (!content.message || content.message !== 'Successfully logged in') { |
296 | const errorMessage = | 281 | const errorMessage = |
297 | 'Could not login into Franz with your supplied credentials. Please check and try again'; | 282 | 'Could not login into Franz with your supplied credentials. Please check and try again' |
298 | return response.status(401).send(errorMessage); | 283 | return response.status(401).send(errorMessage) |
299 | } | 284 | } |
300 | 285 | ||
301 | token = content.token; | 286 | token = content.token |
302 | } catch (error) { | 287 | } catch (error) { |
303 | return response.status(401).send({ | 288 | return response.status(401).send({ |
304 | message: 'Cannot login to Franz', | 289 | message: 'Cannot login to Franz', |
305 | error: error, | 290 | error: error, |
306 | }); | 291 | }) |
307 | } | 292 | } |
308 | 293 | ||
309 | // Get user information | 294 | // Get user information |
310 | // eslint-disable-next-line @typescript-eslint/no-explicit-any | 295 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
311 | let userInf: any = false; | 296 | let userInf: any = false |
312 | try { | 297 | try { |
313 | userInf = await franzRequest('me', 'GET', token); | 298 | userInf = await franzRequest('me', 'GET', token) |
314 | } catch (error) { | 299 | } catch (error) { |
315 | const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${error}`; | 300 | const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${error}` |
316 | return response.status(401).send(errorMessage); | 301 | return response.status(401).send(errorMessage) |
317 | } | 302 | } |
318 | if (!userInf) { | 303 | if (!userInf) { |
319 | const errorMessage = | 304 | const errorMessage = |
320 | 'Could not get your user info from Franz. Please check your credentials or try again later'; | 305 | 'Could not get your user info from Franz. Please check your credentials or try again later' |
321 | return response.status(401).send(errorMessage); | 306 | return response.status(401).send(errorMessage) |
322 | } | 307 | } |
323 | 308 | ||
324 | // Create user in DB | 309 | // Create user in DB |
325 | let user; | 310 | let user |
326 | try { | 311 | try { |
327 | user = await User.create({ | 312 | user = await User.create({ |
328 | email: userInf.email, | 313 | email: userInf.email, |
329 | password: hashedPassword, | 314 | password: hashedPassword, |
330 | username: userInf.firstname, | 315 | username: userInf.firstname, |
331 | lastname: userInf.lastname, | 316 | lastname: userInf.lastname, |
332 | }); | 317 | }) |
333 | } catch (error) { | 318 | } catch (error) { |
334 | const errorMessage = `Could not create your user in our system.\nError: ${error}`; | 319 | const errorMessage = `Could not create your user in our system.\nError: ${error}` |
335 | return response.status(401).send(errorMessage); | 320 | return response.status(401).send(errorMessage) |
336 | } | 321 | } |
337 | 322 | ||
338 | const serviceIdTranslation = {}; | 323 | const serviceIdTranslation = {} |
339 | 324 | ||
340 | // Import services | 325 | // Import services |
341 | try { | 326 | try { |
342 | const services = await franzRequest('me/services', 'GET', token); | 327 | const services = await franzRequest('me/services', 'GET', token) |
343 | 328 | ||
344 | // @ts-expect-error | 329 | // @ts-expect-error |
345 | for (const service of services) { | 330 | for (const service of services) { |
346 | // Get new, unused uuid | 331 | // Get new, unused uuid |
347 | let serviceId; | 332 | let serviceId |
348 | do { | 333 | do { |
349 | serviceId = uuid(); | 334 | serviceId = uuid() |
350 | } while ( | 335 | } while ( |
351 | // eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member | 336 | // eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member |
352 | (await Service.query().where('serviceId', serviceId)).length > 0 | 337 | (await Service.query().where('serviceId', serviceId)).length > 0 |
353 | ); | 338 | ) |
354 | 339 | ||
355 | // eslint-disable-next-line no-await-in-loop | 340 | // eslint-disable-next-line no-await-in-loop |
356 | await Service.create({ | 341 | await Service.create({ |
@@ -359,34 +344,34 @@ export default class UsersController { | |||
359 | name: service.name, | 344 | name: service.name, |
360 | recipeId: service.recipeId, | 345 | recipeId: service.recipeId, |
361 | settings: JSON.stringify(service), | 346 | settings: JSON.stringify(service), |
362 | }); | 347 | }) |
363 | 348 | ||
364 | // @ts-expect-error | 349 | // @ts-expect-error |
365 | serviceIdTranslation[service.id] = serviceId; | 350 | serviceIdTranslation[service.id] = serviceId |
366 | } | 351 | } |
367 | } catch (error) { | 352 | } catch (error) { |
368 | const errorMessage = `Could not import your services into our system.\nError: ${error}`; | 353 | const errorMessage = `Could not import your services into our system.\nError: ${error}` |
369 | return response.status(401).send(errorMessage); | 354 | return response.status(401).send(errorMessage) |
370 | } | 355 | } |
371 | 356 | ||
372 | // Import workspaces | 357 | // Import workspaces |
373 | try { | 358 | try { |
374 | const workspaces = await franzRequest('workspace', 'GET', token); | 359 | const workspaces = await franzRequest('workspace', 'GET', token) |
375 | 360 | ||
376 | // @ts-expect-error | 361 | // @ts-expect-error |
377 | for (const workspace of workspaces) { | 362 | for (const workspace of workspaces) { |
378 | let workspaceId; | 363 | let workspaceId |
379 | do { | 364 | do { |
380 | workspaceId = uuid(); | 365 | workspaceId = uuid() |
381 | } while ( | 366 | } while ( |
382 | // eslint-disable-next-line unicorn/no-await-expression-member, no-await-in-loop | 367 | // eslint-disable-next-line unicorn/no-await-expression-member, no-await-in-loop |
383 | (await Workspace.query().where('workspaceId', workspaceId)).length > 0 | 368 | (await Workspace.query().where('workspaceId', workspaceId)).length > 0 |
384 | ); | 369 | ) |
385 | 370 | ||
386 | const services = workspace.services.map( | 371 | const services = workspace.services.map( |
387 | // @ts-expect-error | 372 | // @ts-expect-error |
388 | service => serviceIdTranslation[service], | 373 | (service) => serviceIdTranslation[service] |
389 | ); | 374 | ) |
390 | 375 | ||
391 | // eslint-disable-next-line no-await-in-loop | 376 | // eslint-disable-next-line no-await-in-loop |
392 | await Workspace.create({ | 377 | await Workspace.create({ |
@@ -396,15 +381,15 @@ export default class UsersController { | |||
396 | order: workspace.order, | 381 | order: workspace.order, |
397 | services: JSON.stringify(services), | 382 | services: JSON.stringify(services), |
398 | data: JSON.stringify({}), | 383 | data: JSON.stringify({}), |
399 | }); | 384 | }) |
400 | } | 385 | } |
401 | } catch (error) { | 386 | } catch (error) { |
402 | const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`; | 387 | const errorMessage = `Could not import your workspaces into our system.\nError: ${error}` |
403 | return response.status(401).send(errorMessage); | 388 | return response.status(401).send(errorMessage) |
404 | } | 389 | } |
405 | 390 | ||
406 | return response.send( | 391 | return response.send( |
407 | 'Your account has been imported. You can now use your Franz/Ferdi account in Ferdium.', | 392 | 'Your account has been imported. You can now use your Franz/Ferdi account in Ferdium.' |
408 | ); | 393 | ) |
409 | } | 394 | } |
410 | } | 395 | } |