Refactor status display

This commit is contained in:
Nicolas Le Goff
2015-02-02 11:34:44 +01:00
parent 47e9605aab
commit 111755fa9b
33 changed files with 928 additions and 646 deletions

View File

@@ -114,6 +114,7 @@ use Alchemy\Phrasea\Core\Provider\RepositoriesServiceProvider;
use Alchemy\Phrasea\Core\Provider\SearchEngineServiceProvider; use Alchemy\Phrasea\Core\Provider\SearchEngineServiceProvider;
use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider; use Alchemy\Phrasea\Core\Provider\SerializerServiceProvider;
use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider; use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider;
use Alchemy\Phrasea\Core\Provider\StatusServiceProvider;
use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider; use Alchemy\Phrasea\Core\Provider\SubdefServiceProvider;
use Alchemy\Phrasea\Core\Provider\TasksServiceProvider; use Alchemy\Phrasea\Core\Provider\TasksServiceProvider;
use Alchemy\Phrasea\Core\Provider\TemporaryFilesystemServiceProvider; use Alchemy\Phrasea\Core\Provider\TemporaryFilesystemServiceProvider;
@@ -237,7 +238,7 @@ class Application extends SilexApplication
$this->register(new FeedServiceProvider()); $this->register(new FeedServiceProvider());
$this->register(new FtpServiceProvider()); $this->register(new FtpServiceProvider());
$this->register(new GeonamesServiceProvider()); $this->register(new GeonamesServiceProvider());
$this->register(new StatusServiceProvider());
$this['geonames.server-uri'] = $this->share(function (Application $app) { $this['geonames.server-uri'] = $this->share(function (Application $app) {
return $app['conf']->get(['registry', 'webservices', 'geonames-server'], 'http://geonames.alchemyasp.com/'); return $app['conf']->get(['registry', 'webservices', 'geonames-server'], 'http://geonames.alchemyasp.com/');
}); });

View File

@@ -263,7 +263,7 @@ class Root implements ControllerProviderInterface
$databox = $app['phraseanet.appbox']->get_databox($databox_id); $databox = $app['phraseanet.appbox']->get_databox($databox_id);
$status = $databox->get_statusbits(); $statusStructure = $databox->getStatusStructure();
switch ($errorMsg = $request->query->get('error')) { switch ($errorMsg = $request->query->get('error')) {
case 'rights': case 'rights':
@@ -283,8 +283,8 @@ class Root implements ControllerProviderInterface
break; break;
} }
if (isset($status[$bit])) { if ($statusStructure->hasStatus($bit)) {
$status = $status[$bit]; $status = $statusStructure->getStatus($bit);
} else { } else {
$status = [ $status = [
"labeloff" => '', "labeloff" => '',
@@ -320,10 +320,12 @@ class Root implements ControllerProviderInterface
$app->abort(403); $app->abort(403);
} }
$databox = $app['phraseanet.appbox']->get_databox($databox_id);
$error = false; $error = false;
try { try {
\databox_status::deleteStatus($app, $app['phraseanet.appbox']->get_databox($databox_id), $bit); $app['status.provider']->deleteStatus($databox->getStatusStructure(), $bit);
} catch (\Exception $e) { } catch (\Exception $e) {
$error = true; $error = true;
} }
@@ -349,7 +351,9 @@ class Root implements ControllerProviderInterface
'labels_off' => $request->request->get('labels_off', []), 'labels_off' => $request->request->get('labels_off', []),
]; ];
\databox_status::updateStatus($app, $databox_id, $bit, $properties); $databox = $app['phraseanet.appbox']->get_databox($databox_id);
$app['status.provider']->updateStatus($databox->getStatusStructure(), $bit, $properties);
if (null !== $request->request->get('delete_icon_off')) { if (null !== $request->request->get('delete_icon_off')) {
\databox_status::deleteIcon($app, $databox_id, $bit, 'off'); \databox_status::deleteIcon($app, $databox_id, $bit, 'off');

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\Controller\Api; namespace Alchemy\Phrasea\Controller\Api;
use Alchemy\Phrasea\Status\StatusStructure;
use Silex\ControllerProviderInterface; use Silex\ControllerProviderInterface;
use Alchemy\Phrasea\Cache\Cache as CacheInterface; use Alchemy\Phrasea\Cache\Cache as CacheInterface;
use Alchemy\Phrasea\Core\PhraseaEvents; use Alchemy\Phrasea\Core\PhraseaEvents;
@@ -437,7 +438,7 @@ class V1 implements ControllerProviderInterface
*/ */
public function get_databox_status(Application $app, Request $request, $databox_id) public function get_databox_status(Application $app, Request $request, $databox_id)
{ {
$ret = ["status" => $this->list_databox_status($app['phraseanet.appbox']->get_databox($databox_id)->get_statusbits())]; $ret = ["status" => $this->list_databox_status($app['phraseanet.appbox']->get_databox($databox_id)->getStatusStructure())];
return Result::create($request, $ret)->createResponse(); return Result::create($request, $ret)->createResponse();
} }
@@ -757,7 +758,7 @@ class V1 implements ControllerProviderInterface
{ {
$record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id); $record = $app['phraseanet.appbox']->get_databox($databox_id)->get_record($record_id);
$ret = ["status" => $this->list_record_status($app['phraseanet.appbox']->get_databox($databox_id), $record->get_status())]; $ret = ["status" => $this->list_record_status($record)];
return Result::create($request, $ret)->createResponse(); return Result::create($request, $ret)->createResponse();
} }
@@ -836,7 +837,7 @@ class V1 implements ControllerProviderInterface
{ {
$databox = $app['phraseanet.appbox']->get_databox($databox_id); $databox = $app['phraseanet.appbox']->get_databox($databox_id);
$record = $databox->get_record($record_id); $record = $databox->get_record($record_id);
$status_bits = $databox->get_statusbits(); $statusStructure = $databox->getStatusStructure();
$status = $request->get('status'); $status = $request->get('status');
@@ -852,7 +853,7 @@ class V1 implements ControllerProviderInterface
if (!in_array($value, ['0', '1'])) { if (!in_array($value, ['0', '1'])) {
return $this->getBadRequest($app, $request); return $this->getBadRequest($app, $request);
} }
if (!isset($status_bits[$n])) { if (!$statusStructure->hasStatus($n)) {
return $this->getBadRequest($app, $request); return $this->getBadRequest($app, $request);
} }
@@ -861,7 +862,7 @@ class V1 implements ControllerProviderInterface
$record->set_binary_status(strrev($datas)); $record->set_binary_status(strrev($datas));
$ret = ["status" => $this->list_record_status($databox, $record->get_status())]; $ret = ["status" => $this->list_record_status($record)];
return Result::create($request, $ret)->createResponse(); return Result::create($request, $ret)->createResponse();
} }
@@ -1304,13 +1305,11 @@ class V1 implements ControllerProviderInterface
* *
* @return array * @return array
*/ */
private function list_record_status(\databox $databox, $status) private function list_record_status(\record_adapter $record)
{ {
$status = strrev($status);
$ret = []; $ret = [];
foreach ($databox->get_statusbits() as $bit => $status_datas) { foreach ($record->getStatusStructure() as $bit => $status) {
$ret[] = ['bit' => $bit, 'state' => !!substr($status, ($bit - 1), 1)]; $ret[] = ['bit' => $bit, 'state' => \databox_status::bitIsSet($record->getStatusBitField(), $bit)];
} }
return $ret; return $ret;
@@ -1502,11 +1501,25 @@ class V1 implements ControllerProviderInterface
* *
* @return array * @return array
*/ */
private function list_databox_status(array $status) private function list_databox_status(StatusStructure $statusStructure)
{ {
$ret = []; $ret = [];
foreach ($status as $n => $datas) { foreach ($statusStructure as $bit => $status) {
$ret[] = ['bit' => $n, 'label_on' => $datas['labelon'], 'label_off' => $datas['labeloff'], 'labels' => ['en' => $datas['labels_on_i18n']['en'], 'fr' => $datas['labels_on_i18n']['fr'], 'de' => $datas['labels_on_i18n']['de'], 'nl' => $datas['labels_on_i18n']['nl'],], 'img_on' => $datas['img_on'], 'img_off' => $datas['img_off'], 'searchable' => !!$datas['searchable'], 'printable' => !!$datas['printable'],]; $ret[] = [
'bit' => $bit,
'label_on' => $status['labelon'],
'label_off' => $status['labeloff'],
'labels' => [
'en' => $status['labels_on_i18n']['en'],
'fr' => $status['labels_on_i18n']['fr'],
'de' => $status['labels_on_i18n']['de'],
'nl' => $status['labels_on_i18n']['nl'],
],
'img_on' => $status['img_on'],
'img_off' => $status['img_off'],
'searchable' => (bool) $status['searchable'],
'printable' => (bool) $status['printable'],
];
} }
return $ret; return $ret;

View File

@@ -39,8 +39,7 @@ class Edit implements ControllerProviderInterface
$records = RecordsRequest::fromRequest($app, $request, RecordsRequest::FLATTEN_YES_PRESERVE_STORIES, ['canmodifrecord']); $records = RecordsRequest::fromRequest($app, $request, RecordsRequest::FLATTEN_YES_PRESERVE_STORIES, ['canmodifrecord']);
$thesaurus = false; $thesaurus = false;
$status = $ids = $elements = $suggValues = $status = $ids = $elements = $suggValues = $fields = $JSFields = [];
$fields = $JSFields = [];
$databox = null; $databox = null;
$multipleDataboxes = count($records->databoxes()) > 1; $multipleDataboxes = count($records->databoxes()) > 1;
@@ -120,16 +119,16 @@ class Edit implements ControllerProviderInterface
* generate javascript status * generate javascript status
*/ */
if ($app['acl']->get($app['authentication']->getUser())->has_right('changestatus')) { if ($app['acl']->get($app['authentication']->getUser())->has_right('changestatus')) {
$dbstatus = \databox_status::getDisplayStatus($app); $statusStructure = $databox->getStatusStructure();
if (isset($dbstatus[$databox->get_sbas_id()])) { foreach ($statusStructure as $statbit) {
foreach ($dbstatus[$databox->get_sbas_id()] as $n => $statbit) { $bit = $statbit['bit'];
$status[$n] = [];
$status[$n]['label0'] = $statbit['labels_off_i18n'][$app['locale']]; $status[$bit] = [];
$status[$n]['label1'] = $statbit['labels_on_i18n'][$app['locale']]; $status[$bit]['label0'] = $statbit['labels_off_i18n'][$app['locale']];
$status[$n]['img_off'] = $statbit['img_off']; $status[$bit]['label1'] = $statbit['labels_on_i18n'][$app['locale']];
$status[$n]['img_on'] = $statbit['img_on']; $status[$bit]['img_off'] = $statbit['img_off'];
$status[$n]['_value'] = 0; $status[$bit]['img_on'] = $statbit['img_on'];
} $status[$bit]['_value'] = 0;
} }
} }

View File

@@ -64,49 +64,42 @@ class Property implements ControllerProviderInterface
} }
$records = RecordsRequest::fromRequest($app, $request, false, ['chgstatus']); $records = RecordsRequest::fromRequest($app, $request, false, ['chgstatus']);
$databoxStatus = \databox_status::getDisplayStatus($app);
$statusBit = $nRec = [];
foreach ($records as $record) { if (count($records->databoxes()) > 1) {
//perform logic return new Response($app['twig']->render('prod/actions/Property/index.html.twig', [
$sbasId = $record->get_databox()->get_sbas_id(); 'records' => $records
]));
if (!isset($nRec[$sbasId])) {
$nRec[$sbasId] = ['stories' => 0, 'records' => 0];
}
$nRec[$sbasId]['records']++;
if ($record->is_grouping()) {
$nRec[$sbasId]['stories']++;
}
if (!isset($statusBit[$sbasId])) {
$statusBit[$sbasId] = isset($databoxStatus[$sbasId]) ? $databoxStatus[$sbasId] : [];
foreach (array_keys($statusBit[$sbasId]) as $bit) {
$statusBit[$sbasId][$bit]['nset'] = 0;
}
}
$status = strrev($record->get_status());
foreach (array_keys($statusBit[$sbasId]) as $bit) {
$statusBit[$sbasId][$bit]["nset"] += substr($status, $bit, 1) !== "0" ? 1 : 0;
}
} }
foreach ($records->databoxes() as $databox) { $databox = current($records->databoxes());
$sbasId = $databox->get_sbas_id(); $statusStructure = $databox->getStatusStructure();
foreach ($statusBit[$sbasId] as $bit => $values) { $recordsStatuses = [];
$statusBit[$sbasId][$bit]["status"] = $values["nset"] == 0 ? 0 : ($values["nset"] == $nRec[$sbasId]['records'] ? 1 : 2);
foreach ($records->received() as $record) {
foreach ($statusStructure as $status) {
$bit = $status['bit'];
if (!isset($recordsStatuses[$bit])) {
$recordsStatuses[$bit] = $status;
}
$statusSet = \databox_status::bitIsSet($record->getStatusBitField(), $bit);
if (!isset($recordsStatuses[$bit]['flag'])) {
$recordsStatuses[$bit]['flag'] = (int) $statusSet;
}
// if flag property was already set and the value is different from the previous one
// it means that records share different value for the same flag
if ($recordsStatuses[$bit]['flag'] !== (int) $statusSet) {
$recordsStatuses[$bit]['flag'] = 2;
}
} }
} }
return new Response($app['twig']->render('prod/actions/Property/index.html.twig', [ return new Response($app['twig']->render('prod/actions/Property/index.html.twig', [
'records' => $records, 'records' => $records,
'statusBit' => $statusBit, 'status' => $recordsStatuses
'nRec' => $nRec
])); ]));
} }

