aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorLibravatar vantezzen <properly@protonmail.com>2019-09-05 11:22:49 +0200
committerLibravatar vantezzen <properly@protonmail.com>2019-09-05 11:22:49 +0200
commit29b8334b060dc0c05a509d523ead4b3a30229fef (patch)
tree4dbfcfb90a3eff31acd219b27557bbdc594f589f /app
parentAdd cookie notice to login page (diff)
downloadferdium-server-29b8334b060dc0c05a509d523ead4b3a30229fef.tar.gz
ferdium-server-29b8334b060dc0c05a509d523ead4b3a30229fef.tar.zst
ferdium-server-29b8334b060dc0c05a509d523ead4b3a30229fef.zip
Add eslint
Diffstat (limited to 'app')
-rw-r--r--app/Controllers/Http/DashboardController.js61
-rw-r--r--app/Controllers/Http/RecipeController.js159
-rw-r--r--app/Controllers/Http/ServiceController.js200
-rw-r--r--app/Controllers/Http/StaticController.js347
-rw-r--r--app/Controllers/Http/UserController.js213
-rw-r--r--app/Controllers/Http/WorkspaceController.js104
-rw-r--r--app/Exceptions/Handler.js16
-rw-r--r--app/Middleware/ConvertEmptyStringsToNull.js15
-rw-r--r--app/Models/Recipe.js5
-rw-r--r--app/Models/Service.js11
-rw-r--r--app/Models/Token.js5
-rw-r--r--app/Models/Traits/NoTimestamp.js9
-rw-r--r--app/Models/User.js28
-rw-r--r--app/Models/Workspace.js11
14 files changed, 577 insertions, 607 deletions
diff --git a/app/Controllers/Http/DashboardController.js b/app/Controllers/Http/DashboardController.js
index aa8127f..49f6cc0 100644
--- a/app/Controllers/Http/DashboardController.js
+++ b/app/Controllers/Http/DashboardController.js
@@ -1,7 +1,6 @@
1'use strict'
2 1
3const { 2const {
4 validateAll 3 validateAll,
5} = use('Validator'); 4} = use('Validator');
6 5
7const crypto = require('crypto'); 6const crypto = require('crypto');
@@ -11,7 +10,7 @@ class DashboardController {
11 request, 10 request,
12 response, 11 response,
13 auth, 12 auth,
14 session 13 session,
15 }) { 14 }) {
16 const validation = await validateAll(request.all(), { 15 const validation = await validateAll(request.all(), {
17 mail: 'required|email', 16 mail: 'required|email',
@@ -20,25 +19,25 @@ class DashboardController {
20 if (validation.fails()) { 19 if (validation.fails()) {
21 session.withErrors({ 20 session.withErrors({
22 type: 'danger', 21 type: 'danger',
23 message: 'Invalid mail or password' 22 message: 'Invalid mail or password',
24 }).flashExcept(['password']); 23 }).flashExcept(['password']);
25 return response.redirect('back'); 24 return response.redirect('back');
26 } 25 }
27 26
28 let { 27 const {
29 mail, 28 mail,
30 password 29 password,
31 } = request.all() 30 } = request.all();
32 31
33 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); 32 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64');
34 33
35 try { 34 try {
36 await auth.authenticator('session').attempt(mail, hashedPassword) 35 await auth.authenticator('session').attempt(mail, hashedPassword);
37 } catch (error) { 36 } catch (error) {
38 session.flash({ 37 session.flash({
39 type: 'danger', 38 type: 'danger',
40 message: 'Invalid mail or password' 39 message: 'Invalid mail or password',
41 }) 40 });
42 return response.redirect('back'); 41 return response.redirect('back');
43 } 42 }
44 return response.redirect('/user/account'); 43 return response.redirect('/user/account');
@@ -46,17 +45,18 @@ class DashboardController {
46 45
47 async account({ 46 async account({
48 auth, 47 auth,
49 view 48 view,
49 response,
50 }) { 50 }) {
51 try { 51 try {
52 await auth.check() 52 await auth.check();
53 } catch (error) { 53 } catch (error) {
54 return response.redirect('/user/login'); 54 return response.redirect('/user/login');
55 } 55 }
56 56
57 return view.render('dashboard.account', { 57 return view.render('dashboard.account', {
58 username: auth.user.username, 58 username: auth.user.username,
59 email: auth.user.email 59 email: auth.user.email,
60 }); 60 });
61 } 61 }
62 62
@@ -65,11 +65,11 @@ class DashboardController {
65 request, 65 request,
66 session, 66 session,
67 view, 67 view,
68 response 68 response,
69 }) { 69 }) {
70 let validation = await validateAll(request.all(), { 70 let validation = await validateAll(request.all(), {
71 username: 'required', 71 username: 'required',
72 email: 'required' 72 email: 'required',
73 }); 73 });
74 if (validation.fails()) { 74 if (validation.fails()) {
75 session.withErrors(validation.messages()).flashExcept(['password']); 75 session.withErrors(validation.messages()).flashExcept(['password']);
@@ -80,19 +80,19 @@ class DashboardController {
80 if (request.input('username') !== auth.user.username) { 80 if (request.input('username') !== auth.user.username) {
81 validation = await validateAll(request.all(), { 81 validation = await validateAll(request.all(), {
82 username: 'required|unique:users,username', 82 username: 'required|unique:users,username',
83 email: 'required' 83 email: 'required',
84 }); 84 });
85 if (validation.fails()) { 85 if (validation.fails()) {
86 session.withErrors(validation.messages()).flashExcept(['password']); 86 session.withErrors(validation.messages()).flashExcept(['password']);
87 return response.redirect('back'); 87 return response.redirect('back');
88 } 88 }
89 } 89 }
90 90
91 // Check new email 91 // Check new email
92 if (request.input('email') !== auth.user.email) { 92 if (request.input('email') !== auth.user.email) {
93 validation = await validateAll(request.all(), { 93 validation = await validateAll(request.all(), {
94 username: 'required', 94 username: 'required',
95 email: 'required|email|unique:users,email' 95 email: 'required|email|unique:users,email',
96 }); 96 });
97 if (validation.fails()) { 97 if (validation.fails()) {
98 session.withErrors(validation.messages()).flashExcept(['password']); 98 session.withErrors(validation.messages()).flashExcept(['password']);
@@ -101,24 +101,25 @@ class DashboardController {
101 } 101 }
102 102
103 // Update user account 103 // Update user account
104 auth.user.username = request.input('username'); 104 const { user } = auth;
105 auth.user.email = request.input('email'); 105 user.username = request.input('username');
106 if (!!request.input('password')) { 106 user.email = request.input('email');
107 if (request.input('password')) {
107 const hashedPassword = crypto.createHash('sha256').update(request.input('password')).digest('base64'); 108 const hashedPassword = crypto.createHash('sha256').update(request.input('password')).digest('base64');
108 auth.user.password = hashedPassword; 109 user.password = hashedPassword;
109 } 110 }
110 auth.user.save(); 111 user.save();
111 112
112 return view.render('dashboard.account', { 113 return view.render('dashboard.account', {
113 username: auth.user.username, 114 username: user.username,
114 email: auth.user.email, 115 email: user.email,
115 success: true 116 success: true,
116 }); 117 });
117 } 118 }
118 119
119 async data({ 120 async data({
120 auth, 121 auth,
121 view 122 view,
122 }) { 123 }) {
123 const general = auth.user; 124 const general = auth.user;
124 const services = (await auth.user.services().fetch()).toJSON(); 125 const services = (await auth.user.services().fetch()).toJSON();
@@ -136,7 +137,7 @@ class DashboardController {
136 137
137 logout({ 138 logout({
138 auth, 139 auth,
139 response 140 response,
140 }) { 141 }) {
141 auth.authenticator('session').logout(); 142 auth.authenticator('session').logout();
142 return response.redirect('/user/login'); 143 return response.redirect('/user/login');
@@ -144,7 +145,7 @@ class DashboardController {
144 145
145 delete({ 146 delete({
146 auth, 147 auth,
147 response 148 response,
148 }) { 149 }) {
149 auth.user.delete(); 150 auth.user.delete();
150 auth.authenticator('session').logout(); 151 auth.authenticator('session').logout();
@@ -152,4 +153,4 @@ class DashboardController {
152 } 153 }
153} 154}
154 155
155module.exports = DashboardController 156module.exports = DashboardController;
diff --git a/app/Controllers/Http/RecipeController.js b/app/Controllers/Http/RecipeController.js
index fd9ed83..217b05b 100644
--- a/app/Controllers/Http/RecipeController.js
+++ b/app/Controllers/Http/RecipeController.js
@@ -1,61 +1,58 @@
1'use strict'
2 1
3const Recipe = use('App/Models/Recipe'); 2const Recipe = use('App/Models/Recipe');
4const Helpers = use('Helpers') 3const Helpers = use('Helpers');
5const Drive = use('Drive') 4const Drive = use('Drive');
6const { 5const {
7 validateAll 6 validateAll,
8} = use('Validator'); 7} = use('Validator');
9const Env = use('Env') 8const Env = use('Env');
10 9
11const fetch = require('node-fetch'); 10const fetch = require('node-fetch');
12const targz = require('targz'); 11const targz = require('targz');
13const path = require('path'); 12const path = require('path');
14const fs = require('fs-extra'); 13const fs = require('fs-extra');
15 14
16const compress = (src, dest) => { 15const compress = (src, dest) => new Promise((resolve, reject) => {
17 return new Promise((resolve, reject) => { 16 targz.compress({
18 targz.compress({ 17 src,
19 src, 18 dest,
20 dest 19 }, (err) => {
21 }, function (err) { 20 if (err) {
22 if (err) { 21 reject(err);
23 reject(err); 22 } else {
24 } else { 23 resolve(dest);
25 resolve(dest); 24 }
26 } 25 });
27 }); 26});
28 })
29}
30 27
31class RecipeController { 28class RecipeController {
32 // List official and custom recipes 29 // List official and custom recipes
33 async list({ 30 async list({
34 response 31 response,
35 }) { 32 }) {
36 const officialRecipes = JSON.parse(await (await fetch('https://api.franzinfra.com/v1/recipes')).text()); 33 const officialRecipes = JSON.parse(await (await fetch('https://api.franzinfra.com/v1/recipes')).text());
37 const customRecipesArray = (await Recipe.all()).rows; 34 const customRecipesArray = (await Recipe.all()).rows;
38 const customRecipes = customRecipesArray.map(recipe => ({ 35 const customRecipes = customRecipesArray.map((recipe) => ({
39 "id": recipe.recipeId, 36 id: recipe.recipeId,
40 "name": recipe.name, 37 name: recipe.name,
41 ...JSON.parse(recipe.data) 38 ...JSON.parse(recipe.data),
42 })) 39 }));
43 40
44 const recipes = [ 41 const recipes = [
45 ...officialRecipes, 42 ...officialRecipes,
46 ...customRecipes, 43 ...customRecipes,
47 ] 44 ];
48 45
49 return response.send(recipes) 46 return response.send(recipes);
50 } 47 }
51 48
52 // Create a new recipe using the new.html page 49 // Create a new recipe using the new.html page
53 async create({ 50 async create({
54 request, 51 request,
55 response 52 response,
56 }) { 53 }) {
57 // Check if recipe creation is enabled 54 // Check if recipe creation is enabled
58 if (Env.get('IS_CREATION_ENABLED') == 'false') { 55 if (Env.get('IS_CREATION_ENABLED') == 'false') { // eslint-disable-line eqeqeq
59 return response.send('This server doesn\'t allow the creation of new recipes.'); 56 return response.send('This server doesn\'t allow the creation of new recipes.');
60 } 57 }
61 58
@@ -69,10 +66,10 @@ class RecipeController {
69 }); 66 });
70 if (validation.fails()) { 67 if (validation.fails()) {
71 return response.status(401).send({ 68 return response.status(401).send({
72 "message": "Invalid POST arguments", 69 message: 'Invalid POST arguments',
73 "messages": validation.messages(), 70 messages: validation.messages(),
74 "status": 401 71 status: 401,
75 }) 72 });
76 } 73 }
77 74
78 const data = request.all(); 75 const data = request.all();
@@ -90,16 +87,16 @@ class RecipeController {
90 await fs.emptyDir(Helpers.tmpPath('recipe')); 87 await fs.emptyDir(Helpers.tmpPath('recipe'));
91 88
92 // Move uploaded files to temporary path 89 // Move uploaded files to temporary path
93 const files = request.file('files') 90 const files = request.file('files');
94 await files.moveAll(Helpers.tmpPath('recipe')) 91 await files.moveAll(Helpers.tmpPath('recipe'));
95 92
96 // Compress files to .tar.gz file 93 // Compress files to .tar.gz file
97 const source = Helpers.tmpPath('recipe'); 94 const source = Helpers.tmpPath('recipe');
98 const destination = path.join(Helpers.appRoot(), '/recipes/' + data.id + '.tar.gz'); 95 const destination = path.join(Helpers.appRoot(), `/recipes/${data.id}.tar.gz`);
99 96
100 compress( 97 compress(
101 source, 98 source,
102 destination 99 destination,
103 ); 100 );
104 101
105 // Create recipe in db 102 // Create recipe in db
@@ -107,74 +104,73 @@ class RecipeController {
107 name: data.name, 104 name: data.name,
108 recipeId: data.id, 105 recipeId: data.id,
109 data: JSON.stringify({ 106 data: JSON.stringify({
110 "author": data.author, 107 author: data.author,
111 "featured": false, 108 featured: false,
112 "version": "1.0.0", 109 version: '1.0.0',
113 "icons": { 110 icons: {
114 "png": data.png, 111 png: data.png,
115 "svg": data.svg 112 svg: data.svg,
116 } 113 },
117 }) 114 }),
118 }) 115 });
119 116
120 return response.send('Created new recipe') 117 return response.send('Created new recipe');
121 } 118 }
122 119
123 // Search official and custom recipes 120 // Search official and custom recipes
124 async search({ 121 async search({
125 request, 122 request,
126 response 123 response,
127 }) { 124 }) {
128 // Validate user input 125 // Validate user input
129 const validation = await validateAll(request.all(), { 126 const validation = await validateAll(request.all(), {
130 needle: 'required' 127 needle: 'required',
131 }); 128 });
132 if (validation.fails()) { 129 if (validation.fails()) {
133 return response.status(401).send({ 130 return response.status(401).send({
134 "message": "Please provide a needle", 131 message: 'Please provide a needle',
135 "messages": validation.messages(), 132 messages: validation.messages(),
136 "status": 401 133 status: 401,
137 }) 134 });
138 } 135 }
139 136
140 const needle = request.input('needle') 137 const needle = request.input('needle');
141 138
142 // Get results 139 // Get results
143 let remoteResults = []; 140 let remoteResults = [];
144 if (Env.get('CONNECT_WITH_FRANZ') == 'true') { 141 if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq
145 remoteResults = JSON.parse(await (await fetch('https://api.franzinfra.com/v1/recipes/search?needle=' + encodeURIComponent(needle))).text()); 142 remoteResults = JSON.parse(await (await fetch(`https://api.franzinfra.com/v1/recipes/search?needle=${encodeURIComponent(needle)}`)).text());
146 } 143 }
147 const localResultsArray = (await Recipe.query().where('name', 'LIKE', '%' + needle + '%').fetch()).toJSON(); 144 const localResultsArray = (await Recipe.query().where('name', 'LIKE', `%${needle}%`).fetch()).toJSON();
148 const localResults = localResultsArray.map(recipe => ({ 145 const localResults = localResultsArray.map((recipe) => ({
149 "id": recipe.recipeId, 146 id: recipe.recipeId,
150 "name": recipe.name, 147 name: recipe.name,
151 ...JSON.parse(recipe.data) 148 ...JSON.parse(recipe.data),
152 })) 149 }));
153 150
154 const results = [ 151 const results = [
155 ...localResults, 152 ...localResults,
156 ...remoteResults, 153 ...remoteResults,
157 ] 154 ];
158 155
159 return response.send(results); 156 return response.send(results);
160 } 157 }
161 158
162 // Download a recipe 159 // Download a recipe
163 async download({ 160 async download({
164 request,
165 response, 161 response,
166 params 162 params,
167 }) { 163 }) {
168 // Validate user input 164 // Validate user input
169 const validation = await validateAll(params, { 165 const validation = await validateAll(params, {
170 recipe: 'required|accepted' 166 recipe: 'required|accepted',
171 }); 167 });
172 if (validation.fails()) { 168 if (validation.fails()) {
173 return response.status(401).send({ 169 return response.status(401).send({
174 "message": "Please provide a recipe ID", 170 message: 'Please provide a recipe ID',
175 "messages": validation.messages(), 171 messages: validation.messages(),
176 "status": 401 172 status: 401,
177 }) 173 });
178 } 174 }
179 175
180 const service = params.recipe; 176 const service = params.recipe;
@@ -185,17 +181,16 @@ class RecipeController {
185 } 181 }
186 182
187 // Check if recipe exists in recipes folder 183 // Check if recipe exists in recipes folder
188 if (await Drive.exists(service + '.tar.gz')) { 184 if (await Drive.exists(`${service}.tar.gz`)) {
189 response.send(await Drive.get(service + '.tar.gz')) 185 response.send(await Drive.get(`${service}.tar.gz`));
190 } else if(Env.get('CONNECT_WITH_FRANZ') == 'true') { 186 } else if (Env.get('CONNECT_WITH_FRANZ') == 'true') { // eslint-disable-line eqeqeq
191 response.redirect('https://api.franzinfra.com/v1/recipes/download/' + service) 187 response.redirect(`https://api.franzinfra.com/v1/recipes/download/${service}`);
192 } else {
193 return response.status(400).send({
194 "message": "Recipe not found",
195 "code": "recipe-not-found"
196 })
197 } 188 }
189 return response.status(400).send({
190 message: 'Recipe not found',
191 code: 'recipe-not-found',
192 });
198 } 193 }
199} 194}
200 195
201module.exports = RecipeController 196module.exports = RecipeController;
diff --git a/app/Controllers/Http/ServiceController.js b/app/Controllers/Http/ServiceController.js
index e887e3a..309ae09 100644
--- a/app/Controllers/Http/ServiceController.js
+++ b/app/Controllers/Http/ServiceController.js
@@ -1,9 +1,6 @@
1'use strict'
2
3const User = use('App/Models/User');
4const Service = use('App/Models/Service'); 1const Service = use('App/Models/Service');
5const { 2const {
6 validateAll 3 validateAll,
7} = use('Validator'); 4} = use('Validator');
8 5
9const uuid = require('uuid/v4'); 6const uuid = require('uuid/v4');
@@ -13,12 +10,12 @@ class ServiceController {
13 async create({ 10 async create({
14 request, 11 request,
15 response, 12 response,
16 auth 13 auth,
17 }) { 14 }) {
18 try { 15 try {
19 await auth.getUser() 16 await auth.getUser();
20 } catch (error) { 17 } catch (error) {
21 return response.send('Missing or invalid api token') 18 return response.send('Missing or invalid api token');
22 } 19 }
23 20
24 // Validate user input 21 // Validate user input
@@ -28,10 +25,10 @@ class ServiceController {
28 }); 25 });
29 if (validation.fails()) { 26 if (validation.fails()) {
30 return response.status(401).send({ 27 return response.status(401).send({
31 "message": "Invalid POST arguments", 28 message: 'Invalid POST arguments',
32 "messages": validation.messages(), 29 messages: validation.messages(),
33 "status": 401 30 status: 401,
34 }) 31 });
35 } 32 }
36 33
37 const data = request.all(); 34 const data = request.all();
@@ -40,83 +37,82 @@ class ServiceController {
40 let serviceId; 37 let serviceId;
41 do { 38 do {
42 serviceId = uuid(); 39 serviceId = uuid();
43 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0) 40 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
44 41
45 const service = await Service.create({ 42 await Service.create({
46 userId: auth.user.id, 43 userId: auth.user.id,
47 serviceId, 44 serviceId,
48 name: data.name, 45 name: data.name,
49 recipeId: data.recipeId, 46 recipeId: data.recipeId,
50 settings: JSON.stringify(data) 47 settings: JSON.stringify(data),
51 }); 48 });
52 49
53 return response.send({ 50 return response.send({
54 "data": { 51 data: {
55 userId: auth.user.id, 52 userId: auth.user.id,
56 id: serviceId, 53 id: serviceId,
57 "isEnabled": true, 54 isEnabled: true,
58 "isNotificationEnabled": true, 55 isNotificationEnabled: true,
59 "isBadgeEnabled": true, 56 isBadgeEnabled: true,
60 "isMuted": false, 57 isMuted: false,
61 "isDarkModeEnabled": "", 58 isDarkModeEnabled: '',
62 "spellcheckerLanguage": "", 59 spellcheckerLanguage: '',
63 "order": 1, 60 order: 1,
64 "customRecipe": false, 61 customRecipe: false,
65 "hasCustomIcon": false, 62 hasCustomIcon: false,
66 "workspaces": [], 63 workspaces: [],
67 "iconUrl": null, 64 iconUrl: null,
68 ...data, 65 ...data,
69 }, 66 },
70 "status": ["created"] 67 status: ['created'],
71 }) 68 });
72 } 69 }
73 70
74 // List all services a user has created 71 // List all services a user has created
75 async list({ 72 async list({
76 request,
77 response, 73 response,
78 auth 74 auth,
79 }) { 75 }) {
80 try { 76 try {
81 await auth.getUser() 77 await auth.getUser();
82 } catch (error) { 78 } catch (error) {
83 return response.send('Missing or invalid api token') 79 return response.send('Missing or invalid api token');
84 } 80 }
85 81
86 const services = (await auth.user.services().fetch()).rows; 82 const services = (await auth.user.services().fetch()).rows;
87 // Convert to array with all data Franz wants 83 // Convert to array with all data Franz wants
88 const servicesArray = services.map(service => ({ 84 const servicesArray = services.map((service) => ({
89 "customRecipe": false, 85 customRecipe: false,
90 "hasCustomIcon": false, 86 hasCustomIcon: false,
91 "isBadgeEnabled": true, 87 isBadgeEnabled: true,
92 "isDarkModeEnabled": "", 88 isDarkModeEnabled: '',
93 "isEnabled": true, 89 isEnabled: true,
94 "isMuted": false, 90 isMuted: false,
95 "isNotificationEnabled": true, 91 isNotificationEnabled: true,
96 "order": 1, 92 order: 1,
97 "spellcheckerLanguage": "", 93 spellcheckerLanguage: '',
98 "workspaces": [], 94 workspaces: [],
99 "iconUrl": null, 95 iconUrl: null,
100 ...JSON.parse(service.settings), 96 ...JSON.parse(service.settings),
101 "id": service.serviceId, 97 id: service.serviceId,
102 "name": service.name, 98 name: service.name,
103 "recipeId": service.recipeId, 99 recipeId: service.recipeId,
104 "userId": auth.user.id, 100 userId: auth.user.id,
105 })) 101 }));
106 102
107 return response.send(servicesArray) 103 return response.send(servicesArray);
108 } 104 }
109 105
110 async edit({ 106 async edit({
111 request, 107 request,
112 response, 108 response,
113 auth, 109 auth,
114 params 110 params,
115 }) { 111 }) {
116 try { 112 try {
117 await auth.getUser() 113 await auth.getUser();
118 } catch (error) { 114 } catch (error) {
119 return response.send('Missing or invalid api token') 115 return response.send('Missing or invalid api token');
120 } 116 }
121 117
122 // Validate user input 118 // Validate user input
@@ -125,15 +121,15 @@ class ServiceController {
125 }); 121 });
126 if (validation.fails()) { 122 if (validation.fails()) {
127 return response.status(401).send({ 123 return response.status(401).send({
128 "message": "Invalid POST arguments", 124 message: 'Invalid POST arguments',
129 "messages": validation.messages(), 125 messages: validation.messages(),
130 "status": 401 126 status: 401,
131 }) 127 });
132 } 128 }
133 129
134 const data = request.all(); 130 const data = request.all();
135 const { 131 const {
136 id 132 id,
137 } = params; 133 } = params;
138 134
139 // Get current settings from db 135 // Get current settings from db
@@ -141,7 +137,7 @@ class ServiceController {
141 .where('serviceId', id) 137 .where('serviceId', id)
142 .where('userId', auth.user.id).fetch()).rows[0]; 138 .where('userId', auth.user.id).fetch()).rows[0];
143 139
144 let settings = { 140 const settings = {
145 ...JSON.parse(serviceData.settings), 141 ...JSON.parse(serviceData.settings),
146 ...data, 142 ...data,
147 }; 143 };
@@ -150,9 +146,9 @@ class ServiceController {
150 await (Service.query() 146 await (Service.query()
151 .where('serviceId', id) 147 .where('serviceId', id)
152 .where('userId', auth.user.id)).update({ 148 .where('userId', auth.user.id)).update({
153 name: data.name, 149 name: data.name,
154 settings: JSON.stringify(settings) 150 settings: JSON.stringify(settings),
155 }); 151 });
156 152
157 // Get updated row 153 // Get updated row
158 const service = (await Service.query() 154 const service = (await Service.query()
@@ -160,88 +156,86 @@ class ServiceController {
160 .where('userId', auth.user.id).fetch()).rows[0]; 156 .where('userId', auth.user.id).fetch()).rows[0];
161 157
162 return response.send({ 158 return response.send({
163 "id": service.serviceId, 159 id: service.serviceId,
164 "name": data.name, 160 name: data.name,
165 ...settings, 161 ...settings,
166 "userId": auth.user.id 162 userId: auth.user.id,
167 }) 163 });
168 } 164 }
169 165
170 async reorder({ 166 async reorder({
171 request, 167 request,
172 response, 168 response,
173 auth 169 auth,
174 }) { 170 }) {
175 const data = request.all(); 171 const data = request.all();
176 172
177 for (const service in data) { 173 for (const service of Object.keys(data)) {
178 // Get current settings from db 174 // Get current settings from db
179 const serviceData = (await Service.query() 175 const serviceData = (await Service.query() // eslint-disable-line no-await-in-loop
180 .where('serviceId', service) 176 .where('serviceId', service)
181 .where('userId', auth.user.id).fetch()).rows[0]; 177 .where('userId', auth.user.id).fetch()).rows[0];
182 178
183 let settings = { 179 const settings = {
184 ...JSON.parse(serviceData.settings), 180 ...JSON.parse(serviceData.settings),
185 order: data[service] 181 order: data[service],
186 }; 182 };
187 183
188 // Update data in database 184 // Update data in database
189 await (Service.query() 185 await (Service.query() // eslint-disable-line no-await-in-loop
190 .where('serviceId', service) 186 .where('serviceId', service)
191 .where('userId', auth.user.id)) 187 .where('userId', auth.user.id))
192 .update({ 188 .update({
193 settings: JSON.stringify(settings) 189 settings: JSON.stringify(settings),
194 }); 190 });
195 } 191 }
196 192
197 // Get new services 193 // Get new services
198 const services = (await auth.user.services().fetch()).rows; 194 const services = (await auth.user.services().fetch()).rows;
199 // Convert to array with all data Franz wants 195 // Convert to array with all data Franz wants
200 const servicesArray = services.map(service => ({ 196 const servicesArray = services.map((service) => ({
201 "customRecipe": false, 197 customRecipe: false,
202 "hasCustomIcon": false, 198 hasCustomIcon: false,
203 "isBadgeEnabled": true, 199 isBadgeEnabled: true,
204 "isDarkModeEnabled": "", 200 isDarkModeEnabled: '',
205 "isEnabled": true, 201 isEnabled: true,
206 "isMuted": false, 202 isMuted: false,
207 "isNotificationEnabled": true, 203 isNotificationEnabled: true,
208 "order": 1, 204 order: 1,
209 "spellcheckerLanguage": "", 205 spellcheckerLanguage: '',
210 "workspaces": [], 206 workspaces: [],
211 "iconUrl": null, 207 iconUrl: null,
212 ...JSON.parse(service.settings), 208 ...JSON.parse(service.settings),
213 "id": service.serviceId, 209 id: service.serviceId,
214 "name": service.name, 210 name: service.name,
215 "recipeId": service.recipeId, 211 recipeId: service.recipeId,
216 "userId": auth.user.id, 212 userId: auth.user.id,
217 })) 213 }));
218 214
219 return response.send(servicesArray) 215 return response.send(servicesArray);
220 } 216 }
221 217
222 update({ 218 update({
223 request, 219 response,
224 response
225 }) { 220 }) {
226 return response.send([]) 221 return response.send([]);
227 } 222 }
228 223
229 async delete({ 224 async delete({
230 request,
231 params, 225 params,
232 auth, 226 auth,
233 response 227 response,
234 }) { 228 }) {
235 // Update data in database 229 // Update data in database
236 await (Service.query() 230 await (Service.query()
237 .where('serviceId', params.id) 231 .where('serviceId', params.id)
238 .where('userId', auth.user.id)).delete() 232 .where('userId', auth.user.id)).delete();
239 233
240 return response.send({ 234 return response.send({
241 "message": "Sucessfully deleted service", 235 message: 'Sucessfully deleted service',
242 "status": 200 236 status: 200,
243 }) 237 });
244 } 238 }
245} 239}
246 240
247module.exports = ServiceController 241module.exports = ServiceController;
diff --git a/app/Controllers/Http/StaticController.js b/app/Controllers/Http/StaticController.js
index 17b641f..b16e6cb 100644
--- a/app/Controllers/Http/StaticController.js
+++ b/app/Controllers/Http/StaticController.js
@@ -1,4 +1,4 @@
1'use strict' 1
2/** 2/**
3 * Controller for routes with static responses 3 * Controller for routes with static responses
4 */ 4 */
@@ -6,220 +6,219 @@
6class StaticController { 6class StaticController {
7 // Enable all features 7 // Enable all features
8 features({ 8 features({
9 response 9 response,
10 }) { 10 }) {
11 return response.send({ 11 return response.send({
12 "needToWaitToProceed": false, 12 needToWaitToProceed: false,
13 "isSpellcheckerPremiumFeature": true, 13 isSpellcheckerPremiumFeature: true,
14 "isServiceProxyEnabled": true, 14 isServiceProxyEnabled: true,
15 "isServiceProxyPremiumFeature": true, 15 isServiceProxyPremiumFeature: true,
16 "isWorkspacePremiumFeature": true, 16 isWorkspacePremiumFeature: true,
17 "isWorkspaceEnabled": true, 17 isWorkspaceEnabled: true,
18 "isAnnouncementsEnabled": true, 18 isAnnouncementsEnabled: true,
19 "isSettingsWSEnabled": false, 19 isSettingsWSEnabled: false,
20 "isServiceLimitEnabled": false, 20 isServiceLimitEnabled: false,
21 "serviceLimitCount": 0, 21 serviceLimitCount: 0,
22 "isCommunityRecipesPremiumFeature": false 22 isCommunityRecipesPremiumFeature: false,
23 }) 23 });
24 } 24 }
25 25
26 // Return an empty array 26 // Return an empty array
27 emptyArray({ 27 emptyArray({
28 response 28 response,
29 }) { 29 }) {
30 return response.send([]) 30 return response.send([]);
31 } 31 }
32 32
33 // Payment plans availible 33 // Payment plans availible
34 plans({ 34 plans({
35 response 35 response,
36 }) { 36 }) {
37 return response.send({ 37 return response.send({
38 "month": { 38 month: {
39 "id": "franz-supporter-license", 39 id: 'franz-supporter-license',
40 "price": 99 40 price: 99,
41 }, 41 },
42 "year": { 42 year: {
43 "id": "franz-supporter-license-year-2019", 43 id: 'franz-supporter-license-year-2019',
44 "price": 99 44 price: 99,
45 } 45 },
46 }) 46 });
47 } 47 }
48 48
49 // Return list of popular recipes (copy of the response Franz's API is returning) 49 // Return list of popular recipes (copy of the response Franz's API is returning)
50 popularRecipes({ 50 popularRecipes({
51 response 51 response,
52 }) { 52 }) {
53 return response.send([{ 53 return response.send([{
54 "author": "Stefan Malzner <stefan@adlk.io>", 54 author: 'Stefan Malzner <stefan@adlk.io>',
55 "featured": false, 55 featured: false,
56 "id": "slack", 56 id: 'slack',
57 "name": "Slack", 57 name: 'Slack',
58 "version": "1.0.4", 58 version: '1.0.4',
59 "icons": { 59 icons: {
60 "png": "https://cdn.franzinfra.com/recipes/dist/slack/src/icon.png", 60 png: 'https://cdn.franzinfra.com/recipes/dist/slack/src/icon.png',
61 "svg": "https://cdn.franzinfra.com/recipes/dist/slack/src/icon.svg" 61 svg: 'https://cdn.franzinfra.com/recipes/dist/slack/src/icon.svg',
62 } 62 },
63 }, { 63 }, {
64 "author": "Stefan Malzner <stefan@adlk.io>", 64 author: 'Stefan Malzner <stefan@adlk.io>',
65 "featured": false, 65 featured: false,
66 "id": "whatsapp", 66 id: 'whatsapp',
67 "name": "WhatsApp", 67 name: 'WhatsApp',
68 "version": "1.0.1", 68 version: '1.0.1',
69 "icons": { 69 icons: {
70 "png": "https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.png", 70 png: 'https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.png',
71 "svg": "https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.svg" 71 svg: 'https://cdn.franzinfra.com/recipes/dist/whatsapp/src/icon.svg',
72 } 72 },
73 }, { 73 }, {
74 "author": "Stefan Malzner <stefan@adlk.io>", 74 author: 'Stefan Malzner <stefan@adlk.io>',
75 "featured": false, 75 featured: false,
76 "id": "messenger", 76 id: 'messenger',
77 "name": "Messenger", 77 name: 'Messenger',
78 "version": "1.0.6", 78 version: '1.0.6',
79 "icons": { 79 icons: {
80 "png": "https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.png", 80 png: 'https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.png',
81 "svg": "https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.svg" 81 svg: 'https://cdn.franzinfra.com/recipes/dist/messenger/src/icon.svg',
82 } 82 },
83 }, { 83 }, {
84 "author": "Stefan Malzner <stefan@adlk.io>", 84 author: 'Stefan Malzner <stefan@adlk.io>',
85 "featured": false, 85 featured: false,
86 "id": "telegram", 86 id: 'telegram',
87 "name": "Telegram", 87 name: 'Telegram',
88 "version": "1.0.0", 88 version: '1.0.0',
89 "icons": { 89 icons: {
90 "png": "https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.png", 90 png: 'https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.png',
91 "svg": "https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.svg" 91 svg: 'https://cdn.franzinfra.com/recipes/dist/telegram/src/icon.svg',
92 } 92 },
93 }, { 93 }, {
94 "author": "Stefan Malzner <stefan@adlk.io>", 94 author: 'Stefan Malzner <stefan@adlk.io>',
95 "featured": false, 95 featured: false,
96 "id": "gmail", 96 id: 'gmail',
97 "name": "Gmail", 97 name: 'Gmail',
98 "version": "1.0.0", 98 version: '1.0.0',
99 "icons": { 99 icons: {
100 "png": "https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.png", 100 png: 'https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.png',
101 "svg": "https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.svg" 101 svg: 'https://cdn.franzinfra.com/recipes/dist/gmail/src/icon.svg',
102 } 102 },
103 }, { 103 }, {
104 "author": "Stefan Malzner <stefan@adlk.io>", 104 author: 'Stefan Malzner <stefan@adlk.io>',
105 "featured": false, 105 featured: false,
106 "id": "skype", 106 id: 'skype',
107 "name": "Skype", 107 name: 'Skype',
108 "version": "1.0.0", 108 version: '1.0.0',
109 "icons": { 109 icons: {
110 "png": "https://cdn.franzinfra.com/recipes/dist/skype/src/icon.png", 110 png: 'https://cdn.franzinfra.com/recipes/dist/skype/src/icon.png',
111 "svg": "https://cdn.franzinfra.com/recipes/dist/skype/src/icon.svg" 111 svg: 'https://cdn.franzinfra.com/recipes/dist/skype/src/icon.svg',
112 } 112 },
113 }, { 113 }, {
114 "author": "Stefan Malzner <stefan@adlk.io>", 114 author: 'Stefan Malzner <stefan@adlk.io>',
115 "featured": false, 115 featured: false,
116 "id": "hangouts", 116 id: 'hangouts',
117 "name": "Hangouts", 117 name: 'Hangouts',
118 "version": "1.0.0", 118 version: '1.0.0',
119 "icons": { 119 icons: {
120 "png": "https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.png", 120 png: 'https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.png',
121 "svg": "https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.svg" 121 svg: 'https://cdn.franzinfra.com/recipes/dist/hangouts/src/icon.svg',
122 } 122 },
123 }, { 123 }, {
124 "author": "Stefan Malzner <stefan@adlk.io>", 124 author: 'Stefan Malzner <stefan@adlk.io>',
125 "featured": false, 125 featured: false,
126 "id": "discord", 126 id: 'discord',
127 "name": "Discord", 127 name: 'Discord',
128 "version": "1.0.0", 128 version: '1.0.0',
129 "icons": { 129 icons: {
130 "png": "https://cdn.franzinfra.com/recipes/dist/discord/src/icon.png", 130 png: 'https://cdn.franzinfra.com/recipes/dist/discord/src/icon.png',
131 "svg": "https://cdn.franzinfra.com/recipes/dist/discord/src/icon.svg" 131 svg: 'https://cdn.franzinfra.com/recipes/dist/discord/src/icon.svg',
132 } 132 },
133 }, { 133 }, {
134 "author": "Stefan Malzner <stefan@adlk.io>", 134 author: 'Stefan Malzner <stefan@adlk.io>',
135 "featured": false, 135 featured: false,
136 "id": "tweetdeck", 136 id: 'tweetdeck',
137 "name": "Tweetdeck", 137 name: 'Tweetdeck',
138 "version": "1.0.1", 138 version: '1.0.1',
139 "icons": { 139 icons: {
140 "png": "https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.png", 140 png: 'https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.png',
141 "svg": "https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.svg" 141 svg: 'https://cdn.franzinfra.com/recipes/dist/tweetdeck/src/icon.svg',
142 } 142 },
143 }, { 143 }, {
144 "author": "Stefan Malzner <stefan@adlk.io>", 144 author: 'Stefan Malzner <stefan@adlk.io>',
145 "featured": false, 145 featured: false,
146 "id": "hipchat", 146 id: 'hipchat',
147 "name": "HipChat", 147 name: 'HipChat',
148 "version": "1.0.1", 148 version: '1.0.1',
149 "icons": { 149 icons: {
150 "png": "https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.png", 150 png: 'https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.png',
151 "svg": "https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.svg" 151 svg: 'https://cdn.franzinfra.com/recipes/dist/hipchat/src/icon.svg',
152 } 152 },
153 }, { 153 }, {
154 "author": "Stefan Malzner <stefan@adlk.io>", 154 author: 'Stefan Malzner <stefan@adlk.io>',
155 "featured": false, 155 featured: false,
156 "id": "gmailinbox", 156 id: 'gmailinbox',
157 "name": "Inbox by Gmail", 157 name: 'Inbox by Gmail',
158 "version": "1.0.0", 158 version: '1.0.0',
159 "icons": { 159 icons: {
160 "png": "https://cdn.franzinfra.com/recipes/dist/gmailinbox/src/icon.png", 160 png: 'https://cdn.franzinfra.com/recipes/dist/gmailinbox/src/icon.png',
161 "svg": "https://cdn.franzinfra.com/recipes/dist/gmailinbox/src/icon.svg" 161 svg: 'https://cdn.franzinfra.com/recipes/dist/gmailinbox/src/icon.svg',
162 } 162 },
163 }, { 163 }, {
164 "author": "Stefan Malzner <stefan@adlk.io>", 164 author: 'Stefan Malzner <stefan@adlk.io>',
165 "featured": false, 165 featured: false,
166 "id": "rocketchat", 166 id: 'rocketchat',
167 "name": "Rocket.Chat", 167 name: 'Rocket.Chat',
168 "version": "1.0.1", 168 version: '1.0.1',
169 "icons": { 169 icons: {
170 "png": "https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.png", 170 png: 'https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.png',
171 "svg": "https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.svg" 171 svg: 'https://cdn.franzinfra.com/recipes/dist/rocketchat/src/icon.svg',
172 } 172 },
173 }, { 173 }, {
174 "author": "Brian Gilbert <brian@briangilbert.net>", 174 author: 'Brian Gilbert <brian@briangilbert.net>',
175 "featured": false, 175 featured: false,
176 "id": "gitter", 176 id: 'gitter',
177 "name": "Gitter", 177 name: 'Gitter',
178 "version": "1.0.0", 178 version: '1.0.0',
179 "icons": { 179 icons: {
180 "png": "https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.png", 180 png: 'https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.png',
181 "svg": "https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.svg" 181 svg: 'https://cdn.franzinfra.com/recipes/dist/gitter/src/icon.svg',
182 } 182 },
183 }, { 183 }, {
184 "author": "Stefan Malzner <stefan@adlk.io>", 184 author: 'Stefan Malzner <stefan@adlk.io>',
185 "featured": false, 185 featured: false,
186 "id": "mattermost", 186 id: 'mattermost',
187 "name": "Mattermost", 187 name: 'Mattermost',
188 "version": "1.0.0", 188 version: '1.0.0',
189 "icons": { 189 icons: {
190 "png": "https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.png", 190 png: 'https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.png',
191 "svg": "https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.svg" 191 svg: 'https://cdn.franzinfra.com/recipes/dist/mattermost/src/icon.svg',
192 } 192 },
193 }, { 193 }, {
194 "author": "Franz <recipe@meetfranz.com>", 194 author: 'Franz <recipe@meetfranz.com>',
195 "featured": false, 195 featured: false,
196 "id": "toggl", 196 id: 'toggl',
197 "name": "toggl", 197 name: 'toggl',
198 "version": "1.0.0", 198 version: '1.0.0',
199 "icons": { 199 icons: {
200 "png": "https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.png", 200 png: 'https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.png',
201 "svg": "https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.svg" 201 svg: 'https://cdn.franzinfra.com/recipes/dist/toggl/src/icon.svg',
202 } 202 },
203 }, { 203 }, {
204 "author": "Stuart Clark <stuart@realityloop.com>", 204 author: 'Stuart Clark <stuart@realityloop.com>',
205 "featured": false, 205 featured: false,
206 "id": "twist", 206 id: 'twist',
207 "name": "twist", 207 name: 'twist',
208 "version": "1.0.0", 208 version: '1.0.0',
209 "icons": { 209 icons: {
210 "png": "https://cdn.franzinfra.com/recipes/dist/twist/src/icon.png", 210 png: 'https://cdn.franzinfra.com/recipes/dist/twist/src/icon.png',
211 "svg": "https://cdn.franzinfra.com/recipes/dist/twist/src/icon.svg" 211 svg: 'https://cdn.franzinfra.com/recipes/dist/twist/src/icon.svg',
212 } 212 },
213 }]) 213 }]);
214 } 214 }
215 215
216 // Show announcements 216 // Show announcements
217 announcement({ 217 announcement({
218 response, 218 response,
219 params
220 }) { 219 }) {
221 return response.send('No announcement found.'); 220 return response.send('No announcement found.');
222 } 221 }
223} 222}
224 223
225module.exports = StaticController 224module.exports = StaticController;
diff --git a/app/Controllers/Http/UserController.js b/app/Controllers/Http/UserController.js
index ced27bb..1e67092 100644
--- a/app/Controllers/Http/UserController.js
+++ b/app/Controllers/Http/UserController.js
@@ -1,12 +1,10 @@
1'use strict'
2
3const User = use('App/Models/User'); 1const User = use('App/Models/User');
4const Service = use('App/Models/Service'); 2const Service = use('App/Models/Service');
5const Workspace = use('App/Models/Workspace'); 3const Workspace = use('App/Models/Workspace');
6const { 4const {
7 validateAll 5 validateAll,
8} = use('Validator'); 6} = use('Validator');
9const Env = use('Env') 7const Env = use('Env');
10 8
11const atob = require('atob'); 9const atob = require('atob');
12const btoa = require('btoa'); 10const btoa = require('btoa');
@@ -14,49 +12,44 @@ const fetch = require('node-fetch');
14const uuid = require('uuid/v4'); 12const uuid = require('uuid/v4');
15const crypto = require('crypto'); 13const crypto = require('crypto');
16 14
17const franzRequest = async (route, method, auth) => { 15const franzRequest = (route, method, auth) => new Promise((resolve, reject) => {
18 return new Promise(async (resolve, reject) => { 16 const base = 'https://api.franzinfra.com/v1/';
19 const base = 'https://api.franzinfra.com/v1/'; 17 const user = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Ferdi/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36';
20 const user = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Ferdi/5.3.0-beta.1 Chrome/69.0.3497.128 Electron/4.2.4 Safari/537.36'; 18
21 19 try {
22 try { 20 fetch(base + route, {
23 const rawResponse = await fetch(base + route, { 21 method,
24 method, 22 headers: {
25 headers: { 23 Authorization: `Bearer ${auth}`,
26 'Authorization': 'Bearer ' + auth, 24 'User-Agent': user,
27 'User-Agent': user 25 },
28 }, 26 })
29 }); 27 .then((data) => data.json())
30 const content = await rawResponse.json(); 28 .then((json) => resolve(json));
31 29 } catch (e) {
32 resolve(content); 30 reject();
33 } catch (e) { 31 }
34 reject(); 32});
35 }
36 })
37}
38 33
39class UserController { 34class UserController {
40
41 // Register a new user 35 // Register a new user
42 async signup({ 36 async signup({
43 request, 37 request,
44 response, 38 response,
45 auth, 39 auth,
46 session
47 }) { 40 }) {
48 // Validate user input 41 // Validate user input
49 const validation = await validateAll(request.all(), { 42 const validation = await validateAll(request.all(), {
50 firstname: 'required', 43 firstname: 'required',
51 email: 'required|email|unique:users,email', 44 email: 'required|email|unique:users,email',
52 password: 'required' 45 password: 'required',
53 }); 46 });
54 if (validation.fails()) { 47 if (validation.fails()) {
55 return response.status(401).send({ 48 return response.status(401).send({
56 "message": "Invalid POST arguments", 49 message: 'Invalid POST arguments',
57 "messages": validation.messages(), 50 messages: validation.messages(),
58 "status": 401 51 status: 401,
59 }) 52 });
60 } 53 }
61 54
62 const data = request.only(['firstname', 'email', 'password']); 55 const data = request.only(['firstname', 'email', 'password']);
@@ -67,21 +60,21 @@ class UserController {
67 user = await User.create({ 60 user = await User.create({
68 email: data.email, 61 email: data.email,
69 password: data.password, 62 password: data.password,
70 username: data.firstname 63 username: data.firstname,
71 }); 64 });
72 } catch (e) { 65 } catch (e) {
73 return response.status(401).send({ 66 return response.status(401).send({
74 "message": "E-Mail Address already in use", 67 message: 'E-Mail Address already in use',
75 "status": 401 68 status: 401,
76 }) 69 });
77 } 70 }
78 71
79 // Generate new auth token 72 // Generate new auth token
80 const token = await auth.generate(user) 73 const token = await auth.generate(user);
81 74
82 return response.send({ 75 return response.send({
83 "message": "Successfully created account", 76 message: 'Successfully created account',
84 "token": token.token 77 token: token.token,
85 }); 78 });
86 } 79 }
87 80
@@ -89,115 +82,112 @@ class UserController {
89 async login({ 82 async login({
90 request, 83 request,
91 response, 84 response,
92 auth 85 auth,
93 }) { 86 }) {
94 if (!request.header('Authorization')) { 87 if (!request.header('Authorization')) {
95 return response.status(401).send({ 88 return response.status(401).send({
96 "message": "Please provide authorization", 89 message: 'Please provide authorization',
97 "status": 401 90 status: 401,
98 }) 91 });
99 } 92 }
100 93
101 // Get auth data from auth token 94 // Get auth data from auth token
102 const authHeader = atob(request.header('Authorization').replace('Basic ', '')).split(':'); 95 const authHeader = atob(request.header('Authorization').replace('Basic ', '')).split(':');
103 96
104 // Check if user with email exists 97 // Check if user with email exists
105 let user = (await User.query().where('email', authHeader[0]).first()); 98 const user = (await User.query().where('email', authHeader[0]).first());
106 if (!user || !user.email) { 99 if (!user || !user.email) {
107 return response.status(401).send({ 100 return response.status(401).send({
108 "message": "User credentials not valid (Invalid mail)", 101 message: 'User credentials not valid (Invalid mail)',
109 "code": "invalid-credentials", 102 code: 'invalid-credentials',
110 "status": 401 103 status: 401,
111 }); 104 });
112 } 105 }
113 106
114 // Try to login 107 // Try to login
115 let token; 108 let token;
116 try { 109 try {
117 token = await auth.attempt(user.email, authHeader[1]) 110 token = await auth.attempt(user.email, authHeader[1]);
118 } catch (e) { 111 } catch (e) {
119 return response.status(401).send({ 112 return response.status(401).send({
120 "message": "User credentials not valid", 113 message: 'User credentials not valid',
121 "code": "invalid-credentials", 114 code: 'invalid-credentials',
122 "status": 401 115 status: 401,
123 }); 116 });
124 } 117 }
125 118
126 return response.send({ 119 return response.send({
127 "message": "Successfully logged in", 120 message: 'Successfully logged in',
128 "token": token.token 121 token: token.token,
129 }); 122 });
130 } 123 }
131 124
132 // Return information about the current user 125 // Return information about the current user
133 async me({ 126 async me({
134 request,
135 response, 127 response,
136 auth, 128 auth,
137 session
138 }) { 129 }) {
139 try { 130 try {
140 await auth.getUser() 131 await auth.getUser();
141 } catch (error) { 132 } catch (error) {
142 response.send('Missing or invalid api token') 133 response.send('Missing or invalid api token');
143 } 134 }
144 135
145 return response.send({ 136 return response.send({
146 accountType: "individual", 137 accountType: 'individual',
147 beta: false, 138 beta: false,
148 donor: {}, 139 donor: {},
149 email: auth.user.email, 140 email: auth.user.email,
150 emailValidated: true, 141 emailValidated: true,
151 features: {}, 142 features: {},
152 firstname: "Franz", 143 firstname: 'Franz',
153 id: "82c1cf9d-ab58-4da2-b55e-aaa41d2142d8", 144 id: '82c1cf9d-ab58-4da2-b55e-aaa41d2142d8',
154 isPremium: true, 145 isPremium: true,
155 isSubscriptionOwner: true, 146 isSubscriptionOwner: true,
156 lastname: "Franz", 147 lastname: 'Franz',
157 locale: "en-US" 148 locale: 'en-US',
158 }); 149 });
159 } 150 }
160 151
161 152
162
163 async import({ 153 async import({
164 request, 154 request,
165 response 155 response,
166 }) { 156 }) {
167 // Validate user input 157 // Validate user input
168 const validation = await validateAll(request.all(), { 158 const validation = await validateAll(request.all(), {
169 email: 'required|email|unique:users,email', 159 email: 'required|email|unique:users,email',
170 password: 'required' 160 password: 'required',
171 }); 161 });
172 if (validation.fails()) { 162 if (validation.fails()) {
173 let errorMessage = "There was an error while trying to import your account:\n"; 163 let errorMessage = 'There was an error while trying to import your account:\n';
174 for (const message of validation.messages()) { 164 for (const message of validation.messages()) {
175 if (message.validation == 'required') { 165 if (message.validation === 'required') {
176 errorMessage += '- Please make sure to supply your ' + message.field + '\n' 166 errorMessage += `- Please make sure to supply your ${message.field}\n`;
177 } else if (message.validation == 'unique') { 167 } else if (message.validation === 'unique') {
178 errorMessage += '- There is already a user with this email.\n' 168 errorMessage += '- There is already a user with this email.\n';
179 } else { 169 } else {
180 errorMessage += message.message + '\n'; 170 errorMessage += `${message.message}\n`;
181 } 171 }
182 } 172 }
183 return response.status(401).send(errorMessage) 173 return response.status(401).send(errorMessage);
184 } 174 }
185 175
186 const { 176 const {
187 email, 177 email,
188 password 178 password,
189 } = request.all() 179 } = request.all();
190 180
191 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64'); 181 const hashedPassword = crypto.createHash('sha256').update(password).digest('base64');
192 182
193 if(Env.get('CONNECT_WITH_FRANZ') == 'false') { 183 if (Env.get('CONNECT_WITH_FRANZ') == 'false') { // eslint-disable-line eqeqeq
194 await User.create({ 184 await User.create({
195 email, 185 email,
196 password: hashedPassword, 186 password: hashedPassword,
197 username: 'Franz' 187 username: 'Franz',
198 }); 188 });
199 189
200 return response.send('Your account has been created but due to this server\'s configuration, 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.') 190 return response.send('Your account has been created but due to this server\'s configuration, 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.');
201 } 191 }
202 192
203 const base = 'https://api.franzinfra.com/v1/'; 193 const base = 'https://api.franzinfra.com/v1/';
@@ -206,42 +196,41 @@ class UserController {
206 // Try to get an authentication token 196 // Try to get an authentication token
207 let token; 197 let token;
208 try { 198 try {
209 const basicToken = btoa(email + ':' + hashedPassword) 199 const basicToken = btoa(`${email}:${hashedPassword}`);
210 200
211 const rawResponse = await fetch(base + 'auth/login', { 201 const rawResponse = await fetch(`${base}auth/login`, {
212 method: 'POST', 202 method: 'POST',
213 headers: { 203 headers: {
214 'Authorization': 'Basic ' + basicToken, 204 Authorization: `Basic ${basicToken}`,
215 'User-Agent': userAgent 205 'User-Agent': userAgent,
216 }, 206 },
217 }); 207 });
218 const content = await rawResponse.json(); 208 const content = await rawResponse.json();
219 209
220 if (!content.message || content.message !== 'Successfully logged in') { 210 if (!content.message || content.message !== 'Successfully logged in') {
221 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again'; 211 const errorMessage = 'Could not login into Franz with your supplied credentials. Please check and try again';
222 return response.status(401).send(errorMessage) 212 return response.status(401).send(errorMessage);
223 } 213 }
224 214
225 token = content.token; 215 token = content.token;
226 } catch (e) { 216 } catch (e) {
227 return response.status(401).send({ 217 return response.status(401).send({
228 "message": "Cannot login to Franz", 218 message: 'Cannot login to Franz',
229 "error": e 219 error: e,
230 }) 220 });
231 } 221 }
232 222
233 // Get user information 223 // Get user information
234 let userInf = false; 224 let userInf = false;
235 try { 225 try {
236 userInf = await franzRequest('me', 'GET', token) 226 userInf = await franzRequest('me', 'GET', token);
237 console.log('A', userInf)
238 } catch (e) { 227 } catch (e) {
239 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; 228 const errorMessage = `Could not get your user info from Franz. Please check your credentials or try again later.\nError: ${e}`;
240 return response.status(401).send(errorMessage) 229 return response.status(401).send(errorMessage);
241 } 230 }
242 if (!userInf) { 231 if (!userInf) {
243 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later.\nError: ' + e; 232 const errorMessage = 'Could not get your user info from Franz. Please check your credentials or try again later';
244 return response.status(401).send(errorMessage) 233 return response.status(401).send(errorMessage);
245 } 234 }
246 235
247 // Create user in DB 236 // Create user in DB
@@ -250,69 +239,69 @@ class UserController {
250 user = await User.create({ 239 user = await User.create({
251 email: userInf.email, 240 email: userInf.email,
252 password: hashedPassword, 241 password: hashedPassword,
253 username: userInf.firstname 242 username: userInf.firstname,
254 }); 243 });
255 } catch (e) { 244 } catch (e) {
256 const errorMessage = 'Could not create your user in our system.\nError: ' + e; 245 const errorMessage = `Could not create your user in our system.\nError: ${e}`;
257 return response.status(401).send(errorMessage) 246 return response.status(401).send(errorMessage);
258 } 247 }
259 248
260 let serviceIdTranslation = {}; 249 const serviceIdTranslation = {};
261 250
262 // Import services 251 // Import services
263 try { 252 try {
264 const services = await franzRequest('me/services', 'GET', token) 253 const services = await franzRequest('me/services', 'GET', token);
265 254
266 for (const service of services) { 255 for (const service of services) {
267 // Get new, unused uuid 256 // Get new, unused uuid
268 let serviceId; 257 let serviceId;
269 do { 258 do {
270 serviceId = uuid(); 259 serviceId = uuid();
271 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0) 260 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
272 261
273 await Service.create({ 262 await Service.create({ // eslint-disable-line no-await-in-loop
274 userId: user.id, 263 userId: user.id,
275 serviceId, 264 serviceId,
276 name: service.name, 265 name: service.name,
277 recipeId: service.recipeId, 266 recipeId: service.recipeId,
278 settings: JSON.stringify(service) 267 settings: JSON.stringify(service),
279 }); 268 });
280 269
281 serviceIdTranslation[service.id] = serviceId; 270 serviceIdTranslation[service.id] = serviceId;
282 } 271 }
283 } catch (e) { 272 } catch (e) {
284 const errorMessage = 'Could not import your services into our system.\nError: ' + e; 273 const errorMessage = `Could not import your services into our system.\nError: ${e}`;
285 return response.status(401).send(errorMessage) 274 return response.status(401).send(errorMessage);
286 } 275 }
287 276
288 // Import workspaces 277 // Import workspaces
289 try { 278 try {
290 const workspaces = await franzRequest('workspace', 'GET', token) 279 const workspaces = await franzRequest('workspace', 'GET', token);
291 280
292 for (const workspace of workspaces) { 281 for (const workspace of workspaces) {
293 let workspaceId; 282 let workspaceId;
294 do { 283 do {
295 workspaceId = uuid(); 284 workspaceId = uuid();
296 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0) 285 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
297 286
298 const services = workspace.services.map(service => serviceIdTranslation[service]) 287 const services = workspace.services.map((service) => serviceIdTranslation[service]);
299 288
300 await Workspace.create({ 289 await Workspace.create({ // eslint-disable-line no-await-in-loop
301 userId: auth.user.id, 290 userId: user.id,
302 workspaceId, 291 workspaceId,
303 name: workspace.name, 292 name: workspace.name,
304 order: workspace.order, 293 order: workspace.order,
305 services: JSON.stringify(services), 294 services: JSON.stringify(services),
306 data: JSON.stringify({}) 295 data: JSON.stringify({}),
307 }); 296 });
308 } 297 }
309 } catch (e) { 298 } catch (e) {
310 const errorMessage = 'Could not import your workspaces into our system.\nError: ' + e; 299 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`;
311 return response.status(401).send(errorMessage) 300 return response.status(401).send(errorMessage);
312 } 301 }
313 302
314 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.') 303 return response.send('Your account has been imported. You can now use your Franz account in Ferdi.');
315 } 304 }
316} 305}
317 306
318module.exports = UserController 307module.exports = UserController;
diff --git a/app/Controllers/Http/WorkspaceController.js b/app/Controllers/Http/WorkspaceController.js
index b64d858..ecf79af 100644
--- a/app/Controllers/Http/WorkspaceController.js
+++ b/app/Controllers/Http/WorkspaceController.js
@@ -1,8 +1,7 @@
1'use strict'
2 1
3const Workspace = use('App/Models/Workspace'); 2const Workspace = use('App/Models/Workspace');
4const { 3const {
5 validateAll 4 validateAll,
6} = use('Validator'); 5} = use('Validator');
7 6
8const uuid = require('uuid/v4'); 7const uuid = require('uuid/v4');
@@ -12,12 +11,12 @@ class WorkspaceController {
12 async create({ 11 async create({
13 request, 12 request,
14 response, 13 response,
15 auth 14 auth,
16 }) { 15 }) {
17 try { 16 try {
18 await auth.getUser() 17 await auth.getUser();
19 } catch (error) { 18 } catch (error) {
20 return response.send('Missing or invalid api token') 19 return response.send('Missing or invalid api token');
21 } 20 }
22 21
23 // Validate user input 22 // Validate user input
@@ -26,10 +25,10 @@ class WorkspaceController {
26 }); 25 });
27 if (validation.fails()) { 26 if (validation.fails()) {
28 return response.status(401).send({ 27 return response.status(401).send({
29 "message": "Invalid POST arguments", 28 message: 'Invalid POST arguments',
30 "messages": validation.messages(), 29 messages: validation.messages(),
31 "status": 401 30 status: 401,
32 }) 31 });
33 } 32 }
34 33
35 const data = request.all(); 34 const data = request.all();
@@ -38,7 +37,7 @@ class WorkspaceController {
38 let workspaceId; 37 let workspaceId;
39 do { 38 do {
40 workspaceId = uuid(); 39 workspaceId = uuid();
41 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0) 40 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
42 41
43 const order = (await auth.user.workspaces().fetch()).rows.length; 42 const order = (await auth.user.workspaces().fetch()).rows.length;
44 43
@@ -48,7 +47,7 @@ class WorkspaceController {
48 name: data.name, 47 name: data.name,
49 order, 48 order,
50 services: JSON.stringify([]), 49 services: JSON.stringify([]),
51 data: JSON.stringify(data) 50 data: JSON.stringify(data),
52 }); 51 });
53 52
54 return response.send({ 53 return response.send({
@@ -57,37 +56,37 @@ class WorkspaceController {
57 id: workspaceId, 56 id: workspaceId,
58 order, 57 order,
59 workspaces: [], 58 workspaces: [],
60 }) 59 });
61 } 60 }
62 61
63 async edit({ 62 async edit({
64 request, 63 request,
65 response, 64 response,
66 auth, 65 auth,
67 params 66 params,
68 }) { 67 }) {
69 try { 68 try {
70 await auth.getUser() 69 await auth.getUser();
71 } catch (error) { 70 } catch (error) {
72 return response.send('Missing or invalid api token') 71 return response.send('Missing or invalid api token');
73 } 72 }
74 73
75 // Validate user input 74 // Validate user input
76 const validation = await validateAll(request.all(), { 75 const validation = await validateAll(request.all(), {
77 name: 'required|alpha', 76 name: 'required|alpha',
78 services: 'required|array' 77 services: 'required|array',
79 }); 78 });
80 if (validation.fails()) { 79 if (validation.fails()) {
81 return response.status(401).send({ 80 return response.status(401).send({
82 "message": "Invalid POST arguments", 81 message: 'Invalid POST arguments',
83 "messages": validation.messages(), 82 messages: validation.messages(),
84 "status": 401 83 status: 401,
85 }) 84 });
86 } 85 }
87 86
88 const data = request.all(); 87 const data = request.all();
89 const { 88 const {
90 id 89 id,
91 } = params; 90 } = params;
92 91
93 // Update data in database 92 // Update data in database
@@ -95,7 +94,7 @@ class WorkspaceController {
95 .where('workspaceId', id) 94 .where('workspaceId', id)
96 .where('userId', auth.user.id)).update({ 95 .where('userId', auth.user.id)).update({
97 name: data.name, 96 name: data.name,
98 services: JSON.stringify(data.services) 97 services: JSON.stringify(data.services),
99 }); 98 });
100 99
101 // Get updated row 100 // Get updated row
@@ -104,24 +103,24 @@ class WorkspaceController {
104 .where('userId', auth.user.id).fetch()).rows[0]; 103 .where('userId', auth.user.id).fetch()).rows[0];
105 104
106 return response.send({ 105 return response.send({
107 "id": workspace.workspaceId, 106 id: workspace.workspaceId,
108 "name": data.name, 107 name: data.name,
109 "order": workspace.order, 108 order: workspace.order,
110 "services": data.services, 109 services: data.services,
111 "userId": auth.user.id 110 userId: auth.user.id,
112 }) 111 });
113 } 112 }
114 113
115 async delete({ 114 async delete({
116 request, 115 request,
117 response, 116 response,
118 auth, 117 auth,
119 params 118 params,
120 }) { 119 }) {
121 try { 120 try {
122 await auth.getUser() 121 await auth.getUser();
123 } catch (error) { 122 } catch (error) {
124 return response.send('Missing or invalid api token') 123 return response.send('Missing or invalid api token');
125 } 124 }
126 125
127 // Validate user input 126 // Validate user input
@@ -130,14 +129,14 @@ class WorkspaceController {
130 }); 129 });
131 if (validation.fails()) { 130 if (validation.fails()) {
132 return response.status(401).send({ 131 return response.status(401).send({
133 "message": "Invalid POST arguments", 132 message: 'Invalid POST arguments',
134 "messages": validation.messages(), 133 messages: validation.messages(),
135 "status": 401 134 status: 401,
136 }) 135 });
137 } 136 }
138 137
139 const { 138 const {
140 id 139 id,
141 } = params; 140 } = params;
142 141
143 // Update data in database 142 // Update data in database
@@ -146,38 +145,37 @@ class WorkspaceController {
146 .where('userId', auth.user.id)).delete(); 145 .where('userId', auth.user.id)).delete();
147 146
148 return response.send({ 147 return response.send({
149 "message": "Successfully deleted workspace", 148 message: 'Successfully deleted workspace',
150 }) 149 });
151 } 150 }
152 151
153 // List all workspaces a user has created 152 // List all workspaces a user has created
154 async list({ 153 async list({
155 request,
156 response, 154 response,
157 auth 155 auth,
158 }) { 156 }) {
159 try { 157 try {
160 await auth.getUser() 158 await auth.getUser();
161 } catch (error) { 159 } catch (error) {
162 return response.send('Missing or invalid api token') 160 return response.send('Missing or invalid api token');
163 } 161 }
164 162
165 const workspaces = (await auth.user.workspaces().fetch()).rows; 163 const workspaces = (await auth.user.workspaces().fetch()).rows;
166 // Convert to array with all data Franz wants 164 // Convert to array with all data Franz wants
167 let workspacesArray = []; 165 let workspacesArray = [];
168 if(workspaces) { 166 if (workspaces) {
169 workspacesArray = workspaces.map(workspace => ({ 167 workspacesArray = workspaces.map((workspace) => ({
170 "id": workspace.workspaceId, 168 id: workspace.workspaceId,
171 "name": workspace.name, 169 name: workspace.name,
172 "order": workspace.order, 170 order: workspace.order,
173 "services": JSON.parse(workspace.services), 171 services: JSON.parse(workspace.services),
174 "userId": auth.user.id 172 userId: auth.user.id,
175 })) 173 }));
176 } 174 }
177
178 175
179 return response.send(workspacesArray) 176
177 return response.send(workspacesArray);
180 } 178 }
181} 179}
182 180
183module.exports = WorkspaceController 181module.exports = WorkspaceController;
diff --git a/app/Exceptions/Handler.js b/app/Exceptions/Handler.js
index efa2e0b..cb9e10b 100644
--- a/app/Exceptions/Handler.js
+++ b/app/Exceptions/Handler.js
@@ -1,6 +1,5 @@
1'use strict'
2 1
3const BaseExceptionHandler = use('BaseExceptionHandler') 2const BaseExceptionHandler = use('BaseExceptionHandler');
4 3
5/** 4/**
6 * This class handles all exceptions thrown during 5 * This class handles all exceptions thrown during
@@ -20,14 +19,14 @@ class ExceptionHandler extends BaseExceptionHandler {
20 * 19 *
21 * @return {void} 20 * @return {void}
22 */ 21 */
23 async handle (error, { request, response }) { 22 async handle(error, { response }) {
24 if (error.name === 'ValidationException') { 23 if (error.name === 'ValidationException') {
25 return response.status(400).send('Invalid arguments') 24 return response.status(400).send('Invalid arguments');
26 } else if (error.name === 'InvalidSessionException') { 25 } if (error.name === 'InvalidSessionException') {
27 return response.status(401).redirect('/user/login'); 26 return response.status(401).redirect('/user/login');
28 } 27 }
29 28
30 response.status(error.status).send(error.message) 29 return response.status(error.status).send(error.message);
31 } 30 }
32 31
33 /** 32 /**
@@ -40,8 +39,9 @@ class ExceptionHandler extends BaseExceptionHandler {
40 * 39 *
41 * @return {void} 40 * @return {void}
42 */ 41 */
43 async report (error, { request }) { 42 async report() {
43 return true;
44 } 44 }
45} 45}
46 46
47module.exports = ExceptionHandler 47module.exports = ExceptionHandler;
diff --git a/app/Middleware/ConvertEmptyStringsToNull.js b/app/Middleware/ConvertEmptyStringsToNull.js
index a5750cc..556f223 100644
--- a/app/Middleware/ConvertEmptyStringsToNull.js
+++ b/app/Middleware/ConvertEmptyStringsToNull.js
@@ -1,17 +1,16 @@
1'use strict'
2 1
3class ConvertEmptyStringsToNull { 2class ConvertEmptyStringsToNull {
4 async handle ({ request }, next) { 3 async handle({ request }, next) {
5 if (Object.keys(request.body).length) { 4 if (Object.keys(request.body).length) {
6 request.body = Object.assign( 5 request.body = Object.assign(
7 ...Object.keys(request.body).map(key => ({ 6 ...Object.keys(request.body).map((key) => ({
8 [key]: request.body[key] !== '' ? request.body[key] : null 7 [key]: request.body[key] !== '' ? request.body[key] : null,
9 })) 8 })),
10 ) 9 );
11 } 10 }
12 11
13 await next() 12 await next();
14 } 13 }
15} 14}
16 15
17module.exports = ConvertEmptyStringsToNull 16module.exports = ConvertEmptyStringsToNull;
diff --git a/app/Models/Recipe.js b/app/Models/Recipe.js
index 9e3619c..da3618b 100644
--- a/app/Models/Recipe.js
+++ b/app/Models/Recipe.js
@@ -1,9 +1,8 @@
1'use strict'
2 1
3/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
4const Model = use('Model') 3const Model = use('Model');
5 4
6class Recipe extends Model { 5class Recipe extends Model {
7} 6}
8 7
9module.exports = Recipe 8module.exports = Recipe;
diff --git a/app/Models/Service.js b/app/Models/Service.js
index 0ca72fd..0a13ec1 100644
--- a/app/Models/Service.js
+++ b/app/Models/Service.js
@@ -1,12 +1,11 @@
1'use strict'
2 1
3/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
4const Model = use('Model') 3const Model = use('Model');
5 4
6class Service extends Model { 5class Service extends Model {
7 user() { 6 user() {
8 return this.belongsTo('App/Models/User', 'userId', 'id') 7 return this.belongsTo('App/Models/User', 'userId', 'id');
9 } 8 }
10} 9}
11 10
12module.exports = Service 11module.exports = Service;
diff --git a/app/Models/Token.js b/app/Models/Token.js
index e089e87..f6bec08 100644
--- a/app/Models/Token.js
+++ b/app/Models/Token.js
@@ -1,9 +1,8 @@
1'use strict'
2 1
3/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
4const Model = use('Model') 3const Model = use('Model');
5 4
6class Token extends Model { 5class Token extends Model {
7} 6}
8 7
9module.exports = Token 8module.exports = Token;
diff --git a/app/Models/Traits/NoTimestamp.js b/app/Models/Traits/NoTimestamp.js
index edd07f0..c647428 100644
--- a/app/Models/Traits/NoTimestamp.js
+++ b/app/Models/Traits/NoTimestamp.js
@@ -1,16 +1,15 @@
1'use strict'
2 1
3class NoTimestamp { 2class NoTimestamp {
4 register (Model) { 3 register(Model) {
5 Object.defineProperties(Model, { 4 Object.defineProperties(Model, {
6 createdAtColumn: { 5 createdAtColumn: {
7 get: () => null, 6 get: () => null,
8 }, 7 },
9 updatedAtColumn: { 8 updatedAtColumn: {
10 get: () => null, 9 get: () => null,
11 } 10 },
12 }) 11 });
13 } 12 }
14} 13}
15 14
16module.exports = NoTimestamp 15module.exports = NoTimestamp;
diff --git a/app/Models/User.js b/app/Models/User.js
index c9a680a..3a40347 100644
--- a/app/Models/User.js
+++ b/app/Models/User.js
@@ -1,14 +1,13 @@
1'use strict'
2 1
3/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
4const Model = use('Model') 3const Model = use('Model');
5 4
6/** @type {import('@adonisjs/framework/src/Hash')} */ 5/** @type {import('@adonisjs/framework/src/Hash')} */
7const Hash = use('Hash') 6const Hash = use('Hash');
8 7
9class User extends Model { 8class User extends Model {
10 static boot () { 9 static boot() {
11 super.boot() 10 super.boot();
12 11
13 /** 12 /**
14 * A hook to hash the user password before saving 13 * A hook to hash the user password before saving
@@ -16,9 +15,10 @@ class User extends Model {
16 */ 15 */
17 this.addHook('beforeSave', async (userInstance) => { 16 this.addHook('beforeSave', async (userInstance) => {
18 if (userInstance.dirty.password) { 17 if (userInstance.dirty.password) {
19 userInstance.password = await Hash.make(userInstance.password) 18 // eslint-disable-next-line no-param-reassign
19 userInstance.password = await Hash.make(userInstance.password);
20 } 20 }
21 }) 21 });
22 } 22 }
23 23
24 /** 24 /**
@@ -31,17 +31,17 @@ class User extends Model {
31 * 31 *
32 * @return {Object} 32 * @return {Object}
33 */ 33 */
34 tokens () { 34 tokens() {
35 return this.hasMany('App/Models/Token') 35 return this.hasMany('App/Models/Token');
36 } 36 }
37 37
38 services () { 38 services() {
39 return this.hasMany('App/Models/Service', 'id', 'userId') 39 return this.hasMany('App/Models/Service', 'id', 'userId');
40 } 40 }
41 41
42 workspaces () { 42 workspaces() {
43 return this.hasMany('App/Models/Workspace', 'id', 'userId') 43 return this.hasMany('App/Models/Workspace', 'id', 'userId');
44 } 44 }
45} 45}
46 46
47module.exports = User 47module.exports = User;
diff --git a/app/Models/Workspace.js b/app/Models/Workspace.js
index f78a3f9..b155e09 100644
--- a/app/Models/Workspace.js
+++ b/app/Models/Workspace.js
@@ -1,12 +1,11 @@
1'use strict'
2 1
3/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */ 2/** @type {typeof import('@adonisjs/lucid/src/Lucid/Model')} */
4const Model = use('Model') 3const Model = use('Model');
5 4
6class Workspace extends Model { 5class Workspace extends Model {
7 user() { 6 user() {
8 return this.belongsTo('App/Models/User', 'userId', 'id') 7 return this.belongsTo('App/Models/User', 'userId', 'id');
9 } 8 }
10} 9}
11 10
12module.exports = Workspace 11module.exports = Workspace;