Merge branch 'master' into PHRAS-2680-webhook-privacy-and-security

This commit is contained in:
Nicolas Maillat
2019-09-30 15:49:33 +02:00
committed by GitHub
16 changed files with 217 additions and 141 deletions

14
composer.lock generated
View File

@@ -383,16 +383,16 @@
}, },
{ {
"name": "alchemy/phpexiftool", "name": "alchemy/phpexiftool",
"version": "0.7.0", "version": "0.7.2",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/PHPExiftool.git", "url": "https://github.com/alchemy-fr/PHPExiftool.git",
"reference": "7372ca4e43473328bf06bca810558fbad7bb2f95" "reference": "ba1cb51eceb6562d7996023478977a8739de188b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/PHPExiftool/zipball/7372ca4e43473328bf06bca810558fbad7bb2f95", "url": "https://api.github.com/repos/alchemy-fr/PHPExiftool/zipball/ba1cb51eceb6562d7996023478977a8739de188b",
"reference": "7372ca4e43473328bf06bca810558fbad7bb2f95", "reference": "ba1cb51eceb6562d7996023478977a8739de188b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -443,8 +443,8 @@
}, },
{ {
"name": "Benoit Burnichon", "name": "Benoit Burnichon",
"role": "Lead Developer", "email": "bburnichon@alchemy.fr",
"email": "bburnichon@alchemy.fr" "role": "Lead Developer"
} }
], ],
"description": "Exiftool driver for PHP", "description": "Exiftool driver for PHP",
@@ -452,7 +452,7 @@
"exiftool", "exiftool",
"metadata" "metadata"
], ],
"time": "2017-05-18T19:04:04+00:00" "time": "2019-02-13T13:06:43+00:00"
}, },
{ {
"name": "alchemy/queue-bundle", "name": "alchemy/queue-bundle",

View File

@@ -114,6 +114,7 @@ class MoveCollectionController extends Controller
$trashCollectionsBySbasId = []; $trashCollectionsBySbasId = [];
foreach ($records as $record) { foreach ($records as $record) {
$oldCollectionId = $record->getCollection()->get_coll_id();
$record->move_to_collection($collection, $this->getApplicationBox()); $record->move_to_collection($collection, $this->getApplicationBox());
if ($request->request->get("chg_coll_son") == "1") { if ($request->request->get("chg_coll_son") == "1") {
@@ -130,7 +131,7 @@ class MoveCollectionController extends Controller
$trashCollectionsBySbasId[$sbasId] = $record->getDatabox()->getTrashCollection(); $trashCollectionsBySbasId[$sbasId] = $record->getDatabox()->getTrashCollection();
} }
if ($trashCollectionsBySbasId[$sbasId] !== null) { if ($trashCollectionsBySbasId[$sbasId] !== null) {
if ($record->getCollection()->get_coll_id() == $trashCollectionsBySbasId[$sbasId]->get_coll_id() && $collection->get_coll_id() !== $trashCollectionsBySbasId[$sbasId]->get_coll_id()) { if ($oldCollectionId == $trashCollectionsBySbasId[$sbasId]->get_coll_id() && $collection->get_coll_id() !== $trashCollectionsBySbasId[$sbasId]->get_coll_id()) {
// record is already in trash so active it // record is already in trash so active it
foreach ($record->get_subdefs() as $subdef) { foreach ($record->get_subdefs() as $subdef) {
if (($pl = $subdef->get_permalink())) { if (($pl = $subdef->get_permalink())) {

View File

@@ -214,7 +214,7 @@ class QueryController extends Controller
if (min($d2top, $d2bottom) < 4) { if (min($d2top, $d2bottom) < 4) {
if ($d2bottom < 4) { if ($d2bottom < 4) {
if($page != 1){ if($page != 1){
$string .= "<a id='PREV_PAGE' class='btn btn-primary btn-mini'></a>"; $string .= "<a id='PREV_PAGE' class='btn btn-primary btn-mini icon-baseline-chevron_left-24px'></a>";
} }
for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) { for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) {
if ($i == $page) if ($i == $page)
@@ -223,13 +223,13 @@ class QueryController extends Controller
$string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>'; $string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>';
} }
if ($npages > 4) if ($npages > 4)
$string .= "<a id='NEXT_PAGE' class='btn btn-primary btn-mini'></a>"; $string .= "<a id='NEXT_PAGE' class='btn btn-primary btn-mini icon icon-baseline-chevron_right-24px'></a>";
$string .= '<a href="#" class="btn btn-primary btn-mini search-navigate-action" data-page="' . $npages . '" id="last"></a>'; $string .= '<a href="#" class="btn btn-primary btn-mini search-navigate-action icon icon-double-arrows" data-page="' . $npages . '" id="last"></a>';
} else { } else {
$start = $npages - 4; $start = $npages - 4;
if (($start) > 0){ if (($start) > 0){
$string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="1" id="first"></a>'; $string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="1" id="first"><span class="icon icon-double-arrows icon-inverse"></span></a>';
$string .= '<a id="PREV_PAGE" class="btn btn-primary btn-mini"></a>'; $string .= '<a id="PREV_PAGE" class="btn btn-primary btn-mini icon icon-baseline-chevron_left-24px"></a>';
}else }else
$start = 1; $start = 1;
for ($i = ($start); $i <= $npages; $i++) { for ($i = ($start); $i <= $npages; $i++) {
@@ -239,11 +239,11 @@ class QueryController extends Controller
$string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>'; $string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>';
} }
if($page < $npages){ if($page < $npages){
$string .= "<a id='NEXT_PAGE' class='btn btn-primary btn-mini'></a>"; $string .= "<a id='NEXT_PAGE' class='btn btn-primary btn-mini icon icon-baseline-chevron_right-24px'></a>";
} }
} }
} else { } else {
$string .= '<a class="btn btn-primary btn-mini btn-mini search-navigate-action" data-page="1" id="first"></a>'; $string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="1" id="first"><span class="icon icon-double-arrows icon-inverse"></span></a>';
for ($i = ($page - 2); $i <= ($page + 2); $i++) { for ($i = ($page - 2); $i <= ($page + 2); $i++) {
if ($i == $page) if ($i == $page)
@@ -252,10 +252,10 @@ class QueryController extends Controller
$string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>'; $string .= '<a class="btn btn-primary btn-mini search-navigate-action" data-page="'.$i.'">' . $i . '</a>';
} }
$string .= '<a href="#" class="btn btn-primary btn-mini search-navigate-action" data-page="' . $npages . '" id="last"></a>'; $string .= '<a href="#" class="btn btn-primary btn-mini search-navigate-action icon icon-double-arrows" data-page="' . $npages . '" id="last"></a>';
} }
} }
$string .= '<div style="display:none;"><div id="NEXT_PAGE"></div><div id="PREV_PAGE"></div></div>'; $string .= '<div style="display:none;"><div id="NEXT_PAGE" class="icon icon-baseline-chevron_right-24px"></div><div id="PREV_PAGE" class="icon icon-baseline-chevron_left-24px"></div></div>';
$explain = $this->render( $explain = $this->render(
"prod/results/infos.html.twig", "prod/results/infos.html.twig",
@@ -470,7 +470,6 @@ class QueryController extends Controller
$json['results'] = $this->render($template, ['results'=> $result]); $json['results'] = $this->render($template, ['results'=> $result]);
} }
return $this->app->json($json); return $this->app->json($json);
} }

View File

@@ -15,12 +15,9 @@ use Alchemy\Phrasea\Core\Configuration\DisplaySettingService;
use Alchemy\Phrasea\Exception\SessionNotFound; use Alchemy\Phrasea\Exception\SessionNotFound;
use Alchemy\Phrasea\Feed\Aggregate; use Alchemy\Phrasea\Feed\Aggregate;
use Alchemy\Phrasea\Helper; use Alchemy\Phrasea\Helper;
use Alchemy\Phrasea\Model\Entities\UserSetting; use Alchemy\Phrasea\Helper\WorkZone as WorkzoneHelper;
use Alchemy\Phrasea\Model\Repositories\FeedRepository; use Alchemy\Phrasea\Model\Repositories\FeedRepository;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
// use Alchemy\Phrasea\Plugin\ActionBarPluginInterface;
class RootController extends Controller class RootController extends Controller
@@ -43,12 +40,11 @@ class RootController extends Controller
public function indexAction(Request $request) { public function indexAction(Request $request) {
try { try {
\Session_Logger::updateClientInfos($this->app, 1); \Session_Logger::updateClientInfos($this->app, 1);
} catch (SessionNotFound $e) { }
catch (SessionNotFound $e) {
return $this->app->redirectPath('logout'); return $this->app->redirectPath('logout');
} }
$css = [];
$user = $this->getAuthenticatedUser(); $user = $this->getAuthenticatedUser();
$cssfile = $this->getSettings()->getUserSetting($user, 'css'); $cssfile = $this->getSettings()->getUserSetting($user, 'css');
@@ -110,7 +106,7 @@ class RootController extends Controller
return $this->render('prod/index.html.twig', [ return $this->render('prod/index.html.twig', [
'module_name' => 'Production', 'module_name' => 'Production',
'WorkZone' => new Helper\WorkZone($this->app, $request), 'WorkZone' => new WorkzoneHelper($this->app, $request),
'module_prod' => $helper, 'module_prod' => $helper,
'search_datas' => $helper->get_search_datas(), 'search_datas' => $helper->get_search_datas(),
'cssfile' => $cssfile, 'cssfile' => $cssfile,
@@ -123,7 +119,7 @@ class RootController extends Controller
'feeds' => $feeds, 'feeds' => $feeds,
'aggregate' => $aggregate, 'aggregate' => $aggregate,
'GV_google_api' => $conf->get(['registry', 'webservices', 'google-charts-enabled']), 'GV_google_api' => $conf->get(['registry', 'webservices', 'google-charts-enabled']),
'geocodingProviders' => $conf->get(['geocoding-providers']), 'geocodingProviders' => $conf->get(['geocoding-providers']),
'search_status' => \databox_status::getSearchStatus($this->app), 'search_status' => \databox_status::getSearchStatus($this->app),
'thesau_js_list' => $thjslist, 'thesau_js_list' => $thjslist,
'thesau_json_sbas' => json_encode($sbas), 'thesau_json_sbas' => json_encode($sbas),

View File

@@ -367,15 +367,17 @@ class UploadController extends Controller
$postMaxSize = PHP_INT_MAX; $postMaxSize = PHP_INT_MAX;
} }
$r = 0;
switch (strtolower(substr($postMaxSize, -1))) { switch (strtolower(substr($postMaxSize, -1))) {
/** @noinspection PhpMissingBreakStatementInspection */ /** @noinspection PhpMissingBreakStatementInspection */
case 'g': case 'g':
$postMaxSize *= 1024; $r += 10;
/** @noinspection PhpMissingBreakStatementInspection */ /** @noinspection PhpMissingBreakStatementInspection */
case 'm': case 'm':
$postMaxSize *= 1024; $r += 10;
case 'k': case 'k':
$postMaxSize *= 1024; $r += 10;
$postMaxSize = ((int)($postMaxSize))<<$r;
} }
return min(UploadedFile::getMaxFilesize(), (int) $postMaxSize); return min(UploadedFile::getMaxFilesize(), (int) $postMaxSize);

View File

@@ -524,27 +524,36 @@ class AccountController extends Controller
$list = array_keys($this->app['repo.collections-registry']->getBaseIdMap()); $list = array_keys($this->app['repo.collections-registry']->getBaseIdMap());
$this->app->getAclForUser($user)->revoke_access_from_bases($list); try {
$this->app->getAclForUser($user)->revoke_access_from_bases($list);
}
catch (\Exception $e) {
// one or more access could not be revoked ? the user will not be phantom
$this->app->addFlash('error', $this->app->trans('phraseanet::error: failed to revoke some user access'));
}
if ($this->app->getAclForUser($user)->is_phantom()) { if ($this->app->getAclForUser($user)->is_phantom()) {
// send confirmation email: the account has been deleted // send confirmation email: the account has been deleted
try { try {
$receiver = Receiver::fromUser($user); $receiver = Receiver::fromUser($user);
} catch (InvalidArgumentException $e) { $mail = MailSuccessAccountDelete::create($this->app, $receiver);
}
catch (InvalidArgumentException $e) {
$this->app->addFlash('error', $this->app->trans('phraseanet::erreur: echec du serveur de mail')); $this->app->addFlash('error', $this->app->trans('phraseanet::erreur: echec du serveur de mail'));
$mail = null;
} }
$mail = MailSuccessAccountDelete::create($this->app, $receiver); $mail = MailSuccessAccountDelete::create($this->app, $receiver);
$this->app['manipulator.user']->delete($user, [$user->getId() => $oldGrantedBaseIds]); $this->app['manipulator.user']->delete($user, [$user->getId() => $oldGrantedBaseIds]);
if($mail) {
$this->deliver($mail);
}
$this->deliver($mail); $this->getAuthenticator()->closeAccount();
$this->app->addFlash('info', $this->app->trans('phraseanet::account The account has been deleted'));
} }
$this->getAuthenticator()->closeAccount();
$this->app->addFlash('info', $this->app->trans('phraseanet::account The account has been deleted'));
} }
/** /**

View File

@@ -94,10 +94,9 @@ class SessionController extends Controller
} }
/** /**
* Check session state * @param Request $request
*
* @param Request $request
* @return JsonResponse * @return JsonResponse
* @throws \Exception in case "new \DateTime()" fails ?
*/ */
public function updateSession(Request $request) public function updateSession(Request $request)
{ {
@@ -120,7 +119,8 @@ class SessionController extends Controller
return $this->app->json($ret); return $this->app->json($ret);
} }
} else { }
else {
$ret['status'] = 'disconnected'; $ret['status'] = 'disconnected';
return $this->app->json($ret); return $this->app->json($ret);
@@ -128,7 +128,8 @@ class SessionController extends Controller
try { try {
$this->getApplicationBox()->get_connection(); $this->getApplicationBox()->get_connection();
} catch (\Exception $e) { }
catch (\Exception $e) {
return $this->app->json($ret); return $this->app->json($ret);
} }
@@ -148,8 +149,9 @@ class SessionController extends Controller
$module->setModuleId($moduleId); $module->setModuleId($moduleId);
$module->setSession($session); $module->setSession($session);
$manager->persist($module); $manager->persist($module);
} else { }
$manager->persist($session->getModuleById($moduleId)->setUpdated(new \DateTime())); else {
$manager->persist($session->getModuleById($moduleId)->setUpdated($now));
} }
$manager->persist($session); $manager->persist($session);
@@ -231,7 +233,10 @@ class SessionController extends Controller
*/ */
private function getBasketRepository() private function getBasketRepository()
{ {
return $this->getEntityManager()->getRepository('Phraseanet:Basket'); /** @var BasketRepository $ret */
$ret = $this->getEntityManager()->getRepository('Phraseanet:Basket');
return $ret;
} }
/** /**

View File

@@ -11,28 +11,29 @@
namespace Alchemy\Phrasea\Helper; namespace Alchemy\Phrasea\Helper;
use Doctrine\Common\Collections\ArrayCollection;
use Alchemy\Phrasea\Model\Entities\Basket as BasketEntity; use Alchemy\Phrasea\Model\Entities\Basket as BasketEntity;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Alchemy\Phrasea\Model\Repositories\StoryWZRepository;
use Doctrine\Common\Collections\ArrayCollection;
class WorkZone extends Helper class WorkZone extends Helper
{ {
const BASKETS = 'baskets'; const BASKETS = 'baskets';
const STORIES = 'stories'; const STORIES = 'stories';
const VALIDATIONS = 'validations'; const VALIDATIONS = 'validations';
/** /**
*
* Returns an ArrayCollection containing three keys : * Returns an ArrayCollection containing three keys :
* - self::BASKETS : an ArrayCollection of the actives baskets * - self::BASKETS : an ArrayCollection of the actives baskets (Non Archived)
* (Non Archived)
* - self::STORIES : an ArrayCollection of working stories * - self::STORIES : an ArrayCollection of working stories
* - self::VALIDATIONS : the validation people are waiting from me * - self::VALIDATIONS : the validation people are waiting from me
* *
* @return \Doctrine\Common\Collections\ArrayCollection * @param null|string $sort "date"|"name"
* @return ArrayCollection
*/ */
public function getContent($sort) public function getContent($sort = null)
{ {
/* @var $repo_baskets Alchemy\Phrasea\Model\Repositories\BasketRepository */ /* @var $repo_baskets BasketRepository */
$repo_baskets = $this->app['repo.baskets']; $repo_baskets = $this->app['repo.baskets'];
$sort = in_array($sort, ['date', 'name']) ? $sort : 'name'; $sort = in_array($sort, ['date', 'name']) ? $sort : 'name';
@@ -42,7 +43,7 @@ class WorkZone extends Helper
$baskets = $repo_baskets->findActiveByUser($this->app->getAuthenticatedUser(), $sort); $baskets = $repo_baskets->findActiveByUser($this->app->getAuthenticatedUser(), $sort);
// force creation of a default basket // force creation of a default basket
if (0 === count($baskets)) { if (count($baskets) === 0) {
$basket = new BasketEntity(); $basket = new BasketEntity();
$basket->setName($this->app->trans('Default basket')); $basket->setName($this->app->trans('Default basket'));
@@ -55,7 +56,7 @@ class WorkZone extends Helper
$validations = $repo_baskets->findActiveValidationByUser($this->app->getAuthenticatedUser(), $sort); $validations = $repo_baskets->findActiveValidationByUser($this->app->getAuthenticatedUser(), $sort);
/* @var $repo_stories Alchemy\Phrasea\Model\Repositories\StoryWZRepository */ /* @var $repo_stories StoryWZRepository */
$repo_stories = $this->app['repo.story-wz']; $repo_stories = $this->app['repo.story-wz'];
$stories = $repo_stories->findByUser($this->app, $this->app->getAuthenticatedUser(), $sort); $stories = $repo_stories->findByUser($this->app, $this->app->getAuthenticatedUser(), $sort);

View File

@@ -61,7 +61,7 @@ class SubdefGenerator
public function generateSubdefs(\record_adapter $record, array $wanted_subdefs = null) public function generateSubdefs(\record_adapter $record, array $wanted_subdefs = null)
{ {
if ($record->get_hd_file() !== null) { if ($record->get_hd_file() !== null && $record->get_hd_file()->getMimeType() == "application/x-indesign") {
$mediaSource = $this->mediavorus->guess($record->get_hd_file()->getPathname()); $mediaSource = $this->mediavorus->guess($record->get_hd_file()->getPathname());
$metadatas = $mediaSource->getMetadatas(); $metadatas = $mediaSource->getMetadatas();
@@ -69,15 +69,27 @@ class SubdefGenerator
if(!isset($this->tmpFilesystem)){ if(!isset($this->tmpFilesystem)){
$this->tmpFilesystem = Manager::create(); $this->tmpFilesystem = Manager::create();
} }
$tmpDir = $this->tmpFilesystem->createTemporaryDirectory(); $tmpDir = $this->tmpFilesystem->createTemporaryDirectory(0777, 500);
try { $files = $this->app['exiftool.preview-extractor']->extract($record->get_hd_file()->getPathname(), $tmpDir);
$this->app['filesystem']->dumpFile($tmpDir.'/file.jpg', $metadatas->get('XMP-xmp:PageImage')->getValue()->asString());
$this->tmpFilePath = $tmpDir.'/file.jpg'; $selected = null;
} catch (\Exception $e) { $size = null;
$this->logger->error(sprintf('Unable to write temporary file : %s', $e->getMessage()));
foreach ($files as $file) {
if ($file->isDir() || $file->isDot()) {
continue;
}
if (is_null($selected) || $file->getSize() > $size) {
$selected = $file->getPathname();
$size = $file->getSize();
}
} }
if ($selected) {
$this->tmpFilePath = $selected;
}
} }
} }

View File

@@ -54,21 +54,24 @@ class BasketRepository extends EntityRepository
/** /**
* Returns all basket for a given user that are not marked as archived * Returns all basket for a given user that are not marked as archived
* *
* @param User $user * @param User $user
* @param null|string $sort
* @return Basket[] * @return Basket[]
*/ */
public function findActiveByUser(User $user, $sort = null) public function findActiveByUser(User $user, $sort = null)
{ {
$dql = 'SELECT b // checked : 4 usages, "b.elements" is useless
FROM Phraseanet:Basket b $dql = "SELECT b\n"
LEFT JOIN b.elements e . " FROM Phraseanet:Basket b\n"
WHERE b.user = :usr_id // . " LEFT JOIN b.elements e\n" //
AND b.archived = false'; . " WHERE b.user = :usr_id\n"
. " AND b.archived = false";
if ($sort == 'date') { if ($sort == 'date') {
$dql .= ' ORDER BY b.created DESC'; $dql .= "\n ORDER BY b.created DESC";
} elseif ($sort == 'name') { }
$dql .= ' ORDER BY b.name ASC'; elseif ($sort == 'name') {
$dql .= "\n ORDER BY b.name ASC";
} }
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
@@ -80,24 +83,27 @@ class BasketRepository extends EntityRepository
/** /**
* Returns all unread basket for a given user that are not marked as archived * Returns all unread basket for a given user that are not marked as archived
* *
* @param User $user * @param User $user
* @return Basket[] * @return Basket[]
*/ */
public function findUnreadActiveByUser(User $user) public function findUnreadActiveByUser(User $user)
{ {
$dql = 'SELECT b // checked : 2 usages, "b.elements" is useless
FROM Phraseanet:Basket b $dql = "SELECT b\n"
JOIN b.elements e . " FROM Phraseanet:Basket b\n"
LEFT JOIN b.validation s // . " JOIN b.elements e\n"
LEFT JOIN s.participants p . " LEFT JOIN b.validation s\n"
WHERE b.archived = false . " LEFT JOIN s.participants p\n"
AND ( . " WHERE b.archived = false\n"
(b.user = :usr_id_owner AND b.isRead = false) . " AND (\n"
OR (b.user != :usr_id_ownertwo . " (b.user = :usr_id_owner AND b.isRead = false)\n"
AND p.user = :usr_id_participant . " OR \n"
AND p.is_aware = false) . " (b.user != :usr_id_ownertwo\n"
) . " AND p.user = :usr_id_participant\n"
AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP())'; . " AND p.is_aware = false\n"
. " AND s.expires > CURRENT_TIMESTAMP()\n"
. " )\n"
. " )";
$params = [ $params = [
'usr_id_owner' => $user->getId(), 'usr_id_owner' => $user->getId(),
@@ -115,11 +121,22 @@ class BasketRepository extends EntityRepository
* Returns all baskets that are in validation session not expired and * Returns all baskets that are in validation session not expired and
* where a specified user is participant (not owner) * where a specified user is participant (not owner)
* *
* @param User $user * @param User $user
* @param null|string $sort
* @return Basket[] * @return Basket[]
*/ */
public function findActiveValidationByUser(User $user, $sort = null) public function findActiveValidationByUser(User $user, $sort = null)
{ {
// checked : 2 usages, "b.elements" seems useless.
$dql = "SELECT b\n"
. "FROM Phraseanet:Basket b\n"
// . " JOIN b.elements e\n"
// . " JOIN e.validation_datas v\n"
. " JOIN b.validation s\n"
. " JOIN s.participants p\n"
. "WHERE b.user != ?1 AND p.user = ?2\n"
. " AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP())";
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
JOIN b.elements e JOIN b.elements e
@@ -130,9 +147,9 @@ class BasketRepository extends EntityRepository
AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP()) '; AND (s.expires IS NULL OR s.expires > CURRENT_TIMESTAMP()) ';
if ($sort == 'date') { if ($sort == 'date') {
$dql .= ' ORDER BY b.created DESC'; $dql .= "\nORDER BY b.created DESC";
} elseif ($sort == 'name') { } elseif ($sort == 'name') {
$dql .= ' ORDER BY b.name ASC'; $dql .= "\nORDER BY b.name ASC";
} }
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
@@ -152,10 +169,11 @@ class BasketRepository extends EntityRepository
*/ */
public function findUserBasket($basket_id, User $user, $requireOwner) public function findUserBasket($basket_id, User $user, $requireOwner)
{ {
$dql = 'SELECT b // checked : 3 usages, "b.elements e" seems useless
FROM Phraseanet:Basket b $dql = "SELECT b\n"
LEFT JOIN b.elements e . " FROM Phraseanet:Basket b\n"
WHERE b.id = :basket_id'; // . " LEFT JOIN b.elements e\n"
. " WHERE b.id = :basket_id";
$query = $this->_em->createQuery($dql); $query = $this->_em->createQuery($dql);
$query->setParameters(['basket_id' => $basket_id]); $query->setParameters(['basket_id' => $basket_id]);
@@ -188,7 +206,7 @@ class BasketRepository extends EntityRepository
public function findContainingRecordForUser(\record_adapter $record, User $user) public function findContainingRecordForUser(\record_adapter $record, User $user)
{ {
// todo : check "e.sbas_id = e.sbas_id" ???
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
JOIN b.elements e JOIN b.elements e
@@ -210,29 +228,31 @@ class BasketRepository extends EntityRepository
{ {
switch ($type) { switch ($type) {
case self::RECEIVED: case self::RECEIVED:
$dql = 'SELECT b // todo : check when called, and if "LEFT JOIN b.elements e" is usefull
FROM Phraseanet:Basket b $dql = "SELECT b\n"
JOIN b.elements e'; . "FROM Phraseanet:Basket b\n"
. " JOIN b.elements e\n"
. "WHERE b.user = :usr_id AND b.pusher_id IS NOT NULL";
$params = [ $params = [
'usr_id' => $user->getId() 'usr_id' => $user->getId()
]; ];
break; break;
case self::VALIDATION_DONE: case self::VALIDATION_DONE:
$dql = 'SELECT b // todo : check when called, and if "LEFT JOIN b.elements e" is usefull
FROM Phraseanet:Basket b $dql = "SELECT b\n"
JOIN b.elements e . "FROM Phraseanet:Basket b\n"
JOIN b.validation s . " JOIN b.elements e\n"
JOIN s.participants p . " JOIN b.validation s\n"
WHERE b.user != ?1 AND p.user = ?2'; . " JOIN s.participants p\n"
. "WHERE b.user != ?1 AND p.user = ?2";
$params = [ $params = [
1 => $user->getId() 1 => $user->getId(),
, 2 => $user->getId() 2 => $user->getId()
]; ];
break; break;
case self::VALIDATION_SENT: case self::VALIDATION_SENT:
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
JOIN b.elements e
JOIN b.validation v JOIN b.validation v
WHERE b.user = :usr_id'; WHERE b.user = :usr_id';
$params = [ $params = [
@@ -242,7 +262,6 @@ class BasketRepository extends EntityRepository
case self::MYBASKETS: case self::MYBASKETS:
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
LEFT JOIN b.elements e
LEFT JOIN b.validation s LEFT JOIN b.validation s
LEFT JOIN s.participants p LEFT JOIN s.participants p
WHERE (b.user = :usr_id)'; WHERE (b.user = :usr_id)';
@@ -251,6 +270,7 @@ class BasketRepository extends EntityRepository
]; ];
break; break;
default: default:
// todo : check when called, and if "LEFT JOIN b.elements e" is usefull
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
LEFT JOIN b.elements e LEFT JOIN b.elements e
@@ -296,6 +316,7 @@ class BasketRepository extends EntityRepository
*/ */
public function findActiveValidationAndBasketByUser(User $user, $sort = null) public function findActiveValidationAndBasketByUser(User $user, $sort = null)
{ {
// todo : check caller and if "LEFT JOIN b.elements e" is usefull
$dql = 'SELECT b $dql = 'SELECT b
FROM Phraseanet:Basket b FROM Phraseanet:Basket b
LEFT JOIN b.elements e LEFT JOIN b.elements e

View File

@@ -1115,7 +1115,6 @@ class ACL implements cache_cacheableInterface
/** /**
* @param array $base_ids * @param array $base_ids
* @return $this * @return $this
* @throws DBALException
* @throws Exception * @throws Exception
*/ */
public function revoke_access_from_bases(Array $base_ids) public function revoke_access_from_bases(Array $base_ids)
@@ -1125,24 +1124,30 @@ class ACL implements cache_cacheableInterface
$usr_id = $this->user->getId(); $usr_id = $this->user->getId();
$errors = 0;
foreach ($base_ids as $base_id) { foreach ($base_ids as $base_id) {
if (!$stmt_del->execute([':base_id' => $base_id, ':usr_id' => $usr_id])) { if ($stmt_del->execute([':base_id' => $base_id, ':usr_id' => $usr_id])) {
throw new Exception('Error while deleteing some rights'); $this->app['dispatcher']->dispatch(
} AclEvents::ACCESS_TO_BASE_REVOKED,
new AccessToBaseRevokedEvent(
$this->app['dispatcher']->dispatch( $this,
AclEvents::ACCESS_TO_BASE_REVOKED, [
new AccessToBaseRevokedEvent( 'base_id' => $base_id
$this, ]
array(
'base_id'=>$base_id
) )
) );
); }
else {
$errors++;
}
} }
$stmt_del->closeCursor(); $stmt_del->closeCursor();
$this->delete_data_from_cache(self::CACHE_RIGHTS_BAS); $this->delete_data_from_cache(self::CACHE_RIGHTS_BAS);
if($errors > 0) {
throw new Exception('Error while deleting some rights');
}
return $this; return $this;
} }

View File

@@ -11,6 +11,9 @@
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Alchemy\Phrasea\Model\Repositories\UserRepository;
class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract
{ {
@@ -31,9 +34,9 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract
/** /**
* *
* @param Array $datas * @param string[] $data
* @param boolean $unread * @param boolean $unread
* @return string * @return array
*/ */
public function datas(array $data, $unread) public function datas(array $data, $unread)
{ {
@@ -41,24 +44,29 @@ class eventsmanager_notify_orderdeliver extends eventsmanager_notifyAbstract
$ssel_id = $data['ssel_id']; $ssel_id = $data['ssel_id'];
$n = $data['n']; $n = $data['n'];
if (null === $user= $this->app['repo.users']->find(($from))) { /** @var UserRepository $userRepo */
$userRepo = $this->app['repo.users'];
if( ($user= $userRepo->find(($from))) === null ) {
return []; return [];
} }
$sender = $user->getDisplayName(); $sender = $user->getDisplayName();
try { try {
/** @var BasketRepository $repository */
$repository = $this->app['repo.baskets']; $repository = $this->app['repo.baskets'];
$basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false); $basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false);
} catch (\Exception $e) { }
catch (\Exception $e) {
return []; return [];
} }
$ret = [ $ret = [
'text' => $this->app->trans('%user% vous a delivre %quantity% document(s) pour votre commande %title%', ['%user%' => $sender, '%quantity%' => $n, '%title%' => '<a href="/lightbox/compare/' 'text' => $this->app->trans('%user% vous a delivre %quantity% document(s) pour votre commande %title%', ['%user%' => $sender, '%quantity%' => $n, '%title%' => '<a href="/lightbox/compare/'
. $ssel_id . '/" target="_blank">' . $ssel_id . '/" target="_blank">'
. $basket->getName() . '</a>']) . $basket->getName() . '</a>']),
, 'class' => '' 'class' => ''
]; ];
return $ret; return $ret;

View File

@@ -11,6 +11,9 @@
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Alchemy\Phrasea\Model\Repositories\UserRepository;
class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract
{ {
@@ -31,35 +34,38 @@ class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract
/** /**
* *
* @param string $datas * @param string[] $data
* @param boolean $unread * @param boolean $unread
* @return Array * @return array
*/ */
public function datas(array $data, $unread) public function datas(array $data, $unread)
{ {
$from = $data['from']; $from = $data['from'];
$ssel_id = $data['ssel_id']; $ssel_id = $data['ssel_id'];
if (null === $registered_user = $this->app['repo.users']->find($from)) { /** @var UserRepository $userRepo */
$userRepo = $this->app['repo.users'];
if ( ($registered_user = $userRepo->find($from)) === null ) {
return []; return [];
} }
$sender = $registered_user->getDisplayName(); $sender = $registered_user->getDisplayName();
try { try {
/** @var BasketRepository $repository */
$repository = $this->app['repo.baskets']; $repository = $this->app['repo.baskets'];
$basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false); $basket = $repository->findUserBasket($ssel_id, $this->app->getAuthenticatedUser(), false);
} catch (\Exception $e) { }
catch (\Exception $e) {
return []; return [];
} }
$ret = [ $ret = [
'text' => $this->app->trans('%user% a envoye son rapport de validation de %title%', ['%user%' => $sender, '%title%' => '<a href="/lightbox/validate/' 'text' => $this->app->trans('%user% a envoye son rapport de validation de %title%', ['%user%' => $sender, '%title%' => '<a href="/lightbox/validate/'
. $ssel_id . '/" target="_blank">' . $ssel_id . '/" target="_blank">'
. $basket->getName() . '</a>' . $basket->getName() . '</a>']),
]) 'class' => ''
, 'class' => ''
]; ];
return $ret; return $ret;
@@ -84,12 +90,18 @@ class eventsmanager_notify_validationdone extends eventsmanager_notifyAbstract
} }
/** /**
* @param integer $usr_id The id of the user to check * @param User $user The id of the user to check
* *
* @return boolean * @return boolean
*/ */
public function is_available(User $user) public function is_available(User $user)
{ {
return $this->app->getAclForUser($user)->has_right(\ACL::CANPUSH); try {
return $this->app->getAclForUser($user)->has_right(\ACL::CANPUSH);
}
catch (\Exception $e) {
// has_right(unknow_right) ? will not happen !
return false;
}
} }
} }

View File

@@ -9,13 +9,16 @@
*/ */
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
use Alchemy\Phrasea\Model\Entities\Token; use Alchemy\Phrasea\Model\Entities\Token;
use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Model\Repositories\BasketRepository;
use Alchemy\Phrasea\Model\Repositories\StoryWZRepository;
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
use Assert\Assertion; use Assert\Assertion;
use Doctrine\DBAL\Connection; use Doctrine\DBAL\Connection;
use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Filesystem\Filesystem;
class set_export extends set_abstract class set_export extends set_abstract
{ {
private static $maxFilenameLength = 256; private static $maxFilenameLength = 256;
@@ -60,6 +63,7 @@ class set_export extends set_abstract
$remain_hd = []; $remain_hd = [];
if ($storyWZid) { if ($storyWZid) {
/** @var StoryWZRepository $repository */
$repository = $app['repo.story-wz']; $repository = $app['repo.story-wz'];
$storyWZ = $repository->findByUserAndId($this->app, $app->getAuthenticatedUser(), $storyWZid); $storyWZ = $repository->findByUserAndId($this->app, $app->getAuthenticatedUser(), $storyWZid);
@@ -68,6 +72,7 @@ class set_export extends set_abstract
} }
if ($sstid != "") { if ($sstid != "") {
/** @var BasketRepository $repository */
$repository = $app['repo.baskets']; $repository = $app['repo.baskets'];
$Basket = $repository->findUserBasket($sstid, $app->getAuthenticatedUser(), false); $Basket = $repository->findUserBasket($sstid, $app->getAuthenticatedUser(), false);

View File

@@ -65,7 +65,7 @@
"normalize-css": "^2.1.0", "normalize-css": "^2.1.0",
"npm": "^6.0.0", "npm": "^6.0.0",
"npm-modernizr": "^2.8.3", "npm-modernizr": "^2.8.3",
"phraseanet-production-client": "0.34.63-d", "phraseanet-production-client": "0.34.72-d",
"requirejs": "^2.3.5", "requirejs": "^2.3.5",
"tinymce": "^4.0.28", "tinymce": "^4.0.28",
"underscore": "^1.8.3", "underscore": "^1.8.3",

View File

@@ -7555,10 +7555,10 @@ phraseanet-common@^0.4.1:
js-cookie "^2.1.0" js-cookie "^2.1.0"
pym.js "^1.3.1" pym.js "^1.3.1"
phraseanet-production-client@0.34.63-d: phraseanet-production-client@0.34.72-d:
version "0.34.63-d" version "0.34.72-d"
resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.63-d.tgz#0b74aa2188002effedd143d4c16364007daad672" resolved "https://registry.yarnpkg.com/phraseanet-production-client/-/phraseanet-production-client-0.34.72-d.tgz#028a5ccd589e696b5433eea9d53d9367966613c8"
integrity sha512-kjySO4v4KALrr7UC/6WacSn/2s4pEaiY98iqejoK2rkzZEsuVOUKyuifxfTaX4xkFSfSwf5F0RA2n43JJbDGHA== integrity sha512-IPaDRqXwyJegoKmzr56bggxTzN4TnmuAqU4O7rDEhh0aqdCiuC8rlH/yzKoLeEIMSrESCw5mBhrI//ccntvv9w==
dependencies: dependencies:
"@mapbox/mapbox-gl-language" "^0.9.2" "@mapbox/mapbox-gl-language" "^0.9.2"
"@turf/turf" "^5.1.6" "@turf/turf" "^5.1.6"