Merge pull request #3181 from HRavalomanana/PHRAS-2761_add_status_change_capabilities-to_quarantine

PHRAS-2761 #comment port to 4.1 add status change to quarantine
This commit is contained in:
Nicolas Maillat
2019-11-05 17:45:39 +01:00
committed by GitHub
6 changed files with 506 additions and 131 deletions

View File

@@ -126,6 +126,16 @@ class LazaretController extends Controller
$ret = $lazaretManipulator->add($file_id, $keepAttributes, $attributesToKeep); $ret = $lazaretManipulator->add($file_id, $keepAttributes, $attributesToKeep);
try{
// get the new record
$record = \Collection::getByBaseId($this->app, $request->request->get('bas_id'))->get_databox()->get_record($ret['result']['record_id']);
$postStatus = (array) $request->request->get('status');
// update status
$this->updateRecordStatus($record, $postStatus);
}catch(\Exception $e){
$ret['message'] = $this->app->trans('An error occured when wanting to change status!');
}
return $this->app->json($ret); return $this->app->json($ret);
} }
@@ -216,6 +226,7 @@ class LazaretController extends Controller
return $this->app->json($ret); return $this->app->json($ret);
} }
$postStatus = (array) $request->request->get('status');
$path = $this->app['tmp.lazaret.path'] . '/'; $path = $this->app['tmp.lazaret.path'] . '/';
$lazaretFileName = $path .$lazaretFile->getFilename(); $lazaretFileName = $path .$lazaretFile->getFilename();
@@ -233,6 +244,9 @@ class LazaretController extends Controller
'' ''
); );
// update status
$this->updateRecordStatus($record, $postStatus);
//Delete lazaret file //Delete lazaret file
$manager = $this->getEntityManager(); $manager = $this->getEntityManager();
$manager->remove($lazaretFile); $manager->remove($lazaretFile);
@@ -278,6 +292,35 @@ class LazaretController extends Controller
); );
} }
/**
* @param Request $request
* @param $databox_id
* @param $record_id
* @return \Symfony\Component\HttpFoundation\JsonResponse
*/
public function getDestinationStatus(Request $request, $databox_id, $record_id)
{
if (!$request->isXmlHttpRequest()) {
$this->app->abort(400);
}
$record = new \record_adapter($this->app, (int) $databox_id, (int) $record_id);
$databox = $this->findDataboxById($databox_id);
$statusStructure = $databox->getStatusStructure();
$recordsStatuses = [];
foreach ($statusStructure as $status) {
// make the key as a string for the json usage in javascript
$bit = "'".$status['bit']."'";
if (!isset($recordsStatuses[$bit])) {
$recordsStatuses[$bit] = $status;
}
$statusSet = \databox_status::bitIsSet($record->getStatusBitField(), $status['bit']);
if (!isset($recordsStatuses[$bit]['flag'])) {
$recordsStatuses[$bit]['flag'] = (int) $statusSet;
}
}
return $this->app->json(['status' => $recordsStatuses]);
}
/** /**
* @return LazaretFileRepository * @return LazaretFileRepository
*/ */
@@ -293,4 +336,32 @@ class LazaretController extends Controller
{ {
return $this->app['border-manager']; return $this->app['border-manager'];
} }
/**
* Set new status to selected record
*
* @param \record_adapter $record
* @param array $postStatus
* @return array|null
*/
private function updateRecordStatus(\record_adapter $record, array $postStatus)
{
$sbasId = $record->getDataboxId();
if (isset($postStatus[$sbasId]) && is_array($postStatus[$sbasId])) {
$postStatus = $postStatus[$sbasId];
$currentStatus = strrev($record->getStatus());
$newStatus = '';
foreach (range(0, 31) as $i) {
$newStatus .= isset($postStatus[$i]) ? ($postStatus[$i] ? '1' : '0') : $currentStatus[$i];
}
$record->setStatus(strrev($newStatus));
$this->getDataboxLogger($record->getDatabox())
->log($record, \Session_Logger::EVENT_STATUS, '', '');
return [
'current_status' => $currentStatus,
'new_status' => $newStatus,
];
}
return null;
}
} }

View File

