mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-18 07:23:13 +00:00
[skip ci]
PHRAS-3381_tx-as-classification-plan_MASTER back controller for ok button fix : PHRAS-3383 WIP
This commit is contained in:
@@ -26,6 +26,8 @@ use Alchemy\Phrasea\Twig\PhraseanetExtension;
|
||||
use Alchemy\Phrasea\Vocabulary\ControlProvider\ControlProviderInterface;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\RecordEditInWorkerEvent;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use stdClass;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
|
||||
@@ -342,6 +344,29 @@ class EditController extends Controller
|
||||
return $this->app->json(['success' => true]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* performs an editing using a similar json-body as api_v3:record:patch (except here we can work on a list of records)
|
||||
*
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function applyJSAction(Request $request): JsonResponse
|
||||
{
|
||||
// todo : by worker
|
||||
|
||||
// for now call record_adapter. no check, no acl, ...
|
||||
/** @var stdClass $arg */
|
||||
$arg = json_decode($request->getContent());
|
||||
|
||||
foreach($arg->records as $rec) {
|
||||
$r = $this->getApplicationBox()->get_databox($rec->sbas_id)->get_record($rec->record_id);
|
||||
$r->setMetadatasByActions($arg->actions);
|
||||
}
|
||||
|
||||
return $this->app->json(['success' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $preset_id
|
||||
* @return Preset
|
||||
@@ -359,7 +384,7 @@ class EditController extends Controller
|
||||
* route GET "../prod/records/edit/presets/{preset_id}"
|
||||
*
|
||||
* @param int $preset_id
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function presetsLoadAction($preset_id)
|
||||
{
|
||||
@@ -381,7 +406,7 @@ class EditController extends Controller
|
||||
* route GET "../prod/records/edit/presets"
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function presetsListAction(Request $request)
|
||||
{
|
||||
@@ -399,7 +424,7 @@ class EditController extends Controller
|
||||
* route DELETE "../prod/records/edit/presets/{preset_id}"
|
||||
*
|
||||
* @param int $preset_id
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function presetsDeleteAction($preset_id)
|
||||
{
|
||||
@@ -421,7 +446,7 @@ class EditController extends Controller
|
||||
* route POST "../prod/records/edit/presets"
|
||||
*
|
||||
* @param Request $request
|
||||
* @return \Symfony\Component\HttpFoundation\JsonResponse
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function presetsSaveAction(Request $request)
|
||||
{
|
||||
|
@@ -30,15 +30,24 @@ class ThesaurusController extends Controller
|
||||
{
|
||||
$sbas_id = $request->get('sbas_id');
|
||||
$tx_term_id = $request->get('tx_term_id');
|
||||
|
||||
$records = RecordsRequest::fromRequest($this->app, $request, RecordsRequest::FLATTEN_YES_PRESERVE_STORIES, [ACL::CANMODIFRECORD]);
|
||||
|
||||
// array of sbid/rid. too bad we cannot array_map on arraycollection
|
||||
$recRefs = [];
|
||||
foreach($records as $r) {
|
||||
$recRefs[] = [
|
||||
'sbas_id'=>$r->getDataboxId(),
|
||||
'record_id'=>$r->getRecordId()
|
||||
];
|
||||
}
|
||||
|
||||
// twig parameters
|
||||
$twp = [
|
||||
'error' => null,
|
||||
'dlg_level' => $request->get('dlg_level'),
|
||||
// 'fields' => [], // fields the can receive the value
|
||||
// 'fvalue' => 'Europe',
|
||||
'lst' => $records->serializedList(),
|
||||
// 'lst' => $records->serializedList(),
|
||||
'records' => $recRefs,
|
||||
'received_cnt' => $records->received()->count(),
|
||||
'rejected_cnt' => $records->rejected()->count(),
|
||||
'up_paths' => [],
|
||||
|
@@ -12,9 +12,9 @@
|
||||
namespace Alchemy\Phrasea\ControllerProvider\Prod;
|
||||
|
||||
use Alchemy\Phrasea\Application as PhraseaApplication;
|
||||
use Alchemy\Phrasea\Core\LazyLocator;
|
||||
use Alchemy\Phrasea\Controller\Prod\EditController;
|
||||
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
|
||||
use Alchemy\Phrasea\Core\LazyLocator;
|
||||
use Silex\Application;
|
||||
use Silex\ControllerProviderInterface;
|
||||
use Silex\ServiceProviderInterface;
|
||||
@@ -54,6 +54,11 @@ class Edit implements ControllerProviderInterface, ServiceProviderInterface
|
||||
|
||||
$controllers->get('/vocabulary/{vocabulary}/', 'controller.prod.edit:searchVocabularyAction');
|
||||
|
||||
/** @uses \Alchemy\Phrasea\Controller\Prod\EditController::applyJSAction */
|
||||
$controllers
|
||||
->post('/applyjs/', 'controller.prod.edit:applyJSAction')
|
||||
->bind('prod_edit_applyJSAction');
|
||||
|
||||
$controllers->post('/apply/', 'controller.prod.edit:applyAction');
|
||||
|
||||
$controllers->get('/presets/{preset_id}', 'controller.prod.edit:presetsLoadAction');
|
||||
|
@@ -42,11 +42,6 @@ class Thesaurus implements ControllerProviderInterface, ServiceProviderInterface
|
||||
public function connect(Application $app)
|
||||
{
|
||||
$controllers = $this->createAuthenticatedCollection($app);
|
||||
// $firewall = $this->getFirewall($app);
|
||||
|
||||
// $controllers->before(function () use ($firewall) {
|
||||
// $firewall->requireRight(\ACL::CANMODIFRECORD);
|
||||
// });
|
||||
|
||||
/** @uses ThesaurusController::dropRecordsAction() */
|
||||
$controllers->get('/droprecords', 'controller.prod.thesaurus:dropRecordsAction');
|
||||
|
@@ -32,11 +32,8 @@ use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\RecordInterface;
|
||||
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
|
||||
use Alchemy\Phrasea\Record\RecordReference;
|
||||
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\Record\Hydrator\GpsPosition;
|
||||
use Alchemy\Phrasea\SearchEngine\SearchEngineInterface;
|
||||
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\RecordsWriteMetaEvent;
|
||||
use Alchemy\Phrasea\WorkerManager\Event\WorkerEvents;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
@@ -1128,6 +1125,351 @@ class record_adapter implements RecordInterface, cache_cacheableInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMetadatasByActions(stdClass $actions)
|
||||
{
|
||||
// WIP crashes when trying to access an undefined stdClass property ? should return null ?
|
||||
// $this->apply_body($actions);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =============================================================================
|
||||
* the following methods allows editing by the json api-v3:record:post format
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param stdClass $b
|
||||
* @param record_adapter $record
|
||||
* @throws Exception
|
||||
*/
|
||||
private function apply_body(stdClass $b)
|
||||
{
|
||||
// do metadatas ops
|
||||
if (is_array($b->metadatas)) {
|
||||
$this->do_metadatas($b->metadatas);
|
||||
}
|
||||
// do sb ops
|
||||
if (is_array($b->status)) {
|
||||
$this->do_status($b->status);
|
||||
}
|
||||
if(!is_null($b->base_id)) {
|
||||
$this->do_collection($b->base_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $base_id
|
||||
*/
|
||||
private function do_collection($base_id)
|
||||
{
|
||||
$this->move_to_collection(collection::getByCollectionId($this->app, $this->getDatabox(), $base_id));
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////
|
||||
/// TODO : keep multi-values uniques !
|
||||
/// it should be done in record_adapter
|
||||
//////////////////////////////////
|
||||
|
||||
/**
|
||||
* @param $metadatas
|
||||
* @throws Exception
|
||||
*/
|
||||
private function do_metadatas($metadatas)
|
||||
{
|
||||
/** @var databox_field[] $struct */
|
||||
$struct = $this->getDatabox()->get_meta_structure();
|
||||
|
||||
|
||||
$structByKey = [];
|
||||
$allStructFields = [];
|
||||
foreach ($struct as $f) {
|
||||
$allStructFields[$f->get_id()] = $f;
|
||||
$structByKey[$f->get_id()] = &$allStructFields[$f->get_id()];
|
||||
$structByKey[$f->get_name()] = &$allStructFields[$f->get_id()];
|
||||
}
|
||||
|
||||
$metadatas_ops = [];
|
||||
foreach ($metadatas as $_m) {
|
||||
// sanity
|
||||
if($_m->meta_struct_id && $_m->field_name) { // WIP crashes if meta_struct_id is undefined
|
||||
throw new Exception("define meta_struct_id OR field_name, not both.");
|
||||
}
|
||||
// select fields that match meta_struct_id or field_name (can be arrays)
|
||||
$fields_list = null; // to filter caption_fields from record, default all
|
||||
$struct_fields = []; // struct fields that match meta_struct_id or field_name
|
||||
$field_keys = $_m->meta_struct_id ? $_m->meta_struct_id : $_m->field_name; // can be null if none defined (=match all)
|
||||
if($field_keys !== null) {
|
||||
if (!is_array($field_keys)) {
|
||||
$field_keys = [$field_keys];
|
||||
}
|
||||
$fields_list = [];
|
||||
foreach ($field_keys as $k) {
|
||||
if(array_key_exists($k, $structByKey)) {
|
||||
$fields_list[] = $structByKey[$k]->get_name();
|
||||
$struct_fields[$structByKey[$k]->get_id()] = $structByKey[$k];
|
||||
}
|
||||
else {
|
||||
throw new Exception(sprintf("unknown field (%s).", $k));
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no meta_struct_id, no field_name --> match all struct fields !
|
||||
$struct_fields = $allStructFields;
|
||||
}
|
||||
$caption_fields = $this->get_caption()->get_fields($fields_list, true);
|
||||
|
||||
$meta_id = is_null($_m->meta_id) ? null : (int)($_m->meta_id);
|
||||
|
||||
if(!($match_method = (string)($_m->match_method))) {
|
||||
$match_method = 'ignore_case';
|
||||
}
|
||||
if(!in_array($match_method, ['strict', 'ignore_case', 'regexp'])) {
|
||||
throw new Exception(sprintf("bad match_method (%s).", $match_method));
|
||||
}
|
||||
|
||||
$values = [];
|
||||
if(is_array($_m->value)) {
|
||||
foreach ($_m->value as $v) {
|
||||
if(($v = trim((string)$v)) !== '') {
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(($v = trim((string)($_m->value))) !== '') {
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
if(!($action = (string)($_m->action))) {
|
||||
$action = 'set';
|
||||
}
|
||||
|
||||
switch ($_m->action) {
|
||||
case 'set':
|
||||
$ops = $this->metadata_set($struct_fields, $caption_fields, $meta_id, $values);
|
||||
break;
|
||||
case 'add':
|
||||
$ops = $this->metadata_add($struct_fields, $values);
|
||||
break;
|
||||
case 'delete':
|
||||
$ops = $this->metadata_replace($caption_fields, $meta_id, $match_method, $values, null);
|
||||
break;
|
||||
case 'replace':
|
||||
if (!is_string($_m->replace_with) && !is_null($_m->replace_with)) {
|
||||
throw new Exception("bad \"replace_with\" for action \"replace\".");
|
||||
}
|
||||
$ops = $this->metadata_replace($caption_fields, $meta_id, $match_method, $values, $_m->replace_with);
|
||||
break;
|
||||
default:
|
||||
throw new Exception(sprintf("bad action (%s).", $action));
|
||||
}
|
||||
|
||||
$metadatas_ops = array_merge($metadatas_ops, $ops);
|
||||
}
|
||||
|
||||
$this->set_metadatas($metadatas_ops, true);
|
||||
|
||||
// order to write meta in file
|
||||
$this->app['dispatcher']->dispatch(WorkerEvents::RECORDS_WRITE_META,
|
||||
new RecordsWriteMetaEvent([$this->getRecordId()], $this->getDataboxId()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $statuses
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
private function do_status($statuses)
|
||||
{
|
||||
$datas = strrev($this->getStatus());
|
||||
|
||||
foreach ($statuses as $status) {
|
||||
$n = (int)($status->bit);
|
||||
$value = (int)($status->state);
|
||||
if ($n > 31 || $n < 4) {
|
||||
throw new Exception(sprintf("Invalid status bit number (%s).", $n));
|
||||
}
|
||||
if ($value < 0 || $value > 1) {
|
||||
throw new Exception(sprintf("Invalid status bit state (%s) for bit (%s).", $value, $n));
|
||||
}
|
||||
|
||||
$datas = substr($datas, 0, ($n)) . $value . substr($datas, ($n + 1));
|
||||
}
|
||||
|
||||
$this->setStatus(strrev($datas));
|
||||
}
|
||||
|
||||
private function match($pattern, $method, $value)
|
||||
{
|
||||
switch ($method) {
|
||||
case 'strict':
|
||||
return $value === $pattern;
|
||||
case 'ignore_case':
|
||||
return strtolower($value) === strtolower($pattern);
|
||||
case 'regexp':
|
||||
return preg_match($pattern, $value) == 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param databox_field[] $struct_fields struct-fields (from struct) matching meta_struct_id or field_name
|
||||
* @param caption_field[] $caption_fields caption-fields (from record) matching meta_struct_id or field_name (or all if not set)
|
||||
* @param int|null $meta_id
|
||||
* @param string[] $values
|
||||
*
|
||||
* @return array ops to execute
|
||||
* @throws Exception
|
||||
*/
|
||||
private function metadata_set(array $struct_fields, $caption_fields, $meta_id, $values): array
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
// if one field was multi-valued and no meta_id was set, we must delete all values
|
||||
foreach ($caption_fields as $cf) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
if (is_null($meta_id) || $field_value->getId() === (int)$meta_id) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => ''
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// now set values to matching struct_fields
|
||||
foreach ($struct_fields as $sf) {
|
||||
if($sf->is_multi()) {
|
||||
// add the non-null value(s)
|
||||
foreach ($values as $value) {
|
||||
if ($value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => $meta_id, // can be null
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mono-valued
|
||||
if(count($values) > 1) {
|
||||
throw new Exception(sprintf("setting mono-valued (%s) requires only one value.", $sf->get_name()));
|
||||
}
|
||||
if( ($value = $values[0]) ) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => $meta_id, // probably null,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param databox_field[] $struct_fields struct-fields (from struct) matching meta_struct_id or field_name
|
||||
* @param string[] $values
|
||||
*
|
||||
* @return array ops to execute
|
||||
* @throws Exception
|
||||
*/
|
||||
private function metadata_add($struct_fields, $values)
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
// now set values to matching struct_fields
|
||||
foreach ($struct_fields as $sf) {
|
||||
if(!$sf->is_multi()) {
|
||||
throw new Exception(sprintf("can't \"add\" to mono-valued (%s).", $sf->get_name()));
|
||||
}
|
||||
foreach ($values as $value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $sf->get_id(),
|
||||
'meta_id' => null,
|
||||
'value' => $value
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param caption_field[] $caption_fields caption-fields (from record) matching meta_struct_id or field_name (or all if not set)
|
||||
* @param int|null $meta_id
|
||||
* @param string $match_method "strict" | "ignore_case" | "regexp"
|
||||
* @param string[] $values
|
||||
* @param string|null $replace_with
|
||||
*
|
||||
* @return array ops to execute
|
||||
*/
|
||||
private function metadata_replace($caption_fields, $meta_id, $match_method, $values, $replace_with)
|
||||
{
|
||||
$ops = [];
|
||||
|
||||
$replace_with = trim((string)$replace_with);
|
||||
|
||||
foreach ($caption_fields as $cf) {
|
||||
// match all ?
|
||||
if(is_null($meta_id) && count($values) == 0) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $replace_with
|
||||
];
|
||||
}
|
||||
}
|
||||
// match by meta-id ?
|
||||
if (!is_null($meta_id)) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
if ($field_value->getId() === $meta_id) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $replace_with
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
// match by value(s) ?
|
||||
foreach ($values as $value) {
|
||||
foreach ($cf->get_values() as $field_value) {
|
||||
$rw = $replace_with;
|
||||
if($match_method=='regexp' && $rw != '') {
|
||||
$rw = preg_replace($value, $rw, $field_value->getValue());
|
||||
}
|
||||
if ($this->match($value, $match_method, $field_value->getValue())) {
|
||||
$ops[] = [
|
||||
'meta_struct_id' => $cf->get_meta_struct_id(),
|
||||
'meta_id' => $field_value->getId(),
|
||||
'value' => $rw
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $ops;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* END editing by the json api-v3:record:post format
|
||||
* =============================================================================
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return record_adapter
|
||||
*/
|
||||
|
Reference in New Issue
Block a user