11const WRITE = { CREATE : 1 , UPDATE : 1 , DELETE : 1 }
22
3+ const $hasPersonalData = Symbol ( '@cap-js/audit-logging:hasPersonalData' )
4+ const $dataSubject = Symbol ( '@cap-js/audit-logging:dataSubject' )
5+ const $parents = Symbol ( '@cap-js/audit-logging:parents' )
6+ const $visitedUp = Symbol ( '@cap-js/audit-logging:visitedUp' )
7+ const $visitedDown = Symbol ( '@cap-js/audit-logging:visitedDown' )
8+
39const hasPersonalData = entity => {
4- if ( ! entity [ '@PersonalData.EntitySemantics' ] ) return
5- // default role to entity name
6- if ( entity [ '@PersonalData.EntitySemantics' ] === 'DataSubject' && ! entity [ '@PersonalData.DataSubjectRole' ] )
7- entity [ '@PersonalData.DataSubjectRole' ] = entity . name . match ( / \w + / g) . pop ( )
8- // prettier-ignore
9- const hasPersonalData = ! ! Object . values ( entity . elements ) . some ( element =>
10- element [ '@PersonalData.IsPotentiallyPersonal' ] ||
11- element [ '@PersonalData.IsPotentiallySensitive' ] ||
12- ( element [ '@PersonalData.FieldSemantics' ] && element [ '@PersonalData.FieldSemantics' ] === 'DataSubjectID' ) )
13- // cache result
14- entity . own ( '_hasPersonalData' , ( ) => hasPersonalData )
15- return hasPersonalData
10+ if ( ! entity . own ( $hasPersonalData ) ) {
11+ if ( ! entity [ '@PersonalData.EntitySemantics' ] ) entity . set ( $hasPersonalData , false )
12+ else {
13+ // default role to entity name
14+ if ( entity [ '@PersonalData.EntitySemantics' ] === 'DataSubject' && ! entity [ '@PersonalData.DataSubjectRole' ] )
15+ entity [ '@PersonalData.DataSubjectRole' ] = entity . name . match ( / \w + / g) . pop ( )
16+ // prettier-ignore
17+ const hasPersonalData = ! ! Object . values ( entity . elements ) . some ( element =>
18+ element [ '@PersonalData.IsPotentiallyPersonal' ] ||
19+ element [ '@PersonalData.IsPotentiallySensitive' ] ||
20+ ( element [ '@PersonalData.FieldSemantics' ] && element [ '@PersonalData.FieldSemantics' ] === 'DataSubjectID' ) )
21+ entity . set ( $hasPersonalData , hasPersonalData )
22+ }
23+ }
24+ return entity . own ( $hasPersonalData )
1625}
1726
1827const getMapKeyForCurrentRequest = req => {
@@ -136,21 +145,25 @@ const _getDataSubjectIdQuery = ({ dataSubjectEntity, subs }, row, model) => {
136145}
137146
138147const _getUps = ( entity , model ) => {
139- if ( entity . own ( '__parents' ) ) return entity . __parents
148+ if ( entity . own ( $parents ) ) return entity [ $parents ]
140149 const ups = [ ]
141150 for ( const def of Object . values ( model . definitions ) ) {
142151 if ( def . kind !== 'entity' || ! def . associations ) continue
143152 for ( const element of Object . values ( def . associations ) ) {
144- if ( element . target !== entity . name || element . _isBacklink ) continue
145- if ( element . name === 'SiblingEntity' ) continue
153+ if ( element . target !== entity . name || element . _isBacklink || element . name === 'SiblingEntity' ) continue
146154 ups . push ( element )
147155 }
148156 }
149- return entity . set ( '__parents' , ups )
157+ return entity . set ( $parents , ups )
150158}
151159
152- const _getDataSubjectUp = ( model , entity , prev , next , result ) => {
160+ const _getDataSubjectUp = ( root , model , entity , prev , next , result ) => {
153161 for ( const element of _getUps ( entity , model ) ) {
162+ // cycle detection
163+ if ( ! element . own ( $visitedUp ) ) element . set ( $visitedUp , new Set ( ) )
164+ if ( element . own ( $visitedUp ) . has ( root ) ) continue
165+ element . own ( $visitedUp ) . add ( root )
166+
154167 const me = { entity, relative : element . parent , element }
155168 if ( prev ) prev . next = me
156169 if ( element . parent [ '@PersonalData.EntitySemantics' ] === 'DataSubject' ) {
@@ -159,38 +172,42 @@ const _getDataSubjectUp = (model, entity, prev, next, result) => {
159172 return result
160173 } else {
161174 // dfs is a must here
162- result = _getDataSubjectUp ( model , element . parent , me , next || me , result )
175+ result = _getDataSubjectUp ( root , model , element . parent , me , next || me , result )
163176 }
164177 }
165178 return result
166179}
167180
168- const _getDataSubjectDown = ( entity , prev , next ) => {
181+ const _getDataSubjectDown = ( root , entity , prev , next ) => {
169182 const associations = Object . values ( entity . associations || { } ) . filter ( e => ! e . _isBacklink )
183+ // bfs makes more sense here -> check all own assocs first before going deeper
170184 for ( const element of associations ) {
171185 const me = { entity, relative : entity , element }
172186 if ( element . _target [ '@PersonalData.EntitySemantics' ] === 'DataSubject' ) {
173187 if ( prev ) prev . next = me
174188 return { dataSubjectEntity : element . _target , subs : [ next || me ] }
175189 }
176190 }
177- // bfs makes more sense here
178191 for ( const element of associations ) {
192+ // cycle detection
193+ if ( ! element . own ( $visitedDown ) ) element . set ( $visitedDown , new Set ( ) )
194+ if ( element . own ( $visitedDown ) . has ( root ) ) continue
195+ element . own ( $visitedDown ) . add ( root )
196+
179197 const me = { entity, relative : entity , element }
180198 if ( prev ) prev . next = me
181- const dataSubject = _getDataSubjectDown ( element . _target , me , next || me )
199+ const dataSubject = _getDataSubjectDown ( root , element . _target , me , next || me )
182200 if ( dataSubject ) return dataSubject
183201 }
184202}
185203
186204const getDataSubject = ( entity , model ) => {
187- const hash = '__dataSubject'
188- if ( entity . own ( hash ) ) return entity [ hash ]
205+ if ( entity . own ( $dataSubject ) ) return entity [ $dataSubject ]
189206 // entities with EntitySemantics 'DataSubjectDetails' or 'Other' must not necessarily
190207 // be always below or always above 'DataSubject' entity in CSN tree
191- let dataSubjectInfo = _getDataSubjectUp ( model , entity )
192- if ( ! dataSubjectInfo ) dataSubjectInfo = _getDataSubjectDown ( entity )
193- return entity . set ( hash , dataSubjectInfo )
208+ let dataSubjectInfo = _getDataSubjectUp ( entity . name , model , entity )
209+ if ( ! dataSubjectInfo ) dataSubjectInfo = _getDataSubjectDown ( entity . name , entity )
210+ return entity . set ( $dataSubject , dataSubjectInfo )
194211}
195212
196213const _getDataSubjectsMap = req => {
0 commit comments