@@ -82,6 +82,11 @@ class Lazaret implements ControllerProviderInterface, ServiceProviderInterface
->assert('file_id', '\d+') ->assert('file_id', '\d+')
->bind('lazaret_thumbnail'); ->bind('lazaret_thumbnail');
$controllers->get('/{databox_id}/{record_id}/status', 'controller.prod.lazaret:getDestinationStatus')
->assert('databox_id', '\d+')
->assert('record_id', '\d+')
->bind('lazaret_destination_status');
return $controllers; return $controllers;
} }
} }

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Model\Entities; namespace Alchemy\Phrasea\Model\Entities;
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo; use Gedmo\Mapping\Annotation as Gedmo;
use \record_adapter; use \record_adapter;
@@ -474,4 +475,32 @@ class LazaretFile
return $merged; return $merged;
} }
/**
* @param Application $app
* @return array|null
*/
public function getStatus(Application $app)
{
/**@var LazaretAttribute $atribute*/
foreach ($this->attributes as $atribute) {
if ($atribute->getName() == AttributeInterface::NAME_STATUS) {
$databox = $this->getCollection($app)->get_databox();
$statusStructure = $databox->getStatusStructure();
$recordsStatuses = [];
foreach ($statusStructure as $status) {
$bit = $status['bit'];
if (!isset($recordsStatuses[$bit])) {
$recordsStatuses[$bit] = $status;
}
$statusSet = \databox_status::bitIsSet(bindec($atribute->getValue()), $bit);
if (!isset($recordsStatuses[$bit]['flag'])) {
$recordsStatuses[$bit]['flag'] = (int) $statusSet;
}
}
return $recordsStatuses;
}
}
return null;
}
} }

View File

