diff --git a/package.json b/package.json index c52f9fb8..68b6e98f 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,8 @@ "react-keydown": "^1.6.1", "react-router": "2.5.1", "rebass": "0.2.6", + "redis": "^2.6.2", + "redis-lock": "^0.1.0", "reflexbox": "^2.0.0", "safestart": "0.8.0", "sass-loader": "4.0.0", @@ -109,6 +111,7 @@ "sequelize-cli": "2.4.0", "sequelize-encrypted": "0.1.0", "slug": "0.9.1", + "string-hash": "^1.1.0", "style-loader": "0.13.0", "truncate-html": "0.0.6", "url-loader": "0.5.7", diff --git a/server/api/documents.js b/server/api/documents.js index b3ed3c0e..ab4271ac 100644 --- a/server/api/documents.js +++ b/server/api/documents.js @@ -3,6 +3,7 @@ import httpErrors from 'http-errors'; import { sequelize, } from '../sequelize'; +import { lock } from '../redis'; const URL_REGEX = /^[a-zA-Z0-9-]*-([a-zA-Z0-9]{10,15})$/; @@ -109,7 +110,7 @@ router.post('documents.search', auth(), async (ctx) => { }); -router.post('documents.create', auth(), async (ctx) => { +router.post('documents.create', auth(), async (ctx, done) => { const { collection, title, @@ -130,39 +131,49 @@ router.post('documents.create', auth(), async (ctx) => { if (!ownerCollection) throw httpErrors.BadRequest(); - let parentDocumentObj = {}; - if (parentDocument && ownerCollection.type === 'atlas') { - parentDocumentObj = await Document.findOne({ - where: { - id: parentDocument, + await lock(ownerCollection.id, 10000, async (done) => { + return new Promise(async resolve => { + console.info(`Execute: ${title}`) + let parentDocumentObj = {}; + if (parentDocument && ownerCollection.type === 'atlas') { + parentDocumentObj = await Document.findOne({ + where: { + id: parentDocument, + atlasId: ownerCollection.id, + }, + }); + } + + const document = await Document.create({ + parentDocumentId: parentDocumentObj.id, atlasId: ownerCollection.id, - }, + teamId: user.teamId, + userId: user.id, + lastModifiedById: user.id, + createdById: user.id, + title, + text, + }); + + // TODO: Move to afterSave hook if possible with imports + if (parentDocument && ownerCollection.type === 'atlas') { + await ownerCollection.reload(); + ownerCollection.addNodeToNavigationTree(document); + await ownerCollection.save(); + } + + console.info(`Finish: ${title}`) + + ctx.body = { + data: await presentDocument(ctx, document, { + includeCollection: true, + includeCollaborators: true, + }), + }; + + done(resolve); }); - } - - const document = await Document.create({ - parentDocumentId: parentDocumentObj.id, - atlasId: ownerCollection.id, - teamId: user.teamId, - userId: user.id, - lastModifiedById: user.id, - createdById: user.id, - title, - text, }); - - // TODO: Move to afterSave hook if possible with imports - if (parentDocument && ownerCollection.type === 'atlas') { - ownerCollection.addNodeToNavigationTree(document); - await ownerCollection.save(); - } - - ctx.body = { - data: await presentDocument(ctx, document, { - includeCollection: true, - includeCollaborators: true, - }), - }; }); router.post('documents.update', auth(), async (ctx) => { diff --git a/server/models/Atlas.js b/server/models/Atlas.js index b8ca7029..6d13330d 100644 --- a/server/models/Atlas.js +++ b/server/models/Atlas.js @@ -142,7 +142,7 @@ const Atlas = sequelize.define('atlas', { return newTree; }, - addNodeToNavigationTree(document) { + async addNodeToNavigationTree(document) { const newNode = { id: document.id, title: document.title, diff --git a/server/redis.js b/server/redis.js new file mode 100644 index 00000000..fcbabbcd --- /dev/null +++ b/server/redis.js @@ -0,0 +1,10 @@ +import redis from 'redis'; +import redisLock from 'redis-lock'; + +const client = redis.createClient(process.env.REDIS_URL); +const lock = redisLock(client); + +export { + client, + lock, +};