| /******************************************************************************** |
| * Copyright (c) 2020 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ********************************************************************************/ |
| |
| import {Injectable} from "@angular/core"; |
| import {Actions, createEffect, ofType} from "@ngrx/effects"; |
| import {Action} from "@ngrx/store"; |
| import {concat, EMPTY, Observable, of, throwError} from "rxjs"; |
| import {catchError, filter, ignoreElements, map, mergeMap, startWith, switchMap} from "rxjs/operators"; |
| import {AttachmentsApiService} from "../../../../core/api/attachments"; |
| import {MailApiService} from "../../../../core/api/mail"; |
| import {arrayJoin, endWithObservable, ignoreError} from "../../../../util"; |
| import {setErrorAction} from "../../../root/actions"; |
| import {EErrorCode} from "../../../root/model"; |
| import { |
| addAttachmentEntityAction, |
| deleteAttachmentsAction, |
| setAttachmentCacheAction, |
| submitAttachmentFormAction, |
| updateAttachmentTagsAction |
| } from "../../actions"; |
| import {IAttachmentControlValue, IAttachmentError, IAttachmentFormValue} from "../../model"; |
| import {FetchAttachmentsEffect} from "../fetch"; |
| |
| @Injectable({providedIn: "root"}) |
| export class SubmitAttachmentsEffect { |
| |
| public submit$ = createEffect(() => this.actions.pipe( |
| ofType(submitAttachmentFormAction), |
| switchMap((action) => { |
| return this.submit(action.statementId, action.taskId, action.value).pipe( |
| ignoreError() |
| ); |
| }) |
| )); |
| |
| public constructor( |
| public readonly actions: Actions, |
| public readonly attachmentsApiService: AttachmentsApiService, |
| public readonly fetchAttachmentsEffect: FetchAttachmentsEffect, |
| public readonly mailApiService: MailApiService |
| ) { |
| |
| } |
| |
| public submit( |
| statementId: number, |
| taskId: string, |
| value: IAttachmentFormValue |
| ): Observable<Action> { |
| const errors: IAttachmentError[] = []; |
| const edit = arrayJoin(value?.edit, value?.email).filter((_) => _?.id); |
| return concat( |
| this.editAttachments(statementId, taskId, edit, errors), |
| this.addAttachments(statementId, taskId, value?.add, errors), |
| this.transferEmailAttachments(statementId, taskId, value?.email, errors), |
| this.transferMailText(statementId, taskId, value?.transferMailText, value?.mailTextAttachmentId, errors), |
| this.fetchAttachmentsEffect.fetchAttachments(statementId) |
| ).pipe( |
| endWithObservable(() => { |
| const lastError = errors.reverse()[0]; |
| return lastError == null ? EMPTY : concat( |
| of(setErrorAction({statementId, error: lastError.message})), |
| throwError(lastError.error) |
| ); |
| }) |
| ); |
| } |
| |
| public transferMailText( |
| statementId: number, |
| taskId: string, |
| shouldBeAdded?: boolean, |
| mailTextAttachmentId?: number, |
| errors?: IAttachmentError[] |
| ) { |
| const mailTextIsAlreadyAdded = mailTextAttachmentId == null; |
| if (shouldBeAdded && mailTextIsAlreadyAdded) { |
| return this.mailApiService.transferMailText(statementId, taskId).pipe( |
| map((entity) => addAttachmentEntityAction({statementId, entity})), |
| catchError((error) => { |
| errors.push({statementId, attachment: null, error, message: EErrorCode.FAILED_MAIL_TRANSFER}); |
| return EMPTY; |
| }) |
| ); |
| } |
| if (!shouldBeAdded && !mailTextIsAlreadyAdded) { |
| return this.attachmentsApiService.deleteAttachment(statementId, taskId, mailTextAttachmentId).pipe( |
| map(() => deleteAttachmentsAction({statementId, entityIds: [mailTextAttachmentId]})), |
| catchError((error) => { |
| errors.push({statementId, attachment: null, error, message: EErrorCode.UNEXPECTED}); |
| return EMPTY; |
| }) |
| ); |
| } |
| return EMPTY; |
| } |
| |
| public transferEmailAttachments(statementId: number, |
| taskId: string, |
| emailAttachments: IAttachmentControlValue[], |
| errors: IAttachmentError[] = []): Observable<Action> { |
| const attachmentsToTransfer = arrayJoin(emailAttachments) |
| .filter((_) => _.isSelected && _.id == null) |
| .map((_) => ({name: _.name, tagIds: _.tagIds})); |
| |
| return attachmentsToTransfer.length === 0 ? EMPTY : |
| this.mailApiService.transferMailAttachment(statementId, taskId, attachmentsToTransfer).pipe( |
| ignoreElements(), |
| catchError((error) => { |
| errors.push({statementId, attachment: null, error, message: EErrorCode.FAILED_MAIL_TRANSFER}); |
| return EMPTY; |
| }) |
| ); |
| } |
| |
| public editAttachments( |
| statementId: number, |
| taskId: string, |
| edit: IAttachmentControlValue[], |
| errors: IAttachmentError[] = [] |
| ): Observable<Action> { |
| return of(...arrayJoin(edit)).pipe( |
| filter((item) => item?.id != null), |
| mergeMap((item) => { |
| return this.editSingleAttachment(statementId, taskId, item.id, item.tagIds, !item.isSelected).pipe( |
| catchError((error) => { |
| errors.push({statementId, attachment: item, error, message: EErrorCode.UNEXPECTED}); |
| return EMPTY; |
| }) |
| ); |
| }, 10), |
| startWith(updateAttachmentTagsAction({items: edit})) |
| ); |
| } |
| |
| public addAttachments( |
| statementId: number, |
| taskId: string, |
| add: IAttachmentControlValue[], |
| errors: IAttachmentError[] = [] |
| ): Observable<Action> { |
| const items: IAttachmentControlValue[] = []; |
| return of(...arrayJoin(add)).pipe( |
| filter((item) => item?.file instanceof File), |
| mergeMap((item) => { |
| return this.addSingleAttachment(statementId, taskId, item.file, item.tagIds).pipe( |
| catchError((error) => { |
| items.push(item); |
| errors.push({statementId, attachment: item, error, message: EErrorCode.FAILED_FILE_UPLOAD}); |
| return EMPTY; |
| }) |
| ); |
| }, 2), |
| startWith(setAttachmentCacheAction({statementId, items: add})), |
| endWithObservable(() => of(setAttachmentCacheAction({statementId, items}))) |
| ); |
| } |
| |
| private editSingleAttachment( |
| statementId: number, |
| taskId: string, |
| id: number, |
| tagIds: string[], |
| remove?: boolean |
| ) { |
| return remove ? |
| this.attachmentsApiService.deleteAttachment(statementId, taskId, id).pipe( |
| map(() => deleteAttachmentsAction({statementId, entityIds: [id]})) |
| ) : |
| this.attachmentsApiService.postAttachmentTags(statementId, taskId, id, ...arrayJoin(tagIds)).pipe( |
| ignoreElements(), |
| ); |
| } |
| |
| private addSingleAttachment( |
| statementId: number, |
| taskId: string, |
| file: File, |
| tagIds: string[] |
| ): Observable<Action> { |
| return this.attachmentsApiService.postAttachment(statementId, taskId, file, ...arrayJoin(tagIds)).pipe( |
| map((entity) => addAttachmentEntityAction({statementId, entity})) |
| ); |
| } |
| |
| } |