feat: Backlinks (#979)

* feat: backlinks

* feat: add backlinkDocumentId to documents.list

* chore: refactor
fix: create and delete backlink handling

* fix: guard against self links

* feat: basic frontend
fix: race condition

* styling

* test: fix parse ids

* self review

* linting

* feat: Improved link styling

* fix: Increase clickable area at bottom of doc / between references

* perf: global styles are SLOW
This commit is contained in:
Tom Moor
2019-07-07 19:25:45 -07:00
committed by GitHub
parent 599e5c8f5d
commit 091e542406
23 changed files with 538 additions and 89 deletions

View File

@ -9,10 +9,19 @@ import {
presentCollection,
presentRevision,
} from '../presenters';
import { Document, Collection, Share, Star, View, Revision } from '../models';
import {
Document,
Collection,
Share,
Star,
View,
Revision,
Backlink,
} from '../models';
import { InvalidRequestError } from '../errors';
import events from '../events';
import policy from '../policies';
import { sequelize } from '../sequelize';
const Op = Sequelize.Op;
const { authorize, cannot } = policy;
@ -22,6 +31,7 @@ router.post('documents.list', auth(), pagination(), async ctx => {
const { sort = 'updatedAt' } = ctx.body;
const collectionId = ctx.body.collection;
const createdById = ctx.body.user;
const backlinkDocumentId = ctx.body.backlinkDocumentId;
let direction = ctx.body.direction;
if (direction !== 'ASC') direction = 'DESC';
@ -50,6 +60,20 @@ router.post('documents.list', auth(), pagination(), async ctx => {
where = { ...where, collectionId: collectionIds };
}
if (backlinkDocumentId) {
const backlinks = await Backlink.findAll({
attributes: ['reverseDocumentId'],
where: {
documentId: backlinkDocumentId,
},
});
where = {
...where,
id: backlinks.map(backlink => backlink.reverseDocumentId),
};
}
// add the users starred state to the response by default
const starredScope = { method: ['withStarred', user.id] };
const documents = await Document.scope('defaultScope', starredScope).findAll({
@ -620,7 +644,7 @@ router.post('documents.update', auth(), async ctx => {
// Update document
if (title) document.title = title;
//append to document
if (append) {
document.text += text;
} else if (text) {
@ -628,28 +652,40 @@ router.post('documents.update', auth(), async ctx => {
}
document.lastModifiedById = user.id;
if (publish) {
await document.publish();
let transaction;
try {
transaction = await sequelize.transaction();
events.add({
name: 'documents.publish',
modelId: document.id,
collectionId: document.collectionId,
teamId: document.teamId,
actorId: user.id,
});
} else {
await document.save({ autosave });
if (publish) {
await document.publish({ transaction });
await transaction.commit();
events.add({
name: 'documents.update',
modelId: document.id,
collectionId: document.collectionId,
teamId: document.teamId,
actorId: user.id,
autosave,
done,
});
events.add({
name: 'documents.publish',
modelId: document.id,
collectionId: document.collectionId,
teamId: document.teamId,
actorId: user.id,
});
} else {
await document.save({ autosave, transaction });
await transaction.commit();
events.add({
name: 'documents.update',
modelId: document.id,
collectionId: document.collectionId,
teamId: document.teamId,
actorId: user.id,
autosave,
done,
});
}
} catch (err) {
if (transaction) {
await transaction.rollback();
}
throw err;
}
ctx.body = {