Merge branch 'master' into RED-1332

This commit is contained in:
Dan Percic 2021-05-11 14:06:58 +03:00
commit 18eb9d0259
24 changed files with 135 additions and 153 deletions

View File

@ -7,8 +7,8 @@ To re-generate http rune swagger
YOu need swagger-codegen installed `brew install swagger-codegen` YOu need swagger-codegen installed `brew install swagger-codegen`
``` ```
BASE=http://localhost:8080/ BASE=https://adi-dev.iqser.cloud/
URL="$BASE"v2/api-docs?group=redaction-gateway-v1 URL="$BASE"redaction-gateway-v1/v2/api-docs?group=redaction-gateway-v1
mkdir -p /tmp/swagger mkdir -p /tmp/swagger
swagger-codegen generate -i "$URL" -l typescript-angular -o /tmp/swagger swagger-codegen generate -i "$URL" -l typescript-angular -o /tmp/swagger
cd /tmp/swagger cd /tmp/swagger

View File

@ -80,12 +80,6 @@
mat-menu-item mat-menu-item
translate="top-bar.navigation-items.my-account.children.downloads" translate="top-bar.navigation-items.my-account.children.downloads"
></button> ></button>
<button [matMenuTriggerFor]="language" mat-menu-item translate="top-bar.navigation-items.my-account.children.language.label"></button>
<mat-menu #language="matMenu">
<button (click)="changeLanguage(lang)" *ngFor="let lang of languages" mat-menu-item translate>
top-bar.navigation-items.my-account.children.language.{{ lang }}
</button>
</mat-menu>
<button (click)="logout()" mat-menu-item> <button (click)="logout()" mat-menu-item>
<mat-icon svgIcon="red:logout"></mat-icon> <mat-icon svgIcon="red:logout"></mat-icon>
<span translate="top-bar.navigation-items.my-account.children.logout"> </span> <span translate="top-bar.navigation-items.my-account.children.logout"> </span>

View File

