Update to move authorship calculation code to note model and support update authorship after making revision of docs
This commit is contained in:
		
							parent
							
								
									a5e6b5dd3b
								
							
						
					
					
						commit
						d23ced1fba
					
				| @ -11,11 +11,16 @@ var shortId = require('shortid'); | |||||||
| var Sequelize = require("sequelize"); | var Sequelize = require("sequelize"); | ||||||
| var async = require('async'); | var async = require('async'); | ||||||
| var moment = require('moment'); | var moment = require('moment'); | ||||||
|  | var DiffMatchPatch = require('diff-match-patch'); | ||||||
|  | var dmp = new DiffMatchPatch(); | ||||||
| 
 | 
 | ||||||
| // core
 | // core
 | ||||||
| var config = require("../config.js"); | var config = require("../config.js"); | ||||||
| var logger = require("../logger.js"); | var logger = require("../logger.js"); | ||||||
| 
 | 
 | ||||||
|  | //ot
 | ||||||
|  | var ot = require("../ot/index.js"); | ||||||
|  | 
 | ||||||
| // permission types
 | // permission types
 | ||||||
| var permissionTypes = ["freely", "editable", "locked", "private"]; | var permissionTypes = ["freely", "editable", "locked", "private"]; | ||||||
| 
 | 
 | ||||||