View File

@@ -0,0 +1,39 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Status\CacheStatusStructureProvider;
use Alchemy\Phrasea\Status\StatusStructureFactory;
use Alchemy\Phrasea\Status\XmlStatusStructureProvider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class StatusServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['status.provider'] = $app->share(function() use ($app) {
return new CacheStatusStructureProvider(
$app['cache'],
new XmlStatusStructureProvider($app['root.path'], $app['locales.available'])
);
});
$app['factory.status-structure'] = $app->share(function() use ($app) {
return new StatusStructureFactory($app['status.provider']);
});
}
public function boot(Application $app)
{
}
}

View File

@@ -256,16 +256,16 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper
$sbas_id = \phrasea::sbasFromBas($this->app, $this->base_id); $sbas_id = \phrasea::sbasFromBas($this->app, $this->base_id);
$databox = $this->app['phraseanet.appbox']->get_databox($sbas_id); $databox = $this->app['phraseanet.appbox']->get_databox($sbas_id);
$status = $databox->get_statusbits(); $statusStructure = $databox->getStatusStructure();
foreach ($status as $bit => $datas) { foreach ($statusStructure as $bit => $status) {
$tbits_left[$bit]["nset"] = 0; $tbits_left[$bit]["nset"] = 0;
$tbits_left[$bit]["name"] = $datas['labels_off_i18n'][$this->app['locale']]; $tbits_left[$bit]["name"] = $status['labels_off_i18n'][$this->app['locale']];
$tbits_left[$bit]["icon"] = $datas["img_off"]; $tbits_left[$bit]["icon"] = $status["img_off"];
$tbits_right[$bit]["nset"] = 0; $tbits_right[$bit]["nset"] = 0;
$tbits_right[$bit]["name"] = $datas['labels_on_i18n'][$this->app['locale']]; $tbits_right[$bit]["name"] = $status['labels_on_i18n'][$this->app['locale']];
$tbits_right[$bit]["icon"] = $datas["img_on"]; $tbits_right[$bit]["icon"] = $status["img_on"];
} }
$vand_and = $vand_or = $vxor_and = $vxor_or = "0000"; $vand_and = $vand_or = $vxor_and = $vxor_or = "0000";

View File

@@ -293,17 +293,16 @@ class ElasticsearchRecord implements RecordInterface, MutableRecordInterface
$this->flags = $flags; $this->flags = $flags;
} }
public function setStatus($status) public function setStatusBitField($status)
{ {
$this->status = $status; $this->status = $status;
} }
/** /**
* Get status of current current as 32 bits binary string
* *
* Eg: 00000000001011100000000000011111 * @return integer
*/ */
public function getStatus() public function getStatusBitField()
{ {
return $this->status; return $this->status;
} }

View File

@@ -426,7 +426,7 @@ class User
self::GENDER_MISS, self::GENDER_MISS,
self::GENDER_MR, self::GENDER_MR,
self::GENDER_MRS self::GENDER_MRS
], true)) { ])) {
throw new InvalidArgumentException(sprintf("Invalid gender %s.", $gender)); throw new InvalidArgumentException(sprintf("Invalid gender %s.", $gender));
} }

View File

@@ -34,8 +34,8 @@ interface MutableRecordInterface
/** @param string $uuid */ /** @param string $uuid */
public function setUuid($uuid); public function setUuid($uuid);
/** @param string $status */ /** @param integer $status */
public function setStatus($status); public function setStatusBitField($status);
/** @param \DateTime $updated */ /** @param \DateTime $updated */
public function setUpdated(\DateTime $updated = null); public function setUpdated(\DateTime $updated = null);

View File

@@ -55,8 +55,8 @@ interface RecordInterface
/** @return string */ /** @return string */
public function getUuid(); public function getUuid();
/** @return string */ /** @return integer */
public function getStatus(); public function getStatusBitField();
/** @return ArrayCollection */ /** @return ArrayCollection */
public function getExif(); public function getExif();

View File