@ -26,11 +26,11 @@ export class AnnotationPermissions {
); );
} }
static forUser(isManagerAndOwner: boolean, user: UserWrapper, annotation: AnnotationWrapper) { static forUser(isApprover: boolean, user: UserWrapper, annotation: AnnotationWrapper) {
const permissions: AnnotationPermissions = new AnnotationPermissions(); const permissions: AnnotationPermissions = new AnnotationPermissions();
permissions.canUndo = permissions.canUndo =
annotation.isUndoableSuperType && (annotation.userId === user.id || (annotation.userId && isManagerAndOwner && !annotation.isSuggestion)); annotation.isUndoableSuperType && (annotation.userId === user.id || (annotation.userId && isApprover && !annotation.isSuggestion));
permissions.canForceRedaction = annotation.isSkipped && !permissions.canUndo; permissions.canForceRedaction = annotation.isSkipped && !permissions.canUndo;
@ -43,10 +43,9 @@ export class AnnotationPermissions {
permissions.canRemoveOrSuggestToRemoveFromDictionary = permissions.canRemoveOrSuggestToRemoveFromDictionary =
annotation.isRedacted && !annotation.isManualRedaction && annotation.isModifyDictionary && !annotation.force; annotation.isRedacted && !annotation.isManualRedaction && annotation.isModifyDictionary && !annotation.force;
permissions.canAcceptSuggestion = isManagerAndOwner && (annotation.isSuggestion || annotation.isDeclinedSuggestion); permissions.canAcceptSuggestion = isApprover && (annotation.isSuggestion || annotation.isDeclinedSuggestion);
permissions.canRejectSuggestion = permissions.canRejectSuggestion =
isManagerAndOwner && isApprover && (annotation.isSuggestion || (annotation.isReadyForAnalysis && !permissions.canUndo && annotation.superType !== 'pending-analysis'));
(annotation.isSuggestion || (annotation.isReadyForAnalysis && !permissions.canUndo && annotation.superType !== 'pending-analysis'));
return permissions; return permissions;
} }

View File

@ -33,7 +33,7 @@ export class AnnotationActionsComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.annotationPermissions = AnnotationPermissions.forUser( this.annotationPermissions = AnnotationPermissions.forUser(
this._permissionsService.isManagerAndOwner(), this._permissionsService.isApprover(),
this._permissionsService.currentUser, this._permissionsService.currentUser,
this.annotation this.annotation
); );

View File

@ -85,7 +85,7 @@ export class AnnotationRemoveActionsComponent {
private _annotationsPermissions(keys: string[], expectedValue: boolean): boolean { private _annotationsPermissions(keys: string[], expectedValue: boolean): boolean {
return this.annotations.reduce((prevValue, annotation) => { return this.annotations.reduce((prevValue, annotation) => {
const annotationPermissions = AnnotationPermissions.forUser( const annotationPermissions = AnnotationPermissions.forUser(
this._permissionsService.isManagerAndOwner(), this._permissionsService.isApprover(),
this._permissionsService.currentUser, this._permissionsService.currentUser,
annotation annotation
); );

View File

@ -15,9 +15,12 @@ import { ProjectsDialogService } from '../../services/projects-dialog.service';
styleUrls: ['./project-overview-bulk-actions.component.scss'] styleUrls: ['./project-overview-bulk-actions.component.scss']
}) })
export class ProjectOverviewBulkActionsComponent { export class ProjectOverviewBulkActionsComponent {
@Input() selectedFileIds: string[]; @Input()
selectedFileIds: string[];
@Output()
reload = new EventEmitter();
loading = false; loading = false;
@Output() private _reload = new EventEmitter();
constructor( constructor(
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
@ -94,7 +97,7 @@ export class ProjectOverviewBulkActionsComponent {
delete() { delete() {
this.loading = true; this.loading = true;
this._dialogService.openDeleteFilesDialog(null, this._appStateService.activeProject.project.projectId, this.selectedFileIds, () => { this._dialogService.openDeleteFilesDialog(null, this._appStateService.activeProject.project.projectId, this.selectedFileIds, () => {
this._reload.emit(); this.reload.emit();
this.loading = false; this.loading = false;
this.selectedFileIds.splice(0, this.selectedFileIds.length); this.selectedFileIds.splice(0, this.selectedFileIds.length);
}); });
@ -103,7 +106,7 @@ export class ProjectOverviewBulkActionsComponent {
assign() { assign() {
this.loading = true; this.loading = true;
this._dialogService.openBulkAssignFileReviewerDialog(this.selectedFileIds, () => { this._dialogService.openBulkAssignFileReviewerDialog(this.selectedFileIds, () => {
this._reload.emit(); this.reload.emit();
this.loading = false; this.loading = false;
}); });
} }
@ -132,7 +135,7 @@ export class ProjectOverviewBulkActionsComponent {
private _performBulkAction(obs: Observable<any>) { private _performBulkAction(obs: Observable<any>) {
this.loading = true; this.loading = true;
obs.subscribe().add(() => { obs.subscribe().add(() => {
this._reload.emit(); this.reload.emit();
this.loading = false; this.loading = false;
}); });
} }

View File

@ -32,9 +32,9 @@
<redaction-circle-button <redaction-circle-button
(action)="assignReviewer($event, fileStatus)" (action)="assignReviewer($event, fileStatus)"
*ngIf="permissionsService.canAssignReviewer(fileStatus) && screen === 'project-overview'" *ngIf="permissionsService.canAssignReviewer(fileStatus) && screen === 'project-overview'"
[icon]="permissionsService.isManagerAndOwner() ? 'red:assign' : 'red:assign-me'" [icon]="permissionsService.isOwner() ? 'red:assign' : 'red:assign-me'"
[tooltipPosition]="tooltipPosition" [tooltipPosition]="tooltipPosition"
[tooltip]="permissionsService.isManagerAndOwner() ? 'project-overview.assign' : 'project-overview.assign-me'" [tooltip]="permissionsService.isApprover() ? 'project-overview.assign' : 'project-overview.assign-me'"
[type]="buttonType" [type]="buttonType"
> >
</redaction-circle-button> </redaction-circle-button>

View File

@ -59,7 +59,7 @@
<div (click)="toggleSelected(userId)" *ngFor="let userId of multiUsersSelectOptions" [class.selected]="isMemberSelected(userId)"> <div (click)="toggleSelected(userId)" *ngFor="let userId of multiUsersSelectOptions" [class.selected]="isMemberSelected(userId)">
<redaction-initials-avatar [userId]="userId" [withName]="true" size="large"></redaction-initials-avatar> <redaction-initials-avatar [userId]="userId" [withName]="true" size="large"></redaction-initials-avatar>
<div class="actions"> <div class="actions">
<div (click)="toggleApprover(userId, $event)" class="make-approver"> <div *ngIf="!isOwner(userId)" (click)="toggleApprover(userId, $event)" class="make-approver">
<redaction-round-checkbox [active]="isApprover(userId)" class="mr-8"></redaction-round-checkbox> <redaction-round-checkbox [active]="isApprover(userId)" class="mr-8"></redaction-round-checkbox>
<span [translate]="'assign-' + data.type + '-owner.dialog.make-approver'"></span> <span [translate]="'assign-' + data.type + '-owner.dialog.make-approver'"></span>
</div> </div>

View File

@ -56,7 +56,9 @@ redaction-team-members {
} }
&.selected { &.selected {
background-color: $green-2; .actions {
display: flex;
}
} }
&:hover { &:hover {

View File

@ -50,7 +50,7 @@ export class ForceRedactionDialogComponent implements OnInit {
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label)); this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
}); });
this.isDocumentAdmin = this._permissionsService.isManagerAndOwner(); this.isDocumentAdmin = this._permissionsService.isApprover();
this.redactionForm = this._formBuilder.group({ this.redactionForm = this._formBuilder.group({
reason: [null, Validators.required], reason: [null, Validators.required],

View File

@ -70,7 +70,7 @@ export class ManualAnnotationDialogComponent implements OnInit {
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label)); this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
}); });
this.isDocumentAdmin = this._permissionsService.isManagerAndOwner(); this.isDocumentAdmin = this._permissionsService.isApprover();
this.isFalsePositiveRequest = this.manualRedactionEntryWrapper.type === 'FALSE_POSITIVE'; this.isFalsePositiveRequest = this.manualRedactionEntryWrapper.type === 'FALSE_POSITIVE';
this.isDictionaryRequest = this.manualRedactionEntryWrapper.type === 'DICTIONARY' || this.isFalsePositiveRequest; this.isDictionaryRequest = this.manualRedactionEntryWrapper.type === 'DICTIONARY' || this.isFalsePositiveRequest;

View File

@ -127,7 +127,7 @@
</redaction-circle-button> </redaction-circle-button>
</div> </div>
<ng-container *ngIf="permissionsService.isManagerAndOwner() && !!appStateService.activeFile.fileStatus.lastReviewer"> <ng-container *ngIf="permissionsService.isApprover() && !!appStateService.activeFile.fileStatus.lastReviewer">
<div class="vertical-line"></div> <div class="vertical-line"></div>
<div class="all-caps-label mr-16 ml-8" translate="file-preview.last-reviewer"></div> <div class="all-caps-label mr-16 ml-8" translate="file-preview.last-reviewer"></div>
<redaction-initials-avatar [userId]="appStateService.activeFile.fileStatus.lastReviewer" [withName]="true"></redaction-initials-avatar> <redaction-initials-avatar [userId]="appStateService.activeFile.fileStatus.lastReviewer" [withName]="true"></redaction-initials-avatar>

View File

@ -33,7 +33,7 @@
<div class="actions"> <div class="actions">
<redaction-circle-button <redaction-circle-button
(action)="openEditProjectDialog($event)" (action)="openEditProjectDialog($event)"
*ngIf="permissionsService.isManagerAndOwner()" *ngIf="permissionsService.isManager()"
icon="red:edit" icon="red:edit"
tooltip="project-overview.header-actions.edit" tooltip="project-overview.header-actions.edit"
tooltipPosition="below" tooltipPosition="below"
@ -47,7 +47,7 @@
></redaction-circle-button> ></redaction-circle-button>
<redaction-circle-button <redaction-circle-button
(action)="openAssignProjectMembersDialog()" (action)="openAssignProjectMembersDialog()"
*ngIf="permissionsService.isManagerAndOwner()" *ngIf="permissionsService.isManager()"
icon="red:assign" icon="red:assign"
tooltip="project-overview.header-actions.assign" tooltip="project-overview.header-actions.assign"
tooltipPosition="below" tooltipPosition="below"

View File

@ -67,7 +67,7 @@ export class AnnotationActionsService {
markAsFalsePositive($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) { markAsFalsePositive($event: MouseEvent, annotations: AnnotationWrapper[], annotationsChanged: EventEmitter<AnnotationWrapper>) {
annotations.forEach((annotation) => { annotations.forEach((annotation) => {
const permissions = AnnotationPermissions.forUser(this._permissionsService.isManagerAndOwner(), this._permissionsService.currentUser, annotation); const permissions = AnnotationPermissions.forUser(this._permissionsService.isApprover(), this._permissionsService.currentUser, annotation);
const value = permissions.canMarkTextOnlyAsFalsePositive ? annotation.value : this._getFalsePositiveText(annotation); const value = permissions.canMarkTextOnlyAsFalsePositive ? annotation.value : this._getFalsePositiveText(annotation);
this._markAsFalsePositive($event, annotation, value, annotationsChanged); this._markAsFalsePositive($event, annotation, value, annotationsChanged);
@ -95,7 +95,7 @@ export class AnnotationActionsService {
const annotationPermissions = annotations.map((a) => ({ const annotationPermissions = annotations.map((a) => ({
annotation: a, annotation: a,
permissions: AnnotationPermissions.forUser(this._permissionsService.isManagerAndOwner(), this._permissionsService.currentUser, a) permissions: AnnotationPermissions.forUser(this._permissionsService.isApprover(), this._permissionsService.currentUser, a)
})); }));
const canForceRedaction = annotationPermissions.reduce((acc, next) => acc && next.permissions.canForceRedaction, true); const canForceRedaction = annotationPermissions.reduce((acc, next) => acc && next.permissions.canForceRedaction, true);

View File

@ -33,7 +33,7 @@ export class FileActionService {
} }
async assignProjectReviewerFromOverview(file?: FileStatusWrapper, callback?: Function) { async assignProjectReviewerFromOverview(file?: FileStatusWrapper, callback?: Function) {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isOwner()) {
this._openAssignReviewerDialog(file, callback); this._openAssignReviewerDialog(file, callback);
} else { } else {
await this.assignToMe(file, callback); await this.assignToMe(file, callback);

View File

@ -56,7 +56,7 @@ export class ManualAnnotationService {
// /manualRedaction/redaction/add // /manualRedaction/redaction/add
// /manualRedaction/request/add // /manualRedaction/request/add
addAnnotation(manualRedactionEntry: AddRedactionRequest) { addAnnotation(manualRedactionEntry: AddRedactionRequest) {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isApprover()) {
return this._makeRedaction(manualRedactionEntry); return this._makeRedaction(manualRedactionEntry);
} else { } else {
return this._makeRedactionRequest(manualRedactionEntry); return this._makeRedactionRequest(manualRedactionEntry);
@ -67,7 +67,7 @@ export class ManualAnnotationService {
// /manualRedaction/redaction/force // /manualRedaction/redaction/force
// /manualRedaction/request/force // /manualRedaction/request/force
forceRedaction(request: ForceRedactionRequest) { forceRedaction(request: ForceRedactionRequest) {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isApprover()) {
return this._makeForceRedaction(request); return this._makeForceRedaction(request);
} else { } else {
return this._makeForceRedactionRequest(request); return this._makeForceRedactionRequest(request);
@ -108,7 +108,7 @@ export class ManualAnnotationService {
// /manualRedaction/decline/remove // /manualRedaction/decline/remove
// /manualRedaction/undo // /manualRedaction/undo
declineOrRemoveRequest(annotationWrapper: AnnotationWrapper) { declineOrRemoveRequest(annotationWrapper: AnnotationWrapper) {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isApprover()) {
return this._manualRedactionControllerService return this._manualRedactionControllerService
.declineRequest(this._appStateService.activeProjectId, this._appStateService.activeFileId, annotationWrapper.id) .declineRequest(this._appStateService.activeProjectId, this._appStateService.activeFileId, annotationWrapper.id)
.pipe( .pipe(
@ -133,7 +133,7 @@ export class ManualAnnotationService {
// /manualRedaction/redaction/remove/ // /manualRedaction/redaction/remove/
// /manualRedaction/request/remove/ // /manualRedaction/request/remove/
removeOrSuggestRemoveAnnotation(annotationWrapper: AnnotationWrapper, removeFromDictionary: boolean = false) { removeOrSuggestRemoveAnnotation(annotationWrapper: AnnotationWrapper, removeFromDictionary: boolean = false) {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isApprover()) {
// if it was something manual simply decline the existing request // if it was something manual simply decline the existing request
if (annotationWrapper.dictionary === 'manual') { if (annotationWrapper.dictionary === 'manual') {
return this._manualRedactionControllerService return this._manualRedactionControllerService
@ -183,7 +183,7 @@ export class ManualAnnotationService {
} }
getTitle(type: 'DICTIONARY' | 'REDACTION' | 'FALSE_POSITIVE') { getTitle(type: 'DICTIONARY' | 'REDACTION' | 'FALSE_POSITIVE') {
if (this._permissionsService.isManagerAndOwner()) { if (this._permissionsService.isApprover()) {
switch (type) { switch (type) {
case 'DICTIONARY': case 'DICTIONARY':
return 'manual-annotation.dialog.header.dictionary'; return 'manual-annotation.dialog.header.dictionary';

View File

@ -23,8 +23,8 @@ export class PermissionsService {
return this._userService.isManager(user); return this._userService.isManager(user);
} }
isReviewerOrOwner(fileStatus?: FileStatusWrapper) { isReviewerOrApprover(fileStatus?: FileStatusWrapper) {
return this.isFileReviewer(fileStatus) || this.isManagerAndOwner(); return this.isFileReviewer(fileStatus) || this.isApprover();
} }
projectReanalysisRequired(project?: ProjectWrapper) { projectReanalysisRequired(project?: ProjectWrapper) {
@ -60,7 +60,7 @@ export class PermissionsService {
if (!project) { if (!project) {
return false; return false;
} }
return this.isManagerAndOwner(project) && project.files.filter((file) => this.fileRequiresReanalysis(file)).length > 0; return this.isApprover(project) && project.files.filter((file) => this.fileRequiresReanalysis(file)).length > 0;
} }
canReanalyseFile(fileStatus?: FileStatusWrapper) { canReanalyseFile(fileStatus?: FileStatusWrapper) {
@ -71,7 +71,7 @@ export class PermissionsService {
return false; return false;
} }
return ( return (
(this.fileRequiresReanalysis(fileStatus) && (this.isReviewerOrOwner(fileStatus) || fileStatus.isUnassigned)) || (this.fileRequiresReanalysis(fileStatus) && (this.isReviewerOrApprover(fileStatus) || fileStatus.isUnassigned)) ||
(fileStatus.isError && fileStatus.isUnassigned) (fileStatus.isError && fileStatus.isUnassigned)
); );
} }
@ -87,7 +87,7 @@ export class PermissionsService {
} }
canDeleteFile(fileStatus?: FileStatusWrapper, project?: ProjectWrapper) { canDeleteFile(fileStatus?: FileStatusWrapper, project?: ProjectWrapper) {
return this.isManagerAndOwner(project) || fileStatus.isUnassigned; return this.isOwner(project) || fileStatus.isUnassigned;
} }
isApprovedOrUnderApproval(fileStatus?: FileStatusWrapper) { isApprovedOrUnderApproval(fileStatus?: FileStatusWrapper) {
@ -117,7 +117,7 @@ export class PermissionsService {
if (!fileStatus) { if (!fileStatus) {
return false; return false;
} }
return fileStatus.status === 'UNDER_APPROVAL' && this.isManagerAndOwner(); return fileStatus.status === 'UNDER_APPROVAL' && this.isApprover();
} }
isReadyForApproval(fileStatus?: FileStatusWrapper) { isReadyForApproval(fileStatus?: FileStatusWrapper) {
@ -147,10 +147,10 @@ export class PermissionsService {
if (!fileStatus) { if (!fileStatus) {
return false; return false;
} }
return fileStatus.status === 'UNDER_REVIEW' && this.isReviewerOrOwner(fileStatus); return fileStatus.status === 'UNDER_REVIEW' && this.isReviewerOrApprover(fileStatus);
} }
isManagerAndOwner(project?: ProjectWrapper, user?: UserWrapper) { isOwner(project?: ProjectWrapper, user?: UserWrapper) {
if (!user) { if (!user) {
user = this._userService.user; user = this._userService.user;
} }
@ -160,7 +160,20 @@ export class PermissionsService {
if (!project) { if (!project) {
return false; return false;
} }
return user.isManager && project.ownerId === user.id; return project.ownerId === user.id;
}
isApprover(project?: ProjectWrapper, user?: UserWrapper) {
if (!user) {
user = this._userService.user;
}
if (!project) {
project = this._appStateService.activeProject;
}
if (!project) {
return false;
}
return project.approverIds?.indexOf(user.id) >= 0;
} }
isProjectMember(project?: ProjectWrapper, user?: UserWrapper) { isProjectMember(project?: ProjectWrapper, user?: UserWrapper) {
@ -209,7 +222,7 @@ export class PermissionsService {
!fileStatus.isError && !fileStatus.isError &&
!fileStatus.isExcluded && !fileStatus.isExcluded &&
!fileStatus.isApprovedOrUnderApproval && !fileStatus.isApprovedOrUnderApproval &&
(this.isManagerAndOwner() || !this.isFileReviewer(fileStatus)) (this.isApprover() || !this.isFileReviewer(fileStatus))
); );
} }
@ -220,7 +233,7 @@ export class PermissionsService {
if (!fileStatus) { if (!fileStatus) {
return false; return false;
} }
return fileStatus.status === 'APPROVED' && this.isManagerAndOwner(); return fileStatus.status === 'APPROVED' && this.isApprover();
} }
canUndoUnderApproval(fileStatus: any) { canUndoUnderApproval(fileStatus: any) {
@ -240,9 +253,7 @@ export class PermissionsService {
if (!fileStatus) { if (!fileStatus) {
return false; return false;
} }
return ( return (fileStatus.status === 'UNDER_REVIEW' && this.isFileReviewer(fileStatus)) || (fileStatus.status === 'UNDER_APPROVAL' && this.isApprover());
(fileStatus.status === 'UNDER_REVIEW' && this.isFileReviewer(fileStatus)) || (fileStatus.status === 'UNDER_APPROVAL' && this.isManagerAndOwner())
);
} }
canDownloadRedactedFile(fileStatus: FileStatusWrapper) { canDownloadRedactedFile(fileStatus: FileStatusWrapper) {
@ -256,7 +267,7 @@ export class PermissionsService {
if (!project) { if (!project) {
return false; return false;
} }
return fileStatus.status === 'APPROVED' && this.isManagerAndOwner(project); return fileStatus.status === 'APPROVED' && this.isApprover(project);
} }
canDeleteProject(project?: ProjectWrapper) { canDeleteProject(project?: ProjectWrapper) {
@ -320,6 +331,6 @@ export class PermissionsService {
if (!fileStatus) { if (!fileStatus) {
return false; return false;
} }
return this.isFileReviewer(fileStatus) || this.isManagerAndOwner(); return this.isFileReviewer(fileStatus) || this.isApprover();
} }
} }

View File

@ -1235,7 +1235,7 @@
"download-type": { "download-type": {
"label": "{{length}} document versions", "label": "{{length}} document versions",
"PREVIEW": "Preview PDF", "PREVIEW": "Preview PDF",
"ORIGINAL": "Original PDF", "ORIGINAL": "Optimized PDF",
"REDACTED": "Redacted PDF" "REDACTED": "Redacted PDF"
}, },
"report-type": { "report-type": {

View File

@ -18,9 +18,7 @@ export class CacheApiService {
for (const dynCache of DYNAMIC_CACHES) { for (const dynCache of DYNAMIC_CACHES) {
for (const cacheUrl of dynCache.urls) { for (const cacheUrl of dynCache.urls) {
if (url.indexOf(cacheUrl) >= 0) { if (url.indexOf(cacheUrl) >= 0) {
return caches.open(dynCache.name).then((cache) => { return caches.open(dynCache.name).then((cache) => this._handleFetchResponse(httpResponse, dynCache, cache, url));
return this._handleFetchResponse(httpResponse, dynCache, cache, url);
});
} }
} }
} }
@ -73,9 +71,7 @@ export class CacheApiService {
removeCache(cacheId: string): Promise<any> { removeCache(cacheId: string): Promise<any> {
if (this.cachesAvailable) { if (this.cachesAvailable) {
return caches.open(APP_LEVEL_CACHE).then((cache) => { return caches.open(APP_LEVEL_CACHE).then((cache) => cache.delete(cacheId));
return cache.delete(cacheId);
});
} else { } else {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
@ -91,9 +87,7 @@ export class CacheApiService {
deleteDynamicCacheEntry(cacheName: string, cacheEntry: string): Promise<any> { deleteDynamicCacheEntry(cacheName: string, cacheEntry: string): Promise<any> {
if (this.cachesAvailable && DYNAMIC_CACHES.some((cache) => cache.name === cacheName)) { if (this.cachesAvailable && DYNAMIC_CACHES.some((cache) => cache.name === cacheName)) {
return caches.open(cacheName).then((cache) => { return caches.open(cacheName).then((cache) => cache.delete(cacheEntry));
return cache.delete(cacheEntry);
});
} else { } else {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
@ -101,8 +95,8 @@ export class CacheApiService {
getCachedValue(name: string): Promise<any> { getCachedValue(name: string): Promise<any> {
if (this.cachesAvailable) { if (this.cachesAvailable) {
return caches.open(APP_LEVEL_CACHE).then((cache) => { return caches.open(APP_LEVEL_CACHE).then((cache) =>
return cache.match(name).then((result) => { cache.match(name).then((result) => {
if (result) { if (result) {
const expires = result.headers.get('_expires'); const expires = result.headers.get('_expires');
try { try {
@ -112,8 +106,8 @@ export class CacheApiService {
} catch (e) {} } catch (e) {}
} }
return undefined; return undefined;
}); })
}); );
} else { } else {
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
@ -187,16 +181,17 @@ export class CacheApiService {
} }
// console.log('[CACHE-API] content type', contentType, response.url); // console.log('[CACHE-API] content type', contentType, response.url);
return obs.pipe( return obs.pipe(
map((body) => { map(
// console.log('[CACHE-API] BODY', body); (body) =>
return new HttpResponse({ // console.log('[CACHE-API] BODY', body);
body, new HttpResponse({
status: response.status, body,
statusText: response.statusText, status: response.status,
url: response.url, statusText: response.statusText,
headers: this._toHttpHeaders(response.headers) url: response.url,
}); headers: this._toHttpHeaders(response.headers)
}) })
)
); );
} }

View File

@ -6,22 +6,22 @@ import { catchError, tap } from 'rxjs/operators';
@Injectable() @Injectable()
export class HttpCacheInterceptor implements HttpInterceptor { export class HttpCacheInterceptor implements HttpInterceptor {
constructor(private cacheApiService: CacheApiService) {} constructor(private _cacheApiService: CacheApiService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// continue if not cachable. // continue if not cachable.
if (!this.cacheApiService.isCachable(req)) { if (!this._cacheApiService.isCachable(req)) {
return next.handle(req); return next.handle(req);
} }
return this.cacheApiService.getCachedRequest(req).pipe( return this._cacheApiService.getCachedRequest(req).pipe(
tap((ok) => { tap(() => {
// console.log('[CACHE-API] got from cache', ok); // console.log('[CACHE-API] got from cache', ok);
}), }),
catchError((cacheError) => { catchError(() =>
// console.log("[CACHE-API] Cache fetch error", cacheError, req.url); // console.log("[CACHE-API] Cache fetch error", cacheError, req.url);
return this.sendRequest(req, next); this.sendRequest(req, next)
}) )
); );
} }
@ -35,7 +35,7 @@ export class HttpCacheInterceptor implements HttpInterceptor {
tap((event) => { tap((event) => {
// There may be other events besides the response. // There may be other events besides the response.
if (event instanceof HttpResponse) { if (event instanceof HttpResponse) {
this.cacheApiService.cacheRequest(request, event); this._cacheApiService.cacheRequest(request, event);
} }
}) })
); );

View File

@ -5,7 +5,7 @@ import { Injectable } from '@angular/core';
providedIn: 'root' providedIn: 'root'
}) })
export class IdToObjectCacheRegisterService { export class IdToObjectCacheRegisterService {
constructor(private idToObjectListCacheStoreService: IdToObjectListCacheStoreService) {} constructor(private _idToObjectListCacheStoreService: IdToObjectListCacheStoreService) {}
registerCaches() {} registerCaches() {}
} }

View File

@ -18,30 +18,30 @@ export interface RegisteredCache {
providedIn: 'root' providedIn: 'root'
}) })
export class IdToObjectListCacheStoreService { export class IdToObjectListCacheStoreService {
private cachesList: { [key: string]: RegisteredCache } = {}; private _cachesList: { [key: string]: RegisteredCache } = {};
constructor(private cacheApiService: CacheApiService) {} constructor(private _cacheApiService: CacheApiService) {}
public registerCache( registerCache(
name: string, name: string,
cacheFunction: (ids: string[], ...params: any) => Observable<{ [key: string]: any }>, cacheFunction: (ids: string[], ...params: any) => Observable<{ [key: string]: any }>,
keyConversionFunction: (id: string, ...params: any) => string = (id, params) => id keyConversionFunction: (id: string, ...params: any) => string = (id) => id
) { ) {
this.cachesList[name] = { this._cachesList[name] = {
name, name,
keyConversionFunction, keyConversionFunction,
cacheFunction cacheFunction
}; };
} }
public invokeCache(name: string, ids: string[], ...params: any): Observable<{ [key: string]: any }> { invokeCache(name: string, ids: string[], ...params: any): Observable<{ [key: string]: any }> {
const promises = []; const promises = [];
const cache = this.cachesList[name]; const cache = this._cachesList[name];
ids.map((id) => this._toUrl(name, cache.keyConversionFunction(id, params))).forEach((url) => { ids.map((id) => this._toUrl(name, cache.keyConversionFunction(id, params))).forEach((url) => {
promises.push(this.cacheApiService.getCachedValue(url)); promises.push(this._cacheApiService.getCachedValue(url));
}); });
return from(Promise.all(promises)) return from(Promise.all(promises))
.pipe(catchError((error) => of([]))) .pipe(catchError(() => of([])))
.pipe( .pipe(
mergeMap((resolvedValues: IdToObject[]) => { mergeMap((resolvedValues: IdToObject[]) => {
const partialResult = {}; const partialResult = {};
@ -52,9 +52,7 @@ export class IdToObjectListCacheStoreService {
}); });
const existingIds = Object.keys(partialResult); const existingIds = Object.keys(partialResult);
const requestIds = ids.filter((el) => { const requestIds = ids.filter((el) => !existingIds.includes(el));
return !existingIds.includes(el);
});
if (requestIds.length > 0) { if (requestIds.length > 0) {
return cache.cacheFunction(requestIds, params).pipe( return cache.cacheFunction(requestIds, params).pipe(
@ -66,7 +64,7 @@ export class IdToObjectListCacheStoreService {
object: data[key] object: data[key]
}; };
// cache each new result // cache each new result
this.cacheApiService.cacheValue(this._toUrl(name, cache.keyConversionFunction(key, params)), idToObject); this._cacheApiService.cacheValue(this._toUrl(name, cache.keyConversionFunction(key, params)), idToObject);
} }
// add existing results to final result // add existing results to final result
for (const existingKey of Object.keys(partialResult)) { for (const existingKey of Object.keys(partialResult)) {
@ -82,10 +80,10 @@ export class IdToObjectListCacheStoreService {
); );
} }
public expireCache(name: string, id: string, ...params: any) { expireCache(name: string, id: string, ...params: any) {
const cache = this.cachesList[name]; const cache = this._cachesList[name];
const cacheUrl = this._toUrl(name, cache.keyConversionFunction(id, params)); const cacheUrl = this._toUrl(name, cache.keyConversionFunction(id, params));
this.cacheApiService.removeCache(cacheUrl); this._cacheApiService.removeCache(cacheUrl);
} }
private _toUrl(cacheName: string, id: string) { private _toUrl(cacheName: string, id: string) {

View File

@ -8,7 +8,7 @@
* NOTE: This class is auto generated by the swagger code generator program. * NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git * https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually. * Do not edit the class manually.
*/ /* eslint-disable @typescript-eslint/no-unused-vars, @typescript-eslint/member-ordering */ */ /* tslint:disable:no-unused-variable member-ordering */
import { Inject, Injectable, Optional } from '@angular/core'; import { Inject, Injectable, Optional } from '@angular/core';
import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http'; import { HttpClient, HttpEvent, HttpHeaders, HttpResponse } from '@angular/common/http';
@ -20,9 +20,9 @@ import { Configuration } from '../configuration';
@Injectable() @Injectable()
export class UserPreferenceControllerService { export class UserPreferenceControllerService {
protected basePath = '';
public defaultHeaders = new HttpHeaders(); public defaultHeaders = new HttpHeaders();
public configuration = new Configuration(); public configuration = new Configuration();
protected basePath = '';
constructor(protected httpClient: HttpClient, @Optional() @Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) { constructor(protected httpClient: HttpClient, @Optional() @Inject(BASE_PATH) basePath: string, @Optional() configuration: Configuration) {
if (basePath) { if (basePath) {
@ -34,6 +34,20 @@ export class UserPreferenceControllerService {
} }
} }
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
/** /**
* Delete User Preferences by key. * Delete User Preferences by key.
* None * None
@ -42,11 +56,8 @@ export class UserPreferenceControllerService {
* @param reportProgress flag to report request and response progress. * @param reportProgress flag to report request and response progress.
*/ */
public deletePreferences(key: string, observe?: 'body', reportProgress?: boolean): Observable<any>; public deletePreferences(key: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public deletePreferences(key: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>; public deletePreferences(key: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public deletePreferences(key: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>; public deletePreferences(key: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public deletePreferences(key: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> { public deletePreferences(key: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (key === null || key === undefined) { if (key === null || key === undefined) {
throw new Error('Required parameter key was null or undefined when calling deletePreferences.'); throw new Error('Required parameter key was null or undefined when calling deletePreferences.');
@ -67,10 +78,7 @@ export class UserPreferenceControllerService {
headers = headers.set('Accept', httpHeaderAcceptSelected); headers = headers.set('Accept', httpHeaderAcceptSelected);
} }
// to determine the Content-Type header return this.httpClient.request<any>('delete', `${this.basePath}/attributes/${encodeURIComponent(String(key))}`, {
const consumes: string[] = [];
return this.httpClient.request<any>('delete', `${this.basePath}/preferences/${encodeURIComponent(String(key))}`, {
withCredentials: this.configuration.withCredentials, withCredentials: this.configuration.withCredentials,
headers: headers, headers: headers,
observe: observe, observe: observe,
@ -79,23 +87,15 @@ export class UserPreferenceControllerService {
} }
/** /**
* Get User Preferences by key. * Get User Attributes.
* None * None
* @param key key
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress. * @param reportProgress flag to report request and response progress.
*/ */
public getPreferences(key: string, observe?: 'body', reportProgress?: boolean): Observable<any>; public getAllUserAttributes(observe?: 'body', reportProgress?: boolean): Observable<{ [key: string]: Array<string> }>;
public getAllUserAttributes(observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<{ [key: string]: Array<string> }>>;
public getPreferences(key: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>; public getAllUserAttributes(observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<{ [key: string]: Array<string> }>>;
public getAllUserAttributes(observe: any = 'body', reportProgress: boolean = false): Observable<any> {
public getPreferences(key: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public getPreferences(key: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (key === null || key === undefined) {
throw new Error('Required parameter key was null or undefined when calling getPreferences.');
}
let headers = this.defaultHeaders; let headers = this.defaultHeaders;
// authentication (RED-OAUTH) required // authentication (RED-OAUTH) required
@ -111,10 +111,7 @@ export class UserPreferenceControllerService {
headers = headers.set('Accept', httpHeaderAcceptSelected); headers = headers.set('Accept', httpHeaderAcceptSelected);
} }
// to determine the Content-Type header return this.httpClient.request<{ [key: string]: Array<string> }>('get', `${this.basePath}/attributes`, {
const consumes: string[] = [];
return this.httpClient.request<any>('get', `${this.basePath}/preferences/${encodeURIComponent(String(key))}`, {
withCredentials: this.configuration.withCredentials, withCredentials: this.configuration.withCredentials,
headers: headers, headers: headers,
observe: observe, observe: observe,
@ -123,20 +120,17 @@ export class UserPreferenceControllerService {
} }
/** /**
* Store User JSON Preferences. * Store User Attribute by key.
* None * None
* @param body jsonNode * @param body values
* @param key key * @param key key
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress. * @param reportProgress flag to report request and response progress.
*/ */
public savePreferences(body: any, key: string, observe?: 'body', reportProgress?: boolean): Observable<any>; public savePreferences(body: Array<string>, key: string, observe?: 'body', reportProgress?: boolean): Observable<any>;
public savePreferences(body: Array<string>, key: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>;
public savePreferences(body: any, key: string, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<any>>; public savePreferences(body: Array<string>, key: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public savePreferences(body: Array<string>, key: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
public savePreferences(body: any, key: string, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<any>>;
public savePreferences(body: any, key: string, observe: any = 'body', reportProgress: boolean = false): Observable<any> {
if (body === null || body === undefined) { if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling savePreferences.'); throw new Error('Required parameter body was null or undefined when calling savePreferences.');
} }
@ -167,7 +161,7 @@ export class UserPreferenceControllerService {
headers = headers.set('Content-Type', httpContentTypeSelected); headers = headers.set('Content-Type', httpContentTypeSelected);
} }
return this.httpClient.request<any>('put', `${this.basePath}/preferences/${encodeURIComponent(String(key))}`, { return this.httpClient.request<any>('put', `${this.basePath}/attributes/${encodeURIComponent(String(key))}`, {
body: body, body: body,
withCredentials: this.configuration.withCredentials, withCredentials: this.configuration.withCredentials,
headers: headers, headers: headers,
@ -175,18 +169,4 @@ export class UserPreferenceControllerService {
reportProgress: reportProgress reportProgress: reportProgress
}); });
} }
/**
* @param consumes string[] mime-types
* @return true: consumes contains 'multipart/form-data', false: otherwise
*/
private canConsumeForm(consumes: string[]): boolean {
const form = 'multipart/form-data';
for (const consume of consumes) {
if (form === consume) {
return true;
}
}
return false;
}
} }

View File

@ -1,6 +1,6 @@
{ {
"name": "redaction", "name": "redaction",
"version": "2.27.0", "version": "2.29.0",
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"scripts": { "scripts": {