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 async = require('async'); | ||||
| var moment = require('moment'); | ||||
| var DiffMatchPatch = require('diff-match-patch'); | ||||
| var dmp = new DiffMatchPatch(); | ||||
| 
 | ||||
| // core
 | ||||
| var config = require("../config.js"); | ||||
| var logger = require("../logger.js"); | ||||
| 
 | ||||
| //ot
 | ||||
| var ot = require("../ot/index.js"); | ||||
| 
 | ||||
| // permission types
 | ||||
| var permissionTypes = ["freely", "editable", "locked", "private"]; | ||||
| 
 | ||||
| @ -115,6 +120,7 @@ module.exports = function (sequelize, DataTypes) { | ||||
|                                     var fsModifiedTime = moment(fs.statSync(filePath).mtime); | ||||
|                                     var dbModifiedTime = moment(note.lastchangeAt || note.createdAt); | ||||
|                                     var body = fs.readFileSync(filePath, 'utf8'); | ||||
|                                     var contentLength = body.length; | ||||
|                                     var title = Note.parseNoteTitle(body); | ||||
|                                     body = LZString.compressToBase64(body); | ||||
|                                     title = LZString.compressToBase64(title); | ||||
| @ -126,7 +132,20 @@ module.exports = function (sequelize, DataTypes) { | ||||
|                                         }).then(function (note) { | ||||
|                                             sequelize.models.Revision.saveNoteRevision(note, function (err, revision) { | ||||
|                                                 if (err) return _callback(err, null); | ||||
|                                                 // 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) { | ||||
|                                             return _callback(err, null); | ||||
| @ -247,6 +266,162 @@ module.exports = function (sequelize, DataTypes) { | ||||
|                         _meta.slideOptions = meta.slideOptions; | ||||
|                 } | ||||
|                 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: { | ||||
|  | ||||
							
								
								
									
										101
									
								
								lib/realtime.js
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								lib/realtime.js
									
									
									
									
									
								
							| @ -642,106 +642,7 @@ function operationCallback(socket, operation) { | ||||
|         } | ||||
|     } | ||||
|     // save authorship
 | ||||
|     var index = 0; | ||||
|     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; | ||||
|     note.authorship = models.Note.updateAuthorshipByOperation(operation, userId, note.authorship); | ||||
| } | ||||
| 
 | ||||
| function connection(socket) { | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user