feat: Allow export of collections as sync zip (#1013)
* feat: Allow export of collections as sync zip * test: Add spec
This commit is contained in:
@ -7,7 +7,7 @@ import { presentCollection, presentUser } from '../presenters';
|
||||
import { Collection, CollectionUser, Team, Event, User } from '../models';
|
||||
import { ValidationError, InvalidRequestError } from '../errors';
|
||||
import { exportCollections } from '../logistics';
|
||||
import { archiveCollection } from '../utils/zip';
|
||||
import { archiveCollection, archiveCollections } from '../utils/zip';
|
||||
import policy from '../policies';
|
||||
|
||||
const { authorize } = policy;
|
||||
@ -168,13 +168,12 @@ router.post('collections.export', auth(), async ctx => {
|
||||
});
|
||||
|
||||
router.post('collections.exportAll', auth(), async ctx => {
|
||||
const { download = false } = ctx.body;
|
||||
|
||||
const user = ctx.state.user;
|
||||
const team = await Team.findByPk(user.teamId);
|
||||
authorize(user, 'export', team);
|
||||
|
||||
// async operation to create zip archive and email user
|
||||
exportCollections(user.teamId, user.email);
|
||||
|
||||
await Event.create({
|
||||
name: 'collections.export',
|
||||
teamId: user.teamId,
|
||||
@ -182,9 +181,24 @@ router.post('collections.exportAll', auth(), async ctx => {
|
||||
ip: ctx.request.ip,
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
success: true,
|
||||
};
|
||||
if (download) {
|
||||
const collections = await Collection.findAll({
|
||||
where: { teamId: team.id },
|
||||
order: [['name', 'ASC']],
|
||||
});
|
||||
const filePath = await archiveCollections(collections);
|
||||
|
||||
ctx.attachment(`${team.name}.zip`);
|
||||
ctx.set('Content-Type', 'application/force-download');
|
||||
ctx.body = fs.createReadStream(filePath);
|
||||
} else {
|
||||
// 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 => {
|
||||
|
@ -120,6 +120,18 @@ describe('#collections.exportAll', async () => {
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
});
|
||||
|
||||
it('should allow downloading directly', async () => {
|
||||
const { admin } = await seed();
|
||||
const res = await server.post('/api/collections.exportAll', {
|
||||
body: { token: admin.getJwtToken(), download: true },
|
||||
});
|
||||
|
||||
expect(res.status).toEqual(200);
|
||||
expect(res.headers.get('content-type')).toEqual(
|
||||
'application/force-download'
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#collections.add_user', async () => {
|
||||
|
@ -3,7 +3,7 @@ import Queue from 'bull';
|
||||
import debug from 'debug';
|
||||
import mailer from './mailer';
|
||||
import { Collection, Team } from './models';
|
||||
import { archiveCollection, archiveCollections } from './utils/zip';
|
||||
import { archiveCollections } from './utils/zip';
|
||||
|
||||
const log = debug('logistics');
|
||||
const logisticsQueue = new Queue('logistics', process.env.REDIS_URL);
|
||||
@ -16,24 +16,6 @@ const queueOptions = {
|
||||
},
|
||||
};
|
||||
|
||||
async function exportAndEmailCollection(collectionId: string, email: string) {
|
||||
log('Archiving collection', collectionId);
|
||||
const collection = await Collection.findByPk(collectionId);
|
||||
const filePath = await archiveCollection(collection);
|
||||
|
||||
log('Archive path', filePath);
|
||||
|
||||
mailer.export({
|
||||
to: email,
|
||||
attachments: [
|
||||
{
|
||||
filename: `${collection.name} Export.zip`,
|
||||
path: filePath,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
async function exportAndEmailCollections(teamId: string, email: string) {
|
||||
log('Archiving team', teamId);
|
||||
const team = await Team.findByPk(teamId);
|
||||
@ -60,28 +42,12 @@ logisticsQueue.process(async job => {
|
||||
log('Process', job.data);
|
||||
|
||||
switch (job.data.type) {
|
||||
case 'export-collection':
|
||||
return await exportAndEmailCollection(
|
||||
job.data.collectionId,
|
||||
job.data.email
|
||||
);
|
||||
case 'export-collections':
|
||||
return await exportAndEmailCollections(job.data.teamId, job.data.email);
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export const exportCollection = (collectionId: string, email: string) => {
|
||||
logisticsQueue.add(
|
||||
{
|
||||
type: 'export-collection',
|
||||
collectionId,
|
||||
email,
|
||||
},
|
||||
queueOptions
|
||||
);
|
||||
};
|
||||
|
||||
export const exportCollections = (teamId: string, email: string) => {
|
||||
logisticsQueue.add(
|
||||
{
|
||||
|
@ -169,6 +169,21 @@ export default function Api() {
|
||||
</Arguments>
|
||||
</Method>
|
||||
|
||||
<Method method="collections.exportAll" label="Export all collections">
|
||||
<Description>
|
||||
Returns a zip file of all the collections or creates an async job
|
||||
to send a zip file via email to the authenticated user. If
|
||||
documents are nested then they will be nested in folders inside
|
||||
the zip file.
|
||||
</Description>
|
||||
<Arguments>
|
||||
<Argument
|
||||
id="download"
|
||||
description="Download as zip (default is email)"
|
||||
/>
|
||||
</Arguments>
|
||||
</Method>
|
||||
|
||||
<Method method="collections.update" label="Update a collection">
|
||||
<Description>
|
||||
This method allows you to modify an already created collection.
|
||||
|
Reference in New Issue
Block a user