From 0b35cc6788747533cde63dcfa0b7fec72f56cdcf Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 17:53:06 -0800 Subject: [PATCH 1/8] SASS config include loading spinner --- Frontend/sass.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/sass.config.js b/Frontend/sass.config.js index 86d1fbaa3..81e42ea68 100644 --- a/Frontend/sass.config.js +++ b/Frontend/sass.config.js @@ -65,7 +65,7 @@ module.exports = { /\.(wp).(scss)$/i, // Exclude list from https://julienrenaux.fr/2017/07/20/optimized-ionic-angular-css-bundle-for-pwas/ // /(action-sheet|alert|backdrop|badge|button|card|checkbox|chip|datetime|fab|grid|icon|img|infinite-scroll|input|item|label|list|loading|menu|modal|note|picker|popover|radio|range|refresher|searchbar|segment|select|show-hide-when|slides|split-pane|spinner|tabs|toast|toggle|virtual-scroll|cordova)/i, - /(action-sheet|chip|datetime|img|infinite-scroll|loading|note|picker|range|slides|split-pane|tabs|virtual-scroll|cordova)/i, + /(action-sheet|chip|datetime|img|infinite-scroll|note|picker|range|slides|split-pane|tabs|virtual-scroll|cordova)/i, ], /** From 885b90eeb432ce7df59824d054ac2b8c579d8eec Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 17:53:26 -0800 Subject: [PATCH 2/8] Fullscreen loading on recipe delete --- .../src/pages/settings-components/account/account.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Frontend/src/pages/settings-components/account/account.ts b/Frontend/src/pages/settings-components/account/account.ts index 7526062bb..1d795da3e 100644 --- a/Frontend/src/pages/settings-components/account/account.ts +++ b/Frontend/src/pages/settings-components/account/account.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { IonicPage, ToastController, AlertController, NavController, NavParams } from 'ionic-angular'; +import { IonicPage, ToastController, AlertController, NavController, NavParams, LoadingController } from 'ionic-angular'; import { UserServiceProvider } from '../../../providers/user-service/user-service'; import { LoadingServiceProvider } from '../../../providers/loading-service/loading-service'; @@ -29,6 +29,7 @@ export class AccountPage { public alertCtrl: AlertController, public navParams: NavParams, public utilService: UtilServiceProvider, + public loadingCtrl: LoadingController, public loadingService: LoadingServiceProvider, public recipeService: RecipeServiceProvider, public userService: UserServiceProvider) { @@ -246,7 +247,11 @@ export class AccountPage { { text: 'Yes, continue', handler: () => { - let loading = this.loadingService.start(); + let loading = this.loadingCtrl.create({ + content: 'Deleting Recipes, Please Wait...' + }); + + loading.present(); Promise.all([ new Promise((resolve, reject) => this.recipeService.fetch({ folder: 'main' }).subscribe(response => resolve(response), err => reject(err))), From a738f3951e3851646bb8f0bbde5a4f9e1c3274de Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:14:52 -0800 Subject: [PATCH 3/8] Added recipe deleteall route --- Backend/routes/recipes.js | 25 ++++++++++ Backend/routes/recipes.spec.js | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/Backend/routes/recipes.js b/Backend/routes/recipes.js index b763b2c49..41ba240bb 100644 --- a/Backend/routes/recipes.js +++ b/Backend/routes/recipes.js @@ -286,6 +286,31 @@ router.put( }); }); +router.delete( + '/all', + cors(), + MiddlewareService.validateSession(['user']), + function(req, res, next) { + + SQ.transaction(t => { + return Recipe.destroy({ + where: { + userId: res.locals.session.userId + }, + transaction: t + }).then(() => { + return Label.destroy({ + where: { + userId: res.locals.session.userId + }, + transaction: t + }).then(() => { + res.status(200).send({}) + }) + }) + }).catch(next); +}) + router.delete( '/:id', cors(), diff --git a/Backend/routes/recipes.spec.js b/Backend/routes/recipes.spec.js index c9c33a9dc..fa6653f77 100644 --- a/Backend/routes/recipes.spec.js +++ b/Backend/routes/recipes.spec.js @@ -469,6 +469,92 @@ describe('recipes', () => { }) }) + describe('delete all', () => { + it('deletes all recipes and labels', async () => { + let user = await createUser(); + + let session = await createSession(user.id); + + let recipe1 = await createRecipe(user.id); + let recipe2 = await createRecipe(user.id); + + let label1 = await createLabel(user.id); + let label2 = await createLabel(user.id); + + await associateLabel(label1.id, recipe1.id); + await associateLabel(label2.id, recipe2.id); + + await request(server) + .delete(`/recipes/all`) + .query({ token: session.token }) + .expect(200) + .then(async () => { + await Recipe.findAll({ + where: { + userId: user.id + } + }).then(async recipes => { + expect(recipes).to.have.lengthOf(0) + + await Label.findAll({ + where: { + userId: user.id + } + }).then(labels => { + expect(labels).to.have.lengthOf(0) + }) + }) + }); + }) + + it('does not remove recipes or labels belonging to another user', async () => { + let user1 = await createUser(); + let user2 = await createUser(); + + let session = await createSession(user1.id); + + let recipe = await createRecipe(user2.id); + + let label = await createLabel(user2.id); + + await associateLabel(label.id, recipe.id); + + await request(server) + .delete(`/recipes/all`) + .query({ token: session.token }) + .then(async () => { + await Recipe.findAll({ + where: { + userId: user2.id + } + }).then(async recipes => { + expect(recipes).to.have.lengthOf(1) + + await Label.findAll({ + where: { + userId: user2.id + } + }).then(labels => { + expect(labels).to.have.lengthOf(1) + }) + }) + }); + }); + + it('requires valid session', async () => { + let user = await createUser(); + + let session = await createSession(user.id); + + let recipe = await createRecipe(user.id); + + return request(server) + .delete(`/recipes/all`) + .query({ token: 'invalid' }) + .expect(401); + }); + }) + describe('delete', () => { it('deletes recipe', async () => { let user = await createUser(); From 0a262627e27691447f71cf24bcd34869b7d123d8 Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:15:23 -0800 Subject: [PATCH 4/8] Revert "Fullscreen loading on recipe delete" This reverts commit 885b90eeb432ce7df59824d054ac2b8c579d8eec. --- .../src/pages/settings-components/account/account.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/Frontend/src/pages/settings-components/account/account.ts b/Frontend/src/pages/settings-components/account/account.ts index 1d795da3e..7526062bb 100644 --- a/Frontend/src/pages/settings-components/account/account.ts +++ b/Frontend/src/pages/settings-components/account/account.ts @@ -1,5 +1,5 @@ import { Component } from '@angular/core'; -import { IonicPage, ToastController, AlertController, NavController, NavParams, LoadingController } from 'ionic-angular'; +import { IonicPage, ToastController, AlertController, NavController, NavParams } from 'ionic-angular'; import { UserServiceProvider } from '../../../providers/user-service/user-service'; import { LoadingServiceProvider } from '../../../providers/loading-service/loading-service'; @@ -29,7 +29,6 @@ export class AccountPage { public alertCtrl: AlertController, public navParams: NavParams, public utilService: UtilServiceProvider, - public loadingCtrl: LoadingController, public loadingService: LoadingServiceProvider, public recipeService: RecipeServiceProvider, public userService: UserServiceProvider) { @@ -247,11 +246,7 @@ export class AccountPage { { text: 'Yes, continue', handler: () => { - let loading = this.loadingCtrl.create({ - content: 'Deleting Recipes, Please Wait...' - }); - - loading.present(); + let loading = this.loadingService.start(); Promise.all([ new Promise((resolve, reject) => this.recipeService.fetch({ folder: 'main' }).subscribe(response => resolve(response), err => reject(err))), From e8d402419690ac323aa1d3ec8f268f788c1cf3f9 Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:15:40 -0800 Subject: [PATCH 5/8] Revert "SASS config include loading spinner" This reverts commit 0b35cc6788747533cde63dcfa0b7fec72f56cdcf. --- Frontend/sass.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Frontend/sass.config.js b/Frontend/sass.config.js index 81e42ea68..86d1fbaa3 100644 --- a/Frontend/sass.config.js +++ b/Frontend/sass.config.js @@ -65,7 +65,7 @@ module.exports = { /\.(wp).(scss)$/i, // Exclude list from https://julienrenaux.fr/2017/07/20/optimized-ionic-angular-css-bundle-for-pwas/ // /(action-sheet|alert|backdrop|badge|button|card|checkbox|chip|datetime|fab|grid|icon|img|infinite-scroll|input|item|label|list|loading|menu|modal|note|picker|popover|radio|range|refresher|searchbar|segment|select|show-hide-when|slides|split-pane|spinner|tabs|toast|toggle|virtual-scroll|cordova)/i, - /(action-sheet|chip|datetime|img|infinite-scroll|note|picker|range|slides|split-pane|tabs|virtual-scroll|cordova)/i, + /(action-sheet|chip|datetime|img|infinite-scroll|loading|note|picker|range|slides|split-pane|tabs|virtual-scroll|cordova)/i, ], /** From d210a81900d14ad62392e223e742256f235199aa Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:17:28 -0800 Subject: [PATCH 6/8] Added recipe removeAll method for recipe service --- .../recipe-service/recipe-service.ts | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Frontend/src/providers/recipe-service/recipe-service.ts b/Frontend/src/providers/recipe-service/recipe-service.ts index 95e719bca..d23008562 100644 --- a/Frontend/src/providers/recipe-service/recipe-service.ts +++ b/Frontend/src/providers/recipe-service/recipe-service.ts @@ -185,7 +185,30 @@ export class RecipeServiceProvider { this.http .delete(this.base + 'recipes/' + data.id + this.getTokenQuery(), httpOptions) .pipe( - retry(1), + retry(2), + catchError(this.handleError) + ).subscribe(response => { + this.events.publish('recipe:deleted'); + this.events.publish('recipe:generalUpdate'); + resolve(response); + }, reject); + } + } + } + + removeAll() { + const httpOptions = { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }; + + return { + subscribe: (resolve, reject) => { + this.http + .delete(this.base + 'recipes/all' + this.getTokenQuery(), httpOptions) + .pipe( + retry(2), catchError(this.handleError) ).subscribe(response => { this.events.publish('recipe:deleted'); From 794eec91d0e89d40944717cf47f828ea3d28da98 Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:21:17 -0800 Subject: [PATCH 7/8] Updated account page to use recipeService removeAll --- .../settings-components/account/account.ts | 56 +++---------------- 1 file changed, 8 insertions(+), 48 deletions(-) diff --git a/Frontend/src/pages/settings-components/account/account.ts b/Frontend/src/pages/settings-components/account/account.ts index 7526062bb..738368553 100644 --- a/Frontend/src/pages/settings-components/account/account.ts +++ b/Frontend/src/pages/settings-components/account/account.ts @@ -4,7 +4,7 @@ import { IonicPage, ToastController, AlertController, NavController, NavParams } import { UserServiceProvider } from '../../../providers/user-service/user-service'; import { LoadingServiceProvider } from '../../../providers/loading-service/loading-service'; import { UtilServiceProvider } from '../../../providers/util-service/util-service'; -import { RecipeServiceProvider, Recipe } from '../../../providers/recipe-service/recipe-service'; +import { RecipeServiceProvider } from '../../../providers/recipe-service/recipe-service'; @IonicPage({ priority: 'low' @@ -248,54 +248,14 @@ export class AccountPage { handler: () => { let loading = this.loadingService.start(); - Promise.all([ - new Promise((resolve, reject) => this.recipeService.fetch({ folder: 'main' }).subscribe(response => resolve(response), err => reject(err))), - new Promise((resolve, reject) => this.recipeService.fetch({ folder: 'inbox' }).subscribe(response => resolve(response), err => reject(err))), - ]).then(([main, inbox]: [[Recipe], [Recipe]]) => { - let allRecipes = [...main, ...inbox] - - Promise.all(allRecipes.map(recipe => { - return new Promise((resolve, reject) => { - setTimeout(() => { - this.recipeService.remove({ - id: recipe.id - }).subscribe(response => resolve(response), err => reject(err)) - }, Math.floor(Math.random() * 1000)) // Avoid server ddos - }) - })).then(() => { - loading.dismiss(); - - this.toastCtrl.create({ - message: 'Your recipe data has been deleted.', - duration: 5000 - }).present(); - }).catch(err => { - loading.dismiss(); + this.recipeService.removeAll().subscribe(() => { + loading.dismiss(); - switch (err.status) { - case 0: - this.toastCtrl.create({ - message: this.utilService.standardMessages.offlinePushMessage, - duration: 5000 - }).present(); - break; - case 401: - this.toastCtrl.create({ - message: 'It looks like your session has expired. Please login and try again.', - duration: 5000 - }).present(); - this.navCtrl.setRoot('LoginPage', {}, { animate: true, direction: 'forward' }); - break; - default: - let errorToast = this.toastCtrl.create({ - message: this.utilService.standardMessages.unexpectedError, - duration: 30000 - }); - errorToast.present(); - break; - } - }) - }).catch(err => { + this.toastCtrl.create({ + message: 'Your recipe data has been deleted.', + duration: 5000 + }).present(); + }, err => { loading.dismiss(); switch (err.status) { From c045948a9ab70adeb9167209d0e9f6eb8413f770 Mon Sep 17 00:00:00 2001 From: Julian Poyourow Date: Thu, 28 Feb 2019 18:23:20 -0800 Subject: [PATCH 8/8] Verbump 1.5.3 --- Backend/app.js | 2 +- Frontend/src/index.html | 2 +- .../pages/info-components/release-notes/release-notes.html | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Backend/app.js b/Backend/app.js index f08eb2b3d..48c98a653 100644 --- a/Backend/app.js +++ b/Backend/app.js @@ -21,7 +21,7 @@ var devMode = appConfig.environment === 'dev'; Raven.config(appConfig.sentry.dsn, { environment: appConfig.environment, - release: '1.5.2' + release: '1.5.3' }).install(); // Routes diff --git a/Frontend/src/index.html b/Frontend/src/index.html index d06eb0040..04365adb2 100644 --- a/Frontend/src/index.html +++ b/Frontend/src/index.html @@ -88,7 +88,7 @@ diff --git a/Frontend/src/pages/info-components/release-notes/release-notes.html b/Frontend/src/pages/info-components/release-notes/release-notes.html index a85ccf24d..873c93649 100644 --- a/Frontend/src/pages/info-components/release-notes/release-notes.html +++ b/Frontend/src/pages/info-components/release-notes/release-notes.html @@ -20,6 +20,11 @@
+ v1.5.3
+ - Fixed a bug where "delete all recipes" would not work on extremely large recipe collections
+ +
+ v1.5.2
- Added "delete all recipes" option in settings under "danger zone"
- Fixed a bug where changing password would not dismiss loading bar