aboutsummaryrefslogtreecommitdiffstats
path: root/src/api
diff options
context:
space:
mode:
Diffstat (limited to 'src/api')
-rw-r--r--src/api/server/ServerApi.ts (renamed from src/api/server/ServerApi.js)99
-rw-r--r--src/api/utils/auth.ts2
2 files changed, 54 insertions, 47 deletions
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.ts
index 6bbf572fa..2fd1a8d0d 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.ts
@@ -1,3 +1,4 @@
1/* eslint-disable import/no-import-module-exports */
1/* eslint-disable global-require */ 2/* eslint-disable global-require */
2import { join } from 'path'; 3import { join } from 'path';
3import tar from 'tar'; 4import tar from 'tar';
@@ -10,6 +11,7 @@ import {
10 pathExistsSync, 11 pathExistsSync,
11 readJsonSync, 12 readJsonSync,
12 removeSync, 13 removeSync,
14 PathOrFileDescriptor,
13} from 'fs-extra'; 15} from 'fs-extra';
14import fetch from 'electron-fetch'; 16import fetch from 'electron-fetch';
15 17
@@ -39,12 +41,12 @@ const debug = require('debug')('Ferdi:ServerApi');
39module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory()); 41module.paths.unshift(getDevRecipeDirectory(), getRecipeDirectory());
40 42
41export default class ServerApi { 43export default class ServerApi {
42 recipePreviews = []; 44 recipePreviews: any[] = [];
43 45
44 recipes = []; 46 recipes: any[] = [];
45 47
46 // User 48 // User
47 async login(email, passwordHash) { 49 async login(email: string, passwordHash: string) {
48 const request = await sendAuthRequest( 50 const request = await sendAuthRequest(
49 `${apiBase()}/auth/login`, 51 `${apiBase()}/auth/login`,
50 { 52 {
@@ -56,7 +58,7 @@ export default class ServerApi {
56 false, 58 false,
57 ); 59 );
58 if (!request.ok) { 60 if (!request.ok) {
59 throw request; 61 throw new Error(request.statusText);
60 } 62 }
61 const u = await request.json(); 63 const u = await request.json();
62 64
@@ -64,7 +66,7 @@ export default class ServerApi {
64 return u.token; 66 return u.token;
65 } 67 }
66 68
67 async signup(data) { 69 async signup(data: any) {
68 const request = await sendAuthRequest( 70 const request = await sendAuthRequest(
69 `${apiBase()}/auth/signup`, 71 `${apiBase()}/auth/signup`,
70 { 72 {
@@ -74,7 +76,7 @@ export default class ServerApi {
74 false, 76 false,
75 ); 77 );
76 if (!request.ok) { 78 if (!request.ok) {
77 throw request; 79 throw new Error(request.statusText);
78 } 80 }
79 const u = await request.json(); 81 const u = await request.json();
80 82
@@ -82,20 +84,20 @@ export default class ServerApi {
82 return u.token; 84 return u.token;
83 } 85 }
84 86
85 async inviteUser(data) { 87 async inviteUser(data: any) {
86 const request = await sendAuthRequest(`${apiBase()}/invite`, { 88 const request = await sendAuthRequest(`${apiBase()}/invite`, {
87 method: 'POST', 89 method: 'POST',
88 body: JSON.stringify(data), 90 body: JSON.stringify(data),
89 }); 91 });
90 if (!request.ok) { 92 if (!request.ok) {
91 throw request; 93 throw new Error(request.statusText);
92 } 94 }
93 95
94 debug('ServerApi::inviteUser'); 96 debug('ServerApi::inviteUser');
95 return true; 97 return true;
96 } 98 }
97 99
98 async retrievePassword(email) { 100 async retrievePassword(email: string) {
99 const request = await sendAuthRequest( 101 const request = await sendAuthRequest(
100 `${apiBase()}/auth/password`, 102 `${apiBase()}/auth/password`,
101 { 103 {
@@ -107,7 +109,7 @@ export default class ServerApi {
107 false, 109 false,
108 ); 110 );
109 if (!request.ok) { 111 if (!request.ok) {
110 throw request; 112 throw new Error(request.statusText);
111 } 113 }
112 const r = await request.json(); 114 const r = await request.json();
113 115
@@ -122,7 +124,7 @@ export default class ServerApi {
122 124
123 const request = await sendAuthRequest(`${apiBase()}/me`); 125 const request = await sendAuthRequest(`${apiBase()}/me`);
124 if (!request.ok) { 126 if (!request.ok) {
125 throw request; 127 throw new Error(request.statusText);
126 } 128 }
127 const data = await request.json(); 129 const data = await request.json();
128 130
@@ -132,13 +134,13 @@ export default class ServerApi {
132 return user; 134 return user;
133 } 135 }
134 136
135 async updateUserInfo(data) { 137 async updateUserInfo(data: any) {
136 const request = await sendAuthRequest(`${apiBase()}/me`, { 138 const request = await sendAuthRequest(`${apiBase()}/me`, {
137 method: 'PUT', 139 method: 'PUT',
138 body: JSON.stringify(data), 140 body: JSON.stringify(data),
139 }); 141 });
140 if (!request.ok) { 142 if (!request.ok) {
141 throw request; 143 throw new Error(request.statusText);
142 } 144 }
143 const updatedData = await request.json(); 145 const updatedData = await request.json();
144 146
@@ -154,7 +156,7 @@ export default class ServerApi {
154 method: 'DELETE', 156 method: 'DELETE',
155 }); 157 });
156 if (!request.ok) { 158 if (!request.ok) {
157 throw request; 159 throw new Error(request.statusText);
158 } 160 }
159 const data = await request.json(); 161 const data = await request.json();
160 162
@@ -170,7 +172,7 @@ export default class ServerApi {
170 172
171 const request = await sendAuthRequest(`${apiBase()}/me/services`); 173 const request = await sendAuthRequest(`${apiBase()}/me/services`);
172 if (!request.ok) { 174 if (!request.ok) {
173 throw request; 175 throw new Error(request.statusText);
174 } 176 }
175 const data = await request.json(); 177 const data = await request.json();
176 178
@@ -180,13 +182,13 @@ export default class ServerApi {
180 return filteredServices; 182 return filteredServices;
181 } 183 }
182 184
183 async createService(recipeId, data) { 185 async createService(recipeId: string, data: { iconFile: any }) {
184 const request = await sendAuthRequest(`${apiBase()}/service`, { 186 const request = await sendAuthRequest(`${apiBase()}/service`, {
185 method: 'POST', 187 method: 'POST',
186 body: JSON.stringify({ recipeId, ...data }), 188 body: JSON.stringify({ recipeId, ...data }),
187 }); 189 });
188 if (!request.ok) { 190 if (!request.ok) {
189 throw request; 191 throw new Error(request.statusText);
190 } 192 }
191 const serviceData = await request.json(); 193 const serviceData = await request.json();
192 194
@@ -207,7 +209,7 @@ export default class ServerApi {
207 return service; 209 return service;
208 } 210 }
209 211
210 async updateService(serviceId, rawData) { 212 async updateService(serviceId: string, rawData: any) {
211 const data = rawData; 213 const data = rawData;
212 214
213 if (data.iconFile) { 215 if (data.iconFile) {
@@ -220,7 +222,7 @@ export default class ServerApi {
220 }); 222 });
221 223
222 if (!request.ok) { 224 if (!request.ok) {
223 throw request; 225 throw new Error(request.statusText);
224 } 226 }
225 227
226 const serviceData = await request.json(); 228 const serviceData = await request.json();
@@ -233,12 +235,13 @@ export default class ServerApi {
233 return service; 235 return service;
234 } 236 }
235 237
236 async uploadServiceIcon(serviceId, icon) { 238 async uploadServiceIcon(serviceId: string, icon: string | Blob) {
237 const formData = new FormData(); 239 const formData = new FormData();
238 formData.append('icon', icon); 240 formData.append('icon', icon);
239 241
240 const requestData = prepareAuthRequest({ 242 const requestData = prepareAuthRequest({
241 method: 'PUT', 243 method: 'PUT',
244 // @ts-expect-error Argument of type '{ method: string; body: FormData; }' is not assignable to parameter of type '{ method: string; }'.
242 body: formData, 245 body: formData,
243 }); 246 });
244 247
@@ -246,11 +249,12 @@ export default class ServerApi {
246 249
247 const request = await window.fetch( 250 const request = await window.fetch(
248 `${apiBase()}/service/${serviceId}`, 251 `${apiBase()}/service/${serviceId}`,
252 // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'.
249 requestData, 253 requestData,
250 ); 254 );
251 255
252 if (!request.ok) { 256 if (!request.ok) {
253 throw request; 257 throw new Error(request.statusText);
254 } 258 }
255 259
256 const serviceData = await request.json(); 260 const serviceData = await request.json();
@@ -258,25 +262,25 @@ export default class ServerApi {
258 return serviceData.data; 262 return serviceData.data;
259 } 263 }
260 264
261 async reorderService(data) { 265 async reorderService(data: any) {
262 const request = await sendAuthRequest(`${apiBase()}/service/reorder`, { 266 const request = await sendAuthRequest(`${apiBase()}/service/reorder`, {
263 method: 'PUT', 267 method: 'PUT',
264 body: JSON.stringify(data), 268 body: JSON.stringify(data),
265 }); 269 });
266 if (!request.ok) { 270 if (!request.ok) {
267 throw request; 271 throw new Error(request.statusText);
268 } 272 }
269 const serviceData = await request.json(); 273 const serviceData = await request.json();
270 debug('ServerApi::reorderService resolves', serviceData); 274 debug('ServerApi::reorderService resolves', serviceData);
271 return serviceData; 275 return serviceData;
272 } 276 }
273 277
274 async deleteService(id) { 278 async deleteService(id: string) {
275 const request = await sendAuthRequest(`${apiBase()}/service/${id}`, { 279 const request = await sendAuthRequest(`${apiBase()}/service/${id}`, {
276 method: 'DELETE', 280 method: 'DELETE',
277 }); 281 });
278 if (!request.ok) { 282 if (!request.ok) {
279 throw request; 283 throw new Error(request.statusText);
280 } 284 }
281 const data = await request.json(); 285 const data = await request.json();
282 286
@@ -290,7 +294,7 @@ export default class ServerApi {
290 async getDefaultFeatures() { 294 async getDefaultFeatures() {
291 const request = await sendAuthRequest(`${apiBase()}/features/default`); 295 const request = await sendAuthRequest(`${apiBase()}/features/default`);
292 if (!request.ok) { 296 if (!request.ok) {
293 throw request; 297 throw new Error(request.statusText);
294 } 298 }
295 const data = await request.json(); 299 const data = await request.json();
296 300
@@ -306,7 +310,7 @@ export default class ServerApi {
306 310
307 const request = await sendAuthRequest(`${apiBase()}/features`); 311 const request = await sendAuthRequest(`${apiBase()}/features`);
308 if (!request.ok) { 312 if (!request.ok) {
309 throw request; 313 throw new Error(request.statusText);
310 } 314 }
311 const data = await request.json(); 315 const data = await request.json();
312 316
@@ -340,13 +344,13 @@ export default class ServerApi {
340 return this.recipes; 344 return this.recipes;
341 } 345 }
342 346
343 async getRecipeUpdates(recipeVersions) { 347 async getRecipeUpdates(recipeVersions: any) {
344 const request = await sendAuthRequest(`${apiBase()}/recipes/update`, { 348 const request = await sendAuthRequest(`${apiBase()}/recipes/update`, {
345 method: 'POST', 349 method: 'POST',
346 body: JSON.stringify(recipeVersions), 350 body: JSON.stringify(recipeVersions),
347 }); 351 });
348 if (!request.ok) { 352 if (!request.ok) {
349 throw request; 353 throw new Error(request.statusText);
350 } 354 }
351 const recipes = await request.json(); 355 const recipes = await request.json();
352 debug('ServerApi::getRecipeUpdates resolves', recipes); 356 debug('ServerApi::getRecipeUpdates resolves', recipes);
@@ -356,7 +360,7 @@ export default class ServerApi {
356 // Recipes Previews 360 // Recipes Previews
357 async getRecipePreviews() { 361 async getRecipePreviews() {
358 const request = await sendAuthRequest(`${apiBase()}/recipes`); 362 const request = await sendAuthRequest(`${apiBase()}/recipes`);
359 if (!request.ok) throw request; 363 if (!request.ok) throw new Error(request.statusText);
360 const data = await request.json(); 364 const data = await request.json();
361 const recipePreviews = this._mapRecipePreviewModel(data); 365 const recipePreviews = this._mapRecipePreviewModel(data);
362 debug('ServerApi::getRecipes resolves', recipePreviews); 366 debug('ServerApi::getRecipes resolves', recipePreviews);
@@ -366,7 +370,7 @@ export default class ServerApi {
366 async getFeaturedRecipePreviews() { 370 async getFeaturedRecipePreviews() {
367 // TODO: If we are hitting the internal-server, we need to return an empty list, else we can hit the remote server and get the data 371 // TODO: If we are hitting the internal-server, we need to return an empty list, else we can hit the remote server and get the data
368 const request = await sendAuthRequest(`${apiBase()}/recipes/popular`); 372 const request = await sendAuthRequest(`${apiBase()}/recipes/popular`);
369 if (!request.ok) throw request; 373 if (!request.ok) throw new Error(request.statusText);
370 374
371 const data = await request.json(); 375 const data = await request.json();
372 const recipePreviews = this._mapRecipePreviewModel(data); 376 const recipePreviews = this._mapRecipePreviewModel(data);
@@ -374,10 +378,10 @@ export default class ServerApi {
374 return recipePreviews; 378 return recipePreviews;
375 } 379 }
376 380
377 async searchRecipePreviews(needle) { 381 async searchRecipePreviews(needle: string) {
378 const url = `${apiBase()}/recipes/search?needle=${needle}`; 382 const url = `${apiBase()}/recipes/search?needle=${needle}`;
379 const request = await sendAuthRequest(url); 383 const request = await sendAuthRequest(url);
380 if (!request.ok) throw request; 384 if (!request.ok) throw new Error(request.statusText);
381 385
382 const data = await request.json(); 386 const data = await request.json();
383 const recipePreviews = this._mapRecipePreviewModel(data); 387 const recipePreviews = this._mapRecipePreviewModel(data);
@@ -385,7 +389,7 @@ export default class ServerApi {
385 return recipePreviews; 389 return recipePreviews;
386 } 390 }
387 391
388 async getRecipePackage(recipeId) { 392 async getRecipePackage(recipeId: string) {
389 try { 393 try {
390 const recipesDirectory = userDataRecipesPath(); 394 const recipesDirectory = userDataRecipesPath();
391 const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId); 395 const recipeTempDirectory = join(recipesDirectory, 'temp', recipeId);
@@ -395,7 +399,7 @@ export default class ServerApi {
395 399
396 ensureDirSync(recipeTempDirectory); 400 ensureDirSync(recipeTempDirectory);
397 401
398 let archivePath; 402 let archivePath: PathOrFileDescriptor;
399 403
400 if (pathExistsSync(internalRecipeFile)) { 404 if (pathExistsSync(internalRecipeFile)) {
401 debug('[ServerApi::getRecipePackage] Using internal recipe file'); 405 debug('[ServerApi::getRecipePackage] Using internal recipe file');
@@ -415,6 +419,7 @@ export default class ServerApi {
415 419
416 await sleep(10); 420 await sleep(10);
417 421
422 // @ts-expect-error No overload matches this call.
418 await tar.x({ 423 await tar.x({
419 file: archivePath, 424 file: archivePath,
420 cwd: recipeTempDirectory, 425 cwd: recipeTempDirectory,
@@ -454,7 +459,7 @@ export default class ServerApi {
454 false, 459 false,
455 ); 460 );
456 if (!request.ok) { 461 if (!request.ok) {
457 throw request; 462 throw new Error(request.statusText);
458 } 463 }
459 debug('ServerApi::healthCheck resolves'); 464 debug('ServerApi::healthCheck resolves');
460 } 465 }
@@ -467,7 +472,7 @@ export default class ServerApi {
467 472
468 if (Object.prototype.hasOwnProperty.call(config, 'services')) { 473 if (Object.prototype.hasOwnProperty.call(config, 'services')) {
469 const services = await Promise.all( 474 const services = await Promise.all(
470 config.services.map(async s => { 475 config.services.map(async (s: { service: any }) => {
471 const service = s; 476 const service = s;
472 const request = await sendAuthRequest( 477 const request = await sendAuthRequest(
473 `${apiBase()}/recipes/${s.service}`, 478 `${apiBase()}/recipes/${s.service}`,
@@ -475,6 +480,7 @@ export default class ServerApi {
475 480
476 if (request.status === 200) { 481 if (request.status === 200) {
477 const data = await request.json(); 482 const data = await request.json();
483 // @ts-expect-error Property 'recipe' does not exist on type '{ service: any; }'.
478 service.recipe = new RecipePreviewModel(data); 484 service.recipe = new RecipePreviewModel(data);
479 } 485 }
480 486
@@ -493,18 +499,18 @@ export default class ServerApi {
493 } 499 }
494 500
495 // Helper 501 // Helper
496 async _mapServiceModels(services) { 502 async _mapServiceModels(services: any[]) {
497 const recipes = services.map(s => s.recipeId); 503 const recipes = services.map((s: { recipeId: string }) => s.recipeId);
498 await this._bulkRecipeCheck(recipes); 504 await this._bulkRecipeCheck(recipes);
499 /* eslint-disable no-return-await */ 505 /* eslint-disable no-return-await */
500 return Promise.all( 506 return Promise.all(
501 services.map(async service => await this._prepareServiceModel(service)), 507 services.map(async (service: any) => this._prepareServiceModel(service)),
502 ); 508 );
503 /* eslint-enable no-return-await */ 509 /* eslint-enable no-return-await */
504 } 510 }
505 511
506 async _prepareServiceModel(service) { 512 async _prepareServiceModel(service: { recipeId: string }) {
507 let recipe; 513 let recipe: undefined;
508 try { 514 try {
509 recipe = this.recipes.find(r => r.id === service.recipeId); 515 recipe = this.recipes.find(r => r.id === service.recipeId);
510 516
@@ -520,14 +526,15 @@ export default class ServerApi {
520 } 526 }
521 } 527 }
522 528
523 async _bulkRecipeCheck(unfilteredRecipes) { 529 async _bulkRecipeCheck(unfilteredRecipes: any[]) {
524 // Filter recipe duplicates as we don't need to download 3 Slack recipes 530 // Filter recipe duplicates as we don't need to download 3 Slack recipes
525 const recipes = unfilteredRecipes.filter( 531 const recipes = unfilteredRecipes.filter(
526 (elem, pos, arr) => arr.indexOf(elem) === pos, 532 (elem: any, pos: number, arr: string | any[]) =>
533 arr.indexOf(elem) === pos,
527 ); 534 );
528 535
529 return Promise.all( 536 return Promise.all(
530 recipes.map(async recipeId => { 537 recipes.map(async (recipeId: string) => {
531 let recipe = this.recipes.find(r => r.id === recipeId); 538 let recipe = this.recipes.find(r => r.id === recipeId);
532 539
533 if (!recipe) { 540 if (!recipe) {
@@ -553,7 +560,7 @@ export default class ServerApi {
553 ).catch(error => console.error("Can't load recipe", error)); 560 ).catch(error => console.error("Can't load recipe", error));
554 } 561 }
555 562
556 _mapRecipePreviewModel(recipes) { 563 _mapRecipePreviewModel(recipes: any[]) {
557 return recipes 564 return recipes
558 .map(recipe => { 565 .map(recipe => {
559 try { 566 try {
diff --git a/src/api/utils/auth.ts b/src/api/utils/auth.ts
index 98295d1a4..899881e88 100644
--- a/src/api/utils/auth.ts
+++ b/src/api/utils/auth.ts
@@ -31,7 +31,7 @@ export const prepareAuthRequest = (
31 31
32export const sendAuthRequest = ( 32export const sendAuthRequest = (
33 url: RequestInfo, 33 url: RequestInfo,
34 options: { method: string } | undefined, 34 options?: { method: string; headers?: any; body?: any },
35 auth?: boolean, 35 auth?: boolean,
36) => 36) =>
37 // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'. 37 // @ts-expect-error Argument of type '{ method: string; } & { mode: string; headers: any; }' is not assignable to parameter of type 'RequestInit | undefined'.