@@ -435,9 +435,11 @@ class ElasticSearchEngine implements SearchEngineInterface
return ['bool' => ['must_not' => ['match_all' => new \stdClass()]]]; return ['bool' => ['must_not' => ['match_all' => new \stdClass()]]];
} }
$flagNamesMap = $this->getFlagsKey($this->app['phraseanet.appbox']); $appbox = $this->app['phraseanet.appbox'];
$flagNamesMap = $this->getFlagsKey($appbox);
// Get flags rules // Get flags rules
$flagRules = $this->getFlagsRules($acl, $grantedCollections); $flagRules = $this->getFlagsRules($appbox, $acl, $grantedCollections);
// Get intersection between collection ACLs and collection chosen by end user // Get intersection between collection ACLs and collection chosen by end user
$aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap); $aclRules = $this->getACLsByCollection($flagRules, $flagNamesMap);
@@ -531,23 +533,25 @@ class ElasticSearchEngine implements SearchEngineInterface
$flags = []; $flags = [];
foreach ($appbox->get_databoxes() as $databox) { foreach ($appbox->get_databoxes() as $databox) {
$databoxId = $databox->get_sbas_id(); $databoxId = $databox->get_sbas_id();
$status = $databox->get_statusbits(); $statusStructure = $databox->getStatusStructure();
foreach($status as $bit => $stat) { foreach($statusStructure as $bit => $status) {
$flags[$databoxId][$bit] = RecordHelper::normalizeFlagKey($stat['labelon']); $flags[$databoxId][$bit] = RecordHelper::normalizeFlagKey($status['labelon']);
} }
} }
return $flags; return $flags;
} }
private function getFlagsRules(\ACL $acl, array $collections) private function getFlagsRules(\appbox $appbox, \ACL $acl, array $collections)
{ {
$rules = []; $rules = [];
foreach ($collections as $collectionId) { foreach ($collections as $collectionId) {
$databoxId = \phrasea::sbasFromBas($this->app, $collectionId); $databoxId = \phrasea::sbasFromBas($this->app, $collectionId);
$databox = $appbox->get_databox($databoxId);
$mask_xor = $acl->get_mask_xor($collectionId); $mask_xor = $acl->get_mask_xor($collectionId);
$mask_and = $acl->get_mask_and($collectionId); $mask_and = $acl->get_mask_and($collectionId);
foreach (range(0, 31) as $bit) { foreach ($databox->getStatusStructure()->getBits() as $bit) {
$rules[$databoxId][$collectionId][$bit] = $this->computeAccess( $rules[$databoxId][$collectionId][$bit] = $this->computeAccess(
$mask_xor, $mask_xor,
$mask_and, $mask_and,

View File

@@ -37,7 +37,7 @@ class ElasticsearchRecordHydrator
$updatedOn = igorw\get_in($data, ['updated_on']); $updatedOn = igorw\get_in($data, ['updated_on']);
$record->setUpdated($updatedOn ? new \DateTime($updatedOn) : $updatedOn); $record->setUpdated($updatedOn ? new \DateTime($updatedOn) : $updatedOn);
$record->setUuid(igorw\get_in($data, ['uuid'], '')); $record->setUuid(igorw\get_in($data, ['uuid'], ''));
$record->setStatus(igorw\get_in($data, ['flags_bitmask'], 0)); $record->setStatusBitField(igorw\get_in($data, ['flags_bit_value'], 0));
$record->setTitles(new ArrayCollection((array) igorw\get_in($data, ['title'], []))); $record->setTitles(new ArrayCollection((array) igorw\get_in($data, ['title'], [])));
$record->setCaption(new ArrayCollection((array) igorw\get_in($data, ['caption'], []))); $record->setCaption(new ArrayCollection((array) igorw\get_in($data, ['caption'], [])));
$record->setExif(new ArrayCollection((array) igorw\get_in($data, ['exif'], []))); $record->setExif(new ArrayCollection((array) igorw\get_in($data, ['exif'], [])));

View File

@@ -250,6 +250,7 @@ class RecordIndexer
$mapping->add('caption', $captionMapping); $mapping->add('caption', $captionMapping);
$privateCaptionMapping = new Mapping(); $privateCaptionMapping = new Mapping();
$mapping->add('private_caption', $privateCaptionMapping); $mapping->add('private_caption', $privateCaptionMapping);
foreach ($this->getFieldsStructure() as $name => $params) { foreach ($this->getFieldsStructure() as $name => $params) {
$m = $params['private'] ? $privateCaptionMapping : $captionMapping; $m = $params['private'] ? $privateCaptionMapping : $captionMapping;
$m->add($name, $params['type']); $m->add($name, $params['type']);
@@ -319,7 +320,7 @@ class RecordIndexer
$mapping = new Mapping(); $mapping = new Mapping();
foreach ($this->appbox->get_databoxes() as $databox) { foreach ($this->appbox->get_databoxes() as $databox) {
foreach ($databox->get_statusbits() as $bit => $status) { foreach ($databox->getStatusStructure() as $bit => $status) {
$key = RecordHelper::normalizeFlagKey($status['labelon']); $key = RecordHelper::normalizeFlagKey($status['labelon']);
// We only add to mapping new statuses // We only add to mapping new statuses
if (!$mapping->has($key)) { if (!$mapping->has($key)) {
@@ -345,10 +346,10 @@ class RecordIndexer
$structure = $this->getFieldsStructure(); $structure = $this->getFieldsStructure();
$databox = $this->appbox->get_databox($record['databox_id']); $databox = $this->appbox->get_databox($record['databox_id']);
foreach ($databox->get_statusbits() as $bit => $status) { foreach ($databox->getStatusStructure() as $bit => $status) {
$key = RecordHelper::normalizeFlagKey($status['labelon']); $key = RecordHelper::normalizeFlagKey($status['labelon']);
$record['flags'][$key] = \databox_status::bitIsSet($record['flags_bitmask'], $bit); $record['flags'][$key] = \databox_status::bitIsSet($record['flags_bit_value'], $bit);
} }
foreach ($dateFields as $field) { foreach ($dateFields as $field) {

View File

@@ -647,7 +647,7 @@ class SphinxSearchEngine implements SearchEngineInterface
*/ */
$status_opts = $options->getStatus(); $status_opts = $options->getStatus();
foreach ($options->getDataboxes() as $databox) { foreach ($options->getDataboxes() as $databox) {
foreach ($databox->get_statusbits() as $n => $status) { foreach ($databox->getStatusStructure() as $n => $status) {
if (!array_key_exists($n, $status_opts)) if (!array_key_exists($n, $status_opts))
continue; continue;
if (!array_key_exists($databox->get_sbas_id(), $status_opts[$n])) if (!array_key_exists($databox->get_sbas_id(), $status_opts[$n]))

View File

@@ -0,0 +1,72 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Status;
use Alchemy\Phrasea\Application;
use Doctrine\Common\Cache\Cache;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Provides status structure definition using cache if possible
*/
class CacheStatusStructureProvider implements StatusStructureProviderInterface
{
private $cache;
private $provider;
public function __construct(Cache $cache, StatusStructureProviderInterface $provider)
{
$this->cache = $cache;
$this->provider = $provider;
}
public function getStructure(\databox $databox)
{
if (false !== ($status = $this->cache->fetch($this->get_cache_key($databox->get_sbas_id())))) {
return new StatusStructure($databox, new ArrayCollection(json_decode($status, true)));
}
$structure = $this->provider->getStructure($databox);
$this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
return $structure;
}
public function deleteStatus(StatusStructure $structure, $bit)
{
$databox = $structure->getDatabox();
$this->provider->deleteStatus($structure, $bit);
$this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
return $structure;
}
public function updateStatus(StatusStructure $structure, $bit, array $properties)
{
$databox = $structure->getDatabox();
$this->provider->updateStatus($structure, $bit, $properties);
$this->cache->save($this->get_cache_key($databox->get_sbas_id()), json_encode($structure->toArray()));
return $structure;
}
private function get_cache_key($databox_id)
{
return sprintf('status_%s', $databox_id);
}
}

View File

@@ -0,0 +1,145 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Status;
use Doctrine\Common\Collections\ArrayCollection;
/**
* Aim to represent status structure of a databox
* which is the combination of a databox and a collection of status
*/
class StatusStructure implements \IteratorAggregate
{
private $databox;
private $status;
private $url;
private $path;
public function __construct(\databox $databox, ArrayCollection $status = null)
{
$this->databox = $databox;
$this->status = $status ?: new ArrayCollection();
$unique_id = md5(implode('-', array(
$this->databox->get_host(),
$this->databox->get_port(),
$this->databox->get_dbname()
)));
// path to status icon
$this->path = __DIR__ . "/../../../../config/status/" . $unique_id;
// url to status icon
$this->url = "/custom/status/" . $unique_id;
}
public function getIterator()
{
return $this->status->getIterator();
}
/**
* Get url to status icons
*
* @return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Get path to status icons
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Get databox where belong status
*
* @return \databox
*/
public function getDatabox()
{
return $this->databox;
}
/**
* Get the bits used in structure
* $
* @return array[] int
*/
public function getBits()
{
return $this->status->getKeys();
}
/**
* Set new status at nth position
*
* @param int $nthBit
* @param array $status
*
* @return $this
*/
public function setStatus($nthBit, array $status)
{
$this->status->set($nthBit, $status);
return $this;
}
/**
* Check whether structure has nth status set
*
* @param int $nthBit
*
* @return bool
*/
public function hasStatus($nthBit)
{
return $this->status->containsKey($nthBit);
}
/**
* Get status at nth position
*
* @param int $nthBit
*
* @return array|null
*/
public function getStatus($nthBit)
{
return $this->status->get($nthBit);
}
/**
* Remove status at nth position
*
* @param int $nthBit
*
* @return $this
*/
public function removeStatus($nthBit)
{
$this->status->remove($nthBit);
return $this;
}
public function toArray()
{
return $this->status->toArray();
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Status;
/**
* This class is used to get databox status structure
*/
class StatusStructureFactory
{
/**
* Keep trace of already instantiated databox status structure
*
* @var array
*/
private $statusStructure = [];
/**
* A provider that gives the definition of a structure
*
* @var StatusStructureProviderInterface
*/
protected $provider;
public function __construct(StatusStructureProviderInterface $provider)
{
$this->provider = $provider;
}
/**
* Get the status structure according to the given databox
*
* @param \databox $databox
*
* @return StatusStructure
*/
public function getStructure(\databox $databox)
{
$databox_id = $databox->get_sbas_id();
if (isset($this->statusStructure[$databox_id])) {
return $this->statusStructure[$databox_id];
}
$this->statusStructure[$databox_id] = $this->provider->getStructure($databox);
return $this->statusStructure[$databox_id];
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Status;
/**
* Interface defined for status definition providers
*/
interface StatusStructureProviderInterface
{
/**
* Returns a status structure for a given databox
*
* @param \databox $databox
*
* @return StatusStructure
*/
public function getStructure(\databox $databox);
/**
* Deletes status at nth bit from given status structure
*
* @param StatusStructure $structure
* @param int $bit
*
* @return StatusStructure
*/
public function deleteStatus(StatusStructure $structure, $bit);
/**
* Updates status at nth bit from given status structure
*
* @param StatusStructure $structure
* @param int $bit
*
* @return StatusStructure
*/
public function updateStatus(StatusStructure $structure, $bit, array $properties);
}

View File

@@ -0,0 +1,235 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2015 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Status;
use Symfony\Component\Filesystem\Filesystem;
/**
* Provides status structure definition from XML
*/
class XmlStatusStructureProvider implements StatusStructureProviderInterface
{
protected $rootPath;
protected $locales;
public function __construct($rootPath, $locales, $fs = null)
{
$this->rootPath = $rootPath;
$this->locales = $locales;
$this->fs = $fs ?: new Filesystem();
}
public function getStructure(\databox $databox)
{
$statusStructure = new StatusStructure($databox);
$xmlPref = $databox->get_structure();
$sxe = simplexml_load_string($xmlPref);
if ($sxe === false) {
throw new \Exception('Failed to load database XML structure');
}
foreach ($sxe->statbits->bit as $sb) {
$bit = (int) ($sb['n']);
if ($bit < 4 && $bit > 31) {
continue;
}
$status = [];
$status['bit'] = $bit;
$status['labeloff'] = (string) $sb['labelOff'];
$status['labelon'] = (string) $sb['labelOn'];
foreach ($this->locales as $code => $language) {
$status['labels_on'][$code] = null;
$status['labels_off'][$code] = null;
}
foreach ($sb->label as $label) {
$status['labels_'.$label['switch']][(string) $label['code']] = (string) $label;
}
foreach ($this->locales as $code => $language) {
$status['labels_on_i18n'][$code] = '' !== trim($status['labels_on'][$code]) ? $status['labels_on'][$code] : $status['labelon'];
$status['labels_off_i18n'][$code] = '' !== trim($status['labels_off'][$code]) ? $status['labels_off'][$code] : $status['labeloff'];
}
$status['img_off'] = null;
$status['img_on'] = null;
if (is_file($statusStructure->getPath() . '-stat_' . $bit . '_0.gif')) {
$status['img_off'] = $statusStructure->getUrl() . '-stat_' . $bit . '_0.gif?etag='.md5_file($statusStructure->getPath() . '-stat_' . $bit . '_0.gif');
$status['path_off'] = $statusStructure->getPath() . '-stat_' . $bit . '_0.gif';
}
if (is_file($statusStructure->getPath() . '-stat_' . $bit . '_1.gif')) {
$status['img_on'] = $statusStructure->getUrl() . '-stat_' . $bit . '_1.gif?etag='.md5_file($statusStructure->getPath() . '-stat_' . $bit . '_1.gif');
$status['path_on'] = $statusStructure->getPath() . '-stat_' . $bit . '_1.gif';
}
$status['searchable'] = isset($sb['searchable']) ? (int) $sb['searchable'] : 0;
$status['printable'] = isset($sb['printable']) ? (int) $sb['printable'] : 0;
$statusStructure->setStatus($bit, $status);
}
return $statusStructure;
}
public function deleteStatus(StatusStructure $statusStructure, $bit)
{
$databox = $statusStructure->getDatabox();
if (false === $statusStructure->hasStatus($bit)) {
return false;
}
$doc = $databox->get_dom_structure();
if (!$doc) {
return false;
}
$xpath = $databox->get_xpath_structure();
$entries = $xpath->query('/record/statbits/bit[@n=' . $bit . ']');
foreach ($entries as $sbit) {
if ($p = $sbit->previousSibling) {
if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == '\n\t\t')
$p->parentNode->removeChild($p);
}
if ($sbit->parentNode->removeChild($sbit)) {
$sql = 'UPDATE record SET status = status&(~(1<<' . $bit . '))';
$stmt = $databox->get_connection()->prepare($sql);
$stmt->execute();
$stmt->closeCursor();
}
}
$databox->saveStructure($doc);
$status = $statusStructure->getStatus($bit);
if (null !== $status['img_off']) {
$this->fs->remove($status['path_off']);
}
if (null !== $status['img_on']) {
$this->fs->remove($status['path_on']);
}
$statusStructure->removeStatus($bit);
return $statusStructure;
}
public function updateStatus(StatusStructure $statusStructure, $bit, array $properties)
{
$databox = $statusStructure->getDatabox();
if (false === $statusStructure->hasStatus($bit)) {
$statusStructure->setStatus($bit, []);
}
$doc = $databox->get_dom_structure();
if (!$doc) {
return false;
}
$xpath = $databox->get_xpath_structure();
$entries = $xpath->query('/record/statbits');
if ($entries->length == 0) {
$statbits = $doc->documentElement->appendChild($doc->createElement('statbits'));
} else {
$statbits = $entries->item(0);
}
if ($statbits) {
$entries = $xpath->query('/record/statbits/bit[@n=' . $bit . ']');
if ($entries->length >= 1) {
foreach ($entries as $k => $sbit) {
if ($p = $sbit->previousSibling) {
if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == '\n\t\t')
$p->parentNode->removeChild($p);
}
$sbit->parentNode->removeChild($sbit);
}
}
$sbit = $statbits->appendChild($doc->createElement('bit'));
if ($n = $sbit->appendChild($doc->createAttribute('n'))) {
$n->value = $bit;
}
if ($labOn = $sbit->appendChild($doc->createAttribute('labelOn'))) {
$labOn->value = $properties['labelon'];
}
if ($searchable = $sbit->appendChild($doc->createAttribute('searchable'))) {
$searchable->value = $properties['searchable'];
}
if ($printable = $sbit->appendChild($doc->createAttribute('printable'))) {
$printable->value = $properties['printable'];
}
if ($labOff = $sbit->appendChild($doc->createAttribute('labelOff'))) {
$labOff->value = $properties['labeloff'];
}
foreach ($properties['labels_off'] as $code => $label) {
$labelTag = $sbit->appendChild($doc->createElement('label'));
$switch = $labelTag->appendChild($doc->createAttribute('switch'));
$switch->value = 'off';
$codeTag = $labelTag->appendChild($doc->createAttribute('code'));
$codeTag->value = $code;
$labelTag->appendChild($doc->createTextNode($label));
}
foreach ($properties['labels_on'] as $code => $label) {
$labelTag = $sbit->appendChild($doc->createElement('label'));
$switch = $labelTag->appendChild($doc->createAttribute('switch'));
$switch->value = 'on';
$codeTag = $labelTag->appendChild($doc->createAttribute('code'));
$codeTag->value = $code;
$labelTag->appendChild($doc->createTextNode($label));
}
}
$databox->saveStructure($doc);
$status = $statusStructure->getStatus($bit);
$status['labelon'] = $properties['labelon'];
$status['labeloff'] = $properties['labeloff'];
$status['searchable'] = (Boolean) $properties['searchable'];
$status['printable'] = (Boolean) $properties['printable'];
if (!isset($properties['img_on'])) {
$status['img_on'] = null;
}
if (!isset($properties['img_off'])) {
$status['img_off'] = null;
}
$statusStructure->setStatus($bit, $status);
return $statusStructure;
}
}

View File

@@ -37,9 +37,41 @@ class PhraseanetExtension extends \Twig_Extension
new \Twig_SimpleFunction('collection_logo', array($this, 'getCollectionLogo'), array( new \Twig_SimpleFunction('collection_logo', array($this, 'getCollectionLogo'), array(
'is_safe' => array('html') 'is_safe' => array('html')
)), )),
new \Twig_SimpleFunction('record_flags', array($this, 'getRecordFlags'))
); );
} }
public function getRecordFlags(RecordInterface $record)
{
$recordStatuses = [];
$databox = $this->app['phraseanet.appbox']->get_databox($record->getDataboxId());
$structure = $databox->getStatusStructure()->toArray();
if (!$this->isGrantedOnCollection($record->getBaseId(), 'chgstatus')) {
$structure = array_filter($structure, function($status) {
return (bool) $status['printable'];
});
}
$bitValue = $record->getStatusBitField();
foreach ($structure as $status) {
$on = \databox_status::bitIsSet($bitValue, $status['bit']);
if (null === ($on ? $status['img_on'] : $status['img_off'])) {
continue;
}
$recordStatuses[] = [
'path' => ($on ? $status['img_on'] : $status['img_off']),
'labels' => ($on ? $status['labels_on_i18n'] : $status['labels_off_i18n'])
];
}
return $recordStatuses;
}
public function isGrantedOnDatabox($databoxId, $rights) public function isGrantedOnDatabox($databoxId, $rights)
{ {
if (false === ($this->app['authentication']->getUser() instanceof User)) { if (false === ($this->app['authentication']->getUser() instanceof User)) {

View File

@@ -210,7 +210,7 @@ class ACL implements cache_cacheableInterface
public function has_status_access_to_record(RecordInterface $record) public function has_status_access_to_record(RecordInterface $record)
{ {
return 0 === ((bindec($record->getStatus()) ^ $this->get_mask_xor($record->getBaseId())) & $this->get_mask_and($record->getBaseId())); return 0 === ((bindec($record->getStatusBitField()) ^ $this->get_mask_xor($record->getBaseId())) & $this->get_mask_and($record->getBaseId()));
} }
public function has_access_to_subdef(RecordInterface $record, $subdef_name) public function has_access_to_subdef(RecordInterface $record, $subdef_name)

View File

@@ -307,9 +307,9 @@ class databox extends base
* *
* @return databox_status * @return databox_status
*/ */
public function get_statusbits() public function getStatusStructure()
{ {
return databox_status::getStatus($this->app, $this->id); return $this->app['factory.status-structure']->getStructure($this);
} }
/** /**

View File

@@ -11,385 +11,101 @@
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper; use Alchemy\Phrasea\SearchEngine\Elastic\RecordHelper;
use MediaAlchemyst\Specification\Image as ImageSpecification;
use Symfony\Component\HttpFoundation\File\UploadedFile; use Symfony\Component\HttpFoundation\File\UploadedFile;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use MediaAlchemyst\Specification\Image as ImageSpecification;
use Symfony\Component\HttpFoundation\File\Exception\FileException; use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Alchemy\Phrasea\Model\RecordInterface;
class databox_status class databox_status
{ {
/**
*
* @var Array
*/
private static $_status = [];
/**
*
* @var Array
*/
protected static $_statuses;
/**
*
* @var Array
*/
private $status = [];
/**
*
* @var string
*/
private $path = '';
/**
*
* @var string
*/
private $url = '';
/**
*
* @param int $sbas_id
* @return status
*/
private function __construct(Application $app, $sbas_id)
{
$this->status = [];
$path = $url = false;
$sbas_params = phrasea::sbas_params($app);
if ( ! isset($sbas_params[$sbas_id])) {
return;
}
$uniqid = md5(implode('-', [
$sbas_params[$sbas_id]["host"],
$sbas_params[$sbas_id]["port"],
$sbas_params[$sbas_id]["dbname"]
]));
$path = $this->path = $app['root.path'] . "/config/status/" . $uniqid;
$url = $this->url = "/custom/status/" . $uniqid;
$databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
$xmlpref = $databox->get_structure();
$sxe = simplexml_load_string($xmlpref);
if ($sxe !== false) {
foreach ($sxe->statbits->bit as $sb) {
$bit = (int) ($sb["n"]);
if ($bit < 4 && $bit > 31)
continue;
$this->status[$bit]["labeloff"] = (string) $sb['labelOff'];
$this->status[$bit]["labelon"] = (string) $sb['labelOn'];
foreach ($app['locales.available'] as $code => $language) {
$this->status[$bit]['labels_on'][$code] = null;
$this->status[$bit]['labels_off'][$code] = null;
}
foreach ($sb->label as $label) {
$this->status[$bit]['labels_'.$label['switch']][(string) $label['code']] = (string) $label;
}
foreach ($app['locales.available'] as $code => $language) {
$this->status[$bit]['labels_on_i18n'][$code] = '' !== trim($this->status[$bit]['labels_on'][$code]) ? $this->status[$bit]['labels_on'][$code] : $this->status[$bit]["labelon"];
$this->status[$bit]['labels_off_i18n'][$code] = '' !== trim($this->status[$bit]['labels_off'][$code]) ? $this->status[$bit]['labels_off'][$code] : $this->status[$bit]["labeloff"];
}
$this->status[$bit]["img_off"] = null;
$this->status[$bit]["img_on"] = null;
if (is_file($path . "-stat_" . $bit . "_0.gif")) {
$this->status[$bit]["img_off"] = $url . "-stat_" . $bit . "_0.gif?etag=".md5_file($path . "-stat_" . $bit . "_0.gif");
$this->status[$bit]["path_off"] = $path . "-stat_" . $bit . "_0.gif";
}
if (is_file($path . "-stat_" . $bit . "_1.gif")) {
$this->status[$bit]["img_on"] = $url . "-stat_" . $bit . "_1.gif?etag=".md5_file($path . "-stat_" . $bit . "_1.gif");
$this->status[$bit]["path_on"] = $path . "-stat_" . $bit . "_1.gif";
}
$this->status[$bit]["searchable"] = isset($sb['searchable']) ? (int) $sb['searchable'] : 0;
$this->status[$bit]["printable"] = isset($sb['printable']) ? (int) $sb['printable'] : 0;
}
}
ksort($this->status);
return $this;
}
public static function getStatus(Application $app, $sbas_id)
{
if ( ! isset(self::$_status[$sbas_id]))
self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
return self::$_status[$sbas_id]->status;
}
public static function getDisplayStatus(Application $app)
{
if (self::$_statuses) {
return self::$_statuses;
}
$sbas_ids = $app['acl']->get($app['authentication']->getUser())->get_granted_sbas();
$statuses = [];
foreach ($sbas_ids as $databox) {
try {
$statuses[$databox->get_sbas_id()] = $databox->get_statusbits();
} catch (\Exception $e) {
}
}
self::$_statuses = $statuses;
return self::$_statuses;
}
public static function getSearchStatus(Application $app) public static function getSearchStatus(Application $app)
{ {
$statuses = $see_all = []; $see_all = $structures = $stats = [];
$databoxes = $app['acl']->get($app['authentication']->getUser())->get_granted_sbas(); foreach ($app['acl']->get($app['authentication']->getUser())->get_granted_sbas() as $databox) {
foreach ($databoxes as $databox) {
$see_all[$databox->get_sbas_id()] = false; $see_all[$databox->get_sbas_id()] = false;
foreach ($databox->get_collections() as $collection) { foreach ($databox->get_collections() as $collection) {
if ($app['acl']->get($app['authentication']->getUser())->has_right_on_base($collection->get_base_id(), 'chgstatus')) { if ($app['acl']->get($app['authentication']->getUser())->has_right_on_base($collection->get_base_id(), 'chgstatus')) {
$see_all[$databox->get_sbas_id()] = true; $see_all[$databox->get_sbas_id()] = true;
break; break;
} }
} }
$structures[$databox->get_sbas_id()] = $databox->getStatusStructure();
try {
$statuses[$databox->get_sbas_id()] = $databox->get_statusbits();
} catch (\Exception $e) {
}
} }
$stats = []; foreach ($structures as $databox_id => $structure) {
if (false === $see_all[$databox_id]) {
$structure = array_filter(function($status) {
return (bool) $status['searchable'];
}, $structure->toArray());
}
foreach ($statuses as $databox_id => $status) { foreach($structure as $bit => $status) {
$canSeeAll = isset($see_all[$databox_id]) ? $see_all[$databox_id] : false; $key = RecordHelper::normalizeFlagKey($status['labelon']);
$canSeeThis = $app['acl']->get($app['authentication']->getUser())->has_right_on_sbas($databox_id, 'bas_modify_struct');
$canAccess = $canSeeAll || $canSeeThis; if (isset($stats[$key])) {
$status = $stats[$key];
foreach ($status as $bit => $props) {
if (!$props['searchable'] && !$canAccess) {
continue;
} }
$stats[$databox_id][$bit] = array(
'name' => RecordHelper::normalizeFlagKey($props['labelon']), $status['sbas'][] = $databox_id;
'labeloff' => $props['labeloff'], $status['bit'] = $bit;
'labelon' => $props['labelon'],
'labels_on_i18n' => $props['labels_on_i18n'], $stats[$key] = $status;
'labels_off_i18n' => $props['labels_off_i18n'],
'imgoff' => $props['img_off'],
'imgon' => $props['img_on']
);
} }
} }
return $stats; return $stats;
} }
public static function getPath(Application $app, $sbas_id) public static function deleteIcon(Application $app, $databox_id, $bit, $switch)
{ {
if ( ! isset(self::$_status[$sbas_id])) { $databox = $app['phraseanet.appbox']->get_databox($databox_id);
self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
$statusStructure = $app['factory.status-structure']->getStructure($databox);
if (!$statusStructure->hasStatus($bit)) {
throw new InvalidArgumentException(sprintf('bit %s does not exists on database %s', $bit, $statusStructure->getDatabox()->get_dbname()));
} }
return self::$_status[$sbas_id]->path; $status = $statusStructure->getStatus($bit);
}
public static function getUrl(Application $app, $sbas_id)
{
if ( ! isset(self::$_status[$sbas_id])) {
self::$_status[$sbas_id] = new databox_status($app, $sbas_id);
}
return self::$_status[$sbas_id]->url;
}
public static function deleteStatus(Application $app, \databox $databox, $bit)
{
$status = self::getStatus($app, $databox->get_sbas_id());
if (isset($status[$bit])) {
$doc = $databox->get_dom_structure();
if ($doc) {
$xpath = $databox->get_xpath_structure();
$entries = $xpath->query("/record/statbits/bit[@n=" . $bit . "]");
foreach ($entries as $sbit) {
if ($p = $sbit->previousSibling) {
if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == "\n\t\t")
$p->parentNode->removeChild($p);
}
if ($sbit->parentNode->removeChild($sbit)) {
$sql = 'UPDATE record SET status = status&(~(1<<' . $bit . '))';
$stmt = $databox->get_connection()->prepare($sql);
$stmt->execute();
$stmt->closeCursor();
}
}
$databox->saveStructure($doc);
if (null !== $status[$bit]['img_off']) {
$app['filesystem']->remove($status[$bit]['path_off']);
}
if (null !== $status[$bit]['img_on']) {
$app['filesystem']->remove($status[$bit]['path_on']);
}
unset(self::$_status[$databox->get_sbas_id()]->status[$bit]);
$app['dispatcher']->dispatch(RecordStructureEvents::STATUS_BIT_DELETED, new StatusBitDeletedEvent($databox, $bit));
return true;
}
}
return false;
}
public static function updateStatus(Application $app, $sbas_id, $bit, $properties)
{
self::getStatus($app, $sbas_id);
$databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
$doc = $databox->get_dom_structure($sbas_id);
if ($doc) {
$xpath = $databox->get_xpath_structure($sbas_id);
$entries = $xpath->query("/record/statbits");
if ($entries->length == 0) {
$statbits = $doc->documentElement->appendChild($doc->createElement("statbits"));
} else {
$statbits = $entries->item(0);
}
if ($statbits) {
$entries = $xpath->query("/record/statbits/bit[@n=" . $bit . "]");
if ($entries->length >= 1) {
foreach ($entries as $k => $sbit) {
if ($p = $sbit->previousSibling) {
if ($p->nodeType == XML_TEXT_NODE && $p->nodeValue == "\n\t\t")
$p->parentNode->removeChild($p);
}
$sbit->parentNode->removeChild($sbit);
}
}
$sbit = $statbits->appendChild($doc->createElement("bit"));
if ($n = $sbit->appendChild($doc->createAttribute("n"))) {
$n->value = $bit;
}
if ($labOn = $sbit->appendChild($doc->createAttribute("labelOn"))) {
$labOn->value = $properties['labelon'];
}
if ($searchable = $sbit->appendChild($doc->createAttribute("searchable"))) {
$searchable->value = $properties['searchable'];
}
if ($printable = $sbit->appendChild($doc->createAttribute("printable"))) {
$printable->value = $properties['printable'];
}
if ($labOff = $sbit->appendChild($doc->createAttribute("labelOff"))) {
$labOff->value = $properties['labeloff'];
}
foreach ($properties['labels_off'] as $code => $label) {
$labelTag = $sbit->appendChild($doc->createElement("label"));
$switch = $labelTag->appendChild($doc->createAttribute("switch"));
$switch->value = 'off';
$codeTag = $labelTag->appendChild($doc->createAttribute("code"));
$codeTag->value = $code;
$labelTag->appendChild($doc->createTextNode($label));
}
foreach ($properties['labels_on'] as $code => $label) {
$labelTag = $sbit->appendChild($doc->createElement("label"));
$switch = $labelTag->appendChild($doc->createAttribute("switch"));
$switch->value = 'on';
$codeTag = $labelTag->appendChild($doc->createAttribute("code"));
$codeTag->value = $code;
$labelTag->appendChild($doc->createTextNode($label));
}
}
$databox->saveStructure($doc);
self::$_status[$sbas_id]->status[$bit]["labelon"] = $properties['labelon'];
self::$_status[$sbas_id]->status[$bit]["labeloff"] = $properties['labeloff'];
self::$_status[$sbas_id]->status[$bit]["searchable"] = (Boolean) $properties['searchable'];
self::$_status[$sbas_id]->status[$bit]["printable"] = (Boolean) $properties['printable'];
if ( ! isset(self::$_status[$sbas_id]->status[$bit]['img_on'])) {
self::$_status[$sbas_id]->status[$bit]['img_on'] = null;
}
if ( ! isset(self::$_status[$sbas_id]->status[$bit]['img_off'])) {
self::$_status[$sbas_id]->status[$bit]['img_off'] = null;
}
$properties = self::$_status[$sbas_id]->status[$bit];
$app['dispatcher']->dispatch(RecordStructureEvents::STATUS_BIT_UPDATED, new StatusBitUpdatedEvent($databox, $bit, $properties));
}
return false;
}
public static function deleteIcon(Application $app, $sbas_id, $bit, $switch)
{
$status = self::getStatus($app, $sbas_id);
$switch = in_array($switch, ['on', 'off']) ? $switch : false; $switch = in_array($switch, ['on', 'off']) ? $switch : false;
if (! $switch) { if (!$switch) {
return false; return false;
} }
if ($status[$bit]['img_' . $switch]) { if ($status['img_' . $switch]) {
if (isset($status[$bit]['path_' . $switch])) { if (isset($status['path_' . $switch])) {
$app['filesystem']->remove($status[$bit]['path_' . $switch]); $app['filesystem']->remove($status['path_' . $switch]);
} }
$status[$bit]['img_' . $switch] = false; $status['img_' . $switch] = false;
unset($status[$bit]['path_' . $switch]); unset($status['path_' . $switch]);
} }
return true; return true;
} }
public static function updateIcon(Application $app, $sbas_id, $bit, $switch, UploadedFile $file) public static function updateIcon(Application $app, $databox_id, $bit, $switch, UploadedFile $file)
{ {
$databox = $app['phraseanet.appbox']->get_databox($databox_id);
$statusStructure = $app['factory.status-structure']->getStructure($databox);
if (!$statusStructure->hasStatus($bit)) {
throw new InvalidArgumentException(sprintf('bit %s does not exists', $bit));
}
$status = $statusStructure->getStatus($bit);
$switch = in_array($switch, ['on', 'off']) ? $switch : false; $switch = in_array($switch, ['on', 'off']) ? $switch : false;
if (! $switch) { if (!$switch) {
throw new Exception_InvalidArgument(); throw new Exception_InvalidArgument();
} }
$url = self::getUrl($app, $sbas_id); $url = $statusStructure->getUrl();
$path = self::getPath($app, $sbas_id); $path = $statusStructure->getPath();
if ($file->getSize() >= 65535) { if ($file->getSize() >= 65535) {
throw new Exception_Upload_FileTooBig(); throw new Exception_Upload_FileTooBig();
@@ -399,7 +115,7 @@ class databox_status
throw new Exception_Upload_Error(); throw new Exception_Upload_Error();
} }
self::deleteIcon($app, $sbas_id, $bit, $switch); self::deleteIcon($app, $databox_id, $bit, $switch);
$name = "-stat_" . $bit . "_" . ($switch == 'on' ? '1' : '0') . ".gif"; $name = "-stat_" . $bit . "_" . ($switch == 'on' ? '1' : '0') . ".gif";
@@ -427,8 +143,8 @@ class databox_status
} }
self::$_status[$sbas_id]->status[$bit]['img_' . $switch] = $url . $name; $status['img_' . $switch] = $url . $name;
self::$_status[$sbas_id]->status[$bit]['path_' . $switch] = $filePath; $status['path_' . $switch] = $filePath;
return true; return true;
} }
@@ -607,13 +323,8 @@ class databox_status
return $status; return $status;
} }
public static function purge() public static function bitIsSet($bitValue, $nthBit)
{ {
self::$_status = self::$_statuses = []; return (bool) ($bitValue & (1 << $nthBit));
}
public static function bitIsSet($bitMask, $nthBit)
{
return (bool) ($bitMask & (1 << $nthBit));
} }
} }

View File

@@ -29,6 +29,7 @@ use Doctrine\ORM\EntityManager;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use MediaVorus\MediaVorus; use MediaVorus\MediaVorus;
use Rhumsaa\Uuid\Uuid; use Rhumsaa\Uuid\Uuid;
use Alchemy\Phrasea\Status\StatusStructure;
use Alchemy\Phrasea\Model\RecordInterface; use Alchemy\Phrasea\Model\RecordInterface;
use Symfony\Component\HttpFoundation\File\File as SymfoFile; use Symfony\Component\HttpFoundation\File\File as SymfoFile;
use Alchemy\Phrasea\Core\PhraseaTokens; use Alchemy\Phrasea\Core\PhraseaTokens;
@@ -381,61 +382,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
return $this->getSubdfefByDeviceAndMime($devices, $mimes); return $this->getSubdfefByDeviceAndMime($devices, $mimes);
} }
/**
*
* @return string
*/
public function get_status_icons()
{
$dstatus = databox_status::getDisplayStatus($this->app);
$sbas_id = $this->get_sbas_id();
$status = '';
if (isset($dstatus[$sbas_id])) {
foreach ($dstatus[$sbas_id] as $n => $statbit) {
if ($statbit['printable'] == '0' &&
!$this->app['acl']->get($this->app['authentication']->getUser())->has_right_on_base($this->base_id, 'chgstatus')) {
continue;
}
$x = (substr((strrev($this->get_status())), $n, 1));
$source0 = "/skins/icons/spacer.gif";
$style0 = "visibility:hidden;display:none;";
$source1 = "/skins/icons/spacer.gif";
$style1 = "visibility:hidden;display:none;";
if ($statbit["img_on"]) {
$source1 = $statbit["img_on"];
$style1 = "visibility:auto;display:none;";
}
if ($statbit["img_off"]) {
$source0 = $statbit["img_off"];
$style0 = "visibility:auto;display:none;";
}
if ($x == '1') {
if ($statbit["img_on"]) {
$style1 = "visibility:auto;display:inline;";
}
} else {
if ($statbit["img_off"]) {
$style0 = "visibility:auto;display:inline;";
}
}
$status .= '<img style="margin:1px;' . $style1 . '" ' .
'class="STAT_' . $this->base_id . '_'
. $this->record_id . '_' . $n . '_1" ' .
'src="' . $source1 . '" title="' . $statbit['labels_on_i18n'][$this->app['locale']] . '"/>';
$status .= '<img style="margin:1px;' . $style0 . '" ' .
'class="STAT_' . $this->base_id . '_'
. $this->record_id . '_' . $n . '_0" ' .
'src="' . $source0 . '" title="' . $statbit['labels_off_i18n'][$this->app['locale']] . '"/>';
}
}
return $status;
}
/** /**
* Returns the type of the document * Returns the type of the document
* *
@@ -1601,8 +1547,6 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
} }
$databox = $this->get_databox(); $databox = $this->get_databox();
\cache_databox::update($this->app, $this->get_sbas_id(), 'record', $this->get_record_id());
return $databox->delete_data_from_cache($this->get_cache_key($option)); return $databox->delete_data_from_cache($this->get_cache_key($option));
} }
@@ -1947,9 +1891,9 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
} }
/** {@inheritdoc} */ /** {@inheritdoc} */
public function getStatus() public function getStatusBitField()
{ {
return $this->get_status(); return bindec($this->get_status());
} }
/** {@inheritdoc} */ /** {@inheritdoc} */

View File

@@ -1,4 +1,4 @@
{% set status = databox.get_statusbits() %} {% set statusStructure = databox.getStatusStructure() %}
{% set databox_id = databox.get_sbas_id() %} {% set databox_id = databox.get_sbas_id() %}
<h1> <h1>
@@ -19,7 +19,7 @@
<td> <td>
{{ bit }} {{ bit }}
</td> </td>
{% if attribute(status, bit) is defined %} {% if statusStructure.hasStatus(bit) %}
<td> <td>
<a target="right" href="{{ path('database_display_statusbit_form', { 'databox_id' : databox_id, 'bit' : bit }) }}" class="ajax"> <a target="right" href="{{ path('database_display_statusbit_form', { 'databox_id' : databox_id, 'bit' : bit }) }}" class="ajax">
<img class="editer" src="/skins/icons/edit_0.gif" /> <img class="editer" src="/skins/icons/edit_0.gif" />
@@ -38,8 +38,8 @@
</td> </td>
{% endif %} {% endif %}
{% if attribute(status, bit) is defined %} {% if statusStructure.hasStatus(bit) %}
{% set statusbit = attribute(status, bit) %} {% set statusbit = statusStructure.getStatus(bit) %}
<td> <td>
{% if statusbit['img_off'] %} {% if statusbit['img_off'] %}
<img title='{{ statusbit['labels_off_i18n'][app['locale']] }}' src='{{ statusbit['img_off'] }}' /> <img title='{{ statusbit['labels_off_i18n'][app['locale']] }}' src='{{ statusbit['img_off'] }}' />

View File

@@ -195,7 +195,7 @@
<img onclick="removeFilters({{ sbasId }});" id="filter_danger{{ sbasId }}" class="filter_danger" src="/skins/icons/alert.png" title="{{ "client::recherche: cliquez ici pour desactiver tous les filtres de cette base" | trans }}" style="vertical-align:bottom;width:12px;height:12px;display:none;"/> <img onclick="removeFilters({{ sbasId }});" id="filter_danger{{ sbasId }}" class="filter_danger" src="/skins/icons/alert.png" title="{{ "client::recherche: cliquez ici pour desactiver tous les filtres de cette base" | trans }}" style="vertical-align:bottom;width:12px;height:12px;display:none;"/>
</div> </div>
{% set status_bit_filters = '' %} {% set status_bit_filters = '' %}
{% for bit, data in databox.get_statusbits() if data['searchable'] %} {% for bit, data in databox.getStatusStructure.getStatuses if data['searchable'] %}
{% set html_status_bit %} {% set html_status_bit %}
<div style="text-align:center;overflow:hidden;"> <div style="text-align:center;overflow:hidden;">
<table style="table-layout:fixed;width:90%;text-align:left;" cellspacing="0" cellpadding="0"> <table style="table-layout:fixed;width:90%;text-align:left;" cellspacing="0" cellpadding="0">

View File

@@ -4,45 +4,50 @@
<div id='tabs-records-property'> <div id='tabs-records-property'>
{# This value is fetched when click on 2nd tab #} {# if multi databox edit abort #}
<input type="hidden" name='original_selection' value="{{ app.request.query.get('lst') }}"> {% if records.databoxes() | length > 1 %}
<div class="well-small">
{{ 'prod::Les enregistrements ne provienent pas tous de la meme base et ne peuvent donc etre traites ensemble' | trans }}
</div>
{% else %}
<ul> {% set databox = records.databoxes|first %}
<li><a href="#property-statut">{{ 'Records Statut' | trans }}</a></li> {# This value is fetched when click on 2nd tab #}
{# <span>&nbsp;</span> element is required for the jQuery loading spinner appears && disappears properly #} <input type="hidden" name='original_selection' value="{{ app.request.query.get('lst') }}">
<li><a href="{{ path('display_type_property', { 'lst' : records.serializedList() } ) }}">{{ 'Records type' | trans }}&nbsp;<span>&nbsp;</span></a></li>
</ul>
<div id='property-statut'> <ul>
<p class="header"> <li><a href="#property-statut">{{ 'Records Statut' | trans }}</a></li>
<h4 style='text-align:center;'> {# <span>&nbsp;</span> element is required for the jQuery loading spinner appears && disappears properly #}
{% if nbReceivedDocuments == 1 %} <li><a href="{{ path('display_type_property', { 'lst' : records.serializedList() } ) }}">{{ 'Records type' | trans }}&nbsp;<span>&nbsp;</span></a></li>
{% trans %}You have selected one record.{% endtrans %} </ul>
{% else %}
{% trans with {'%nbReceivedDocuments%' : nbReceivedDocuments} %}You have selected %nbReceivedDocuments% records.{% endtrans %}
{% endif %}
{% if nbEditableDocuments == 0 %} <div id='property-statut'>
{% trans %}None of the records can be modified.{% endtrans %} <p class="header">
{% else %} <h4 style='text-align:center;'>
{% if nbEditableDocuments < nbReceivedDocuments %} {% if nbReceivedDocuments == 1 %}
{% if nbEditableDocuments == 1 %} {% trans %}You have selected one record.{% endtrans %}
{% trans %}Only one record can be modified.{% endtrans %} {% else %}
{% else %} {% trans with {'%nbReceivedDocuments%' : nbReceivedDocuments} %}You have selected %nbReceivedDocuments% records.{% endtrans %}
{% trans with {'%nbEditableDocuments%' : nbEditableDocuments} %}Only %nbEditableDocuments% records can be modified.{% endtrans %} {% endif %}
{% endif %}
{% endif %}
{% endif %}
</h4>
</p>
<form style='padding:15px;' name="change-records-status" action="{{ path('change_status') }}" method="POST"> {% if nbEditableDocuments == 0 %}
<input name="lst" type="hidden" value="{{ records.serializedList() }}"/> {% trans %}None of the records can be modified.{% endtrans %}
{% for databox in records.databoxes() %} {% else %}
{% if nbEditableDocuments < nbReceivedDocuments %}
{% if nbEditableDocuments == 1 %}
{% trans %}Only one record can be modified.{% endtrans %}
{% else %}
{% trans with {'%nbEditableDocuments%' : nbEditableDocuments} %}Only %nbEditableDocuments% records can be modified.{% endtrans %}
{% endif %}
{% endif %}
{% endif %}
</h4>
</p>
<form style='padding:15px;' name="change-records-status" action="{{ path('change_status') }}" method="POST">
<input name="lst" type="hidden" value="{{ records.serializedList() }}"/>
{% set sbasId = databox.get_sbas_id() %} {% set sbasId = databox.get_sbas_id() %}
{% set nbItems = attribute(nRec, sbasId) %}
{% set nbRecords = nbItems['records'] %}
{% set nbStories = nbItems['stories'] %}
<table style='width:auto;margin:0 auto'> <table style='width:auto;margin:0 auto'>
<thead> <thead>
<tr> <tr>
@@ -54,22 +59,10 @@
<tbody> <tbody>
<tr style='border-bottom:1px solid #FFF;'> <tr style='border-bottom:1px solid #FFF;'>
<td colspan="6" style='font-size:11px;text-align:center'> <td colspan="6" style='font-size:11px;text-align:center'>
{% if nbRecords == 0 and nbStories > 0 %} {% trans %}Status edition{% endtrans %}</i>
<i>({% trans %}Stories status edition{% endtrans %})</i>
{% elseif nbRecords > 0 and nbStories == 0 %}
<i>({% trans %}Records status edition{% endtrans %})</i>
{% endif %}
</td> </td>
</tr> </tr>
{% set databoxStatus = attribute(statusBit, sbasId) %} {% for bit,values in status %}
{% for bit,values in databoxStatus %}
{% set inverse = 0 %}
{% if values["status"] == "2" %}
{% set inverse = 2 %}
{% elseif values["status"] == "0" %}
{% set inverse = 1 %}
{% endif %}
<tr> <tr>
<td style='text-align:right'> <td style='text-align:right'>
{% if values['img_off'] is not empty %} {% if values['img_off'] is not empty %}
@@ -79,18 +72,18 @@
{% endif %} {% endif %}
</td> </td>
<td style='text-align:right'> <td style='text-align:right'>
<label for="status-radio-{{ sbasId ~ "-" ~ bit ~ '-off'}}" {% if inverse == 2 %}style='color:#FF3333'{% endif%}> <label for="status-radio-{{ sbasId ~ "-" ~ bit ~ '-off'}}" {% if values['flag'] == 2 %}style='color:#FF3333'{% endif%}>
{{ values['labels_off_i18n'][app['locale']] }} {{ values['labels_off_i18n'][app['locale']] }}
</label> </label>
</td> </td>
<td style='text-align:right'> <td style='text-align:right'>
<input id="status-radio-{{ sbasId ~ "-" ~ bit ~ '-off'}}" type="radio" name="status[{{ sbasId }}][{{ bit }}]" value="0" {% if inverse == 1 %}checked="checked"{% endif %}/> <input id="status-radio-{{ sbasId ~ "-" ~ bit ~ '-off'}}" type="radio" name="status[{{ sbasId }}][{{ bit }}]" {% if values['flag'] == 0 %}checked="checked"{% endif%} value="0"/>
</td> </td>
<td style='text-align:left'> <td style='text-align:left'>
<input id="status-radio-{{ sbasId ~ "-" ~ bit ~ '-on'}}" type="radio" name="status[{{ sbasId }}][{{ bit }}]" value="1" {% if inverse == 0 %}checked="checked"{% endif %}/> <input id="status-radio-{{ sbasId ~ "-" ~ bit ~ '-on'}}" type="radio" name="status[{{ sbasId }}][{{ bit }}]" {% if values['flag'] == 1 %}checked="checked"{% endif%} value="1"/>
</td> </td>
<td style='text-align:left'> <td style='text-align:left'>
<label for="status-radio-{{ sbasId ~ "-" ~ bit ~ '-on'}}" {% if inverse == 2 %}style='color:#FF3333'{% endif%}> <label for="status-radio-{{ sbasId ~ "-" ~ bit ~ '-on'}}" {% if values['flag'] == 2 %}style='color:#FF3333'{% endif%}>
{{ values['labels_on_i18n'][app['locale']] }} {{ values['labels_on_i18n'][app['locale']] }}
</label> </label>
</td> </td>
@@ -105,89 +98,85 @@
{% endfor %} {% endfor %}
</tbody> </tbody>
<tfoot> <tfoot>
{% if nbStories > 0 %} {% if records.stories.count > 0 %}
<tr> <tr>
<td colspan="6"> <td colspan="6">
<input type="checkbox" name="apply_to_children[{{ sbasId }}]"/> <input type="checkbox" name="apply_to_children[{{ sbasId }}]"/>
{% if nbStories == 1 %} {% trans %}Apply status on story children.{% endtrans %}
{% trans %}Apply status on stories children.{% endtrans %}
{% elseif nbStories > 0 %}
{% trans %}Apply status on story children.{% endtrans %}
{% endif %}
</td> </td>
</tr> </tr>
{% endif %} {% endif %}
</tfoot> </tfoot>
</table> </table>
{% endfor %} <div class="form-actions" style="background:transparent">
<div class="form-actions" style="background:transparent"> {% if nbEditableDocuments > 0 %}
{% if nbEditableDocuments > 0 %} <button type="button" class="btn btn-primary submiter">{{ "Apply changes" | trans }}</button>
<button type="button" class="btn btn-primary submiter">{{ "Apply changes" | trans }}</button> {% endif %}
{% endif %} <button type="button" class="btn cancel">{{ "Cancel" | trans }}</button>
<button type="button" class="btn cancel">{{ "Cancel" | trans }}</button> <span class="form-action-loader" style="display:none;">
<span class="form-action-loader" style="display:none;"> <img src="../skins/icons/loader414141.gif" />
<img src="../skins/icons/loader414141.gif" /> </span>
</span> </div>
</div> </form>
</form> </div>
</div> </div>
</div>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function(){ $(document).ready(function(){
$("#tabs-records-property").tabs({ $("#tabs-records-property").tabs({
beforeLoad: function( event, ui ) { beforeLoad: function( event, ui ) {
ui.ajaxSettings.data = { ui.ajaxSettings.data = {
lst: $("input[name=original_selection]", $(this)).val() lst: $("input[name=original_selection]", $(this)).val()
}; };
// load template only once // load template only once
if ( ui.tab.data( "loaded" ) ) { if ( ui.tab.data( "loaded" ) ) {
event.preventDefault(); event.preventDefault();
return; return;
} }
ui.jqXHR.success(function() { ui.jqXHR.success(function() {
ui.tab.data( "loaded", true ); ui.tab.data( "loaded", true );
}); });
ui.tab.find('span').html("<i>{{ 'Loading'|trans }}...</i>"); ui.tab.find('span').html("<i>{{ 'Loading'|trans }}...</i>");
}, },
load: function(event, ui) load: function(event, ui)
{ {
ui.tab.find('span').empty(); ui.tab.find('span').empty();
}
});
var $dialog = p4.Dialog.get(1);
var $dialogBox = $dialog.getDomElement();
$("button.cancel", $dialogBox).bind("click", function(){
$dialog.Close();
});
$("button.submiter", $dialogBox).bind("click", function(){
var $this = $(this);
var form = $(this).closest("form");
var loader = form.find("form-action-loader");
$.ajax({
type: form.attr("method"),
url: form.attr("action"),
data: form.serializeArray(),
dataType: 'json',
beforeSend:function(){
$this.attr("disabled", true);
loader.show();
},
success: function(data){
$dialog.Close();
},
complete: function(){
$this.attr("disabled", false);
loader.hide();
} }
}); });
var $dialog = p4.Dialog.get(1);
var $dialogBox = $dialog.getDomElement();
$("button.cancel", $dialogBox).bind("click", function(){
$dialog.Close();
});
$("button.submiter", $dialogBox).bind("click", function(){
var $this = $(this);
var form = $(this).closest("form");
var loader = form.find("form-action-loader");
$.ajax({
type: form.attr("method"),
url: form.attr("action"),
data: form.serializeArray(),
dataType: 'json',
beforeSend:function(){
$this.attr("disabled", true);
loader.show();
},
success: function(data){
$dialog.Close();
},
complete: function(){
$this.attr("disabled", false);
loader.hide();
}
});
});
}); });
}); </script>
</script> {% endif %}

View File

@@ -379,33 +379,31 @@
<div class="status_filter"> <div class="status_filter">
<span>{{ 'Status des documents a rechercher' | trans }}</span> <span>{{ 'Status des documents a rechercher' | trans }}</span>
<table style="width: 100%;"> <table style="width: 100%;">
{% for sbas_id, bits in search_status %} {% for databox_id, flag in search_status %}
{% for n, bit in bits %}
<tr> <tr>
<td> <td>
{% if bit['imgoff'] %}
<img src="{{bit['imgoff']}}" title="{{bit['labels_off_i18n'][app['locale']]}}" />
{% endif %}
<label class="checkbox inline"> <label class="checkbox inline">
<input onchange="checkFilters(true);" class="field_switch field_{{sbas_id}}" {% if flag['img_off'] %}
<img src="{{flag['img_off']}}" title="{{flag['labels_off_i18n'][app['locale']]}}" />
{% endif %}
<input onchange="checkFilters(true);" class="field_switch field_{{databox_id}}"
type="checkbox" value="0" type="checkbox" value="0"
n="{{n}}" name="status[{{sbas_id}}][{{n}}]" /> n="{{flag['bit']}}" name="status[{{databox_id}}][{{flag['bit']}}]" />
{{bit['labels_off_i18n'][app['locale']]}} {{flag['labels_off_i18n'][app['locale']]}}
</label> </label>
</td> </td>
<td> <td>
{% if bit['imgon'] %}
<img src="{{bit['imgon']}}" title="{{bit['labels_on_i18n'][app['locale']]}}" />
{% endif %}
<label class="checkbox inline"> <label class="checkbox inline">
<input onchange="checkFilters(true);" class="field_switch field_{{sbas_id}}" {% if flag['img_on'] %}
<img src="{{flag['img_on']}}" title="{{flag['labels_on_i18n'][app['locale']]}}" />
{% endif %}
<input onchange="checkFilters(true);" class="field_switch field_{{databox_id}}"
type="checkbox" value="1" type="checkbox" value="1"
n="{{n}}" name="status[{{sbas_id}}][{{n}}]"/> n="{{flag['bit']}}" name="status[{{databox_id}}][{{flag['bit']}}]"/>
{{bit['labels_on_i18n'][app['locale']]}} {{flag['labels_on_i18n'][app['locale']]}}
</label> </label>
</td> </td>
</tr> </tr>
{% endfor %}
{% endfor %} {% endfor %}
</table> </table>
</div> </div>

View File

@@ -12,8 +12,9 @@
{{ record.title }} {{ record.title }}
</div> </div>
<div class="status"> <div class="status">
{# @todo find a proper way to map lifted flag to status icon img path #} {% for flag in record_flags(record) %}
{#{{record.get_status_icons|raw}}#} <img src="{{ flag.path }}" title="{{ attribute(flag.labels, app.locale) }}" />
{% endfor %}
</div> </div>
</div> </div>

View File

@@ -66,7 +66,7 @@
<h5>{{ 'upload:: Status :' | trans }} :</h5> <h5>{{ 'upload:: Status :' | trans }} :</h5>
<table class="status-tab"> <table class="status-tab">
<tbody> <tbody>
{% for bit, status in availableCollections['databox'].get_statusbits() %} {% for bit, status in availableCollections['databox'].getStatusStructure() %}
<tr> <tr>
<td class="status-tab-left"> <td class="status-tab-left">
{% if status['img_off'] is not empty %} {% if status['img_off'] is not empty %}

View File

@@ -71,7 +71,7 @@
<h5>{{ 'upload:: Status :' | trans }} :</h5> <h5>{{ 'upload:: Status :' | trans }} :</h5>
<table class="status-tab"> <table class="status-tab">
<tbody> <tbody>
{% for bit, status in availableCollections['databox'].get_statusbits() %} {% for bit, status in availableCollections['databox'].getStatusStructure() %}
<tr> <tr>
<td class="status-tab-left"> <td class="status-tab-left">
{% if status['img_off'] is not empty %} {% if status['img_off'] is not empty %}

View File

@@ -197,8 +197,6 @@ function checkFilters(save) {
$('input.field_switch:checked', container).removeAttr('checked'); $('input.field_switch:checked', container).removeAttr('checked');
$('input.field_switch:checkbox', container).parent().hide();
filters.removeClass('danger'); filters.removeClass('danger');
var nbSelectedColls = 0; var nbSelectedColls = 0;