aboutsummaryrefslogtreecommitdiffstats
path: root/src/internal-server
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal-server')
-rw-r--r--src/internal-server/app/Controllers/Http/RecipeController.js53
-rw-r--r--src/internal-server/app/Controllers/Http/ServiceController.js18
-rw-r--r--src/internal-server/app/Controllers/Http/UserController.js176
-rw-r--r--src/internal-server/app/Controllers/Http/WorkspaceController.js59
-rw-r--r--src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js2
-rw-r--r--src/internal-server/app/Models/Recipe.js3
-rw-r--r--src/internal-server/app/Models/Service.js3
-rw-r--r--src/internal-server/app/Models/Token.js3
-rw-r--r--src/internal-server/app/Models/User.js3
-rw-r--r--src/internal-server/app/Models/Workspace.js3
-rw-r--r--src/internal-server/config/shield.js3
-rw-r--r--src/internal-server/public/js/transfer.js20
-rw-r--r--src/internal-server/start.ts (renamed from src/internal-server/start.js)18
-rw-r--r--src/internal-server/start/kernel.js10
-rw-r--r--src/internal-server/start/migrate.js26
-rw-r--r--src/internal-server/start/routes.js2
-rw-r--r--src/internal-server/test.js9
-rw-r--r--src/internal-server/test.ts9
18 files changed, 210 insertions, 210 deletions
diff --git a/src/internal-server/app/Controllers/Http/RecipeController.js b/src/internal-server/app/Controllers/Http/RecipeController.js
index 1a7595a9d..d44839db1 100644
--- a/src/internal-server/app/Controllers/Http/RecipeController.js
+++ b/src/internal-server/app/Controllers/Http/RecipeController.js
@@ -1,22 +1,18 @@
1const Recipe = use('App/Models/Recipe'); 1const Recipe = use('App/Models/Recipe');
2const Drive = use('Drive'); 2const Drive = use('Drive');
3const { 3const { validateAll } = use('Validator');
4 validateAll,
5} = use('Validator');
6const Env = use('Env'); 4const Env = use('Env');
7 5
8const fetch = require('node-fetch'); 6const fetch = require('node-fetch');
9const debug = require('debug')('Ferdi:internalServer:RecipeController'); 7const debug = require('debug')('Ferdi:internalServer:RecipeController');
10const { LIVE_FERDI_API } = require('../../../../config'); 8const { LIVE_FERDI_API } = require('../../../../config');
11const { API_VERSION } = require('../../../../environment'); 9const { API_VERSION } = require('../../../../environment-remote');
12 10
13const RECIPES_URL = `${LIVE_FERDI_API}/${API_VERSION}/recipes`; 11const RECIPES_URL = `${LIVE_FERDI_API}/${API_VERSION}/recipes`;
14 12
15class RecipeController { 13class RecipeController {
16 // List official and custom recipes 14 // List official and custom recipes
17 async list({ 15 async list({ response }) {
18 response,
19 }) {
20 const officialRecipes = JSON.parse(await (await fetch(RECIPES_URL)).text()); 16 const officialRecipes = JSON.parse(await (await fetch(RECIPES_URL)).text());
21 const customRecipesArray = (await Recipe.all()).rows; 17 const customRecipesArray = (await Recipe.all()).rows;
22 const customRecipes = customRecipesArray.map(recipe => ({ 18 const customRecipes = customRecipesArray.map(recipe => ({
@@ -25,19 +21,13 @@ class RecipeController {
25 ...JSON.parse(recipe.data), 21 ...JSON.parse(recipe.data),
26 })); 22 }));
27 23
28 const recipes = [ 24 const recipes = [...officialRecipes, ...customRecipes];
29 ...officialRecipes,
30 ...customRecipes,
31 ];
32 25
33 return response.send(recipes); 26 return response.send(recipes);
34 } 27 }
35 28
36 // Search official and custom recipes 29 // Search official and custom recipes
37 async search({ 30 async search({ request, response }) {
38 request,
39 response,
40 }) {
41 // Validate user input 31 // Validate user input
42 const validation = await validateAll(request.all(), { 32 const validation = await validateAll(request.all(), {
43 needle: 'required', 33 needle: 'required',
@@ -64,13 +54,23 @@ class RecipeController {
64 })); 54 }));
65 } else { 55 } else {
66 let remoteResults = []; 56 let remoteResults = [];
67 if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq 57 // eslint-disable-next-line eqeqeq
68 remoteResults = JSON.parse(await (await fetch(`${RECIPES_URL}/search?needle=${encodeURIComponent(needle)}`)).text()); 58 if (Env.get('CONNECT_WITH_FRANZ') == 'true') {
59 // eslint-disable-line eqeqeq
60 remoteResults = JSON.parse(
61 await (
62 await fetch(
63 `${RECIPES_URL}/search?needle=${encodeURIComponent(needle)}`,
64 )
65 ).text(),
66 );
69 } 67 }
70 68
71 debug('remoteResults:', remoteResults); 69 debug('remoteResults:', remoteResults);
72 70
73 const localResultsArray = (await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()).toJSON(); 71 const localResultsArray = (
72 await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()
73 ).toJSON();
74 const localResults = localResultsArray.map(recipe => ({ 74 const localResults = localResultsArray.map(recipe => ({
75 id: recipe.recipeId, 75 id: recipe.recipeId,
76 name: recipe.name, 76 name: recipe.name,
@@ -79,20 +79,14 @@ class RecipeController {
79 79
80 debug('localResults:', localResults); 80 debug('localResults:', localResults);
81 81
82 results = [ 82 results = [...localResults, ...(remoteResults || [])];
83 ...localResults,
84 ...remoteResults || [],
85 ];
86 } 83 }
87 84
88 return response.send(results); 85 return response.send(results);
89 } 86 }
90 87
91 // Download a recipe 88 // Download a recipe
92 async download({ 89 async download({ response, params }) {
93 response,
94 params,
95 }) {
96 // Validate user input 90 // Validate user input
97 const validation = await validateAll(params, { 91 const validation = await validateAll(params, {
98 recipe: 'required|accepted', 92 recipe: 'required|accepted',
@@ -108,14 +102,17 @@ class RecipeController {
108 const service = params.recipe; 102 const service = params.recipe;
109 103
110 // Check for invalid characters 104 // Check for invalid characters
111 if (/\.{1,}/.test(service) || /\/{1,}/.test(service)) { 105 if (/\.+/.test(service) || /\/+/.test(service)) {
112 return response.send('Invalid recipe name'); 106 return response.send('Invalid recipe name');
113 } 107 }
114 108
115 // Check if recipe exists in recipes folder 109 // Check if recipe exists in recipes folder
116 if (await Drive.exists(`${service}.tar.gz`)) { 110 if (await Drive.exists(`${service}.tar.gz`)) {
117 return response.send(await Drive.get(`${service}.tar.gz`)); 111 return response.send(await Drive.get(`${service}.tar.gz`));
118 } if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq 112 }
113 // eslint-disable-next-line eqeqeq
114 if (Env.get('CONNECT_WITH_FRANZ') == 'true') {
115 // eslint-disable-line eqeqeq
119 return response.redirect(`${RECIPES_URL}/download/${service}`); 116 return response.redirect(`${RECIPES_URL}/download/${service}`);
120 } 117 }
121 return response.status(400).send({ 118 return response.status(400).send({
diff --git a/src/internal-server/app/Controllers/Http/ServiceController.js b/src/internal-server/app/Controllers/Http/ServiceController.js
index f2af9d411..133473b68 100644
--- a/src/internal-server/app/Controllers/Http/ServiceController.js
+++ b/src/internal-server/app/Controllers/Http/ServiceController.js
@@ -2,7 +2,7 @@ const Service = use('App/Models/Service');
2const { validateAll } = use('Validator'); 2const { validateAll } = use('Validator');
3const Env = use('Env'); 3const Env = use('Env');
4 4
5const uuid = require('uuid/v4'); 5const { v4: uuid } = require('uuid');
6const path = require('path'); 6const path = require('path');
7const fs = require('fs-extra'); 7const fs = require('fs-extra');
8const { LOCAL_HOSTNAME, DEFAULT_SERVICE_ORDER } = require('../../../../config'); 8const { LOCAL_HOSTNAME, DEFAULT_SERVICE_ORDER } = require('../../../../config');
@@ -135,13 +135,11 @@ class ServiceController {
135 135
136 const newSettings = { 136 const newSettings = {
137 ...settings, 137 ...settings,
138 ...{ 138 iconId,
139 iconId, 139 customIconVersion:
140 customIconVersion: 140 settings && settings.customIconVersion
141 settings && settings.customIconVersion 141 ? settings.customIconVersion + 1
142 ? settings.customIconVersion + 1 142 : 1,
143 : 1,
144 },
145 }; 143 };
146 144
147 // Update data in database 145 // Update data in database
@@ -157,9 +155,7 @@ class ServiceController {
157 id, 155 id,
158 name: service.name, 156 name: service.name,
159 ...newSettings, 157 ...newSettings,
160 iconUrl: `http://${hostname}:${port}/${API_VERSION}/icon/${ 158 iconUrl: `http://${hostname}:${port}/${API_VERSION}/icon/${newSettings.iconId}`,
161 newSettings.iconId
162 }`,
163 userId: 1, 159 userId: 1,
164 }, 160 },
165 status: ['updated'], 161 status: ['updated'],
diff --git a/src/internal-server/app/Controllers/Http/UserController.js b/src/internal-server/app/Controllers/Http/UserController.js
index 994dcc0dc..25b5277bd 100644
--- a/src/internal-server/app/Controllers/Http/UserController.js
+++ b/src/internal-server/app/Controllers/Http/UserController.js
@@ -1,34 +1,35 @@
1const User = use('App/Models/User'); 1const User = use('App/Models/User');
2const Service = use('App/Models/Service'); 2const Service = use('App/Models/Service');
3const Workspace = use('App/Models/Workspace'); 3const Workspace = use('App/Models/Workspace');
4const { 4const { validateAll } = use('Validator');
5 validateAll,
6} = use('Validator');
7 5
8const btoa = require('btoa'); 6const btoa = require('btoa');
9const fetch = require('node-fetch'); 7const fetch = require('node-fetch');
10const uuid = require('uuid/v4'); 8const { v4: uuid } = require('uuid');
11const crypto = require('crypto'); 9const crypto = require('crypto');
12const { DEFAULT_APP_SETTINGS, API_VERSION } = require('../../../../environment'); 10const { DEFAULT_APP_SETTINGS } = require('../../../../config');
11const { API_VERSION } = require('../../../../environment-remote');
13const { default: userAgent } = require('../../../../helpers/userAgent-helpers'); 12const { default: userAgent } = require('../../../../helpers/userAgent-helpers');
14 13
15const apiRequest = (url, route, method, auth) => new Promise((resolve, reject) => { 14const apiRequest = (url, route, method, auth) =>
16 try { 15 new Promise((resolve, reject) => {
17 fetch(`${url}/${API_VERSION}/${route}`, { 16 try {
18 method, 17 fetch(`${url}/${API_VERSION}/${route}`, {
19 headers: { 18 method,
20 Authorization: `Bearer ${auth}`, 19 headers: {
21 'User-Agent': userAgent(), 20 Authorization: `Bearer ${auth}`,
22 }, 21 'User-Agent': userAgent(),
23 }) 22 },
24 .then(data => data.json()) 23 })
25 .then(json => resolve(json)); 24 .then(data => data.json())
26 } catch (e) { 25 .then(json => resolve(json));
27 reject(); 26 } catch {
28 } 27 reject();
29}); 28 }
29 });
30 30
31const LOGIN_SUCCESS_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M'; 31const LOGIN_SUCCESS_TOKEN =
32 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJGZXJkaSBJbnRlcm5hbCBTZXJ2ZXIiLCJpYXQiOjE1NzEwNDAyMTUsImV4cCI6MjUzMzk1NDE3ODQ0LCJhdWQiOiJnZXRmZXJkaS5jb20iLCJzdWIiOiJmZXJkaUBsb2NhbGhvc3QiLCJ1c2VySWQiOiIxIn0.9_TWFGp6HROv8Yg82Rt6i1-95jqWym40a-HmgrdMC6M';
32 33
33const DEFAULT_USER_DATA = { 34const DEFAULT_USER_DATA = {
34 accountType: 'individual', 35 accountType: 'individual',
@@ -45,10 +46,7 @@ const DEFAULT_USER_DATA = {
45 46
46class UserController { 47class UserController {
47 // Register a new user 48 // Register a new user
48 async signup({ 49 async signup({ request, response }) {
49 request,
50 response,
51 }) {
52 // Validate user input 50 // Validate user input
53 const validation = await validateAll(request.all(), { 51 const validation = await validateAll(request.all(), {
54 firstname: 'required', 52 firstname: 'required',
@@ -70,10 +68,7 @@ class UserController {
70 } 68 }
71 69
72 // Login using an existing user 70 // Login using an existing user
73 async login({ 71 async login({ request, response }) {
74 request,
75 response,
76 }) {
77 if (!request.header('Authorization')) { 72 if (!request.header('Authorization')) {
78 return response.status(401).send({ 73 return response.status(401).send({
79 message: 'Please provide authorization', 74 message: 'Please provide authorization',
@@ -88,23 +83,21 @@ class UserController {
88 } 83 }
89 84
90 // Return information about the current user 85 // Return information about the current user
91 async me({ 86 async me({ response }) {
92 response,
93 }) {
94 const user = await User.find(1); 87 const user = await User.find(1);
95 88
96 const settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings; 89 const settings =
90 typeof user.settings === 'string'
91 ? JSON.parse(user.settings)
92 : user.settings;
97 93
98 return response.send({ 94 return response.send({
99 ...DEFAULT_USER_DATA, 95 ...DEFAULT_USER_DATA,
100 ...settings || {}, 96 ...settings,
101 }); 97 });
102 } 98 }
103 99
104 async updateMe({ 100 async updateMe({ request, response }) {
105 request,
106 response,
107 }) {
108 const user = await User.find(1); 101 const user = await User.find(1);
109 102
110 let settings = user.settings || {}; 103 let settings = user.settings || {};
@@ -125,16 +118,11 @@ class UserController {
125 ...DEFAULT_USER_DATA, 118 ...DEFAULT_USER_DATA,
126 ...newSettings, 119 ...newSettings,
127 }, 120 },
128 status: [ 121 status: ['data-updated'],
129 'data-updated',
130 ],
131 }); 122 });
132 } 123 }
133 124
134 async import({ 125 async import({ request, response }) {
135 request,
136 response,
137 }) {
138 // Validate user input 126 // Validate user input
139 const validation = await validateAll(request.all(), { 127 const validation = await validateAll(request.all(), {
140 email: 'required|email', 128 email: 'required|email',
@@ -142,7 +130,8 @@ class UserController {
142 server: 'required', 130 server: 'required',
143 }); 131 });
144 if (validation.fails()) { 132 if (validation.fails()) {
145 let errorMessage = 'There was an error while trying to import your account:\n'; 133 let errorMessage =
134 'There was an error while trying to import your account:\n';
146 for (const message of validation.messages()) { 135 for (const message of validation.messages()) {
147 if (message.validation === 'required') { 136 if (message.validation === 'required') {
148 errorMessage += `- Please make sure to supply your ${message.field}\n`; 137 errorMessage += `- Please make sure to supply your ${message.field}\n`;
@@ -155,13 +144,12 @@ class UserController {
155 return response.status(401).send(errorMessage); 144 return response.status(401).send(errorMessage);
156 } 145 }
157 146
158 const { 147 const { email, password, server } = request.all();
159 email,
160 password,
161 server,
162 } = request.all();
163 148
164 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); 149 const hashedPassword = crypto
150 .createHash('sha256')
151 .update(password)
152 .digest('base64');
165 153
166 // Try to get an authentication token 154 // Try to get an authentication token
167 let token; 155 let token;
@@ -178,16 +166,17 @@ class UserController {
178 const content = await rawResponse.json(); 166 const content = await rawResponse.json();
179 167
180 if (!content.message || content.message !== 'Successfully logged in') { 168 if (!content.message || content.message !== 'Successfully logged in') {
181 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; 169 const errorMessage =
170 'Could not login into Franz with your supplied credentials. Please check and try again';
182 return response.status(401).send(errorMessage); 171 return response.status(401).send(errorMessage);
183 } 172 }
184 173
185 // eslint-disable-next-line prefer-destructuring 174 // eslint-disable-next-line prefer-destructuring
186 token = content.token; 175 token = content.token;
187 } catch (e) { 176 } catch (error) {
188 return response.status(401).send({ 177 return response.status(401).send({
189 message: 'Cannot login to Franz', 178 message: 'Cannot login to Franz',
190 error: e, 179 error,
191 }); 180 });
192 } 181 }
193 182
@@ -195,12 +184,13 @@ class UserController {
195 let userInf = false; 184 let userInf = false;
196 try { 185 try {
197 userInf = await apiRequest(server, 'me', 'GET', token); 186 userInf = await apiRequest(server, 'me', 'GET', token);
198 } catch (e) { 187 } catch (error) {
199 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${e}`; 188 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${error}`;
200 return response.status(401).send(errorMessage); 189 return response.status(401).send(errorMessage);
201 } 190 }
202 if (!userInf) { 191 if (!userInf) {
203 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later'; 192 const errorMessage =
193 'Could not get your user info from Franz. Please check your credentials or try again later';
204 return response.status(401).send(errorMessage); 194 return response.status(401).send(errorMessage);
205 } 195 }
206 196
@@ -213,8 +203,8 @@ class UserController {
213 for (const service of services) { 203 for (const service of services) {
214 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 204 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
215 } 205 }
216 } catch (e) { 206 } catch (error) {
217 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 207 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
218 return response.status(401).send(errorMessage); 208 return response.status(401).send(errorMessage);
219 } 209 }
220 210
@@ -225,12 +215,14 @@ class UserController {
225 for (const workspace of workspaces) { 215 for (const workspace of workspaces) {
226 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 216 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
227 } 217 }
228 } catch (e) { 218 } catch (error) {
229 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 219 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
230 return response.status(401).send(errorMessage); 220 return response.status(401).send(errorMessage);
231 } 221 }
232 222
233 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.'); 223 return response.send(
224 'Your account has been imported. You can now use your Franz account in Ferdi.',
225 );
234 } 226 }
235 227
236 // Account import/export 228 // Account import/export
@@ -255,10 +247,7 @@ class UserController {
255 .send(exportData); 247 .send(exportData);
256 } 248 }
257 249
258 async importFerdi({ 250 async importFerdi({ request, response }) {
259 request,
260 response,
261 }) {
262 const validation = await validateAll(request.all(), { 251 const validation = await validateAll(request.all(), {
263 file: 'required', 252 file: 'required',
264 }); 253 });
@@ -269,8 +258,10 @@ class UserController {
269 let file; 258 let file;
270 try { 259 try {
271 file = JSON.parse(request.input('file')); 260 file = JSON.parse(request.input('file'));
272 } catch (e) { 261 } catch {
273 return response.send('Could not import: Invalid file, could not read file'); 262 return response.send(
263 'Could not import: Invalid file, could not read file',
264 );
274 } 265 }
275 266
276 if (!file || !file.services || !file.workspaces) { 267 if (!file || !file.services || !file.workspaces) {
@@ -284,8 +275,8 @@ class UserController {
284 for (const service of file.services) { 275 for (const service of file.services) {
285 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop 276 await this._createAndCacheService(service, serviceIdTranslation); // eslint-disable-line no-await-in-loop
286 } 277 }
287 } catch (e) { 278 } catch (error) {
288 const errorMessage = `Could not import your services into our system.\nError: ${e}`; 279 const errorMessage = `Could not import your services into our system.\nError: ${error}`;
289 return response.send(errorMessage); 280 return response.send(errorMessage);
290 } 281 }
291 282
@@ -294,8 +285,8 @@ class UserController {
294 for (const workspace of file.workspaces) { 285 for (const workspace of file.workspaces) {
295 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop 286 await this._createWorkspace(workspace, serviceIdTranslation); // eslint-disable-line no-await-in-loop
296 } 287 }
297 } catch (e) { 288 } catch (error) {
298 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`; 289 const errorMessage = `Could not import your workspaces into our system.\nError: ${error}`;
299 return response.status(401).send(errorMessage); 290 return response.status(401).send(errorMessage);
300 } 291 }
301 292
@@ -306,15 +297,29 @@ class UserController {
306 let newWorkspaceId; 297 let newWorkspaceId;
307 do { 298 do {
308 newWorkspaceId = uuid(); 299 newWorkspaceId = uuid();
309 } while ((await Workspace.query().where('workspaceId', newWorkspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 300 } while (
310 301 (await Workspace.query().where('workspaceId', newWorkspaceId).fetch())
311 if (workspace.services && typeof (workspace.services) === 'string' && workspace.services.length > 0) { 302 .rows.length > 0
303 ); // eslint-disable-line no-await-in-loop
304
305 if (
306 workspace.services &&
307 typeof workspace.services === 'string' &&
308 workspace.services.length > 0
309 ) {
312 workspace.services = JSON.parse(workspace.services); 310 workspace.services = JSON.parse(workspace.services);
313 } 311 }
314 const services = (workspace.services && typeof (workspace.services) === 'object') ? 312 const services =
315 workspace.services.map(oldServiceId => serviceIdTranslation[oldServiceId]) : 313 workspace.services && typeof workspace.services === 'object'
316 []; 314 ? workspace.services.map(
317 if (workspace.data && typeof (workspace.data) === 'string' && workspace.data.length > 0) { 315 oldServiceId => serviceIdTranslation[oldServiceId],
316 )
317 : [];
318 if (
319 workspace.data &&
320 typeof workspace.data === 'string' &&
321 workspace.data.length > 0
322 ) {
318 workspace.data = JSON.parse(workspace.data); 323 workspace.data = JSON.parse(workspace.data);
319 } 324 }
320 325
@@ -332,12 +337,19 @@ class UserController {
332 let newServiceId; 337 let newServiceId;
333 do { 338 do {
334 newServiceId = uuid(); 339 newServiceId = uuid();
335 } while ((await Service.query().where('serviceId', newServiceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 340 } while (
341 (await Service.query().where('serviceId', newServiceId).fetch()).rows
342 .length > 0
343 ); // eslint-disable-line no-await-in-loop
336 344
337 // store the old serviceId as the key for future lookup 345 // store the old serviceId as the key for future lookup
338 serviceIdTranslation[service.serviceId] = newServiceId; 346 serviceIdTranslation[service.serviceId] = newServiceId;
339 347
340 if (service.settings && typeof (service.settings) === 'string' && service.settings.length > 0) { 348 if (
349 service.settings &&
350 typeof service.settings === 'string' &&
351 service.settings.length > 0
352 ) {
341 service.settings = JSON.parse(service.settings); 353 service.settings = JSON.parse(service.settings);
342 } 354 }
343 355
diff --git a/src/internal-server/app/Controllers/Http/WorkspaceController.js b/src/internal-server/app/Controllers/Http/WorkspaceController.js
index 773312a0b..9d461135e 100644
--- a/src/internal-server/app/Controllers/Http/WorkspaceController.js
+++ b/src/internal-server/app/Controllers/Http/WorkspaceController.js
@@ -1,16 +1,11 @@
1const Workspace = use('App/Models/Workspace'); 1const Workspace = use('App/Models/Workspace');
2const { 2const { validateAll } = use('Validator');
3 validateAll,
4} = use('Validator');
5 3
6const uuid = require('uuid/v4'); 4const { v4: uuid } = require('uuid');
7 5
8class WorkspaceController { 6class WorkspaceController {
9 // Create a new workspace for user 7 // Create a new workspace for user
10 async create({ 8 async create({ request, response }) {
11 request,
12 response,
13 }) {
14 // Validate user input 9 // Validate user input
15 const validation = await validateAll(request.all(), { 10 const validation = await validateAll(request.all(), {
16 name: 'required', 11 name: 'required',
@@ -29,10 +24,13 @@ class WorkspaceController {
29 let workspaceId; 24 let workspaceId;
30 do { 25 do {
31 workspaceId = uuid(); 26 workspaceId = uuid();
32 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop 27 } while (
28 (await Workspace.query().where('workspaceId', workspaceId).fetch()).rows
29 .length > 0
30 ); // eslint-disable-line no-await-in-loop
33 31
34 const order = (await Workspace.all()).rows.length; 32 const order = (await Workspace.all()).rows.length;
35 const name = data.name; 33 const { name } = data;
36 delete data.name; 34 delete data.name;
37 35
38 await Workspace.create({ 36 await Workspace.create({
@@ -52,11 +50,7 @@ class WorkspaceController {
52 }); 50 });
53 } 51 }
54 52
55 async edit({ 53 async edit({ request, response, params }) {
56 request,
57 response,
58 params,
59 }) {
60 // Validate user input 54 // Validate user input
61 const validation = await validateAll(request.all(), { 55 const validation = await validateAll(request.all(), {
62 name: 'required', 56 name: 'required',
@@ -71,20 +65,19 @@ class WorkspaceController {
71 } 65 }
72 66
73 const data = request.all(); 67 const data = request.all();
74 const { 68 const { id } = params;
75 id,
76 } = params;
77 69
78 // Update data in database 70 // Update data in database
79 await (Workspace.query() 71 await Workspace.query()
80 .where('workspaceId', id)).update({ 72 .where('workspaceId', id)
81 name: data.name, 73 .update({
82 services: JSON.stringify(data.services), 74 name: data.name,
83 }); 75 services: JSON.stringify(data.services),
76 });
84 77
85 // Get updated row 78 // Get updated row
86 const workspace = (await Workspace.query() 79 const workspace = (await Workspace.query().where('workspaceId', id).fetch())
87 .where('workspaceId', id).fetch()).rows[0]; 80 .rows[0];
88 81
89 return response.send({ 82 return response.send({
90 id: workspace.workspaceId, 83 id: workspace.workspaceId,
@@ -113,13 +106,10 @@ class WorkspaceController {
113 }); 106 });
114 } 107 }
115 108
116 const { 109 const { id } = params;
117 id,
118 } = params;
119 110
120 // Update data in database 111 // Update data in database
121 await (Workspace.query() 112 await Workspace.query().where('workspaceId', id).delete();
122 .where('workspaceId', id)).delete();
123 113
124 return response.send({ 114 return response.send({
125 message: 'Successfully deleted workspace', 115 message: 'Successfully deleted workspace',
@@ -127,9 +117,7 @@ class WorkspaceController {
127 } 117 }
128 118
129 // List all workspaces a user has created 119 // List all workspaces a user has created
130 async list({ 120 async list({ response }) {
131 response,
132 }) {
133 const workspaces = (await Workspace.all()).rows; 121 const workspaces = (await Workspace.all()).rows;
134 // Convert to array with all data Franz wants 122 // Convert to array with all data Franz wants
135 let workspacesArray = []; 123 let workspacesArray = [];
@@ -138,7 +126,10 @@ class WorkspaceController {
138 id: workspace.workspaceId, 126 id: workspace.workspaceId,
139 name: workspace.name, 127 name: workspace.name,
140 order: workspace.order, 128 order: workspace.order,
141 services: typeof workspace.services === 'string' ? JSON.parse(workspace.services) : workspace.services, 129 services:
130 typeof workspace.services === 'string'
131 ? JSON.parse(workspace.services)
132 : workspace.services,
142 userId: 1, 133 userId: 1,
143 })); 134 }));
144 } 135 }
diff --git a/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js b/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
index 87f1f6c25..9591cdc41 100644
--- a/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
+++ b/src/internal-server/app/Middleware/ConvertEmptyStringsToNull.js
@@ -1,6 +1,6 @@
1class ConvertEmptyStringsToNull { 1class ConvertEmptyStringsToNull {
2 async handle({ request }, next) { 2 async handle({ request }, next) {
3 if (Object.keys(request.body).length) { 3 if (Object.keys(request.body).length > 0) {
4 request.body = Object.assign( 4 request.body = Object.assign(
5 ...Object.keys(request.body).map(key => ({ 5 ...Object.keys(request.body).map(key => ({
6 [key]: request.body[key] !== '' ? request.body[key] : null, 6 [key]: request.body[key] !== '' ? request.body[key] : null,
diff --git a/src/internal-server/app/Models/Recipe.js b/src/internal-server/app/Models/Recipe.js
index bd9741114..f9370e206 100644
--- a/src/internal-server/app/Models/Recipe.js
+++ b/src/internal-server/app/Models/Recipe.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Recipe extends Model { 4class Recipe extends Model {}
5}
6 5
7module.exports = Recipe; 6module.exports = Recipe;
diff --git a/src/internal-server/app/Models/Service.js b/src/internal-server/app/Models/Service.js
index a2e5c981e..95321686c 100644
--- a/src/internal-server/app/Models/Service.js
+++ b/src/internal-server/app/Models/Service.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Service extends Model { 4class Service extends Model {}
5}
6 5
7module.exports = Service; 6module.exports = Service;
diff --git a/src/internal-server/app/Models/Token.js b/src/internal-server/app/Models/Token.js
index 83e989117..1388b94ad 100644
--- a/src/internal-server/app/Models/Token.js
+++ b/src/internal-server/app/Models/Token.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Token extends Model { 4class Token extends Model {}
5}
6 5
7module.exports = Token; 6module.exports = Token;
diff --git a/src/internal-server/app/Models/User.js b/src/internal-server/app/Models/User.js
index 907710d8d..f17f04c3e 100644
--- a/src/internal-server/app/Models/User.js
+++ b/src/internal-server/app/Models/User.js
@@ -2,7 +2,6 @@
2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
3const Model = use('Model'); 3const Model = use('Model');
4 4
5class User extends Model { 5class User extends Model {}
6}
7 6
8module.exports = User; 7module.exports = User;
diff --git a/src/internal-server/app/Models/Workspace.js b/src/internal-server/app/Models/Workspace.js
index dcf39ac75..c47c02e37 100644
--- a/src/internal-server/app/Models/Workspace.js
+++ b/src/internal-server/app/Models/Workspace.js
@@ -1,7 +1,6 @@
1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 1/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
2const Model = use('Model'); 2const Model = use('Model');
3 3
4class Workspace extends Model { 4class Workspace extends Model {}
5}
6 5
7module.exports = Workspace; 6module.exports = Workspace;
diff --git a/src/internal-server/config/shield.js b/src/internal-server/config/shield.js
index 76f430e91..4ff22c3f9 100644
--- a/src/internal-server/config/shield.js
+++ b/src/internal-server/config/shield.js
@@ -25,8 +25,7 @@ module.exports = {
25 | } 25 | }
26 | 26 |
27 */ 27 */
28 directives: { 28 directives: {},
29 },
30 /* 29 /*
31 |-------------------------------------------------------------------------- 30 |--------------------------------------------------------------------------
32 | Report only 31 | Report only
diff --git a/src/internal-server/public/js/transfer.js b/src/internal-server/public/js/transfer.js
index 8382bba02..36fdbd61a 100644
--- a/src/internal-server/public/js/transfer.js
+++ b/src/internal-server/public/js/transfer.js
@@ -1,13 +1,17 @@
1const submitBtn = document.getElementById('submit'); 1const submitBtn = document.querySelector('#submit');
2const fileInput = document.getElementById('file'); 2const fileInput = document.querySelector('#file');
3const fileOutput = document.getElementById('fileoutput'); 3const fileOutput = document.querySelector('#fileoutput');
4 4
5fileInput.addEventListener('change', () => { 5fileInput?.addEventListener('change', () => {
6 const reader = new FileReader(); 6 const reader = new FileReader();
7 reader.onload = () => { 7 reader.addEventListener('load', () => {
8 const text = reader.result; 8 const text = reader.result;
9 fileOutput.value = text; 9 if (fileOutput) {
10 submitBtn.disabled = false; 10 fileOutput.value = text;
11 }; 11 }
12 if (submitBtn) {
13 submitBtn.disabled = false;
14 }
15 });
12 reader.readAsText(fileInput.files[0]); 16 reader.readAsText(fileInput.files[0]);
13}); 17});
diff --git a/src/internal-server/start.js b/src/internal-server/start.ts
index 5ccc1330e..392f7cf41 100644
--- a/src/internal-server/start.js
+++ b/src/internal-server/start.ts
@@ -15,16 +15,16 @@
15| Make sure to pass a relative path from the project root. 15| Make sure to pass a relative path from the project root.
16*/ 16*/
17 17
18const fold = require('@adonisjs/fold'); 18import fold from '@adonisjs/fold';
19const { Ignitor } = require('@adonisjs/ignitor'); 19import { Ignitor } from '@adonisjs/ignitor';
20const fs = require('fs-extra'); 20import fs from 'fs-extra';
21const path = require('path'); 21import path from 'path';
22const { LOCAL_HOSTNAME } = require('../config'); 22import { LOCAL_HOSTNAME } from '../config';
23const { isWindows } = require('../environment'); 23import { isWindows } from '../environment';
24 24
25process.env.ENV_PATH = path.join(__dirname, 'env.ini'); 25process.env.ENV_PATH = path.join(__dirname, 'env.ini');
26 26
27module.exports = async (userPath, port) => { 27export const server = async (userPath: string, port: number) => {
28 const dbPath = path.join(userPath, 'server.sqlite'); 28 const dbPath = path.join(userPath, 'server.sqlite');
29 const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite'); 29 const dbTemplatePath = path.join(__dirname, 'database', 'template.sqlite');
30 30
@@ -45,7 +45,7 @@ module.exports = async (userPath, port) => {
45 process.env.DB_PATH = dbPath; 45 process.env.DB_PATH = dbPath;
46 process.env.USER_PATH = userPath; 46 process.env.USER_PATH = userPath;
47 process.env.HOST = LOCAL_HOSTNAME; 47 process.env.HOST = LOCAL_HOSTNAME;
48 process.env.PORT = port; 48 process.env.PORT = port.toString();
49 49
50 new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error); // eslint-disable-line no-console 50 new Ignitor(fold).appRoot(__dirname).fireHttpServer().catch(console.error);
51}; 51};
diff --git a/src/internal-server/start/kernel.js b/src/internal-server/start/kernel.js
index 7b540f829..f72e445f2 100644
--- a/src/internal-server/start/kernel.js
+++ b/src/internal-server/start/kernel.js
@@ -32,8 +32,7 @@ const globalMiddleware = [
32| Route.get().middleware('auth') 32| Route.get().middleware('auth')
33| 33|
34*/ 34*/
35const namedMiddleware = { 35const namedMiddleware = {};
36};
37 36
38/* 37/*
39|-------------------------------------------------------------------------- 38|--------------------------------------------------------------------------
@@ -45,11 +44,8 @@ const namedMiddleware = {
45| control over request lifecycle. 44| control over request lifecycle.
46| 45|
47*/ 46*/
48const serverMiddleware = [ 47const serverMiddleware = ['Adonis/Middleware/Static'];
49 'Adonis/Middleware/Static',
50];
51 48
52Server 49Server.registerGlobal(globalMiddleware)
53 .registerGlobal(globalMiddleware)
54 .registerNamed(namedMiddleware) 50 .registerNamed(namedMiddleware)
55 .use(serverMiddleware); 51 .use(serverMiddleware);
diff --git a/src/internal-server/start/migrate.js b/src/internal-server/start/migrate.js
index c27e07bc5..97cefcc54 100644
--- a/src/internal-server/start/migrate.js
+++ b/src/internal-server/start/migrate.js
@@ -1,4 +1,4 @@
1const { ferdiVersion } = require('../../environment'); 1const { ferdiVersion } = require('../../environment-remote');
2 2
3/** 3/**
4 * Migrate server database to work with current Ferdi version 4 * Migrate server database to work with current Ferdi version
@@ -6,29 +6,39 @@ const { ferdiVersion } = require('../../environment');
6const Database = use('Database'); 6const Database = use('Database');
7const User = use('App/Models/User'); 7const User = use('App/Models/User');
8 8
9const migrateLog = (text) => { 9const migrateLog = text => {
10 console.log('\x1b[36m%s\x1b[0m', 'Ferdi Migration:', '\x1b[0m', text); 10 console.log('\u001B[36m%s\u001B[0m', 'Ferdi Migration:', '\u001B[0m', text);
11}; 11};
12 12
13module.exports = async () => { 13module.exports = async () => {
14 migrateLog('🧙‍ Running database migration wizard'); 14 migrateLog('🧙‍ Running database migration wizard');
15 15
16 // Make sure user table exists 16 // Make sure user table exists
17 await Database.raw('CREATE TABLE IF NOT EXISTS `users` (`id` integer not null primary key autoincrement, `settings` text, `created_at` datetime, `updated_at` datetime);'); 17 await Database.raw(
18 'CREATE TABLE IF NOT EXISTS `users` (`id` integer not null primary key autoincrement, `settings` text, `created_at` datetime, `updated_at` datetime);',
19 );
18 20
19 const user = await User.find(1); 21 const user = await User.find(1);
20 let settings; 22 let settings;
21 if (!user) { 23 if (!user) {
22 migrateLog('🎩 Migrating from old Ferdi version as user doesn\'t exist'); 24 migrateLog("🎩 Migrating from old Ferdi version as user doesn't exist");
23 25
24 // Create new user 26 // Create new user
25 await Database.raw('INSERT INTO "users" ("id") VALUES (\'1\');'); 27 await Database.raw('INSERT INTO "users" ("id") VALUES (\'1\');');
26 } else { 28 } else {
27 settings = typeof user.settings === 'string' ? JSON.parse(user.settings) : user.settings; 29 settings =
30 typeof user.settings === 'string'
31 ? JSON.parse(user.settings)
32 : user.settings;
28 } 33 }
29 34
30 if (!settings || !settings.db_version || settings.db_version !== ferdiVersion) { 35 if (
31 const srcVersion = settings && settings.db_version ? settings.db_version : '5.4.0-beta.2'; 36 !settings ||
37 !settings.db_version ||
38 settings.db_version !== ferdiVersion
39 ) {
40 const srcVersion =
41 settings && settings.db_version ? settings.db_version : '5.4.0-beta.2';
32 migrateLog(`🔮 Migrating table from ${srcVersion} to ${ferdiVersion}`); 42 migrateLog(`🔮 Migrating table from ${srcVersion} to ${ferdiVersion}`);
33 43
34 // Migrate database to current Ferdi version 44 // Migrate database to current Ferdi version
diff --git a/src/internal-server/start/routes.js b/src/internal-server/start/routes.js
index e75380ccd..db74479c9 100644
--- a/src/internal-server/start/routes.js
+++ b/src/internal-server/start/routes.js
@@ -8,7 +8,7 @@
8/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */ 8/** @type {typeof import('@adonisjs/framework/src/Route/Manager')} */
9const Route = use('Route'); 9const Route = use('Route');
10 10
11const { API_VERSION } = require('../../environment'); 11const { API_VERSION } = require('../../environment-remote');
12// Run latest database migration 12// Run latest database migration
13const migrate = require('./migrate'); 13const migrate = require('./migrate');
14 14
diff --git a/src/internal-server/test.js b/src/internal-server/test.js
deleted file mode 100644
index 8d4807d06..000000000
--- a/src/internal-server/test.js
+++ /dev/null
@@ -1,9 +0,0 @@
1const path = require('path');
2const fs = require('fs-extra');
3const server = require('./start');
4
5const dummyUserFolder = path.join(__dirname, 'user_data');
6
7fs.ensureDirSync(dummyUserFolder);
8
9server(dummyUserFolder, 45568);
diff --git a/src/internal-server/test.ts b/src/internal-server/test.ts
new file mode 100644
index 000000000..437a2813b
--- /dev/null
+++ b/src/internal-server/test.ts
@@ -0,0 +1,9 @@
1import path from 'path';
2import fs from 'fs-extra';
3import { server } from './start';
4
5const dummyUserFolder = path.join(__dirname, 'user_data');
6
7fs.ensureDirSync(dummyUserFolder);
8
9server(dummyUserFolder, 45_568);