Merge branch 'master' into PHRAS-2739-incorporate-subdefwebhook

This commit is contained in:
Nicolas Maillat
2019-11-08 18:32:07 +01:00
committed by GitHub
32 changed files with 979 additions and 398 deletions

View File

@@ -314,6 +314,8 @@ class FieldsController extends Controller
->set_readonly($data['readonly'])
->set_type($data['type'])
->set_tbranch($data['tbranch'])
->set_generate_cterms($data['generate_cterms'])
->set_gui_editable($data['gui_editable'])
->set_report($data['report'])
->setVocabularyControl(null)
->setVocabularyRestricted(false);
@@ -349,7 +351,7 @@ class FieldsController extends Controller
{
return [
'name', 'multi', 'thumbtitle', 'tag', 'business', 'indexable', 'aggregable',
'required', 'separator', 'readonly', 'type', 'tbranch', 'report',
'required', 'separator', 'readonly', 'gui_editable', 'type', 'tbranch', 'generate_cterms', 'report',
'vocabulary-type', 'vocabulary-restricted', 'dces-element', 'labels'
];
}

View File

@@ -594,6 +594,8 @@ class V1Controller extends Controller
],
'separator' => $databox_field->get_separator(),
'thesaurus_branch' => $databox_field->get_tbranch(),
'generate_cterms' => $databox_field->get_generate_cterms(),
'gui_editable' => $databox_field->get_gui_editable(),
'type' => $databox_field->get_type(),
'indexable' => $databox_field->is_indexable(),
'multivalue' => $databox_field->is_multi(),

View File

@@ -75,6 +75,8 @@ class EditController extends Controller
'format' => '',
'explain' => '',
'tbranch' => $meta->get_tbranch(),
'generate_cterms' => $meta->get_generate_cterms(),
'gui_editable' => $meta->get_gui_editable(),
'maxLength' => $meta->get_tag()
->getMaxLength(),
'minLength' => $meta->get_tag()

View File

@@ -70,7 +70,7 @@ class LazaretController extends Controller
public function getElement($file_id)
{
$ret = ['success' => false, 'message' => '', 'result' => []];
/* @var LazaretFile $lazaretFile */
$lazaretFile = $this->getLazaretFileRepository()->find($file_id);
@@ -126,6 +126,16 @@ class LazaretController extends Controller
$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);
}
@@ -216,6 +226,7 @@ class LazaretController extends Controller
return $this->app->json($ret);
}
$postStatus = (array) $request->request->get('status');
$path = $this->app['tmp.lazaret.path'] . '/';
$lazaretFileName = $path .$lazaretFile->getFilename();
@@ -233,6 +244,9 @@ class LazaretController extends Controller
''
);
// update status
$this->updateRecordStatus($record, $postStatus);
//Delete lazaret file
$manager = $this->getEntityManager();
$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
*/
@@ -293,4 +336,32 @@ class LazaretController extends Controller
{
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+')
->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;
}
}

View File

