@@ -100,10 +100,10 @@ export class DatabaseConnection {
100100 if ( collectionname === "fs.files" ) {
101101 _query = { $and : [ query , this . getbasequery ( jwt , "metadata._acl" , [ Rights . read ] ) ] } ;
102102 } else {
103- if ( ! collectionname . endsWith ( "hist " ) ) {
103+ if ( ! collectionname . endsWith ( "_hist " ) ) {
104104 _query = { $and : [ query , this . getbasequery ( jwt , "_acl" , [ Rights . read ] ) ] } ;
105105 } else {
106- // todo: enforcer permissions when fetching hist ?
106+ // todo: enforcer permissions when fetching _hist ?
107107 _query = query ;
108108 }
109109 }
@@ -259,12 +259,15 @@ export class DatabaseConnection {
259259 j = ( ( j as any ) === 'true' || j === true ) ;
260260 w = parseInt ( ( w as any ) ) ;
261261
262+ item . _version = await this . SaveDiff ( collectionname , null , item ) ;
263+
262264 // var options:CollectionInsertOneOptions = { writeConcern: { w: parseInt((w as any)), j: j } };
263265 var options : CollectionInsertOneOptions = { w : w , j : j } ;
264266 //var options: CollectionInsertOneOptions = { w: "majority" };
265267 var result : InsertOneWriteOpResult = await this . db . collection ( collectionname ) . insertOne ( item , options ) ;
266268 item = result . ops [ 0 ] ;
267269
270+
268271 if ( collectionname === "users" && item . _type === "user" ) {
269272 var users : Role = await Role . FindByNameOrId ( "users" , jwt ) ;
270273 users . AddMember ( item ) ;
@@ -307,13 +310,14 @@ export class DatabaseConnection {
307310 var user : TokenUser = Crypt . verityToken ( q . jwt ) ;
308311 if ( ! this . hasAuthorization ( user , q . item , "update" ) ) { throw new Error ( "Access denied" ) ; }
309312
313+ var original : T = null ;
310314 // assume empty query, means full document, else update document
311315 if ( q . query === null || q . query === undefined ) {
312316 // this will add an _acl so needs to be after we checked old item
313317 if ( ! q . item . hasOwnProperty ( "_id" ) ) {
314318 throw Error ( "Cannot update item without _id" ) ;
315319 }
316- var original : T = await this . getbyid < T > ( q . item . _id , q . collectionname , q . jwt ) ;
320+ original = await this . getbyid < T > ( q . item . _id , q . collectionname , q . jwt ) ;
317321 if ( ! original ) { throw Error ( "item not found!" ) ; }
318322 q . item . _modifiedby = user . name ;
319323 q . item . _modifiedbyid = user . _id ;
@@ -346,8 +350,12 @@ export class DatabaseConnection {
346350 if ( q . collectionname != "audit" ) { this . _logger . debug ( "Adding self " + user . username + " to object " + ( q . item . name || q . item . _name ) ) ; }
347351 q . item . addRight ( user . _id , user . name , [ Rights . full_control ] ) ;
348352 }
353+ q . item . _version = await this . SaveDiff ( q . collectionname , original , q . item ) ;
349354 } else {
350355 itemReplace = false ;
356+ var _version = await this . SaveUpdateDiff ( q , user ) ;
357+ if ( ( q . item [ "$set" ] ) === undefined ) { ( q . item [ "$set" ] ) = { } } ;
358+ ( q . item [ "$set" ] ) . _version = _version ;
351359 }
352360
353361 if ( q . collectionname === "users" && q . item . _type === "user" && q . item . hasOwnProperty ( "newpassword" ) ) {
@@ -365,10 +373,10 @@ export class DatabaseConnection {
365373 if ( q . collectionname === "fs.files" ) {
366374 _query = { $and : [ q . query , this . getbasequery ( q . jwt , "metadata._acl" , [ Rights . update ] ) ] } ;
367375 } else {
368- if ( ! q . collectionname . endsWith ( "hist " ) ) {
376+ if ( ! q . collectionname . endsWith ( "_hist " ) ) {
369377 _query = { $and : [ q . query , this . getbasequery ( q . jwt , "_acl" , [ Rights . update ] ) ] } ;
370378 } else {
371- // todo: enforcer permissions when fetching hist ?
379+ // todo: enforcer permissions when fetching _hist ?
372380 _query = q . query ;
373381 }
374382 }
@@ -386,15 +394,17 @@ export class DatabaseConnection {
386394 ( q . item [ "$set" ] ) . _modifiedby = user . name ;
387395 ( q . item [ "$set" ] ) . _modifiedbyid = user . _id ;
388396 ( q . item [ "$set" ] ) . _modified = new Date ( new Date ( ) . toISOString ( ) ) ;
397+ if ( ( q . item [ "$inc" ] ) === undefined ) { ( q . item [ "$inc" ] ) = { } } ;
398+ ( q . item [ "$inc" ] ) . _version = 1 ;
389399 q . opresult = await this . db . collection ( q . collectionname ) . updateOne ( _query , q . item , options ) ;
390400 }
391401 q . item = this . decryptentity < T > ( q . item ) ;
392402 this . traversejsondecode ( q . item ) ;
393403 q . result = q . item ;
394- return q ;
395404 } catch ( error ) {
396405 throw error ;
397406 }
407+ return q ;
398408 }
399409 /**
400410 * Update multiple documents in database based on update document
@@ -429,10 +439,10 @@ export class DatabaseConnection {
429439 if ( q . collectionname === "fs.files" ) {
430440 _query = { $and : [ q . query , this . getbasequery ( q . jwt , "metadata._acl" , [ Rights . read ] ) ] } ;
431441 } else {
432- if ( ! q . collectionname . endsWith ( "hist " ) ) {
442+ if ( ! q . collectionname . endsWith ( "_hist " ) ) {
433443 _query = { $and : [ q . query , this . getbasequery ( q . jwt , "_acl" , [ Rights . read ] ) ] } ;
434444 } else {
435- // todo: enforcer permissions when fetching hist ?
445+ // todo: enforcer permissions when fetching _hist ?
436446 _query = q . query ;
437447 }
438448 }
@@ -540,8 +550,6 @@ export class DatabaseConnection {
540550 this . _logger . debug ( "deleting " + id + " in database" ) ;
541551 var res : DeleteWriteOpResultObject = await this . db . collection ( collectionname ) . deleteOne ( _query ) ;
542552
543-
544-
545553 // var res:DeleteWriteOpResultObject = await this.db.collection(collectionname).deleteOne({_id:id});
546554 // var res:DeleteWriteOpResultObject = await this.db.collection(collectionname).deleteOne(id);
547555 if ( res . deletedCount === 0 ) { throw Error ( "item not found!" ) ; }
@@ -780,4 +788,129 @@ export class DatabaseConnection {
780788
781789 }
782790
791+ async SaveUpdateDiff < T extends Base > ( q : UpdateOneMessage < T > , user : TokenUser ) {
792+ var _skip_array : string [ ] = Config . skip_history_collections . split ( "," ) ;
793+ var skip_array : string [ ] = [ ] ;
794+ _skip_array . forEach ( x => skip_array . push ( x . trim ( ) ) ) ;
795+ if ( skip_array . indexOf ( q . collectionname ) > - 1 ) { return 0 ; }
796+ var res = await this . query < T > ( q . query , null , 1 , 0 , null , q . collectionname , q . jwt ) ;
797+ if ( res . length > 0 ) {
798+ var _version = 1 ;
799+ var original = res [ 0 ] ;
800+
801+ delete original . _modifiedby ;
802+ delete original . _modifiedbyid ;
803+ delete original . _modified ;
804+ if ( original . _version != undefined && original . _version != null ) {
805+ _version = original . _version + 1 ;
806+ }
807+ }
808+ var updatehist = {
809+ _modified : new Date ( new Date ( ) . toISOString ( ) ) ,
810+ _modifiedby : user . name ,
811+ _modifiedbyid : user . _id ,
812+ _created : new Date ( new Date ( ) . toISOString ( ) ) ,
813+ _createdby : user . name ,
814+ _createdbyid : user . _id ,
815+ name : original . name ,
816+ id : original . _id ,
817+ update : q . item ,
818+ _version : _version ,
819+ reason : ""
820+ }
821+ await this . db . collection ( q . collectionname + '_hist' ) . insertOne ( updatehist ) ;
822+ }
823+ async SaveDiff ( collectionname : string , original : any , item : any ) {
824+ if ( item . _type == 'instance' && collectionname == 'workflows' ) return 0 ;
825+ if ( item . _type == 'instance' && collectionname == 'workflows' ) return 0 ;
826+ var _modified = item . _modified ;
827+ var _modifiedby = item . _modifiedby ;
828+ var _modifiedbyid = item . _modifiedbyid ;
829+ var _version = 0 ;
830+ var _acl = item . _acl ;
831+ var _type = item . _type ;
832+ var reason = item . _updatereason ;
833+ try {
834+ var _skip_array : string [ ] = Config . skip_history_collections . split ( "," ) ;
835+ var skip_array : string [ ] = [ ] ;
836+ _skip_array . forEach ( x => skip_array . push ( x . trim ( ) ) ) ;
837+ if ( skip_array . indexOf ( collectionname ) > - 1 ) { return 0 ; }
838+
839+ if ( original != null ) {
840+ delete original . _modifiedby ;
841+ delete original . _modifiedbyid ;
842+ delete original . _modified ;
843+ if ( original . _version != undefined && original . _version != null ) {
844+ _version = original . _version + 1 ;
845+ }
846+ }
847+ var jsondiffpatch = require ( 'jsondiffpatch' ) . create ( {
848+ objectHash : function ( obj , index ) {
849+ // try to find an id property, otherwise just use the index in the array
850+ return obj . name || obj . id || obj . _id || '$$index:' + index ;
851+ }
852+ } ) ;
853+ var delta : any = null ;
854+ // for backward comp, we cannot assume all objects have an history
855+ // we create diff from version 0
856+ // var delta_collections = Config.history_delta_collections.split(',');
857+ // var full_collections = Config.history_full_collections.split(',');
858+ // if (delta_collections.indexOf(collectionname) == -1 && full_collections.indexOf(collectionname) == -1) return 0;
859+
860+ item . _version = _version ;
861+ delete item . _modifiedby ;
862+ delete item . _modifiedbyid ;
863+ delete item . _modified ;
864+ delete item . _updatereason ;
865+
866+ // if (original != null && _version > 0 && delta_collections.indexOf(collectionname) > -1) {
867+ if ( original != null && _version > 0 ) {
868+ delta = jsondiffpatch . diff ( original , item ) ;
869+ if ( delta == undefined || delta == null ) return 0 ;
870+ var deltahist = {
871+ _acl : _acl ,
872+ _type : _type ,
873+ _modified : _modified ,
874+ _modifiedby : _modifiedby ,
875+ _modifiedbyid : _modifiedbyid ,
876+ _created : _modified ,
877+ _createdby : _modifiedby ,
878+ _createdbyid : _modifiedbyid ,
879+ name : item . name ,
880+ id : item . _id ,
881+ item : original ,
882+ delta : delta ,
883+ _version : _version ,
884+ reason : reason
885+ }
886+ await this . db . collection ( collectionname + '_hist' ) . insertOne ( deltahist ) ;
887+ }
888+ else {
889+ var fullhist = {
890+ _acl : _acl ,
891+ _type : _type ,
892+ _modified : _modified ,
893+ _modifiedby : _modifiedby ,
894+ _modifiedbyid : _modifiedbyid ,
895+ _created : _modified ,
896+ _createdby : _modifiedby ,
897+ _createdbyid : _modifiedbyid ,
898+ name : item . name ,
899+ id : item . _id ,
900+ item : item ,
901+ _version : _version ,
902+ reason : reason
903+ }
904+ await this . db . collection ( collectionname + '_hist' ) . insertOne ( fullhist ) ;
905+ }
906+ item . _modifiedby = _modifiedby ;
907+ item . _modifiedbyid = _modifiedbyid ;
908+ item . _modified = _modified ;
909+ } catch ( error ) {
910+ this . _logger . error ( error ) ;
911+ }
912+ return _version ;
913+ }
914+
915+
783916}
0 commit comments