mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-08 10:34:34 +00:00
586 lines
22 KiB
PHP
586 lines
22 KiB
PHP
<?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.
|
|
*/
|
|
|
|
namespace Alchemy\Phrasea\Controller\Admin;
|
|
|
|
use Alchemy\Phrasea\Controller\Controller;
|
|
use Alchemy\Phrasea\Core\Event\Record\Structure\RecordStructureEvents;
|
|
use Alchemy\Phrasea\Core\Event\Record\Structure\StatusBitEvent;
|
|
use Alchemy\Phrasea\Core\Event\Record\Structure\StatusBitUpdatedEvent;
|
|
use Alchemy\Phrasea\Databox\Subdef\MediaSubdefRepository;
|
|
use Alchemy\Phrasea\Exception\SessionNotFound;
|
|
use Alchemy\Phrasea\Model\Entities\ApiApplication;
|
|
use Alchemy\Phrasea\Model\Manipulator\ApiOauthTokenManipulator;
|
|
use Alchemy\Phrasea\Model\Repositories\ApiAccountRepository;
|
|
use Alchemy\Phrasea\Model\Repositories\ApiOauthTokenRepository;
|
|
use Alchemy\Phrasea\Model\Repositories\BasketElementRepository;
|
|
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
|
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
|
|
use Alchemy\Phrasea\Status\StatusStructureProviderInterface;
|
|
use GuzzleHttp\Client;
|
|
use Symfony\Component\HttpFoundation\Request;
|
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
|
|
class RootController extends Controller
|
|
{
|
|
public function indexAction(Request $request)
|
|
{
|
|
try {
|
|
\Session_Logger::updateClientInfos($this->app, 3);
|
|
} catch (SessionNotFound $e) {
|
|
return $this->app->redirectPath('logout');
|
|
}
|
|
|
|
$params = $this->getSectionParameters($request->query->get('section', false));
|
|
|
|
return $this->render('admin/index.html.twig', array_merge([
|
|
'module' => 'admin',
|
|
'events' => $this->app['events-manager'],
|
|
'module_name' => 'Admin',
|
|
'notice' => $request->query->get("notice")
|
|
], $params));
|
|
}
|
|
|
|
public function displayTreeAction(Request $request)
|
|
{
|
|
try {
|
|
\Session_Logger::updateClientInfos($this->app, 3);
|
|
} catch (SessionNotFound $e) {
|
|
return $this->app->redirectPath('logout');
|
|
}
|
|
|
|
$params = $this->getSectionParameters($request->query->get('position', false));
|
|
|
|
return $this->render('admin/tree.html.twig', $params);
|
|
}
|
|
|
|
public function testPathsAction(Request $request)
|
|
{
|
|
if (!$request->isXmlHttpRequest()) {
|
|
$this->app->abort(400);
|
|
}
|
|
if (!array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) {
|
|
$this->app->abort(400, $this->app->trans('Bad request format, only JSON is allowed'));
|
|
}
|
|
|
|
if (0 === count($tests = $request->query->get('tests', []))) {
|
|
$this->app->abort(400, $this->app->trans('Missing tests parameter'));
|
|
}
|
|
|
|
if (null === $path = $request->query->get('path')) {
|
|
$this->app->abort(400, $this->app->trans('Missing path parameter'));
|
|
}
|
|
|
|
$result = false;
|
|
foreach ($tests as $test) {
|
|
switch ($test) {
|
|
case 'writeable':
|
|
$result = is_writable($path);
|
|
break;
|
|
case 'readable':
|
|
default:
|
|
$result = is_readable($path);
|
|
}
|
|
}
|
|
|
|
return $this->app->json(['results' => $result]);
|
|
}
|
|
|
|
/**
|
|
* @param int $databox_id
|
|
* @return string
|
|
* @throws \Exception
|
|
*/
|
|
public function displayStatusBitAction($databox_id)
|
|
{
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
return $this->render('admin/statusbit.html.twig', [
|
|
'databox' => $this->findDataboxById($databox_id),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param Request $request
|
|
* @param int $databox_id
|
|
* @return string
|
|
* @throws \Exception
|
|
*/
|
|
public function displayDataboxStructureAction(Request $request, $databox_id)
|
|
{
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
$databox = $this->findDataboxById((int) $databox_id);
|
|
$structure = $databox->get_structure();
|
|
$errors = \databox::get_structure_errors($this->app['translator'], $structure);
|
|
|
|
if ($updateOk = !!$request->query->get('success', false)) {
|
|
$updateOk = true;
|
|
}
|
|
|
|
if (false !== $errorsStructure = $request->query->get('error', false)) {
|
|
$errorsStructure = true;
|
|
}
|
|
|
|
return $this->render('admin/structure.html.twig', [
|
|
'databox' => $databox,
|
|
'errors' => $errors,
|
|
'structure' => $structure,
|
|
'errorsStructure' => $errorsStructure,
|
|
'updateOk' => $updateOk
|
|
]);
|
|
}
|
|
|
|
public function submitDatabaseStructureAction(Request $request, $databox_id)
|
|
{
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
if (null === $structure = $request->request->get('structure')) {
|
|
$this->app->abort(400, $this->app->trans('Missing "structure" parameter'));
|
|
}
|
|
|
|
$errors = \databox::get_structure_errors($this->app['translator'], $structure);
|
|
|
|
$domst = new \DOMDocument('1.0', 'UTF-8');
|
|
$domst->preserveWhiteSpace = false;
|
|
$domst->formatOutput = true;
|
|
|
|
if (count($errors) == 0 && $domst->loadXML($structure)) {
|
|
$databox = $this->findDataboxById($databox_id);
|
|
$databox->saveStructure($domst);
|
|
|
|
return $this->app->redirectPath('database_display_stucture', ['databox_id' => $databox_id, 'success' => 1]);
|
|
}
|
|
|
|
return $this->app->redirectPath('database_display_stucture', [
|
|
'databox_id' => $databox_id,
|
|
'success' => 0,
|
|
'error' => 'struct',
|
|
]);
|
|
}
|
|
|
|
public function displayDatabaseStatusBitFormAction(Request $request, $databox_id, $bit)
|
|
{
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
$databox = $this->findDataboxById($databox_id);
|
|
|
|
$statusStructure = $databox->getStatusStructure();
|
|
|
|
switch ($errorMsg = $request->query->get('error')) {
|
|
case 'rights':
|
|
$errorMsg = $this->app->trans('You do not enough rights to update status');
|
|
break;
|
|
case 'too-big':
|
|
$errorMsg = $this->app->trans('File is too big : 64k max');
|
|
break;
|
|
case 'upload-error':
|
|
$errorMsg = $this->app->trans('Status icon upload failed : upload error');
|
|
break;
|
|
case 'wright-error':
|
|
$errorMsg = $this->app->trans('Status icon upload failed : can not write on disk');
|
|
break;
|
|
case 'unknow-error':
|
|
$errorMsg = $this->app->trans('Something wrong happend');
|
|
break;
|
|
}
|
|
|
|
if ($statusStructure->hasStatus($bit)) {
|
|
$status = $statusStructure->getStatus($bit);
|
|
} else {
|
|
$status = [
|
|
"labeloff" => '',
|
|
"labelon" => '',
|
|
"img_off" => '',
|
|
"img_on" => '',
|
|
"path_off" => '',
|
|
"path_on" => '',
|
|
"searchable" => false,
|
|
"printable" => false,
|
|
];
|
|
|
|
foreach ($this->app['locales.available'] as $code => $language) {
|
|
$status['labels_on'][$code] = null;
|
|
$status['labels_off'][$code] = null;
|
|
}
|
|
}
|
|
|
|
return $this->render('admin/statusbit/edit.html.twig', [
|
|
'status' => $status,
|
|
'errorMsg' => $errorMsg
|
|
]);
|
|
}
|
|
|
|
public function deleteStatusBitAction(Request $request, $databox_id, $bit)
|
|
{
|
|
if (!$request->isXmlHttpRequest() || !array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) {
|
|
$this->app->abort(400, $this->app->trans('Bad request format, only JSON is allowed'));
|
|
}
|
|
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
$databox = $this->findDataboxById($databox_id);
|
|
|
|
$error = false;
|
|
|
|
try {
|
|
$this->app['status.provider']->deleteStatus($databox->getStatusStructure(), $bit);
|
|
} catch (\Exception $e) {
|
|
$error = true;
|
|
}
|
|
|
|
$this->dispatchEvent(RecordStructureEvents::STATUS_BIT_DELETED, new StatusBitUpdatedEvent($databox, $bit, []));
|
|
|
|
return $this->app->json(['success' => !$error]);
|
|
}
|
|
|
|
public function submitStatusBitAction(Request $request, $databox_id, $bit) {
|
|
if (!$this->getAclForUser()->has_right_on_sbas($databox_id, \ACL::BAS_MODIFY_STRUCT)) {
|
|
$this->app->abort(403);
|
|
}
|
|
|
|
$properties = [
|
|
'searchable' => $request->request->get('searchable') ? '1' : '0',
|
|
'printable' => $request->request->get('printable') ? '1' : '0',
|
|
'name' => $request->request->get('name', ''),
|
|
'labelon' => $request->request->get('label_on', ''),
|
|
'labeloff' => $request->request->get('label_off', ''),
|
|
'labels_on' => $request->request->get('labels_on', []),
|
|
'labels_off' => $request->request->get('labels_off', []),
|
|
];
|
|
|
|
$databox = $this->findDataboxById($databox_id);
|
|
|
|
/** @var StatusStructureProviderInterface $statusProvider */
|
|
$statusProvider = $this->app['status.provider'];
|
|
$statusProvider->updateStatus($databox->getStatusStructure(), $bit, $properties);
|
|
|
|
if (null !== $request->request->get('delete_icon_off')) {
|
|
\databox_status::deleteIcon($this->app, $databox_id, $bit, 'off');
|
|
}
|
|
|
|
if (null !== $file = $request->files->get('image_off')) {
|
|
try {
|
|
\databox_status::updateIcon($this->app, $databox_id, $bit, 'off', $file);
|
|
} catch (AccessDeniedHttpException $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'rights',
|
|
]);
|
|
} catch (\Exception_InvalidArgument $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'unknow-error',
|
|
]);
|
|
} catch (\Exception_Upload_FileTooBig $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'too-big',
|
|
]);
|
|
} catch (\Exception_Upload_Error $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'upload-error',
|
|
]);
|
|
} catch (\Exception_Upload_CannotWriteFile $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'wright-error',
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'unknow-error',
|
|
]);
|
|
}
|
|
}
|
|
|
|
if (null !== $request->request->get('delete_icon_on')) {
|
|
\databox_status::deleteIcon($this->app, $databox_id, $bit, 'on');
|
|
}
|
|
|
|
if (null !== $file = $request->files->get('image_on')) {
|
|
try {
|
|
\databox_status::updateIcon($this->app, $databox_id, $bit, 'on', $file);
|
|
} catch (AccessDeniedHttpException $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'rights',
|
|
]);
|
|
} catch (\Exception_InvalidArgument $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'unknow-error',
|
|
]);
|
|
} catch (\Exception_Upload_FileTooBig $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'too-big',
|
|
]);
|
|
} catch (\Exception_Upload_Error $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'upload-error',
|
|
]);
|
|
} catch (\Exception_Upload_CannotWriteFile $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'wright-error',
|
|
]);
|
|
} catch (\Exception $e) {
|
|
return $this->app->redirectPath('database_display_statusbit_form', [
|
|
'databox_id' => $databox_id,
|
|
'bit' => $bit,
|
|
'error' => 'unknow-error',
|
|
]);
|
|
}
|
|
}
|
|
|
|
$this->dispatchEvent(RecordStructureEvents::STATUS_BIT_UPDATED, new StatusBitUpdatedEvent($databox, $bit, []));
|
|
|
|
return $this->app->redirectPath('database_display_statusbit', ['databox_id' => $databox_id, 'success' => 1]);
|
|
}
|
|
|
|
public function displayInspector(Request $request)
|
|
{
|
|
$databoxIds = array_map(function (\databox $databox) {
|
|
return $databox->get_sbas_id();
|
|
},
|
|
$this->app->getApplicationBox()->get_databoxes()
|
|
);
|
|
|
|
return $this->render('admin/inspector/record-index.html.twig', ['databoxIds' => $databoxIds]);
|
|
}
|
|
|
|
public function getESRecord(Request $request)
|
|
{
|
|
$client = new Client();
|
|
|
|
/** @var ElasticsearchOptions $options */
|
|
$options = $this->app['elasticsearch.options'];
|
|
|
|
$uri = $options->getHost() . ":" . $options->getPort() . "/" . urlencode($options->getIndexName()) . "/record/" . urlencode($request->query->get('databoxId')) . "_" . urlencode($request->query->get('recordId'));
|
|
|
|
$ret = [
|
|
'uri' => $uri
|
|
];
|
|
$js = $client->get($uri, ['http_errors' => false])->getBody()->getContents();
|
|
$arr = json_decode($js,true);
|
|
if(is_null($arr)) {
|
|
$ret['result'] = "*** error decoding json ***";
|
|
$ret['raw'] = $js;
|
|
}
|
|
else {
|
|
$ret['result'] = $arr;
|
|
}
|
|
|
|
return json_encode($ret, JSON_PRETTY_PRINT, 512);
|
|
}
|
|
|
|
public function getRecordDetails(Request $request)
|
|
{
|
|
$recordId = $request->query->get('recordId');
|
|
$databoxId = $request->query->get('databoxId');
|
|
$detailsType = $request->query->get('type');
|
|
|
|
if ($detailsType == 'subdef') {
|
|
$databox = $this->getApplicationBox()->get_databox($databoxId);
|
|
|
|
try {
|
|
$record = $databox->get_record($recordId);
|
|
|
|
$databoxSubdefs = $databox->get_subdef_structure()->getSubdefGroup($record->getType());
|
|
|
|
$availableSubdefs = [];
|
|
|
|
foreach ($databoxSubdefs as $sub) {
|
|
$availableSubdefs[$sub->get_name()] = $sub->get_name();
|
|
}
|
|
|
|
/** @var MediaSubdefRepository $mediaSubdefRepository */
|
|
$mediaSubdefRepository = $this->app['provider.repo.media_subdef']->getRepositoryForDatabox($request->query->get('databoxId'));
|
|
|
|
$mediaSubdefs = $mediaSubdefRepository->findByRecordIdsAndNames([$request->query->get('recordId')]);
|
|
|
|
$notGeneratedSubdefs = $availableSubdefs;
|
|
|
|
foreach ($mediaSubdefs as $mediaSubdef) {
|
|
if (in_array($mediaSubdef->get_name(), $notGeneratedSubdefs)) {
|
|
unset($notGeneratedSubdefs[$mediaSubdef->get_name()]);
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
$mediaSubdefs = [];
|
|
$notGeneratedSubdefs = [];
|
|
}
|
|
|
|
return $this->render('admin/inspector/record-detail.html.twig', [
|
|
'mediaSubdefs' => $mediaSubdefs,
|
|
'notGeneratedSubdefs' => $notGeneratedSubdefs,
|
|
'type' => 'subdef'
|
|
]);
|
|
} elseif ($detailsType == 'basket') {
|
|
/** @var BasketElementRepository $basketElementRepository */
|
|
$basketElementRepository = $this->app['repo.basket-elements'];
|
|
$basketElements = $basketElementRepository->findBy([
|
|
'sbas_id' => $databoxId,
|
|
'record_id' => $recordId
|
|
], ['basket' => 'asc']
|
|
);
|
|
|
|
return $this->render('admin/inspector/record-detail.html.twig', [
|
|
'basketElements' => $basketElements,
|
|
'type' => 'basket'
|
|
]);
|
|
} elseif ($detailsType == 'story') {
|
|
$databox = $this->getApplicationBox()->get_databox($databoxId);
|
|
$recordParents = $databox->getRecordRepository()->findParents([$recordId]);
|
|
$recordParents = reset($recordParents);
|
|
|
|
return $this->render('admin/inspector/record-detail.html.twig', [
|
|
'recordParents' => $recordParents,
|
|
'type' => 'story'
|
|
]);
|
|
} elseif ($detailsType == 'log') {
|
|
$databox = $this->getApplicationBox()->get_databox($databoxId);
|
|
$sql = "SELECT d.* , l.usrid
|
|
FROM log_docs d
|
|
LEFT JOIN log l ON l.id = d.log_id
|
|
WHERE d.record_id =" . $recordId . " ORDER BY date LIMIT 1000";
|
|
|
|
$stmt = $databox->get_connection()->prepare($sql);
|
|
$stmt->execute();
|
|
$logDocs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
|
|
$stmt->closeCursor();
|
|
|
|
return $this->render('admin/inspector/record-detail.html.twig', [
|
|
'logDocs' => $logDocs,
|
|
'type' => 'log'
|
|
]);
|
|
}
|
|
}
|
|
|
|
public function renewAccessToken(Request $request, ApiApplication $application)
|
|
{
|
|
/** @var UserRepository $userRepository */
|
|
$userRepository = $this->app['repo.users'];
|
|
/** @var ApiAccountRepository $apiAccountRepository */
|
|
$apiAccountRepository = $this->app['repo.api-accounts'];
|
|
$user = $userRepository->find($request->query->get('user_id'));
|
|
$account = $apiAccountRepository->findByUserAndApplication($user, $application);
|
|
|
|
if (null !== $devToken = $this->getApiOAuthTokenRepository()->findDeveloperToken($account)) {
|
|
$this->getApiOAuthTokenManipulator()->renew($devToken);
|
|
} else {
|
|
// dev tokens do not expires
|
|
$this->getApiOAuthTokenManipulator()->create($account);
|
|
}
|
|
|
|
return $this->app->json(['success' => true]);
|
|
}
|
|
|
|
/**
|
|
* @return ApiOauthTokenRepository
|
|
*/
|
|
private function getApiOAuthTokenRepository()
|
|
{
|
|
return $this->app['repo.api-oauth-tokens'];
|
|
}
|
|
|
|
/**
|
|
* @return ApiOauthTokenManipulator
|
|
*/
|
|
private function getApiOAuthTokenManipulator()
|
|
{
|
|
return $this->app['manipulator.api-oauth-token'];
|
|
}
|
|
|
|
private function dispatchEvent($eventName, StatusBitEvent $event = null)
|
|
{
|
|
$this->app['dispatcher']->dispatch($eventName, $event);
|
|
}
|
|
|
|
/**
|
|
* @param string $section
|
|
* @return array
|
|
*/
|
|
private function getSectionParameters($section)
|
|
{
|
|
$available = [
|
|
'connected',
|
|
'registrations',
|
|
'taskmanager',
|
|
'base',
|
|
'bases',
|
|
'collection',
|
|
'user',
|
|
'users',
|
|
'workermanager'
|
|
];
|
|
|
|
$feature = 'connected';
|
|
$featured = false;
|
|
$position = explode(':', $section);
|
|
if (count($position) > 0) {
|
|
if (in_array($position[0], $available)) {
|
|
$feature = $position[0];
|
|
|
|
if (isset($position[1])) {
|
|
$featured = $position[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
$databoxes = $off_databoxes = [];
|
|
$acl = $this->getAclForUser();
|
|
foreach ($this->getApplicationBox()->get_databoxes() as $databox) {
|
|
try {
|
|
if (!$acl->has_access_to_sbas($databox->get_sbas_id())) {
|
|
continue;
|
|
}
|
|
$databox->get_connection();
|
|
} catch (\Exception $e) {
|
|
$off_databoxes[] = $databox;
|
|
continue;
|
|
}
|
|
|
|
$databoxes[] = $databox;
|
|
}
|
|
|
|
return [
|
|
'feature' => $feature,
|
|
'featured' => $featured,
|
|
'databoxes' => $databoxes,
|
|
'off_databoxes' => $off_databoxes,
|
|
];
|
|
}
|
|
}
|