From 7ee3e761819e2a10399c33e67634293f9982959a Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Wed, 8 Apr 2020 11:47:32 +0200
Subject: [PATCH] FEAT #13441 TIME 9 edit template with onlyoffice + fix
 interceptor

---
 .../controllers/OnlyOfficeController.php      |   6 +-
 .../administration/administration.module.ts   | 113 ++--
 .../template-administration.component.html    | 140 +++--
 .../template-administration.component.ts      | 500 ++++++++++++------
 .../template-file-editor-modal.component.html |  13 +
 .../template-file-editor-modal.component.scss |   0
 .../template-file-editor-modal.component.ts   |  36 ++
 .../app/viewer/document-viewer.component.ts   |   4 +-
 .../onlyoffice-viewer.component.html          |   2 +-
 .../onlyoffice-viewer.component.ts            |  13 +-
 .../service/auth-interceptor.service.ts       |   2 +-
 11 files changed, 531 insertions(+), 298 deletions(-)
 create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html
 create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss
 create mode 100644 src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts

diff --git a/src/app/contentManagement/controllers/OnlyOfficeController.php b/src/app/contentManagement/controllers/OnlyOfficeController.php
index 86292e602e5..cb2974bc8cd 100644
--- a/src/app/contentManagement/controllers/OnlyOfficeController.php
+++ b/src/app/contentManagement/controllers/OnlyOfficeController.php
@@ -70,7 +70,11 @@ class OnlyOfficeController
             }
 
             $path = $body['objectId'];
