Commit 9215ee37 authored by Alexandre Morin's avatar Alexandre Morin
Browse files

Merge branch 'hotfix/2.1.1' into 'Support/2.1.X'

Hotfix/2.1.1

See merge request maarch/archivesPubliques!12
parents ee847d78 023e4f81
# Migration 2.0 vers 2.1
## Configuration
**Toutes les modifications qui vont suivre seront à effectuer dans le fichier `configuration.ini`.
Afin de vous aider dans votre migration, le fichier `configuration.ini.default` peut vous servir de modèle.**
### Conf.d
Dans le but de regrouper la configuration dans un même fichier, nous avons copié le contenu des fichiers suivants dans le fichier principal `configuration.ini` :
- dependency#datasource.ini
- dependency#filesystem.ini
- dependency#html.ini
- dependency#json.ini
- dependency#localisation.ini
- dependency#logger.ini
- dependency#notification.ini
- dependency#repository.ini
- dependency#sdo.ini
Tous ces fichiers sont présents dans le dossier `conf.d`.
### Black list
L'option `blackList` a été ajoutée dans la configuration. Cette option permet de désactiver une ou plusieurs route(s) de service.
Voici le paramétrage par défaut. Ce paramétrage désactive les routes inutiles pour l'archivage sphère publique.
```bash
; Blacklist of user stories
blacklistUserStories = "[
'archiveDeposit/deposit',
'adminArchive/descriptionField',
'archiveManagement/modifyDescription'
]"
```
### CSRF (facultatif)
Afin de nous protéger des attaques de "Cross-Site Request Forgery", nous avons ajouté une dépendance.
La dépendance "csrf" doit être ajoutée dans vos deux vhost (présentation et service) comme ci-dessous.
```bash
SetEnv LAABS_DEPENDENCIES repository;xml;html;localisation;datasource;sdo;json;fileSystem;notification;csrf
```
La dépendance amène une configuration associée.
Si cette configuration n'est pas ajoutée cela n'empêche en rien le bon fonctionnement de l'application.
```ini
[dependency.csrf]
whiteList = "['user/login']"
config = "{
'CSRFP_TOKEN' : '',
'logDirectory' : '/tmp',
'failedAuthAction' : {
'GET' : 0,
'POST' : 0
},
'errorRedirectionPage' : '',
'customErrorMessage' : '',
'jsUrl' : '/public/js/csrf/csrfprotector.js',
'tokenLength' : 10,
'cookieConfig' : {
'path' : '',
'domain' : '',
'secure' : false
},
'disabledJavascriptMessage' : 'This site attempts to protect users against <a href='https://www.owasp.org/index.php/Cross-Site_Request_Forgery_%28CSRF%29'> Cross-Site Request Forgeries </a> attacks. In order to do so, you must have JavaScript enabled in your web browser otherwise this site will fail to work correctly for you. See details of your web browser for how to enable JavaScript.',
'verifyGetFor': {}
}"
```
### Public user story
Nous avons déplacé des informations techniques de la BDD vers le fichier de configuration.
Ces informations ne sont plus censées être modifiées après l'installation.
Le contenu doit être identique à la table `"auth"."publicUserStory"`.
Voici un exemple de contenu:
```bash
publicUserStory = "['app/*']"
```
*Voir sous-menu "Base de données" pour la suppression de la table "auth"."publicUserStory".*
### Task
Nous avons déplacé des informations techniques de la BDD vers le fichier de configuration.
Le contenu doit être identique à la table `"batchProcessing"."task"`.
Voici un exemple de contenu:
```bash
[batchProcessing]
tasks = "[
{
'taskId': '01',
'route' : 'audit/event/createChainjournal',
'description' : 'Chainer le journal de l\'application'
},
{
'taskId': '02',
'route' : 'lifeCycle/journal/createChainjournal',
'description' : 'Chainer le journal du cycle de vie'
},
{
'taskId': '03',
'route' : 'recordsManagement/archiveCompliance/readPeriodic',
'description' : 'Intégrité périodique'
},
{
'taskId': '04',
'route' : 'medona/ArchiveDelivery/updateProcessBatch',
'description' : 'Traiter les communications'
},
{
'taskId': '05',
'route' : 'medona/ArchiveDestruction/updateProcessAll',
'description' : 'Traiter les destructions'
},
{
'taskId': '06',
'route' : 'medona/ArchiveRestitution/updateProcessBatch',
'description' : 'Traiter les restitutions'
},
{
'taskId': '07',
'route' : 'medona/ArchiveTransfer/updateProcessBatch',
'description' : 'Traiter les transferts'
},
{
'taskId': '08',
'route' : 'medona/ArchiveTransfer/updateValidateBatch',
'description' : 'Valider les transferts'
},
{
'taskId': '09',
'route' : 'medona/message/deleteMessageDirectoryPurge',
'description' : 'Purge des bordereaux'
}
]"
```
*Voir sous-menu "Base de données" pour la suppression de la table "batchProcessing"."task".*
### Menu
Le menu a été restructuré.
Il vous suffit de remplacer le fichier "menu.ini" utilisé par votre application par celui livré par défaut dans le répertoire `data`.
## Base de données
Un fichier de migration a été mis en place pour faciliter la migration de données.
Ce fichier se nomme `apv2_v2.1.sql` et se situe dans le dossier `src/ext/archivesPubliques/data/sql/pgsql`.
Voici le detail de ce fichier :
Ajout d'une liaison entre le profil et le niveau de service. La fonctionnalité n'est pas disponible pour l'archivage public.
```sql
ALTER TABLE "organization"."archivalProfileAccess" ADD COLUMN "serviceLevelReference" text;
```
Modification du type de la colonne "size"
```sql
ALTER TABLE "digitalResource"."digitalResource" ALTER COLUMN "size" TYPE bigint;
```
Ajout du processus de transfert sortant.
```sql
ALTER TABLE "medona"."message" ADD COLUMN "isIncoming" BOOLEAN;
UPDATE "medona"."message" SET "isIncoming" = TRUE WHERE "type" = 'ArchiveTransfer';
```
Suppression des tables correspondants à la liste des tâches et des routes publiques.
```sql
alter table "batchProcessing"."scheduling" drop constraint "scheduling_taskId_fkey";
DROP TABLE "batchProcessing"."task";
DROP TABLE "auth"."publicUserStory";
```
Ajout de la fonctionnalité "Reprise sur bordereaux" sur les transferts entrants.
```sql
INSERT INTO "lifeCycle"."eventFormat" ("type", "format", "notification", "message") VALUES
('medona/retry', 'type senderOrgRegNumber senderOrgName recipientOrgRegNumber recipientOrgName reference', FALSE, 'Message %14$s de type %9$s réinitialisé par %13$s (%12$s)');
```
Modification des vues pour l'archivage public.
```sql
DROP VIEW IF EXISTS "archivesPubliques"."documentDescription";
CREATE OR REPLACE VIEW "archivesPubliques"."documentDescription" AS
SELECT "archive"."archiveId",
"archive"."originatorArchiveId",
"archive"."depositorArchiveId",
"archive"."archiveName",
"archive"."originatorOrgRegNumber",
"archive"."originatorOwnerOrgId",
"archive"."depositorOrgRegNumber",
"archive"."archiverOrgRegNumber",
"archive"."status",
"archive"."archivalProfileReference",
"archive"."archivalAgreementReference",
"archive"."finalDisposition",
"archive"."disposalDate",
"archive"."descriptionClass",
"archive"."parentArchiveId",
"archive"."depositDate",
"archive"."accessRuleCode",
"archive"."accessRuleDuration",
"archive"."accessRuleStartDate",
"archive"."accessRuleComDate",
"archive"."retentionDuration",
"archive"."retentionStartDate",
"archive"."retentionRuleCode",
"content"."contentId",
"content"."description",
"content"."descriptionLevel",
"content"."title",
"content"."filePlanPosition",
"content"."documentType",
"content"."language",
"content"."descriptionLanguage",
"content"."status" AS "contentStatus",
"content"."version",
"content"."tag",
"content"."spatialCoverage",
"content"."temporalCoverage",
"content"."juridictionalCoverage",
"content"."source",
"content"."createdDate",
"content"."transactedDate",
"content"."acquiredDate",
"content"."sentDate",
"content"."receivedDate",
"content"."registeredDate",
"content"."startDate",
"content"."endDate",
"content"."otherDescriptiveData",
"content"."archiverDocId",
"content"."depositorDocId",
"content"."originatorDocId",
"content"."text",
"digitalResource"."resId",
"digitalResource"."clusterId",
"digitalResource"."size",
"digitalResource"."puid",
"digitalResource"."mimetype",
"digitalResource"."hash",
"digitalResource"."hashAlgorithm",
"digitalResource"."fileExtension",
"digitalResource"."fileName",
"digitalResource"."mediaInfo",
"digitalResource"."created",
"digitalResource"."updated"
FROM "recordsManagement"."archive"
LEFT JOIN "archivesPubliques"."content" ON "archive"."archiveId" = "content"."archiveId" AND "content"."resId" IS NULL
JOIN "digitalResource"."digitalResource" ON "archive"."archiveId" = "digitalResource"."archiveId"
WHERE "archive"."descriptionClass" = 'archivesPubliques/content';
DROP VIEW IF EXISTS "archivesPubliques"."archiveDescription" CASCADE;
CREATE VIEW "archivesPubliques"."archiveDescription" AS
SELECT DISTINCT
"archive"."archiveId",
"archive"."originatorArchiveId",
"archive"."depositorArchiveId",
"archive"."archiveName",
"archive"."originatorOrgRegNumber",
"archive"."originatorOwnerOrgId",
"archive"."depositorOrgRegNumber",
"archive"."archiverOrgRegNumber",
"archive"."status",
"archive"."archivalProfileReference",
"archive"."archivalAgreementReference",
"archive"."finalDisposition",
"archive"."disposalDate",
"archive"."descriptionClass",
"archive"."parentArchiveId",
"archive"."depositDate",
"archive"."accessRuleCode",
"archive"."accessRuleDuration",
"archive"."accessRuleStartDate",
"archive"."accessRuleComDate",
"archive"."retentionDuration",
"archive"."retentionStartDate",
"archive"."retentionRuleCode",
"content"."contentId",
"content"."resId",
"content"."description",
"content"."descriptionLevel",
"content"."title",
"content"."filePlanPosition",
"content"."documentType",
"content"."language",
"content"."descriptionLanguage",
"content"."status" "contentStatus",
"content"."version",
"content"."tag",
"content"."spatialCoverage",
"content"."temporalCoverage",
"content"."juridictionalCoverage",
"content"."source",
"content"."createdDate",
"content"."transactedDate",
"content"."acquiredDate",
"content"."sentDate",
"content"."receivedDate",
"content"."registeredDate",
"content"."startDate",
"content"."endDate",
"content"."otherDescriptiveData",
"content"."archiverDocId",
"content"."depositorDocId",
"content"."originatorDocId",
"content"."text"
FROM "recordsManagement"."archive"
LEFT JOIN "archivesPubliques"."content" ON "archive"."archiveId" = "content"."archiveId" AND "resId" IS NULL
WHERE "archive"."descriptionClass" = 'archivesPubliques/content';
```
\ No newline at end of file
...@@ -760,7 +760,7 @@ class content implements \bundle\recordsManagement\Controller\archiveDescription ...@@ -760,7 +760,7 @@ class content implements \bundle\recordsManagement\Controller\archiveDescription
//$queryParts['accessRule'] = $this->getAccessRuleAssert(); //$queryParts['accessRule'] = $this->getAccessRuleAssert();
$queryParts[] = \laabs::newController('recordsManagement/archive')->getArchiveAssert($archiveArgs); $queryParts[] = \laabs::newController('recordsManagement/archive')->getArchiveAssert($archiveArgs,$queryParams);
// Json // Json
if (!empty($description)) { if (!empty($description)) {
......
...@@ -37,6 +37,7 @@ trait ArchiveTransferSendingTrait ...@@ -37,6 +37,7 @@ trait ArchiveTransferSendingTrait
public function send($message) public function send($message)
{ {
$archiveTransferReply = abstractMessage::send($message); $archiveTransferReply = abstractMessage::send($message);
$archiveTransferReply->date = date_format($archiveTransferReply->date, "Y-m-d\TH:i:s\Z");
$archiveTransferReply->transferIdentifier = \laabs::newInstance('seda/ID', $message->reference); $archiveTransferReply->transferIdentifier = \laabs::newInstance('seda/ID', $message->reference);
......
...@@ -697,7 +697,7 @@ abstract class abstractMessage ...@@ -697,7 +697,7 @@ abstract class abstractMessage
if ($rmArchive->finalDisposition == "preservation") { if ($rmArchive->finalDisposition == "preservation") {
$appraisalRule->code = "conserver"; $appraisalRule->code = "conserver";
} else { } else {
$appraisalRule->code = "détruire"; $appraisalRule->code = "detruire";
} }
$appraisalRule->duration = $rmArchive->retentionDuration; $appraisalRule->duration = $rmArchive->retentionDuration;
...@@ -828,7 +828,7 @@ abstract class abstractMessage ...@@ -828,7 +828,7 @@ abstract class abstractMessage
$this->validateSchema($message); $this->validateSchema($message);
} catch (\Exception $e) { } catch (\Exception $e) {
// TEMP // TEMP
//file_put_contents($this->messageDirectory.DIRECTORY_SEPARATOR.$message->messageId. DIRECTORY_SEPARATOR . 'exception.txt', (string) $e); file_put_contents($this->messageDirectory.DIRECTORY_SEPARATOR.$message->messageId. DIRECTORY_SEPARATOR . 'exception.txt', (string) $e);
} }
// Documents // Documents
...@@ -921,7 +921,11 @@ abstract class abstractMessage ...@@ -921,7 +921,11 @@ abstract class abstractMessage
} elseif ($object->identification->value == $message->senderOrg->registrationNumber) { } elseif ($object->identification->value == $message->senderOrg->registrationNumber) {
$organization = $message->senderOrg; $organization = $message->senderOrg;
} else { } else {
$organization = \laabs::callService('organization/organization/readByregnumber', $object->identification->value)->orgName; try {
$organization = \laabs::callService('organization/organization/readByregnumber', $object->identifier->value)->orgName;
} catch (\Exception $e) {
$organization = "Organisation inconnue (" . $object->identifier->value . ")";
}
} }
return $organization; return $organization;
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
<?merge .appraisalRule.bool() ?> <?merge .appraisalRule.bool() ?>
<AppraisalRule> <AppraisalRule>
<Code><?merge .appraisalRule.code ?></Code> <Code><?merge .appraisalRule.code ?></Code>
<Duration><?merge .appraisalRule.Duration ?></Duration> <Duration><?merge .appraisalRule.duration ?></Duration>
<StartDate><?merge .appraisalRule.startDate ?></StartDate> <StartDate><?merge .appraisalRule.startDate ?></StartDate>
</AppraisalRule> </AppraisalRule>
<?merge .archiveObject /seda/ArchiveObject.xml ?> <?merge .archiveObject /seda/ArchiveObject.xml ?>
......
...@@ -20,9 +20,18 @@ ...@@ -20,9 +20,18 @@
<CustodialHistoryItem when="[?merge .when ?]"><?merge .value ?></CustodialHistoryItem> <CustodialHistoryItem when="[?merge .when ?]"><?merge .value ?></CustodialHistoryItem>
</CustodialHistory> </CustodialHistory>
<?merge .contentDescription.keyword.array() ?><Keyword> <?merge .contentDescription.keyword.array() ?><Keyword>
<KeywordContent role="[?merge .keywordContent.role @role ?]"><?merge .keywordContent.value ?></KeywordContent> <?merge .keywordContent.value.bool() ?>
<KeywordReference schemeID="[?merge .keywordReference.schemeID @schemeID ?]" schemeName="[?merge .keywordReference.schemeName @schemeName ?]" schemeAgencyID="[?merge .keywordReference.schemeAgencyID @schemeAgencyID ?]" schemeAgencyName="[?merge .keywordReference.schemeAgencyName @schemeAgencyName ?]" schemeVersionID="[?merge .keywordReference.schemeVersionID @schemeVersionID ?]" schemeDataURI="[?merge .keywordReference.schemeDataURI @schemeDataURI ?]" schemeURI="[?merge .keywordReference.schemeURI @schemeURI ?]"><?merge .keywordReference.value ?></KeywordReference> <KeywordContent role="[?merge .keywordContent.role @role ?]">
<KeywordType listVersionID="[?merge .keywordType.listVersionID @listVersionID ?]"><?merge .keywordType ?></KeywordType> <?merge .keywordContent.value ?>
</KeywordContent>
<?merge .keywordReference.value.bool() ?>
<KeywordReference schemeID="[?merge .keywordReference.schemeID @schemeID ?]" schemeName="[?merge .keywordReference.schemeName @schemeName ?]" schemeAgencyID="[?merge .keywordReference.schemeAgencyID @schemeAgencyID ?]" schemeAgencyName="[?merge .keywordReference.schemeAgencyName @schemeAgencyName ?]" schemeVersionID="[?merge .keywordReference.schemeVersionID @schemeVersionID ?]" schemeDataURI="[?merge .keywordReference.schemeDataURI @schemeDataURI ?]" schemeURI="[?merge .keywordReference.schemeURI @schemeURI ?]">
<?merge .keywordReference.value ?>
</KeywordReference>
<?merge .keywordType.bool() ?>
<KeywordType listVersionID="[?merge .keywordType.listVersionID @listVersionID ?]">
<?merge .keywordType ?>
</KeywordType>
</Keyword> </Keyword>
<?merge .contentDescription.originatingAgency.bool() ?> <?merge .contentDescription.originatingAgency.bool() ?>
<OriginatingAgency> <OriginatingAgency>
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
* along with bundle seda. If not, see <http://www.gnu.org/licenses/>. * along with bundle seda. If not, see <http://www.gnu.org/licenses/>.
*/ */
namespace ext\archivesPubliques\bundle\seda2\Controller; namespace ext\archivesPubliques\bundle\seda2\Controller;
use core\Exception;
/** /**
* Class abstractMessage * Class abstractMessage
...@@ -444,7 +445,11 @@ abstract class abstractMessage ...@@ -444,7 +445,11 @@ abstract class abstractMessage
} elseif ($object->identifier->value == $message->senderOrg->registrationNumber) { } elseif ($object->identifier->value == $message->senderOrg->registrationNumber) {
$organization = $message->senderOrg; $organization = $message->senderOrg;
} else { } else {
$organization = \laabs::callService('organization/organization/readByregnumber', $object->identifier->value)->orgName; try {
$organization = \laabs::callService('organization/organization/readByregnumber', $object->identifier->value)->orgName;
} catch (\Exception $e) {
$organization = "Organisation inconnue (" . $object->identifier->value . ")";
}
} }
return $organization; return $organization;
......
...@@ -69,28 +69,28 @@ ...@@ -69,28 +69,28 @@
<div class="col-md-offset-2"> <div class="col-md-offset-2">
<table class="table table-condensed"> <table class="table table-condensed">
<thead> <thead>
<th>Thesaurus</th> <th>Thesaurus</th>
<th>Reference / Valeur</th> <th>Reference / Valeur</th>
<th></th> <th></th>
</thead> </thead>
<tbody id="publicArchive_keywordsList"> <tbody id="publicArchive_keywordsList">
<tr> <tr>
<td> <td>
<select class="form-control" name="type" id="publicArchive_keywordType"> <select class="form-control" name="type" id="publicArchive_keywordType">
<option value=""></option> <option value=""></option>
<option value="T1">Mot-matière</option> <option value="T1">Mot-matière</option>
<option value="T2">Activité</option> <option value="T2">Activité</option>
<option value="T3">Type de document</option> <option value="T3">Type de document</option>
<option value="T4">Contexte historique</option> <option value="T4">Contexte historique</option>
</select> </select>
</td> </td>
<td> <td>
<input type="text" id="publicArchive_keywordValue" class="form-control" placeholder="Reference / Valeur"/> <input type="text" id="publicArchive_keywordValue" class="form-control" placeholder="Reference / Valeur"/>
</td> </td>
<td> <td>
<button type="button" class="btn btn-success" id="publicArchive_addKeyword" title="Add" disabled><span class="fa fa-plus"></span></button> <button type="button" class="btn btn-success" id="publicArchive_addKeyword" title="Add" disabled><span class="fa fa-plus"></span></button>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
...@@ -108,11 +108,11 @@ ...@@ -108,11 +108,11 @@
<option value="disposable">En cours d'&eacute;limination</option> <option value="disposable">En cours d'&eacute;limination</option>
<option value="restituable">En cours de restitution</option> <option value="restituable">En cours de restitution</option>
<option value="transferable">En cours de transfert</option> <option value="transferable">En cours de transfert</option>
<option value="disposed">&Eacute;limin&eacute;e</option> <option value="disposed">&Eacute;limin&eacute;e</option>
<option value="transfered">Transf&eacute;r&eacute;e</option> <option value="transfered">Transf&eacute;r&eacute;e</option>
<option value="restituted">Restitu&eacute;e</option> <option value="restituted">Restitu&eacute;e</option>
<option value="error">Erreur</option> <option value="error">Erreur</option>
</select> </select>
</div> </div>
...@@ -152,7 +152,7 @@ ...@@ -152,7 +152,7 @@
</label> </label>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-4 control-label">DUA &eacute;chue</label> <label class="col-sm-4 control-label">DUA &eacute;chue</label>
<div class="btn-group col-sm-6" data-toggle="buttons"> <div class="btn-group col-sm-6" data-toggle="buttons">
<label class="btn btn-default" title="Oui"> <label class="btn btn-default" title="Oui">
...@@ -301,7 +301,7 @@ ...@@ -301,7 +301,7 @@
$('.toggle-off').removeClass('btn-info') //class="toggle btn btn-default off" //class="btn btn-default active toggle-off" $('.toggle-off').removeClass('btn-info') //class="toggle btn btn-default off" //class="btn btn-default active toggle-off"
} }
}); });
/* ------ SEARCH FORM ------ */ /* ------ SEARCH FORM ------ */
$('#contain').keypress(function (e) { $('#contain').keypress(function (e) {
if (e.which != 13) { if (e.which != 13) {
...@@ -377,18 +377,18 @@ ...@@ -377,18 +377,18 @@
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'), datumTokenizer: Bloodhound.tokenizers.obj.whitespace('label'),
queryTokenizer: Bloodhound.tokenizers.whitespace, queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: { remote: {
wildcard: '%QUERY',
url: '/thesaurus/T1/%QUERY', url: '/thesaurus/T1/%QUERY',
replace: function(url, query) { replace: function(url, query) {
thesaurus = $('#publicArchive_keywordType').val(); thesaurus = $('#publicArchive_keywordType').val();
return '/thesaurus/'+thesaurus+'/'+query; return '/thesaurus/'+thesaurus+'/'+query;
}, },
ajax : { transform: function(response) {
async: false return response;
} }
}, },
limit: 10 limit: 10
}); });
keywords.initialize();
// initialize typeahead // initialize typeahead
$('#publicArchive_keywordValue').typeahead( $('#publicArchive_keywordValue').typeahead(
...@@ -399,15 +399,17 @@ ...@@ -399,15 +399,17 @@
}, },
{ {
name: 'keywords', name: 'keywords',
displayKey: 'label', templates: {
source: function(query, cb) { suggestion: function(keyword) {