Commit c2fe7bf8 authored by Alexandre Morin's avatar Alexandre Morin

Merge branch 'Support/2.4.X' into 'master'

Support/2.4.x master

See merge request !286
parents dcef8a19 738ba413
# CHANGELOG
## Version 2.4.4
### IHM
- `Fixed` Retrait de l’affichage des ressources si l'archive est en cours de suppression
### Métadonnées
- `Fixed` Ajout d'un bouton dans la modale de détail de l'archive permettant la conversion unitaire d'un document
- `Fixed` Rétablissement de l'affichage des fichiers convertis et des relations dans la modale de détails de l'archive
- `Changed` Différenciation entre le fichier d'origine et ses conversions dans l'arborescence du plan de classement
### Sécurité
- `Changed` Ajout du paramètre `lifetime` pour le jeton CSRF qui définit la durée de validité des jetons en secondes. Si omis, durée de 1 heure par défaut.
- `Fixed` Jeton CRSF consommé lorsqu'utilisé.
## Version 2.4.3
### Métadonnées
......
......@@ -64,7 +64,7 @@ class csrf
return;
}
$requestToken = $this->getRequestToken();
$requestToken = \laabs::getToken("Csrf", LAABS_IN_HEADER);
// Get account with LOCK
$this->sdoFactory->beginTransaction();
......@@ -75,17 +75,19 @@ class csrf
return;
}
$accountTokens = $account->authentication->csrf;
switch ($userCommand->method) {
case "create":
case "update":
case "delete":
$requestTokenTime = $this->isValidToken($requestToken, $accountTokens);
if (empty($requestToken)) {
throw new \core\Exception('Attempt to access without a valid token 1', 412);
}
$requestTokenTime = $this->checkToken($requestToken, $accountTokens);
$accountTokens = $this->shiftTokens($requestTokenTime, $accountTokens);
$accountTokens = $this->addToken($accountTokens);
break;
......@@ -130,21 +132,9 @@ class csrf
}
/**
* Retrieves the request csrf token
*
* @return string
*/
private function getRequestToken()
{
$requestToken = \laabs::getToken("Csrf", LAABS_IN_HEADER);
return $requestToken;
}
/**
* Retrieves the account information with a LOCK on database
* @param bool $lock Lock user
*
*
* @return auth/userAccount
*/
private function getAccount($lock = false)
......@@ -171,10 +161,28 @@ class csrf
if (!is_object($account->authentication->csrf)) {
$account->authentication->csrf = [];
} else {
$account->authentication->csrf = get_object_vars($account->authentication->csrf);
return $account;
}
$account->authentication->csrf = get_object_vars($account->authentication->csrf);
$lifetime = '3600';
if (isset($this->config['lifetime'])) {
$lifetime = $this->config['lifetime'];
}
$duration = \laabs::newDuration('PT'.$lifetime.'S');
$now = \laabs::newTimestamp();
foreach ($account->authentication->csrf as $time => $token) {
$timestamp = \laabs::newTimestamp($time);
$expiration = $timestamp->add($duration);
if ($now->diff($expiration)->invert == 1) {
unset($account->authentication->csrf[$time]);
}
}
return $account;
}
......@@ -214,16 +222,8 @@ class csrf
return end($accountTokens);
}
private function isValidToken($requestToken, $accountTokens)
private function checkToken($requestToken, $accountTokens)
{
if (empty($requestToken)) {
$e = new \core\Exception('Attempt to access without a valid token', 412);
throw $e;
return false;
}
$requestTokenTime = array_search($requestToken, $accountTokens);
if (empty($requestTokenTime)) {
......@@ -240,7 +240,7 @@ class csrf
private function shiftTokens($requestTokenTime, $accountTokens)
{
foreach ($accountTokens as $time => $token) {
if ($time < $requestTokenTime) {
if ($time <= $requestTokenTime) {
unset($accountTokens[$time]);
}
}
......
......@@ -168,7 +168,7 @@ class archive
} else {
$archive->hasRights = $archiveController->checkRights($archive);
}
} catch(\Exception $e) {
} catch (\Exception $e) {
$archive->hasRights = false;
}
}
......@@ -230,7 +230,7 @@ class archive
{
$this->view->addContentFile("recordsManagement/archive/archiveInfo/archiveInfo.html");
// Managment metadata
// Management metadata
$this->setManagementMetadatas($archive);
// Descriptive metadata
......@@ -254,7 +254,7 @@ class archive
$this->view->translate();
$this->view->merge();
return $this->view->saveHtml();
}
......@@ -289,7 +289,6 @@ class archive
$this->view->translate();
$this->view->merge();
return $this->view->saveHtml();
}
......@@ -342,7 +341,7 @@ class archive
$this->view->translate();
$this->view->merge();
return $this->view->saveHtml();
}
......@@ -656,7 +655,7 @@ class archive
if ($result == false) {
$count = 0;
} else {
$count = count($result);
$count = 1;
}
$this->json->message = '%1$s document(s) converted.';
$this->json->message = $this->translator->getText($this->json->message);
......@@ -1227,22 +1226,22 @@ class archive
protected function setDigitalResources($archive)
{
if ($archive->status == "disposed") {
if ($archive->status == "disposed" || $archive->status == "restituted" || $archive->status == "transfered") {
$archive->digitalResources = null;
} elseif (isset($archive->digitalResources)) {
foreach ($archive->digitalResources as $key => $digitalResource) {
$archive->digitalResources[$key]->json = json_encode($digitalResource);
$digitalResource->isConvertible = \laabs::callService("digitalResource/digitalResource/updateIsconvertible", $digitalResource);
if (!isset($digitalResource->relatedResource)) {
$digitalResource->relatedResource = [];
continue;
}
foreach ($digitalResource->relatedResource as $relatedResource) {
$relatedResource->isConvertible = \laabs::callService("digitalResource/digitalResource/updateIsconvertible", $relatedResource);
$relatedResource->relationshipType = $this->view->translator->getText($relatedResource->relationshipType, "relationship", "recordsManagement/messages");
} else {
foreach ($digitalResource->relatedResource as $relatedResource) {
$relatedResource->isConvertible = \laabs::callService("digitalResource/digitalResource/updateIsconvertible", $relatedResource);
$relatedResource->relationshipType = $this->view->translator->getText($relatedResource->relationshipType, "relationship", "recordsManagement/messages");
}
}
$archive->digitalResources[$key]->json = json_encode($digitalResource);
}
}
}
......
......@@ -843,10 +843,6 @@ msgid "isTimestampOf"
msgstr "Jeton d'horodatage"
msgctxt "relationship"
msgid "isConversionOf"
msgstr "Document converti"
msgctxt "relationship"
msgid "Indexing modification"
msgstr "Modification de l'index"
......
<div id="resourceInformation" class="row">
<div class="col-xs-12 text-center">
<div id="preview" class="hide" data-format="[?merge displayableFormat ?]"/>
<i class="infoIcon fa fa-file-o"/>
<div id="preview" class="hide" data-format="[?merge displayableFormat ?]" />
<i class="infoIcon fa fa-file-o" />
</div>
<div class="col-xs-12 text-center">
<button type="button" id="viewResource" class="btn btn-link btn-sm" data-resid="" data-archiveid=""><i class ="fa-eye fa">&nbsp;</i>View</button>
<button type="button" id="deleteResource" class="btn btn-link btn-sm hide" data-resid="" data-archiveid="" title2="Delete"><i class ="fa fa-trash">&nbsp;</i>Delete</button>
<button type="button" id="viewResource" class="btn btn-link btn-sm" data-resid="" data-archiveid=""><i class="fa-eye fa">&nbsp;</i>View</button>
<button type="button" id="deleteResource" class="btn btn-link btn-sm hide" data-resid="" data-archiveid="" title2="Delete"><i class="fa fa-trash">&nbsp;</i>Delete</button>
<button type="button" id="convertResource" class="btn btn-link btn-sm hide" data-resid="" data-archiveid=""><i class="fa fa-recycle">&nbsp;</i>Convert</button>
</div>
<div class="col-xs-12">
<table>
<tr>
<th title="Name">Name</th>
<td name="fileName"/>
<td name="fileName" />
</tr>
<tr>
<th title="Creation date">Creation date</th>
<td name="created"/>
<td name="created" />
</tr>
<tr>
<th title="Identifier">Identifier</th>
<td name="resId"/>
<td name="resId" />
</tr>
<tr>
<th title="Size">Size</th>
<td><span name="size"/> <span>bytes</span></td>
<td><span name="size" /> <span>bytes</span></td>
</tr>
<tr>
<th title="Format">Format</th>
......@@ -43,22 +45,27 @@
font-size: 12px;
min-height: calc(95vh - 80px);
}
#resourceInformation table {
table-layout:fixed;
width:100%;
table-layout: fixed;
width: 100%;
}
#resourceInformation table th {
width: 40%;
text-align: right;
}
#resourceInformation table td, #resourceInformation table th {
padding: 0 5px 0 5px ;
#resourceInformation table td,
#resourceInformation table th {
padding: 0 5px 0 5px;
text-overflow: crop;
overflow: hidden;
white-space: nowrap;
}
#resourceInformation .infoIcon {
font-size: 80px;
font-size: 80px;
margin-bottom: 10px;
}
</style>
......@@ -67,10 +74,13 @@
DocumentInformation = {
form: $('#resourceInformation'),
load: function (resource) {
DocumentInformation.form.find("#viewResource").data("resid", resource.resId);
DocumentInformation.form.find("#viewResource").data("archiveid", resource.archiveId);
DocumentInformation.form.find("#deleteResource").data("resid", resource.resId);
DocumentInformation.form.find("#deleteResource").data("archiveid", resource.archiveId);
DocumentInformation.form.find("#convertResource").data("archiveid", resource.archiveId);
DocumentInformation.form.find("#viewResource").data("resid", resource.resId);
DocumentInformation.form.find("#deleteResource").data("resid", resource.resId);
DocumentInformation.form.find("#convertResource").data("resid", resource.resId);
DocumentInformation.form.find('[name="fileName"]').text(resource.fileName).attr('title', resource.fileName);
DocumentInformation.form.find('[name="created"]').text(resource.created).attr('title', resource.created);
DocumentInformation.form.find('[name="size"]').text(resource.size).attr('title', resource.size);
......@@ -79,11 +89,13 @@
DocumentInformation.form.find('[name="puid"]').closest('tr').addClass('hide');
} else {
DocumentInformation.form.find('[name="puid"]').text(resource.puid).attr('title', resource.puid);
}
// cache le bouton de conversion selon le format
if (resource.isConvertible) {
DocumentInformation.form.find("#convertResource").removeClass('hide');
}
if (resource.format) {
var formatname = resource.format.name+' '+resource.format.version;
var formatname = resource.format.name + ' ' + resource.format.version;
DocumentInformation.form.find('[name="format"]').text(formatname).attr('title', formatname);
var iconI = DocumentInformation.form.find(".infoIcon");
......@@ -128,20 +140,26 @@
if (resource.mimetype.match(mimetype)) {
$.ajax({
url : '/'+$("#viewResource").data("archiveid")+"/digitalResource/"+resource.resId,
data : {isCommunication:1},
type : "GET",
dataType : 'html',
success : function(response) {
url: '/' + $("#viewResource").data("archiveid") + "/digitalResource/" +
resource.resId,
data: {
isCommunication: 1
},
type: "GET",
dataType: 'html',
success: function (response) {
$("#preview").removeClass('hide').html(response);
$('#preview').find('object').css('height', '70vh').css('width', '100%');
if (resource.mimetype == 'text/plain' || resource.mimetype == 'application/pdf') {
$('#preview').find('object').css('height', '70vh').css('width',
'100%');
if (resource.mimetype == 'text/plain' || resource.mimetype ==
'application/pdf') {
$('#preview').find('object').attr('height', '300');
}
$('#preview').siblings('i').addClass('hide');
},
error : function(response) {
gritter.show(response.responseJSON.message, response.responseJSON.status, response.responseJSON.errors);
error: function (response) {
gritter.show(response.responseJSON.message, response
.responseJSON.status, response.responseJSON.errors);
}
});
......@@ -151,38 +169,58 @@
});
}
}
$("#viewResource").on("click", function() {
window.open("/recordsManagement/"+$(this).data("archiveid")+"/digitalResource/"+$(this).data("resid")+"?isCommunication=1");
$("#viewResource").on("click", function () {
window.open("/recordsManagement/" + $(this).data("archiveid") + "/digitalResource/" + $(this).data(
"resid") + "?isCommunication=1");
});
// This event refresh view after a click on deleteResource
$('#resourceInformation').onEvent("deleteResourceDone.recordsManagement", function () {
$('#modalArchiveInfo').one('hidden.bs.modal', function (e) {
$('#' + $('#deleteResource').data("archiveid")).find('.viewArchive').click();
}).modal('hide');
});
$("#deleteResource").on("click", function(){
$("#deleteResource").on("click", function () {
var resources = {
resIds : [$(this).data('resid')]
resIds: [$(this).data('resid')]
}
ajax($('#deleteResource'), {
type: "DELETE",
url: '/' + $(this).data("archiveid") + '/digitalResource',
data: JSON.stringify(resources),
dataType: 'json',
contentType: 'application/json',
success: function (response) {
gritter.show(response.message, true);
trigger('deleteResourceDone.recordsManagement');
},
error: function (response) {
gritter.show(response.responseJSON.message, response.responseJSON.status, response
.responseJSON.errors);
}
ajax($('#deleteResource'), {
type: "DELETE",
url: '/' + $(this).data("archiveid") + '/digitalResource',
data: JSON.stringify(resources),
dataType: 'json',
contentType: 'application/json',
success : function (response) {
gritter.show(response.message, true);
trigger('deleteResourceDone.recordsManagement');
},
error : function(response) {
gritter.show(response.responseJSON.message, response.responseJSON.status, response.responseJSON.errors);
}
});
});
});
// This event refresh view after a click on deleteResource
$('#resourceInformation').onEvent("deleteResourceDone.recordsManagement", function()
{
$('#modalArchiveInfo').one('hidden.bs.modal', function(e){
$('#'+$('#deleteResource').data("archiveid")).find('.viewArchive').click();
}).modal('hide');
$("#convertResource").on('click', function () {
var resId = $(this).data('resid');
var archiveId = $(this).data('archiveid');
$.ajax({
type: "PUT",
url: "/recordsManagement/InteractiveConversion/" + resId,
dataType: 'json',
success: function (response) {
gritter.show(response.message, response.status, response.errors);
if (response.status && response.result != false) {
archiveInfoModal.close();
$('#modalArchiveInfo').one('hidden.bs.modal', function () {
archiveInfoModal.load(archiveId);
});
$('#modalArchiveInfo').one('shown.bs.modal', function () {
$("#modalArchiveInfo").find('[href=#digitalResourcesTab]').tab(
"show");
});
}
}
});
});
</script>
\ No newline at end of file
<li class="document" data-archive-id="[?merge .archiveId ?]" data-res-id="[?merge .resId ?]" data-json="[?merge .json ?]">
<span class="">
<small class="documentName"><i class="fa fa-file">&nbsp;</i><?merge .fileName ?></small>
<?merge .relationshipType.ifeq('isConversionOf') ?><i class="fa" data-closed-icon="none" data-opened-icon="none">&nbsp;</i>
<?merge .relatedResource.bool() ?><i class="fa" data-closed-icon="fa-caret-right" data-opened-icon="fa-caret-down">&nbsp;</i>
<small class="documentName">
<?merge .relationshipType.ifeq('isConversionOf') ?><i class="fa fa-files-o fa-fw">&nbsp;</i>
<?merge .relationshipType.bool().not() ?><i class="fa fa-file">&nbsp;</i>
<?merge .fileName ?>
</small>
</span>
<ul>
<?merge .contents /recordsManagement/archive/archiveTree/archiveContentTemplate.html ?>
<?merge .relatedResource /recordsManagement/archive/archiveTree/archiveContentTemplate.html ?>
</ul>
</li>
\ No newline at end of file
......@@ -34,17 +34,25 @@
selected: null,
select: function(e) {
this.unselect();
var li = e.closest('li')
var li = e.closest('li');
if(e.hasClass('archiveName')) {
$("#archiveNameH3").text(e.text());
li.children('span').removeClass('node-default').addClass('node-warning');
li.children('span').removeClass('node-default').addClass('node-warning');
trigger("showDetails.archive", li.data('archive-id'));
this.selected = li;
} else if (e.hasClass('documentName')) {
e.addClass('node-warning');
}
else if (e.hasClass('documentName')) {
// Pour les fichiers convertis, on va récupérer les 'relatedResource' dans le data.json du parent
if (!li.data('json')){
var converted_data = li.parents("li").first().data('json');
$.each(converted_data.relatedResource, function( index, value ) {
if(value.resId == li.data('resId')) {
li.data('json', value);
}
});
}
e.addClass('node-warning').removeClass('node-default');
trigger("showDetails.digitalResource", li.data('json'));
this.selected = li;
}
......
......@@ -17,7 +17,7 @@ var BootstrapTree = {
.find('.fa:first')
.each(function() {
$(this).addClass($(this).data('closed-icon'));
$(this).next().find("i").addClass("fa_folder");
$(this).next().find("i").addClass("fa-folder");
// $(this).next().find("i").addClass("fa-folder").removeClass("fa-folder-o");
});
......
Markdown is supported
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