File bulk actions service, permissions for multiple files, workflow done

This commit is contained in:
Adina Țeudan 2021-12-08 00:21:55 +02:00
parent a660f3e3af
commit 02da8e5a02
9 changed files with 295 additions and 246 deletions

View File

@ -66,7 +66,7 @@ export class AssignReviewerApproverDialogComponent {
}
private get _canUnassignFiles() {
return this.data.files.reduce((prev, file) => prev && this.permissionsService.canUnassignUser(file), true);
return this.permissionsService.canUnassignUser(this.data.files);
}
/** Initialize the form with:

View File

@ -1,15 +1,11 @@
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
import { Action, ActionTypes, Dossier, File } from '@red/domain';
import { FileAssignService } from '../../../../shared/services/file-assign.service';
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
import { CircleButtonType, CircleButtonTypes, ConfirmationDialogInput, LoadingService, Required } from '@iqser/common-ui';
import { CircleButtonType, CircleButtonTypes, Required } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { LongPressEvent } from '@shared/directives/long-press.directive';
import { UserPreferenceService } from '@services/user-preference.service';
import { FileManagementService } from '@services/entity-services/file-management.service';
import { ReanalysisService } from '@services/reanalysis.service';
import { FilesService } from '@services/entity-services/files.service';
import { BulkActionsService } from '../../services/bulk-actions.service';
@Component({
selector: 'redaction-dossier-overview-bulk-actions',
@ -40,49 +36,44 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
private _canMoveToSameState: boolean;
constructor(
private readonly _dialogService: DossiersDialogService,
private readonly _fileManagementService: FileManagementService,
private readonly _reanalysisService: ReanalysisService,
private readonly _permissionsService: PermissionsService,
private readonly _fileAssignService: FileAssignService,
private readonly _loadingService: LoadingService,
private readonly _userPreferenceService: UserPreferenceService,
private readonly _filesService: FilesService,
private readonly _bulkActionsService: BulkActionsService,
) {}
private get _buttons(): Action[] {
return [
{
type: ActionTypes.circleBtn,
action: () => this._delete(),
action: () => this._bulkActionsService.delete(this.selectedFiles),
tooltip: _('dossier-overview.bulk.delete'),
icon: 'iqser:trash',
show: this.canDelete,
},
{
type: ActionTypes.circleBtn,
action: () => this._assign(),
action: () => this._bulkActionsService.assign(this.selectedFiles),
tooltip: this.assignTooltip,
icon: 'red:assign',
show: this.canAssign,
},
{
type: ActionTypes.circleBtn,
action: () => this._assignToMe(),
action: () => this._bulkActionsService.assignToMe(this.selectedFiles),
tooltip: _('dossier-overview.assign-me'),
icon: 'red:assign-me',
show: this.canAssignToSelf,
},
{
type: ActionTypes.circleBtn,
action: () => this._setToUnderApproval(),
action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles),
tooltip: _('dossier-overview.under-approval'),
icon: 'red:ready-for-approval',
show: this.canSetToUnderApproval,
},
{
type: ActionTypes.circleBtn,
action: () => this._setToUnderReview(),
action: () => this._bulkActionsService.backToUnderReview(this.selectedFiles),
tooltip: _('dossier-overview.under-review'),
icon: 'red:undo',
show: this.canSetToUnderReview,
@ -94,7 +85,7 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
},
{
type: ActionTypes.circleBtn,
action: () => this._approveDocuments(),
action: () => this._bulkActionsService.approve(this.selectedFiles),
disabled: !this.canApprove,
tooltip: this.canApprove ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'),
icon: 'red:approved',
@ -102,21 +93,21 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
},
{
type: ActionTypes.circleBtn,
action: () => this._setToUnderApproval(),
action: () => this._bulkActionsService.setToUnderApproval(this.selectedFiles),
tooltip: _('dossier-overview.under-approval'),
icon: 'red:undo',
show: this.canUndoApproval,
},
{
type: ActionTypes.circleBtn,
action: () => this._ocr(),
action: () => this._bulkActionsService.ocr(this.selectedFiles),
tooltip: _('dossier-overview.ocr-file'),
icon: 'iqser:ocr',
show: this.canOcr,
},
{
type: ActionTypes.circleBtn,
action: () => this._reanalyse(),
action: () => this._bulkActionsService.reanalyse(this.selectedFiles),
tooltip: _('dossier-overview.bulk.reanalyse'),
icon: 'iqser:refresh',
show: this.canReanalyse && this.analysisForced,
@ -133,159 +124,42 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
this._setup();
}
private _delete() {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.delete-file.title'),
question: _('confirmation-dialog.delete-file.question'),
}),
async () => {
this._loadingService.start();
await this._fileManagementService
.delete(
this.selectedFiles.map(item => item.fileId),
this.dossier.dossierId,
)
.toPromise();
this._loadingService.stop();
},
);
}
private async _setToUnderApproval() {
// If more than 1 approver - show dialog and ask who to assign
if (this.dossier.approverIds.length > 1) {
this._assignFiles('approver', true);
} else {
this._loadingService.start();
await this._filesService
.setUnderApprovalFor(
this.selectedFiles.map(f => f.id),
this.dossier.id,
this.dossier.approverIds[0],
)
.toPromise();
this._loadingService.stop();
}
}
private async _reanalyse() {
this._loadingService.start();
const fileIds = this.selectedFiles.filter(file => file.analysisRequired).map(file => file.fileId);
await this._reanalysisService.reanalyzeFilesForDossier(fileIds, this.dossier.id).toPromise();
this._loadingService.stop();
}
private async _ocr() {
this._loadingService.start();
await this._reanalysisService
.ocrFiles(
this.selectedFiles.map(f => f.fileId),
this.dossier.id,
)
.toPromise();
this._loadingService.stop();
}
private async _setToUnderReview() {
this._loadingService.start();
await this._filesService
.setUnderReviewFor(
this.selectedFiles.map(f => f.id),
this.dossier.id,
)
.toPromise();
this._loadingService.stop();
}
private async _approveDocuments(): Promise<void> {
const foundUpdatedFile = this.selectedFiles.find(file => file.hasUpdates);
if (foundUpdatedFile) {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.approve-multiple-files.title'),
question: _('confirmation-dialog.approve-multiple-files.question'),
}),
async () => {
this._loadingService.start();
await this._filesService
.setApprovedFor(
this.selectedFiles.map(f => f.id),
this.dossier.id,
)
.toPromise();
this._loadingService.stop();
},
);
} else {
this._loadingService.start();
await this._filesService
.setApprovedFor(
this.selectedFiles.map(f => f.id),
this.dossier.id,
)
.toPromise();
this._loadingService.stop();
}
}
private async _assignToMe() {
await this._fileAssignService.assignToMe(this.selectedFiles);
}
private _assign() {
const mode = this.selectedFiles[0].isUnderApproval ? 'approver' : 'reviewer';
this._assignFiles(mode);
}
private _setup() {
const allFilesAreUnderReviewOrUnassigned = this.selectedFiles.reduce(
(acc, file) => acc && (file.isUnderReview || file.isNew),
true,
);
const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true);
this._canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval;
this.canAssign =
this._canMoveToSameState &&
this.selectedFiles.reduce(
(acc, file) => (acc && this._permissionsService.canAssignUser(file)) || this._permissionsService.canUnassignUser(file),
if (this.selectedFiles.length) {
const allFilesAreUnderReviewOrUnassigned = this.selectedFiles.reduce(
(acc, file) => acc && (file.isUnderReview || file.isNew),
true,
);
this.canAssignToSelf =
this._canMoveToSameState &&
this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canAssignToSelf(file), true);
const allFilesAreUnderApproval = this.selectedFiles.reduce((acc, file) => acc && file.isUnderApproval, true);
this._canMoveToSameState = allFilesAreUnderReviewOrUnassigned || allFilesAreUnderApproval;
this.canDelete = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canDeleteFile(file), true);
this.canAssign =
this._canMoveToSameState &&
this.selectedFiles.reduce(
(acc, file) => (acc && this._permissionsService.canAssignUser(file)) || this._permissionsService.canUnassignUser(file),
true,
);
this.canAssignToSelf = this._canMoveToSameState && this._permissionsService.canAssignToSelf(this.selectedFiles);
this.canReanalyse = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canReanalyseFile(file), true);
this.canDelete = this._permissionsService.canDeleteFile(this.selectedFiles);
this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true);
this.canReanalyse = this._permissionsService.canReanalyseFile(this.selectedFiles);
this.canSetToUnderReview = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canSetUnderReview(file), true);
this.canOcr = this.selectedFiles.reduce((acc, file) => acc && file.canBeOCRed, true);
this.canSetToUnderApproval = this.selectedFiles.reduce(
(acc, file) => acc && this._permissionsService.canSetUnderApproval(file),
true,
);
this.canSetToUnderReview = this._permissionsService.canSetUnderReview(this.selectedFiles);
this.isReadyForApproval = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.isReadyForApproval(file), true);
this.canSetToUnderApproval = this._permissionsService.canSetUnderApproval(this.selectedFiles);
this.canApprove = this.selectedFiles.reduce((acc, file) => acc && file.canBeApproved, true);
this.isReadyForApproval = this._permissionsService.isReadyForApproval(this.selectedFiles);
this.canUndoApproval = this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canUndoApproval(file), true);
this.canApprove = this._permissionsService.canBeApproved(this.selectedFiles);
this.assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer');
this.canUndoApproval = this._permissionsService.canUndoApproval(this.selectedFiles);
this.buttons = this._buttons;
}
this.assignTooltip = allFilesAreUnderApproval ? _('dossier-overview.assign-approver') : _('dossier-overview.assign-reviewer');
private _assignFiles(mode: 'reviewer' | 'approver', ignoreChanged = false) {
const data = { mode, files: this.selectedFiles, ignoreChanged };
this._dialogService.openDialog('assignFile', null, data);
this.buttons = this._buttons;
}
}
}

View File

@ -7,14 +7,12 @@ import {
List,
ListingMode,
ListingModes,
LoadingService,
NestedFilter,
TableColumnConfig,
WorkflowConfig,
} from '@iqser/common-ui';
import { File, IFileAttributeConfig, StatusSorter, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { workflowFileStatusTranslations } from '../../translations/file-status-translations';
import { FileAssignService } from '../../shared/services/file-assign.service';
import { PermissionsService } from '@services/permissions.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { TranslateService } from '@ngx-translate/core';
@ -24,26 +22,22 @@ import { annotationFilterChecker, RedactionFilterSorter } from '@utils/index';
import { workloadTranslations } from '../../translations/workload-translations';
import * as moment from 'moment';
import { ConfigService as AppConfigService } from '@services/config.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesService } from '@services/entity-services/files.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { noop } from 'lodash';
import noop from 'lodash/noop';
import { BulkActionsService } from './services/bulk-actions.service';
@Injectable()
export class ConfigService {
readonly listingMode$: Observable<ListingMode>;
private readonly _listingMode$ = new BehaviorSubject<ListingMode>(ListingModes.workflow);
private readonly _listingMode$ = new BehaviorSubject<ListingMode>(ListingModes.table);
constructor(
private readonly _fileAssignService: FileAssignService,
private readonly _filesService: FilesService,
private readonly _loadingService: LoadingService,
private readonly _dossiersService: DossiersService,
private readonly _permissionsService: PermissionsService,
private readonly _translateService: TranslateService,
private readonly _userService: UserService,
private readonly _dialogService: DossiersDialogService,
private readonly _appConfigService: AppConfigService,
private readonly _bulkActionsService: BulkActionsService,
) {
this.listingMode$ = this._listingMode$.asObservable();
}
@ -71,28 +65,35 @@ export class ConfigService {
},
{
label: workflowFileStatusTranslations[WorkflowFileStatuses.UNDER_REVIEW],
enterFn: this._underReviewFn,
enterPredicate: (file: File) =>
this._permissionsService.canSetUnderReview(file) ||
this._permissionsService.canAssignToSelf(file) ||
this._permissionsService.canAssignUser(file),
enterFn: async (files: File[]) => {
if (files[0].workflowStatus === WorkflowFileStatuses.UNDER_APPROVAL) {
await this._bulkActionsService.backToUnderReview(files);
} else {
await this._bulkActionsService.assignToMe(files);
}
},
enterPredicate: (files: File[]) =>
this._permissionsService.canSetUnderReview(files) ||
this._permissionsService.canAssignToSelf(files) ||
this._permissionsService.canAssignUser(files),
key: WorkflowFileStatuses.UNDER_REVIEW,
color: '#FDBD00',
entities: new BehaviorSubject([]),
},
{
label: workflowFileStatusTranslations[WorkflowFileStatuses.UNDER_APPROVAL],
enterFn: this._underApprovalFn,
enterPredicate: (file: File) =>
this._permissionsService.canSetUnderApproval(file) || this._permissionsService.canUndoApproval(file),
enterFn: (files: File[]) => this._bulkActionsService.setToUnderApproval(files),
enterPredicate: (files: File[]) =>
this._permissionsService.canSetUnderApproval(files) || this._permissionsService.canUndoApproval(files),
key: WorkflowFileStatuses.UNDER_APPROVAL,
color: '#374C81',
entities: new BehaviorSubject([]),
},
{
label: workflowFileStatusTranslations[WorkflowFileStatuses.APPROVED],
enterFn: this._approveFn,
enterPredicate: (file: File) => this._permissionsService.isReadyForApproval(file) && file.canBeApproved,
enterFn: (files: File[]) => this._bulkActionsService.approve(files),
enterPredicate: (files: File[]) =>
this._permissionsService.isReadyForApproval(files) && this._permissionsService.canBeApproved(files),
key: WorkflowFileStatuses.APPROVED,
color: '#48C9F7',
entities: new BehaviorSubject([]),
@ -366,25 +367,4 @@ export class ConfigService {
private _openEditDossierDialog($event: MouseEvent, dossierId: string) {
this._dialogService.openDialog('editDossier', $event, { dossierId });
}
private _underReviewFn = async (file: File) => {
await this._fileAssignService.assignReviewer(null, file, true);
};
private _underApprovalFn = async (file: File) => {
const dossier = this._dossiersService.find(file.dossierId);
if (dossier.approverIds.length > 1) {
await this._fileAssignService.assignApprover(null, file, true);
} else {
this._loadingService.start();
await this._filesService.setUnderApprovalFor([file.id], dossier.dossierId, dossier.approverIds[0]).toPromise();
this._loadingService.stop();
}
};
private _approveFn = async (file: File) => {
this._loadingService.start();
await this._filesService.setApprovedFor([file.id], file.dossierId).toPromise();
this._loadingService.stop();
};
}

View File

@ -18,6 +18,7 @@ import { ScreenHeaderComponent } from './components/screen-header/screen-header.
import { ViewModeSelectionComponent } from './components/view-mode-selection/view-mode-selection.component';
import { FileNameColumnComponent } from './components/table-item/file-name-column/file-name-column.component';
import { AddedColumnComponent } from './components/table-item/added-column/added-column.component';
import { BulkActionsService } from './services/bulk-actions.service';
const routes: Routes = [
{
@ -45,7 +46,7 @@ const routes: Routes = [
FileNameColumnComponent,
AddedColumnComponent,
],
providers: [ConfigService],
providers: [ConfigService, BulkActionsService],
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule],
})
export class DossierOverviewModule {}

View File

@ -0,0 +1,140 @@
import { Injectable } from '@angular/core';
import { Dossier, File } from '@red/domain';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { ConfirmationDialogInput, LoadingService } from '@iqser/common-ui';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesService } from '@services/entity-services/files.service';
import { FileAssignService } from '../../../shared/services/file-assign.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { ReanalysisService } from '../../../../../services/reanalysis.service';
import { FileManagementService } from '@services/entity-services/file-management.service';
@Injectable()
export class BulkActionsService {
constructor(
private readonly _dialogService: DossiersDialogService,
private readonly _loadingService: LoadingService,
private readonly _dossiersService: DossiersService,
private readonly _filesService: FilesService,
private readonly _fileAssignService: FileAssignService,
private readonly _reanalysisService: ReanalysisService,
private readonly _fileManagementService: FileManagementService,
) {}
async setToUnderApproval(files: File[]) {
const dossier = this._getDossier(files);
// If more than 1 approver - show dialog and ask who to assign
if (dossier.approverIds.length > 1) {
this._assignFiles(files, 'approver', true);
} else {
this._loadingService.start();
await this._filesService
.setUnderApprovalFor(
files.map(f => f.id),
dossier.id,
dossier.approverIds[0],
)
.toPromise();
this._loadingService.stop();
}
}
async assignToMe(files: File[]) {
await this._fileAssignService.assignToMe(files);
}
async ocr(files: File[]) {
this._loadingService.start();
await this._reanalysisService
.ocrFiles(
files.map(f => f.fileId),
files[0].dossierId,
)
.toPromise();
this._loadingService.stop();
}
delete(files: File[]) {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.delete-file.title'),
question: _('confirmation-dialog.delete-file.question'),
}),
async () => {
this._loadingService.start();
await this._fileManagementService
.delete(
files.map(item => item.fileId),
files[0].dossierId,
)
.toPromise();
this._loadingService.stop();
},
);
}
async reanalyse(files: File[]) {
this._loadingService.start();
const fileIds = files.filter(file => file.analysisRequired).map(file => file.fileId);
await this._reanalysisService.reanalyzeFilesForDossier(fileIds, files[0].dossierId).toPromise();
this._loadingService.stop();
}
async backToUnderReview(files: File[]): Promise<void> {
this._loadingService.start();
await this._filesService
.setUnderReviewFor(
files.map(f => f.id),
files[0].dossierId,
)
.toPromise();
this._loadingService.stop();
}
async approve(files: File[]): Promise<void> {
const foundUpdatedFile = files.find(file => file.hasUpdates);
if (foundUpdatedFile) {
this._dialogService.openDialog(
'confirm',
null,
new ConfirmationDialogInput({
title: _('confirmation-dialog.approve-multiple-files.title'),
question: _('confirmation-dialog.approve-multiple-files.question'),
}),
async () => {
this._loadingService.start();
await this._filesService
.setApprovedFor(
files.map(f => f.id),
files[0].dossierId,
)
.toPromise();
this._loadingService.stop();
},
);
} else {
this._loadingService.start();
await this._filesService
.setApprovedFor(
files.map(f => f.id),
files[0].dossierId,
)
.toPromise();
this._loadingService.stop();
}
}
assign(files: File[], mode: 'reviewer' | 'approver' = files[0].isUnderApproval ? 'approver' : 'reviewer') {
this._assignFiles(files, mode);
}
private _getDossier(files: File[]): Dossier {
return this._dossiersService.find(files[0].dossierId);
}
private _assignFiles(files: File[], mode: 'reviewer' | 'approver', ignoreChanged = false) {
this._dialogService.openDialog('assignFile', null, { mode, files, ignoreChanged });
}
}

View File

@ -68,9 +68,9 @@ export class UserManagementComponent implements OnChanges {
}
ngOnChanges() {
this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.file, this.dossier);
this.canAssignUser = this.permissionsService.canAssignUser(this.file, this.dossier);
this.canUnassignUser = this.permissionsService.canUnassignUser(this.file, this.dossier);
this.canAssignToSelf = this.permissionsService.canAssignToSelf(this.file);
this.canAssignUser = this.permissionsService.canAssignUser(this.file);
this.canUnassignUser = this.permissionsService.canUnassignUser(this.file);
this.canAssignOrUnassign = this.canAssignUser || this.canUnassignUser;
this.canAssign = this.canAssignToSelf || this.canAssignOrUnassign;

View File

@ -22,58 +22,57 @@ export class PermissionsService {
return this.isReviewerOrApprover(file) && (file.isNew || file.isUnderReview || file.isUnderApproval);
}
canReanalyseFile(file: File): boolean {
return this.isReviewerOrApprover(file) || file.isNew || (file.isError && file.isNew);
canReanalyseFile(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
return files.reduce((acc, _file) => this._canReanalyseFile(_file) && acc, true);
}
isFileAssignee(file: File): boolean {
return file.assignee === this._userService.currentUser.id;
}
// https://jira.iqser.com/browse/RED-2787
canDeleteFile(file: File): boolean {
const dossier = this._getDossier(file);
return (
file.isNew ||
(file.isUnderReview && !file.assignee && this.isDossierMember(dossier)) ||
(file.isUnderApproval && !file.assignee && this.isApprover(dossier)) ||
(file.assignee && !file.isApproved && (this.isFileAssignee(file) || this.isOwner(dossier)))
);
canDeleteFile(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return files.reduce((acc, _file) => this._canDeleteFile(_file, dossier) && acc, true);
}
canAssignToSelf(file: File, dossier = this._getDossier(file)): boolean {
const precondition = this.isDossierMember(dossier) && !this.isFileAssignee(file) && !file.isError && !file.isProcessing;
return precondition && (file.isNew || file.isUnderReview || (file.isUnderApproval && this.isApprover(dossier)));
canAssignToSelf(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return files.reduce((acc, _file) => this._canAssignToSelf(_file, dossier) && acc, true);
}
canAssignUser(file: File, dossier = this._getDossier(file)): boolean {
const precondition = !file.isProcessing && !file.isError && !file.isApproved && this.isApprover(dossier);
if (precondition) {
if ((file.isNew || file.isUnderReview) && dossier.hasReviewers) {
return true;
}
if (file.isUnderApproval && dossier.approverIds.length > 1) {
return true;
}
}
return false;
canAssignUser(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return files.reduce((acc, _file) => this._canAssignUser(_file, dossier) && acc, true);
}
canUnassignUser(file: File, dossier = this._getDossier(file)): boolean {
return (file.isUnderReview || file.isUnderApproval) && (this.isFileAssignee(file) || this.isApprover(dossier));
canUnassignUser(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return files.reduce((acc, _file) => this._canUnassignUser(_file, dossier) && acc, true);
}
canSetUnderReview(file: File, dossier = this._getDossier(file)): boolean {
return file.isUnderApproval && this.isApprover(dossier);
canSetUnderReview(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return this.isApprover(dossier) && files.reduce((acc, _file) => this._canSetUnderReview(_file) && acc, true);
}
isReadyForApproval(file: File): boolean {
return this.canSetUnderReview(file);
canBeApproved(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
return files.reduce((acc, _file) => this._canBeApproved(_file) && acc, true);
}
canSetUnderApproval(file: File): boolean {
return file.isUnderReview && this.isReviewerOrApprover(file);
isReadyForApproval(files: File | File[]): boolean {
return this.canSetUnderReview(files);
}
canSetUnderApproval(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
return files.reduce((acc, _file) => this._canSetUnderApproval(_file) && acc, true);
}
isOwner(dossier: Dossier, user = this._userService.currentUser): boolean {
@ -97,8 +96,10 @@ export class PermissionsService {
return (file?.isUnderReview || file?.isUnderApproval) && this.isFileAssignee(file);
}
canUndoApproval(file: File): boolean {
return file.isApproved && this.isApprover(this._getDossier(file));
canUndoApproval(file: File | File[]): boolean {
const files = file instanceof File ? [file] : file;
const dossier = this._getDossier(files[0]);
return files.reduce((acc, _file) => this._canUndoApproval(_file, dossier) && acc, true);
}
canMarkPagesAsViewed(file: File): boolean {
@ -135,6 +136,59 @@ export class PermissionsService {
return (comment.user === this._userService.currentUser.id || this.isApprover(dossier)) && !file.isApproved;
}
// https://jira.iqser.com/browse/RED-2787
private _canDeleteFile(file: File, dossier: Dossier): boolean {
return (
file.isNew ||
(file.isUnderReview && !file.assignee && this.isDossierMember(dossier)) ||
(file.isUnderApproval && !file.assignee && this.isApprover(dossier)) ||
(file.assignee && !file.isApproved && (this.isFileAssignee(file) || this.isOwner(dossier)))
);
}
private _canReanalyseFile(file: File): boolean {
return this.isReviewerOrApprover(file) || file.isNew || (file.isError && file.isNew);
}
private _canAssignToSelf(file: File, dossier: Dossier): boolean {
const precondition = this.isDossierMember(dossier) && !this.isFileAssignee(file) && !file.isError && !file.isProcessing;
return precondition && (file.isNew || file.isUnderReview || (file.isUnderApproval && this.isApprover(dossier)));
}
private _canSetUnderApproval(file: File): boolean {
return file.isUnderReview && this.isReviewerOrApprover(file);
}
private _canUndoApproval(file: File, dossier: Dossier): boolean {
return file.isApproved && this.isApprover(dossier);
}
private _canBeApproved(file: File): boolean {
return file.canBeApproved;
}
private _canAssignUser(file: File, dossier: Dossier) {
const precondition = !file.isProcessing && !file.isError && !file.isApproved && this.isApprover(dossier);
if (precondition) {
if ((file.isNew || file.isUnderReview) && dossier.hasReviewers) {
return true;
}
if (file.isUnderApproval && dossier.approverIds.length > 1) {
return true;
}
}
return false;
}
private _canUnassignUser(file: File, dossier: Dossier) {
return (file.isUnderReview || file.isUnderApproval) && (this.isFileAssignee(file) || this.isApprover(dossier));
}
private _canSetUnderReview(file: File): boolean {
return file.isUnderApproval;
}
private _getDossier(file: File): Dossier {
return this._dossiersService.find(file.dossierId);
}

View File

@ -45,8 +45,8 @@ export class ReanalysisService extends GenericService<unknown> {
}
@Validate()
ocrFiles(@RequiredParam() body: List, @RequiredParam() dossierId: string) {
return this._post(body, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId)));
ocrFiles(@RequiredParam() fileIds: List, @RequiredParam() dossierId: string) {
return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId)));
}
@Validate()

@ -1 +1 @@
Subproject commit 567de98f30d622c6bbc9a47d87a784c7aa36055f
Subproject commit 28a6b735f700351f36c2583de4b581fe5fb8106b