aboutsummaryrefslogtreecommitdiffstats
path: root/src/internal-server/app/Controllers/Http/ServiceController.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal-server/app/Controllers/Http/ServiceController.js')
-rw-r--r--src/internal-server/app/Controllers/Http/ServiceController.js292
1 files changed, 292 insertions, 0 deletions
diff --git a/src/internal-server/app/Controllers/Http/ServiceController.js b/src/internal-server/app/Controllers/Http/ServiceController.js
new file mode 100644
index 000000000..c76a287f7
--- /dev/null
+++ b/src/internal-server/app/Controllers/Http/ServiceController.js
@@ -0,0 +1,292 @@
1const Service = use('App/Models/Service');
2const { validateAll } = use('Validator');
3const Env = use('Env');
4
5const uuid = require('uuid/v4');
6const path = require('path');
7const fs = require('fs-extra');
8const { LOCAL_HOSTNAME } = require('../../../../config');
9
10const hostname = LOCAL_HOSTNAME;
11const port = Env.get('PORT');
12
13class ServiceController {
14 // Create a new service for user
15 async create({ request, response }) {
16 // Validate user input
17 const validation = await validateAll(request.all(), {
18 name: 'required|string',
19 recipeId: 'required',
20 });
21 if (validation.fails()) {
22 return response.status(401).send({
23 message: 'Invalid POST arguments',
24 messages: validation.messages(),
25 status: 401,
26 });
27 }
28
29 const data = request.all();
30
31 // Get new, unused uuid
32 let serviceId;
33 do {
34 serviceId = uuid();
35 } while (
36 (await Service.query().where('serviceId', serviceId).fetch()).rows
37 .length > 0
38 ); // eslint-disable-line no-await-in-loop
39
40 await Service.create({
41 serviceId,
42 name: data.name,
43 recipeId: data.recipeId,
44 settings: JSON.stringify(data),
45 });
46
47 return response.send({
48 data: {
49 userId: 1,
50 id: serviceId,
51 isEnabled: true,
52 isNotificationEnabled: true,
53 isBadgeEnabled: true,
54 isMuted: false,
55 isDarkModeEnabled: '', // TODO: This should ideally be a boolean (false). But, changing it caused the sidebar toggle to not work.
56 spellcheckerLanguage: '',
57 order: 1,
58 customRecipe: false,
59 hasCustomIcon: false,
60 workspaces: [],
61 iconUrl: null,
62 ...data,
63 },
64 status: ['created'],
65 });
66 }
67
68 // List all services a user has created
69 async list({ response }) {
70 const services = (await Service.all()).rows;
71 // Convert to array with all data Franz wants
72 const servicesArray = services.map(service => {
73 const settings =
74 typeof service.settings === 'string'
75 ? JSON.parse(service.settings)
76 : service.settings;
77
78 return {
79 customRecipe: false,
80 hasCustomIcon: false,
81 isBadgeEnabled: true,
82 isDarkModeEnabled: '', // TODO: This should ideally be a boolean (false). But, changing it caused the sidebar toggle to not work.
83 isEnabled: true,
84 isMuted: false,
85 isNotificationEnabled: true,
86 order: 1,
87 spellcheckerLanguage: '',
88 workspaces: [],
89 ...JSON.parse(service.settings),
90 iconUrl: settings.iconId
91 ? `http://${hostname}:${port}/v1/icon/${settings.iconId}`
92 : null,
93 id: service.serviceId,
94 name: service.name,
95 recipeId: service.recipeId,
96 userId: 1,
97 };
98 });
99
100 return response.send(servicesArray);
101 }
102
103 async edit({ request, response, params }) {
104 if (request.file('icon')) {
105 // Upload custom service icon
106 await fs.ensureDir(path.join(Env.get('USER_PATH'), 'icons'));
107
108 const icon = request.file('icon', {
109 types: ['image'],
110 size: '2mb',
111 });
112 const { id } = params;
113 const service = (await Service.query().where('serviceId', id).fetch())
114 .rows[0];
115 const settings =
116 typeof service.settings === 'string'
117 ? JSON.parse(service.settings)
118 : service.settings;
119
120 // Generate new icon ID
121 let iconId;
122 do {
123 iconId = uuid() + uuid();
124 } while (fs.existsSync(path.join(Env.get('USER_PATH'), 'icons', iconId)));
125
126 await icon.move(path.join(Env.get('USER_PATH'), 'icons'), {
127 name: iconId,
128 overwrite: true,
129 });
130
131 if (!icon.moved()) {
132 return response.status(500).send(icon.error());
133 }
134
135 const newSettings = {
136 ...settings,
137 ...{
138 iconId,
139 customIconVersion:
140 settings && settings.customIconVersion
141 ? settings.customIconVersion + 1
142 : 1,
143 },
144 };
145
146 // Update data in database
147 await Service.query()
148 .where('serviceId', id)
149 .update({
150 name: service.name,
151 settings: JSON.stringify(newSettings),
152 });
153
154 return response.send({
155 data: {
156 id,
157 name: service.name,
158 ...newSettings,
159 iconUrl: `http://${hostname}:${port}/v1/icon/${
160 newSettings.iconId
161 }`,
162 userId: 1,
163 },
164 status: ['updated'],
165 });
166 }
167 // Update service info
168 const data = request.all();
169 const { id } = params;
170
171 // Get current settings from db
172 const serviceData = (await Service.query().where('serviceId', id).fetch())
173 .rows[0];
174
175 const settings = {
176 ...(typeof serviceData.settings === 'string'
177 ? JSON.parse(serviceData.settings)
178 : serviceData.settings),
179 ...data,
180 };
181
182 // Update data in database
183 await Service.query()
184 .where('serviceId', id)
185 .update({
186 name: data.name,
187 settings: JSON.stringify(settings),
188 });
189
190 // Get updated row
191 const service = (await Service.query().where('serviceId', id).fetch())
192 .rows[0];
193
194 return response.send({
195 data: {
196 id,
197 name: service.name,
198 ...settings,
199 iconUrl: `${Env.get('APP_URL')}/v1/icon/${settings.iconId}`,
200 userId: 1,
201 },
202 status: ['updated'],
203 });
204 }
205
206 async icon({ params, response }) {
207 const { id } = params;
208
209 const iconPath = path.join(Env.get('USER_PATH'), 'icons', id);
210 if (!fs.existsSync(iconPath)) {
211 return response.status(404).send({
212 status: "Icon doesn't exist",
213 });
214 }
215
216 return response.download(iconPath);
217 }
218
219 async reorder({ request, response }) {
220 const data = request.all();
221
222 for (const service of Object.keys(data)) {
223 // Get current settings from db
224 const serviceData = (
225 await Service.query() // eslint-disable-line no-await-in-loop
226 .where('serviceId', service)
227 .fetch()
228 ).rows[0];
229
230 const settings = {
231 ...JSON.parse(serviceData.settings),
232 order: data[service],
233 };
234
235 // Update data in database
236 await Service.query() // eslint-disable-line no-await-in-loop
237 .where('serviceId', service)
238 .update({
239 settings: JSON.stringify(settings),
240 });
241 }
242
243 // Get new services
244 const services = (await Service.all()).rows;
245 // Convert to array with all data Franz wants
246 const servicesArray = services.map(service => {
247 const settings =
248 typeof service.settings === 'string'
249 ? JSON.parse(service.settings)
250 : service.settings;
251
252 return {
253 customRecipe: false,
254 hasCustomIcon: false,
255 isBadgeEnabled: true,
256 isDarkModeEnabled: '', // TODO: This should ideally be a boolean (false). But, changing it caused the sidebar toggle to not work.
257 isEnabled: true,
258 isMuted: false,
259 isNotificationEnabled: true,
260 order: 1,
261 spellcheckerLanguage: '',
262 workspaces: [],
263 ...JSON.parse(service.settings),
264 iconUrl: settings.iconId
265 ? `http://${hostname}:${port}/v1/icon/${settings.iconId}`
266 : null,
267 id: service.serviceId,
268 name: service.name,
269 recipeId: service.recipeId,
270 userId: 1,
271 };
272 });
273
274 return response.send(servicesArray);
275 }
276
277 update({ response }) {
278 return response.send([]);
279 }
280
281 async delete({ params, response }) {
282 // Update data in database
283 await Service.query().where('serviceId', params.id).delete();
284
285 return response.send({
286 message: 'Sucessfully deleted service',
287 status: 200,
288 });
289 }
290}
291
292module.exports = ServiceController;