Commit 55c0cb26 authored by Alex ORLUC's avatar Alex ORLUC
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request maarch/MaarchCourrier!297
parents 6a7ebc29 07f44c2f
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
[![coverage report](https://labs.maarch.org/maarch/MaarchCourrier/badges/develop/coverage.svg)](https://labs.maarch.org/maarch/MaarchCourrier/commits/develop) [![coverage report](https://labs.maarch.org/maarch/MaarchCourrier/badges/develop/coverage.svg)](https://labs.maarch.org/maarch/MaarchCourrier/commits/develop)
# Maarch Courrier # Maarch Courrier
Gestionnaire Électronique de Correspondances – Libre et Open Source – Gestionnaire Électronique de Correspondances – Libre et Open Source –
...@@ -41,4 +40,3 @@ display_errors = On ...@@ -41,4 +40,3 @@ display_errors = On
## Le coin des developpeurs ## Le coin des developpeurs
[Maarch Developer handbook](https://labs.maarch.org/maarch/MaarchCourrier/blob/master/CONTRIBUTING.md) [Maarch Developer handbook](https://labs.maarch.org/maarch/MaarchCourrier/blob/master/CONTRIBUTING.md)
\ No newline at end of file
...@@ -64,7 +64,7 @@ if ($notification['is_enabled'] === 'N') { ...@@ -64,7 +64,7 @@ if ($notification['is_enabled'] === 'N') {
//SECOND STEP //SECOND STEP
writeLog(['message' => "Loading events for notification {$notificationId}", 'level' => 'INFO']); writeLog(['message' => "Loading events for notification {$notificationId}", 'level' => 'INFO']);
$events = \Notification\models\NotificationsEventsModel::get(['select' => ['*'], 'where' => ['notification_sid = ?', 'exec_date is NULL'], 'data' => [$notification['notification_sid']]]); $events = \Notification\models\NotificationsEventsModel::get(['select' => ['*'], 'where' => ['notification_sid = ?', 'exec_date is NULL'], 'data' => [$notification['notification_sid']], 'orderBy' => ['event_date desc']]);
$totalEventsToProcess = count($events); $totalEventsToProcess = count($events);
$currentEvent = 0; $currentEvent = 0;
if ($totalEventsToProcess === 0) { if ($totalEventsToProcess === 0) {
......
...@@ -102,7 +102,8 @@ class EntityController ...@@ -102,7 +102,8 @@ class EntityController
'email' => $entity['email'], 'email' => $entity['email'],
'producerService' => $entity['producer_service'], 'producerService' => $entity['producer_service'],
'business_id' => $entity['business_id'], 'business_id' => $entity['business_id'],
'external_id' => $entity['external_id'] 'external_id' => $entity['external_id'],
'fastParapheurSubscriberId' => json_decode($entity['external_id'], true)['fastParapheurSubscriberId'],
]; ];
$aEntities = EntityModel::getAllowedEntitiesByUserId(['userId' => $GLOBALS['login']]); $aEntities = EntityModel::getAllowedEntitiesByUserId(['userId' => $GLOBALS['login']]);
...@@ -219,6 +220,10 @@ class EntityController ...@@ -219,6 +220,10 @@ class EntityController
return $response->withStatus(400)->withJson(['errors' => _ENTITY_ID_ALREADY_EXISTS]); return $response->withStatus(400)->withJson(['errors' => _ENTITY_ID_ALREADY_EXISTS]);
} }
$externalId = [];
if (!empty($body['fastParapheurSubscriberId'])) {
$externalId['fastParapheurSubscriberId'] = $body['fastParapheurSubscriberId'];
}
$id = EntityModel::create([ $id = EntityModel::create([
'entity_id' => $body['entity_id'], 'entity_id' => $body['entity_id'],
'entity_label' => $body['entity_label'], 'entity_label' => $body['entity_label'],
...@@ -236,7 +241,8 @@ class EntityController ...@@ -236,7 +241,8 @@ class EntityController
'entity_type' => $body['entity_type'], 'entity_type' => $body['entity_type'],
'ldap_id' => $body['ldap_id'], 'ldap_id' => $body['ldap_id'],
'entity_full_name' => $body['entity_full_name'], 'entity_full_name' => $body['entity_full_name'],
'producer_service' => $body['producerService'] 'producer_service' => $body['producerService'],
'external_id' => json_encode($externalId)
]); ]);
HistoryController::add([ HistoryController::add([
'tableName' => 'entities', 'tableName' => 'entities',
...@@ -274,7 +280,7 @@ class EntityController ...@@ -274,7 +280,7 @@ class EntityController
return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']); return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
} }
$entity = EntityModel::getByEntityId(['entityId' => $aArgs['id'], 'select' => [1]]); $entity = EntityModel::getByEntityId(['entityId' => $aArgs['id'], 'select' => ['id', 'external_id']]);
if (empty($entity)) { if (empty($entity)) {
return $response->withStatus(400)->withJson(['errors' => 'Entity not found']); return $response->withStatus(400)->withJson(['errors' => 'Entity not found']);
} }
...@@ -306,6 +312,12 @@ class EntityController ...@@ -306,6 +312,12 @@ class EntityController
$body['producer_service'] = $aArgs['id']; $body['producer_service'] = $aArgs['id'];
} }
$externalId = json_decode($entity['external_id'], true);
if (!empty($body['fastParapheurSubscriberId'])) {
$externalId['fastParapheurSubscriberId'] = $body['fastParapheurSubscriberId'];
} else {
unset($externalId['fastParapheurSubscriberId']);
}
EntityModel::update(['set' => [ EntityModel::update(['set' => [
'entity_label' => $body['entity_label'], 'entity_label' => $body['entity_label'],
'short_label' => $body['short_label'], 'short_label' => $body['short_label'],
...@@ -322,7 +334,8 @@ class EntityController ...@@ -322,7 +334,8 @@ class EntityController
'entity_type' => $body['entity_type'], 'entity_type' => $body['entity_type'],
'ldap_id' => $body['ldap_id'], 'ldap_id' => $body['ldap_id'],
'entity_full_name' => $body['entity_full_name'], 'entity_full_name' => $body['entity_full_name'],
'producer_service' => $body['producerService'] 'producer_service' => $body['producerService'],
'external_id' => json_encode($externalId)
], ],
'where' => ['entity_id = ?'], 'where' => ['entity_id = ?'],
'data' => [$aArgs['id']] 'data' => [$aArgs['id']]
......
...@@ -109,7 +109,8 @@ abstract class EntityModelAbstract ...@@ -109,7 +109,8 @@ abstract class EntityModelAbstract
'entity_type' => $args['entity_type'], 'entity_type' => $args['entity_type'],
'ldap_id' => $args['ldap_id'], 'ldap_id' => $args['ldap_id'],
'entity_full_name' => $args['entity_full_name'], 'entity_full_name' => $args['entity_full_name'],
'producer_service' => $args['producer_service'] 'producer_service' => $args['producer_service'],
'external_id' => $args['external_id']
] ]
]); ]);
......
...@@ -367,7 +367,7 @@ class FastParapheurController ...@@ -367,7 +367,7 @@ class FastParapheurController
$config = $aArgs['config']; $config = $aArgs['config'];
// We need the SIRET field and the user_id of the signatory user's primary entity // We need the SIRET field and the user_id of the signatory user's primary entity
$signatory = DatabaseModel::select([ $signatory = DatabaseModel::select([
'select' => ['user_id', 'business_id', 'entities.entity_label'], 'select' => ['user_id', 'external_id', 'entities.entity_label'],
'table' => ['listinstance', 'users_entities', 'entities'], 'table' => ['listinstance', 'users_entities', 'entities'],
'left_join' => ['item_id = user_id', 'users_entities.entity_id = entities.entity_id'], 'left_join' => ['item_id = user_id', 'users_entities.entity_id = entities.entity_id'],
'where' => ['res_id = ?', 'item_mode = ?', 'process_date is null'], 'where' => ['res_id = ?', 'item_mode = ?', 'process_date is null'],
...@@ -381,6 +381,7 @@ class FastParapheurController ...@@ -381,6 +381,7 @@ class FastParapheurController
'data' => [$aArgs['resIdMaster']] 'data' => [$aArgs['resIdMaster']]
])[0]; ])[0];
$signatory['business_id'] = json_decode($signatory['external_id'], true)['fastParapheurSubscriberId'];
if (empty($signatory['business_id']) || substr($signatory['business_id'], 0, 3) == 'org') { if (empty($signatory['business_id']) || substr($signatory['business_id'], 0, 3) == 'org') {
$signatory['business_id'] = $config['data']['subscriberId']; $signatory['business_id'] = $config['data']['subscriberId'];
} }
......
...@@ -61,7 +61,7 @@ use User\models\UserSignatureModel; ...@@ -61,7 +61,7 @@ use User\models\UserSignatureModel;
class UserController class UserController
{ {
const ALTERNATIVES_CONNECTIONS_METHODS = ['sso', 'cas', 'ldap', 'keycloak', 'shibboleth']; const ALTERNATIVES_CONNECTIONS_METHODS = ['sso', 'cas', 'ldap', 'keycloak', 'shibboleth', 'azure_saml'];
public function get(Request $request, Response $response) public function get(Request $request, Response $response)
{ {
......
...@@ -373,7 +373,7 @@ class AuthenticationController ...@@ -373,7 +373,7 @@ class AuthenticationController
'eventType' => 'LOGIN', 'eventType' => 'LOGIN',
'info' => _LOGIN . ' : ' . $login, 'info' => _LOGIN . ' : ' . $login,
'moduleId' => 'authentication', 'moduleId' => 'authentication',
'eventId' => 'login' 'eventId' => 'userlogin'
]); ]);
return $response->withStatus(204); return $response->withStatus(204);
...@@ -395,6 +395,15 @@ class AuthenticationController ...@@ -395,6 +395,15 @@ class AuthenticationController
$logoutUrl = $disconnection['logoutUrl']; $logoutUrl = $disconnection['logoutUrl'];
} }
HistoryController::add([
'tableName' => 'users',
'recordId' => $GLOBALS['id'],
'eventType' => 'LOGOUT',
'info' => _LOGOUT . ' : ' . $GLOBALS['login'],
'moduleId' => 'authentication',
'eventId' => 'userlogout'
]);
return $response->withJson(['logoutUrl' => $logoutUrl]); return $response->withJson(['logoutUrl' => $logoutUrl]);
} }
......
...@@ -152,6 +152,12 @@ class AutoCompleteController ...@@ -152,6 +152,12 @@ class AutoCompleteController
} }
$curlResponse['response'][$key]['idToDisplay'] = $value['firstname'] . ' ' . $value['lastname']; $curlResponse['response'][$key]['idToDisplay'] = $value['firstname'] . ' ' . $value['lastname'];
$curlResponse['response'][$key]['externalId']['maarchParapheur'] = $value['id']; $curlResponse['response'][$key]['externalId']['maarchParapheur'] = $value['id'];
// Remove external value in signatureModes
$array = $curlResponse['response'][$key]['signatureModes'];
unset($array[array_search('external', $array)]);
$array = array_values($array);
$curlResponse['response'][$key]['signatureModes'] = $array;
} }
return $response->withJson($curlResponse['response']); return $response->withJson($curlResponse['response']);
} else { } else {
......
...@@ -160,6 +160,7 @@ define('_DOCUMENT_UNSIGNED', 'Document unsigned'); ...@@ -160,6 +160,7 @@ define('_DOCUMENT_UNSIGNED', 'Document unsigned');
define('_LINK_ADDED_TAG', 'Tag link added'); define('_LINK_ADDED_TAG', 'Tag link added');
define('_LINK_DELETED_TAG', 'Tag link deleted'); define('_LINK_DELETED_TAG', 'Tag link deleted');
define('_LOGIN', 'User connection'); define('_LOGIN', 'User connection');
define('_LOGOUT', 'User disconnection');
// ADMINISTRATION // ADMINISTRATION
define('_USERS', 'Users'); define('_USERS', 'Users');
......
...@@ -160,6 +160,7 @@ define('_DOCUMENT_UNSIGNED', 'Document dé-signé'); ...@@ -160,6 +160,7 @@ define('_DOCUMENT_UNSIGNED', 'Document dé-signé');
define('_LINK_ADDED_TAG', 'Liaison de mot-clé ajoutée'); define('_LINK_ADDED_TAG', 'Liaison de mot-clé ajoutée');
define('_LINK_DELETED_TAG', 'Liaison de mot-clé supprimée'); define('_LINK_DELETED_TAG', 'Liaison de mot-clé supprimée');
define('_LOGIN', 'Connexion de l\'utilisateur'); define('_LOGIN', 'Connexion de l\'utilisateur');
define('_LOGOUT', 'Déconnexion de l\'utilisateur');
// ADMINISTRATION // ADMINISTRATION
define('_USERS', 'Utilisateurs'); define('_USERS', 'Utilisateurs');
......
...@@ -80,12 +80,16 @@ export class SendExternalSignatoryBookActionComponent implements OnInit { ...@@ -80,12 +80,16 @@ export class SendExternalSignatoryBookActionComponent implements OnInit {
this.checkExternalSignatureBook(); this.checkExternalSignatureBook();
} }
onSubmit() { async onSubmit() {
if (this.hasEmptyOtpSignaturePosition()) {
this.notify.error(this.translate.instant('lang.mustSign'));
} else {
this.loading = true; this.loading = true;
if (this.data.resIds.length > 0) { if (this.data.resIds.length > 0) {
this.executeAction(); this.executeAction();
} }
} }
}
checkExternalSignatureBook() { checkExternalSignatureBook() {
this.loading = true; this.loading = true;
...@@ -176,4 +180,33 @@ export class SendExternalSignatoryBookActionComponent implements OnInit { ...@@ -176,4 +180,33 @@ export class SendExternalSignatoryBookActionComponent implements OnInit {
this.resourcesToSign.splice(index, 1); this.resourcesToSign.splice(index, 1);
} }
} }
hasEmptyOtpSignaturePosition() {
if (this.signatoryBookEnabled == 'maarchParapheur') {
const externalUsers: any[] = this.maarchParapheur.appExternalVisaWorkflow.visaWorkflow.items.filter((user: any) => user.item_id === null && user.role === 'sign');
if (externalUsers.length > 0) {
let resToSign: any[] = this.maarchParapheur.resourcesToSign.filter((res: any) => res.hasOwnProperty('signaturePositions'));
let mustSign: boolean = false;
if (this.maarchParapheur.resourcesToSign.length > 1 && this.maarchParapheur.resourcesToSign.length - resToSign.length >= 1) {
return true;
} else if (resToSign.length === 0) {
return true;
} else {
resToSign = resToSign.map((res: any) => res.signaturePositions);
externalUsers.forEach((element: any) => {
for (let i = 0; i < resToSign.length; i++) {
const userIndex: number = this.maarchParapheur.appExternalVisaWorkflow.visaWorkflow.items.indexOf(element);
if (resToSign[i].filter((item: any) => item.sequence === userIndex).length === 0) {
mustSign = true;
break;
}
}
});
return mustSign;
}
}
} else {
return false;
}
}
} }
...@@ -262,7 +262,7 @@ export class ContactsFormComponent implements OnInit { ...@@ -262,7 +262,7 @@ export class ContactsFormComponent implements OnInit {
type: 'string', type: 'string',
control: new FormControl({value: '', disabled: true}), control: new FormControl({value: '', disabled: true}),
required: false, required: false,
display: true, display: false,
filling: false, filling: false,
values: [] values: []
}, },
...@@ -814,12 +814,19 @@ export class ContactsFormComponent implements OnInit { ...@@ -814,12 +814,19 @@ export class ContactsFormComponent implements OnInit {
this.checkFilling(); this.checkFilling();
this.http.get('../rest/contacts/sector', {params: {'addressNumber': contact['addressNumber'], 'addressStreet': contact['addressStreet'], 'addressPostcode': contact['addressPostcode'], 'addressTown': contact['addressTown']}}).pipe( this.http.get('../rest/contacts/sector', {params: {'addressNumber': contact['addressNumber'], 'addressStreet': contact['addressStreet'], 'addressPostcode': contact['addressPostcode'], 'addressTown': contact['addressTown']}}).pipe(
tap((data: any) => { tap((data: any) => {
if (data.sector !== null) {
const sectorIndex = this.contactForm.findIndex(element => element.id === 'sector'); const sectorIndex = this.contactForm.findIndex(element => element.id === 'sector');
if (data.sector !== null) {
this.contactForm[sectorIndex].control.setValue(data.sector.label); this.contactForm[sectorIndex].control.setValue(data.sector.label);
this.contactForm[sectorIndex].display = true; this.contactForm[sectorIndex].display = true;
} else {
this.contactForm[sectorIndex].control.setValue('');
this.contactForm[sectorIndex].display = false;
} }
}), }),
catchError((err: any) => {
this.notify.handleErrors(err);
return of(false);
})
).subscribe(); ).subscribe();
this.addressBANMode = disableBan ? false : true; this.addressBANMode = disableBan ? false : true;
......
...@@ -326,6 +326,17 @@ ...@@ -326,6 +326,17 @@
</mat-form-field> </mat-form-field>
</div> </div>
</div> </div>
<div class="form-group" *ngIf="externalSignatoryBook == 'fastParapheur'">
<div class="col-sm-12">
<mat-form-field>
<input matInput [(ngModel)]="currentEntity.fastParapheurSubscriberId"
name="fastParapheurSubscriberId" id="fastParapheurSubscriberId"
title="{{'lang.fastParapheurSubscriberId' | translate}}" type="text"
placeholder="{{'lang.fastParapheurSubscriberId' | translate}}" maxlength="255"
pattern="^[\w-]*$">
</mat-form-field>
</div>
</div>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
<div class="form-group"> <div class="form-group">
......
...@@ -72,6 +72,7 @@ export class EntitiesAdministrationComponent implements OnInit { ...@@ -72,6 +72,7 @@ export class EntitiesAdministrationComponent implements OnInit {
addressBANFilteredResult: Observable<string[]>; addressBANFilteredResult: Observable<string[]>;
addressBANCurrentDepartment: string = '75'; addressBANCurrentDepartment: string = '75';
departmentList: any[] = []; departmentList: any[] = [];
externalSignatoryBook: string;
constructor( constructor(
public translate: TranslateService, public translate: TranslateService,
...@@ -114,6 +115,21 @@ export class EntitiesAdministrationComponent implements OnInit { ...@@ -114,6 +115,21 @@ export class EntitiesAdministrationComponent implements OnInit {
this.initEntitiesTree(); this.initEntitiesTree();
this.initBanSearch(); this.initBanSearch();
this.initAutocompleteAddressBan(); this.initAutocompleteAddressBan();
this.initSignatoryBook();
}
initSignatoryBook() {
this.http.get('../rest/externalConnectionsEnabled').pipe(
tap((data: any) => {
Object.keys(data.connection).filter(connectionId => connectionId !== 'maileva').forEach(connectionId => {
this.externalSignatoryBook = connectionId;
});
}),
catchError((err: any) => {
this.notify.handleSoftErrors(err);
return of(false);
})
).subscribe();
} }
initEntitiesTree() { initEntitiesTree() {
......
...@@ -110,6 +110,7 @@ export class ParametersCustomizationComponent implements OnInit, OnDestroy { ...@@ -110,6 +110,7 @@ export class ParametersCustomizationComponent implements OnInit, OnDestroy {
}); });
}, },
base_url: '../node_modules/tinymce/', base_url: '../node_modules/tinymce/',
convert_urls: false,
height: '200', height: '200',
suffix: '.min', suffix: '.min',
language: this.translate.instant('lang.langISO').replace('-', '_'), language: this.translate.instant('lang.langISO').replace('-', '_'),
......
...@@ -209,6 +209,7 @@ export class TemplateAdministrationComponent implements OnInit, OnDestroy { ...@@ -209,6 +209,7 @@ export class TemplateAdministrationComponent implements OnInit, OnDestroy {
tinymce.suffix = '.min'; tinymce.suffix = '.min';
tinymce.init({ tinymce.init({
selector: selectorId, selector: selectorId,
convert_urls: false,
statusbar: false, statusbar: false,
language: this.translate.instant('lang.langISO').replace('-', '_'), language: this.translate.instant('lang.langISO').replace('-', '_'),
language_url: `../node_modules/tinymce-i18n/langs/${this.translate.instant('lang.langISO').replace('-', '_')}.js`, language_url: `../node_modules/tinymce-i18n/langs/${this.translate.instant('lang.langISO').replace('-', '_')}.js`,
......
...@@ -59,7 +59,7 @@ ...@@ -59,7 +59,7 @@
</a> </a>
</div> </div>
<div *ngIf="showLogout()" style="text-align:right;flex:2;"> <div *ngIf="showLogout()" style="text-align:right;flex:2;">
<a (click)="authService.logout()" style="cursor:pointer; color: white;padding-right: 10px;"> <a (click)="authService.logout(true, false, true)" style="cursor:pointer; color: white;padding-right: 10px;">
<span class="badge action-header-profile">{{'lang.logout' | translate}}</span> <span class="badge action-header-profile">{{'lang.logout' | translate}}</span>
</a> </a>
</div> </div>
......
...@@ -78,7 +78,7 @@ export class HeaderRightComponent implements OnInit { ...@@ -78,7 +78,7 @@ export class HeaderRightComponent implements OnInit {
} }
showLogout() { showLogout() {
return ['sso'].indexOf(this.authService.authMode) > -1 && this.functions.empty(this.authService.authUri) ? false : true; return ['sso', 'azure_saml'].indexOf(this.authService.authMode) > -1 && this.functions.empty(this.authService.authUri) ? false : true;
} }
goTo() { goTo() {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment