diff options
author | MCMXC <16797721+mcmxcdev@users.noreply.github.com> | 2024-02-10 18:19:14 -0700 |
---|---|---|
committer | Vijay A <vraravam@users.noreply.github.com> | 2024-02-13 06:59:44 +0530 |
commit | 7584d2d7a7110aef0331ebfa178b2295842c59fa (patch) | |
tree | 900cd71237e6231b57936fcce77ff229cd459041 /app/Controllers/Http/ServiceController.ts | |
parent | upgrade recipes submodule (diff) | |
download | ferdium-server-7584d2d7a7110aef0331ebfa178b2295842c59fa.tar.gz ferdium-server-7584d2d7a7110aef0331ebfa178b2295842c59fa.tar.zst ferdium-server-7584d2d7a7110aef0331ebfa178b2295842c59fa.zip |
refactor: project maintenance
- work in progress
Diffstat (limited to 'app/Controllers/Http/ServiceController.ts')
-rw-r--r-- | app/Controllers/Http/ServiceController.ts | 204 |
1 files changed, 92 insertions, 112 deletions
diff --git a/app/Controllers/Http/ServiceController.ts b/app/Controllers/Http/ServiceController.ts index 76e72e4..9988244 100644 --- a/app/Controllers/Http/ServiceController.ts +++ b/app/Controllers/Http/ServiceController.ts | |||
@@ -1,49 +1,49 @@ | |||
1 | import type { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; | 1 | import type { HttpContext } from '@adonisjs/core/http' |
2 | import { schema } from '@ioc:Adonis/Core/Validator'; | 2 | import { schema } from '@adonisjs/validator' |
3 | import Service from 'App/Models/Service'; | 3 | import Service from '#app/Models/Service' |
4 | import { url } from 'Config/app'; | 4 | import { url } from '#config/app' |
5 | import { v4 as uuid } from 'uuid'; | 5 | import { v4 as uuid } from 'uuid' |
6 | import * as fs from 'fs-extra'; | 6 | import * as fs from 'fs-extra' |
7 | import path from 'node:path'; | 7 | import path from 'node:path' |
8 | import Application from '@ioc:Adonis/Core/Application'; | 8 | import { app } from '@adonisjs/core/services/app' |
9 | import sanitize from 'sanitize-filename'; | 9 | import sanitize from 'sanitize-filename' |
10 | 10 | ||
11 | const createSchema = schema.create({ | 11 | const createSchema = schema.create({ |
12 | name: schema.string(), | 12 | name: schema.string(), |
13 | recipeId: schema.string(), | 13 | recipeId: schema.string(), |
14 | }); | 14 | }) |
15 | 15 | ||
16 | export default class ServiceController { | 16 | export default class ServiceController { |
17 | // Create a new service for user | 17 | // Create a new service for user |
18 | public async create({ request, response, auth }: HttpContextContract) { | 18 | public async create({ request, response, auth }: HttpContext) { |
19 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 19 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
20 | const user = auth.user ?? request.user; | 20 | const user = auth.user ?? request.user |
21 | 21 | ||
22 | if (!user) { | 22 | if (!user) { |
23 | return response.unauthorized('Missing or invalid api token'); | 23 | return response.unauthorized('Missing or invalid api token') |
24 | } | 24 | } |
25 | 25 | ||
26 | // Validate user input | 26 | // Validate user input |
27 | const data = request.all(); | 27 | const data = request.all() |
28 | 28 | ||
29 | try { | 29 | try { |
30 | await request.validate({ schema: createSchema }); | 30 | await request.validate({ schema: createSchema }) |
31 | } catch (error) { | 31 | } catch (error) { |
32 | return response.status(401).send({ | 32 | return response.status(401).send({ |
33 | message: 'Invalid POST arguments', | 33 | message: 'Invalid POST arguments', |
34 | messages: error.messages, | 34 | messages: error.messages, |
35 | status: 401, | 35 | status: 401, |
36 | }); | 36 | }) |
37 | } | 37 | } |
38 | 38 | ||
39 | // Get new, unused uuid | 39 | // Get new, unused uuid |
40 | let serviceId; | 40 | let serviceId |
41 | do { | 41 | do { |
42 | serviceId = uuid(); | 42 | serviceId = uuid() |
43 | } while ( | 43 | } while ( |
44 | // eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member | 44 | // eslint-disable-next-line no-await-in-loop, unicorn/no-await-expression-member |
45 | (await Service.query().where('serviceId', serviceId)).length > 0 | 45 | (await Service.query().where('serviceId', serviceId)).length > 0 |
46 | ); | 46 | ) |
47 | 47 | ||
48 | await Service.create({ | 48 | await Service.create({ |
49 | userId: user.id, | 49 | userId: user.id, |
@@ -51,7 +51,7 @@ export default class ServiceController { | |||
51 | name: data.name, | 51 | name: data.name, |
52 | recipeId: data.recipeId, | 52 | recipeId: data.recipeId, |
53 | settings: JSON.stringify(data), | 53 | settings: JSON.stringify(data), |
54 | }); | 54 | }) |
55 | 55 | ||
56 | return response.send({ | 56 | return response.send({ |
57 | data: { | 57 | data: { |
@@ -72,28 +72,26 @@ export default class ServiceController { | |||
72 | ...data, | 72 | ...data, |
73 | }, | 73 | }, |
74 | status: ['created'], | 74 | status: ['created'], |
75 | }); | 75 | }) |
76 | } | 76 | } |
77 | 77 | ||
78 | // List all services a user has created | 78 | // List all services a user has created |
79 | public async list({ request, response, auth }: HttpContextContract) { | 79 | public async list({ request, response, auth }: HttpContext) { |
80 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 80 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
81 | const user = auth.user ?? request.user; | 81 | const user = auth.user ?? request.user |
82 | 82 | ||
83 | if (!user) { | 83 | if (!user) { |
84 | return response.unauthorized('Missing or invalid api token'); | 84 | return response.unauthorized('Missing or invalid api token') |
85 | } | 85 | } |
86 | 86 | ||
87 | const { id } = user; | 87 | const { id } = user |
88 | const services = await user.related('services').query(); | 88 | const services = await user.related('services').query() |
89 | 89 | ||
90 | // Convert to array with all data Franz wants | 90 | // Convert to array with all data Franz wants |
91 | // eslint-disable-next-line @typescript-eslint/no-explicit-any | 91 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
92 | const servicesArray = services.map((service: any) => { | 92 | const servicesArray = services.map((service: any) => { |
93 | const settings = | 93 | const settings = |
94 | typeof service.settings === 'string' | 94 | typeof service.settings === 'string' ? JSON.parse(service.settings) : service.settings |
95 | ? JSON.parse(service.settings) | ||
96 | : service.settings; | ||
97 | 95 | ||
98 | return { | 96 | return { |
99 | customRecipe: false, | 97 | customRecipe: false, |
@@ -110,99 +108,87 @@ export default class ServiceController { | |||
110 | iconUrl: settings.iconId | 108 | iconUrl: settings.iconId |
111 | ? `${url}/v1/icon/${settings.iconId}` | 109 | ? `${url}/v1/icon/${settings.iconId}` |
112 | : // eslint-disable-next-line unicorn/no-null | 110 | : // eslint-disable-next-line unicorn/no-null |
113 | null, | 111 | null, |
114 | id: service.serviceId, | 112 | id: service.serviceId, |
115 | name: service.name, | 113 | name: service.name, |
116 | recipeId: service.recipeId, | 114 | recipeId: service.recipeId, |
117 | userId: id, | 115 | userId: id, |
118 | }; | 116 | } |
119 | }); | 117 | }) |
120 | 118 | ||
121 | return response.send(servicesArray); | 119 | return response.send(servicesArray) |
122 | } | 120 | } |
123 | 121 | ||
124 | public async delete({ | 122 | public async delete({ request, params, auth, response }: HttpContext) { |
125 | request, | ||
126 | params, | ||
127 | auth, | ||
128 | response, | ||
129 | }: HttpContextContract) { | ||
130 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 123 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
131 | const user = auth.user ?? request.user; | 124 | const user = auth.user ?? request.user |
132 | 125 | ||
133 | if (!user) { | 126 | if (!user) { |
134 | return response.unauthorized('Missing or invalid api token'); | 127 | return response.unauthorized('Missing or invalid api token') |
135 | } | 128 | } |
136 | 129 | ||
137 | // Update data in database | 130 | // Update data in database |
138 | await Service.query() | 131 | await Service.query().where('serviceId', params.id).where('userId', user.id).delete() |
139 | .where('serviceId', params.id) | ||
140 | .where('userId', user.id) | ||
141 | .delete(); | ||
142 | 132 | ||
143 | return response.send({ | 133 | return response.send({ |
144 | message: 'Sucessfully deleted service', | 134 | message: 'Sucessfully deleted service', |
145 | status: 200, | 135 | status: 200, |
146 | }); | 136 | }) |
147 | } | 137 | } |
148 | 138 | ||
149 | // TODO: Test if icon upload works | 139 | // TODO: Test if icon upload works |
150 | public async edit({ request, response, auth, params }: HttpContextContract) { | 140 | public async edit({ request, response, auth, params }: HttpContext) { |
151 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 141 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
152 | const user = auth.user ?? request.user; | 142 | const user = auth.user ?? request.user |
153 | 143 | ||
154 | if (!user) { | 144 | if (!user) { |
155 | return response.unauthorized('Missing or invalid api token'); | 145 | return response.unauthorized('Missing or invalid api token') |
156 | } | 146 | } |
157 | 147 | ||
158 | const { id } = params; | 148 | const { id } = params |
159 | const service = await Service.query() | 149 | const service = await Service.query() |
160 | .where('serviceId', id) | 150 | .where('serviceId', id) |
161 | .where('userId', user.id) | 151 | .where('userId', user.id) |
162 | .firstOrFail(); | 152 | .firstOrFail() |
163 | 153 | ||
164 | if (request.file('icon')) { | 154 | if (request.file('icon')) { |
165 | // Upload custom service icon | 155 | // Upload custom service icon |
166 | const icon = request.file('icon', { | 156 | const icon = request.file('icon', { |
167 | extnames: ['png', 'jpg', 'jpeg', 'svg'], | 157 | extnames: ['png', 'jpg', 'jpeg', 'svg'], |
168 | size: '2mb', | 158 | size: '2mb', |
169 | }); | 159 | }) |
170 | 160 | ||
171 | if (icon === null) { | 161 | if (icon === null) { |
172 | return response.badRequest('Icon not uploaded.'); | 162 | return response.badRequest('Icon not uploaded.') |
173 | } | 163 | } |
174 | 164 | ||
175 | const settings = | 165 | const settings = |
176 | typeof service.settings === 'string' | 166 | typeof service.settings === 'string' ? JSON.parse(service.settings) : service.settings |
177 | ? JSON.parse(service.settings) | ||
178 | : service.settings; | ||
179 | 167 | ||
180 | let iconId; | 168 | let iconId |
181 | do { | 169 | do { |
182 | iconId = uuid() + uuid(); | 170 | iconId = uuid() + uuid() |
183 | } while ( | 171 | } while ( |
184 | // eslint-disable-next-line no-await-in-loop | 172 | // eslint-disable-next-line no-await-in-loop |
185 | await fs.exists(path.join(Application.tmpPath('uploads'), iconId)) | 173 | await fs.exists(path.join(app.tmpPath('uploads'), iconId)) |
186 | ); | 174 | ) |
187 | iconId = `${iconId}.${icon.extname}`; | 175 | iconId = `${iconId}.${icon.extname}` |
188 | 176 | ||
189 | await icon.move(Application.tmpPath('uploads'), { | 177 | await icon.move(app.tmpPath('uploads'), { |
190 | name: iconId, | 178 | name: iconId, |
191 | overwrite: true, | 179 | overwrite: true, |
192 | }); | 180 | }) |
193 | 181 | ||
194 | if (icon.state !== 'moved') { | 182 | if (icon.state !== 'moved') { |
195 | return response.status(500).send(icon.errors); | 183 | return response.status(500).send(icon.errors) |
196 | } | 184 | } |
197 | 185 | ||
198 | const newSettings = { | 186 | const newSettings = { |
199 | ...settings, | 187 | ...settings, |
200 | 188 | ||
201 | iconId, | 189 | iconId, |
202 | customIconVersion: settings?.customIconVersion | 190 | customIconVersion: settings?.customIconVersion ? settings.customIconVersion + 1 : 1, |
203 | ? settings.customIconVersion + 1 | 191 | } |
204 | : 1, | ||
205 | }; | ||
206 | 192 | ||
207 | // Update data in database | 193 | // Update data in database |
208 | await Service.query() | 194 | await Service.query() |
@@ -211,7 +197,7 @@ export default class ServiceController { | |||
211 | .update({ | 197 | .update({ |
212 | name: service.name, | 198 | name: service.name, |
213 | settings: JSON.stringify(newSettings), | 199 | settings: JSON.stringify(newSettings), |
214 | }); | 200 | }) |
215 | 201 | ||
216 | return response.send({ | 202 | return response.send({ |
217 | data: { | 203 | data: { |
@@ -222,28 +208,24 @@ export default class ServiceController { | |||
222 | userId: user.id, | 208 | userId: user.id, |
223 | }, | 209 | }, |
224 | status: ['updated'], | 210 | status: ['updated'], |
225 | }); | 211 | }) |
226 | } | 212 | } |
227 | // Update service info | 213 | // Update service info |
228 | const data = request.all(); | 214 | const data = request.all() |
229 | 215 | ||
230 | const settings = { | 216 | const settings = { |
231 | ...(typeof service.settings === 'string' | 217 | ...(typeof service.settings === 'string' ? JSON.parse(service.settings) : service.settings), |
232 | ? JSON.parse(service.settings) | ||
233 | : service.settings), | ||
234 | ...data, | 218 | ...data, |
235 | }; | 219 | } |
236 | 220 | ||
237 | if (settings.customIcon === 'delete') { | 221 | if (settings.customIcon === 'delete') { |
238 | fs.remove( | 222 | fs.remove(path.join(app.tmpPath('uploads'), settings.iconId)).catch((error) => { |
239 | path.join(Application.tmpPath('uploads'), settings.iconId), | 223 | console.error(error) |
240 | ).catch(error => { | 224 | }) |
241 | console.error(error); | 225 | |
242 | }); | 226 | settings.iconId = undefined |
243 | 227 | settings.customIconVersion = undefined | |
244 | settings.iconId = undefined; | 228 | settings.customIcon = '' |
245 | settings.customIconVersion = undefined; | ||
246 | settings.customIcon = ''; | ||
247 | } | 229 | } |
248 | 230 | ||
249 | // Update data in database | 231 | // Update data in database |
@@ -253,13 +235,13 @@ export default class ServiceController { | |||
253 | .update({ | 235 | .update({ |
254 | name: data.name, | 236 | name: data.name, |
255 | settings: JSON.stringify(settings), | 237 | settings: JSON.stringify(settings), |
256 | }); | 238 | }) |
257 | 239 | ||
258 | // Get updated row | 240 | // Get updated row |
259 | const serviceUpdated = await Service.query() | 241 | const serviceUpdated = await Service.query() |
260 | .where('serviceId', id) | 242 | .where('serviceId', id) |
261 | .where('userId', user.id) | 243 | .where('userId', user.id) |
262 | .firstOrFail(); | 244 | .firstOrFail() |
263 | 245 | ||
264 | return response.send({ | 246 | return response.send({ |
265 | data: { | 247 | data: { |
@@ -270,19 +252,19 @@ export default class ServiceController { | |||
270 | userId: user.id, | 252 | userId: user.id, |
271 | }, | 253 | }, |
272 | status: ['updated'], | 254 | status: ['updated'], |
273 | }); | 255 | }) |
274 | } | 256 | } |
275 | 257 | ||
276 | // TODO: Test if this works | 258 | // TODO: Test if this works |
277 | public async reorder({ request, response, auth }: HttpContextContract) { | 259 | public async reorder({ request, response, auth }: HttpContext) { |
278 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. | 260 | // @ts-expect-error Property 'user' does not exist on type 'HttpContextContract'. |
279 | const user = auth.user ?? request.user; | 261 | const user = auth.user ?? request.user |
280 | 262 | ||
281 | if (!user) { | 263 | if (!user) { |
282 | return response.unauthorized('Missing or invalid api token'); | 264 | return response.unauthorized('Missing or invalid api token') |
283 | } | 265 | } |
284 | 266 | ||
285 | const data = request.all(); | 267 | const data = request.all() |
286 | 268 | ||
287 | for (const service of Object.keys(data)) { | 269 | for (const service of Object.keys(data)) { |
288 | // Get current settings from db | 270 | // Get current settings from db |
@@ -290,14 +272,14 @@ export default class ServiceController { | |||
290 | .where('serviceId', service) | 272 | .where('serviceId', service) |
291 | .where('userId', user.id) | 273 | .where('userId', user.id) |
292 | 274 | ||
293 | .firstOrFail(); | 275 | .firstOrFail() |
294 | 276 | ||
295 | const settings = { | 277 | const settings = { |
296 | ...(typeof serviceData.settings === 'string' | 278 | ...(typeof serviceData.settings === 'string' |
297 | ? JSON.parse(serviceData.settings) | 279 | ? JSON.parse(serviceData.settings) |
298 | : serviceData.settings), | 280 | : serviceData.settings), |
299 | order: data[service], | 281 | order: data[service], |
300 | }; | 282 | } |
301 | 283 | ||
302 | // Update data in database | 284 | // Update data in database |
303 | await Service.query() // eslint-disable-line no-await-in-loop | 285 | await Service.query() // eslint-disable-line no-await-in-loop |
@@ -305,18 +287,16 @@ export default class ServiceController { | |||
305 | .where('userId', user.id) | 287 | .where('userId', user.id) |
306 | .update({ | 288 | .update({ |
307 | settings: JSON.stringify(settings), | 289 | settings: JSON.stringify(settings), |
308 | }); | 290 | }) |
309 | } | 291 | } |
310 | 292 | ||
311 | // Get new services | 293 | // Get new services |
312 | const services = await user.related('services').query(); | 294 | const services = await user.related('services').query() |
313 | // Convert to array with all data Franz wants | 295 | // Convert to array with all data Franz wants |
314 | // eslint-disable-next-line @typescript-eslint/no-explicit-any | 296 | // eslint-disable-next-line @typescript-eslint/no-explicit-any |
315 | const servicesArray = services.map((service: any) => { | 297 | const servicesArray = services.map((service: any) => { |
316 | const settings = | 298 | const settings = |
317 | typeof service.settings === 'string' | 299 | typeof service.settings === 'string' ? JSON.parse(service.settings) : service.settings |
318 | ? JSON.parse(service.settings) | ||
319 | : service.settings; | ||
320 | 300 | ||
321 | return { | 301 | return { |
322 | customRecipe: false, | 302 | customRecipe: false, |
@@ -333,39 +313,39 @@ export default class ServiceController { | |||
333 | iconUrl: settings.iconId | 313 | iconUrl: settings.iconId |
334 | ? `${url}/v1/icon/${settings.iconId}` | 314 | ? `${url}/v1/icon/${settings.iconId}` |
335 | : // eslint-disable-next-line unicorn/no-null | 315 | : // eslint-disable-next-line unicorn/no-null |
336 | null, | 316 | null, |
337 | id: service.serviceId, | 317 | id: service.serviceId, |
338 | name: service.name, | 318 | name: service.name, |
339 | recipeId: service.recipeId, | 319 | recipeId: service.recipeId, |
340 | userId: user.id, | 320 | userId: user.id, |
341 | }; | 321 | } |
342 | }); | 322 | }) |
343 | 323 | ||
344 | return response.send(servicesArray); | 324 | return response.send(servicesArray) |
345 | } | 325 | } |
346 | 326 | ||
347 | // TODO: Test if this works | 327 | // TODO: Test if this works |
348 | public async icon({ params, response }: HttpContextContract) { | 328 | public async icon({ params, response }: HttpContext) { |
349 | let { id } = params; | 329 | let { id } = params |
350 | 330 | ||
351 | id = sanitize(id); | 331 | id = sanitize(id) |
352 | if (id === '') { | 332 | if (id === '') { |
353 | return response.status(404).send({ | 333 | return response.status(404).send({ |
354 | status: 'Icon doesn\'t exist', | 334 | status: "Icon doesn't exist", |
355 | }); | 335 | }) |
356 | } | 336 | } |
357 | 337 | ||
358 | const iconPath = path.join(Application.tmpPath('uploads'), id); | 338 | const iconPath = path.join(app.tmpPath('uploads'), id) |
359 | 339 | ||
360 | try { | 340 | try { |
361 | await fs.access(iconPath); | 341 | await fs.access(iconPath) |
362 | } catch { | 342 | } catch { |
363 | // File not available. | 343 | // File not available. |
364 | return response.status(404).send({ | 344 | return response.status(404).send({ |
365 | status: 'Icon doesn\'t exist', | 345 | status: "Icon doesn't exist", |
366 | }); | 346 | }) |
367 | } | 347 | } |
368 | 348 | ||
369 | return response.download(iconPath); | 349 | return response.download(iconPath) |
370 | } | 350 | } |
371 | } | 351 | } |