Retrieve documents using shareId

This commit is contained in:
Tom Moor
2018-05-13 13:26:06 -07:00
parent 22bc5a7373
commit 500d039856
4 changed files with 100 additions and 56 deletions

View File

@ -14,6 +14,12 @@ export const DEFAULT_PAGINATION_LIMIT = 25;
type Options = { type Options = {
ui: UiStore, ui: UiStore,
errors: ErrorsStore,
};
type FetchOptions = {
prefetch?: boolean,
shareId?: string,
}; };
class DocumentsStore extends BaseStore { class DocumentsStore extends BaseStore {
@ -166,15 +172,20 @@ class DocumentsStore extends BaseStore {
@action @action
prefetchDocument = async (id: string) => { prefetchDocument = async (id: string) => {
if (!this.getById(id)) this.fetch(id, true); if (!this.getById(id)) {
this.fetch(id, { prefetch: true });
}
}; };
@action @action
fetch = async (id: string, prefetch?: boolean): Promise<*> => { fetch = async (id: string, options?: FetchOptions = {}): Promise<*> => {
if (!prefetch) this.isFetching = true; if (!options.prefetch) this.isFetching = true;
try { try {
const res = await client.post('/documents.info', { id }); const res = await client.post('/documents.info', {
id,
shareId: options.shareId,
});
invariant(res && res.data, 'Document not available'); invariant(res && res.data, 'Document not available');
const { data } = res; const { data } = res;
const document = new Document(data); const document = new Document(data);
@ -186,7 +197,7 @@ class DocumentsStore extends BaseStore {
return document; return document;
} catch (e) { } catch (e) {
this.errors.add('Failed to load documents'); this.errors.add('Failed to load document');
} finally { } finally {
this.isFetching = false; this.isFetching = false;
} }

View File

@ -4,7 +4,7 @@ import Sequelize from 'sequelize';
import auth from './middlewares/authentication'; import auth from './middlewares/authentication';
import pagination from './middlewares/pagination'; import pagination from './middlewares/pagination';
import { presentDocument, presentRevision } from '../presenters'; import { presentDocument, presentRevision } from '../presenters';
import { Document, Collection, Star, View, Revision } from '../models'; import { Document, Collection, Share, Star, View, Revision } from '../models';
import { InvalidRequestError } from '../errors'; import { InvalidRequestError } from '../errors';
import events from '../events'; import events from '../events';
import policy from '../policies'; import policy from '../policies';
@ -157,12 +157,26 @@ router.post('documents.drafts', auth(), pagination(), async ctx => {
}; };
}); });
router.post('documents.info', auth(), async ctx => { router.post('documents.info', auth({ required: false }), async ctx => {
const { id } = ctx.body; const { id, shareId } = ctx.body;
ctx.assertPresent(id, 'id is required'); ctx.assertPresent(id || shareId, 'id or shareId is required');
const document = await Document.findById(id);
let document;
if (shareId) {
const share = await Share.findById(shareId, {
include: [
{
model: Document,
required: true,
as: 'document',
},
],
});
document = share.document;
} else {
document = await Document.findById(id);
authorize(ctx.state.user, 'read', document); authorize(ctx.state.user, 'read', document);
}
ctx.body = { ctx.body = {
data: await presentDocument(ctx, document), data: await presentDocument(ctx, document),

View File

@ -3,7 +3,7 @@ import TestServer from 'fetch-test-server';
import app from '..'; import app from '..';
import { Document, View, Star, Revision } from '../models'; import { Document, View, Star, Revision } from '../models';
import { flushdb, seed } from '../test/support'; import { flushdb, seed } from '../test/support';
import { buildUser } from '../test/factories'; import { buildShare, buildUser } from '../test/factories';
const server = new TestServer(app.callback()); const server = new TestServer(app.callback());
@ -35,6 +35,22 @@ describe('#documents.info', async () => {
expect(res.status).toEqual(200); expect(res.status).toEqual(200);
expect(body.data.id).toEqual(document.id); expect(body.data.id).toEqual(document.id);
}); });
it('should return documents from shareId', async () => {
const { user, document } = await seed();
const share = await buildShare({
documentId: document.id,
teamId: document.teamId,
});
const res = await server.post('/api/documents.info', {
body: { token: user.getJwtToken(), shareId: share.id },
});
const body = await res.json();
expect(res.status).toEqual(200);
expect(body.data.id).toEqual(document.id);
});
}); });
describe('#documents.list', async () => { describe('#documents.list', async () => {

View File

@ -4,7 +4,7 @@ import { type Context } from 'koa';
import { User, ApiKey } from '../../models'; import { User, ApiKey } from '../../models';
import { AuthenticationError, UserSuspendedError } from '../../errors'; import { AuthenticationError, UserSuspendedError } from '../../errors';
export default function auth() { export default function auth(options?: { required?: boolean } = {}) {
return async function authMiddleware( return async function authMiddleware(
ctx: Context, ctx: Context,
next: () => Promise<void> next: () => Promise<void>
@ -33,10 +33,12 @@ export default function auth() {
token = ctx.request.query.token; token = ctx.request.query.token;
} }
if (!token) throw new AuthenticationError('Authentication required'); if (!token && options.required !== false) {
throw new AuthenticationError('Authentication required');
}
let user; let user;
if (token) {
if (String(token).match(/^[\w]{38}$/)) { if (String(token).match(/^[\w]{38}$/)) {
// API key // API key
let apiKey; let apiKey;
@ -84,6 +86,7 @@ export default function auth() {
ctx.state.user = user; ctx.state.user = user;
// $FlowFixMe // $FlowFixMe
ctx.cache[user.id] = user; ctx.cache[user.id] = user;
}
return next(); return next();
}; };