Trash dossiers service
This commit is contained in:
parent
0a05eb9a6c
commit
e50b5bd567
14
apps/red-ui/src/app/guards/trash-dossiers.guard.ts
Normal file
14
apps/red-ui/src/app/guards/trash-dossiers.guard.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { CanActivate } from '@angular/router';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
import { TrashDossiersService } from '../services/entity-services/trash-dossiers.service';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class TrashDossiersGuard implements CanActivate {
|
||||||
|
constructor(private readonly _trashDossiersService: TrashDossiersService) {}
|
||||||
|
|
||||||
|
async canActivate(): Promise<boolean> {
|
||||||
|
await firstValueFrom(this._trashDossiersService.loadAll());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { SharedModule } from '@shared/shared.module';
|
import { SharedModule } from '@shared/shared.module';
|
||||||
import { NotificationsScreenComponent } from './notifications-screen/notifications-screen.component';
|
import { NotificationsScreenComponent } from './notifications-screen/notifications-screen.component';
|
||||||
import { PendingChangesGuard } from '../../../../guards/can-deactivate.guard';
|
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||||
|
|
||||||
const routes = [{ path: '', component: NotificationsScreenComponent, canDeactivate: [PendingChangesGuard] }];
|
const routes = [{ path: '', component: NotificationsScreenComponent, canDeactivate: [PendingChangesGuard] }];
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router';
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { SharedModule } from '@shared/shared.module';
|
import { SharedModule } from '@shared/shared.module';
|
||||||
import { UserProfileScreenComponent } from './user-profile-screen/user-profile-screen.component';
|
import { UserProfileScreenComponent } from './user-profile-screen/user-profile-screen.component';
|
||||||
import { PendingChangesGuard } from '../../../../guards/can-deactivate.guard';
|
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||||
|
|
||||||
const routes = [{ path: '', component: UserProfileScreenComponent, canDeactivate: [PendingChangesGuard] }];
|
const routes = [{ path: '', component: UserProfileScreenComponent, canDeactivate: [PendingChangesGuard] }];
|
||||||
|
|
||||||
|
|||||||
@ -17,11 +17,12 @@ import { TrashScreenComponent } from './screens/trash/trash-screen.component';
|
|||||||
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
||||||
import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component';
|
import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component';
|
||||||
import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component';
|
import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component';
|
||||||
import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard';
|
import { DossierTemplatesGuard } from '@guards/dossier-templates.guard';
|
||||||
import { DICTIONARY_TYPE, DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
import { DICTIONARY_TYPE, DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||||
import { DossierTemplateExistsGuard } from '../../guards/dossier-template-exists.guard';
|
import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard';
|
||||||
import { DictionaryExistsGuard } from '../../guards/dictionary-exists.guard';
|
import { DictionaryExistsGuard } from '@guards/dictionary-exists.guard';
|
||||||
import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component';
|
import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component';
|
||||||
|
import { TrashDossiersGuard } from '@guards/trash-dossiers.guard';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
|
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
|
||||||
@ -200,7 +201,7 @@ const routes: Routes = [
|
|||||||
component: TrashScreenComponent,
|
component: TrashScreenComponent,
|
||||||
canActivate: [CompositeRouteGuard],
|
canActivate: [CompositeRouteGuard],
|
||||||
data: {
|
data: {
|
||||||
routeGuards: [AuthGuard, RedRoleGuard],
|
routeGuards: [AuthGuard, RedRoleGuard, TrashDossiersGuard],
|
||||||
requiredRoles: ['RED_MANAGER'],
|
requiredRoles: ['RED_MANAGER'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,45 +1,42 @@
|
|||||||
import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, forwardRef, Injector } from '@angular/core';
|
||||||
import {
|
import {
|
||||||
CircleButtonTypes,
|
CircleButtonTypes,
|
||||||
ConfirmationDialogInput,
|
ConfirmationDialogInput,
|
||||||
DefaultListingServices,
|
DefaultListingServicesTmp,
|
||||||
IListable,
|
EntitiesService,
|
||||||
ListingComponent,
|
ListingComponent,
|
||||||
LoadingService,
|
LoadingService,
|
||||||
SortingOrders,
|
SortingOrders,
|
||||||
TableColumnConfig,
|
TableColumnConfig,
|
||||||
TitleColors,
|
TitleColors,
|
||||||
} from '@iqser/common-ui';
|
} from '@iqser/common-ui';
|
||||||
import { ConfigService } from '@services/config.service';
|
|
||||||
import * as moment from 'moment';
|
|
||||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
|
||||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { distinctUntilChanged, map } from 'rxjs/operators';
|
import { distinctUntilChanged, map } from 'rxjs/operators';
|
||||||
import { getLeftDateTime } from '@utils/functions';
|
|
||||||
import { RouterHistoryService } from '@services/router-history.service';
|
import { RouterHistoryService } from '@services/router-history.service';
|
||||||
import { IDossier } from '@red/domain';
|
import { TrashDossier } from '@red/domain';
|
||||||
import { PermissionsService } from '@services/permissions.service';
|
import { TrashDossiersService } from '@services/entity-services/trash-dossiers.service';
|
||||||
|
|
||||||
interface DossierListItem extends IDossier, IListable {
|
|
||||||
readonly canRestore: boolean;
|
|
||||||
readonly canHardDelete: boolean;
|
|
||||||
readonly restoreDate: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './trash-screen.component.html',
|
templateUrl: './trash-screen.component.html',
|
||||||
styleUrls: ['./trash-screen.component.scss'],
|
styleUrls: ['./trash-screen.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => TrashScreenComponent) }],
|
providers: [
|
||||||
|
...DefaultListingServicesTmp,
|
||||||
|
{
|
||||||
|
provide: EntitiesService,
|
||||||
|
useExisting: TrashDossiersService,
|
||||||
|
},
|
||||||
|
{ provide: ListingComponent, useExisting: forwardRef(() => TrashScreenComponent) },
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class TrashScreenComponent extends ListingComponent<DossierListItem> implements OnInit {
|
export class TrashScreenComponent extends ListingComponent<TrashDossier> {
|
||||||
readonly circleButtonTypes = CircleButtonTypes;
|
readonly circleButtonTypes = CircleButtonTypes;
|
||||||
readonly tableHeaderLabel = _('trash.table-header.title');
|
readonly tableHeaderLabel = _('trash.table-header.title');
|
||||||
readonly canRestoreSelected$ = this._canRestoreSelected$;
|
readonly canRestoreSelected$ = this._canRestoreSelected$;
|
||||||
readonly canHardDeleteSelected$ = this._canHardDeleteSelected$;
|
readonly canHardDeleteSelected$ = this._canHardDeleteSelected$;
|
||||||
readonly tableColumnConfigs: TableColumnConfig<DossierListItem>[] = [
|
readonly tableColumnConfigs: TableColumnConfig<TrashDossier>[] = [
|
||||||
{ label: _('trash.table-col-names.name'), sortByKey: 'searchKey' },
|
{ label: _('trash.table-col-names.name'), sortByKey: 'searchKey' },
|
||||||
{ label: _('trash.table-col-names.owner'), class: 'user-column' },
|
{ label: _('trash.table-col-names.owner'), class: 'user-column' },
|
||||||
{ label: _('trash.table-col-names.deleted-on'), sortByKey: 'softDeletedTime' },
|
{ label: _('trash.table-col-names.deleted-on'), sortByKey: 'softDeletedTime' },
|
||||||
@ -49,13 +46,16 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
|
|||||||
constructor(
|
constructor(
|
||||||
protected readonly _injector: Injector,
|
protected readonly _injector: Injector,
|
||||||
private readonly _loadingService: LoadingService,
|
private readonly _loadingService: LoadingService,
|
||||||
private readonly _permissionsService: PermissionsService,
|
private readonly _trashDossiersService: TrashDossiersService,
|
||||||
private readonly _activeDossiersService: ActiveDossiersService,
|
|
||||||
readonly routerHistoryService: RouterHistoryService,
|
readonly routerHistoryService: RouterHistoryService,
|
||||||
private readonly _configService: ConfigService,
|
|
||||||
private readonly _adminDialogService: AdminDialogService,
|
private readonly _adminDialogService: AdminDialogService,
|
||||||
) {
|
) {
|
||||||
super(_injector);
|
super(_injector);
|
||||||
|
|
||||||
|
this.sortingService.setSortingOption({
|
||||||
|
column: 'softDeletedTime',
|
||||||
|
order: SortingOrders.desc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _canRestoreSelected$(): Observable<boolean> {
|
private get _canRestoreSelected$(): Observable<boolean> {
|
||||||
@ -72,17 +72,7 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
disabledFn = (dossier: DossierListItem) => !dossier.canRestore;
|
disabledFn = (dossier: TrashDossier) => !dossier.canRestore;
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
|
||||||
this._loadingService.start();
|
|
||||||
await this._loadDossiersData();
|
|
||||||
this.sortingService.setSortingOption({
|
|
||||||
column: 'softDeletedTime',
|
|
||||||
order: SortingOrders.desc,
|
|
||||||
});
|
|
||||||
this._loadingService.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
hardDelete(dossiers = this.listingService.selected): void {
|
hardDelete(dossiers = this.listingService.selected): void {
|
||||||
const data = new ConfirmationDialogInput({
|
const data = new ConfirmationDialogInput({
|
||||||
@ -95,60 +85,13 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
this._adminDialogService.openDialog('confirm', null, data, () => {
|
this._adminDialogService.openDialog('confirm', null, data, () => {
|
||||||
this._loadingService.loadWhile(this._hardDelete(dossiers));
|
const dossierIds: string[] = dossiers.map(d => d.id);
|
||||||
|
this._loadingService.loadWhile(this._trashDossiersService.hardDelete(dossierIds));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
restore(dossiers = this.listingService.selected): void {
|
restore(dossiers = this.listingService.selected): void {
|
||||||
this._loadingService.loadWhile(this._restore(dossiers));
|
const dossierIds: string[] = dossiers.map(d => d.id);
|
||||||
}
|
this._loadingService.loadWhile(this._trashDossiersService.restore(dossierIds));
|
||||||
|
|
||||||
private _getRestoreDate(softDeletedTime: string): string {
|
|
||||||
return moment(softDeletedTime).add(this._configService.values.DELETE_RETENTION_HOURS, 'hours').toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _loadDossiersData(): Promise<void> {
|
|
||||||
this.entitiesService.setEntities(this._toListItems(await this._activeDossiersService.getDeleted()).filter(d => d.canRestore));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _canRestoreDossier(restoreDate: string): boolean {
|
|
||||||
const { daysLeft, hoursLeft, minutesLeft } = getLeftDateTime(restoreDate);
|
|
||||||
|
|
||||||
return daysLeft >= 0 && hoursLeft >= 0 && minutesLeft > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toListItems(dossiers: IDossier[]): DossierListItem[] {
|
|
||||||
return dossiers.map(dossier => this._toListItem(dossier));
|
|
||||||
}
|
|
||||||
|
|
||||||
private _toListItem(dossier: IDossier): DossierListItem {
|
|
||||||
const restoreDate = this._getRestoreDate(dossier.softDeletedTime);
|
|
||||||
return {
|
|
||||||
id: dossier.dossierId,
|
|
||||||
...dossier,
|
|
||||||
searchKey: dossier.dossierName,
|
|
||||||
restoreDate,
|
|
||||||
canRestore: this._canRestoreDossier(restoreDate),
|
|
||||||
canHardDelete: this._permissionsService.canDeleteDossier(dossier),
|
|
||||||
// Because of migrations, for some this is not set
|
|
||||||
softDeletedTime: dossier.softDeletedTime || '-',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _restore(dossiers: DossierListItem[]): Promise<void> {
|
|
||||||
const dossierIds = dossiers.map(d => d.id);
|
|
||||||
await this._activeDossiersService.restore(dossierIds);
|
|
||||||
this._removeFromList(dossierIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async _hardDelete(dossiers: DossierListItem[]) {
|
|
||||||
const dossierIds = dossiers.map(d => d.id);
|
|
||||||
await this._activeDossiersService.hardDelete(dossierIds);
|
|
||||||
this._removeFromList(dossierIds);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _removeFromList(ids: string[]): void {
|
|
||||||
const entities = this.entitiesService.all.filter(e => !ids.includes(e.id));
|
|
||||||
this.entitiesService.setEntities(entities);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { ArchivedDossiersScreenComponent } from './screens/archived-dossiers-scr
|
|||||||
import { DOSSIER_ID } from '@utils/constants';
|
import { DOSSIER_ID } from '@utils/constants';
|
||||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||||
import { ARCHIVED_DOSSIERS_SERVICE } from '../../tokens';
|
import { ARCHIVED_DOSSIERS_SERVICE } from '../../tokens';
|
||||||
import { DossierFilesGuard } from '../../guards/dossier-files-guard';
|
import { DossierFilesGuard } from '@guards/dossier-files-guard';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{
|
{
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import { DossierStateService } from '@services/entity-services/dossier-state.ser
|
|||||||
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||||
|
import { TrashDossiersService } from '@services/entity-services/trash-dossiers.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-edit-dossier-general-info',
|
selector: 'redaction-edit-dossier-general-info',
|
||||||
@ -39,6 +40,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
|||||||
private readonly _dossierStateService: DossierStateService,
|
private readonly _dossierStateService: DossierStateService,
|
||||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||||
private readonly _dossiersService: DossiersService,
|
private readonly _dossiersService: DossiersService,
|
||||||
|
private readonly _trashDossiersService: TrashDossiersService,
|
||||||
private readonly _dossierStatsService: DossierStatsService,
|
private readonly _dossierStatsService: DossierStatsService,
|
||||||
private readonly _formBuilder: FormBuilder,
|
private readonly _formBuilder: FormBuilder,
|
||||||
private readonly _dialogService: DossiersDialogService,
|
private readonly _dialogService: DossiersDialogService,
|
||||||
@ -139,7 +141,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
this._dialogService.openDialog('confirm', null, data, async () => {
|
this._dialogService.openDialog('confirm', null, data, async () => {
|
||||||
await firstValueFrom(this._dossiersService.delete(this.dossier));
|
await firstValueFrom(this._trashDossiersService.delete(this.dossier));
|
||||||
this._editDossierDialogRef.close();
|
this._editDossierDialogRef.close();
|
||||||
this._router.navigate(['main', 'dossiers']).then(() => this.#notifyDossierDeleted());
|
this._router.navigate(['main', 'dossiers']).then(() => this.#notifyDossierDeleted());
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
|
import { switchMap, tap } from 'rxjs/operators';
|
||||||
import { Dossier, IDossier } from '@red/domain';
|
import { timer } from 'rxjs';
|
||||||
import { catchError, switchMap, tap } from 'rxjs/operators';
|
|
||||||
import { firstValueFrom, Observable, of, timer } from 'rxjs';
|
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
|
||||||
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
|
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
|
||||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||||
|
|
||||||
@ -27,37 +24,7 @@ export class ActiveDossiersService extends DossiersService {
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
getDeleted(): Promise<IDossier[]> {
|
|
||||||
return firstValueFrom(this.getAll('deleted-dossiers'));
|
|
||||||
}
|
|
||||||
|
|
||||||
delete(dossier: Dossier): Observable<unknown> {
|
|
||||||
const showToast = () => {
|
|
||||||
this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier });
|
|
||||||
return of({});
|
|
||||||
};
|
|
||||||
return super.delete(dossier.dossierId).pipe(
|
|
||||||
tap(() => this.#removeDossiers([dossier])),
|
|
||||||
catchError(showToast),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Validate()
|
|
||||||
restore(@RequiredParam() dossierIds: List): Promise<unknown> {
|
|
||||||
return firstValueFrom(this._post(dossierIds, 'deleted-dossiers/restore').pipe(switchMap(() => this.loadAll())));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Validate()
|
|
||||||
hardDelete(@RequiredParam() dossierIds: List): Promise<unknown> {
|
|
||||||
const body = dossierIds.map<QueryParam>(id => ({ key: 'dossierId', value: id }));
|
|
||||||
return firstValueFrom(super.delete(body, 'deleted-dossiers/hard-delete', body));
|
|
||||||
}
|
|
||||||
|
|
||||||
getCountWithState(dossierStatusId: string): number {
|
getCountWithState(dossierStatusId: string): number {
|
||||||
return this.all.filter(dossier => dossier.dossierStatusId === dossierStatusId).length;
|
return this.all.filter(dossier => dossier.dossierStatusId === dossierStatusId).length;
|
||||||
}
|
}
|
||||||
|
|
||||||
#removeDossiers(dossiers: Dossier[]): void {
|
|
||||||
this.setEntities(this.all.filter(dossier => !dossiers.find(d => dossier.id === d.id)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,83 @@
|
|||||||
|
import { Injectable, Injector } from '@angular/core';
|
||||||
|
import { EntitiesService, mapEach, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||||
|
import { Dossier, IDossier, TrashDossier } from '@red/domain';
|
||||||
|
import { catchError, switchMap, tap } from 'rxjs/operators';
|
||||||
|
import { firstValueFrom, Observable, of } from 'rxjs';
|
||||||
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
|
import * as moment from 'moment';
|
||||||
|
import { ConfigService } from '../config.service';
|
||||||
|
import { PermissionsService } from '../permissions.service';
|
||||||
|
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||||
|
|
||||||
|
export interface IDossiersStats {
|
||||||
|
totalPeople: number;
|
||||||
|
totalAnalyzedPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class TrashDossiersService extends EntitiesService<TrashDossier, IDossier> {
|
||||||
|
constructor(
|
||||||
|
protected readonly _injector: Injector,
|
||||||
|
private readonly _toaster: Toaster,
|
||||||
|
private readonly _configService: ConfigService,
|
||||||
|
private readonly _permissionsService: PermissionsService,
|
||||||
|
private readonly _activeDossiersService: ActiveDossiersService,
|
||||||
|
) {
|
||||||
|
super(_injector, TrashDossier, 'dossier');
|
||||||
|
}
|
||||||
|
|
||||||
|
loadAll(): Observable<TrashDossier[]> {
|
||||||
|
return this.#getDeleted().pipe(
|
||||||
|
mapEach(
|
||||||
|
dossier => new TrashDossier(dossier, this.#getRestoreDate(dossier), this._permissionsService.canDeleteDossier(dossier)),
|
||||||
|
),
|
||||||
|
tap(dossiers => this.setEntities(dossiers)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete(dossier: Dossier): Observable<unknown> {
|
||||||
|
const showToast = () => {
|
||||||
|
this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier });
|
||||||
|
return of({});
|
||||||
|
};
|
||||||
|
return super.delete(dossier.dossierId).pipe(
|
||||||
|
switchMap(() => this._activeDossiersService.loadAll()),
|
||||||
|
catchError(showToast),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate()
|
||||||
|
restore(@RequiredParam() dossierIds: string[]): Promise<unknown> {
|
||||||
|
return firstValueFrom(
|
||||||
|
this._post(dossierIds, 'deleted-dossiers/restore').pipe(
|
||||||
|
switchMap(() => this._activeDossiersService.loadAll()),
|
||||||
|
tap(() => this.#removeDossiers(dossierIds)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Validate()
|
||||||
|
hardDelete(@RequiredParam() dossierIds: string[]): Promise<unknown> {
|
||||||
|
const body = dossierIds.map<QueryParam>(id => ({ key: 'dossierId', value: id }));
|
||||||
|
return firstValueFrom(
|
||||||
|
super.delete(body, 'deleted-dossiers/hard-delete', body).pipe(
|
||||||
|
switchMap(() => this._activeDossiersService.loadAll()),
|
||||||
|
tap(() => this.#removeDossiers(dossierIds)),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#getRestoreDate(dossier: IDossier): string {
|
||||||
|
return moment(dossier.softDeletedTime).add(this._configService.values.DELETE_RETENTION_HOURS, 'hours').toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#getDeleted(): Observable<IDossier[]> {
|
||||||
|
return this.getAll('deleted-dossiers');
|
||||||
|
}
|
||||||
|
|
||||||
|
#removeDossiers(dossierIds: string[]): void {
|
||||||
|
this.setEntities(this.all.filter(dossier => !dossierIds.includes(dossier.id)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -20,3 +20,4 @@ export * from './lib/signature';
|
|||||||
export * from './lib/legal-basis';
|
export * from './lib/legal-basis';
|
||||||
export * from './lib/dossier-stats';
|
export * from './lib/dossier-stats';
|
||||||
export * from './lib/dossier-state';
|
export * from './lib/dossier-state';
|
||||||
|
export * from './lib/trash-dossier';
|
||||||
|
|||||||
1
libs/red-domain/src/lib/trash-dossier/index.ts
Normal file
1
libs/red-domain/src/lib/trash-dossier/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from './trash-dossier.model';
|
||||||
69
libs/red-domain/src/lib/trash-dossier/trash-dossier.model.ts
Normal file
69
libs/red-domain/src/lib/trash-dossier/trash-dossier.model.ts
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { List } from '@iqser/common-ui';
|
||||||
|
import { DownloadFileType } from '../shared';
|
||||||
|
import { DossierStatus, IDossier } from '@red/domain';
|
||||||
|
import { getLeftDateTime } from '@utils/functions';
|
||||||
|
|
||||||
|
export class TrashDossier implements IDossier {
|
||||||
|
readonly dossierId: string;
|
||||||
|
readonly dossierTemplateId: string;
|
||||||
|
readonly ownerId: string;
|
||||||
|
readonly memberIds: List;
|
||||||
|
readonly approverIds: List;
|
||||||
|
readonly reportTemplateIds: List;
|
||||||
|
readonly dossierName: string;
|
||||||
|
readonly dossierStatusId: string;
|
||||||
|
readonly date: string;
|
||||||
|
readonly dueDate?: string;
|
||||||
|
readonly description?: string;
|
||||||
|
readonly downloadFileTypes?: List<DownloadFileType>;
|
||||||
|
readonly hardDeletedTime?: string;
|
||||||
|
readonly softDeletedTime?: string;
|
||||||
|
readonly startDate?: string;
|
||||||
|
readonly status: DossierStatus;
|
||||||
|
readonly watermarkEnabled: boolean;
|
||||||
|
readonly watermarkPreviewEnabled: boolean;
|
||||||
|
readonly archivedTime: string;
|
||||||
|
readonly hasReviewers: boolean;
|
||||||
|
readonly canRestore: boolean;
|
||||||
|
|
||||||
|
constructor(dossier: IDossier, readonly restoreDate: string, readonly canHardDelete: boolean) {
|
||||||
|
this.dossierId = dossier.dossierId;
|
||||||
|
this.approverIds = dossier.approverIds;
|
||||||
|
this.date = dossier.date;
|
||||||
|
this.description = dossier.description;
|
||||||
|
this.dossierName = dossier.dossierName;
|
||||||
|
this.dossierStatusId = dossier.dossierStatusId;
|
||||||
|
this.dossierTemplateId = dossier.dossierTemplateId;
|
||||||
|
this.downloadFileTypes = dossier.downloadFileTypes;
|
||||||
|
this.dueDate = dossier.dueDate;
|
||||||
|
this.hardDeletedTime = dossier.hardDeletedTime;
|
||||||
|
this.memberIds = dossier.memberIds;
|
||||||
|
this.ownerId = dossier.ownerId;
|
||||||
|
this.reportTemplateIds = dossier.reportTemplateIds;
|
||||||
|
this.softDeletedTime = dossier.softDeletedTime;
|
||||||
|
this.startDate = dossier.startDate;
|
||||||
|
this.status = dossier.status;
|
||||||
|
this.watermarkEnabled = dossier.watermarkEnabled;
|
||||||
|
this.watermarkPreviewEnabled = dossier.watermarkPreviewEnabled;
|
||||||
|
this.archivedTime = dossier.archivedTime;
|
||||||
|
this.hasReviewers = !!this.memberIds && this.memberIds.length > 1;
|
||||||
|
|
||||||
|
this.canRestore = this.#canRestoreDossier(restoreDate);
|
||||||
|
// Because of migrations, for some this is not set
|
||||||
|
this.softDeletedTime = dossier.softDeletedTime || '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
get id(): string {
|
||||||
|
return this.dossierId;
|
||||||
|
}
|
||||||
|
|
||||||
|
get searchKey(): string {
|
||||||
|
return this.dossierName;
|
||||||
|
}
|
||||||
|
|
||||||
|
#canRestoreDossier(restoreDate: string): boolean {
|
||||||
|
const { daysLeft, hoursLeft, minutesLeft } = getLeftDateTime(restoreDate);
|
||||||
|
|
||||||
|
return daysLeft >= 0 && hoursLeft >= 0 && minutesLeft > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user