Skip to content

Commit

Permalink
Merge pull request #169 from julianpoy/bug/#127-user-delete-better-lo…
Browse files Browse the repository at this point in the history
…ading

Bug/#127 User delete all recipes bulk
  • Loading branch information
julianpoy authored Mar 1, 2019
2 parents 33657eb + c045948 commit 8d8a757
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 51 deletions.
2 changes: 1 addition & 1 deletion Backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
25 changes: 25 additions & 0 deletions Backend/routes/recipes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
86 changes: 86 additions & 0 deletions Backend/routes/recipes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion Frontend/src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
</script>

<script>
window.version = '1.5.2';
window.version = '1.5.3';
</script>

<link href="build/main.css" rel="stylesheet" async>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@

<br />

<b>v1.5.3</b><br />
- Fixed a bug where "delete all recipes" would not work on extremely large recipe collections<br />

<br />

<b>v1.5.2</b><br />
- Added "delete all recipes" option in settings under "danger zone"<br />
- Fixed a bug where changing password would not dismiss loading bar<br />
Expand Down
56 changes: 8 additions & 48 deletions Frontend/src/pages/settings-components/account/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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) {
Expand Down
25 changes: 24 additions & 1 deletion Frontend/src/providers/recipe-service/recipe-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down

0 comments on commit 8d8a757

Please sign in to comment.