Commit 91534f05 authored by Cyril Vazquez's avatar Cyril Vazquez
Browse files

Merge branch 'release/2.9' into 'fix/21434_DIP_error_on_SEDA1_generated_archives'

# Conflicts:
#   VERSION.md
parents 65b31e40 6c17ca05
# Migration 2.8 vers 2.9
## Schéma SQL
Voir le fichier de migration de base de données socle dans le fichier MIGRATION.md situé à la racine du socle applicatif.
# Migration 2.7 vers 2.8
## Vhost
Voir le fichier MIGRATION.md situé à la racine du socle applicatif.
## Configuration
### Changements globaux
Voir le fichier MIGRATION.md situé à la racine du socle applicatif.
......@@ -13,11 +20,12 @@ Dans la section [medona], ajout de tous les connecteurs disponibles pour l'appli
Modification du presenter pour le schema Seda 2 dans la directive `descriptionSchemes` de la section [recordsManagement].
## Schéma SQL
Voir le fichier de migration de base de donées socle dans le fichier MIGRATION.md situé à la racine du socle applicatif.
Voir le fichier de migration de base de données socle dans le fichier MIGRATION.md situé à la racine du socle applicatif.
Voir le fichier spécifique
laabs/src/ext/archivesPubliques/data/sql/pgsql/apV2.7_V2.8.sql
# Migration 2.6 vers 2.7
## Ajout dans la configuration
......
......@@ -839,7 +839,8 @@ class content implements \bundle\recordsManagement\Controller\archiveDescription
$term = null,
$keyword = array()
) {
$queryParts['json'] = "(descriptionClass = 'seda2' || descriptionClass = 'seda2/Content')";
//$queryParts['json'] = "(descriptionClass = 'seda2' || descriptionClass = 'seda2/Content')";
$queryParts['json'] = "(descriptionClass != 'archivesPubliques/content' || descriptionClass = null)";
if (is_array($keyword) && !empty($keyword)) {
foreach ($keyword as $keywordObj) {
......@@ -934,11 +935,8 @@ class content implements \bundle\recordsManagement\Controller\archiveDescription
$queryUserOrg['accessRule'] = "(
originatorOwnerOrgId = '" . $currentService->ownerOrgId. "' AND (
(
accessRuleComDate <= '$currentDateString'
OR accessRuleComDate = NULL
)
OR (archivalProfileReference = [" . \laabs\implode(", ", $discoverableProfilesIdentifiers) . "])
accessRuleComDate <= '$currentDateString'
OR archivalProfileReference = [" . \laabs\implode(", ", $discoverableProfilesIdentifiers) . "]
)
)";
......
......@@ -349,7 +349,7 @@ class ArchiveTransfer extends abstractMessage implements \bundle\medona\Controll
protected function validateAttachments($message, $archivalAgreement)
{
$serviceLevelController = \laabs::newController("recordsManagement/serviceLevel");
$formatController = \laabs::newController("digitalResource/format");
$formatController = \laabs::newController("digitalResource/pronomFormat");
$messageDir = dirname($message->path);
$attachments = array($message->path);
......
......@@ -167,7 +167,7 @@ class ArchiveTransferComposition extends abstractMessage
*/
public function addDocument($messageId, $documents)
{
$formatController = \laabs::newController('digitalResource/format');
$formatController = \laabs::newController('digitalResource/pronomFormat');
foreach ($documents as $document) {
if (is_resource($document->attachment->value)) {
......@@ -372,7 +372,7 @@ class ArchiveTransferComposition extends abstractMessage
protected function documentValidation($filepath, $archivalAgreementReference)
{
$archivalAgreementController = \laabs::newController('medona/archivalAgreement');
$formatController = \laabs::newController("digitalResource/format");
$formatController = \laabs::newController("digitalResource/pronomFormat");
$archivalAgreement = $archivalAgreementController->getByReference($archivalAgreementReference);
$format = $formatController->identifyFormat($filepath);
......
......@@ -283,7 +283,7 @@ class ArchiveTransferComposition extends abstractMessage
protected function documentValidation($filepath, $archivalAgreementReference)
{
$archivalAgreementController = \laabs::newController('medona/archivalAgreement');
$formatController = \laabs::newController("digitalResource/format");
$formatController = \laabs::newController("digitalResource/pronomFormat");
$archivalAgreement = $archivalAgreementController->getByReference($archivalAgreementReference);
$format = $formatController->identifyFormat($filepath);
......
<?php
/*
* Copyright (C) 2015 Maarch
*
* This file is part of bundle seda.
*
* Bundle seda is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Bundle seda is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with bundle seda. If not, see <http://www.gnu.org/licenses/>.
*/
namespace ext\archivesPubliques\bundle\seda2\Controller;
/**
* Class ArchiveTransferRequest
*
* @package Seda
*/
class ArchiveTransferRequest extends abstractMessage
{
public $errors = [];
public $infos = [];
public $replyCode;
/**
* Receive message with all contents embedded
* @param mixed $message The message
*/
public function receive($message)
{
$this->loadMessage($message);
// Conformité au schéma SEDA
switch ($message->xml->documentElement->namespaceURI) {
case 'fr:gouv:culture:archivesdefrance:seda:v2.0':
$schemaUri = 'seda2'.LAABS_URI_SEPARATOR.'2.0'.LAABS_URI_SEPARATOR.'schema'.LAABS_URI_SEPARATOR.'seda-2.0-main.xsd';
break;
case 'fr:gouv:culture:archivesdefrance:seda:v2.1':
$schemaUri = 'seda2'.LAABS_URI_SEPARATOR.'2.1'.LAABS_URI_SEPARATOR.'schema'.LAABS_URI_SEPARATOR.'seda-2.1-main.xsd';
break;
default:
$exception = \laabs::newException('seda/invalidMessageException', 'Bordereau non reçu : il ne respecte pas le standard SEDA 2.');
$exception->errors[] = new \core\Error('Bordereau non reçu : il ne respecte pas le standard SEDA 2 (le format utilisé est "'.$message->xml->documentElement->namespaceURI.'")');
throw $exception;
}
$router = new \core\Route\ResourceRouter($schemaUri);
$schemaFile = $router->getResource()->getRealPath();
libxml_use_internal_errors(true);
$valid = $message->xml->schemaValidate($schemaFile);
if ($valid == false) {
$exception = \laabs::newException('seda/invalidMessageException', 'Bordereau non reçu : il ne respecte pas le standard SEDA 2.');
$exception->errors = libxml_get_errors();
libxml_clear_errors();
libxml_use_internal_errors(false);
throw $exception;
}
$message->object = $message->xml->export('seda2/ArchiveTransferRequest');
$message->date = $message->object->date;
$message->senderOrgRegNumber = $message->object->transferringAgency->identifier->value;
$message->recipientOrgRegNumber = $message->object->archivalAgency->identifier->value;
$message->reference = $message->object->messageIdentifier->value;
if (isset($message->object->archivalAgreement->value)) {
$message->archivalAgreementReference = $message->object->archivalAgreement->value;
}
$this->receiveAttachments($message);
}
protected function receiveAttachments($message)
{
if (is_null($message->object->dataObjectPackage)) {
$this->sendError("213");
} else {
$dataObjectPackage = $message->object->dataObjectPackage;
$archives = $dataObjectPackage->descriptiveMetadata->archiveUnit;
$binaryDataObjects = (array) $dataObjectPackage->binaryDataObject;
$physicalDataObjects = (array) $dataObjectPackage->physicalDataObject;
if (isset($dataObjectPackage->dataObjectGroup)) {
foreach ((array)$dataObjectPackage->dataObjectGroup as $dataObjectGroup) {
if (isset($dataObjectGroup->binaryDataObject)) {
foreach ($dataObjectGroup->binaryDataObject as $binaryDataObject) {
$binaryDataObjects[] = $binaryDataObject;
}
}
if (isset($dataObjectGroup->physicalDataObject)) {
foreach ($dataObjectGroup->physicalDataObject as $physicalDataObject) {
$physicalDataObjects[] = $physicalDataObject;
}
}
}
}
$message->dataObjectCount = count($binaryDataObjects) + count($physicalDataObjects);
foreach ($archives as $archive) {
if ($archive->dataObjectReference) {
$this->validateDataObjectReferences($message, $archive);
}
}
}
if (isset($binaryDataObjects) && is_array($binaryDataObjects) && !empty($binaryDataObjects)) {
foreach ($binaryDataObjects as $binaryDataObject) {
$dataObjectId = $binaryDataObject->id;
// Use attachment to create local file with uri access
if (isset($binaryDataObject->attachment)) {
$attachment = $binaryDataObject->attachment;
if (!empty($attachment->value)) {
$binaryDataObject->uri = null;
} elseif (isset($attachment->filename)) { // Non compliant with SEDA2 but...
$binaryDataObject->uri = $attachment->filename;
} elseif (isset($attachment->uri)) { // Non compliant with SEDA2 but...
$binaryDataObject->uri = $attachment->uri;
}
unset($binaryDataObject->attachment);
}
if (!isset($binaryDataObject->uri)) {
$this->sendError("211", "Le document '$dataObjectId' n'a pas été trouvé.");
continue;
}
$message->size += $binaryDataObject->size;
}
}
return $this->errors;
}
protected function validateDataObjectReferences($message, $archive)
{
foreach ($archive->dataObjectReference as $dataObjectReference) {
if (!$this->getBinaryDataObjectById($dataObjectReference->dataObjectReferenceId, $message)) {
$this->sendError("213", "Le document référencé par '$dataObjectReference->dataObjectReferenceId' est introuvable.");
}
}
}
/* VALIDATION */
/*************************************************************************/
/**
* Validate against profile
* @param seda/message $message The message object with the xml
* @param object $archivalAgreement The archival agreement
*
* @return boolean The result of the operation
*/
public function validate($message, $archivalAgreement = null)
{
$this->errors = array();
$this->replyCode = null;
$this->loadMessage($message);
if (!empty($archivalAgreement)) {
if ($archivalAgreement->originatorOrgIds) {
$this->validateOriginators($message, $archivalAgreement);
}
if ($archivalAgreement->signed && !isset($message->object->signature)) {
$this->sendError("309");
}
if (!empty($archivalAgreement->archivalProfileReference)
|| isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
$this->validateProfile($this->message, $archivalAgreement);
}
}
// Contrôle des documents attachés
$this->validateAttachments($this->message, $archivalAgreement);
$this->validateRules($this->message, $this->message->object->dataObjectPackage->descriptiveMetadata->archiveUnit);
return true;
}
protected function validateRules($message, $archives)
{
foreach ($archives as $archive) {
if (isset($archive->management->appraisalRule->rule) && !empty($archive->management->appraisalRule->rule)) {
foreach ($archive->management->appraisalRule->rule as $ruleObject) {
$ruleSdo = $this->retentionRuleController->read($ruleObject->value);
if (!isset($ruleSdo) || empty($ruleSdo)) {
$this->sendError("404", "La règle de conservation '$ruleObject->value' n'a pas pu être transmise");
}
}
}
if (isset($archive->management->accessRule->rule) && !empty($archive->management->accessRule->rule)) {
foreach ($archive->management->accessRule->rule as $ruleObject) {
$ruleSdo = $this->accessRuleController->edit($ruleObject->value);
if (!isset($ruleSdo) || empty($ruleSdo)) {
$this->sendError("404", "La règle de communicabilité '$ruleObject->value' n'a pas pu être transmise");
}
}
}
if (isset($archive->archiveUnit)) {
$this->validateRules($message, $archive->archiveUnit);
}
}
}
protected function validateOriginators($message, $archivalAgreement)
{
// Contrôle du producteur
$originatorIdentifications = array();
if (isset($message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier) && !empty($message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier->value)) {
$originatorIdentifications[] = $message->object->dataObjectPackage->managementMetadata->originatingAgencyIdentifier->value;
}
foreach ($message->object->dataObjectPackage->descriptiveMetadata->archiveUnit as $archive) {
$originatorIdentifications = array_merge($originatorIdentifications, $this->getOriginatorIdentifications($archive));
}
$originatorIdentifications = array_unique($originatorIdentifications);
$originatorOrgs = array();
foreach ($originatorIdentifications as $originatorIdentification) {
//$originatorOrgRegNumber = $originatorOrgRegNumberElement->nodeValue;
if (!isset($originatorOrgs[$originatorIdentification])) {
try {
$originatorOrg = $this->orgController->getOrgByRegNumber($originatorIdentification);
$originatorOrgs[$originatorIdentification] = $originatorOrg;
} catch (\Exception $e) {
$this->sendError("200", "Le producteur de l'archive identifié par '$originatorIdentification' n'est pas référencé dans le système.");
continue;
}
if (!in_array('originator', (array) $originatorOrg->orgRoleCodes)) {
$this->sendError("302", "Le service identifié par '$originatorIdentification' n'est pas référencé comme producteur dans le système.");
}
if (!in_array((string) $originatorOrg->orgId, (array) $archivalAgreement->originatorOrgIds)) {
$this->sendError("302", "Le producteur de l'archive identifié par '$originatorIdentification' n'est pas indiqué dans l'accord de versement.");
}
if (!$originatorOrg->enabled) {
$this->sendError("302", "Le service producteur '$originatorIdentification' est désactivé : veuillez le réactiver pour pouvoir verser des archives");
}
}
}
}
protected function getOriginatorIdentifications($archive)
{
$originatorIdentifications = array();
if (isset($archive->content->originatingAgency) && !empty($archive->content->originatingAgency->identifier->value)) {
$originatorIdentifications[] = $archive->content->originatingAgency->identifier->value;
}
if (isset($archive->archiveUnit)) {
foreach ($archive->archiveUnit as $archiveUnit) {
$originatorIdentifications = array_merge($originatorIdentifications, $this->getOriginatorIdentifications($archiveUnit));
}
}
return array_unique($originatorIdentifications);
}
protected function validateProfile($message, $archivalAgreement)
{
// No agreement and no profile
if (!$archivalAgreement && !isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
$this->sendError("203");
return;
}
// Aggreement but no profile
if (!isset($message->object->dataObjectPackage->managementMetadata->archivalProfile->value)) {
$archivalprofileReference = $archivalAgreement->archivalProfileReference;
} else {
$archivalprofileReference = $message->object->dataObjectPackage->managementMetadata->archivalProfile->value;
if ($archivalAgreement && $archivalprofileReference != $archivalAgreement->archivalProfileReference) {
$this->sendError("203", "Le profil d'archive du bordereau $archivalprofileReference ne correspond pas à celui de l'accord de versement");
return;
}
}
$configuration = \laabs::configuration('recordsManagement');
if ($configuration['archivalProfileType'] == '1' || $configuration['archivalProfileType'] == '3') {
// Profile is based on an XSD or RelaxNG file
$profileFiles = glob($this->profilesDirectory.DIRECTORY_SEPARATOR.$archivalprofileReference.'.*');
if (count($profileFiles) == 0 && $configuration['archivalProfileType'] == '1') {
$this->sendError("203", "Le message fait référence à un profil d'archive $archivalprofileReference non enregistré dans le système.");
return;
}
foreach ($profileFiles as $profileFile) {
$extension = pathinfo($profileFile, \PATHINFO_EXTENSION);
switch ($extension) {
case 'rng':
//if ($validationMode == 'jing') {
if (true) {
$jing = \laabs::newService('dependency/xml/plugins/jing/jing');
$valid = $jing->validate($profileFile, $this->message->path);
if (!$valid) {
$this->sendError("203");
if ($jing->getErrors()) {
foreach ($jing->getErrors() as $errorMessage) {
$this->errors[] = new \core\error($errorMessage);
}
}
}
} else {
libxml_use_internal_errors(true);
$valid = $message->xml->relaxNGValidate($profileFile);
if ($valid == false) {
$this->sendError("203");
foreach (libxml_get_errors() as $libxmlError) {
$this->errors[] = new \core\error($libxmlError->message, null, $libxmlError->code);
}
}
libxml_clear_errors();
libxml_use_internal_errors(false);
}
break;
case 'xsd':
libxml_use_internal_errors(true);
$valid = $message->xml->schemaValidate($profileFile);
if ($valid == false) {
foreach (libxml_get_errors() as $libxmlError) {
$this->errors[] = new \core\error($libxmlError->message, null, $libxmlError->code);
}
}
libxml_clear_errors();
libxml_use_internal_errors(false);
break;
default:
$path = $this->profilesDirectory.DIRECTORY_SEPARATOR.$archivalprofileReference;
// if a profile were previously saved without extension
if (empty($extension) && (file_exists($path . '.rng') || file_exists($path . '.xsd'))) {
break;
}
$this->sendError("203", "Le message fait référence à un profil d'archive dont le format n'est pas géré.");
break;
}
}
}
}
protected function validateAttachments($message, $archivalAgreement)
{
$serviceLevelController = \laabs::newController("recordsManagement/serviceLevel");
$dataObjectPackage = $message->object->dataObjectPackage;
if (isset($dataObjectPackage->managementMetadata->serviceLevel)) {
$serviceLevelReference = $dataObjectPackage->managementMetadata->serviceLevel->value;
} elseif (isset($archivalAgreement)) {
$serviceLevelReference = $archivalAgreement->serviceLevelReference;
}
if (!isset($serviceLevelReference) || empty($serviceLevelReference)) {
$serviceLevelByDefault = $this->sdoFactory->find('recordsManagement/serviceLevel', 'default= true');
if (!isset($serviceLevelByDefault) || empty($serviceLevelByDefault)) {
$this->sendError("203", "Le niveau de service n'est pas renseigné.");
return;
}
$serviceLevel = $serviceLevelByDefault[0];
} else {
$serviceLevel = $serviceLevelController->getByReference($serviceLevelReference);
}
if ($archivalAgreement) {
$allowedFormats = \laabs\explode(' ', $archivalAgreement->allowedFormats);
} else {
$allowedFormats = [];
}
$binaryDataObjects = (array) $dataObjectPackage->binaryDataObject;
if (isset($dataObjectPackage->dataObjectGroup)) {
foreach ((array)$dataObjectPackage->dataObjectGroup as $dataObjectGroup) {
if (!isset($dataObjectGroup->binaryDataObject)) {
continue;
}
$binaryDataObjects = array_merge($binaryDataObjects, $dataObjectGroup->binaryDataObject);
}
}
if (count($binaryDataObjects)) {
foreach ($binaryDataObjects as $binaryDataObject) {
if (!isset($binaryDataObject->formatIdentification->formatId)) {
continue;
}
$puid = $binaryDataObject->formatIdentification->formatId;
if (count($allowedFormats) && !in_array($puid, $allowedFormats)) {
$this->sendError("307", "Le format du document '".$binaryDataObject->uri."' ".$puid." n'est pas autorisé par l'accord de versement.");
}
}
}
}
}
<?php
/*
* Copyright (C) 2015 Maarch
*
* This file is part of bundle medona.
*
* Bundle medona is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Bundle medona is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with bundle medona. If not, see <http://www.gnu.org/licenses/>.
*/
namespace ext\archivesPubliques\bundle\seda2\Controller;
/**
* Class for ArchiveTransferRequestReply message handling
*/
class ArchiveTransferRequestReply extends abstractMessage
{
/**
* Generate a new archive delivery request reply
* @param medona/message $message
*/
public function send($message)
{
$archiveTransferRequestReply = abstractMessage::send($message);
$archiveTransferRequestReply->replyCode = $this->sendReplyCode($message->replyCode);
$archiveTransferRequestReply->messageRequestIdentifier = \laabs::newInstance('seda2/ID', $message->requestReference);
$archiveTransferRequestReply->archivalAgency = $this->sendOrganization($message->senderOrg);
$archiveTransferRequestReply->transferringAgency = $this->sendOrganization($message->recipientOrg);
$archiveTransferRequestReply->dataObjectPackage = $this->sendDataObjectPackage($message, false);
$this->sendXml($message, $withData = false);
}
}
......@@ -275,7 +275,7 @@ trait ArchiveTransferValidationTrait
$serviceLevel = $serviceLevelController->getByReference($serviceLevelReference);
}
$formatController = \laabs::newController("digitalResource/format");
$formatController = \laabs::newController("digitalResource/pronomFormat");
if ($archivalAgreement) {
$allowedFormats = \laabs\explode(' ', $archivalAgreement->allowedFormats);
} else {
......
<?php
namespace ext\archivesPubliques\bundle\seda2\Model;
/**
* The archive transfer request message
*
* @package Seda2
* @author Cyril Vazquez <cyril.vazquez@maarch.org>