-            $fileContent = file_get_contents($path);
+            
+            $fileContent = @file_get_contents($path);
+            if ($fileContent == false) {
+                return $response->withStatus(400)->withJson(['errors' => 'No content found']);
+            }
         } elseif ($body['objectType'] == 'templateModification') {
             $docserver = DocserverModel::getCurrentDocserver(['typeId' => 'TEMPLATES', 'collId' => 'templates', 'select' => ['path_template']]);
             $template = TemplateModel::getById(['id' => $body['objectId'], 'select' => ['template_path', 'template_file_name']]);
diff --git a/src/frontend/app/administration/administration.module.ts b/src/frontend/app/administration/administration.module.ts
index ab585337aba..5821c37ed7c 100755
--- a/src/frontend/app/administration/administration.module.ts
+++ b/src/frontend/app/administration/administration.module.ts
@@ -1,60 +1,63 @@
-import { NgModule }                             from '@angular/core';
+import { NgModule } from '@angular/core';
 
-import { SharedModule }                         from '../app-common.module';
+import { SharedModule } from '../app-common.module';
 
-import { AdministrationRoutingModule }          from './administration-routing.module';
+import { AdministrationRoutingModule } from './administration-routing.module';
 import { NgxChartsModule } from '@swimlane/ngx-charts';
 
-import { AdministrationComponent }                      from './home/administration.component';
-import { UsersAdministrationComponent, UsersAdministrationRedirectModalComponent }      from './user/users-administration.component';
-import { AccountLinkComponent }      from './user/account-link/account-link.component';
-import { GroupsAdministrationComponent, GroupsAdministrationRedirectModalComponent }    from './group/groups-administration.component';
-import { UserAdministrationComponent, UserAdministrationRedirectModalComponent }                  from './user/user-administration.component';
-import { GroupAdministrationComponent }                 from './group/group-administration.component';
-import { IndexingAdministrationComponent }                 from './group/indexing/indexing-administration.component';
-import { BasketsAdministrationComponent }               from './basket/baskets-administration.component';
-import { BasketAdministrationComponent, BasketAdministrationSettingsModalComponent, BasketAdministrationGroupListModalComponent }                from './basket/basket-administration.component';
-import { EntitiesAdministrationComponent, EntitiesAdministrationRedirectModalComponent} from './entity/entities-administration.component';
-import { DiffusionModelsAdministrationComponent }       from './diffusionModel/diffusionModels-administration.component';
-import { DiffusionModelAdministrationComponent }        from './diffusionModel/diffusionModel-administration.component';
-import { DoctypesAdministrationComponent, DoctypesAdministrationRedirectModalComponent }              from './doctype/doctypes-administration.component';
-import { StatusesAdministrationComponent }              from './status/statuses-administration.component';
-import { StatusAdministrationComponent }                from './status/status-administration.component';
-import { ActionsAdministrationComponent }               from './action/actions-administration.component';
-import { ActionAdministrationComponent }                from './action/action-administration.component';
-import { ParametersAdministrationComponent }            from './parameter/parameters-administration.component';
-import { ParameterAdministrationComponent }             from './parameter/parameter-administration.component';
-import { PrioritiesAdministrationComponent }            from './priority/priorities-administration.component';
-import { PriorityAdministrationComponent }              from './priority/priority-administration.component';
-import { HistoryAdministrationComponent }               from './history/history-administration.component';
-import { HistoryBatchAdministrationComponent }               from './history/batch/history-batch-administration.component';
-import { UpdateStatusAdministrationComponent }          from './updateStatus/update-status-administration.component';
-import { NotificationsAdministrationComponent }         from './notification/notifications-administration.component';
-import { NotificationAdministrationComponent }          from './notification/notification-administration.component';
-import { ContactsGroupsAdministrationComponent }        from './contact/group/contacts-groups-administration.component';
-import { ContactsGroupAdministrationComponent }         from './contact/group/contacts-group-administration.component';
-import { ContactsParametersAdministrationComponent }       from './contact/parameter/contacts-parameters-administration.component';
-import { VersionsUpdateAdministrationComponent }        from './versionUpdate/versions-update-administration.component';
-import { DocserversAdministrationComponent }            from './docserver/docservers-administration.component';
-import { DocserverAdministrationComponent }             from './docserver/docserver-administration.component';
-import { TemplatesAdministrationComponent }             from './template/templates-administration.component';
-import { TemplateAdministrationComponent, TemplateAdministrationCheckEntitiesModalComponent }              from './template/template-administration.component';
-import { SecuritiesAdministrationComponent }            from './security/securities-administration.component';
-import { SendmailAdministrationComponent }              from './sendmail/sendmail-administration.component';
-import { ListAdministrationComponent }                  from './basket/list/list-administration.component';
-import { ShippingsAdministrationComponent }              from './shipping/shippings-administration.component';
-import { ShippingAdministrationComponent }              from './shipping/shipping-administration.component';
-import { CustomFieldsAdministrationComponent }              from './customField/custom-fields-administration.component';
-import { IndexingModelAdministrationComponent }              from './indexingModel/indexing-model-administration.component';
-import { IndexingModelsAdministrationComponent }              from './indexingModel/indexing-models-administration.component';
-import { ContactsListAdministrationComponent, ContactsListAdministrationRedirectModalComponent} from './contact/list/contacts-list-administration.component';
-import { ContactsCustomFieldsAdministrationComponent }              from './contact/customField/contacts-custom-fields-administration.component';
-import { ContactsPageAdministrationComponent }              from './contact/page/contacts-page-administration.component';
-import { TagsAdministrationComponent }              from './tag/tags-administration.component';
-import { TagAdministrationComponent }              from './tag/tag-administration.component';
+import { AdministrationComponent } from './home/administration.component';
+import { UsersAdministrationComponent, UsersAdministrationRedirectModalComponent } from './user/users-administration.component';
+import { AccountLinkComponent } from './user/account-link/account-link.component';
+import { GroupsAdministrationComponent, GroupsAdministrationRedirectModalComponent } from './group/groups-administration.component';
+import { UserAdministrationComponent, UserAdministrationRedirectModalComponent } from './user/user-administration.component';
+import { GroupAdministrationComponent } from './group/group-administration.component';
+import { IndexingAdministrationComponent } from './group/indexing/indexing-administration.component';
+import { BasketsAdministrationComponent } from './basket/baskets-administration.component';
+import { BasketAdministrationComponent, BasketAdministrationSettingsModalComponent, BasketAdministrationGroupListModalComponent } from './basket/basket-administration.component';
+import { EntitiesAdministrationComponent, EntitiesAdministrationRedirectModalComponent } from './entity/entities-administration.component';
+import { DiffusionModelsAdministrationComponent } from './diffusionModel/diffusionModels-administration.component';
+import { DiffusionModelAdministrationComponent } from './diffusionModel/diffusionModel-administration.component';
+import { DoctypesAdministrationComponent, DoctypesAdministrationRedirectModalComponent } from './doctype/doctypes-administration.component';
+import { StatusesAdministrationComponent } from './status/statuses-administration.component';
+import { StatusAdministrationComponent } from './status/status-administration.component';
+import { ActionsAdministrationComponent } from './action/actions-administration.component';
+import { ActionAdministrationComponent } from './action/action-administration.component';
+import { ParametersAdministrationComponent } from './parameter/parameters-administration.component';
+import { ParameterAdministrationComponent } from './parameter/parameter-administration.component';
+import { PrioritiesAdministrationComponent } from './priority/priorities-administration.component';
+import { PriorityAdministrationComponent } from './priority/priority-administration.component';
+import { HistoryAdministrationComponent } from './history/history-administration.component';
+import { HistoryBatchAdministrationComponent } from './history/batch/history-batch-administration.component';
+import { UpdateStatusAdministrationComponent } from './updateStatus/update-status-administration.component';
+import { NotificationsAdministrationComponent } from './notification/notifications-administration.component';
+import { NotificationAdministrationComponent } from './notification/notification-administration.component';
+import { ContactsGroupsAdministrationComponent } from './contact/group/contacts-groups-administration.component';
+import { ContactsGroupAdministrationComponent } from './contact/group/contacts-group-administration.component';
+import { ContactsParametersAdministrationComponent } from './contact/parameter/contacts-parameters-administration.component';
+import { VersionsUpdateAdministrationComponent } from './versionUpdate/versions-update-administration.component';
+import { DocserversAdministrationComponent } from './docserver/docservers-administration.component';
+import { DocserverAdministrationComponent } from './docserver/docserver-administration.component';
+import { TemplatesAdministrationComponent } from './template/templates-administration.component';
+import { TemplateAdministrationComponent, TemplateAdministrationCheckEntitiesModalComponent } from './template/template-administration.component';
+import { SecuritiesAdministrationComponent } from './security/securities-administration.component';
+import { SendmailAdministrationComponent } from './sendmail/sendmail-administration.component';
+import { ListAdministrationComponent } from './basket/list/list-administration.component';
+import { ShippingsAdministrationComponent } from './shipping/shippings-administration.component';
+import { ShippingAdministrationComponent } from './shipping/shipping-administration.component';
+import { CustomFieldsAdministrationComponent } from './customField/custom-fields-administration.component';
+import { IndexingModelAdministrationComponent } from './indexingModel/indexing-model-administration.component';
+import { IndexingModelsAdministrationComponent } from './indexingModel/indexing-models-administration.component';
+import { ContactsListAdministrationComponent, ContactsListAdministrationRedirectModalComponent } from './contact/list/contacts-list-administration.component';
+import { ContactsCustomFieldsAdministrationComponent } from './contact/customField/contacts-custom-fields-administration.component';
+import { ContactsPageAdministrationComponent } from './contact/page/contacts-page-administration.component';
+import { TagsAdministrationComponent } from './tag/tags-administration.component';
+import { TagAdministrationComponent } from './tag/tag-administration.component';
+import { TemplateFileEditorModalComponent } from './template/templateFileEditorModal/template-file-editor-modal.component';
+
+
 
 @NgModule({
-    imports:      [
+    imports: [
         SharedModule,
         NgxChartsModule,
         AdministrationRoutingModule
@@ -115,7 +118,8 @@ import { TagAdministrationComponent }              from './tag/tag-administratio
         ContactsCustomFieldsAdministrationComponent,
         ContactsPageAdministrationComponent,
         TagsAdministrationComponent,
-        TagAdministrationComponent
+        TagAdministrationComponent,
+        TemplateFileEditorModalComponent
     ],
     entryComponents: [
         UsersAdministrationRedirectModalComponent,
@@ -127,7 +131,8 @@ import { TagAdministrationComponent }              from './tag/tag-administratio
         DoctypesAdministrationRedirectModalComponent,
         ContactsListAdministrationRedirectModalComponent,
         TemplateAdministrationCheckEntitiesModalComponent,
-        AccountLinkComponent
+        AccountLinkComponent,
+        TemplateFileEditorModalComponent
     ],
 })
-export class AdministrationModule {}
+export class AdministrationModule { }
diff --git a/src/frontend/app/administration/template/template-administration.component.html b/src/frontend/app/administration/template/template-administration.component.html
index 1f872f92436..3a3b3f93f49 100755
--- a/src/frontend/app/administration/template/template-administration.component.html
+++ b/src/frontend/app/administration/template/template-administration.component.html
@@ -2,8 +2,8 @@
     <ng-template #adminMenuTemplate>
         <mat-nav-list *ngIf="!creationMode && !loading">
             <h3 mat-subheader>{{lang.actions}}</h3>
-            <a mat-list-item [disableRipple]="lockFound || template.template_target == 'acknowledgementReceipt'"
-                [class.disabled]="lockFound || template.template_target == 'acknowledgementReceipt'"
+            <a mat-list-item [disableRipple]="lockFound || template.target == 'acknowledgementReceipt'"
+                [class.disabled]="lockFound || template.target == 'acknowledgementReceipt'"
                 (click)="duplicateTemplate()">
                 <mat-icon color="primary" mat-list-icon class="fa fa-copy"></mat-icon>
                 <p mat-line>
@@ -36,19 +36,19 @@
                             <div class="form-group">
                                 <div class="col-sm-12">
                                     <mat-form-field>
-                                        <input matInput [(ngModel)]="template.template_label" required
-                                            name="template_label" id="template_label" title="{{lang.templateName}}"
-                                            type="text" placeholder="{{lang.templateName}}" maxlength="255">
+                                        <input matInput name="label" [(ngModel)]="template.label"
+                                            title="{{lang.templateName}}" type="text"
+                                            placeholder="{{lang.templateName}}" maxlength="255" required>
                                     </mat-form-field>
                                 </div>
                             </div>
                             <div class="form-group">
                                 <div class="col-sm-12">
                                     <mat-form-field>
-                                        <textarea matInput [(ngModel)]="template.template_comment" required
-                                            name="template_comment" id="template_comment"
-                                            placeholder="{{lang.description}}" title="{{lang.description}}"
-                                            matTextareaAutosize matAutosizeMinRows="2" matAutosizeMaxRows="5">
+                                        <textarea matInput name="description" [(ngModel)]="template.description"
+                                            name="template_comment" placeholder="{{lang.description}}"
+                                            title="{{lang.description}}" matTextareaAutosize matAutosizeMinRows="2"
+                                            matAutosizeMaxRows="5" required>
                                     </textarea>
                                     </mat-form-field>
                                 </div>
@@ -56,21 +56,17 @@
                             <div class="form-group">
                                 <div class="col-sm-12">
                                     <mat-form-field>
-                                        <mat-select [disabled]="!creationMode" id="template_target" required
-                                            name="template_target" title="{{lang.templateTarget}}"
-                                            placeholder="{{lang.templateTarget}}" [(ngModel)]="template.template_target"
-                                            (ngModelChange)="updateTemplateType()">
-                                            <mat-option value="acknowledgementReceipt">{{lang.acknowledgementReceipt}}</mat-option>
-                                            <mat-option value="notes">{{lang.notes}}</mat-option>
-                                            <mat-option value="sendmail">{{lang.sendmail}}</mat-option>
-                                            <mat-option value="indexingFile">{{lang.indexingFile}}</mat-option>
-                                            <mat-option value="notifications">{{lang.notifications}}</mat-option>
-                                            <mat-option value="attachments">{{lang.attachments}}</mat-option>
+                                        <mat-select [disabled]="!creationMode" name="target" required
+                                            title="{{lang.templateTarget}}" placeholder="{{lang.templateTarget}}"
+                                            [(ngModel)]="template.target"
+                                            (selectionChange)="updateTemplateType($event)">
+                                            <mat-option *ngFor="let target of targetTypes" [value]="target">
+                                                {{lang[target]}}</mat-option>
                                         </mat-select>
                                     </mat-form-field>
                                 </div>
                             </div>
-                            <div class="form-group" *ngIf="template.template_target == 'attachments'">
+                            <div class="form-group" *ngIf="template.target == 'attachments'">
                                 <div class="col-sm-12">
                                     <mat-form-field>
                                         <mat-select id="template_attachment_type" name="template_attachment_type"
@@ -85,7 +81,7 @@
                                 </div>
                             </div>
 
-                            <div class="form-group" *ngIf="template.template_target == 'acknowledgementReceipt'">
+                            <div class="form-group" *ngIf="template.target == 'acknowledgementReceipt'">
                                 <div class="col-sm-12">
                                     <mat-form-field>
                                         <mat-select [disabled]="!creationMode" id="template_attachment_type"
@@ -100,48 +96,40 @@
                                 </div>
                             </div>
 
-                            <div class="form-group"
-                                [hidden]="template.template_target=='attachments' || template.template_target=='notifications' || template.template_target=='doctypes' || template.template_target=='notes' || template.template_target=='acknowledgementReceipt'">
+                            <div class="form-group" *ngIf="availableTypes.length > 1">
                                 <div class="col-sm-12">
-                                    <mat-radio-group [disabled]="!creationMode" required name="template_type"
-                                        [(ngModel)]="template.template_type">
-                                        <mat-radio-button style="margin-left:10px" color="primary" name="template_type"
-                                            value="OFFICE" [checked]="template.template_type=='OFFICE'"
-                                            *ngIf="template.template_target=='attachments' || template.template_target==''">
-                                            {{lang.office}}</mat-radio-button>
-                                        <mat-radio-button style="margin-left:10px" color="primary" name="template_type"
-                                            value="HTML" [checked]="template.template_type=='HTML'"
-                                            *ngIf="template.template_target=='sendmail' || template.template_target=='doctypes' || template.template_target == 'notifications' || template.template_target == ''"
-                                            (click)="initMce('textarea#templateHtml')">{{lang.html}}</mat-radio-button>
-                                        <mat-radio-button style="margin-left:10px" color="primary" name="template_type"
-                                            value="TXT" [checked]="template.template_type=='TXT'"
-                                            *ngIf="template.template_target=='sendmail' || template.template_target=='notes' || template.template_target == ''">
-                                            {{lang.txt}}</mat-radio-button>
+                                    <mat-radio-group [disabled]="!creationMode" required name="type"
+                                        (change)="changeType($event)">
+                                        <mat-radio-button style="margin-left:10px" color="primary" name="type"
+                                            *ngFor="let type of availableTypes" [value]="type"
+                                            [checked]="template.type===type">
+                                            {{type}}</mat-radio-button>
                                     </mat-radio-group>
                                 </div>
                             </div>
-                            <div class="form-group" *ngIf="template.template_type=='OFFICE'">
+                            <div class="form-group" *ngIf="template.type=='OFFICE'">
                                 <div class="col-md-12" style="display: none;">
                                     <div class="form-inline hide">
                                         <div class="form-group">
-                                            <input type="file" name="files[]" id="uploadSignFileOffice"
+                                            <input type="file" name="files[]" #uploadSignFileOffice
                                                 (change)="uploadFileTrigger($event)"
                                                 accept="application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml‌.slideshow,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.spreadsheet">
                                         </div>
                                     </div>
                                 </div>
                                 <div class="col-sm-12">
-                                    <mat-form-field *ngIf="creationMode || template.template_style">
+                                    <mat-form-field *ngIf="creationMode || template.file.name">
                                         <mat-select id="template_style" [disabled]="!creationMode" name="template_style"
                                             title="{{lang.defaultTemplate}}" placeholder="{{lang.chosenModel}}"
-                                            [(ngModel)]="template.template_style" (ngModelChange)="resetFileUploaded()"
-                                            [required]="template.template_target!='acknowledgementReceipt'">
+                                            [(ngModel)]="selectedModelFile"
+                                            [required]="template.target!='acknowledgementReceipt'">
                                             <mat-optgroup label="{{lang.loadedFile}} :">
                                                 <mat-option class="selectFile"
-                                                    (click)="clickOnUploader('uploadSignFileOffice')"
-                                                    value="uploadFile">
+                                                    (click)="uploadSignFileOffice.click()"
+                                                    [value]="template.file.name">
                                                     <mat-icon class="fa fa-paperclip" color="primary"
-                                                        style="height:auto;"></mat-icon> {{buttonFileName}}
+                                                        style="height:auto;"></mat-icon>
+                                                    {{!functionsService.empty(template.file) && !functionsService.empty(template.file.name) ? template.file.name : lang.importFile}}
                                                 </mat-option>
                                             </mat-optgroup>
                                             <ng-container *ngFor="let extension of extensionModels">
@@ -157,43 +145,45 @@
                                         </mat-select>
                                     </mat-form-field>
                                     <button mat-raised-button color="default" type="button"
-                                        (click)="$event.stopPropagation();startJnlp()"
-                                        *ngIf="((creationMode && template.template_style != 'uploadFile' && template.template_style) || (!creationMode))"
+                                        (click)="$event.stopPropagation();editFile()"
+                                        *ngIf="((creationMode && selectedModelFile) || (!creationMode))"
                                         [disabled]="lockFound">{{lang.templateEdition}}</button>
                                     <button mat-raised-button color="default" type="button"
-                                        (click)="$event.stopPropagation();clickOnUploader('uploadSignFileOffice')"
-                                        *ngIf="((creationMode && template.template_style && template.template_style == 'uploadFile') || (!creationMode))"
+                                        (click)="$event.stopPropagation();uploadSignFileOffice.click()"
+                                        *ngIf="((creationMode && !selectedModelFile) || (!creationMode))"
                                         [disabled]="lockFound">{{lang.importFile}}</button>
                                 </div>
+                                <iframe *ngIf="templateDocView !== null" [src]="templateDocView"
+                                    style="width:100%;height:800px;"></iframe>
+                                <!--<app-document-viewer *ngIf="templateDocView !== null" #appDocumentViewer [editMode]="false" [base64]="templateDocView" style="height:100%;width:100%;"></app-document-viewer>-->
                             </div>
-                            <div class="form-group" *ngIf="template.template_type=='TXT'">
+                            <div class="form-group" *ngIf="template.type=='TXT'">
                                 <div class="col-sm-12">
                                     <mat-form-field>
-                                        <textarea matInput [(ngModel)]="template.template_content" name="templateTxt"
+                                        <textarea matInput [(ngModel)]="template.file.content" name="templateTxt"
                                             id="templateTxt" placeholder="{{lang.contentTxtTemplate}}"
                                             title="{{lang.contentTxtTemplate}}" matTextareaAutosize
                                             matAutosizeMinRows="5" matAutosizeMaxRows="5"
-                                            [required]="template.template_target!='acknowledgementReceipt'">
+                                            [required]="template.target!='acknowledgementReceipt'">
                                     </textarea>
                                     </mat-form-field>
                                 </div>
                             </div>
-                            <div class="form-group" *ngIf="template.template_type=='HTML'">
+                            <div class="form-group" *ngIf="template.type=='HTML'">
                                 <div class="col-sm-12">
                                     <div id="html_mode" style="display: block; width:100%;">
-                                        <textarea [(ngModel)]="template.template_content" name="templateHtml"
+                                        <textarea [(ngModel)]="template.file.content" name="templateHtml"
                                             id="templateHtml" style="width:100%" rows="15" cols="60"
-                                            [required]="template.template_target!='acknowledgementReceipt'"></textarea>
+                                            [required]="template.target!='acknowledgementReceipt'"></textarea>
                                     </div>
                                 </div>
                             </div>
-                            <div class="form-group" *ngIf="template.template_target=='notifications'">
+                            <div class="form-group" *ngIf="template.target=='notifications'">
                                 <div class="col-sm-12">
                                     <mat-form-field>
-                                        <mat-select id="template_datasource" name="template_datasource"
+                                        <mat-select id="datasource" name="datasource"
                                             title="{{lang.templateDatasource}}"
-                                            placeholder="{{lang.templateDatasource}}"
-                                            [(ngModel)]="template.template_datasource">
+                                            placeholder="{{lang.templateDatasource}}" [(ngModel)]="template.datasource">
                                             <mat-option value="">{{lang.noDatasource}}</mat-option>
                                             <ng-container *ngFor="let datasource of datasourcesList">
                                                 <mat-option *ngIf="displayDatasources(datasource)"
@@ -204,15 +194,15 @@
                                 </div>
                             </div>
 
-                            <div class="form-group" *ngIf="template.template_type=='OFFICE_HTML'">
+                            <div class="form-group" *ngIf="template.type=='OFFICE_HTML'">
                                 <mat-tab-group (selectedTabChange)="loadTab($event);">
                                     <mat-tab label="{{lang.electronicTemplate}}">
                                         <div class="col-sm-12">
                                             <div id="html_mode" style="display: block; width:100%;">
-                                                <textarea [(ngModel)]="template.template_content"
+                                                <textarea [(ngModel)]="template.file.electronic.content"
                                                     name="templateOfficeHtml" id="templateOfficeHtml" style="width:100%"
                                                     rows="15" cols="60"
-                                                    [required]="template.template_target!='acknowledgementReceipt'"></textarea>
+                                                    [required]="template.target!='acknowledgementReceipt'"></textarea>
                                             </div>
                                         </div>
                                     </mat-tab>
@@ -220,7 +210,7 @@
                                         <div class="col-md-12" style="display: none;">
                                             <div class="form-inline hide">
                                                 <div class="form-group">
-                                                    <input type="file" name="files[]" id="uploadSignFileOfficeHtml"
+                                                    <input type="file" name="files[]" #uploadSignFileOfficeHtml
                                                         (change)="uploadFileTrigger($event)"
                                                         accept="application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel,application/vnd.ms-powerpoint,application/vnd.openxmlformats-officedocument.presentationml‌.slideshow,application/vnd.oasis.opendocument.text,application/vnd.oasis.opendocument.presentation,application/vnd.oasis.opendocument.spreadsheet">
                                                 </div>
@@ -229,18 +219,18 @@
                                         <div class="col-sm-12">
                                             <mat-form-field>
                                                 <mat-select id="template_style"
-                                                    [disabled]="!creationMode && template.template_file_name != null"
+                                                    [disabled]="!creationMode && template.file.paper.name !== null"
                                                     name="template_style" title="{{lang.defaultTemplate}}"
                                                     placeholder="{{lang.chosenModel}}"
-                                                    [(ngModel)]="template.template_style"
+                                                    [(ngModel)]="selectedModelFile"
                                                     (ngModelChange)="resetFileUploaded()"
-                                                    [required]="template.template_target!='acknowledgementReceipt'">
+                                                    [required]="template.target!='acknowledgementReceipt'">
                                                     <mat-optgroup label="{{lang.loadedFile}} :">
                                                         <mat-option
-                                                            (click)="clickOnUploader('uploadSignFileOfficeHtml')"
-                                                            style="text-align: center;" value="uploadFile">
+                                                            (click)="uploadSignFileOfficeHtml.click()"
+                                                            style="text-align: center;" [value]="template.file.paper.name">
                                                             <mat-icon class="fa fa-paperclip" color="primary"
-                                                                style="height:auto;"></mat-icon> {{buttonFileName}}
+                                                                style="height:auto;"></mat-icon> {{!functionsService.empty(template.file.paper) && !functionsService.empty(template.file.paper.name) ? template.file.paper.name : lang.importFile}}
                                                         </mat-option>
                                                     </mat-optgroup>
                                                     <ng-container *ngFor="let extension of extensionModels">
@@ -256,14 +246,16 @@
                                                 </mat-select>
                                             </mat-form-field>
                                             <button mat-raised-button color="default" type="button"
-                                                (click)="$event.stopPropagation();startJnlp()"
-                                                *ngIf="template.template_file_name != null || (template.template_style != 'uploadFile' && template.template_style)"
+                                                (click)="$event.stopPropagation();editFile()"
+                                                *ngIf="((creationMode && selectedModelFile) || (!creationMode))"
                                                 [disabled]="lockFound">{{lang.templateEdition}}</button>
                                             <button mat-raised-button color="default" type="button"
-                                                (click)="$event.stopPropagation();clickOnUploader('uploadSignFileOfficeHtml')"
-                                                *ngIf="template.template_file_name != null || (template.template_style && template.template_style == 'uploadFile')"
+                                                (click)="$event.stopPropagation();uploadSignFileOfficeHtml.click()"
+                                                *ngIf="!selectedModelFile || !creationMode"
                                                 [disabled]="lockFound">{{lang.importFile}}</button>
                                         </div>
+                                        <iframe *ngIf="templateDocView !== null" [src]="templateDocView"
+                                            style="width:100%;height:800px;"></iframe>
                                     </mat-tab>
                                 </mat-tab-group>
                             </div>
@@ -293,4 +285,4 @@
             </div>
         </mat-list>
     </mat-sidenav>
-</mat-sidenav-container>
+</mat-sidenav-container>
\ No newline at end of file
diff --git a/src/frontend/app/administration/template/template-administration.component.ts b/src/frontend/app/administration/template/template-administration.component.ts
index 16bdf237f7c..d1fcad0c671 100755
--- a/src/frontend/app/administration/template/template-administration.component.ts
+++ b/src/frontend/app/administration/template/template-administration.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, NgZone, ViewChild, Inject, TemplateRef, ViewContainerRef } from '@angular/core';
+import { Component, OnInit, ViewChild, Inject, TemplateRef, ViewContainerRef } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import { Router, ActivatedRoute } from '@angular/router';
 import { LANG } from '../../translate.component';
@@ -7,6 +7,12 @@ import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dial
 import { MatSidenav } from '@angular/material/sidenav';
 import { HeaderService } from '../../../service/header.service';
 import { AppService } from '../../../service/app.service';
+import { filter, tap, catchError } from 'rxjs/operators';
+import { FunctionsService } from '../../../service/functions.service';
+import { of } from 'rxjs/internal/observable/of';
+import { TemplateFileEditorModalComponent } from './templateFileEditorModal/template-file-editor-modal.component';
+import { DomSanitizer } from '@angular/platform-browser';
+import { AlertComponent } from '../../../plugins/modal/alert.component';
 
 declare var tinymce: any;
 
@@ -24,7 +30,45 @@ export class TemplateAdministrationComponent implements OnInit {
     loading: boolean = false;
 
     creationMode: boolean;
-    template: any = {};
+
+    template: any = {
+        label: '',
+        description: '',
+        datasource: 'letterbox_attachment',
+        target: '',
+        type: '',
+        file: null
+    };
+
+    targetTypes: string[] = [
+        'acknowledgementReceipt',
+        'notes',
+        'sendmail',
+        'indexingFile',
+        'notifications',
+        'attachments'
+    ];
+
+    allowedExtensions: string[] = [
+        'doc',
+        'docx',
+        'dotx',
+        'odt',
+        'ott',
+        'rtf',
+        'txt',
+        'html',
+        'xlsl',
+        'xlsx',
+        'xltx',
+        'ods',
+        'ots',
+        'csv',
+    ];
+
+    selectedModelFile: any = null;
+    availableTypes: string[] = [];
+
     statuses: any[] = [];
     categoriesList: any[] = [];
     keywordsList: any[] = [];
@@ -37,6 +81,8 @@ export class TemplateAdministrationComponent implements OnInit {
     lockFound: boolean = false;
     intervalLockFile: any;
 
+    templateDocView: any = null;
+
     dialogRef: MatDialogRef<any>;
     data: any[] = [];
     config: any = {};
@@ -44,19 +90,16 @@ export class TemplateAdministrationComponent implements OnInit {
 
     constructor(
         public http: HttpClient,
-        private zone: NgZone,
+        private sanitizer: DomSanitizer,
         private route: ActivatedRoute,
         private router: Router,
         private notify: NotificationService,
         private headerService: HeaderService,
         public dialog: MatDialog,
         public appService: AppService,
-        private viewContainerRef: ViewContainerRef
-    ) {
-        window['angularTemplateComponent'] = {
-            componentAfterUpload: (base64Content: any) => this.processAfterUpload(base64Content)
-        };
-    }
+        private viewContainerRef: ViewContainerRef,
+        private functionsService: FunctionsService
+    ) { }
 
     ngOnInit(): void {
         this.loading = true;
@@ -71,8 +114,6 @@ export class TemplateAdministrationComponent implements OnInit {
                 this.http.get('../../rest/administration/templates/new')
                     .subscribe((data: any) => {
                         this.setInitialValue(data);
-                        this.template.template_target = '';
-                        this.template.template_type = 'OFFICE';
                         this.loading = false;
 
                     });
@@ -82,24 +123,36 @@ export class TemplateAdministrationComponent implements OnInit {
                 this.http.get('../../rest/templates/' + params['id'] + '/details')
                     .subscribe((data: any) => {
                         this.setInitialValue(data);
-                        this.template = data.template;
+                        this.template = {
+                            label: data.template.template_label,
+                            description: data.template.template_comment,
+                            datasource: data.template.template_datasource,
+                            target: data.template.template_target,
+                            type: data.template.template_type,
+                            file: {}
+                        };
+                        this.updateTemplateType();
+
+                        this.selectedModelFile = data.template.template_file_name;
+                        if (this.template.type === 'HTML' || this.template.type === 'TXT') {
+                            this.template.file.content = data.template.template_content;
+                        } else if (this.template.type === 'OFFICE') {
+                            this.template.file.format = data.template.template_file_name.split('.').pop();
+                            this.template.file.name = data.template.template_file_name;
+                        } else if (this.template.target === 'acknowledgementReceipt') {
+                            this.template.file.paper.format = data.template.template_file_name.split('.').pop();
+                            this.template.file.paper.name = data.template.template_file_name;
+                            this.template.file.electronic.content = data.template.template_content;
+                            this.template.template_attachment_type = data.template.template_attachment_type;
+                        }
+
                         this.headerService.setHeader(this.lang.templateModification, this.template.template_label);
                         this.loading = false;
-                        if (this.template.template_type === 'HTML') {
-                            this.initMce('textarea#templateHtml');
-                        }
-                        if (this.template.template_type === 'OFFICE_HTML') {
-                            this.initMce('textarea#templateOfficeHtml');
-                        }
-                        if (this.template.template_style === '' && this.template.template_file_name != null) {
-                            this.buttonFileName = this.template.template_file_name;
-                        } else if (this.template.template_style !== '') {
-                            this.buttonFileName = this.template.template_style;
-                        }
 
-                        if (this.template.template_style === '') {
-                            this.template.template_style = 'uploadFile';
-                        }
+                        console.log(this.selectedModelFile);
+                        console.log(this.template);
+                        console.log(data);
+
                     });
             }
             if (!this.template.template_attachment_type) {
@@ -121,7 +174,6 @@ export class TemplateAdministrationComponent implements OnInit {
                 language_url: `../../node_modules/tinymce-i18n/langs/${this.lang.langISO.replace('-', '_')}.js`,
                 height: '200',
                 plugins: [
-                    'textcolor',
                     'autoresize',
                     'code'
                 ],
@@ -140,11 +192,11 @@ export class TemplateAdministrationComponent implements OnInit {
                 theme_styles: 'Header 1=header1;Header 2=header2;Header 3=header3;Table Row=tableRow1',
                 setup: (ed: any) => {
                     ed.on('keyup', (e: any) => {
-                        if (this.template.template_type === 'HTML' && tinymce.get('templateHtml') != null) {
-                            this.template.template_content = tinymce.get('templateHtml').getContent();
+                        if (this.template.type === 'HTML' && tinymce.get('templateHtml') != null) {
+                            this.template.file.content = tinymce.get('templateHtml').getContent();
                         }
-                        if (this.template.template_type === 'OFFICE_HTML' && tinymce.get('templateOfficeHtml') != null) {
-                            this.template.template_content = tinymce.get('templateOfficeHtml').getContent();
+                        if (this.template.type === 'OFFICE_HTML' && tinymce.get('templateOfficeHtml') != null) {
+                            this.template.file.electronic.content = tinymce.get('templateOfficeHtml').getContent();
                         }
                     });
                 }
@@ -194,81 +246,189 @@ export class TemplateAdministrationComponent implements OnInit {
         }, 0);
     }
 
-    clickOnUploader(id: string) {
-        $('#' + id).click();
+    getBase64Document(buffer: ArrayBuffer) {
+        const TYPED_ARRAY = new Uint8Array(buffer);
+        const STRING_CHAR = TYPED_ARRAY.reduce((data, byte) => {
+            return data + String.fromCharCode(byte);
+        }, '');
+
+        return btoa(STRING_CHAR);
     }
 
     uploadFileTrigger(fileInput: any) {
-        this.template.jnlpUniqueId = null;
-        if (fileInput.target.files && fileInput.target.files[0]) {
-            this.template.uploadedFile = {};
-            this.template.uploadedFile.name = fileInput.target.files[0].name;
-            this.template.uploadedFile.size = fileInput.target.files[0].size;
-            this.template.uploadedFile.type = fileInput.target.files[0].type;
-            if (this.template.uploadedFile.label === '') {
-                this.template.uploadedFile.label = this.template.uploadedFile.name;
-            }
+        if (fileInput.target.files && fileInput.target.files[0] && this.isExtensionAllowed(fileInput.target.files[0])) {
 
             const reader = new FileReader();
-            reader.readAsDataURL(fileInput.target.files[0]);
 
-            reader.onload = function (value: any) {
-                window['angularTemplateComponent'].componentAfterUpload(value.target.result);
+            if (this.template.target === 'acknowledgementReceipt') {
+                this.template.file.paper = {
+                    name: '',
+                    type: '',
+                    content: ''
+                };
+                this.template.file.paper.name = fileInput.target.files[0].name;
+                this.selectedModelFile = this.template.file.paper.name;
+                this.template.file.paper.type = fileInput.target.files[0].type;
+                this.template.file.paper.format = this.template.file.paper.name.split('.').pop();
+            } else {
+                this.template.file = {
+                    name: '',
+                    type: '',
+                    content: ''
+                };
+                this.template.file.name = fileInput.target.files[0].name;
+                this.selectedModelFile = this.template.file.name;
+                this.template.file.type = fileInput.target.files[0].type;
+                this.template.file.format = this.template.file.name.split('.').pop();
+            }
+
+            reader.readAsArrayBuffer(fileInput.target.files[0]);
+
+            reader.onload = (value: any) => {
+                if (this.template.target === 'acknowledgementReceipt') {
+                    this.template.file.paper.content = this.getBase64Document(value.target.result);
+                } else {
+                    this.template.file.content = this.getBase64Document(value.target.result);
+                }
+
+                this.getViewTemplateFile();
             };
         }
     }
 
-    processAfterUpload(b64Content: any) {
-        this.zone.run(() => this.resfreshUpload(b64Content));
-    }
+    isExtensionAllowed(file: any) {
+        const fileExtension = file.name.toLowerCase().split('.').pop();
 
-    resfreshUpload(b64Content: any) {
-        this.template.uploadedFile.base64 = b64Content.replace(/^data:.*?;base64,/, '');
-        this.template.template_style = 'uploadFile';
-        this.fileImported();
+        if (this.allowedExtensions.filter(ext => ext.toLowerCase() === fileExtension.toLowerCase()).length === 0) {
+            this.dialog.open(AlertComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.lang.notAllowedExtension + ' !', msg: this.lang.file + ' : <b>' + file.name + '</b>, ' + this.lang.type + ' : <b>' + file.type + '</b><br/><br/><u>' + this.lang.allowedExtensions + '</u> : <br/>' + this.allowedExtensions.filter((elem: any, index: any, self: any) => index === self.indexOf(elem)).join(', ') } });
+            return false;
+        } else {
+            return true;
+        }
     }
 
-    startJnlp() {
-        if (this.creationMode || (this.template.template_file_name == null && this.template.template_path == null)) {
-            this.jnlpValue.objectType = 'templateCreation';
+    editFile() {
+        const editorOptions: any = {};
+
+        if (this.creationMode || ((this.template.target !== 'acknowledgementReceipt' && this.functionsService.empty(this.template.file.name) || (this.template.target === 'acknowledgementReceipt' && this.functionsService.empty(this.template.file.paper.name))))) {
             for (const element of this.defaultTemplatesList) {
-                if (this.template.template_style === element.fileExt + ': ' + element.fileName) {
-                    this.jnlpValue.objectId = element.filePath;
+                if (this.selectedModelFile === element.fileExt + ': ' + element.fileName) {
+                    editorOptions.objectId = element.filePath;
                 }
             }
+            editorOptions.objectType = 'templateCreation';
+            editorOptions.docUrl = `rest/onlyOffice/mergedFile`;
+            editorOptions.extension = editorOptions.objectId.toLowerCase().split('.').pop();
+
         } else {
-            this.jnlpValue.objectType = 'templateModification';
-            this.jnlpValue.objectId = this.template.template_id;
+            editorOptions.objectType = 'templateModification';
+            editorOptions.objectId = this.template.template_id;
+            editorOptions.extension = this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.name : this.template.file.name;
+        }
+
+        if (this.headerService.user.preferences.documentEdition === 'java') {
+            this.launchJavaEditor(editorOptions);
+        } else if (this.headerService.user.preferences.documentEdition === 'onlyoffice') {
+            this.launchOOEditor(editorOptions);
         }
-        this.jnlpValue.table = 'templates';
-        this.jnlpValue.uniqueId = 0;
-        this.jnlpValue.cookies = document.cookie;
-
-        this.http.post('../../rest/jnlp', this.jnlpValue)
-            .subscribe((data: any) => {
-                this.template.jnlpUniqueId = data.jnlpUniqueId;
-                this.fileToImport();
+    }
+
+    launchJavaEditor(params: any) {
+        this.http.post('../../rest/jnlp', params).pipe(
+            tap((data: any) => {
                 window.location.href = '../../rest/jnlp/' + data.generatedJnlp;
-                this.checkLockFile();
-            }, (err) => {
-                this.notify.error(err.error.errors);
-            });
+                this.checkLockFile(data.jnlpUniqueId, params.extension);
+            }),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    launchOOEditor(params: any) {
+        this.dialogRef = this.dialog.open(
+            TemplateFileEditorModalComponent,
+            {
+                autoFocus: false,
+                panelClass: 'maarch-full-height-modal',
+                minWidth: '80%',
+                disableClose: true,
+                data: {
+                    title: this.template.template_style,
+                    editorOptions: params,
+                    file: { format: params.extension }
+                }
+            }
+        );
+        this.dialogRef.afterClosed().pipe(
+            filter((data: string) => !this.functionsService.empty(data)),
+            tap((data: any) => {
+                if (this.template.target === 'acknowledgementReceipt') {
+                    this.template.file.paper.name = this.selectedModelFile;
+                    this.template.file.paper.format = params.extension;
+                    this.template.file.paper.content = data.content;
+                } else {
+                    this.template.file.name = this.selectedModelFile;
+                    this.template.file.format = params.extension;
+                    this.template.file.content = data.content;
+                }
+                this.getViewTemplateFile();
+            }),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    getViewTemplateFile() {
+
+        this.http.post('../../rest/convertedFile/encodedFile', { encodedFile: this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.content : this.template.file.content, format: this.template.target === 'acknowledgementReceipt' ? this.template.file.paper.format : this.template.file.format }).pipe(
+            tap((data: any) => {
+                this.templateDocView = this.sanitizer.bypassSecurityTrustResourceUrl('data:application/pdf;base64,' + data.encodedResource);
+            }),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+
     }
 
-    checkLockFile() {
+    checkLockFile(id: string, extension: string) {
         this.intervalLockFile = setInterval(() => {
-            this.http.get('../../rest/jnlp/lock/' + this.template.jnlpUniqueId)
-                .subscribe((data: any) => {
+            this.http.get('../../rest/jnlp/lock/' + id).pipe(
+                tap((data: any) => {
                     this.lockFound = data.lockFileFound;
                     if (!this.lockFound) {
                         clearInterval(this.intervalLockFile);
+                        this.loadTmpFile(`${data.fileTrunk}.${extension}`);
                     }
-                });
+                })
+            ).subscribe();
         }, 1000);
     }
 
+    loadTmpFile(filenameOnTmp: string) {
+        this.http.get(`../../rest/convertedFile/${filenameOnTmp}?convert=true`).pipe(
+            tap((data: any) => {
+                if (this.template.target === 'acknowledgementReceipt') {
+                    this.template.file.paper.name = this.selectedModelFile;
+                    this.template.file.paper.format = filenameOnTmp.toLowerCase().split('.').pop();
+                    this.template.file.paper.content = data.encodedResource;
+                } else {
+                    this.template.file.name = this.selectedModelFile;
+                    this.template.file.format = filenameOnTmp.toLowerCase().split('.').pop();
+                    this.template.file.content = data.encodedResource;
+                }
+                this.templateDocView = data.encodedConvertedResource;
+            })
+        ).subscribe();
+    }
+
     duplicateTemplate() {
-        if (!this.lockFound && this.template.template_target !== 'acknowledgementReceipt') {
+        if (!this.lockFound && this.template.target !== 'acknowledgementReceipt') {
             const r = confirm(this.lang.confirmDuplicate);
 
             if (r) {
@@ -284,127 +444,143 @@ export class TemplateAdministrationComponent implements OnInit {
     }
 
     onSubmit() {
-        this.template.entities = $('#jstree').jstree(true).get_checked([true]);
-        if (this.template.template_target !== 'notifications') {
-            this.template.template_datasource = 'letterbox_attachment';
-        }
+        this.formatTemplate();
 
-        if (this.template.template_type === 'HTML') {
+        /*this.template.entities = $('#jstree').jstree(true).get_checked([true]);
+        if (this.template.type === 'HTML') {
             this.template.template_content = tinymce.get('templateHtml').getContent();
 
-        } else if (this.template.template_type === 'OFFICE_HTML') {
+        } else if (this.template.type === 'OFFICE_HTML') {
             this.template.template_content = tinymce.get('templateOfficeHtml').getContent();
+        }*/
+
+        if (this.isValidTemplate()) {
+            if (this.creationMode) {
+                this.http.post('../../rest/templates', this.template)
+                    .subscribe((data: any) => {
+                        if (data.checkEntities) {
+                            this.config = {
+                                panelClass: 'maarch-modal',
+                                data: {
+                                    entitiesList: data.checkEntities,
+                                    template_attachment_type: this.template.template_attachment_type
+                                }
+                            };
+                            this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config);
+                        } else {
+                            this.router.navigate(['/administration/templates']);
+                            this.notify.success(this.lang.templateAdded);
+                        }
+                    }, (err) => {
+                        this.notify.error(err.error.errors);
+                    });
+            } else {
+                this.http.put('../../rest/templates/' + this.template.template_id, this.template)
+                    .subscribe((data: any) => {
+                        if (data.checkEntities) {
+                            this.config = {
+                                panelClass: 'maarch-modal',
+                                data: {
+                                    entitiesList: data.checkEntities,
+                                    template_attachment_type: this.template.template_attachment_type
+                                }
+                            };
+                            this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config);
+                        } else {
+                            this.router.navigate(['/administration/templates']);
+                            this.notify.success(this.lang.templateUpdated);
+                        }
+                    }, (err) => {
+                        this.notify.error(err.error.errors);
+                    });
+            }
         }
 
-        if (this.template.template_target === 'acknowledgementReceipt') {
-            if (this.template.template_content === '' && (!this.template.template_style || (this.template.template_style && !this.template.jnlpUniqueId && !this.template.uploadedFile && !this.template.template_file_name))) {
+    }
+
+    formatTemplate() {
+        const template = { ...this.template };
+        console.log(template);
+
+    }
+
+    isValidTemplate() {
+        if (this.template.target === 'acknowledgementReceipt') {
+            if (this.functionsService.empty(this.template.file.paper.name) && this.functionsService.empty(this.template.file.electronic.content)) {
                 alert(this.lang.mustCompleteAR);
-                return;
+                return false;
             }
-        } else if (this.template.template_target !== 'acknowledgementReceipt' && this.template.template_type === 'OFFICE') {
-            if (!this.template.template_style || (this.template.template_style && !this.template.jnlpUniqueId && !this.template.template_file_name && !this.template.uploadedFile)) {
+        } else if (this.template.target !== 'acknowledgementReceipt' && this.template.type === 'OFFICE') {
+            if (this.functionsService.empty(this.template.file.name)) {
                 alert(this.lang.editModelFirst);
-                return;
+                return false;
             }
-        }
-
-        if (this.creationMode) {
-            if (this.template.template_style === 'uploadFile') {
-                this.template.template_style = '';
-            }
-            this.http.post('../../rest/templates', this.template)
-                .subscribe((data: any) => {
-                    if (data.checkEntities) {
-                        this.config = {
-                            panelClass: 'maarch-modal',
-                            data: {
-                                entitiesList: data.checkEntities,
-                                template_attachment_type: this.template.template_attachment_type
-                            }
-                        };
-                        this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config);
-                    } else {
-                        this.router.navigate(['/administration/templates']);
-                        this.notify.success(this.lang.templateAdded);
-                    }
-                }, (err) => {
-                    this.notify.error(err.error.errors);
-                });
         } else {
-            if (this.template.template_style === 'uploadFile') {
-                this.template.template_style = '';
-            }
-            this.http.put('../../rest/templates/' + this.template.template_id, this.template)
-                .subscribe((data: any) => {
-                    if (data.checkEntities) {
-                        this.config = {
-                            panelClass: 'maarch-modal',
-                            data: {
-                                entitiesList: data.checkEntities,
-                                template_attachment_type: this.template.template_attachment_type
-                            }
-                        };
-                        this.dialogRef = this.dialog.open(TemplateAdministrationCheckEntitiesModalComponent, this.config);
-                    } else {
-                        this.router.navigate(['/administration/templates']);
-                        this.notify.success(this.lang.templateUpdated);
-                    }
-                }, (err) => {
-                    this.notify.error(err.error.errors);
-                });
-        }
-    }
-
-    checkArMode() {
-        if (this.template.template_content === '' && !this.template.template_style && this.template.target === 'acknowledgementReceipt') {
-            alert(this.lang.mustCompleteAR);
             return true;
-        } else {
-            return false;
         }
     }
 
     displayDatasources(datasource: any) {
-        if (datasource.target === 'notification' && this.template.template_target === 'notifications') {
+        if (datasource.target === 'notification' && this.template.target === 'notifications') {
             return true;
-        } else if (datasource.target === 'document' && this.template.template_target !== 'notifications') {
+        } else if (datasource.target === 'document' && this.template.target !== 'notifications') {
             return true;
         }
         return false;
     }
 
     updateTemplateType() {
-        if (this.template.template_target === 'attachments' || this.template.template_target === 'indexingFile') {
-            this.template.template_type = 'OFFICE';
-        } else if (this.template.template_target === 'notifications' || this.template.template_target === 'doctypes' || this.template.template_target === 'sendmail') {
-            this.template.template_type = 'HTML';
+        this.template.file = {
+            name: '',
+            type: '',
+            content: ''
+        };
+
+        this.templateDocView = null;
+        if (['attachments', 'indexingFile'].indexOf(this.template.target) > -1) {
+            this.template.type = 'OFFICE';
+            this.availableTypes = ['OFFICE'];
+        } else if (['notifications', 'sendmail'].indexOf(this.template.target) > -1) {
+            this.template.type = 'HTML';
+            this.availableTypes = ['HTML', 'TXT'];
             this.initMce('textarea#templateHtml');
-        } else if (this.template.template_target === 'notes') {
-            this.template.template_type = 'TXT';
-        } else if (this.template.template_target === 'acknowledgementReceipt') {
-            this.template.template_type = 'OFFICE_HTML';
+        } else if (this.template.target === 'notes') {
+            this.template.type = 'TXT';
+            this.availableTypes = ['TXT'];
+        } else if (this.template.target === 'acknowledgementReceipt') {
+            this.template.file = {
+                electronic: {
+                    name: '',
+                    type: '',
+                    content: ''
+                },
+                paper: {
+                    name: '',
+                    type: '',
+                    content: ''
+                }
+            };
+            this.template.type = 'OFFICE_HTML';
+            this.availableTypes = [];
             this.template.template_attachment_type = '';
             this.initMce('textarea#templateOfficeHtml');
         }
     }
 
-    fileImported() {
-        this.buttonFileName = this.template.uploadedFile.name;
-    }
-
-    fileToImport() {
-        this.buttonFileName = this.lang.importFile;
-    }
-
-    resetFileUploaded() {
-        this.fileToImport();
-        this.template.uploadedFile = null;
+    changeType(ev: any) {
+        if (ev.value === 'HTML') {
+            this.initMce('textarea#templateHtml');
+        } else {
+            tinymce.remove('textarea');
+        }
+        this.template.type = ev.value;
     }
 
     loadTab(event: any) {
         if (event.index === 0) {
             this.initMce('textarea#templateOfficeHtml');
         } else {
+            tinymce.remove('textarea');
             if (this.template.template_file_name == null && this.template.template_style == null) {
                 this.buttonFileName = this.lang.importFile;
             }
diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html
new file mode 100644
index 00000000000..0d2a71e8664
--- /dev/null
+++ b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.html
@@ -0,0 +1,13 @@
+<div class="mat-dialog-content-container">
+    <mat-dialog-content style="padding: 0px;">
+        <onlyoffice-viewer #onlyofficeViewer style="height:100%;width:100%;" [hideCloseEditor]="true"
+            [params]="editorOptions" [file]="file" [editMode]="true" (triggerAfterUpdatedDoc)="close()"
+            (triggerCloseEditor)="dialogRef.close('');" (triggerModifiedDocument)="isDocModified = true"></onlyoffice-viewer>
+    </mat-dialog-content>
+    <span class="divider-modal"></span>
+    <div mat-dialog-actions class="actions">
+        <button mat-raised-button mat-button color="primary"
+            (click)="close()">{{lang.validate}}</button>
+        <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button>
+    </div>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.scss
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts
new file mode 100644
index 00000000000..04da26ed67a
--- /dev/null
+++ b/src/frontend/app/administration/template/templateFileEditorModal/template-file-editor-modal.component.ts
@@ -0,0 +1,36 @@
+import { Component, OnInit, Inject, ViewChild } from '@angular/core';
+import { LANG } from '../../../translate.component';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { take } from 'rxjs/internal/operators/take';
+import { tap } from 'rxjs/internal/operators/tap';
+import { EcplOnlyofficeViewerComponent } from '../../../../plugins/onlyoffice-api-js/onlyoffice-viewer.component';
+
+@Component({
+    templateUrl: 'template-file-editor-modal.component.html',
+    styleUrls: ['template-file-editor-modal.component.scss'],
+})
+export class TemplateFileEditorModalComponent implements OnInit {
+
+    lang: any = LANG;
+    loading: boolean = false;
+    editorOptions: any = null;
+    file: any = null;
+
+    @ViewChild('onlyofficeViewer', { static: true }) onlyofficeViewer: EcplOnlyofficeViewerComponent;
+
+    constructor(public dialogRef: MatDialogRef<TemplateFileEditorModalComponent>, @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+    ngOnInit(): void {
+        this.editorOptions = this.data.editorOptions;
+        this.file = this.data.file;
+    }
+
+    close() {
+        this.onlyofficeViewer.getFile().pipe(
+            take(1),
+            tap((data: any) => {
+                this.dialogRef.close(data);
+            })
+        ).subscribe();
+    }
+}
diff --git a/src/frontend/app/viewer/document-viewer.component.ts b/src/frontend/app/viewer/document-viewer.component.ts
index fac3cc4160e..f6eb6e4aab5 100755
--- a/src/frontend/app/viewer/document-viewer.component.ts
+++ b/src/frontend/app/viewer/document-viewer.component.ts
@@ -155,7 +155,7 @@ export class DocumentViewerComponent implements OnInit {
                         extension: '.' + ext.extension.toLowerCase(),
                         mimeType: ext.mimeType,
                         canConvert: ext.canConvert
-                    }
+                    };
                 });
                 this.allowedExtensions = this.sortPipe.transform(this.allowedExtensions, 'extension');
 
@@ -184,7 +184,7 @@ export class DocumentViewerComponent implements OnInit {
 
         if (!this.functions.empty(this.base64)) {
             this.loadFileFromBase64();
-        } else if (this.tmpFilename != '' && this.tmpFilename !== undefined) {
+        } else if (this.tmpFilename !== '' && this.tmpFilename !== undefined) {
             this.http.get('../../rest/convertedFile/' + this.tmpFilename).pipe(
                 tap((data: any) => {
                     this.file = {
diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html
index 3a8a765375b..a2545c0bc0e 100644
--- a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.html
@@ -1,5 +1,5 @@
 <div *ngIf="loading" style="display:block;padding: 10px;">{{lang.checkOnlyofficeServer}}...</div>
-<button class="onlyofficeButton_fullscreen" [class.fullScreen]="fullscreenMode" mat-mini-fab color="warn"
+<button *ngIf="!hideCloseEditor" class="onlyofficeButton_fullscreen" [class.fullScreen]="fullscreenMode" mat-mini-fab color="warn"
     [title]="lang.closeEditor" (click)="quit()">
     <mat-icon class="fa fa-times" style="height:auto;"></mat-icon>
 </button>
diff --git a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts
index bb547e5a0a5..ee19865cadf 100644
--- a/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts
+++ b/src/frontend/plugins/onlyoffice-api-js/onlyoffice-viewer.component.ts
@@ -10,7 +10,7 @@ import {
 } from '@angular/core';
 import './onlyoffice-api.js';
 import { HttpClient } from '@angular/common/http';
-import { catchError, tap, filter } from 'rxjs/operators';
+import { catchError, tap, filter, finalize } from 'rxjs/operators';
 import { LANG } from '../../app/translate.component';
 import { ConfirmComponent } from '../modal/confirm.component';
 import { MatDialogRef, MatDialog } from '@angular/material/dialog';
@@ -36,6 +36,7 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD
     @Input() editMode: boolean = false;
     @Input() file: any = {};
     @Input() params: any = {};
+    @Input() hideCloseEditor: any = false;
 
     @Output() triggerAfterUpdatedDoc = new EventEmitter<string>();
     @Output() triggerCloseEditor = new EventEmitter<string>();
@@ -62,7 +63,13 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD
         'ott',
         'rtf',
         'txt',
-        'html'
+        'html',
+        'xlsl',
+        'xlsx',
+        'xltx',
+        'ods',
+        'ots',
+        'csv',
     ];
 
     private eventAction = new Subject<any>();
@@ -227,7 +234,7 @@ export class EcplOnlyofficeViewerComponent implements OnInit, AfterViewInit, OnD
                 }),
                 catchError((err) => {
                     this.notify.handleErrors(err);
-                    this.closeEditor();
+                    this.triggerCloseEditor.emit();
                     return of(false);
                 }),
             ).subscribe();
diff --git a/src/frontend/service/auth-interceptor.service.ts b/src/frontend/service/auth-interceptor.service.ts
index 89d37194357..a5982031f67 100644
--- a/src/frontend/service/auth-interceptor.service.ts
+++ b/src/frontend/service/auth-interceptor.service.ts
@@ -93,7 +93,7 @@ export class AuthInterceptor implements HttpInterceptor {
                             })
                         );
                     } else {
-                        return of(false);
+                        return next.handle(request);
                     }
                 })
             );
-- 
GitLab