mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-15 05:53:13 +00:00
- add : doc of stories/children
- fix : limiting the number of children with search stories (story_max_records=N in url) respects coll/mask rights
This commit is contained in:
@@ -118,3 +118,46 @@ paths:
|
||||
description: Record not found
|
||||
default:
|
||||
$ref: 'responses.yaml#/error_response'
|
||||
'/stories/{sbas_id}/{record_id}/children':
|
||||
get:
|
||||
tags:
|
||||
- story
|
||||
summary: Returns uri of each record (child) contained in the story ; Optional pagination
|
||||
description: Returns children of a story
|
||||
operationId: getRecordById
|
||||
parameters:
|
||||
- name: sbas_id
|
||||
in: path
|
||||
description: ID of the databox
|
||||
required: true
|
||||
schema:
|
||||
$ref: schemas.yaml#/ID
|
||||
- name: record_id
|
||||
in: path
|
||||
description: ID of the story record
|
||||
required: true
|
||||
schema:
|
||||
$ref: schemas.yaml#/ID
|
||||
- name: page
|
||||
in: query
|
||||
description: page number (default 1)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
- name: per_page
|
||||
in: query
|
||||
description: number of children (records uri) per page (default 10)
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
responses:
|
||||
200:
|
||||
description: ok
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: schemas.yaml#/ApiResponse_RecordsUriArray
|
||||
404:
|
||||
description: Story (record) not found
|
||||
default:
|
||||
$ref: 'responses.yaml#/error_response'
|
||||
|
@@ -1,2 +1,15 @@
|
||||
record_response:
|
||||
type: object
|
||||
properties:
|
||||
200:
|
||||
description: successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: schemas.yaml#/ApiResponse_record
|
||||
400:
|
||||
description: Any other error
|
||||
404:
|
||||
description: Record not found
|
||||
error_response:
|
||||
description: Any (other) error
|
||||
|
@@ -169,4 +169,19 @@ Record:
|
||||
- video
|
||||
uuid:
|
||||
type: string
|
||||
RecordUri:
|
||||
type: string
|
||||
example:
|
||||
'/api/v3/records/1/48'
|
||||
RecordsUriArray:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/RecordUri'
|
||||
|
||||
ApiResponse_RecordsUriArray:
|
||||
type: object
|
||||
properties:
|
||||
meta:
|
||||
$ref: '#/ApiResponse_meta'
|
||||
response:
|
||||
$ref: '#/RecordsUriArray'
|
||||
|
@@ -12,8 +12,11 @@ namespace Alchemy\Phrasea\Databox\Record;
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Cache\Exception;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use databox;
|
||||
use Doctrine\DBAL\Connection;
|
||||
use Doctrine\DBAL\Query\QueryBuilder;
|
||||
use record_adapter;
|
||||
use set_selection;
|
||||
|
||||
class LegacyRecordRepository implements RecordRepository
|
||||
{
|
||||
@@ -23,7 +26,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
private $app;
|
||||
|
||||
/**
|
||||
* @var \databox
|
||||
* @var databox
|
||||
*/
|
||||
private $databox;
|
||||
|
||||
@@ -32,7 +35,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
*/
|
||||
private $site;
|
||||
|
||||
public function __construct(Application $app, \databox $databox, $site)
|
||||
public function __construct(Application $app, databox $databox, $site)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->databox = $databox;
|
||||
@@ -41,7 +44,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
public function find($record_id, $number = null)
|
||||
{
|
||||
$record = new \record_adapter($this->app, $this->databox->get_sbas_id(), $record_id, $number, false);
|
||||
$record = new record_adapter($this->app, $this->databox->get_sbas_id(), $record_id, $number, false);
|
||||
try {
|
||||
$data = $record->get_data_from_cache();
|
||||
} catch (Exception $exception) {
|
||||
@@ -67,7 +70,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
/**
|
||||
* @param string $sha256
|
||||
* @return \record_adapter[]
|
||||
* @return record_adapter[]
|
||||
*/
|
||||
public function findBySha256($sha256)
|
||||
{
|
||||
@@ -112,7 +115,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
/**
|
||||
* @param string $uuid
|
||||
* @return \record_adapter[]
|
||||
* @return record_adapter[]
|
||||
*/
|
||||
public function findByUuid($uuid)
|
||||
{
|
||||
@@ -130,7 +133,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
/**
|
||||
* @param string $uuid
|
||||
* @param array $excludedCollIds
|
||||
* @return \record_adapter[]
|
||||
* @return record_adapter[]
|
||||
*/
|
||||
public function findByUuidWithExcludedCollIds($uuid, $excludedCollIds = [])
|
||||
{
|
||||
@@ -190,85 +193,86 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
$connection = $this->databox->get_connection();
|
||||
|
||||
// the columns we want from the record
|
||||
//
|
||||
$selects = $this->getRecordSelects();
|
||||
array_unshift($selects, 'r.rid_parent AS story_id'); // add this to default
|
||||
|
||||
// sql parameters will be completed depending of (paginated / not paginated) and/or (user / no user)
|
||||
//
|
||||
$parmValues = [
|
||||
':storyIds' => $storyIds,
|
||||
];
|
||||
$parmTypes = [
|
||||
':storyIds' => Connection::PARAM_INT_ARRAY,
|
||||
];
|
||||
|
||||
// if there is a user, we must join collusr to filter results depending on coll/masks
|
||||
//
|
||||
$userFilter = "";
|
||||
if(!is_null($user)) {
|
||||
$userFilter = " INNER JOIN collusr c ON c.site = :site AND c.usr_id = :userId AND c.coll_id=r.coll_id AND ((r.status ^ c.mask_xor) & c.mask_and) = 0\n";
|
||||
$parmValues[':site'] = $this->site;
|
||||
$parmValues[':userId'] = $user instanceof User ? $user->getId() : (int)$user;
|
||||
}
|
||||
|
||||
if ($max_items) {
|
||||
array_unshift($selects, 'sr.rid_parent as story_id');
|
||||
|
||||
$subBuilder = $connection->createQueryBuilder();
|
||||
|
||||
$subBuilder
|
||||
->select('s.*,
|
||||
IF(@old_rid_parent != s.rid_parent, @cpt := 1, @cpt := @cpt+1) AS CPT')
|
||||
->addSelect("IF(@old_rid_parent != s.rid_parent, IF(@old_rid_parent:=s.rid_parent,'NEW PARENT',0), '----------') AS Y")
|
||||
->from('regroup', 's')
|
||||
->where('s.rid_parent IN (:storyIds)')
|
||||
->setParameter('storyIds', $storyIds, Connection::PARAM_INT_ARRAY)
|
||||
->orderBy('s.rid_parent, s.ord')
|
||||
//
|
||||
// we want paginated results AFTER applying all filters, we build a dynamic cptr
|
||||
// WARNING : due to bugs (?) in mysql optimizer, do NOT try to optimize this sql (e.g. removing a sub-q, or moving cpt to anothe sub-q)
|
||||
//
|
||||
$sql = "SELECT " . join(', ', $selects) . "\n"
|
||||
. "FROM (\n"
|
||||
. " SELECT t.*,\n"
|
||||
. " IF(@old_rid_parent != t.rid_parent, @cpt := 1, @cpt := @cpt+1) AS CPT,\n"
|
||||
. " IF(@old_rid_parent != t.rid_parent, IF(@old_rid_parent:=t.rid_parent,'NEW PARENT',0), '----------') AS Y\n"
|
||||
. " FROM (\n"
|
||||
. " SELECT g.ord, g.rid_parent, r.coll_id, r.record_id, r.credate, r.status, r.uuid, r.moddate, r.parent_record_id,r.type, r.originalname, r.sha256, r.mime\n"
|
||||
. " FROM regroup g\n"
|
||||
. " INNER JOIN record r ON r.record_id=g.rid_child\n"
|
||||
. $userFilter
|
||||
. " WHERE g.rid_parent IN ( :storyIds )\n"
|
||||
. " ORDER BY g.rid_parent, g.ord ASC\n"
|
||||
. " ) t\n"
|
||||
. ") r\n"
|
||||
. "WHERE CPT BETWEEN :offset AND :maxresult"
|
||||
;
|
||||
|
||||
$builder = $subBuilder->getConnection()->createQueryBuilder();
|
||||
|
||||
$builder->select($selects)
|
||||
->from(sprintf('( %s )', $subBuilder->getSQL()), 'sr')
|
||||
->innerJoin('sr', 'record', 'r', 'r.record_id = sr.rid_child')
|
||||
->where('sr.CPT BETWEEN :offset AND :maxresult')
|
||||
->andWhere('r.parent_record_id = 0')
|
||||
->setParameter('offset', $offset)
|
||||
->setParameter('maxresult', ($offset + $max_items -1))
|
||||
->orderBy('story_id, sr.CPT')
|
||||
;
|
||||
|
||||
if (null !== $user) {
|
||||
$this->addUserFilter($builder, $user);
|
||||
}
|
||||
$parmValues[':offset'] = $offset;
|
||||
$parmValues[':maxresult'] = ($offset + $max_items -1);
|
||||
|
||||
$connection->executeQuery('SET @cpt = 1');
|
||||
|
||||
$connection->executeQuery('SET @old_rid_parent = -1');
|
||||
|
||||
|
||||
$data = $connection->fetchAll(
|
||||
$builder->getSQL(),
|
||||
array_merge($subBuilder->getParameters(), $builder->getParameters()),
|
||||
array_merge($subBuilder->getParameterTypes(), $builder->getParameterTypes())
|
||||
);
|
||||
|
||||
} else {
|
||||
array_unshift($selects, 's.rid_parent as story_id');
|
||||
|
||||
$builder = $connection->createQueryBuilder();
|
||||
|
||||
$builder
|
||||
->select($selects)
|
||||
->from('regroup', 's')
|
||||
->innerJoin('s', 'record', 'r', 'r.record_id = s.rid_child')
|
||||
->where(
|
||||
's.rid_parent IN (:storyIds)',
|
||||
'r.parent_record_id = 0'
|
||||
)
|
||||
->orderBy('s.ord', 'ASC')
|
||||
->setParameter('storyIds', $storyIds, Connection::PARAM_INT_ARRAY)
|
||||
}
|
||||
else {
|
||||
//
|
||||
// se want all children, easy
|
||||
//
|
||||
$sql = "SELECT " . join(', ', $selects) . "\n"
|
||||
. "FROM (\n"
|
||||
. " SELECT g.ord, g.rid_parent, r.coll_id, r.record_id, r.credate, r.status, r.uuid, r.moddate, r.parent_record_id,r.type, r.originalname, r.sha256, r.mime\n"
|
||||
. " FROM regroup g\n"
|
||||
. " INNER JOIN record r ON r.record_id=g.rid_child\n"
|
||||
. $userFilter
|
||||
. " WHERE g.rid_parent IN ( :storyIds )\n"
|
||||
. " ORDER BY g.rid_parent, g.ord ASC\n"
|
||||
. ") r\n"
|
||||
;
|
||||
|
||||
if (null !== $user) {
|
||||
$this->addUserFilter($builder, $user);
|
||||
}
|
||||
|
||||
$data = $connection->fetchAll($builder->getSQL(), $builder->getParameters(), $builder->getParameterTypes());
|
||||
}
|
||||
$data = $connection->fetchAll($sql, $parmValues, $parmTypes);
|
||||
|
||||
$records = $this->mapRecordsFromResultSet($data);
|
||||
|
||||
$selections = array_map(
|
||||
function () {
|
||||
return new \set_selection($this->app);
|
||||
return new set_selection($this->app);
|
||||
},
|
||||
array_flip($storyIds)
|
||||
);
|
||||
|
||||
foreach ($records as $index => $child) {
|
||||
/** @var \set_selection $selection */
|
||||
/** @var set_selection $selection */
|
||||
$selection = $selections[$data[$index]['story_id']];
|
||||
|
||||
$child->setNumber($selection->get_count() + 1);
|
||||
@@ -312,12 +316,12 @@ class LegacyRecordRepository implements RecordRepository
|
||||
$stories = $this->mapRecordsFromResultSet($data);
|
||||
|
||||
$selections = array_map(function () {
|
||||
return new \set_selection($this->app);
|
||||
return new set_selection($this->app);
|
||||
}, array_flip($recordIds));
|
||||
|
||||
|
||||
foreach ($stories as $index => $child) {
|
||||
/** @var \set_selection $selection */
|
||||
/** @var set_selection $selection */
|
||||
$selection = $selections[$data[$index]['child_id']];
|
||||
|
||||
$selection->add_element($child);
|
||||
@@ -357,7 +361,7 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
/**
|
||||
* @param array $result
|
||||
* @return \record_adapter[]
|
||||
* @return record_adapter[]
|
||||
*/
|
||||
private function mapRecordsFromResultSet(array $result)
|
||||
{
|
||||
@@ -372,13 +376,13 @@ class LegacyRecordRepository implements RecordRepository
|
||||
|
||||
/**
|
||||
* @param array $row
|
||||
* @param \record_adapter|null $record
|
||||
* @return \record_adapter
|
||||
* @param record_adapter|null $record
|
||||
* @return record_adapter
|
||||
*/
|
||||
private function mapRecordFromResultRow(array $row, \record_adapter $record = null)
|
||||
private function mapRecordFromResultRow(array $row, record_adapter $record = null)
|
||||
{
|
||||
if (null === $record) {
|
||||
$record = new \record_adapter($this->app, $this->databox->get_sbas_id(), $row['record_id'], null, false);
|
||||
$record = new record_adapter($this->app, $this->databox->get_sbas_id(), $row['record_id'], null, false);
|
||||
}
|
||||
|
||||
$record->mapFromData($row);
|
||||
@@ -400,15 +404,13 @@ class LegacyRecordRepository implements RecordRepository
|
||||
->select('1')
|
||||
->from('collusr', 'c')
|
||||
->where(
|
||||
'c.usr_id = :userId',
|
||||
'c.site = :site',
|
||||
'c.usr_id = ' . ($user instanceof User ? $user->getId() : (int)$user),
|
||||
'c.site = \'' . $this->site . '\'',
|
||||
'((r.status ^ c.mask_xor) & c.mask_and) = 0',
|
||||
'c.coll_id = r.coll_id'
|
||||
);
|
||||
|
||||
$builder
|
||||
->andWhere(sprintf('EXISTS(%s)', $subBuilder->getSQL()))
|
||||
->setParameter('userId', $user instanceof User ? $user->getId() : (int)$user)
|
||||
->setParameter('site', $this->site);
|
||||
->andWhere(sprintf('EXISTS(%s)', $subBuilder->getSQL()));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user