@@ -226,6 +226,8 @@ class LazaretManipulator
$this->entityManager->remove($lazaretFile); $this->entityManager->remove($lazaretFile);
$this->entityManager->flush(); $this->entityManager->flush();
$ret['result']['record_id'] = $record->getRecordId();
$ret['success'] = true; $ret['success'] = true;
} catch (\Exception $e) { } catch (\Exception $e) {
$ret['message'] = $this->app->trans('An error occured'); $ret['message'] = $this->app->trans('An error occured');

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="32px" height="32px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: sketchtool 58 (101010) - https://sketch.com -->
<title>5609DDD5-6B9C-411B-B926-EEA284949013</title>
<desc>Created with sketchtool.</desc>
<defs>
<polygon id="path-1" points="0 0 22.3169609 16.2062701 0 32.4125403"></polygon>
<filter x="-31.4%" y="-15.4%" width="162.7%" height="143.2%" filterUnits="objectBoundingBox" id="filter-3">
<feOffset dx="0" dy="2" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
</filter>
</defs>
<g id="Pictos" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pictos/Arrow/Pleine">
<g id="Colors/Black" transform="translate(5.000000, 0.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<g id="Mask" fill="black" fill-opacity="1">
<use filter="url(#filter-3)" xlink:href="#path-1"></use>
</g>
<g id="Colors/Rectangular/Black" mask="url(#mask-2)" fill="#000000">
<g transform="translate(-5.000000, 0.000000)" id="Rectangle">
<rect x="0" y="0" width="32" height="32"></rect>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -92,12 +92,12 @@
} }
} }
$(".records-subititution .diapo", scope) /* $(".records-subititution .diapo", scope)
.bind('click', function(e){ .bind('click', function(e){
$(this).closest('.lazaret-proposals').find('.diapo').removeClass('selected'); $(this).closest('.lazaret-proposals').find('.diapo').removeClass('selected');
$(this).addClass('selected'); $(this).addClass('selected');
} }
); );*/
$(".records-subititution .captionTips", scope).tooltip(); $(".records-subititution .captionTips", scope).tooltip();
$(".records-subititution .infoTips", scope).tooltip(); $(".records-subititution .infoTips", scope).tooltip();
@@ -176,27 +176,32 @@
emptying = true; emptying = true;
f(); f();
}); });
var data;
//add lazaret file click action //add lazaret file click action
$("button.add-lazaret", scope).bind('click', function () { $("button.add-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
var lazaretId = getLazaretId(that); var lazaretId = getLazaretId(that);
var destinationCollectionId = getDestinationId(that); var destinationCollectionId = getDestinationId(that);
var container = $(this).closest('.wrapper-item');
var form = $(this).closest("form");
/*fix POST on firefox*/
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/prod/lazaret/' + lazaretId + '/force-add/', url: '/prod/lazaret/' + lazaretId + '/force-add/',
dataType: 'json', dataType: 'json',
data : { data: data,
bas_id:destinationCollectionId,
keep_attributes: 1
},
beforeSend: function () { beforeSend: function () {
startAjax(that); startAjax(that);
}, },
success: function (data) { success: function (data) {
if (data.success) { if (data.success) {
that.closest(".wrapper-item").remove(); container.remove();
} else { } else {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content: data.message content: data.message
@@ -221,6 +226,12 @@
$("button.delete-lazaret", scope).bind('click', function () { $("button.delete-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
var lazaretId = getLazaretId(that); var lazaretId = getLazaretId(that);
var container = $(this).closest('.wrapper-item');
var form = $(this).closest("form");
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
@@ -231,7 +242,7 @@
}, },
success: function (data) { success: function (data) {
if (data.success) { if (data.success) {
that.closest(".wrapper-item").remove(); container.remove();
} else { } else {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content: data.message content: data.message
@@ -252,6 +263,89 @@
}); });
}); });
//update status list
function resetStatus(that) {
that.removeClass('selected');
var html = that.parent().closest('.wrapper-item').find(".status-backup").html();
that.parent().closest('.wrapper-item').find(".status-container").html('');
that.parent().closest('.wrapper-item').find(".status-container").append(html);
};
$(".span12 img, .reset-status").click(function () {
var that = $(this).closest('.wrapper-item').find('.lazaret-proposals .diapo');
resetStatus(that);
});
$(".records-subititution .diapo", scope).bind('click', function () {
var that = $(this);
var diapo = that.closest('.lazaret-proposals').find('.diapo');
var container = that.closest('.wrapper-item');
diapo.not(this).removeClass('selected');
/*Set selected or not to check for sending ajax request*/
if (that.hasClass("selected")) {
resetStatus(that);
} else {
that.addClass('selected');
var elements = $(".selected", container);
var recordId = elements.first().attr("data-record_id");
var sBas = elements.first().attr("sbas");
$.ajax({
type: 'GET',
url: '/prod/lazaret/' + sBas + '/' + recordId + '/status',
dataType: 'json',
beforeSend: function () {
startAjax(that);
},
success: function (data) {
if (data.status) {
html = '';
for ([key, value] of Object.entries(data.status)) {
if (value.flag == 1) {
checkValOff = '';
checkValOn = 'checked=checked';
} else {
checkValOff = 'checked=checked';
checkValOn = '';
}
var labelOff = value['labels_off_i18n']["{{ app['locale'] }}"];
var labelOn = value['labels_on_i18n']["{{ app['locale'] }}"];
if (labelOff == null || labelOff == "") {
labelOff = 'off';
}
if (labelOn == null || labelOn == "") {
labelOn = 'on';
}
html += '<tr>';
html += '<td class="status-tab-left">';
if (value['img_off'] != null) {
html += ' <img src="{{ value['img_off'] }}" width="16" height="16" />';
}
;
html += '<span>' + labelOff + '</span>';
html += '<input type="radio" name="status[' + sBas + '][' + value.bit + ']" value="0" ' + checkValOff + ' />';
html += '</td>';
html += '<td class="status-tab-right">';
html += '<input type="radio" name="status[' + sBas + '][' + value.bit + ']" value="1" ' + checkValOn + ' />';
html += '<span>' + labelOn + '</span>';
if (value['img_on'] != null) {
html += '<img src="' + value['img_on'] + '" width="16" height="16" />';
}
;
html += '</td>';
html += '</tr>';
}
;
that.parent().closest('.wrapper-item').find(".status-container").html('');
that.parent().closest('.wrapper-item').find(".status-container").append(html);
}
},
complete: function () {
stopAjax(that);
reloadContent();
}
});
}
});
//substitute lazaret file click action //substitute lazaret file click action
$("button.subtitute-lazaret", scope).bind('click', function () { $("button.subtitute-lazaret", scope).bind('click', function () {
var that = $(this); var that = $(this);
@@ -278,20 +372,27 @@
} }
var recordId = elements.first().attr("data-record_id"); var recordId = elements.first().attr("data-record_id");
var form = $(this).closest("form");
$(".record_id").val(recordId);
var form = $(this).closest("form");
data = form.serializeArray();
var allData = that.parent().closest('.wrapper-item').find(".change-record-wrapper").html();
that.closest(".form-backup ").append(allData);
that.parent().closest('.wrapper-item').find(".change-record ").remove();
$.ajax({ $.ajax({
type: 'POST', type: 'POST',
url: '/prod/lazaret/' + lazaretId + '/accept/', url: '/prod/lazaret/' + lazaretId + '/accept/',
dataType: 'json', dataType: 'json',
data:{ data: data,
record_id: recordId
},
beforeSend: function () { beforeSend: function () {
startAjax(that); startAjax(that);
}, },
success: function (data) { success: function (data) {
if (data.success) { if (data.success) {
that.closest(".wrapper-item").remove(); container.remove();
} else { } else {
var html = _.template($("#alert_error_tpl").html(), { var html = _.template($("#alert_error_tpl").html(), {
content: data.message content: data.message
@@ -311,18 +412,18 @@
} }
}); });
}); });
/*Toggle status block*/
$(".toggle-status").click(function () {
$(this).nextAll('.status-wrapper').first().toggleClass('hidden');
});
}); });
</script> </script>
<style>
.lazaret-proposals .diapo {
float:none;
}
</style>
{% macro lazaretElement(app, file) %} {% macro lazaretElement(app, file) %}
{% import "common/thumbnail.html.twig" as thumb %} {% import "common/thumbnail.html.twig" as thumb %}
{% set records = file.getRecordsToSubstitute(app, true) %} {% set records = file.getRecordsToSubstitute(app, true) %}
<div class="lazaret-file span4"> <div class="lazaret-file span4">
<h5>{{ "Last uploaded version" | trans }}</h5> <h5>{{ "Last uploaded version" | trans }}</h5>
<ul class="thumbnails"> <ul class="thumbnails">
<li class="span12"> <li class="span12">
@@ -344,6 +445,66 @@
<p>{{ border_checker_from_fqcn(check.getCheckClassname()).getMessage(app['translator']) }}</p> <p>{{ border_checker_from_fqcn(check.getCheckClassname()).getMessage(app['translator']) }}</p>
{% endfor %} {% endfor %}
</div> </div>
<form class="change-record" name="change-records-status" action="/" method="POST">
<div class="change-record-wrapper">
{% set collection = file.getCollection(app) %}
<input type="hidden" name="bas_id" value="{{ collection.get_base_id() }}">
<input type="hidden" name="keep_attributes" value="1">
<input class="record_id" type="hidden" name="record_id">
<div class="update-status">
<div id="status-{{ collection.get_base_id() }}" class='collection-status'>
<a href="#" class="reset-status btn">Reset status</a>
<h5 class="toggle-status">{{ 'upload:: Status :' | trans }} <img src="/assets/common/images/icons/icon-right-arrow.svg" width="10" height="10" class="btn-status"></h5>
<div class="status-wrapper hidden">
<table style="margin: auto">
<tbody class="status-container">
{% if file.getStatus(app) is not null %}
{% for bit, status in file.getStatus(app) %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" {% if status['flag'] == 0 %}checked="checked"{% endif%}/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" {% if status['flag'] == 1 %}checked="checked"{% endif%} />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
{% for bit, status in collection.get_databox().getStatusStructure() %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" checked="checked"/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</div>
</div>
<div class="btn-group" style="text-align:center; padding:5px;"> <div class="btn-group" style="text-align:center; padding:5px;">
<button class="btn add-lazaret" title="{{ "Add" | trans }}"> <button class="btn add-lazaret" title="{{ "Add" | trans }}">
<img src="/assets/common/images/icons/add.png" width="16" height="16" class="btn-image">{{ "Add" | trans }} <img src="/assets/common/images/icons/add.png" width="16" height="16" class="btn-image">{{ "Add" | trans }}
@@ -358,6 +519,55 @@
{% endif %} {% endif %}
</div> </div>
</div> </div>
</form>
<div class="hidden form-backup"></div>
{# bloc to backup initial value of status list#}
<table class="hidden">
<tbody class="status-backup">
{% if file.getStatus(app) is not null %}
{% for bit, status in file.getStatus(app) %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16"/>
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" {% if status['flag'] == 0 %}checked="checked"{% endif%}/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" {% if status['flag'] == 1 %}checked="checked"{% endif%} />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16"/>
{% endif %}
</td>
</tr>
{% endfor %}
{% else %}
{% for bit, status in collection.get_databox().getStatusStructure() %}
<tr>
<td class="status-tab-left">
{% if status['img_off'] is not empty %}
<img src="{{ status['img_off'] }}" width="16" height="16" />
{% endif %}
<span>{{ status['labels_off_i18n'][app['locale']]|default('off') }}</span>
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="0" checked="checked"/>
</td>
<td class="status-tab-right">
<input type="radio" name="status[{{ collection.get_sbas_id() }}][{{ bit }}]" value="1" />
<span for="labelon">{{ status['labels_on_i18n'][app['locale']]|default('on') }}</span>
{% if status['img_on'] is not empty %}
<img src="{{ status['img_on'] }}" width="16" height="16" />
{% endif %}
</td>
</tr>
{% endfor %}
{% endif %}
</tbody>
</table>
</div>
</li> </li>
</ul> </ul>
{# Store lazaret file id in hidden input #} {# Store lazaret file id in hidden input #}
@@ -406,3 +616,30 @@
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
<style>
.lazaret-proposals .diapo {
float:none;
}
.collection-status {
margin: 0 11px 14px;
background: #f5f5f5;
padding-bottom: 10px;
color: #151515;
}
.collection-status h5 {
padding: 10px 10px 0 10px;
cursor: pointer;
margin-bottom: 0;
}
.reset-status {
display: inline-block;
float: right;
background: #fff;
border: 1px solid;
padding: 2px 5px;
margin-top: -4px;
margin-right: -6px;
}
</style>