aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar vantezzen <hello@vantezzen.io>2019-10-19 15:41:31 +0200
committerLibravatar vantezzen <hello@vantezzen.io>2019-10-19 15:41:31 +0200
commit5bf9eb5898f14afc66f690c866637b4815195bad (patch)
tree08e772531561928f9152a559b43c1e74909886c5
parentBump version number (diff)
downloadferdium-server-5bf9eb5898f14afc66f690c866637b4815195bad.tar.gz
ferdium-server-5bf9eb5898f14afc66f690c866637b4815195bad.tar.zst
ferdium-server-5bf9eb5898f14afc66f690c866637b4815195bad.zip
Add page to transfer user accounts
-rw-r--r--app/Controllers/Http/DashboardController.js106
-rw-r--r--public/js/transfer.js14
-rw-r--r--resources/views/dashboard/account.edge3
-rw-r--r--resources/views/dashboard/transfer.edge52
-rw-r--r--start/routes.js3
5 files changed, 178 insertions, 0 deletions
diff --git a/app/Controllers/Http/DashboardController.js b/app/Controllers/Http/DashboardController.js
index 49f6cc0..fe179c9 100644
--- a/app/Controllers/Http/DashboardController.js
+++ b/app/Controllers/Http/DashboardController.js
@@ -3,7 +3,11 @@ const {
3 validateAll, 3 validateAll,
4} = use('Validator'); 4} = use('Validator');
5 5
6const Service = use('App/Models/Service');
7const Workspace = use('App/Models/Workspace');
8
6const crypto = require('crypto'); 9const crypto = require('crypto');
10const uuid = require('uuid/v4');
7 11
8class DashboardController { 12class DashboardController {
9 async login({ 13 async login({
@@ -135,6 +139,108 @@ class DashboardController {
135 }); 139 });
136 } 140 }
137 141
142 async export({
143 auth,
144 response,
145 }) {
146 const general = auth.user;
147 const services = (await auth.user.services().fetch()).toJSON();
148 const workspaces = (await auth.user.workspaces().fetch()).toJSON();
149
150 const exportData = {
151 username: general.username,
152 mail: general.email,
153 services,
154 workspaces,
155 };
156
157 return response
158 .header('Content-Type', 'application/force-download')
159 .header('Content-disposition', 'attachment; filename=export.ferdi-data')
160 .send(exportData);
161 }
162
163 async import({
164 auth,
165 request,
166 session,
167 response,
168 }) {
169 let validation = await validateAll(request.all(), {
170 file: 'required',
171 });
172 if (validation.fails()) {
173 session.withErrors(validation.messages()).flashExcept(['password']);
174 return response.redirect('back');
175 }
176
177 let file;
178 try {
179 file = JSON.parse(request.input('file'));
180 } catch(e) {
181 session.flash({ type: 'danger', message: 'Invalid Ferdi account file' })
182 return response.redirect('back');
183 }
184 console.log(file);
185
186 if(!file || !file.services || !file.workspaces) {
187 session.flash({ type: 'danger', message: 'Invalid Ferdi account file (2)' })
188 return response.redirect('back');
189 }
190
191 const serviceIdTranslation = {};
192
193 // Import services
194 try {
195 for (const service of file.services) {
196 // Get new, unused uuid
197 let serviceId;
198 do {
199 serviceId = uuid();
200 } while ((await Service.query().where('serviceId', serviceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
201
202 await Service.create({ // eslint-disable-line no-await-in-loop
203 userId: auth.user.id,
204 serviceId,
205 name: service.name,
206 recipeId: service.recipeId,
207 settings: JSON.stringify(service.settings),
208 });
209
210 serviceIdTranslation[service.id] = serviceId;
211 }
212 } catch (e) {
213 const errorMessage = `Could not import your services into our system.\nError: ${e}`;
214 return response.status(401).send(errorMessage);
215 }
216
217 // Import workspaces
218 try {
219 for (const workspace of file.workspaces) {
220 let workspaceId;
221 do {
222 workspaceId = uuid();
223 } while ((await Workspace.query().where('workspaceId', workspaceId).fetch()).rows.length > 0); // eslint-disable-line no-await-in-loop
224
225 const services = workspace.services.map((service) => serviceIdTranslation[service]);
226
227 await Workspace.create({ // eslint-disable-line no-await-in-loop
228 userId: auth.user.id,
229 workspaceId,
230 name: workspace.name,
231 order: workspace.order,
232 services: JSON.stringify(services),
233 data: JSON.stringify(workspace.data),
234 });
235 }
236 } catch (e) {
237 const errorMessage = `Could not import your workspaces into our system.\nError: ${e}`;
238 return response.status(401).send(errorMessage);
239 }
240
241 return response.send('Your account has been imported.');
242 }
243
138 logout({ 244 logout({
139 auth, 245 auth,
140 response, 246 response,
diff --git a/public/js/transfer.js b/public/js/transfer.js
new file mode 100644
index 0000000..d3d23b3
--- /dev/null
+++ b/public/js/transfer.js
@@ -0,0 +1,14 @@
1/* eslint-env browser */
2const submitBtn = document.getElementById('submit');
3const fileInput = document.getElementById('file');
4const fileOutput = document.getElementById('fileoutput');
5
6fileInput.addEventListener('change', () => {
7 const reader = new FileReader();
8 reader.onload = function () {
9 const text = reader.result;
10 fileOutput.value = text;
11 submitBtn.disabled = false;
12 };
13 reader.readAsText(fileInput.files[0]);
14})
diff --git a/resources/views/dashboard/account.edge b/resources/views/dashboard/account.edge
index 0361fa4..a91aa11 100644
--- a/resources/views/dashboard/account.edge
+++ b/resources/views/dashboard/account.edge
@@ -55,6 +55,9 @@
55 <a class="button" href="/user/data" style="margin-bottom:1rem;">My account data</a> 55 <a class="button" href="/user/data" style="margin-bottom:1rem;">My account data</a>
56</div> 56</div>
57<div> 57<div>
58 <a class="button" href="/user/transfer" style="margin-bottom:1rem;">Import/Export account data</a>
59</div>
60<div>
58 <a class="button" href="/user/logout">Logout</a> 61 <a class="button" href="/user/logout">Logout</a>
59</div> 62</div>
60 63
diff --git a/resources/views/dashboard/transfer.edge b/resources/views/dashboard/transfer.edge
new file mode 100644
index 0000000..94efeb0
--- /dev/null
+++ b/resources/views/dashboard/transfer.edge
@@ -0,0 +1,52 @@
1@layout('layouts.main')
2
3@section('content')
4<h2>Import/Export data from another Ferdi server</h2>
5@if(flashMessage('error'))
6 <div class="alert">
7 {{ flashMessage('error') }}
8 </div>
9@endif
10@if(old('message'))
11 <div class="alert">
12 {{ old('message') }}
13 </div>
14@endif
15@if(flashMessage('notification'))
16 <div class="alert">
17 {{ flashMessage('notification.message') }}
18 </div>
19@endif
20@if(success === true)
21 <div class="alert" style="background-color:#28C76F;">
22 Sucessfully imported your account data
23 </div>
24@endif
25
26<h3>Import data</h3>
27<div>
28 <label>Account data</label>
29 <div>
30 <input type="file" name="file" id="file" value="" accept=".json,.ferdi-data" required>
31 </div>
32</div>
33
34<form action="/user/transfer" method="POST">
35 {{ csrfField() }}
36 <input type="hidden" name="file" id="fileoutput" value="">
37 <div>
38 <button style="background-color:#28C76F;margin-bottom:1rem;" id="submit" disabled>Import data</button>
39 </div>
40</form>
41
42<h3>Export data</h3>
43<a class="button" style="background-color:#28C76F;margin-bottom:1rem;" href="/user/export">Export data</a>
44
45<div>
46 <a class="button" href="/user/account">Back to my account</a>
47</div>
48
49</div>
50<script src="/js/transfer.js"></script>
51
52@endsection \ No newline at end of file
diff --git a/start/routes.js b/start/routes.js
index 4373b75..7243079 100644
--- a/start/routes.js
+++ b/start/routes.js
@@ -67,6 +67,9 @@ Route.group(() => {
67 Route.get('account', 'DashboardController.account').middleware('auth:session'); 67 Route.get('account', 'DashboardController.account').middleware('auth:session');
68 Route.post('account', 'DashboardController.edit').middleware('auth:session'); 68 Route.post('account', 'DashboardController.edit').middleware('auth:session');
69 Route.get('data', 'DashboardController.data').middleware('auth:session'); 69 Route.get('data', 'DashboardController.data').middleware('auth:session');
70 Route.get('export', 'DashboardController.export').middleware('auth:session');
71 Route.post('transfer', 'DashboardController.import').middleware('auth:session');
72 Route.get('transfer', ({ view }) => view.render('dashboard.transfer')).middleware('auth:session');
70 Route.get('delete', ({ view }) => view.render('dashboard.delete')).middleware('auth:session'); 73 Route.get('delete', ({ view }) => view.render('dashboard.delete')).middleware('auth:session');
71 Route.post('delete', 'DashboardController.delete').middleware('auth:session'); 74 Route.post('delete', 'DashboardController.delete').middleware('auth:session');
72 Route.get('logout', 'DashboardController.logout').middleware('auth:session'); 75 Route.get('logout', 'DashboardController.logout').middleware('auth:session');