RED-7619 wip migration to entity log

This commit is contained in:
Dan Percic 2023-10-23 17:58:18 +03:00
parent e3463907f6
commit c94ef48844
11 changed files with 224 additions and 141 deletions

View File

@ -156,7 +156,7 @@ export const appModuleFactory = (config: AppConfig) => {
enabled: false, enabled: false,
}, },
REDACTION_LOG: { REDACTION_LOG: {
enabled: false, enabled: true,
}, },
VIEWED_PAGES: { VIEWED_PAGES: {
enabled: false, enabled: false,

View File

@ -9,13 +9,15 @@ import {
DefaultColors, DefaultColors,
Dictionary, Dictionary,
Earmark, Earmark,
EntryStates,
EntryTypes,
FalsePositiveSuperTypes, FalsePositiveSuperTypes,
IComment, IComment,
IEntityLogEntry,
ILegalBasis, ILegalBasis,
IManualChange, IManualChange,
IPoint, IPoint,
IRectangle, IRectangle,
IRedactionLogEntry,
LogEntryEngine, LogEntryEngine,
LogEntryEngines, LogEntryEngines,
LogEntryStatuses, LogEntryStatuses,
@ -296,7 +298,7 @@ export class AnnotationWrapper implements IListable {
} }
static fromData( static fromData(
redactionLogEntry: IRedactionLogEntry, logEntry: IEntityLogEntry,
dictionaries: Dictionary[], dictionaries: Dictionary[],
defaultColors: DefaultColors, defaultColors: DefaultColors,
changeLogType: ChangeType, changeLogType: ChangeType,
@ -306,56 +308,61 @@ export class AnnotationWrapper implements IListable {
) { ) {
const annotationWrapper = new AnnotationWrapper(); const annotationWrapper = new AnnotationWrapper();
annotationWrapper.id = redactionLogEntry.id; annotationWrapper.id = logEntry.id;
annotationWrapper.isChangeLogEntry = !!changeLogType; annotationWrapper.isChangeLogEntry = !!changeLogType;
annotationWrapper.changeLogType = changeLogType; annotationWrapper.changeLogType = changeLogType;
annotationWrapper.legalBasisList = legalBasisList; annotationWrapper.legalBasisList = legalBasisList;
annotationWrapper.redaction = redactionLogEntry.redacted; annotationWrapper.redaction = logEntry.entryType === EntryTypes.ENTITY;
annotationWrapper.hint = redactionLogEntry.hint; annotationWrapper.hint = logEntry.entryType === EntryTypes.HINT;
annotationWrapper.typeValue = redactionLogEntry.type; annotationWrapper.typeValue = logEntry.type;
annotationWrapper.value = redactionLogEntry.value; annotationWrapper.value = logEntry.value;
annotationWrapper.firstTopLeftPoint = redactionLogEntry.positions[0]?.topLeft; annotationWrapper.firstTopLeftPoint = { x: logEntry.positions[0].rectangle[0], y: logEntry.positions[0].rectangle[1] };
annotationWrapper.pageNumber = redactionLogEntry.positions[0]?.page; annotationWrapper.pageNumber = logEntry.positions[0].pageNumber;
annotationWrapper.positions = redactionLogEntry.positions; annotationWrapper.positions = logEntry.positions.map(p => ({
annotationWrapper.textBefore = redactionLogEntry.textBefore; page: p.pageNumber,
annotationWrapper.textAfter = redactionLogEntry.textAfter; height: p.rectangle[3],
annotationWrapper.dictionaryOperation = redactionLogEntry.dictionaryEntry; width: p.rectangle[2],
annotationWrapper.image = redactionLogEntry.image; topLeft: { x: p.rectangle[0], y: p.rectangle[1] },
annotationWrapper.imported = redactionLogEntry.imported; }));
annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis; annotationWrapper.textBefore = logEntry.textBefore;
annotationWrapper.comments = redactionLogEntry.comments || []; annotationWrapper.textAfter = logEntry.textAfter;
annotationWrapper.manual = redactionLogEntry.manualChanges?.length > 0; annotationWrapper.dictionaryOperation = logEntry.dictionaryEntry;
annotationWrapper.engines = redactionLogEntry.engines; annotationWrapper.image = logEntry.entryType === EntryTypes.IMAGE;
annotationWrapper.section = redactionLogEntry.section; annotationWrapper.imported = logEntry.imported;
annotationWrapper.reference = redactionLogEntry.reference || []; annotationWrapper.legalBasisValue = logEntry.legalBasis;
annotationWrapper.rectangle = redactionLogEntry.rectangle; annotationWrapper.comments = []; //logEntry.comments || [];
annotationWrapper.manual = logEntry.manualChanges?.length > 0;
annotationWrapper.engines = logEntry.engines;
annotationWrapper.section = logEntry.section;
annotationWrapper.reference = logEntry.reference || [];
annotationWrapper.rectangle = logEntry.entryType === EntryTypes.AREA;
annotationWrapper.hintDictionary = hintDictionary; annotationWrapper.hintDictionary = hintDictionary;
annotationWrapper.hasBeenResized = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasBeenResized = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.RESIZE && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.hasBeenRecategorized = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasBeenRecategorized = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.RECATEGORIZE && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.hasLegalBasisChanged = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasLegalBasisChanged = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.hasBeenForcedHint = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasBeenForcedHint = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.FORCE_HINT && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.hasBeenForcedRedaction = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasBeenForcedRedaction = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.FORCE_REDACT && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.hasBeenRemovedByManualOverride = !!redactionLogEntry.manualChanges?.find( annotationWrapper.hasBeenRemovedByManualOverride = !!logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.annotationStatus === LogEntryStatuses.APPROVED, c => c.manualRedactionType === ManualRedactionTypes.REMOVE_LOCALLY && c.annotationStatus === LogEntryStatuses.APPROVED,
); );
annotationWrapper.legalBasisChangeValue = redactionLogEntry.manualChanges?.find( annotationWrapper.legalBasisChangeValue = logEntry.manualChanges?.find(
c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.REQUESTED, c => c.manualRedactionType === ManualRedactionTypes.LEGAL_BASIS_CHANGE && c.annotationStatus === LogEntryStatuses.REQUESTED,
)?.propertyChanges.legalBasis; )?.propertyChanges.legalBasis;
this.#createContent(annotationWrapper, redactionLogEntry, isDocumine); this.#createContent(annotationWrapper, logEntry, isDocumine);
this.#setSuperType(annotationWrapper, redactionLogEntry); this.#setSuperType(annotationWrapper, logEntry);
this.#handleRecommendations(annotationWrapper, redactionLogEntry); this.#handleRecommendations(annotationWrapper, logEntry);
annotationWrapper.typeLabel = this.#getTypeLabel(redactionLogEntry, annotationWrapper); annotationWrapper.typeLabel = this.#getTypeLabel(logEntry, annotationWrapper);
const entity = dictionaries.find(d => d.type === annotationWrapper.typeValue); const entity = dictionaries.find(d => d.type === annotationWrapper.typeValue);
annotationWrapper.entity = entity?.virtual ? null : entity; annotationWrapper.entity = entity?.virtual ? null : entity;
@ -373,8 +380,8 @@ export class AnnotationWrapper implements IListable {
return annotationWrapper; return annotationWrapper;
} }
static #getTypeLabel(redactionLogEntry: IRedactionLogEntry, annotation: AnnotationWrapper): string { static #getTypeLabel(logEntry: IEntityLogEntry, annotation: AnnotationWrapper): string {
if (redactionLogEntry.reason?.toLowerCase() === 'false positive') { if (logEntry.reason?.toLowerCase() === 'false positive') {
return annotationTypesTranslations[SuggestionAddFalsePositive]; return annotationTypesTranslations[SuggestionAddFalsePositive];
} }
if (annotation.superType === SuperTypes.ManualRedaction && annotation.hintDictionary) { if (annotation.superType === SuperTypes.ManualRedaction && annotation.hintDictionary) {
@ -383,38 +390,48 @@ export class AnnotationWrapper implements IListable {
return annotationTypesTranslations[annotation.superType]; return annotationTypesTranslations[annotation.superType];
} }
static #handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: IRedactionLogEntry) { static #handleRecommendations(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) {
if (annotationWrapper.superType === SuperTypes.Recommendation) { if (annotationWrapper.superType === SuperTypes.Recommendation) {
annotationWrapper.recommendationType = redactionLogEntry.type; annotationWrapper.recommendationType = logEntry.type;
} }
} }
static #setSuperType(annotationWrapper: AnnotationWrapper, entry: IRedactionLogEntry) { static #setSuperType(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry) {
if (entry.manualChanges?.length) { if (logEntry.manualChanges?.length) {
const lastRelevantManualChange = entry.manualChanges?.at(-1); const lastRelevantManualChange = logEntry.manualChanges?.at(-1);
const viableChanges = entry.changes.filter(c => c.analysisNumber > 1); const viableChanges = logEntry.changes.filter(c => c.analysisNumber > 1);
const lastChange = viableChanges.sort(chronologicallyBy(x => x.dateTime)).at(-1); const lastChange = viableChanges.sort(chronologicallyBy(x => x.dateTime)).at(-1);
const lastChangeOccurredAfterLastManualChange = const lastChangeOccurredAfterLastManualChange =
lastChange && timestampOf(lastChange.dateTime) > timestampOf(lastRelevantManualChange.processedDate); lastChange && timestampOf(lastChange.dateTime) > timestampOf(lastRelevantManualChange.processedDate);
if (lastChangeOccurredAfterLastManualChange && lastChange.type === ChangeTypes.ADDED && entry.redacted) { if (
lastChangeOccurredAfterLastManualChange &&
lastChange.type === ChangeTypes.ADDED &&
logEntry.entryType === EntryTypes.ENTITY
) {
annotationWrapper.superType = SuperTypes.Redaction; annotationWrapper.superType = SuperTypes.Redaction;
return; return;
} }
annotationWrapper.pending = !lastRelevantManualChange.processed; annotationWrapper.pending = !lastRelevantManualChange.processed;
annotationWrapper.superType = this.#selectSuperType(entry, lastRelevantManualChange, annotationWrapper.hintDictionary); annotationWrapper.superType = this.#selectSuperType(logEntry, lastRelevantManualChange, annotationWrapper.hintDictionary);
if (lastRelevantManualChange.annotationStatus === LogEntryStatuses.REQUESTED) { if (lastRelevantManualChange.annotationStatus === LogEntryStatuses.REQUESTED) {
annotationWrapper.recategorizationType = lastRelevantManualChange.propertyChanges.type; annotationWrapper.recategorizationType = lastRelevantManualChange.propertyChanges.type;
} }
} else { } else {
if (entry.recommendation) { if (logEntry.state === EntryStates.SKIPPED) {
if (logEntry.entryType === EntryTypes.HINT) {
annotationWrapper.superType = SuperTypes.Hint;
} else {
annotationWrapper.superType = SuperTypes.Skipped;
}
} else if (logEntry.entryType === EntryTypes.RECOMMENDATION) {
annotationWrapper.superType = SuperTypes.Recommendation; annotationWrapper.superType = SuperTypes.Recommendation;
} else if (entry.redacted) { } else if (logEntry.entryType === EntryTypes.ENTITY) {
annotationWrapper.superType = SuperTypes.Redaction; annotationWrapper.superType = SuperTypes.Redaction;
} else if (entry.hint) { } else if (logEntry.entryType === EntryTypes.HINT) {
annotationWrapper.superType = SuperTypes.Hint; annotationWrapper.superType = SuperTypes.Hint;
} else { } else {
annotationWrapper.superType = SuperTypes.Skipped; annotationWrapper.superType = SuperTypes.Skipped;
@ -422,18 +439,18 @@ export class AnnotationWrapper implements IListable {
} }
} }
static #createContent(annotationWrapper: AnnotationWrapper, entry: IRedactionLogEntry, isDocumine: boolean) { static #createContent(annotationWrapper: AnnotationWrapper, logEntry: IEntityLogEntry, isDocumine: boolean) {
let content = ''; let content = '';
if (entry.matchedRule) { if (logEntry.matchedRule) {
content += `Rule ${entry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`; content += `Rule ${logEntry.matchedRule} matched${isDocumine ? ':' : ''} \n\n`;
} }
if (entry.reason) { if (logEntry.reason) {
if (isDocumine && entry.reason.slice(-1) === '.') { if (isDocumine && logEntry.reason.slice(-1) === '.') {
entry.reason = entry.reason.slice(0, -1); logEntry.reason = logEntry.reason.slice(0, -1);
} }
content += entry.reason + '\n\n'; content += logEntry.reason + '\n\n';
//remove leading and trailing commas and whitespaces //remove leading and trailing commas and whitespaces
content = content.replace(/(^[, ]*)|([, ]*$)/g, ''); content = content.replace(/(^[, ]*)|([, ]*$)/g, '');
content = content.substring(0, 1).toUpperCase() + content.substring(1); content = content.substring(0, 1).toUpperCase() + content.substring(1);
@ -447,12 +464,12 @@ export class AnnotationWrapper implements IListable {
content += 'Removed by manual override'; content += 'Removed by manual override';
} }
if (entry.section) { if (logEntry.section) {
let prefix = `In section${isDocumine ? '' : ':'} `; let prefix = `In section${isDocumine ? '' : ':'} `;
if (content.length) { if (content.length) {
prefix = ` ${prefix.toLowerCase()}`; prefix = ` ${prefix.toLowerCase()}`;
} }
content += `${prefix} "${entry.section}"`; content += `${prefix} "${logEntry.section}"`;
} }
annotationWrapper.shortContent = this.#getShortContent(annotationWrapper) || content; annotationWrapper.shortContent = this.#getShortContent(annotationWrapper) || content;
@ -472,7 +489,7 @@ export class AnnotationWrapper implements IListable {
return annotationWrapper.legalBasis; return annotationWrapper.legalBasis;
} }
static #selectSuperType(redactionLogEntry: IRedactionLogEntry, lastManualChange: IManualChange, isHintDictionary: boolean): SuperType { static #selectSuperType(logEntry: IEntityLogEntry, lastManualChange: IManualChange, isHintDictionary: boolean): SuperType {
switch (lastManualChange.manualRedactionType) { switch (lastManualChange.manualRedactionType) {
case ManualRedactionTypes.ADD_LOCALLY: case ManualRedactionTypes.ADD_LOCALLY:
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
@ -503,7 +520,7 @@ export class AnnotationWrapper implements IListable {
return SuperTypes.Hint; return SuperTypes.Hint;
} }
if (redactionLogEntry.redacted) { if (logEntry.entryType === EntryTypes.ENTITY) {
return SuperTypes.Redaction; return SuperTypes.Redaction;
} }
@ -514,7 +531,7 @@ export class AnnotationWrapper implements IListable {
} }
break; break;
case ManualRedactionTypes.REMOVE_FROM_DICTIONARY: case ManualRedactionTypes.REMOVE_FROM_DICTIONARY:
if (redactionLogEntry.redacted) { if (logEntry.entryType === EntryTypes.ENTITY) {
if (lastManualChange.processed) { if (lastManualChange.processed) {
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED: case LogEntryStatuses.APPROVED:
@ -524,35 +541,34 @@ export class AnnotationWrapper implements IListable {
case LogEntryStatuses.REQUESTED: case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary; return SuperTypes.SuggestionRemoveDictionary;
} }
} else {
switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED:
return SuperTypes.Redaction;
case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary;
}
} }
} else { switch (lastManualChange.annotationStatus) {
if (lastManualChange.processed) { case LogEntryStatuses.APPROVED:
switch (lastManualChange.annotationStatus) { case LogEntryStatuses.DECLINED:
case LogEntryStatuses.APPROVED: return SuperTypes.Redaction;
return redactionLogEntry.recommendation ? SuperTypes.Recommendation : SuperTypes.Skipped; case LogEntryStatuses.REQUESTED:
case LogEntryStatuses.DECLINED: return SuperTypes.SuggestionRemoveDictionary;
return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped;
case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary;
}
} else {
switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED:
return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped;
case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary;
}
} }
} }
if (lastManualChange.processed) {
switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED:
return logEntry.entryType === EntryTypes.RECOMMENDATION ? SuperTypes.Recommendation : SuperTypes.Skipped;
case LogEntryStatuses.DECLINED:
return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped;
case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary;
}
}
switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED:
return isHintDictionary ? SuperTypes.Hint : SuperTypes.Skipped;
case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionRemoveDictionary;
}
break; break;
case ManualRedactionTypes.FORCE_REDACT: case ManualRedactionTypes.FORCE_REDACT:
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
@ -578,13 +594,18 @@ export class AnnotationWrapper implements IListable {
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED: case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED: { case LogEntryStatuses.DECLINED: {
if (redactionLogEntry.recommendation) { if (logEntry.entryType === EntryTypes.RECOMMENDATION) {
return SuperTypes.Recommendation; return SuperTypes.Recommendation;
} else if (redactionLogEntry.redacted) { }
if (logEntry.entryType === EntryTypes.ENTITY) {
return SuperTypes.Redaction; return SuperTypes.Redaction;
} else if (redactionLogEntry.hint) { }
if (logEntry.entryType === EntryTypes.HINT) {
return SuperTypes.Hint; return SuperTypes.Hint;
} }
return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped;
} }
case LogEntryStatuses.REQUESTED: case LogEntryStatuses.REQUESTED:
@ -595,7 +616,7 @@ export class AnnotationWrapper implements IListable {
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED: case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED: case LogEntryStatuses.DECLINED:
return redactionLogEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction; return logEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction;
case LogEntryStatuses.REQUESTED: case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionChangeLegalBasis; return SuperTypes.SuggestionChangeLegalBasis;
} }
@ -604,17 +625,18 @@ export class AnnotationWrapper implements IListable {
switch (lastManualChange.annotationStatus) { switch (lastManualChange.annotationStatus) {
case LogEntryStatuses.APPROVED: case LogEntryStatuses.APPROVED:
case LogEntryStatuses.DECLINED: case LogEntryStatuses.DECLINED:
if (redactionLogEntry.recommendation) { if (logEntry.entryType === EntryTypes.RECOMMENDATION) {
return SuperTypes.Recommendation; return SuperTypes.Recommendation;
} else if (redactionLogEntry.redacted) { }
return redactionLogEntry.type === SuperTypes.ManualRedaction
? SuperTypes.ManualRedaction if (logEntry.entryType === EntryTypes.ENTITY) {
: SuperTypes.Redaction; return logEntry.type === SuperTypes.ManualRedaction ? SuperTypes.ManualRedaction : SuperTypes.Redaction;
} else if (redactionLogEntry.hint) { }
if (logEntry.entryType === EntryTypes.HINT) {
return SuperTypes.Hint; return SuperTypes.Hint;
} }
return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped; return isHintDictionary ? SuperTypes.IgnoredHint : SuperTypes.Skipped;
case LogEntryStatuses.REQUESTED: case LogEntryStatuses.REQUESTED:
return SuperTypes.SuggestionResize; return SuperTypes.SuggestionResize;
} }

View File

@ -3,17 +3,7 @@ import { toObservable } from '@angular/core/rxjs-interop';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui'; import { EntitiesService, getConfig, Toaster } from '@iqser/common-ui';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { import { ChangeType, ChangeTypes, File, IEntityLog, IEntityLogEntry, LogEntryStatuses, ViewedPage, ViewMode, ViewModes } from '@red/domain';
ChangeType,
ChangeTypes,
File,
IRedactionLog,
IRedactionLogEntry,
LogEntryStatuses,
ViewedPage,
ViewMode,
ViewModes,
} from '@red/domain';
import { DefaultColorsService } from '@services/entity-services/default-colors.service'; import { DefaultColorsService } from '@services/entity-services/default-colors.service';
import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DictionaryService } from '@services/entity-services/dictionary.service';
import { EarmarksService } from '@services/files/earmarks.service'; import { EarmarksService } from '@services/files/earmarks.service';
@ -132,7 +122,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
async loadRedactionLog() { async loadRedactionLog() {
this._logger.info('[REDACTION_LOG] Loading redaction log...'); this._logger.info('[REDACTION_LOG] Loading redaction log...');
const redactionLog = await this._redactionLogService.getRedactionLog(this._state.dossierId, this._state.fileId); const redactionLog = await this._redactionLogService.getEntityLog(this._state.dossierId, this._state.fileId);
this._logger.info('[REDACTION_LOG] Redaction log loaded', redactionLog); this._logger.info('[REDACTION_LOG] Redaction log loaded', redactionLog);
let annotations = await this.#convertData(redactionLog); let annotations = await this.#convertData(redactionLog);
@ -177,8 +167,8 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
}); });
} }
async #convertData(redactionLog: IRedactionLog) { async #convertData(entityLog: IEntityLog) {
if (!redactionLog.redactionLogEntry) { if (!entityLog.entityLogEntry) {
return []; return [];
} }
@ -189,8 +179,8 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
const defaultColors = this._defaultColorsService.find(this._state.dossierTemplateId); const defaultColors = this._defaultColorsService.find(this._state.dossierTemplateId);
let checkDictionary = true; let checkDictionary = true;
for (const entry of redactionLog.redactionLogEntry) { for (const entry of entityLog.entityLogEntry) {
const pageNumber = entry.positions[0]?.page; const pageNumber = entry.positions[0].pageNumber;
const manual = entry.manualChanges?.length > 0; const manual = entry.manualChanges?.length > 0;
if (!manual && file.excludedPages.includes(pageNumber)) { if (!manual && file.excludedPages.includes(pageNumber)) {
continue; continue;
@ -219,17 +209,17 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
dictionaries, dictionaries,
defaultColors, defaultColors,
changeLogValues.changeLogType, changeLogValues.changeLogType,
redactionLog.legalBasis ?? [], entityLog.legalBasis ?? [],
!!dictionary?.hint, !!dictionary?.hint,
this.#isDocumine, this.#isDocumine,
); );
if (entry.sourceId) { // if (entry.sourceId) {
if (!sourceIds[entry.sourceId]) { // if (!sourceIds[entry.sourceId]) {
sourceIds[entry.sourceId] = []; // sourceIds[entry.sourceId] = [];
} // }
sourceIds[entry.sourceId].push(annotation); // sourceIds[entry.sourceId].push(annotation);
} // }
annotations.push(annotation); annotations.push(annotation);
} }
@ -239,13 +229,13 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
} }
#getChangeLogValues( #getChangeLogValues(
redactionLogEntry: IRedactionLogEntry, entityLogEntry: IEntityLogEntry,
file: File, file: File,
): { ): {
hidden: boolean; hidden: boolean;
changeLogType?: ChangeType; changeLogType?: ChangeType;
} { } {
const hasManualChanges = redactionLogEntry.manualChanges?.length > 0; const hasManualChanges = entityLogEntry.manualChanges?.length > 0;
if (file.numberOfAnalyses <= 1 && !file.hasUpdates && !hasManualChanges) { if (file.numberOfAnalyses <= 1 && !file.hasUpdates && !hasManualChanges) {
return { return {
changeLogType: undefined, changeLogType: undefined,
@ -253,10 +243,10 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
}; };
} }
const viableChanges = redactionLogEntry.changes?.filter(c => c.analysisNumber > 1); const viableChanges = entityLogEntry.changes?.filter(c => c.analysisNumber > 1);
const lastChange = viableChanges?.sort(chronologicallyBy(x => x.dateTime)).at(-1); const lastChange = viableChanges?.sort(chronologicallyBy(x => x.dateTime)).at(-1);
const page = redactionLogEntry.positions?.[0].page; const page = entityLogEntry.positions?.[0].pageNumber;
const viewedPage = this.#originalViewedPages.find(p => p.page === page); const viewedPage = this.#originalViewedPages.find(p => p.page === page);
if (!viewedPage) { if (!viewedPage) {
@ -279,7 +269,7 @@ export class FileDataService extends EntitiesService<AnnotationWrapper, Annotati
} }
const visibleStatuses: string[] = [LogEntryStatuses.APPROVED, LogEntryStatuses.REQUESTED]; const visibleStatuses: string[] = [LogEntryStatuses.APPROVED, LogEntryStatuses.REQUESTED];
const viableManualChanges = redactionLogEntry.manualChanges.filter(change => visibleStatuses.includes(change.annotationStatus)); const viableManualChanges = entityLogEntry.manualChanges.filter(change => visibleStatuses.includes(change.annotationStatus));
viableManualChanges.sort(chronologicallyBy(x => x.processedDate)); viableManualChanges.sort(chronologicallyBy(x => x.processedDate));
const lastManualChange = viableManualChanges.at(-1); const lastManualChange = viableManualChanges.at(-1);
const isSuggestion = lastManualChange?.annotationStatus === LogEntryStatuses.REQUESTED; const isSuggestion = lastManualChange?.annotationStatus === LogEntryStatuses.REQUESTED;

View File

@ -1,8 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { GenericService, QueryParam } from '@iqser/common-ui'; import { GenericService } from '@iqser/common-ui';
import { IRedactionLog, ISectionGrid } from '@red/domain'; import { IEntityLog, ISectionGrid } from '@red/domain';
import { catchError } from 'rxjs/operators';
import { firstValueFrom, of } from 'rxjs'; import { firstValueFrom, of } from 'rxjs';
import { catchError } from 'rxjs/operators';
@Injectable({ @Injectable({
providedIn: 'root', providedIn: 'root',
@ -10,16 +10,11 @@ import { firstValueFrom, of } from 'rxjs';
export class RedactionLogService extends GenericService<unknown> { export class RedactionLogService extends GenericService<unknown> {
protected readonly _defaultModelPath = ''; protected readonly _defaultModelPath = '';
async getRedactionLog(dossierId: string, fileId: string, withManualRedactions?: boolean) { async getEntityLog(dossierId: string, fileId: string) {
const queryParams: QueryParam[] = []; const entityLog$ = this._getOne<IEntityLog>([dossierId, fileId], 'entityLog');
if (withManualRedactions) { const entityLog = await firstValueFrom(entityLog$.pipe(catchError(() => of({} as IEntityLog))));
queryParams.push({ key: 'withManualRedactions', value: withManualRedactions }); entityLog.entityLogEntry.sort((a, b) => a.positions[0].pageNumber - b.positions[0].pageNumber);
} return entityLog;
const redactionLog$ = this._getOne<IRedactionLog>([dossierId, fileId], 'redactionLog', queryParams);
const redactionLog = await firstValueFrom(redactionLog$.pipe(catchError(() => of({} as IRedactionLog))));
redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page);
return redactionLog;
} }
getSectionGrid(dossierId: string, fileId: string) { getSectionGrid(dossierId: string, fileId: string) {

@ -1 +1 @@
Subproject commit a6383c1dbc840115897a31567c3f5633ba78b43a Subproject commit 85fba4a1dd57ecbb133d938552d75fceffa1099c

View File

@ -1,5 +1,5 @@
export interface ILegalBasis { export interface ILegalBasis {
name: string; readonly name: string;
description?: string; readonly description?: string;
reason?: string; readonly reason?: string;
} }

View File

@ -0,0 +1,40 @@
import { ITrackable } from '@iqser/common-ui';
import { IChange } from './change';
import { EntryState } from './entity-states';
import { EntryType } from './entry-types';
import { IManualChange } from './manual-change';
import { LogEntryEngine } from './types';
export interface IEntityLogEntryPosition {
readonly pageNumber: number;
readonly rectangle: readonly [number, number, number, number];
}
export interface IEntityLogEntry extends ITrackable {
type: string;
entryType: EntryType;
state: EntryState;
value: string;
reason: string;
matchedRule: string;
legalBasis: string;
imported: boolean;
containingNodeId: number[];
closestHeadline: string;
section: string;
color: number[];
positions: IEntityLogEntryPosition[];
textAfter?: string;
textBefore?: string;
startOffset?: number;
endOffset?: number;
imageHasTransparency: boolean;
dictionaryEntry: boolean;
dossierDictionaryEntry: boolean;
excluded: boolean;
changes: IChange[];
manualChanges: IManualChange[];
engines: LogEntryEngine[];
reference: string[];
importedRedactionIntersections: string[];
}

View File

@ -0,0 +1,13 @@
import { ILegalBasis } from '../legal-basis';
import { IEntityLogEntry } from './entity-log-entry';
export interface IEntityLog {
analysisVersion: number;
analysisNumber: number;
entityLogEntry: IEntityLogEntry[];
legalBasis: ILegalBasis[];
dictionaryVersion: number;
dossierDictionaryVersion: number;
rulesVersion: number;
legalBasisVersion: number;
}

View File

@ -0,0 +1,8 @@
export const EntryStates = {
APPLIED: 'APPLIED',
SKIPPED: 'SKIPPED',
IGNORED: 'IGNORED',
REMOVED: 'REMOVED',
} as const;
export type EntryState = (typeof EntryStates)[keyof typeof EntryStates];

View File

@ -0,0 +1,11 @@
export const EntryTypes = {
ENTITY: 'ENTITY',
HINT: 'HINT',
FALSE_POSITIVE: 'FALSE_POSITIVE',
RECOMMENDATION: 'RECOMMENDATION',
FALSE_RECOMMENDATION: 'FALSE_RECOMMENDATION',
AREA: 'AREA',
IMAGE: 'IMAGE',
} as const;
export type EntryType = (typeof EntryTypes)[keyof typeof EntryTypes];

View File

@ -12,3 +12,7 @@ export * from './recategorization.request';
export * from './resize.request'; export * from './resize.request';
export * from './manual-change'; export * from './manual-change';
export * from './dictionary-entry-types'; export * from './dictionary-entry-types';
export * from './entity-log';
export * from './entity-log-entry';
export * from './entity-states';
export * from './entry-types';