@@ -16,7 +16,7 @@ class Version
/**
* @var string
*/
private $number = '4.1.0-alpha.15a';
private $number = '4.1.0-alpha.17a';
/**
* @var string

View File

@@ -36,6 +36,8 @@ final class DbalDataboxFieldRepository implements DataboxFieldRepository
'label_fr',
'label_de',
'label_nl',
'generate_cterms',
'gui_editable',
];
/** @var DataboxFieldFactory */

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea\Model\Entities;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use \record_adapter;
@@ -474,4 +475,32 @@ class LazaretFile
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->flush();
$ret['result']['record_id'] = $record->getRecordId();
$ret['success'] = true;
} catch (\Exception $e) {
$ret['message'] = $this->app->trans('An error occured');

View File

@@ -58,6 +58,11 @@ class GeolocationKey implements Key
$this->key = $key;
}
public function getFieldType(QueryContext $context)
{
return $this->type;
}
public function getIndexField(QueryContext $context, $raw = false)
{
return $this->key;

View File

@@ -42,7 +42,7 @@ class ThesaurusHydrator implements HydratorInterface
$fields = [];
$index_fields = [];
foreach ($structure as $name => $field) {
$fields[$name] = $field->getThesaurusRoots();
$fields[$name] = $field; // ->getThesaurusRoots();
$index_fields[$name] = $field->getIndexField();
}
// Hydrate records with concepts
@@ -51,7 +51,13 @@ class ThesaurusHydrator implements HydratorInterface
}
}
private function hydrate(array &$record, array $fields, array $index_fields)
/**
* @param array $record
* @param Field[] $fields
* @param array $index_fields
* @throws Exception
*/
private function hydrate(array &$record, $fields, array $index_fields)
{
if (!isset($record['databox_id'])) {
throw new Exception('Expected a record with the "databox_id" key set.');
@@ -61,7 +67,8 @@ class ThesaurusHydrator implements HydratorInterface
$terms = array();
$filters = array();
$field_names = array();
foreach ($fields as $name => $root_concepts) {
foreach ($fields as $name => $field) {
$root_concepts = $field->getThesaurusRoots();
// Loop through all values to prepare bulk query
$field_values = \igorw\get_in($record, explode('.', $index_fields[$name]));
if ($field_values !== null) {
@@ -84,13 +91,17 @@ class ThesaurusHydrator implements HydratorInterface
$bulk = $this->thesaurus->findConceptsBulk($terms, null, $filters, true);
foreach ($bulk as $offset => $item_concepts) {
$name = $field_names[$offset];
if ($item_concepts && is_array($item_concepts) && count($item_concepts)>0) {
$name = $field_names[$offset];
foreach ($item_concepts as $concept) {
$record['concept_path'][$name][] = $concept->getPath();
}
} else {
$this->candidate_terms->insert($field_names[$offset], $values[$offset]);
}
else {
$field = $fields[$name];
if($field->get_generate_cterms()) {
$this->candidate_terms->insert($field_names[$offset], $values[$offset]);
}
}
}
}

View File

@@ -46,22 +46,23 @@ class FacetsResponse
if (!isset($bucket['key']) || !isset($bucket['doc_count'])) {
$this->throwAggregationResponseError();
}
$key = array_key_exists('key_as_string', $bucket) ? $bucket['key_as_string'] : $bucket['key'];
if($tf) {
// the field is one of the hardcoded tech fields
$value = [
'value' => $valueFormatter($bucket['key']),
'raw_value' => $bucket['key'],
'value' => $valueFormatter($key),
'raw_value' => $key,
'count' => $bucket['doc_count'],
'query' => sprintf($tf['query'], $this->escaper->escapeWord($bucket['key']))
'query' => sprintf($tf['query'], $this->escaper->escapeWord($key))
];
}
else {
// the field is a normal field
$value = [
'value' => $bucket['key'],
'raw_value' => $bucket['key'],
'value' => $key,
'raw_value' => $key,
'count' => $bucket['doc_count'],
'query' => sprintf('field.%s:%s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($bucket['key']))
'query' => sprintf('field.%s:%s', $this->escaper->escapeWord($name), $this->escaper->escapeWord($key))
];
}

View File

@@ -63,4 +63,26 @@ class StringUtils
return self::$transliterator->transliterate($string);
}
/**
* replace bad chars (ascii 0...31 except 9,10,13)
*
* @param $s
* @param string $replace
* @return mixed
*/
public static function substituteCtrlCharacters($s, $replace = '_')
{
static $bad_chars = null;
if($bad_chars === null) {
$bad_chars = [];
for($i=0; $i<32; $i++) {
if($i != 9 && $i != 10 && $i != 13) {
$bad_chars[] = chr($i);
}
}
}
return str_replace($bad_chars, $replace, $s);
}
}

View File

@@ -43,6 +43,8 @@ class Field implements Typed
private $thesaurus_roots;
private $generate_cterms;
private $used_by_collections;
public static function createFromLegacyField(databox_field $field, $with = Structure::WITH_EVERYTHING)
@@ -75,6 +77,7 @@ class Field implements Typed
'private' => $field->isBusiness(),
'facet' => $facet,
'thesaurus_roots' => $roots,
'generate_cterms' => $field->get_generate_cterms(),
'used_by_collections' => $databox->get_collection_unique_ids()
]);
}
@@ -103,6 +106,7 @@ class Field implements Typed
$this->is_private = \igorw\get_in($options, ['private'], false);
$this->facet = \igorw\get_in($options, ['facet']);
$this->thesaurus_roots = \igorw\get_in($options, ['thesaurus_roots'], null);
$this->generate_cterms = \igorw\get_in($options, ['generate_cterms'], false);
$this->used_by_collections = \igorw\get_in($options, ['used_by_collections'], []);
Assertion::boolean($this->is_searchable);
@@ -126,6 +130,7 @@ class Field implements Typed
'private' => $this->is_private,
'facet' => $this->facet,
'thesaurus_roots' => $this->thesaurus_roots,
'generate_cterms' => $this->generate_cterms,
'used_by_collections' => $this->used_by_collections
]);
}
@@ -190,6 +195,11 @@ class Field implements Typed
return $this->thesaurus_roots;
}
public function get_generate_cterms()
{
return $this->generate_cterms;
}
/**
* Merge with another field, returning the new instance
*

View File

@@ -32,6 +32,7 @@ class CandidateTerms
public function insert($field, $value)
{
$value = StringUtils::substituteCtrlCharacters($value, '');
$this->ensureVisitorSetup();
if (!$this->visitor->hasTerm($field, $value)) {
$this->new_candidates[$value] = $field;

View File

@@ -462,6 +462,8 @@ class databox extends base implements ThumbnailedElement
->set_aggregable((isset($field['aggregable']) ? (string) $field['aggregable'] : 0))
->set_type($type)
->set_tbranch(isset($field['tbranch']) ? (string) $field['tbranch'] : '')
->set_generate_cterms((isset($field['generate_cterms']) && (string) $field['generate_cterms'] == 1))
->set_gui_editable((isset($field['gui_editable']) && (string) $field['gui_editable'] == 1))
->set_thumbtitle(isset($field['thumbtitle']) ? (string) $field['thumbtitle'] : (isset($field['thumbTitle']) ? $field['thumbTitle'] : '0'))
->set_report(isset($field['report']) ? (string) $field['report'] : '1')
->save();
@@ -1214,21 +1216,40 @@ class databox extends base implements ThumbnailedElement
$domct = $this->get_dom_cterms();
if ($domct !== false) {
$changed = false;
$nodesToDel = [];
// loop on first level : "fields"
for($n = $domct->documentElement->firstChild; $n; $n = $n->nextSibling) {
if($n->nodeType == XML_ELEMENT_NODE && !($n->getAttribute('delbranch'))){
$nodesToDel[] = $n;
$nodesToDel2 = [];
// loop on 2nd level : "terms"
for($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) {
// do not remove "rejected" candidates
if(substr($n2->getAttribute('id'), 0, 1) != 'R') {
$nodesToDel2[] = $n2;
}
}
foreach($nodesToDel2 as $n2) {
$n->removeChild($n2);
$changed = true;
}
// if a field has no more candidates, we can remove it
if(!($n->firstChild)) {
$nodesToDel[] = $n;
}
}
}
foreach($nodesToDel as $n) {
$n->parentNode->removeChild($n);
$changed = true;
}
if(!empty($nodesToDel)) {
if($changed) {
$this->saveCterms($domct);
}
}
} catch (\Exception $e) {
}
catch (\Exception $e) {
// no-op
}
}

View File

@@ -43,6 +43,8 @@ class databox_field implements cache_cacheableInterface
protected $report;
protected $type;
protected $tbranch;
protected $generate_cterms;
protected $gui_editable;
protected $separator;
protected $thumbtitle;
@@ -166,6 +168,8 @@ class databox_field implements cache_cacheableInterface
$this->position = (int)$row['sorter'];
$this->type = $row['type'] ?: self::TYPE_STRING;
$this->tbranch = $row['tbranch'];
$this->generate_cterms = (bool)$row['generate_cterms'];
$this->gui_editable = (bool)$row['gui_editable'];
$this->VocabularyType = $row['VocabularyControlType'];
$this->VocabularyRestriction = (bool)$row['RestrictToVocabularyControl'];
@@ -306,6 +310,8 @@ class databox_field implements cache_cacheableInterface
`report` = :report,
`type` = :type,
`tbranch` = :tbranch,
`generate_cterms` = :generate_cterms,
`gui_editable` = :gui_editable,
`sorter` = :position,
`thumbtitle` = :thumbtitle,
`VocabularyControlType` = :VocabularyControlType,
@@ -329,6 +335,8 @@ class databox_field implements cache_cacheableInterface
':report' => $this->report ? '1' : '0',
':type' => $this->type,
':tbranch' => $this->tbranch,
':generate_cterms' => $this->generate_cterms ? '1' : '0',
':gui_editable' => $this->gui_editable ? '1' : '0',
':position' => $this->position,
':thumbtitle' => $this->thumbtitle,
':VocabularyControlType' => $this->getVocabularyControl() ? $this->getVocabularyControl()->getType() : null,
@@ -380,6 +388,8 @@ class databox_field implements cache_cacheableInterface
$meta->setAttribute('aggregable', $this->aggregable);
$meta->setAttribute('type', $this->type);
$meta->setAttribute('tbranch', $this->tbranch);
$meta->setAttribute('generate_cterms', $this->generate_cterms ? '1' : '0');
$meta->setAttribute('gui_editable', $this->gui_editable ? '1' : '0');
if ($this->multi) {
$meta->setAttribute('separator', $this->separator);
}
@@ -711,6 +721,28 @@ class databox_field implements cache_cacheableInterface
return $this;
}
/**
* @param boolean $generate_cterms
* @return databox_field
*/
public function set_generate_cterms($generate_cterms)
{
$this->generate_cterms = $generate_cterms;
return $this;
}
/**
* @param boolean $gui_editable
* @return databox_field
*/
public function set_gui_editable($gui_editable)
{
$this->gui_editable = $gui_editable;
return $this;
}
/**
*
* @param string $separator
@@ -795,6 +827,24 @@ class databox_field implements cache_cacheableInterface
return $this->tbranch;
}
/**
*
* @return boolean
*/
public function get_generate_cterms()
{
return $this->generate_cterms;
}
/**
*
* @return boolean
*/
public function get_gui_editable()
{
return $this->gui_editable;
}
/**
* @param Boolean $all If set to false, returns a one-char separator to use for serialiation
*
@@ -905,6 +955,8 @@ class databox_field implements cache_cacheableInterface
'sorter' => $this->position,
'thumbtitle' => $this->thumbtitle,
'tbranch' => $this->tbranch,
'generate_cterms' => $this->generate_cterms,
'gui_editable' => $this->gui_editable,
'separator' => $this->separator,
'required' => $this->required,
'report' => $this->report,
@@ -943,10 +995,10 @@ class databox_field implements cache_cacheableInterface
}
$sql = "INSERT INTO metadatas_structure
(`id`, `name`, `src`, `readonly`, `required`, `indexable`, `type`, `tbranch`,
(`id`, `name`, `src`, `readonly`, `gui_editable`, `required`, `indexable`, `type`, `tbranch`, `generate_cterms`,
`thumbtitle`, `multi`, `business`, `aggregable`,
`report`, `sorter`, `separator`)
VALUES (null, :name, '', 0, 0, 1, 'string', '',
VALUES (null, :name, '', 0, 1, 0, 1, 'string', '', 1,
null, 0, 0, 0,
1, :sorter, '')";

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Alchemy\Phrasea\Application;
class patch_410alpha17a implements patchInterface
{
/** @var string */
private $release = '4.1.0-alpha.17a';
/** @var array */
private $concern = [base::DATA_BOX];
/**
* {@inheritdoc}
*/
public function get_release()
{
return $this->release;
}
/**
* {@inheritdoc}
*/
public function getDoctrineMigrations()
{
return [];
}
/**
* {@inheritdoc}
*/
public function require_all_upgrades()
{
return false;
}
/**
* {@inheritdoc}
*/
public function concern()
{
return $this->concern;
}
/**
* {@inheritdoc}
*/
public function apply(base $databox, Application $app)
{
// -- done by xml schema --
// $sql = "ALTER TABLE `metadatas_structure` ADD `generate_cterms` INT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `tbranch`";
// $databox->get_connection()->executeQuery($sql);
// $sql = "ALTER TABLE `metadatas_structure` ADD `gui_editable` INT(1) UNSIGNED NOT NULL DEFAULT '0' AFTER `readonly`";
// $databox->get_connection()->executeQuery($sql);
return true;
}
}

View File

@@ -2033,6 +2033,22 @@
<default></default>
<comment></comment>
</field>
<field>
<name>generate_cterms</name>
<type>int(1) unsigned</type>
<null></null>
<extra></extra>
<default>1</default>
<comment></comment>
</field>
<field>
<name>gui_editable</name>
<type>int(1) unsigned</type>
<null></null>
<extra></extra>
<default>1</default>
<comment></comment>
</field>
</fields>
<indexes>
<index>