| @ -115,6 +120,7 @@ module.exports = function (sequelize, DataTypes) { | |||||||
|                                     var fsModifiedTime = moment(fs.statSync(filePath).mtime); |                                     var fsModifiedTime = moment(fs.statSync(filePath).mtime); | ||||||
|                                     var dbModifiedTime = moment(note.lastchangeAt || note.createdAt); |                                     var dbModifiedTime = moment(note.lastchangeAt || note.createdAt); | ||||||
|                                     var body = fs.readFileSync(filePath, 'utf8'); |                                     var body = fs.readFileSync(filePath, 'utf8'); | ||||||
|  |                                     var contentLength = body.length; | ||||||
|                                     var title = Note.parseNoteTitle(body); |                                     var title = Note.parseNoteTitle(body); | ||||||
|                                     body = LZString.compressToBase64(body); |                                     body = LZString.compressToBase64(body); | ||||||
|                                     title = LZString.compressToBase64(title); |                                     title = LZString.compressToBase64(title); | ||||||
| @ -126,7 +132,20 @@ module.exports = function (sequelize, DataTypes) { | |||||||
|                                         }).then(function (note) { |                                         }).then(function (note) { | ||||||
|                                             sequelize.models.Revision.saveNoteRevision(note, function (err, revision) { |                                             sequelize.models.Revision.saveNoteRevision(note, function (err, revision) { | ||||||
|                                                 if (err) return _callback(err, null); |                                                 if (err) return _callback(err, null); | ||||||
|                                                 return callback(null, note.id); |                                                 // update authorship on after making revision of docs
 | ||||||
|  |                                                 var patch = dmp.patch_fromText(LZString.decompressFromBase64(revision.patch)); | ||||||
|  |                                                 var operations = Note.transformPatchToOperations(patch, contentLength); | ||||||
|  |                                                 var authorship = note.authorship ? JSON.parse(LZString.decompressFromBase64(note.authorship)) : []; | ||||||
|  |                                                 for (var i = 0; i < operations.length; i++) { | ||||||
|  |                                                     authorship = Note.updateAuthorshipByOperation(operations[i], null, authorship); | ||||||
|  |                                                 } | ||||||
|  |                                                 note.update({ | ||||||
|  |                                                     authorship: authorship | ||||||
|  |                                                 }).then(function (note) { | ||||||
|  |                                                     return callback(null, note.id); | ||||||
|  |                                                 }).catch(function (err) { | ||||||
|  |                                                     return _callback(err, null); | ||||||
|  |                                                 }); | ||||||
|                                             }); |                                             }); | ||||||
|                                         }).catch(function (err) { |                                         }).catch(function (err) { | ||||||
|                                             return _callback(err, null); |                                             return _callback(err, null); | ||||||
| @ -247,6 +266,162 @@ module.exports = function (sequelize, DataTypes) { | |||||||
|                         _meta.slideOptions = meta.slideOptions; |                         _meta.slideOptions = meta.slideOptions; | ||||||
|                 } |                 } | ||||||
|                 return _meta;  |                 return _meta;  | ||||||
|  |             }, | ||||||
|  |             updateAuthorshipByOperation: function (operation, userId, authorships) { | ||||||
|  |                 var index = 0; | ||||||
|  |                 var timestamp = Date.now(); | ||||||
|  |                 for (var i = 0; i < operation.length; i++) { | ||||||
|  |                     var op = operation[i]; | ||||||
|  |                     if (ot.TextOperation.isRetain(op)) { | ||||||
|  |                         index += op; | ||||||
|  |                     } else if (ot.TextOperation.isInsert(op)) { | ||||||
|  |                         var opStart = index; | ||||||
|  |                         var opEnd = index + op.length; | ||||||
|  |                         var inserted = false; | ||||||
|  |                         // authorship format: [userId, startPos, endPos, createdAt, updatedAt]
 | ||||||
|  |                         if (authorships.length <= 0) authorships.push([userId, opStart, opEnd, timestamp, timestamp]); | ||||||
|  |                         else { | ||||||
|  |                             for (var j = 0; j < authorships.length; j++) { | ||||||
|  |                                 var authorship = authorships[j]; | ||||||
|  |                                 if (!inserted) { | ||||||
|  |                                     var nextAuthorship = authorships[j + 1] || -1; | ||||||
|  |                                     if (nextAuthorship != -1 && nextAuthorship[1] >= opEnd || j >= authorships.length - 1) { | ||||||
|  |                                         if (authorship[1] < opStart && authorship[2] > opStart) { | ||||||
|  |                                             // divide
 | ||||||
|  |                                             var postLength = authorship[2] - opStart; | ||||||
|  |                                             authorship[2] = opStart; | ||||||
|  |                                             authorship[4] = timestamp; | ||||||
|  |                                             authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]); | ||||||
|  |                                             authorships.splice(j + 2, 0, [authorship[0], opEnd, opEnd + postLength, authorship[3], timestamp]); | ||||||
|  |                                             j += 2; | ||||||
|  |                                             inserted = true; | ||||||
|  |                                         } else if (authorship[1] >= opStart) { | ||||||
|  |                                             authorships.splice(j, 0, [userId, opStart, opEnd, timestamp, timestamp]); | ||||||
|  |                                             j += 1; | ||||||
|  |                                             inserted = true; | ||||||
|  |                                         } else if (authorship[2] <= opStart) { | ||||||
|  |                                             authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]); | ||||||
|  |                                             j += 1; | ||||||
|  |                                             inserted = true; | ||||||
|  |                                         } | ||||||
|  |                                     } | ||||||
|  |                                 } | ||||||
|  |                                 if (authorship[1] >= opStart) { | ||||||
|  |                                     authorship[1] += op.length; | ||||||
|  |                                     authorship[2] += op.length; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         index += op.length; | ||||||
|  |                     } else if (ot.TextOperation.isDelete(op)) { | ||||||
|  |                         var opStart = index; | ||||||
|  |                         var opEnd = index - op; | ||||||
|  |                         if (operation.length == 1) { | ||||||
|  |                             authorships = []; | ||||||
|  |                         } else if (authorships.length > 0) { | ||||||
|  |                             for (var j = 0; j < authorships.length; j++) { | ||||||
|  |                                 var authorship = authorships[j]; | ||||||
|  |                                 if (authorship[1] >= opStart && authorship[1] <= opEnd && authorship[2] >= opStart && authorship[2] <= opEnd) { | ||||||
|  |                                     authorships.splice(j, 1); | ||||||
|  |                                     j -= 1; | ||||||
|  |                                 } else if (authorship[1] < opStart && authorship[1] < opEnd && authorship[2] > opStart && authorship[2] > opEnd) { | ||||||
|  |                                     authorship[2] += op; | ||||||
|  |                                     authorship[4] = timestamp; | ||||||
|  |                                 } else if (authorship[2] >= opStart && authorship[2] <= opEnd) { | ||||||
|  |                                     authorship[2] = opStart; | ||||||
|  |                                     authorship[4] = timestamp; | ||||||
|  |                                 } else if (authorship[1] >= opStart && authorship[1] <= opEnd) { | ||||||
|  |                                     authorship[1] = opEnd; | ||||||
|  |                                     authorship[4] = timestamp; | ||||||
|  |                                 } | ||||||
|  |                                 if (authorship[1] >= opEnd) { | ||||||
|  |                                     authorship[1] += op; | ||||||
|  |                                     authorship[2] += op; | ||||||
|  |                                 } | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         index += op; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 // merge
 | ||||||
|  |                 for (var j = 0; j < authorships.length; j++) { | ||||||
|  |                     var authorship = authorships[j]; | ||||||
|  |                     for (var k = j + 1; k < authorships.length; k++) { | ||||||
|  |                         var nextAuthorship = authorships[k]; | ||||||
|  |                         if (nextAuthorship && authorship[0] === nextAuthorship[0] && authorship[2] === nextAuthorship[1]) { | ||||||
|  |                             var minTimestamp = Math.min(authorship[3], nextAuthorship[3]); | ||||||
|  |                             var maxTimestamp = Math.max(authorship[3], nextAuthorship[3]); | ||||||
|  |                             authorships.splice(j, 1, [authorship[0], authorship[1], nextAuthorship[2], minTimestamp, maxTimestamp]); | ||||||
|  |                             authorships.splice(k, 1); | ||||||
|  |                             j -= 1; | ||||||
|  |                             break; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 // clear
 | ||||||
|  |                 for (var j = 0; j < authorships.length; j++) { | ||||||
|  |                     var authorship = authorships[j]; | ||||||
|  |                     if (!authorship[0]) { | ||||||
|  |                         authorships.splice(j, 1); | ||||||
|  |                         j -= 1; | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return authorships; | ||||||
|  |             }, | ||||||
|  |             transformPatchToOperations: function (patch, contentLength) { | ||||||
|  |                 var operations = []; | ||||||
|  |                 if (patch.length > 0) { | ||||||
|  |                     // calculate original content length
 | ||||||
|  |                     for (var j = patch.length - 1; j >= 0; j--) { | ||||||
|  |                         var p = patch[j]; | ||||||
|  |                         for (var i = 0; i < p.diffs.length; i++) { | ||||||
|  |                             var diff = p.diffs[i]; | ||||||
|  |                             switch(diff[0]) { | ||||||
|  |                                 case 1: // insert
 | ||||||
|  |                                     contentLength -= diff[1].length; | ||||||
|  |                                 break; | ||||||
|  |                                 case -1: // delete
 | ||||||
|  |                                     contentLength += diff[1].length; | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     // generate operations
 | ||||||
|  |                     var bias = 0; | ||||||
|  |                     var lengthBias = 0; | ||||||
|  |                     for (var j = 0; j < patch.length; j++) { | ||||||
|  |                         var operation = []; | ||||||
|  |                         var p = patch[j]; | ||||||
|  |                         var currIndex = p.start1; | ||||||
|  |                         var currLength = contentLength - bias; | ||||||
|  |                         for (var i = 0; i < p.diffs.length; i++) { | ||||||
|  |                             var diff = p.diffs[i]; | ||||||
|  |                             switch(diff[0]) { | ||||||
|  |                                 case 0: // retain
 | ||||||
|  |                                     if (i == 0) // first
 | ||||||
|  |                                         operation.push(currIndex + diff[1].length); | ||||||
|  |                                     else if (i != p.diffs.length - 1) // mid
 | ||||||
|  |                                         operation.push(diff[1].length); | ||||||
|  |                                     else // last
 | ||||||
|  |                                         operation.push(currLength + lengthBias - currIndex); | ||||||
|  |                                     currIndex += diff[1].length; | ||||||
|  |                                 break; | ||||||
|  |                                 case 1: // insert
 | ||||||
|  |                                     operation.push(diff[1]); | ||||||
|  |                                     lengthBias += diff[1].length; | ||||||
|  |                                     currIndex += diff[1].length; | ||||||
|  |                                 break; | ||||||
|  |                                 case -1: // delete
 | ||||||
|  |                                     operation.push(-diff[1].length); | ||||||
|  |                                     bias += diff[1].length; | ||||||
|  |                                     currIndex += diff[1].length; | ||||||
|  |                                 break; | ||||||
|  |                             } | ||||||
|  |                         } | ||||||
|  |                         operations.push(operation); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |                 return operations; | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|         hooks: { |         hooks: { | ||||||
|  | |||||||
							
								
								
									
										101
									
								
								lib/realtime.js
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								lib/realtime.js
									
									
									
									
									
								
							| @ -642,106 +642,7 @@ function operationCallback(socket, operation) { | |||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     // save authorship
 |     // save authorship
 | ||||||
|     var index = 0; |     note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.authorship); | ||||||
|     var authorships = note.authorship; |  | ||||||
|     var timestamp = Date.now(); |  | ||||||
|     for (var i = 0; i < operation.length; i++) { |  | ||||||
|         var op = operation[i]; |  | ||||||
|         if (ot.TextOperation.isRetain(op)) { |  | ||||||
|             index += op; |  | ||||||
|         } else if (ot.TextOperation.isInsert(op)) { |  | ||||||
|             var opStart = index; |  | ||||||
|             var opEnd = index + op.length; |  | ||||||
|             var inserted = false; |  | ||||||
|             // authorship format: [userId, startPos, endPos, createdAt, updatedAt]
 |  | ||||||
|             if (authorships.length <= 0) authorships.push([userId, opStart, opEnd, timestamp, timestamp]); |  | ||||||
|             else { |  | ||||||
|                 for (var j = 0; j < authorships.length; j++) { |  | ||||||
|                     var authorship = authorships[j]; |  | ||||||
|                     if (!inserted) { |  | ||||||
|                         var nextAuthorship = authorships[j + 1] || -1; |  | ||||||
|                         if (nextAuthorship != -1 && nextAuthorship[1] >= opEnd || j >= authorships.length - 1) { |  | ||||||
|                             if (authorship[1] < opStart && authorship[2] > opStart) { |  | ||||||
|                                 // divide
 |  | ||||||
|                                 var postLength = authorship[2] - opStart; |  | ||||||
|                                 authorship[2] = opStart; |  | ||||||
|                                 authorship[4] = timestamp; |  | ||||||
|                                 authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]); |  | ||||||
|                                 authorships.splice(j + 2, 0, [authorship[0], opEnd, opEnd + postLength, authorship[3], timestamp]); |  | ||||||
|                                 j += 2; |  | ||||||
|                                 inserted = true; |  | ||||||
|                             } else if (authorship[1] >= opStart) { |  | ||||||
|                                 authorships.splice(j, 0, [userId, opStart, opEnd, timestamp, timestamp]); |  | ||||||
|                                 j += 1; |  | ||||||
|                                 inserted = true; |  | ||||||
|                             } else if (authorship[2] <= opStart) { |  | ||||||
|                                 authorships.splice(j + 1, 0, [userId, opStart, opEnd, timestamp, timestamp]); |  | ||||||
|                                 j += 1; |  | ||||||
|                                 inserted = true; |  | ||||||
|                             } |  | ||||||
|                         } |  | ||||||
|                     } |  | ||||||
|                     if (authorship[1] >= opStart) { |  | ||||||
|                         authorship[1] += op.length; |  | ||||||
|                         authorship[2] += op.length; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             index += op.length; |  | ||||||
|         } else if (ot.TextOperation.isDelete(op)) { |  | ||||||
|             var opStart = index; |  | ||||||
|             var opEnd = index - op; |  | ||||||
|             if (operation.length == 1) { |  | ||||||
|                 authorships = []; |  | ||||||
|             } else if (authorships.length > 0) { |  | ||||||
|                 for (var j = 0; j < authorships.length; j++) { |  | ||||||
|                     var authorship = authorships[j]; |  | ||||||
|                     if (authorship[1] >= opStart && authorship[1] <= opEnd && authorship[2] >= opStart && authorship[2] <= opEnd) { |  | ||||||
|                         authorships.splice(j, 1); |  | ||||||
|                         j -= 1; |  | ||||||
|                     } else if (authorship[1] < opStart && authorship[1] < opEnd && authorship[2] > opStart && authorship[2] > opEnd) { |  | ||||||
|                         authorship[2] += op; |  | ||||||
|                         authorship[4] = timestamp; |  | ||||||
|                     } else if (authorship[2] >= opStart && authorship[2] <= opEnd) { |  | ||||||
|                         authorship[2] = opStart; |  | ||||||
|                         authorship[4] = timestamp; |  | ||||||
|                     } else if (authorship[1] >= opStart && authorship[1] <= opEnd) { |  | ||||||
|                         authorship[1] = opEnd; |  | ||||||
|                         authorship[4] = timestamp; |  | ||||||
|                     } |  | ||||||
|                     if (authorship[1] >= opEnd) { |  | ||||||
|                         authorship[1] += op; |  | ||||||
|                         authorship[2] += op; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             index += op; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     // merge
 |  | ||||||
|     for (var j = 0; j < authorships.length; j++) { |  | ||||||
|         var authorship = authorships[j]; |  | ||||||
|         for (var k = j + 1; k < authorships.length; k++) { |  | ||||||
|             var nextAuthorship = authorships[k]; |  | ||||||
|             if (nextAuthorship && authorship[0] === nextAuthorship[0] && authorship[2] === nextAuthorship[1]) { |  | ||||||
|                 var minTimestamp = Math.min(authorship[3], nextAuthorship[3]); |  | ||||||
|                 var maxTimestamp = Math.max(authorship[3], nextAuthorship[3]); |  | ||||||
|                 authorships.splice(j, 1, [authorship[0], authorship[1], nextAuthorship[2], minTimestamp, maxTimestamp]); |  | ||||||
|                 authorships.splice(k, 1); |  | ||||||
|                 j -= 1; |  | ||||||
|                 break; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     // clear
 |  | ||||||
|     for (var j = 0; j < authorships.length; j++) { |  | ||||||
|         var authorship = authorships[j]; |  | ||||||
|         if (!authorship[0]) { |  | ||||||
|             authorships.splice(j, 1); |  | ||||||
|             j -= 1; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     note.authorship = authorships; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function connection(socket) { | function connection(socket) { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user