2005 lines
58 KiB
JavaScript
2005 lines
58 KiB
JavaScript
/* eslint-disable flowtype/require-valid-file-annotation */
|
|
import TestServer from "fetch-test-server";
|
|
import app from "../app";
|
|
import {
|
|
Document,
|
|
View,
|
|
Star,
|
|
Revision,
|
|
Backlink,
|
|
CollectionUser,
|
|
SearchQuery,
|
|
} from "../models";
|
|
import {
|
|
buildShare,
|
|
buildCollection,
|
|
buildUser,
|
|
buildDocument,
|
|
} from "../test/factories";
|
|
import { flushdb, seed } from "../test/support";
|
|
|
|
const server = new TestServer(app.callback());
|
|
|
|
beforeEach(() => flushdb());
|
|
afterAll(() => server.close());
|
|
|
|
describe("#documents.info", () => {
|
|
it("should return published document", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return archived document", async () => {
|
|
const { user, document } = await seed();
|
|
await document.archive(user.id);
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return published document in collection not a member of", async () => {
|
|
const user = await buildUser();
|
|
const collection = await buildCollection({
|
|
private: true,
|
|
teamId: user.teamId,
|
|
});
|
|
const document = await buildDocument({ collectionId: collection.id });
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should return drafts", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return document from shareId without token", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { shareId: share.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.id).toEqual(document.id);
|
|
expect(body.data.createdBy).toEqual(undefined);
|
|
expect(body.data.updatedBy).toEqual(undefined);
|
|
});
|
|
|
|
it("should not return document from revoked shareId", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
await share.revoke(user.id);
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { shareId: share.id },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should not return document from archived shareId", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { shareId: share.id },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should return document from shareId with token", async () => {
|
|
const { user, document } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
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);
|
|
expect(body.data.createdBy.id).toEqual(user.id);
|
|
expect(body.data.updatedBy.id).toEqual(user.id);
|
|
});
|
|
|
|
it("should return draft document from shareId with token", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
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);
|
|
expect(body.data.createdBy.id).toEqual(user.id);
|
|
expect(body.data.updatedBy.id).toEqual(user.id);
|
|
});
|
|
|
|
it("should return document from shareId in collection not a member of", async () => {
|
|
const { user, document, collection } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
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);
|
|
});
|
|
|
|
it("should not error if document doesn't exist", async () => {
|
|
const user = await buildUser();
|
|
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: "test" },
|
|
});
|
|
expect(res.status).toEqual(404);
|
|
});
|
|
|
|
it("should require authorization without token", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require authorization with incorrect token", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require a valid shareId", async () => {
|
|
const res = await server.post("/api/documents.info", {
|
|
body: { shareId: 123 },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
});
|
|
|
|
describe("#documents.export", () => {
|
|
it("should return published document", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should return archived document", async () => {
|
|
const { user, document } = await seed();
|
|
await document.archive(user.id);
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should not return published document in collection not a member of", async () => {
|
|
const user = await buildUser();
|
|
const collection = await buildCollection({
|
|
private: true,
|
|
teamId: user.teamId,
|
|
});
|
|
const document = await buildDocument({ collectionId: collection.id });
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should return drafts", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should return document from shareId without token", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { shareId: share.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should not return document from revoked shareId", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
await share.revoke(user.id);
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { shareId: share.id },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should not return document from archived shareId", async () => {
|
|
const { document, user } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { shareId: share.id },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should return document from shareId with token", async () => {
|
|
const { user, document } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), shareId: share.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should return draft document from shareId with token", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), shareId: share.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should return document from shareId in collection not a member of", async () => {
|
|
const { user, document, collection } = await seed();
|
|
const share = await buildShare({
|
|
documentId: document.id,
|
|
teamId: document.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), shareId: share.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data).toEqual(document.toMarkdown());
|
|
});
|
|
|
|
it("should require authorization without token", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require authorization with incorrect token", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require a valid shareId", async () => {
|
|
const res = await server.post("/api/documents.export", {
|
|
body: { shareId: 123 },
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
});
|
|
|
|
describe("#documents.list", () => {
|
|
it("should return documents", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return unpublished documents", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not return archived documents", async () => {
|
|
const { user, document } = await seed();
|
|
document.archivedAt = new Date();
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not return documents in private collections not a member of", async () => {
|
|
const { user, collection } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should allow changing sort direction", async () => {
|
|
const { user, document } = await seed();
|
|
const anotherDoc = await buildDocument({
|
|
title: "another document",
|
|
text: "random text",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken(), direction: "ASC" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
expect(body.data[1].id).toEqual(anotherDoc.id);
|
|
});
|
|
|
|
it("should allow filtering by collection", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.list", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collection: document.collectionId,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
});
|
|
|
|
it("should allow filtering to private collection", async () => {
|
|
const { user, collection } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
await CollectionUser.create({
|
|
createdById: user.id,
|
|
collectionId: collection.id,
|
|
userId: user.id,
|
|
permission: "read",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collection: collection.id,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
});
|
|
|
|
it("should return backlinks", async () => {
|
|
const { user, document } = await seed();
|
|
const anotherDoc = await buildDocument({
|
|
title: "another document",
|
|
text: "random text",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
await Backlink.create({
|
|
reverseDocumentId: anotherDoc.id,
|
|
documentId: document.id,
|
|
userId: user.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.list", {
|
|
body: { token: user.getJwtToken(), backlinkDocumentId: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(anotherDoc.id);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.list");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
describe("#documents.pinned", () => {
|
|
it("should return pinned documents", async () => {
|
|
const { user, document } = await seed();
|
|
document.pinnedById = user.id;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.pinned", {
|
|
body: { token: user.getJwtToken(), collectionId: document.collectionId },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return pinned documents in private collections member of", async () => {
|
|
const { user, collection, document } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
document.pinnedById = user.id;
|
|
await document.save();
|
|
|
|
await CollectionUser.create({
|
|
collectionId: collection.id,
|
|
userId: user.id,
|
|
createdById: user.id,
|
|
permission: "read_write",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.pinned", {
|
|
body: { token: user.getJwtToken(), collectionId: document.collectionId },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return pinned documents in private collections not a member of", async () => {
|
|
const collection = await buildCollection({
|
|
private: true,
|
|
});
|
|
|
|
const user = await buildUser({ teamId: collection.teamId });
|
|
|
|
const res = await server.post("/api/documents.pinned", {
|
|
body: { token: user.getJwtToken(), collectionId: collection.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.pinned");
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
});
|
|
|
|
describe("#documents.drafts", () => {
|
|
it("should return unpublished documents", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.drafts", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
});
|
|
|
|
it("should not return documents in private collections not a member of", async () => {
|
|
const { user, document, collection } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
const res = await server.post("/api/documents.drafts", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
});
|
|
|
|
describe("#documents.search_titles", () => {
|
|
it("should return case insensitive results for partial query", async () => {
|
|
const user = await buildUser();
|
|
const document = await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
title: "Super secret",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search_titles", {
|
|
body: { token: user.getJwtToken(), query: "SECRET" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not include archived or deleted documents", async () => {
|
|
const user = await buildUser();
|
|
await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
title: "Super secret",
|
|
archivedAt: new Date(),
|
|
});
|
|
|
|
await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
title: "Super secret",
|
|
deletedAt: new Date(),
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search_titles", {
|
|
body: { token: user.getJwtToken(), query: "SECRET" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.search_titles");
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
});
|
|
|
|
describe("#documents.search", () => {
|
|
it("should return results", async () => {
|
|
const { user } = await seed();
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "much" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.text).toEqual("# Much test support");
|
|
});
|
|
|
|
it("should return results in ranked order", async () => {
|
|
const { user } = await seed();
|
|
const firstResult = await buildDocument({
|
|
title: "search term",
|
|
text: "random text",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
const secondResult = await buildDocument({
|
|
title: "random text",
|
|
text: "search term",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "search term" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(2);
|
|
expect(body.data[0].document.id).toEqual(firstResult.id);
|
|
expect(body.data[1].document.id).toEqual(secondResult.id);
|
|
});
|
|
|
|
it("should return partial results in ranked order", async () => {
|
|
const { user } = await seed();
|
|
const firstResult = await buildDocument({
|
|
title: "search term",
|
|
text: "random text",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
const secondResult = await buildDocument({
|
|
title: "random text",
|
|
text: "search term",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "sear &" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(2);
|
|
expect(body.data[0].document.id).toEqual(firstResult.id);
|
|
expect(body.data[1].document.id).toEqual(secondResult.id);
|
|
});
|
|
|
|
it("should strip junk from search term", async () => {
|
|
const { user } = await seed();
|
|
const firstResult = await buildDocument({
|
|
title: "search term",
|
|
text: "this is some random text of the document body",
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "rando &\\;:()" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(firstResult.id);
|
|
});
|
|
|
|
it("should not return draft documents", async () => {
|
|
const { user } = await seed();
|
|
await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
publishedAt: null,
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should return draft documents created by user if chosen", async () => {
|
|
const { user } = await seed();
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
publishedAt: null,
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
includeDrafts: "true",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return draft documents created by other users", async () => {
|
|
const { user } = await seed();
|
|
await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
publishedAt: null,
|
|
teamId: user.teamId,
|
|
});
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
includeDrafts: "true",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not return archived documents", async () => {
|
|
const { user } = await seed();
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "search term" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should return archived documents if chosen", async () => {
|
|
const { user } = await seed();
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
includeArchived: "true",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return documents for a specific user", async () => {
|
|
const { user } = await seed();
|
|
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
userId: user.id,
|
|
});
|
|
|
|
// This one will be filtered out
|
|
await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
userId: user.id,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return documents for a specific private collection", async () => {
|
|
const { user, collection } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
await CollectionUser.create({
|
|
createdById: user.id,
|
|
collectionId: collection.id,
|
|
userId: user.id,
|
|
permission: "read",
|
|
});
|
|
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
collectionId: collection.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should return documents for a specific collection", async () => {
|
|
const { user } = await seed();
|
|
const collection = await buildCollection();
|
|
|
|
const document = await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
// This one will be filtered out
|
|
await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
teamId: user.teamId,
|
|
collectionId: collection.id,
|
|
});
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
collectionId: document.collectionId,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].document.id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return documents in private collections not a member of", async () => {
|
|
const { user } = await seed();
|
|
const collection = await buildCollection({ private: true });
|
|
|
|
await buildDocument({
|
|
title: "search term",
|
|
text: "search term",
|
|
publishedAt: null,
|
|
teamId: user.teamId,
|
|
collectionId: collection.id,
|
|
});
|
|
const res = await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "search term" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not allow unknown dateFilter values", async () => {
|
|
const { user } = await seed();
|
|
|
|
const res = await server.post("/api/documents.search", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
query: "search term",
|
|
dateFilter: "DROP TABLE students;",
|
|
},
|
|
});
|
|
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.search");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should save search term, hits and source", async (done) => {
|
|
const { user } = await seed();
|
|
await server.post("/api/documents.search", {
|
|
body: { token: user.getJwtToken(), query: "my term" },
|
|
});
|
|
|
|
// setTimeout is needed here because SearchQuery is saved asynchronously
|
|
// in order to not slow down the response time.
|
|
setTimeout(async () => {
|
|
const searchQuery = await SearchQuery.findAll({
|
|
where: { query: "my term" },
|
|
});
|
|
expect(searchQuery.length).toBe(1);
|
|
expect(searchQuery[0].results).toBe(0);
|
|
expect(searchQuery[0].source).toBe("app");
|
|
done();
|
|
}, 100);
|
|
});
|
|
});
|
|
|
|
describe("#documents.archived", () => {
|
|
it("should return archived documents", async () => {
|
|
const { user } = await seed();
|
|
const document = await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.archived", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
});
|
|
|
|
it("should not return deleted documents", async () => {
|
|
const { user } = await seed();
|
|
const document = await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
await document.delete();
|
|
|
|
const res = await server.post("/api/documents.archived", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not return documents in private collections not a member of", async () => {
|
|
const { user } = await seed();
|
|
const collection = await buildCollection({ private: true });
|
|
|
|
const document = await buildDocument({
|
|
teamId: user.teamId,
|
|
collectionId: collection.id,
|
|
});
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.archived", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.archived");
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
});
|
|
|
|
describe("#documents.viewed", () => {
|
|
it("should return empty result if no views", async () => {
|
|
const { user } = await seed();
|
|
const res = await server.post("/api/documents.viewed", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should return recently viewed documents", async () => {
|
|
const { user, document } = await seed();
|
|
await View.increment({ documentId: document.id, userId: user.id });
|
|
|
|
const res = await server.post("/api/documents.viewed", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
});
|
|
|
|
it("should not return recently viewed but deleted documents", async () => {
|
|
const { user, document } = await seed();
|
|
await View.increment({ documentId: document.id, userId: user.id });
|
|
await document.destroy();
|
|
|
|
const res = await server.post("/api/documents.viewed", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should not return recently viewed documents in collection not a member of", async () => {
|
|
const { user, document, collection } = await seed();
|
|
await View.increment({ documentId: document.id, userId: user.id });
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
const res = await server.post("/api/documents.viewed", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.viewed");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
describe("#documents.starred", () => {
|
|
it("should return empty result if no stars", async () => {
|
|
const { user } = await seed();
|
|
const res = await server.post("/api/documents.starred", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(0);
|
|
});
|
|
|
|
it("should return starred documents", async () => {
|
|
const { user, document } = await seed();
|
|
await Star.create({ documentId: document.id, userId: user.id });
|
|
|
|
const res = await server.post("/api/documents.starred", {
|
|
body: { token: user.getJwtToken() },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.length).toEqual(1);
|
|
expect(body.data[0].id).toEqual(document.id);
|
|
expect(body.policies[0].abilities.update).toEqual(true);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.starred");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
describe("#documents.pin", () => {
|
|
it("should pin the document", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.pin", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.pinned).toEqual(true);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.pin");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.pin", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.move", () => {
|
|
it("should move the document", async () => {
|
|
const { user, document } = await seed();
|
|
const collection = await buildCollection({ teamId: user.teamId });
|
|
|
|
const res = await server.post("/api/documents.move", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.documents[0].collectionId).toEqual(collection.id);
|
|
});
|
|
|
|
it("should not allow moving the document to a collection the user cannot access", async () => {
|
|
const { user, document } = await seed();
|
|
const collection = await buildCollection();
|
|
|
|
const res = await server.post("/api/documents.move", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.move");
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document, collection } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.move", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.restore", () => {
|
|
it("should allow restore of trashed documents", async () => {
|
|
const { user, document } = await seed();
|
|
await document.destroy(user.id);
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.deletedAt).toEqual(null);
|
|
});
|
|
|
|
it("should allow restore of trashed documents with collectionId", async () => {
|
|
const { user, document } = await seed();
|
|
const collection = await buildCollection({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
});
|
|
|
|
await document.destroy(user.id);
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.deletedAt).toEqual(null);
|
|
expect(body.data.collectionId).toEqual(collection.id);
|
|
});
|
|
|
|
it("should now allow restore of trashed documents to collection user cannot access", async () => {
|
|
const { user, document } = await seed();
|
|
const collection = await buildCollection();
|
|
|
|
await document.destroy(user.id);
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
collectionId: collection.id,
|
|
},
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should allow restore of archived documents", async () => {
|
|
const { user, document } = await seed();
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.archivedAt).toEqual(null);
|
|
});
|
|
|
|
it("should restore archived when previous parent is archived", async () => {
|
|
const { user, document } = await seed();
|
|
const childDocument = await buildDocument({
|
|
userId: user.id,
|
|
teamId: user.teamId,
|
|
collectionId: document.collectionId,
|
|
parentDocumentId: document.id,
|
|
});
|
|
await childDocument.archive(user.id);
|
|
await document.archive(user.id);
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: childDocument.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.parentDocumentId).toEqual(undefined);
|
|
expect(body.data.archivedAt).toEqual(null);
|
|
});
|
|
|
|
it("should restore the document to a previous version", async () => {
|
|
const { user, document } = await seed();
|
|
const revision = await Revision.findOne({
|
|
where: { documentId: document.id },
|
|
});
|
|
const previousText = revision.text;
|
|
const revisionId = revision.id;
|
|
|
|
// update the document contents
|
|
document.text = "UPDATED";
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: document.id, revisionId },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.text).toEqual(previousText);
|
|
});
|
|
|
|
it("should not allow restoring a revision in another document", async () => {
|
|
const { user, document } = await seed();
|
|
const anotherDoc = await buildDocument();
|
|
const revision = await Revision.findOne({
|
|
where: { documentId: anotherDoc.id },
|
|
});
|
|
const revisionId = revision.id;
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: document.id, revisionId },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should not error if document doesn't exist", async () => {
|
|
const user = await buildUser();
|
|
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: "test" },
|
|
});
|
|
expect(res.status).toEqual(404);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.restore");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const revision = await Revision.findOne({
|
|
where: { documentId: document.id },
|
|
});
|
|
const revisionId = revision.id;
|
|
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.restore", {
|
|
body: { token: user.getJwtToken(), id: document.id, revisionId },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.unpin", () => {
|
|
it("should unpin the document", async () => {
|
|
const { user, document } = await seed();
|
|
document.pinnedBy = user;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.unpin", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.pinned).toEqual(false);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.unpin");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.unpin", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.star", () => {
|
|
it("should star the document", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.star", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
const stars = await Star.findAll();
|
|
expect(res.status).toEqual(200);
|
|
expect(stars.length).toEqual(1);
|
|
expect(stars[0].documentId).toEqual(document.id);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.star");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.star", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.unstar", () => {
|
|
it("should unstar the document", async () => {
|
|
const { user, document } = await seed();
|
|
await Star.create({ documentId: document.id, userId: user.id });
|
|
|
|
const res = await server.post("/api/documents.unstar", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
const stars = await Star.findAll();
|
|
expect(res.status).toEqual(200);
|
|
expect(stars.length).toEqual(0);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const res = await server.post("/api/documents.star");
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.unstar", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.create", () => {
|
|
it("should create as a new document", async () => {
|
|
const { user, collection } = await seed();
|
|
const res = await server.post("/api/documents.create", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collectionId: collection.id,
|
|
title: "new document",
|
|
text: "hello",
|
|
publish: true,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
const newDocument = await Document.findByPk(body.data.id);
|
|
expect(res.status).toEqual(200);
|
|
expect(newDocument.parentDocumentId).toBe(null);
|
|
expect(newDocument.collectionId).toBe(collection.id);
|
|
});
|
|
|
|
it("should not allow very long titles", async () => {
|
|
const { user, collection } = await seed();
|
|
const res = await server.post("/api/documents.create", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collectionId: collection.id,
|
|
title:
|
|
"This is a really long title that is not acceptable to Outline because it is so ridiculously long that we need to have a limit somewhere",
|
|
text: " ",
|
|
},
|
|
});
|
|
expect(res.status).toEqual(400);
|
|
});
|
|
|
|
it("should create as a child and add to collection if published", async () => {
|
|
const { user, document, collection } = await seed();
|
|
const res = await server.post("/api/documents.create", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collectionId: collection.id,
|
|
parentDocumentId: document.id,
|
|
title: "new document",
|
|
text: "hello",
|
|
publish: true,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.title).toBe("new document");
|
|
});
|
|
|
|
it("should error with invalid parentDocument", async () => {
|
|
const { user, collection } = await seed();
|
|
const res = await server.post("/api/documents.create", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collectionId: collection.id,
|
|
parentDocumentId: "d7a4eb73-fac1-4028-af45-d7e34d54db8e",
|
|
title: "new document",
|
|
text: "hello",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(403);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should create as a child and not add to collection", async () => {
|
|
const { user, document, collection } = await seed();
|
|
const res = await server.post("/api/documents.create", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
collectionId: collection.id,
|
|
parentDocumentId: document.id,
|
|
title: "new document",
|
|
text: "hello",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.title).toBe("new document");
|
|
});
|
|
});
|
|
|
|
describe("#documents.update", () => {
|
|
it("should update document details in the root", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
title: "Updated title",
|
|
text: "Updated text",
|
|
lastRevision: document.revision,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.title).toBe("Updated title");
|
|
expect(body.data.text).toBe("Updated text");
|
|
});
|
|
|
|
it("should allow publishing document in private collection", async () => {
|
|
const { user, collection, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
await CollectionUser.create({
|
|
createdById: user.id,
|
|
collectionId: collection.id,
|
|
userId: user.id,
|
|
permission: "read_write",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
title: "Updated title",
|
|
text: "Updated text",
|
|
lastRevision: document.revision,
|
|
publish: true,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.publishedAt).toBeTruthy();
|
|
expect(body.policies[0].abilities.update).toEqual(true);
|
|
});
|
|
|
|
it("should not edit archived document", async () => {
|
|
const { user, document } = await seed();
|
|
await document.archive();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
title: "Updated title",
|
|
text: "Updated text",
|
|
lastRevision: document.revision,
|
|
},
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should not create new version when autosave=true", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
title: "Updated title",
|
|
text: "Updated text",
|
|
lastRevision: document.revision,
|
|
autosave: true,
|
|
},
|
|
});
|
|
|
|
const prevRevisionRecords = await Revision.count();
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.title).toBe("Updated title");
|
|
expect(body.data.text).toBe("Updated text");
|
|
|
|
const revisionRecords = await Revision.count();
|
|
expect(revisionRecords).toBe(prevRevisionRecords);
|
|
});
|
|
|
|
it("should fail if document lastRevision does not match", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
text: "Updated text",
|
|
lastRevision: 123,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(400);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should update document details for children", async () => {
|
|
const { user, document, collection } = await seed();
|
|
collection.documentStructure = [
|
|
{
|
|
id: "af1da94b-9591-4bab-897c-11774b804b77",
|
|
url: "/d/some-beef-RSZwQDsfpc",
|
|
title: "some beef",
|
|
children: [
|
|
{
|
|
id: "ab1da94b-9591-4bab-897c-11774b804b66",
|
|
url: "/d/another-doc-RSZwQDsfpc",
|
|
title: "Another doc",
|
|
children: [],
|
|
},
|
|
{ ...document.toJSON(), children: [] },
|
|
],
|
|
},
|
|
];
|
|
await collection.save();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
title: "Updated title",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.title).toBe("Updated title");
|
|
});
|
|
|
|
it("allows editing by read-write collection user", async () => {
|
|
const { admin, document, collection } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
await CollectionUser.create({
|
|
collectionId: collection.id,
|
|
userId: admin.id,
|
|
createdById: admin.id,
|
|
permission: "read_write",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: admin.getJwtToken(),
|
|
id: document.id,
|
|
text: "Changed text",
|
|
lastRevision: document.revision,
|
|
},
|
|
});
|
|
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.text).toBe("Changed text");
|
|
expect(body.data.updatedBy.id).toBe(admin.id);
|
|
});
|
|
|
|
it("does not allow editing by read-only collection user", async () => {
|
|
const { user, document, collection } = await seed();
|
|
collection.private = true;
|
|
await collection.save();
|
|
|
|
await CollectionUser.create({
|
|
collectionId: collection.id,
|
|
userId: user.id,
|
|
createdById: user.id,
|
|
permission: "read",
|
|
});
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
text: "Changed text",
|
|
lastRevision: document.revision,
|
|
},
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should append document with text", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
text: "Additional text",
|
|
lastRevision: document.revision,
|
|
append: true,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.text).toBe(document.text + "Additional text");
|
|
expect(body.data.updatedBy.id).toBe(user.id);
|
|
});
|
|
|
|
it("should require text while appending", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
lastRevision: document.revision,
|
|
title: "Updated Title",
|
|
append: true,
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(400);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should allow setting empty text", async () => {
|
|
const { user, document } = await seed();
|
|
|
|
const res = await server.post("/api/documents.update", {
|
|
body: {
|
|
token: user.getJwtToken(),
|
|
id: document.id,
|
|
lastRevision: document.revision,
|
|
title: "Updated Title",
|
|
text: "",
|
|
},
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.text).toBe("");
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.update", {
|
|
body: { id: document.id, text: "Updated" },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
|
|
it("should require authorization", async () => {
|
|
const { document } = await seed();
|
|
const user = await buildUser();
|
|
const res = await server.post("/api/documents.update", {
|
|
body: { token: user.getJwtToken(), id: document.id, text: "Updated" },
|
|
});
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
});
|
|
|
|
describe("#documents.archive", () => {
|
|
it("should allow archiving document", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.archive", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.updatedBy.id).toEqual(user.id);
|
|
expect(body.data.archivedAt).toBeTruthy();
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.archive", {
|
|
body: { id: document.id },
|
|
});
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
});
|
|
|
|
describe("#documents.delete", () => {
|
|
it("should allow deleting document", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.delete", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.success).toEqual(true);
|
|
});
|
|
|
|
it("should allow deleting document without collection", async () => {
|
|
const { user, document, collection } = await seed();
|
|
|
|
// delete collection without hooks to trigger document deletion
|
|
await collection.destroy({ hooks: false });
|
|
const res = await server.post("/api/documents.delete", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.success).toEqual(true);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.delete", {
|
|
body: { id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(401);
|
|
expect(body).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
describe("#documents.unpublish", () => {
|
|
it("should unpublish a document", async () => {
|
|
const { user, document } = await seed();
|
|
const res = await server.post("/api/documents.unpublish", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
const body = await res.json();
|
|
|
|
expect(res.status).toEqual(200);
|
|
expect(body.data.id).toEqual(document.id);
|
|
expect(body.data.publishedAt).toBeNull();
|
|
});
|
|
|
|
it("should fail to unpublish a draft document", async () => {
|
|
const { user, document } = await seed();
|
|
document.publishedAt = null;
|
|
await document.save();
|
|
|
|
const res = await server.post("/api/documents.unpublish", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should fail to unpublish a deleted document", async () => {
|
|
const { user, document } = await seed();
|
|
await document.delete();
|
|
|
|
const res = await server.post("/api/documents.unpublish", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should fail to unpublish a archived document", async () => {
|
|
const { user, document } = await seed();
|
|
await document.archive();
|
|
|
|
const res = await server.post("/api/documents.unpublish", {
|
|
body: { token: user.getJwtToken(), id: document.id },
|
|
});
|
|
|
|
expect(res.status).toEqual(403);
|
|
});
|
|
|
|
it("should require authentication", async () => {
|
|
const { document } = await seed();
|
|
const res = await server.post("/api/documents.unpublish", {
|
|
body: { id: document.id },
|
|
});
|
|
expect(res.status).toEqual(401);
|
|
});
|
|
});
|