Bulk export (#684)

* First pass (working) collection export to zip

* Add export confirmation screen

* 👕

* Refactor

* Job for team export, move to tmp file, settings UI

* Export all collections job

* 👕

* Add specs

* Clarify UI
This commit is contained in:
Tom Moor
2018-06-20 21:33:21 -07:00
committed by GitHub
parent cedd31c9ea
commit b9e0668d7d
26 changed files with 543 additions and 28 deletions

View File

@@ -18,6 +18,24 @@ Object {
}
`;
exports[`#collections.export should require authentication 1`] = `
Object {
"error": "authentication_required",
"message": "Authentication required",
"ok": false,
"status": 401,
}
`;
exports[`#collections.exportAll should require authentication 1`] = `
Object {
"error": "authentication_required",
"message": "Authentication required",
"ok": false,
"status": 401,
}
`;
exports[`#collections.info should require authentication 1`] = `
Object {
"error": "authentication_required",

View File

@@ -4,8 +4,9 @@ import Router from 'koa-router';
import auth from '../middlewares/authentication';
import pagination from './middlewares/pagination';
import { presentCollection } from '../presenters';
import { Collection } from '../models';
import { Collection, Team } from '../models';
import { ValidationError } from '../errors';
import { exportCollection, exportCollections } from '../logistics';
import policy from '../policies';
const { authorize } = policy;
@@ -46,6 +47,35 @@ router.post('collections.info', auth(), async ctx => {
};
});
router.post('collections.export', auth(), async ctx => {
const { id } = ctx.body;
ctx.assertPresent(id, 'id is required');
const user = ctx.state.user;
const collection = await Collection.findById(id);
authorize(user, 'export', collection);
// async operation to create zip archive and email user
exportCollection(id, user.email);
ctx.body = {
success: true,
};
});
router.post('collections.exportAll', auth(), async ctx => {
const user = ctx.state.user;
const team = await Team.findById(user.teamId);
authorize(user, 'export', team);
// async operation to create zip archive and email user
exportCollections(user.teamId, user.email);
ctx.body = {
success: true,
};
});
router.post('collections.update', auth(), async ctx => {
const { id, name, color } = ctx.body;
ctx.assertPresent(name, 'name is required');

View File

@@ -31,6 +31,52 @@ describe('#collections.list', async () => {
});
});
describe('#collections.export', async () => {
it('should require authentication', async () => {
const res = await server.post('/api/collections.export');
const body = await res.json();
expect(res.status).toEqual(401);
expect(body).toMatchSnapshot();
});
it('should return success', async () => {
const { user, collection } = await seed();
const res = await server.post('/api/collections.export', {
body: { token: user.getJwtToken(), id: collection.id },
});
expect(res.status).toEqual(200);
});
});
describe('#collections.exportAll', async () => {
it('should require authentication', async () => {
const res = await server.post('/api/collections.exportAll');
const body = await res.json();
expect(res.status).toEqual(401);
expect(body).toMatchSnapshot();
});
it('should require authorization', async () => {
const user = await buildUser();
const res = await server.post('/api/collections.exportAll', {
body: { token: user.getJwtToken() },
});
expect(res.status).toEqual(403);
});
it('should return success', async () => {
const { admin } = await seed();
const res = await server.post('/api/collections.exportAll', {
body: { token: admin.getJwtToken() },
});
expect(res.status).toEqual(200);
});
});
describe('#collections.info', async () => {
it('should return collection', async () => {
const { user, collection } = await seed();