mirror of
https://github.com/alchemy-fr/Phraseanet.git
synced 2025-10-10 11:33:17 +00:00
Merge branch 4.0 into master
This commit is contained in:
@@ -70,7 +70,7 @@
|
||||
"ircmaxell/random-lib": "~1.0",
|
||||
"jms/serializer": "~0.10",
|
||||
"jms/translation-bundle": "dev-rebase-2015-10-20",
|
||||
"justinrainbow/json-schema": "~1.3",
|
||||
"justinrainbow/json-schema": "2.0.3 as 1.6.1",
|
||||
"league/flysystem": "^1.0",
|
||||
"league/flysystem-aws-s3-v2": "^1.0",
|
||||
"league/fractal": "dev-bug/null-resource-serialization#891856f as 0.13.0",
|
||||
|
82
composer.lock
generated
82
composer.lock
generated
@@ -4,8 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"hash": "685ed8f8578c211ee14ebc00703ab281",
|
||||
"content-hash": "acd719252dc8e17e752f2e87f571a7b5",
|
||||
"hash": "e3c9335da1fb653e0e2af3c12ad85d1e",
|
||||
"content-hash": "2af2f721294eb3e2aed29d7a686f6567",
|
||||
"packages": [
|
||||
{
|
||||
"name": "alchemy-fr/tcpdf-clone",
|
||||
@@ -15,6 +15,12 @@
|
||||
"url": "https://github.com/alchemy-fr/tcpdf-clone.git",
|
||||
"reference": "2ba0248a7187f1626df6c128750650416267f0e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/tcpdf-clone/zipball/2ba0248a7187f1626df6c128750650416267f0e7",
|
||||
"reference": "2ba0248a7187f1626df6c128750650416267f0e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
@@ -61,6 +67,10 @@
|
||||
"qrcode",
|
||||
"tcpdf"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/alchemy-fr/tcpdf-clone/tree/6.0.039",
|
||||
"issues": "https://github.com/alchemy-fr/tcpdf-clone/issues"
|
||||
},
|
||||
"time": "2013-10-13 16:11:17"
|
||||
},
|
||||
{
|
||||
@@ -537,6 +547,12 @@
|
||||
"url": "https://github.com/alchemy-fr/symfony-cors.git",
|
||||
"reference": "dbf7fcff1ce9fc1265db12955476ff169eab7375"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/alchemy-fr/symfony-cors/zipball/dbf7fcff1ce9fc1265db12955476ff169eab7375",
|
||||
"reference": "dbf7fcff1ce9fc1265db12955476ff169eab7375",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"symfony/http-kernel": "^2.3.0|^3.0.0"
|
||||
},
|
||||
@@ -557,11 +573,7 @@
|
||||
"Alchemy\\CorsBundle\\": "src/Bundle/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Alchemy\\Cors\\Tests\\": "tests/unit/Component/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
@@ -1790,12 +1802,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/igorw/evenement.git",
|
||||
"reference": "v1.0.0"
|
||||
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/igorw/evenement/zipball/v1.0.0",
|
||||
"reference": "v1.0.0",
|
||||
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
|
||||
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -1822,7 +1834,7 @@
|
||||
"keywords": [
|
||||
"event-dispatcher"
|
||||
],
|
||||
"time": "2012-05-30 08:01:08"
|
||||
"time": "2012-05-30 15:01:08"
|
||||
},
|
||||
{
|
||||
"name": "facebook/php-sdk",
|
||||
@@ -2811,12 +2823,12 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hoaproject/Stream.git",
|
||||
"reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3"
|
||||
"reference": "3bc446bc00849bf51166adc415d77aa375d48d8c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/hoaproject/Stream/zipball/011ab91d942f1d7096deade4c8a10fe57d51c5b3",
|
||||
"reference": "011ab91d942f1d7096deade4c8a10fe57d51c5b3",
|
||||
"url": "https://api.github.com/repos/hoaproject/Stream/zipball/3bc446bc00849bf51166adc415d77aa375d48d8c",
|
||||
"reference": "3bc446bc00849bf51166adc415d77aa375d48d8c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2861,7 +2873,7 @@
|
||||
"stream",
|
||||
"wrapper"
|
||||
],
|
||||
"time": "2015-10-22 06:30:43"
|
||||
"time": "2015-10-26 12:21:43"
|
||||
},
|
||||
{
|
||||
"name": "hoa/ustring",
|
||||
@@ -3453,25 +3465,25 @@
|
||||
},
|
||||
{
|
||||
"name": "justinrainbow/json-schema",
|
||||
"version": "1.6.1",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/justinrainbow/json-schema.git",
|
||||
"reference": "cc84765fb7317f6b07bd8ac78364747f95b86341"
|
||||
"reference": "c21534c635f03428e92254333fab4ae35b2cdfd9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/cc84765fb7317f6b07bd8ac78364747f95b86341",
|
||||
"reference": "cc84765fb7317f6b07bd8ac78364747f95b86341",
|
||||
"url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/c21534c635f03428e92254333fab4ae35b2cdfd9",
|
||||
"reference": "c21534c635f03428e92254333fab4ae35b2cdfd9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.29"
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"json-schema/json-schema-test-suite": "1.1.0",
|
||||
"json-schema/json-schema-test-suite": "1.1.2",
|
||||
"phpdocumentor/phpdocumentor": "~2",
|
||||
"phpunit/phpunit": "~3.7"
|
||||
"phpunit/phpunit": "^4.8.22"
|
||||
},
|
||||
"bin": [
|
||||
"bin/validate-json"
|
||||
@@ -3479,7 +3491,7 @@
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.6.x-dev"
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3489,7 +3501,7 @@
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
@@ -3515,7 +3527,7 @@
|
||||
"json",
|
||||
"schema"
|
||||
],
|
||||
"time": "2016-01-25 15:43:01"
|
||||
"time": "2016-05-10 20:38:51"
|
||||
},
|
||||
{
|
||||
"name": "league/flysystem",
|
||||
@@ -3890,7 +3902,7 @@
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Stephen Clay",
|
||||
"name": "Steve Clay",
|
||||
"email": "steve@mrclay.org",
|
||||
"homepage": "http://www.mrclay.org/",
|
||||
"role": "Developer"
|
||||
@@ -4076,21 +4088,21 @@
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git",
|
||||
"reference": "0.1.2"
|
||||
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/0.1.2",
|
||||
"reference": "0.1.2",
|
||||
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084",
|
||||
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"imagine/imagine": "*",
|
||||
"php": ">=5.3.3",
|
||||
"silex/silex": ">=1.0,<2.0"
|
||||
"silex/silex": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/browser-kit": ">=2.0,<3.0"
|
||||
"symfony/browser-kit": "~2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -5563,7 +5575,7 @@
|
||||
},
|
||||
{
|
||||
"name": "Phraseanet Team",
|
||||
"email": "support@alchemy.fr",
|
||||
"email": "info@alchemy.fr",
|
||||
"homepage": "http://www.phraseanet.com/"
|
||||
}
|
||||
],
|
||||
@@ -7716,6 +7728,12 @@
|
||||
}
|
||||
],
|
||||
"aliases": [
|
||||
{
|
||||
"alias": "1.6.1",
|
||||
"alias_normalized": "1.6.1.0",
|
||||
"version": "2.0.3.0",
|
||||
"package": "justinrainbow/json-schema"
|
||||
},
|
||||
{
|
||||
"alias": "0.13.0",
|
||||
"alias_normalized": "0.13.0.0",
|
||||
|
@@ -6,6 +6,7 @@ main:
|
||||
maintenance: false
|
||||
languages: []
|
||||
key: ''
|
||||
api_require_ssl: true
|
||||
database:
|
||||
host: 127.0.0.1
|
||||
port: 3306
|
||||
|
81
lib/Alchemy/Phrasea/Account/RestrictedStatusExtractor.php
Normal file
81
lib/Alchemy/Phrasea/Account/RestrictedStatusExtractor.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of alchemy/pipeline-component.
|
||||
*
|
||||
* (c) Alchemy <info@alchemy.fr>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Account;
|
||||
|
||||
class RestrictedStatusExtractor
|
||||
{
|
||||
/**
|
||||
* @var \ACL
|
||||
*/
|
||||
private $acl;
|
||||
|
||||
/**
|
||||
* @var \appbox
|
||||
*/
|
||||
private $applicationBox;
|
||||
|
||||
/**
|
||||
* @param \ACL $acl
|
||||
* @param \appbox $applicationBox
|
||||
*/
|
||||
public function __construct(\ACL $acl, \appbox $applicationBox)
|
||||
{
|
||||
$this->acl = $acl;
|
||||
$this->applicationBox = $applicationBox;
|
||||
}
|
||||
|
||||
public function getRestrictedStatuses($baseId)
|
||||
{
|
||||
$restrictions = [];
|
||||
|
||||
$andMask = $this->acl->get_mask_and($baseId);
|
||||
$xorMask = $this->acl->get_mask_xor($baseId);
|
||||
|
||||
$structure = $this->getStatusStructure($baseId);
|
||||
|
||||
for ($position = 0; $position < 32; $position++) {
|
||||
$andBit = (1 << $position) & $andMask;
|
||||
$xorBit = (1 << $position) & $xorMask;
|
||||
|
||||
$status = $structure->getStatus($position);
|
||||
|
||||
if (! $andBit && $status['labels_on_i18n'] == null && $status['labels_off_i18n'] == null) {
|
||||
// Ignore unrestricted statuses with null label arrays (label is not configured, hence not used)
|
||||
continue;
|
||||
}
|
||||
|
||||
$restrictions[] = [
|
||||
'position' => $position,
|
||||
'labels' => [
|
||||
'on' => $status['labels_on_i18n'],
|
||||
'off' => $status['labels_off_i18n']
|
||||
],
|
||||
'restricted' => (bool) $andBit,
|
||||
'restriction_flag' => (bool) $xorBit
|
||||
];
|
||||
}
|
||||
|
||||
return $restrictions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $baseId
|
||||
* @return \Alchemy\Phrasea\Status\StatusStructure
|
||||
*/
|
||||
private function getStatusStructure($baseId)
|
||||
{
|
||||
$databoxId = $this->applicationBox->get_collection($baseId)->get_sbas_id();
|
||||
$databox = $this->applicationBox->get_databox($databoxId);
|
||||
|
||||
return $databox->getStatusStructure();
|
||||
}
|
||||
}
|
@@ -23,7 +23,6 @@ use Alchemy\Phrasea\Core\Event\Subscriber\BridgeSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\ExportSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\FeedEntrySubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\LazaretSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\OrderSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\PhraseaInstallSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\RegistrationSubscriber;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\ValidationSubscriber;
|
||||
@@ -56,6 +55,7 @@ use Alchemy\Phrasea\Core\Provider\JMSSerializerServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\LocaleServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\ManipulatorServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\NotificationDelivererServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\OrderServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\PhraseaEventServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\PhraseanetServiceProvider;
|
||||
use Alchemy\Phrasea\Core\Provider\PhraseaVersionServiceProvider;
|
||||
@@ -237,10 +237,12 @@ class Application extends SilexApplication
|
||||
$this->register(new PhraseaEventServiceProvider());
|
||||
|
||||
$this->register(new LocaleServiceProvider());
|
||||
|
||||
$this->setupEventDispatcher();
|
||||
|
||||
$this->register(new OrderServiceProvider());
|
||||
$this->register(new WebhookServiceProvider());
|
||||
|
||||
|
||||
$this['phraseanet.exception_handler'] = $this->share(function ($app) {
|
||||
/** @var PhraseaExceptionHandler $handler */
|
||||
$handler = PhraseaExceptionHandler::register($app['debug']);
|
||||
@@ -705,7 +707,6 @@ class Application extends SilexApplication
|
||||
$dispatcher->addSubscriber(new RegistrationSubscriber($app));
|
||||
$dispatcher->addSubscriber(new BridgeSubscriber($app));
|
||||
$dispatcher->addSubscriber(new ExportSubscriber($app));
|
||||
$dispatcher->addSubscriber(new OrderSubscriber($app));
|
||||
$dispatcher->addSubscriber(new BasketSubscriber($app));
|
||||
$dispatcher->addSubscriber(new LazaretSubscriber($app));
|
||||
$dispatcher->addSubscriber(new ValidationSubscriber($app));
|
||||
|
@@ -15,6 +15,7 @@ use Alchemy\Phrasea\Command\TaskManagerCommand;
|
||||
use Alchemy\Phrasea\Exception\RuntimeException;
|
||||
use Alchemy\Phrasea\Model\Entities\Task;
|
||||
use Alchemy\Phrasea\TaskManager\Event\FinishedJobRemoverSubscriber;
|
||||
use Alchemy\Phrasea\TaskManager\Job\AbstractJob;
|
||||
use Alchemy\Phrasea\TaskManager\Job\JobData;
|
||||
use Alchemy\TaskManager\Event\JobSubscriber\DurationLimitSubscriber;
|
||||
use Alchemy\TaskManager\Event\JobSubscriber\LockFileSubscriber;
|
||||
@@ -72,6 +73,12 @@ class TaskRun extends TaskManagerCommand
|
||||
return $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param InputInterface $input
|
||||
* @param Task $task
|
||||
* @param Logger $logger
|
||||
* @return AbstractJob
|
||||
*/
|
||||
protected function createJob(InputInterface $input, Task $task, Logger $logger)
|
||||
{
|
||||
$job = $this->container['task-manager.job-factory']->create($task->getJobId());
|
||||
|
@@ -16,6 +16,7 @@ use Alchemy\Phrasea\Authentication\Exception\AccountLockedException;
|
||||
use Alchemy\Phrasea\Authentication\Exception\RequireCaptchaException;
|
||||
use Alchemy\Phrasea\Authentication\Phrasea\PasswordAuthenticationInterface;
|
||||
use Alchemy\Phrasea\Controller\Controller;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
use Alchemy\Phrasea\Core\Event\PostAuthenticate;
|
||||
use Alchemy\Phrasea\Core\Event\PreAuthenticate;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
@@ -174,8 +175,11 @@ class OAuth2Controller extends Controller
|
||||
*/
|
||||
public function tokenAction(Request $request)
|
||||
{
|
||||
if ( ! $request->isSecure()) {
|
||||
throw new HttpException(400, 'This route requires the use of the https scheme', null, ['content-type' => 'application/json']);
|
||||
/** @var PropertyAccess $config */
|
||||
$config = $this->app['conf'];
|
||||
|
||||
if ( ! $request->isSecure() && $config->get(['main', 'api_require_ssl'], true) == true) {
|
||||
throw new HttpException(400, 'This route requires the use of the https scheme: ' . $config->get(['main', 'api_require_ssl']), null, ['content-type' => 'application/json']);
|
||||
}
|
||||
|
||||
$this->oAuth2Adapter->grantAccessToken($request);
|
||||
|
@@ -14,6 +14,7 @@ use Alchemy\Phrasea\Account\AccountService;
|
||||
use Alchemy\Phrasea\Account\CollectionRequestMapper;
|
||||
use Alchemy\Phrasea\Account\Command\UpdateAccountCommand;
|
||||
use Alchemy\Phrasea\Account\Command\UpdatePasswordCommand;
|
||||
use Alchemy\Phrasea\Account\RestrictedStatusExtractor;
|
||||
use Alchemy\Phrasea\Application\Helper\DataboxLoggerAware;
|
||||
use Alchemy\Phrasea\Application\Helper\DispatcherAware;
|
||||
use Alchemy\Phrasea\Application\Helper\JsonBodyAware;
|
||||
@@ -84,6 +85,10 @@ use Alchemy\Phrasea\Status\StatusStructure;
|
||||
use Alchemy\Phrasea\TaskManager\LiveInformation;
|
||||
use Alchemy\Phrasea\Utilities\NullableDateTime;
|
||||
use Doctrine\ORM\EntityManager;
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
use JMS\TranslationBundle\Annotation\Ignore;
|
||||
>>>>>>> 4.0
|
||||
use League\Fractal\Resource\Item;
|
||||
use Symfony\Component\Form\Form;
|
||||
use Symfony\Component\HttpFoundation\File\UploadedFile;
|
||||
@@ -747,6 +752,9 @@ class V1Controller extends Controller
|
||||
|
||||
$grants = [];
|
||||
|
||||
|
||||
$statusMapper = new RestrictedStatusExtractor($acl, $this->getApplicationBox());
|
||||
|
||||
foreach ($bases as $base) {
|
||||
$baseGrants = [];
|
||||
|
||||
@@ -763,6 +771,33 @@ class V1Controller extends Controller
|
||||
'base_id' => $base->get_base_id(),
|
||||
'collection_id' => $base->get_coll_id(),
|
||||
'rights' => $baseGrants,
|
||||
'statuses' => $statusMapper->getRestrictedStatuses($base->get_base_id())
|
||||
];
|
||||
}
|
||||
|
||||
return $grants;
|
||||
}
|
||||
|
||||
private function listUserDataboxes(User $user)
|
||||
{
|
||||
$acl = $this->getAclForUser($user);
|
||||
$rightsByDatabox = $acl->get_sbas_rights();
|
||||
$grants = [];
|
||||
|
||||
foreach ($rightsByDatabox as $databoxId => $databoxRights) {
|
||||
$rights = [];
|
||||
|
||||
foreach ($databoxRights as $name => $allowedFlag) {
|
||||
if (! $allowedFlag) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rights[] = $name;
|
||||
}
|
||||
|
||||
$grants[] = [
|
||||
'databox_id' => $databoxId,
|
||||
'rights' => $rights
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1180,6 +1215,7 @@ class V1Controller extends Controller
|
||||
->getRecordRepository()
|
||||
->findChildren($storyIds, $user);
|
||||
$children[$databoxId] = array_combine($storyIds, $selections);
|
||||
<<<<<<< HEAD
|
||||
}
|
||||
|
||||
/** @var StoryView[] $storyViews */
|
||||
@@ -1223,6 +1259,51 @@ class V1Controller extends Controller
|
||||
$allChildren[$index] = $childrenView->getRecord();
|
||||
}
|
||||
|
||||
=======
|
||||
}
|
||||
|
||||
/** @var StoryView[] $storyViews */
|
||||
$storyViews = [];
|
||||
/** @var RecordView[] $childrenViews */
|
||||
$childrenViews = [];
|
||||
|
||||
foreach ($stories as $index => $story) {
|
||||
$storyView = new StoryView($story);
|
||||
|
||||
$selection = $children[$story->getDataboxId()][$story->getRecordId()];
|
||||
|
||||
$childrenView = $this->buildRecordViews($selection);
|
||||
|
||||
foreach ($childrenView as $view) {
|
||||
$childrenViews[spl_object_hash($view)] = $view;
|
||||
}
|
||||
|
||||
$storyView->setChildren($childrenView);
|
||||
|
||||
$storyViews[$index] = $storyView;
|
||||
}
|
||||
|
||||
if (in_array('results.stories.thumbnail', $includes, true)) {
|
||||
$subdefViews = $this->buildSubdefsViews($stories, ['thumbnail'], $urlTTL);
|
||||
|
||||
foreach ($storyViews as $index => $storyView) {
|
||||
$storyView->setSubdefs($subdefViews[$index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (in_array('results.stories.metadatas', $includes, true)) {
|
||||
$captions = $this->app['service.caption']->findByReferenceCollection($stories);
|
||||
$canSeeBusiness = $this->retrieveSeeBusinessPerDatabox($stories);
|
||||
|
||||
$this->buildCaptionViews($storyViews, $captions, $canSeeBusiness);
|
||||
}
|
||||
|
||||
$allChildren = new RecordCollection();
|
||||
foreach ($childrenViews as $index => $childrenView) {
|
||||
$allChildren[$index] = $childrenView->getRecord();
|
||||
}
|
||||
|
||||
>>>>>>> 4.0
|
||||
$names = in_array('results.stories.records.subdefs', $includes, true) ? null : ['thumbnail'];
|
||||
$subdefViews = $this->buildSubdefsViews($allChildren, $names, $urlTTL);
|
||||
$technicalDatasets = $this->app['service.technical_data']->fetchRecordsTechnicalData($allChildren);
|
||||
@@ -1339,6 +1420,7 @@ class V1Controller extends Controller
|
||||
/** @var \media_subdef $subdef */
|
||||
foreach ($allSubdefs as $index => $subdef) {
|
||||
$subdefView = new SubdefView($subdef);
|
||||
<<<<<<< HEAD
|
||||
|
||||
if (isset($allPermalinks[$index])) {
|
||||
$subdefView->setPermalinkView(new PermalinkView($allPermalinks[$index]));
|
||||
@@ -1407,6 +1489,76 @@ class V1Controller extends Controller
|
||||
];
|
||||
}
|
||||
|
||||
=======
|
||||
|
||||
if (isset($allPermalinks[$index])) {
|
||||
$subdefView->setPermalinkView(new PermalinkView($allPermalinks[$index]));
|
||||
}
|
||||
|
||||
$subdefView->setUrl($urls[$index]);
|
||||
$subdefView->setUrlTTL($urlTTL);
|
||||
|
||||
$subdefViews[spl_object_hash($subdef)] = $subdefView;
|
||||
}
|
||||
|
||||
$reorderedGroups = [];
|
||||
|
||||
/** @var \media_subdef[] $subdefGroup */
|
||||
foreach ($subdefGroups as $index => $subdefGroup) {
|
||||
$reordered = [];
|
||||
|
||||
foreach ($subdefGroup as $subdef) {
|
||||
$reordered[] = $subdefViews[spl_object_hash($subdef)];
|
||||
}
|
||||
|
||||
$reorderedGroups[$index] = $reordered;
|
||||
}
|
||||
|
||||
return $reorderedGroups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns requested includes
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveSearchIncludes(Request $request)
|
||||
{
|
||||
if ($request->attributes->get('_extended', false)) {
|
||||
return [
|
||||
'results.stories.records.subdefs',
|
||||
'results.stories.records.metadata',
|
||||
'results.stories.records.caption',
|
||||
'results.stories.records.status',
|
||||
'results.records.subdefs',
|
||||
'results.records.metadata',
|
||||
'results.records.caption',
|
||||
'results.records.status',
|
||||
];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns requested includes
|
||||
*
|
||||
* @param Request $request
|
||||
* @return string[]
|
||||
*/
|
||||
private function resolveSearchRecordsIncludes(Request $request)
|
||||
{
|
||||
if ($request->attributes->get('_extended', false)) {
|
||||
return [
|
||||
'results.subdefs',
|
||||
'results.metadata',
|
||||
'results.caption',
|
||||
'results.status',
|
||||
];
|
||||
}
|
||||
|
||||
>>>>>>> 4.0
|
||||
return [];
|
||||
}
|
||||
|
||||
@@ -2559,6 +2711,7 @@ class V1Controller extends Controller
|
||||
$ret = [
|
||||
"user" => $this->listUser($this->getAuthenticatedUser()),
|
||||
"collections" => $this->listUserCollections($this->getAuthenticatedUser()),
|
||||
"databoxes" => $this->listUserDataboxes($this->getAuthenticatedUser())
|
||||
];
|
||||
|
||||
if (defined('API_SKIP_USER_REGISTRATIONS') && ! constant('API_SKIP_USER_REGISTRATIONS')) {
|
||||
@@ -2608,12 +2761,16 @@ class V1Controller extends Controller
|
||||
$ret = [ 'success' => true ];
|
||||
}
|
||||
catch (AccountException $exception) {
|
||||
/** @Ignore */
|
||||
$ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
|
||||
}
|
||||
|
||||
return Result::create($request, $ret)->createResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* @Ignore
|
||||
*/
|
||||
public function updateCurrentUserPasswordAction(Request $request)
|
||||
{
|
||||
$service = $this->getAccountService();
|
||||
@@ -2631,6 +2788,7 @@ class V1Controller extends Controller
|
||||
$service->updatePassword($command, null);
|
||||
$ret = ['success' => true];
|
||||
} catch (AccountException $exception) {
|
||||
/** @Ignore */
|
||||
$ret = [ 'success' => false, 'message' => $this->app->trans($exception->getMessage()) ];
|
||||
}
|
||||
} else {
|
||||
|
@@ -87,7 +87,7 @@ class PermalinkController extends AbstractDelivery
|
||||
'sbas_id' => $sbas_id,
|
||||
'record_id' => $record_id,
|
||||
'subdef' => $subdefName,
|
||||
'label' => $record->get_title(),
|
||||
'label' => str_replace('/', '_', $record->get_title()),
|
||||
'token' => $token,
|
||||
]
|
||||
);
|
||||
|
@@ -162,7 +162,7 @@ class DoDownloadController extends Controller
|
||||
$this->app,
|
||||
$token,
|
||||
$list,
|
||||
sprintf($this->app['tmp.download.path'].'/%s.zip', $token->getValue()) // Dest file
|
||||
sprintf('%s/%s.zip', $this->app['tmp.download.path'], $token->getValue()) // Dest file
|
||||
);
|
||||
} else {
|
||||
$list['complete'] = true;
|
||||
|
@@ -141,7 +141,7 @@ class PushController extends Controller
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication'])
|
||||
|| !$request->get('force_authentication')
|
||||
) {
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($Basket, $user_receiver);
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($Basket, $user_receiver)->getValue();
|
||||
}
|
||||
|
||||
$url = $this->app->url('lightbox_compare', $arguments);
|
||||
@@ -343,7 +343,7 @@ class PushController extends Controller
|
||||
if (!$this->getConf()->get(['registry', 'actions', 'enable-push-authentication'])
|
||||
|| !$request->get('force_authentication')
|
||||
) {
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($basket, $participantUser);
|
||||
$arguments['LOG'] = $this->getTokenManipulator()->createBasketAccessToken($basket, $participantUser)->getValue();
|
||||
}
|
||||
|
||||
$url = $this->app->url('lightbox_validation', $arguments);
|
||||
|
@@ -22,6 +22,7 @@ use Alchemy\Phrasea\Model\Repositories\ApiOauthTokenRepository;
|
||||
use Symfony\Component\HttpFoundation\JsonResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
@@ -239,6 +240,10 @@ class DeveloperController extends Controller
|
||||
? $this->getApiOAuthTokenRepository()->findDeveloperToken($account)
|
||||
: null;
|
||||
|
||||
if (! $account) {
|
||||
throw new AccessDeniedHttpException();
|
||||
}
|
||||
|
||||
return $this->render('developers/application.html.twig', [
|
||||
"application" => $application,
|
||||
"user" => $user,
|
||||
|
@@ -55,6 +55,8 @@ class V2 implements ControllerProviderInterface, ServiceProviderInterface
|
||||
return (new ApiOrderController($app))
|
||||
->setDispatcher($app['dispatcher'])
|
||||
->setEntityManagerLocator(new LazyLocator($app, 'orm.em'))
|
||||
->setDelivererLocator(new LazyLocator($app, 'phraseanet.file-serve'))
|
||||
->setFileSystemLocator(new LazyLocator($app, 'filesystem'))
|
||||
->setJsonBodyHelper($app['json.body_helper']);
|
||||
}
|
||||
);
|
||||
@@ -115,6 +117,10 @@ class V2 implements ControllerProviderInterface, ServiceProviderInterface
|
||||
->assert('orderId', '\d+')
|
||||
->bind('api_v2_orders_deny');
|
||||
|
||||
$controllers->get('/orders/{orderId}/archive', 'controller.api.v2.orders:getArchiveAction')
|
||||
->assert('orderId', '\d+')
|
||||
->bind('api_v2_orders_archive');
|
||||
|
||||
return $controllers;
|
||||
}
|
||||
|
||||
|
@@ -13,33 +13,49 @@ namespace Alchemy\Phrasea\Core\Event;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Order\OrderDelivery;
|
||||
|
||||
class OrderDeliveryEvent extends OrderEvent
|
||||
{
|
||||
private $admin;
|
||||
private $quantity;
|
||||
/**
|
||||
* @var OrderDelivery
|
||||
*/
|
||||
private $orderDelivery;
|
||||
|
||||
public function __construct(Order $order, User $admin, $quantity)
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function __construct(OrderDelivery $delivery)
|
||||
{
|
||||
parent::__construct($order);
|
||||
$this->admin = $admin;
|
||||
$this->quantity = $quantity;
|
||||
parent::__construct($delivery->getOrder());
|
||||
|
||||
$this->orderDelivery = $delivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OrderDelivery
|
||||
*/
|
||||
public function getDelivery()
|
||||
{
|
||||
return $this->orderDelivery;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
* @deprecated Use OrderDeliveryEvent::getDelivery() to retrieve admin user.
|
||||
*/
|
||||
public function getAdmin()
|
||||
{
|
||||
return $this->admin;
|
||||
return $this->orderDelivery->getAdmin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
* @return int
|
||||
* @deprecated Use OrderDeliveryEvent::getDelivery() to read quantity.
|
||||
*/
|
||||
public function getQuantity()
|
||||
{
|
||||
return $this->quantity;
|
||||
return $this->orderDelivery->getQuantity();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -11,30 +11,42 @@
|
||||
|
||||
namespace Alchemy\Phrasea\Core\Event\Subscriber;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Core\Event\OrderDeliveryEvent;
|
||||
use Alchemy\Phrasea\Core\Event\OrderEvent;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\OrderElement;
|
||||
use Alchemy\Phrasea\Notification\Emitter;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoNewOrder;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoOrderCancelled;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoOrderDelivered;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier\CompositeNotifier;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifierRegistry;
|
||||
|
||||
class OrderSubscriber extends AbstractNotificationSubscriber
|
||||
{
|
||||
/**
|
||||
* @var ValidationNotifierRegistry
|
||||
*/
|
||||
private $notifierRegistry;
|
||||
|
||||
/**
|
||||
* @param Application $application
|
||||
* @param ValidationNotifierRegistry $notifierRegistry
|
||||
*/
|
||||
public function __construct(Application $application, ValidationNotifierRegistry $notifierRegistry)
|
||||
{
|
||||
parent::__construct($application);
|
||||
|
||||
$this->notifierRegistry = $notifierRegistry;
|
||||
}
|
||||
|
||||
public function onCreate(OrderEvent $event)
|
||||
{
|
||||
$params = [
|
||||
'usr_id' => $event->getOrder()->getUser()->getId(),
|
||||
'order_id' => $event->getOrder()->getId(),
|
||||
];
|
||||
|
||||
$base_ids = array_unique(array_map(function (OrderElement $element) {
|
||||
return $element->getBaseId();
|
||||
}, iterator_to_array($event->getOrder()->getElements())));
|
||||
|
||||
$query = $this->app['phraseanet.user-query'];
|
||||
/** @var User[] $users */
|
||||
$users = $query->on_base_ids($base_ids)
|
||||
->who_have_right(['order_master'])
|
||||
->execute()->get_results();
|
||||
@@ -43,99 +55,80 @@ class OrderSubscriber extends AbstractNotificationSubscriber
|
||||
return;
|
||||
}
|
||||
|
||||
$datas = json_encode($params);
|
||||
$notificationData = json_encode([
|
||||
'usr_id' => $event->getOrder()->getUser()->getId(),
|
||||
'order_id' => $event->getOrder()->getId(),
|
||||
]);
|
||||
|
||||
$orderInitiator = $event->getOrder()->getUser();
|
||||
$notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod());
|
||||
|
||||
$notifier->notifyCreation($event->getOrder(), $event->getOrder()->getUser());
|
||||
|
||||
$notifier = $this->notifierRegistry->getNotifier(Order::NOTIFY_MAIL);
|
||||
|
||||
foreach ($users as $user) {
|
||||
$mailed = false;
|
||||
$notified = false;
|
||||
|
||||
if ($this->shouldSendNotificationFor($user, 'eventsmanager_notify_order')) {
|
||||
try {
|
||||
$receiver = Receiver::fromUser($user);
|
||||
$notifier->notifyCreation($event->getOrder(), $user);
|
||||
} catch (\Exception $e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mail = MailInfoNewOrder::create($this->app, $receiver);
|
||||
$mail->setUser($orderInitiator);
|
||||
|
||||
$this->deliver($mail);
|
||||
$mailed = true;
|
||||
$notified = true;
|
||||
}
|
||||
|
||||
$this->app['events-manager']->notify($user->getId(), 'eventsmanager_notify_order', $datas, $mailed);
|
||||
$this->app['events-manager']->notify($user->getId(), 'eventsmanager_notify_order', $notificationData, $notified);
|
||||
}
|
||||
}
|
||||
|
||||
public function onDeliver(OrderDeliveryEvent $event)
|
||||
{
|
||||
$params = [
|
||||
'from' => $event->getAdmin()->getId(),
|
||||
$notified = false;
|
||||
$notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod());
|
||||
$notificationData = json_encode([
|
||||
'from' => $event->getDelivery()->getAdmin()->getId(),
|
||||
'to' => $event->getOrder()->getUser()->getId(),
|
||||
'ssel_id' => $event->getOrder()->getBasket()->getId(),
|
||||
'n' => $event->getQuantity(),
|
||||
];
|
||||
|
||||
$datas = json_encode($params);
|
||||
|
||||
$mailed = false;
|
||||
'n' => $event->getDelivery()->getQuantity()
|
||||
]);
|
||||
|
||||
if ($this->shouldSendNotificationFor($event->getOrder()->getUser(), 'eventsmanager_notify_orderdeliver')) {
|
||||
$user_from = $event->getAdmin();
|
||||
$user_to = $event->getOrder()->getUser();
|
||||
|
||||
$receiver = Receiver::fromUser($event->getOrder()->getUser());
|
||||
$emitter = Emitter::fromUser($event->getAdmin());
|
||||
|
||||
$basket = $event->getOrder()->getBasket();
|
||||
|
||||
$url = $this->app->url('lightbox_compare', [
|
||||
'basket' => $basket->getId(),
|
||||
'LOG' => $this->app['manipulator.token']->createBasketAccessToken($basket, $user_to)->getValue(),
|
||||
]);
|
||||
|
||||
$mail = MailInfoOrderDelivered::create($this->app, $receiver, $emitter, null);
|
||||
$mail->setButtonUrl($url);
|
||||
$mail->setBasket($basket);
|
||||
$mail->setDeliverer($user_from);
|
||||
|
||||
$this->deliver($mail);
|
||||
$mailed = true;
|
||||
$notifier->notifyDelivery($event->getDelivery());
|
||||
$notified = true;
|
||||
}
|
||||
|
||||
return $this->app['events-manager']->notify($params['to'], 'eventsmanager_notify_orderdeliver', $datas, $mailed);
|
||||
return $this->app['events-manager']->notify(
|
||||
$event->getOrder()->getUser()->getId(),
|
||||
'eventsmanager_notify_orderdeliver',
|
||||
$notificationData,
|
||||
$notified
|
||||
);
|
||||
}
|
||||
|
||||
public function onDeny(OrderDeliveryEvent $event)
|
||||
{
|
||||
$params = [
|
||||
'from' => $event->getAdmin()->getId(),
|
||||
$notified = false;
|
||||
$notifier = $this->notifierRegistry->getNotifier($event->getOrder()->getNotificationMethod());
|
||||
$notificationData = json_encode([
|
||||
'from' => $event->getDelivery()->getAdmin()->getId(),
|
||||
'to' => $event->getOrder()->getUser()->getId(),
|
||||
'n' => $event->getQuantity(),
|
||||
];
|
||||
'n' => $event->getDelivery()->getQuantity()
|
||||
]);
|
||||
|
||||
$datas = json_encode($params);
|
||||
|
||||
$mailed = false;
|
||||
|
||||
if ($this->shouldSendNotificationFor($event->getOrder()->getUser(), 'eventsmanager_notify_ordernotdelivered')) {
|
||||
$user_from = $event->getAdmin();
|
||||
$user_to = $event->getOrder()->getUser();
|
||||
|
||||
$receiver = Receiver::fromUser($user_to);
|
||||
$emitter = Emitter::fromUser($user_from);
|
||||
|
||||
$mail = MailInfoOrderCancelled::create($this->app, $receiver, $emitter);
|
||||
$mail->setQuantity($params['n']);
|
||||
$mail->setDeliverer($user_from);
|
||||
|
||||
$this->deliver($mail);
|
||||
|
||||
$mailed = true;
|
||||
$notifier->notifyDenial($event->getDelivery());
|
||||
$notified = true;
|
||||
}
|
||||
|
||||
return $this->app['events-manager']->notify($params['to'], 'eventsmanager_notify_ordernotdelivered', $datas, $mailed);
|
||||
return $this->app['events-manager']->notify(
|
||||
$event->getOrder()->getUser()->getId(),
|
||||
'eventsmanager_notify_ordernotdelivered',
|
||||
$notificationData,
|
||||
$notified
|
||||
);
|
||||
}
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
|
@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\Core\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Helper\JsonBodyHelper;
|
||||
use JsonSchema\RefResolver;
|
||||
use JsonSchema\Uri\UriResolver;
|
||||
use JsonSchema\Uri\UriRetriever;
|
||||
use JsonSchema\Validator;
|
||||
use Silex\Application;
|
||||
@@ -31,7 +32,7 @@ class JsonSchemaServiceProvider implements ServiceProviderInterface
|
||||
});
|
||||
|
||||
$app['json-schema.ref_resolver'] = $app->share(function (Application $app) {
|
||||
return new RefResolver($app['json-schema.retriever']);
|
||||
return new RefResolver($app['json-schema.retriever'], new UriResolver());
|
||||
});
|
||||
|
||||
$app['json-schema.validator'] = $app->share(function (Application $app) {
|
||||
|
57
lib/Alchemy/Phrasea/Core/Provider/OrderServiceProvider.php
Normal file
57
lib/Alchemy/Phrasea/Core/Provider/OrderServiceProvider.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of alchemy/pipeline-component.
|
||||
*
|
||||
* (c) Alchemy <info@alchemy.fr>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Core\Provider;
|
||||
|
||||
use Alchemy\Phrasea\Controller\LazyLocator;
|
||||
use Alchemy\Phrasea\Core\Event\Subscriber\OrderSubscriber;
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier\MailNotifier;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier\WebhookNotifier;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifierRegistry;
|
||||
use Silex\Application;
|
||||
use Silex\ServiceProviderInterface;
|
||||
|
||||
class OrderServiceProvider implements ServiceProviderInterface
|
||||
{
|
||||
|
||||
/**
|
||||
* Registers services on the given app.
|
||||
*
|
||||
* This method should only be used to configure services and parameters.
|
||||
* It should not get services.
|
||||
*/
|
||||
public function register(Application $app)
|
||||
{
|
||||
$app['events.order_subscriber'] = $app->share(function (Application $app) {
|
||||
$notifierRegistry = new ValidationNotifierRegistry();
|
||||
|
||||
$notifierRegistry->registerNotifier(Order::NOTIFY_MAIL, new MailNotifier($app));
|
||||
$notifierRegistry->registerNotifier(Order::NOTIFY_WEBHOOK, new WebhookNotifier(
|
||||
new LazyLocator($app, 'manipulator.webhook-event')
|
||||
));
|
||||
|
||||
return new OrderSubscriber($app, $notifierRegistry);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstraps the application.
|
||||
*
|
||||
* This method is called after all services are registered
|
||||
* and should be used for "dynamic" configuration (whenever
|
||||
* a service must be requested).
|
||||
*/
|
||||
public function boot(Application $app)
|
||||
{
|
||||
$app['dispatcher']->addSubscriber($app['events.order_subscriber']);
|
||||
}
|
||||
}
|
@@ -16,7 +16,7 @@ class Version
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $number = '4.0.0-alpha.6';
|
||||
private $number = '4.0.0-alpha.8';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
|
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Phraseanet
|
||||
*
|
||||
@@ -7,6 +8,7 @@
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Alchemy\Phrasea\Databox;
|
||||
|
||||
interface DataboxRepository
|
||||
|
@@ -52,11 +52,7 @@ class JsonBodyHelper
|
||||
*/
|
||||
public function retrieveSchema($schemaUri)
|
||||
{
|
||||
$schema = $this->uriRetriever->retrieve($schemaUri, $this->baseUri);
|
||||
|
||||
$this->refResolver->resolve($schema);
|
||||
|
||||
return $schema;
|
||||
return $this->refResolver->resolve($this->baseUri . $schemaUri);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -33,7 +33,7 @@ class FeedEntry
|
||||
private $title;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=128)
|
||||
* @ORM\Column(type="string", length=1024)
|
||||
*/
|
||||
private $subtitle;
|
||||
|
||||
|
@@ -20,12 +20,17 @@ use Gedmo\Mapping\Annotation as Gedmo;
|
||||
*/
|
||||
class Order
|
||||
{
|
||||
|
||||
const NOTIFY_MAIL = 'mail';
|
||||
|
||||
const NOTIFY_WEBHOOK = 'webhook';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
* @ORM\GeneratedValue
|
||||
*/
|
||||
private $id;
|
||||
private $id;
|
||||
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="User")
|
||||
@@ -67,12 +72,18 @@ class Order
|
||||
*/
|
||||
private $basket;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=32, name="notification_method")
|
||||
*/
|
||||
private $notificationMethod;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->elements = new ArrayCollection();
|
||||
$this->notificationMethod = self::NOTIFY_MAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,4 +291,28 @@ class Order
|
||||
{
|
||||
return $this->basket;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The name of the notification method that will be used to handle this order's status change
|
||||
* notifications.
|
||||
*/
|
||||
public function getNotificationMethod()
|
||||
{
|
||||
return $this->notificationMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the notification method to handle this order's status change
|
||||
* notifications.
|
||||
* @param string $methodName
|
||||
* @return void
|
||||
*/
|
||||
public function setNotificationMethod($methodName)
|
||||
{
|
||||
if (trim($methodName) == '') {
|
||||
$methodName = self::NOTIFY_MAIL;
|
||||
}
|
||||
|
||||
$this->notificationMethod = $methodName;
|
||||
}
|
||||
}
|
||||
|
@@ -26,6 +26,11 @@ class WebhookEvent
|
||||
const RECORD_SUBDEFS_CREATED = 'record.subdefs.created';
|
||||
const RECORD_SUBDEF_TYPE = 'record.subdef';
|
||||
|
||||
const ORDER_TYPE = 'order';
|
||||
const ORDER_CREATED = 'order.created';
|
||||
const ORDER_DELIVERED = 'order.delivered';
|
||||
const ORDER_DENIED = 'order.denied';
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\Id
|
||||
|
@@ -41,11 +41,13 @@ class OrderRepository extends EntityRepository
|
||||
public function listOrders($baseIds, $offsetStart = 0, $perPage = 20, $sort = "created_on")
|
||||
{
|
||||
$qb = $this
|
||||
->createQueryBuilder('o')
|
||||
->innerJoin('o.elements', 'e');
|
||||
->createQueryBuilder('o');
|
||||
|
||||
if (!empty($baseIds)) {
|
||||
$qb->where($qb->expr()->in('e.baseId', $baseIds));
|
||||
$qb
|
||||
->innerJoin('o.elements', 'e')
|
||||
->where($qb->expr()->in('e.baseId', $baseIds))
|
||||
->groupBy('o.id');
|
||||
}
|
||||
|
||||
if ($sort === 'user') {
|
||||
@@ -53,7 +55,7 @@ class OrderRepository extends EntityRepository
|
||||
} elseif ($sort === 'usage') {
|
||||
$qb->orderBy('o.orderUsage', 'ASC');
|
||||
} else {
|
||||
$qb->orderBy('o.createdOn', 'ASC');
|
||||
$qb->orderBy('o.createdOn', 'DESC');
|
||||
}
|
||||
|
||||
$qb
|
||||
|
@@ -16,9 +16,20 @@ use Alchemy\Phrasea\Model\Entities\User;
|
||||
|
||||
class Emitter implements EmitterInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $name;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $email;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $email
|
||||
*/
|
||||
public function __construct($name, $email)
|
||||
{
|
||||
if (!\Swift_Validate::email($email)) {
|
||||
|
@@ -194,7 +194,7 @@ abstract class AbstractMail implements MailInterface
|
||||
* @param EmitterInterface $emitter
|
||||
* @param string $message
|
||||
*
|
||||
* @return MailInterface
|
||||
* @return static
|
||||
*/
|
||||
public static function create(Application $app, ReceiverInterface $receiver, EmitterInterface $emitter = null, $message = null)
|
||||
{
|
||||
|
@@ -10,24 +10,23 @@
|
||||
|
||||
namespace Alchemy\Phrasea\Order\Controller;
|
||||
|
||||
use Alchemy\Phrasea\Application\Helper\DelivererAware;
|
||||
use Alchemy\Phrasea\Application\Helper\FilesystemAware;
|
||||
use Alchemy\Phrasea\Application\Helper\JsonBodyAware;
|
||||
use Alchemy\Phrasea\Controller\Api\Result;
|
||||
use Alchemy\Phrasea\Controller\RecordsRequest;
|
||||
use Alchemy\Phrasea\Core\Event\ExportEvent;
|
||||
use Alchemy\Phrasea\Core\Event\OrderEvent;
|
||||
use Alchemy\Phrasea\Core\PhraseaEvents;
|
||||
use Alchemy\Phrasea\Http\DeliverDataInterface;
|
||||
use Alchemy\Phrasea\Model\Entities\Basket;
|
||||
use Alchemy\Phrasea\Model\Entities\BasketElement;
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\OrderElement;
|
||||
use Alchemy\Phrasea\Model\RecordReferenceInterface;
|
||||
use Alchemy\Phrasea\Order\OrderElementTransformer;
|
||||
use Alchemy\Phrasea\Order\OrderElementView;
|
||||
use Alchemy\Phrasea\Order\OrderFiller;
|
||||
use Alchemy\Phrasea\Order\OrderTransformer;
|
||||
use Alchemy\Phrasea\Order\OrderView;
|
||||
use Alchemy\Phrasea\Order\OrderViewBuilder;
|
||||
use Alchemy\Phrasea\Record\RecordReference;
|
||||
use Alchemy\Phrasea\Record\RecordReferenceCollection;
|
||||
use Assert\Assertion;
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
use League\Fractal\Manager;
|
||||
use League\Fractal\Pagination\PagerfantaPaginatorAdapter;
|
||||
@@ -39,9 +38,12 @@ use Pagerfanta\Pagerfanta;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
|
||||
class ApiOrderController extends BaseOrderController
|
||||
{
|
||||
use DelivererAware;
|
||||
use FilesystemAware;
|
||||
use JsonBodyAware;
|
||||
|
||||
public function createAction(Request $request)
|
||||
@@ -61,6 +63,7 @@ class ApiOrderController extends BaseOrderController
|
||||
$order->setUser($this->getAuthenticatedUser());
|
||||
$order->setDeadline(new \DateTime($data->data->deadline, new \DateTimeZone('UTC')));
|
||||
$order->setOrderUsage($data->data->usage);
|
||||
$order->setNotificationMethod(Order::NOTIFY_WEBHOOK);
|
||||
|
||||
$filler->fillOrder($order, $recordRequest);
|
||||
|
||||
@@ -124,7 +127,7 @@ class ApiOrderController extends BaseOrderController
|
||||
|
||||
$fractal = $this->buildFractalManager($request->get('includes', []));
|
||||
|
||||
if ($order->getUser()->getId() !== $this->getAuthenticatedUser()->getId()) {
|
||||
if (! $this->isOrderAccessible($order)) {
|
||||
throw new AccessDeniedHttpException(sprintf('Cannot access order "%d"', $order->getId()));
|
||||
}
|
||||
|
||||
@@ -134,6 +137,54 @@ class ApiOrderController extends BaseOrderController
|
||||
return $this->returnResourceResponse($request, $fractal, $resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param int $orderId
|
||||
* @return Response
|
||||
*/
|
||||
public function getArchiveAction(Request $request, $orderId)
|
||||
{
|
||||
$order = $this->findOr404($orderId);
|
||||
|
||||
if (! $this->isOrderAccessible($order)) {
|
||||
throw new AccessDeniedHttpException(sprintf('Cannot access order "%d"', $order->getId()));
|
||||
}
|
||||
|
||||
$basket = $order->getBasket();
|
||||
|
||||
if (null === $basket instanceof Basket) {
|
||||
throw new NotFoundHttpException(sprintf('No archive could be downloaded for Order "%d"', $order->getId()));
|
||||
}
|
||||
|
||||
$export = new \set_export($this->app, '', $basket->getId());
|
||||
$exportName = sprintf('%s/%s.zip', $this->app['tmp.download.path'], $export->getExportName());
|
||||
|
||||
$user = $this->getAuthenticatedUser();
|
||||
|
||||
$subdefs = $this->findDataboxSubdefNames();
|
||||
|
||||
$exportData = $export->prepare_export($user, $this->getFilesystem(), $subdefs, true, true);
|
||||
$exportData['export_name'] = $exportName;
|
||||
|
||||
$token = $this->app['manipulator.token']->createDownloadToken($user, serialize($exportData));
|
||||
$lst = [];
|
||||
|
||||
foreach ($exportData['files'] as $file) {
|
||||
$lst[] = $this->getApplicationBox()->get_collection($file['base_id'])->get_databox()->get_sbas_id() . '_' . $file['record_id'];
|
||||
}
|
||||
|
||||
$this->dispatch(
|
||||
PhraseaEvents::EXPORT_CREATE,
|
||||
new ExportEvent($user, $basket->getId(), implode(';', $lst), $subdefs, $exportName)
|
||||
);
|
||||
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
$file = \set_export::build_zip($this->app, $token, $exportData, $exportName);
|
||||
|
||||
return $this->deliverFile($file, $exportName, DeliverDataInterface::DISPOSITION_INLINE, 'application/zip');
|
||||
}
|
||||
|
||||
public function acceptElementsAction(Request $request, $orderId)
|
||||
{
|
||||
$elementIds = $this->fetchElementIdsFromRequest($request);
|
||||
@@ -258,4 +309,42 @@ class ApiOrderController extends BaseOrderController
|
||||
$this->app['service.media_subdef']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $order
|
||||
* @return bool
|
||||
*/
|
||||
private function isOrderAccessible(Order $order)
|
||||
{
|
||||
if ($order->getUser()->getId() === $this->getAuthenticatedUser()->getId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($order->getUser()->isAdmin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string[]
|
||||
*/
|
||||
private function findDataboxSubdefNames()
|
||||
{
|
||||
$subdefNames = [
|
||||
'document' => true,
|
||||
];
|
||||
|
||||
foreach ($this->getApplicationBox()->get_databoxes() as $databox) {
|
||||
foreach ($databox->get_subdef_structure() as $subdefGroup) {
|
||||
/** @var \databox_subdef $subdef */
|
||||
foreach ($subdefGroup as $subdef) {
|
||||
$subdefNames[$subdef->get_name()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_keys($subdefNames);
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ use Alchemy\Phrasea\Model\Entities\OrderElement;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Repositories\OrderElementRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\OrderRepository;
|
||||
use Alchemy\Phrasea\Order\OrderDelivery;
|
||||
use Alchemy\Phrasea\Order\OrderValidator;
|
||||
use Alchemy\Phrasea\Order\PartialOrder;
|
||||
use Alchemy\Phrasea\Record\RecordReference;
|
||||
@@ -136,7 +137,9 @@ class BaseOrderController extends Controller
|
||||
$manager->persist($element);
|
||||
}
|
||||
|
||||
$this->dispatch(PhraseaEvents::ORDER_DELIVER, new OrderDeliveryEvent($order, $acceptor, count($basketElements)));
|
||||
$delivery = new OrderDelivery($order, $acceptor, count($basketElements));
|
||||
|
||||
$this->dispatch(PhraseaEvents::ORDER_DELIVER, new OrderDeliveryEvent($delivery));
|
||||
}
|
||||
|
||||
$manager->persist($basket);
|
||||
@@ -164,7 +167,9 @@ class BaseOrderController extends Controller
|
||||
|
||||
try {
|
||||
if (!empty($elements)) {
|
||||
$this->dispatch(PhraseaEvents::ORDER_DENY, new OrderDeliveryEvent($order, $acceptor, count($elements)));
|
||||
$delivery = new OrderDelivery($order, $acceptor, count($elements));
|
||||
|
||||
$this->dispatch(PhraseaEvents::ORDER_DENY, new OrderDeliveryEvent($delivery));
|
||||
}
|
||||
|
||||
$manager = $this->getEntityManager();
|
||||
@@ -189,7 +194,7 @@ class BaseOrderController extends Controller
|
||||
|
||||
$basketReferences = new RecordReferenceCollection();
|
||||
|
||||
$basket->getElements()->forAll(function (BasketElement $element) use ($basketReferences) {
|
||||
$basket->getElements()->forAll(function ($index, BasketElement $element) use ($basketReferences) {
|
||||
$basketReferences->addRecordReference($element->getSbasId(), $element->getRecordId());
|
||||
});
|
||||
|
||||
|
@@ -100,8 +100,13 @@ class ProdOrderController extends BaseOrderController
|
||||
public function displayOrders(Request $request)
|
||||
{
|
||||
$page = (int) $request->query->get('page', 1);
|
||||
$offsetStart = $page - 1;
|
||||
$perPage = (int) $request->query->get('per-page', 10);
|
||||
$offsetStart = 0;
|
||||
|
||||
if ($page > 0) {
|
||||
$offsetStart = ($page - 1) * $perPage;
|
||||
}
|
||||
|
||||
$sort = $request->query->get('sort');
|
||||
|
||||
$baseIds = array_keys($this->getAclForUser()->get_granted_base(['order_master']));
|
||||
|
69
lib/Alchemy/Phrasea/Order/OrderDelivery.php
Normal file
69
lib/Alchemy/Phrasea/Order/OrderDelivery.php
Normal file
@@ -0,0 +1,69 @@
|
||||
<?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\Order;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
|
||||
class OrderDelivery
|
||||
{
|
||||
/**
|
||||
* @var User
|
||||
*/
|
||||
private $admin;
|
||||
|
||||
/**
|
||||
* @var Order
|
||||
*/
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $quantity;
|
||||
|
||||
/**
|
||||
* @param Order $deliveredOrder
|
||||
* @param User $manager
|
||||
* @param int $quantity
|
||||
*/
|
||||
public function __construct(Order $deliveredOrder, User $manager, $quantity)
|
||||
{
|
||||
$this->order = $deliveredOrder;
|
||||
$this->admin = $manager;
|
||||
$this->quantity = $quantity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getAdmin()
|
||||
{
|
||||
return $this->admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Order
|
||||
*/
|
||||
public function getOrder()
|
||||
{
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getQuantity()
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
}
|
@@ -77,6 +77,7 @@ class OrderElementView
|
||||
|
||||
/**
|
||||
* @param \media_subdef[] $subdefs
|
||||
* @return void
|
||||
*/
|
||||
public function setOrderableMediaSubdefs($subdefs)
|
||||
{
|
||||
|
@@ -37,9 +37,13 @@ class OrderTransformer extends TransformerAbstract
|
||||
'owner_id' => (int)$order->getUser()->getId(),
|
||||
'created' => $order->getCreatedOn()->format(DATE_ATOM),
|
||||
'usage' => $order->getOrderUsage(),
|
||||
'status' => 0 === $order->getTodo() ? 'finished' : 'pending'
|
||||
'status' => 0 === $order->getTodo() ? 'finished' : 'pending',
|
||||
];
|
||||
|
||||
if ($view->getArchiveUrl()) {
|
||||
$data['archive_url'] = $view->getArchiveUrl();
|
||||
}
|
||||
|
||||
if ($order->getDeadline()) {
|
||||
$data['deadline'] = $order->getDeadline()->format(DATE_ATOM);
|
||||
}
|
||||
|
@@ -20,6 +20,11 @@ class OrderView
|
||||
*/
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $archiveUrl;
|
||||
|
||||
/**
|
||||
* @var OrderElementView[]
|
||||
*/
|
||||
@@ -43,6 +48,14 @@ class OrderView
|
||||
$this->viewElements = $viewElements instanceof \Traversable ? iterator_to_array($viewElements) : $viewElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $archiveUrl
|
||||
*/
|
||||
public function setArchiveUrl($archiveUrl)
|
||||
{
|
||||
$this->archiveUrl = (string)$archiveUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Order
|
||||
*/
|
||||
@@ -51,6 +64,14 @@ class OrderView
|
||||
return $this->order;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getArchiveUrl()
|
||||
{
|
||||
return $this->archiveUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return OrderElementView[]
|
||||
*/
|
||||
|
@@ -84,6 +84,21 @@ class OrderViewBuilder
|
||||
*/
|
||||
private function fillViews(array $views, array $includes)
|
||||
{
|
||||
array_walk($views, function (OrderView $view) {
|
||||
// Archive is only available when a Basket is associated with the order (at least one element was accepted)
|
||||
if (null === $basket = $view->getOrder()->getBasket()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($basket->getElements()->isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$view->setArchiveUrl($this->application->url('api_v2_orders_archive', [
|
||||
'orderId' => $view->getOrder()->getId(),
|
||||
]));
|
||||
});
|
||||
|
||||
if (!in_array('elements', $includes, true)) {
|
||||
return;
|
||||
}
|
||||
|
38
lib/Alchemy/Phrasea/Order/ValidationNotifier.php
Normal file
38
lib/Alchemy/Phrasea/Order/ValidationNotifier.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?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\Order;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
|
||||
interface ValidationNotifier
|
||||
{
|
||||
/**
|
||||
* @param Order $order
|
||||
* @param User $recipient
|
||||
* @return void
|
||||
*/
|
||||
public function notifyCreation(Order $order, User $recipient);
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
* @return void
|
||||
*/
|
||||
public function notifyDelivery(OrderDelivery $delivery);
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
* @return void
|
||||
*/
|
||||
public function notifyDenial(OrderDelivery $delivery);
|
||||
|
||||
}
|
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Order\ValidationNotifier;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Order\OrderDelivery;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier;
|
||||
use Assert\Assertion;
|
||||
|
||||
class CompositeNotifier implements ValidationNotifier
|
||||
{
|
||||
|
||||
/**
|
||||
* @var ValidationNotifier[]
|
||||
*/
|
||||
private $notifiers = [];
|
||||
|
||||
public function __construct(array $notifiers)
|
||||
{
|
||||
Assertion::allIsInstanceOf($notifiers, ValidationNotifier::class);
|
||||
|
||||
$this->notifiers = $notifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Order $order
|
||||
* @param User $recipient
|
||||
*/
|
||||
public function notifyCreation(Order $order, User $recipient)
|
||||
{
|
||||
foreach ($this->notifiers as $notifier) {
|
||||
$notifier->notifyCreation($order, $recipient);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDelivery(OrderDelivery $delivery)
|
||||
{
|
||||
foreach ($this->notifiers as $notifier) {
|
||||
$notifier->notifyDelivery($delivery);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDenial(OrderDelivery $delivery)
|
||||
{
|
||||
foreach ($this->notifiers as $notifier) {
|
||||
$notifier->notifyDenial($delivery);
|
||||
}
|
||||
}
|
||||
}
|
101
lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php
Normal file
101
lib/Alchemy/Phrasea/Order/ValidationNotifier/MailNotifier.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?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\Order\ValidationNotifier;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Notification\Deliverer;
|
||||
use Alchemy\Phrasea\Notification\Emitter;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoNewOrder;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoOrderCancelled;
|
||||
use Alchemy\Phrasea\Notification\Mail\MailInfoOrderDelivered;
|
||||
use Alchemy\Phrasea\Notification\Receiver;
|
||||
use Alchemy\Phrasea\Order\OrderDelivery;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier;
|
||||
|
||||
class MailNotifier implements ValidationNotifier
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
private $application;
|
||||
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Deliverer
|
||||
*/
|
||||
private function getDeliverer()
|
||||
{
|
||||
return $this->application['notification.deliverer'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Order $order
|
||||
* @param User $recipient
|
||||
*/
|
||||
public function notifyCreation(Order $order, User $recipient)
|
||||
{
|
||||
$mail = MailInfoNewOrder::create($this->application, Receiver::fromUser($recipient));
|
||||
|
||||
$mail->setUser($order->getUser());
|
||||
|
||||
$this->getDeliverer()->deliver($mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDelivery(OrderDelivery $delivery)
|
||||
{
|
||||
$order = $delivery->getOrder();
|
||||
|
||||
$recipient = Receiver::fromUser($order->getUser());
|
||||
$sender = Emitter::fromUser($delivery->getAdmin());
|
||||
|
||||
$basket = $order->getBasket();
|
||||
$token = $this->application['manipulator.token']->createBasketAccessToken($basket, $order->getUser());
|
||||
|
||||
$url = $this->application->url('lightbox_compare', [
|
||||
'basket' => $basket->getId(),
|
||||
'LOG' => $token->getValue(),
|
||||
]);
|
||||
|
||||
$mail = MailInfoOrderDelivered::create($this->application, $recipient, $sender, null);
|
||||
|
||||
$mail->setButtonUrl($url);
|
||||
$mail->setBasket($basket);
|
||||
$mail->setDeliverer($delivery->getAdmin());
|
||||
|
||||
$this->getDeliverer()->deliver($mail);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDenial(OrderDelivery $delivery)
|
||||
{
|
||||
$sender = Emitter::fromUser($delivery->getAdmin());
|
||||
$recipient = Receiver::fromUser($delivery->getOrder()->getUser());
|
||||
|
||||
$mail = MailInfoOrderCancelled::create($this->application, $recipient, $sender);
|
||||
|
||||
$mail->setQuantity($delivery->getQuantity());
|
||||
$mail->setDeliverer($delivery->getAdmin());
|
||||
|
||||
$this->getDeliverer()->deliver($mail);
|
||||
}
|
||||
}
|
@@ -0,0 +1,88 @@
|
||||
<?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\Order\ValidationNotifier;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Entities\WebhookEvent;
|
||||
use Alchemy\Phrasea\Model\Manipulator\WebhookEventManipulator;
|
||||
use Alchemy\Phrasea\Order\OrderDelivery;
|
||||
use Alchemy\Phrasea\Order\ValidationNotifier;
|
||||
|
||||
class WebhookNotifier implements ValidationNotifier
|
||||
{
|
||||
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $webhookManipulatorLocator;
|
||||
|
||||
/**
|
||||
* @param callable $webhookEventManipulatorLocator
|
||||
*/
|
||||
public function __construct($webhookEventManipulatorLocator)
|
||||
{
|
||||
$this->webhookManipulatorLocator = $webhookEventManipulatorLocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WebhookEventManipulator
|
||||
*/
|
||||
private function getManipulator()
|
||||
{
|
||||
$factory = $this->webhookManipulatorLocator;
|
||||
|
||||
return $factory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Order $order
|
||||
* @param User $recipient
|
||||
*/
|
||||
public function notifyCreation(Order $order, User $recipient)
|
||||
{
|
||||
$eventData = [
|
||||
'order_id' => $order->getId(),
|
||||
'user_id' => $recipient->getId(),
|
||||
];
|
||||
|
||||
$this->getManipulator()->create(WebhookEvent::ORDER_CREATED, WebhookEvent::ORDER_TYPE, $eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDelivery(OrderDelivery $delivery)
|
||||
{
|
||||
$eventData = [
|
||||
'order_id' => $delivery->getOrder()->getId(),
|
||||
'admin_id' => $delivery->getAdmin()->getId(),
|
||||
'quantity' => $delivery->getQuantity()
|
||||
];
|
||||
|
||||
$this->getManipulator()->create(WebhookEvent::ORDER_DELIVERED, WebhookEvent::ORDER_TYPE, $eventData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OrderDelivery $delivery
|
||||
*/
|
||||
public function notifyDenial(OrderDelivery $delivery)
|
||||
{
|
||||
$eventData = [
|
||||
'order_id' => $delivery->getOrder()->getId(),
|
||||
'admin_id' => $delivery->getAdmin()->getId(),
|
||||
'quantity' => $delivery->getQuantity()
|
||||
];
|
||||
|
||||
$this->getManipulator()->create(WebhookEvent::ORDER_DENIED, WebhookEvent::ORDER_TYPE, $eventData);
|
||||
}
|
||||
}
|
44
lib/Alchemy/Phrasea/Order/ValidationNotifierRegistry.php
Normal file
44
lib/Alchemy/Phrasea/Order/ValidationNotifierRegistry.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?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\Order;
|
||||
|
||||
use Alchemy\Phrasea\Exception\InvalidArgumentException;
|
||||
|
||||
class ValidationNotifierRegistry
|
||||
{
|
||||
/**
|
||||
* @var ValidationNotifier[]
|
||||
*/
|
||||
private $notifiers = [];
|
||||
|
||||
/**
|
||||
* @param string $notificationMethodName
|
||||
* @param ValidationNotifier $notifier
|
||||
*/
|
||||
public function registerNotifier($notificationMethodName, ValidationNotifier $notifier)
|
||||
{
|
||||
$this->notifiers[$notificationMethodName] = $notifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $notificationMethodName
|
||||
* @return ValidationNotifier
|
||||
*/
|
||||
public function getNotifier($notificationMethodName)
|
||||
{
|
||||
if (! isset($this->notifiers[$notificationMethodName])) {
|
||||
throw new InvalidArgumentException(sprintf('Undefined notifier for method: %s', $notificationMethodName));
|
||||
}
|
||||
|
||||
return $this->notifiers[$notificationMethodName];
|
||||
}
|
||||
}
|
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Setup\DoctrineMigrations;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration as BaseMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
class Version20160511160640 extends BaseMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql(sprintf("ALTER TABLE Orders ADD COLUMN notification_method VARCHAR(32) NOT NULL DEFAULT '%s'", Order::NOTIFY_MAIL));
|
||||
$this->addSql("ALTER TABLE Orders ALTER COLUMN notification_method DROP DEFAULT");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql("ALTER TABLE Orders DROP COLUMN notification_method");
|
||||
}
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Setup\DoctrineMigrations;
|
||||
|
||||
use Doctrine\DBAL\Migrations\AbstractMigration as BaseMigration;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
class Version20160520165600 extends BaseMigration
|
||||
{
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function up(Schema $schema)
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE FeedEntries CHANGE subtitle subtitle VARCHAR(1024) NOT NULL');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Schema $schema
|
||||
*/
|
||||
public function down(Schema $schema)
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.');
|
||||
|
||||
$this->addSql('ALTER TABLE FeedEntries CHANGE subtitle subtitle VARCHAR(128) NOT NULL COLLATE utf8_unicode_ci');
|
||||
}
|
||||
}
|
@@ -19,6 +19,7 @@ use Alchemy\Phrasea\TaskManager\Editor\DefaultEditor;
|
||||
use Alchemy\Phrasea\Webhook\EventProcessorFactory;
|
||||
use Guzzle\Http\Client as GuzzleClient;
|
||||
use Guzzle\Batch\BatchBuilder;
|
||||
use Guzzle\Http\Message\Request;
|
||||
use Silex\Application;
|
||||
use Guzzle\Common\Event;
|
||||
use Guzzle\Plugin\Backoff\BackoffPlugin;
|
||||
@@ -33,6 +34,8 @@ class WebhookJob extends AbstractJob
|
||||
{
|
||||
private $httpClient;
|
||||
|
||||
private $firstRun = true;
|
||||
|
||||
public function __construct(
|
||||
TranslatorInterface $translator,
|
||||
EventDispatcherInterface $dispatcher = null,
|
||||
@@ -88,37 +91,55 @@ class WebhookJob extends AbstractJob
|
||||
$thirdPartyApplications = $app['repo.api-applications']->findWithDefinedWebhookCallback();
|
||||
$that = $this;
|
||||
|
||||
$this->httpClient->getEventDispatcher()->addListener('request.error', function (Event $event) {
|
||||
// override guzzle default behavior of throwing exceptions
|
||||
// when 4xx & 5xx responses are encountered
|
||||
$event->stopPropagation();
|
||||
}, -254);
|
||||
if ($this->firstRun) {
|
||||
$this->httpClient->getEventDispatcher()->addListener('request.error', function (Event $event) {
|
||||
// override guzzle default behavior of throwing exceptions
|
||||
// when 4xx & 5xx responses are encountered
|
||||
$event->stopPropagation();
|
||||
}, -254);
|
||||
|
||||
$this->httpClient->addSubscriber(new BackoffPlugin(
|
||||
// set max retries
|
||||
new TruncatedBackoffStrategy(WebhookEventDelivery::MAX_DELIVERY_TRIES,
|
||||
// set callback which logs success or failure
|
||||
new CallbackBackoffStrategy(function ($retries, $request, $response, $e) use ($app, $that) {
|
||||
$retry = true;
|
||||
if ($response && (null !== $deliverId = parse_url($request->getUrl(), PHP_URL_FRAGMENT))) {
|
||||
$delivery = $app['repo.webhook-delivery']->find($deliverId);
|
||||
// Set callback which logs success or failure
|
||||
$subscriber = new CallbackBackoffStrategy(function ($retries, Request $request, $response, $e) use ($app, $that) {
|
||||
$retry = true;
|
||||
if ($response && (null !== $deliverId = parse_url($request->getUrl(), PHP_URL_FRAGMENT))) {
|
||||
$delivery = $app['repo.webhook-delivery']->find($deliverId);
|
||||
|
||||
if ($response->isSuccessful()) {
|
||||
$app['manipulator.webhook-delivery']->deliverySuccess($delivery);
|
||||
$logContext = [ 'host' => $request->getHost() ];
|
||||
|
||||
$that->log('info', sprintf('Deliver success event "%d:%s" for app "%s"', $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), $delivery->getThirdPartyApplication()->getName()));
|
||||
$retry = false;
|
||||
} else {
|
||||
$app['manipulator.webhook-delivery']->deliveryFailure($delivery);
|
||||
if ($response->isSuccessful()) {
|
||||
$app['manipulator.webhook-delivery']->deliverySuccess($delivery);
|
||||
|
||||
$that->log('error', sprintf('Deliver failure event "%d:%s" for app "%s"', $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), $delivery->getThirdPartyApplication()->getName()));
|
||||
}
|
||||
$logType = 'info';
|
||||
$logEntry = sprintf('Deliver success event "%d:%s" for app "%s"',
|
||||
$delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(),
|
||||
$delivery->getThirdPartyApplication()->getName()
|
||||
);
|
||||
|
||||
return $retry;
|
||||
$retry = false;
|
||||
} else {
|
||||
$app['manipulator.webhook-delivery']->deliveryFailure($delivery);
|
||||
|
||||
$logType = 'error';
|
||||
$logEntry = sprintf('Deliver failure event "%d:%s" for app "%s"',
|
||||
$delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(),
|
||||
$delivery->getThirdPartyApplication()->getName()
|
||||
);
|
||||
}
|
||||
}, true, new CurlBackoffStrategy())
|
||||
)
|
||||
));
|
||||
|
||||
$that->log($logType, $logEntry, $logContext);
|
||||
|
||||
return $retry;
|
||||
}
|
||||
}, true, new CurlBackoffStrategy());
|
||||
|
||||
// set max retries
|
||||
$subscriber = new TruncatedBackoffStrategy(WebhookEventDelivery::MAX_DELIVERY_TRIES, $subscriber);
|
||||
$subscriber = new BackoffPlugin($subscriber);
|
||||
|
||||
$this->httpClient->addSubscriber($subscriber);
|
||||
|
||||
$this->firstRun = false;
|
||||
}
|
||||
|
||||
/** @var EventProcessorFactory $eventFactory */
|
||||
$eventFactory = $app['webhook.processor_factory'];
|
||||
|
@@ -7,6 +7,7 @@ use Alchemy\Phrasea\Model\Entities\WebhookEvent;
|
||||
use Alchemy\Phrasea\Application;
|
||||
use Alchemy\Phrasea\Webhook\Processor\CallableProcessorFactory;
|
||||
use Alchemy\Phrasea\Webhook\Processor\FeedEntryProcessorFactory;
|
||||
use Alchemy\Phrasea\Webhook\Processor\OrderNotificationProcessorFactory;
|
||||
use Alchemy\Phrasea\Webhook\Processor\ProcessorFactory;
|
||||
use Alchemy\Phrasea\Webhook\Processor\UserRegistrationProcessorFactory;
|
||||
|
||||
@@ -25,6 +26,7 @@ class EventProcessorFactory
|
||||
{
|
||||
$this->registerFactory(WebhookEvent::FEED_ENTRY_TYPE, new FeedEntryProcessorFactory($app));
|
||||
$this->registerFactory(WebhookEvent::USER_REGISTRATION_TYPE, new UserRegistrationProcessorFactory($app));
|
||||
$this->registerFactory(WebhookEvent::ORDER_TYPE, new OrderNotificationProcessorFactory($app));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Webhook\Processor;
|
||||
|
||||
use Alchemy\Phrasea\Model\Entities\Order;
|
||||
use Alchemy\Phrasea\Model\Entities\User;
|
||||
use Alchemy\Phrasea\Model\Entities\WebhookEvent;
|
||||
use Alchemy\Phrasea\Model\Repositories\OrderRepository;
|
||||
use Alchemy\Phrasea\Model\Repositories\UserRepository;
|
||||
|
||||
class OrderNotificationProcessor implements ProcessorInterface
|
||||
{
|
||||
/**
|
||||
* @var OrderRepository
|
||||
*/
|
||||
private $orderRepository;
|
||||
|
||||
/**
|
||||
* @var UserRepository
|
||||
*/
|
||||
private $userRepository;
|
||||
|
||||
public function __construct(OrderRepository $orderRepository, UserRepository $userRepository)
|
||||
{
|
||||
$this->orderRepository = $orderRepository;
|
||||
$this->userRepository = $userRepository;
|
||||
}
|
||||
|
||||
public function process(WebhookEvent $event)
|
||||
{
|
||||
if ($event->getName() == WebhookEvent::ORDER_CREATED) {
|
||||
return $this->processCreateOrder($event);
|
||||
}
|
||||
|
||||
return $this->processDeliveryOrder($event);
|
||||
}
|
||||
|
||||
protected function processCreateOrder(WebhookEvent $event)
|
||||
{
|
||||
$data = $event->getData();
|
||||
|
||||
/** @var User $user */
|
||||
$user = $this->userRepository->find($data['user_id']);
|
||||
/** @var Order $order */
|
||||
$order = $this->orderRepository->find($data['order_id']);
|
||||
|
||||
return $this->getOrderData($event, $user, $order);
|
||||
}
|
||||
|
||||
protected function processDeliveryOrder(WebhookEvent $event)
|
||||
{
|
||||
$data = $event->getData();
|
||||
|
||||
/** @var Order $order */
|
||||
$order = $this->orderRepository->find($data['order_id']);
|
||||
$user = $order->getUser();
|
||||
|
||||
return $this->getOrderData($event, $user, $order);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebhookEvent $event
|
||||
* @param User $user
|
||||
* @param Order $order
|
||||
* @return array
|
||||
*/
|
||||
protected function getOrderData(WebhookEvent $event, User $user, Order $order)
|
||||
{
|
||||
return [
|
||||
'event' => $event->getName(),
|
||||
'user' => [
|
||||
'id' => $user->getId(),
|
||||
'email' => $user->getEmail(),
|
||||
'login' => $user->getLogin()
|
||||
],
|
||||
'order' => $order->getId()
|
||||
];
|
||||
}
|
||||
}
|
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace Alchemy\Phrasea\Webhook\Processor;
|
||||
|
||||
use Alchemy\Phrasea\Application;
|
||||
|
||||
class OrderNotificationProcessorFactory implements ProcessorFactory
|
||||
{
|
||||
/**
|
||||
* @var Application
|
||||
*/
|
||||
private $application;
|
||||
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ProcessorInterface
|
||||
*/
|
||||
public function createProcessor()
|
||||
{
|
||||
return new OrderNotificationProcessor(
|
||||
$this->application['repo.orders'],
|
||||
$this->application['repo.users']
|
||||
);
|
||||
}
|
||||
}
|
@@ -147,6 +147,18 @@ class ACL implements cache_cacheableInterface
|
||||
return self::$bas_rights;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available rights by databox for the current user
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_sbas_rights()
|
||||
{
|
||||
$this->load_rights_sbas();
|
||||
|
||||
return $this->_rights_sbas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a hd grant has been received for a record
|
||||
*
|
||||
@@ -580,10 +592,11 @@ class ACL implements cache_cacheableInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user has the right, at least on one collection
|
||||
* Check if the user has the right, on at least one collection
|
||||
*
|
||||
* @param string $right
|
||||
* @return boolean
|
||||
* @param string $right
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function has_right($right)
|
||||
{
|
||||
@@ -598,9 +611,10 @@ class ACL implements cache_cacheableInterface
|
||||
/**
|
||||
* Check if the user has the required right on a database
|
||||
*
|
||||
* @param <type> $sbas_id
|
||||
* @param <type> $right
|
||||
* @return <type>
|
||||
* @param int $sbas_id
|
||||
* @param string $right
|
||||
* @return bool
|
||||
* @throws Exception
|
||||
*/
|
||||
public function has_right_on_sbas($sbas_id, $right)
|
||||
{
|
||||
@@ -623,8 +637,8 @@ class ACL implements cache_cacheableInterface
|
||||
/**
|
||||
* Retrieve mask AND for user on specified base_id
|
||||
*
|
||||
* @param int $base_id
|
||||
* @return string
|
||||
* @param int $base_id
|
||||
* @return int
|
||||
*/
|
||||
public function get_mask_and($base_id)
|
||||
{
|
||||
@@ -639,8 +653,8 @@ class ACL implements cache_cacheableInterface
|
||||
/**
|
||||
* Retrieve mask XOR for user on specified base_id
|
||||
*
|
||||
* @param int $base_id
|
||||
* @return string
|
||||
* @param int $base_id
|
||||
* @return int
|
||||
*/
|
||||
public function get_mask_xor($base_id)
|
||||
{
|
||||
|
@@ -118,7 +118,7 @@ class media_Permalink_Adapter implements cache_cacheableInterface
|
||||
'record_id' => $this->media_subdef->get_record_id(),
|
||||
'subdef' => $this->media_subdef->get_name(),
|
||||
/** @Ignore */
|
||||
'label' => $label,
|
||||
'label' => str_replace('/', '_', $label),
|
||||
'token' => $this->get_token(),
|
||||
]));
|
||||
}
|
||||
|
64
lib/classes/patch/400alpha7a.php
Normal file
64
lib/classes/patch/400alpha7a.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
|
||||
class patch_400alpha7a implements patchInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $release = '4.0.0-alpha.7';
|
||||
|
||||
/** @var array */
|
||||
private $concern = [base::APPLICATION_BOX];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_release()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDoctrineMigrations()
|
||||
{
|
||||
return [
|
||||
'20160511160640'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function require_all_upgrades()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function concern()
|
||||
{
|
||||
return $this->concern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(base $databox, Application $app)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
64
lib/classes/patch/400alpha8a.php
Normal file
64
lib/classes/patch/400alpha8a.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?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;
|
||||
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
|
||||
|
||||
class patch_400alpha8a implements patchInterface
|
||||
{
|
||||
/** @var string */
|
||||
private $release = '4.0.0-alpha.8';
|
||||
|
||||
/** @var array */
|
||||
private $concern = [base::APPLICATION_BOX];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function get_release()
|
||||
{
|
||||
return $this->release;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getDoctrineMigrations()
|
||||
{
|
||||
return [
|
||||
'20160520165600'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function require_all_upgrades()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function concern()
|
||||
{
|
||||
return $this->concern;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(base $databox, Application $app)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -68,8 +68,6 @@ class record_exportElement extends record_adapter
|
||||
parent::__construct($app, $sbas_id, $record_id);
|
||||
|
||||
$this->get_actions($remain_hd);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,8 +268,7 @@ class record_exportElement extends record_adapter
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Array
|
||||
* @return array
|
||||
*/
|
||||
public function get_orderable()
|
||||
{
|
||||
@@ -279,8 +276,7 @@ class record_exportElement extends record_adapter
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return Array
|
||||
* @return array
|
||||
*/
|
||||
public function get_downloadable()
|
||||
{
|
||||
|
@@ -99,19 +99,20 @@ class set_export extends set_abstract
|
||||
} else {
|
||||
$this->exportName = "Export_" . date("Y-n-d") . '_' . mt_rand(100, 999);
|
||||
|
||||
$tmp_lst = explode(';', $lst);
|
||||
$n = 1;
|
||||
foreach ($tmp_lst as $basrec) {
|
||||
$basrec = explode('_', $basrec);
|
||||
if (count($basrec) != 2)
|
||||
continue;
|
||||
|
||||
$records = new \Alchemy\Phrasea\Record\RecordReferenceCollection();
|
||||
|
||||
foreach (explode(';', $lst) as $basrec) {
|
||||
try {
|
||||
$record = new record_adapter($this->app, $basrec[0], $basrec[1]);
|
||||
} catch (\Exception_Record_AdapterNotFound $e) {
|
||||
$records[] = \Alchemy\Phrasea\Record\RecordReference::createFromRecordReference($basrec);
|
||||
} catch (Exception $exception) {
|
||||
// Ignore invalid record references
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($records->toRecords($app->getApplicationBox()) as $record) {
|
||||
if ($record->isStory()) {
|
||||
foreach ($record->getChildren() as $child_basrec) {
|
||||
$base_id = $child_basrec->getBaseId();
|
||||
|
@@ -5,6 +5,7 @@ languages:
|
||||
main:
|
||||
maintenance: false
|
||||
key: ''
|
||||
api_require_ssl: true
|
||||
database:
|
||||
host: 'sql-host'
|
||||
port: 3306
|
||||
|
@@ -5,9 +5,16 @@
|
||||
- name: Create mailcatcher log directory
|
||||
file: path={{ mailcatcher_log_path }} owner=mailcatcher mode=0755 state=directory
|
||||
|
||||
- name: Install Mailcatcher
|
||||
gem: name={{ mailcatcher_gem }} user_install=no state=latest
|
||||
notify: restart mailcatcher
|
||||
# https://github.com/jadb/ansible-role-mailcatcher/blob/b4df99308f0e5222a4ccb7d519504f967b0ea21b/tasks/main.yml
|
||||
|
||||
- name: Install mime-types for Ruby1.9
|
||||
# https://github.com/sj26/mailcatcher/issues/277#issuecomment-209154903
|
||||
command: gem install mime-types --version "< 3"
|
||||
|
||||
- name: Install the mailcatcher (GEM)
|
||||
# gem module is flaky, this is consistent
|
||||
command: gem install mailcatcher --conservative
|
||||
ignore_errors: yes
|
||||
|
||||
- name: Install mailcatcher supervisord conf
|
||||
template: src='program_mailcatcher.conf.j2' dest='/etc/supervisor/conf.d/program_mailcatcher.conf'
|
||||
|
@@ -19,10 +19,10 @@ server {
|
||||
|
||||
location /api {
|
||||
root {{ nginx.docroot }}/www;
|
||||
rewrite ^(.*)$ /api.php/$1 last;
|
||||
rewrite ^(.*)$ /api_dev.php/$1 last;
|
||||
}
|
||||
|
||||
location ~ ^/(index|index_dev|api)\.php(/|$) {
|
||||
location ~ ^/(index|index_dev|api|api_dev)\.php(/|$) {
|
||||
root {{ nginx.docroot }}/www;
|
||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||
fastcgi_pass unix:/var/run/php5-fpm.sock;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2016-05-19T12:33:00Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<file date="2016-05-24T15:19:59Z" source-language="en" target-language="de" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="new">Please provide the same passwords.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2016-05-19T12:34:27Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<file date="2016-05-24T15:21:47Z" source-language="en" target-language="en" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="translated">Please provide the same passwords.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore" approved="yes">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2016-05-19T12:36:01Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<file date="2016-05-24T15:23:43Z" source-language="en" target-language="fr" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="translated">Veuillez indiquer des mots de passe identiques.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore" approved="yes">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xliff xmlns="urn:oasis:names:tc:xliff:document:1.2" xmlns:jms="urn:jms:translation" version="1.2">
|
||||
<file date="2016-05-19T12:37:43Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<file date="2016-05-24T15:25:46Z" source-language="en" target-language="nl" datatype="plaintext" original="not.available">
|
||||
<header>
|
||||
<tool tool-id="JMSTranslationBundle" tool-name="JMSTranslationBundle" tool-version="1.1.0-DEV"/>
|
||||
<note>The source node in most cases contains the sample message as written by the developer. If it looks like a dot-delimitted string such as "form.label.firstname", then the developer has not provided a default message.</note>
|
||||
@@ -10,8 +10,8 @@
|
||||
<source>Please provide the same passwords.</source>
|
||||
<target state="new">Please provide the same passwords.</target>
|
||||
<jms:reference-file line="44">Form/Login/PhraseaRecoverPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
<jms:reference-file line="36">Form/Login/PhraseaRenewPasswordForm.php</jms:reference-file>
|
||||
<jms:reference-file line="49">Form/Login/PhraseaRegisterForm.php</jms:reference-file>
|
||||
</trans-unit>
|
||||
<trans-unit id="90b8c9717bb7ed061dbf20fe1986c8b8593d43d4" resname="The token provided is not valid anymore">
|
||||
<source>The token provided is not valid anymore</source>
|
||||
|
@@ -5,6 +5,7 @@ languages:
|
||||
main:
|
||||
maintenance: false
|
||||
key: ''
|
||||
api_require_ssl: true
|
||||
database:
|
||||
host: 'sql-host'
|
||||
port: 3306
|
||||
|
@@ -77,19 +77,19 @@
|
||||
settings = $.extend({}, $.tooltip.defaults, settings);
|
||||
createHelper(settings);
|
||||
return this.each(function () {
|
||||
$.data(this, "tooltip", settings);
|
||||
// copy tooltip into its own expando and remove the title
|
||||
this.tooltipText = $(this).attr('title');
|
||||
this.tooltipSrc = $(this).attr('tooltipsrc');
|
||||
$.data(this, "tooltip", settings);
|
||||
// copy tooltip into its own expando and remove the title
|
||||
this.tooltipText = $(this).attr('title');
|
||||
this.tooltipSrc = $(this).attr('tooltipsrc');
|
||||
|
||||
this.ajaxLoad = ($.trim(this.tooltipText) === '' && this.tooltipSrc !== '');
|
||||
this.ajaxTimeout;
|
||||
this.ajaxLoad = ($.trim(this.tooltipText) === '' && this.tooltipSrc !== '');
|
||||
this.ajaxTimeout;
|
||||
|
||||
this.orEl = $(this);
|
||||
$(this).removeAttr("title");
|
||||
// also remove alt attribute to prevent default tooltip in IE
|
||||
this.alt = "";
|
||||
})
|
||||
this.orEl = $(this);
|
||||
$(this).removeAttr("title");
|
||||
// also remove alt attribute to prevent default tooltip in IE
|
||||
this.alt = "";
|
||||
})
|
||||
.mouseover(save)
|
||||
.mouseout(hide)
|
||||
.mouseleave(function () {
|
||||
@@ -114,10 +114,10 @@
|
||||
'backgroundImage': 'none',
|
||||
'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
|
||||
}).each(function () {
|
||||
var position = $(this).css('position');
|
||||
if (position != 'absolute' && position != 'relative')
|
||||
$(this).css('position', 'relative');
|
||||
});
|
||||
var position = $(this).css('position');
|
||||
if (position != 'absolute' && position != 'relative')
|
||||
$(this).css('position', 'relative');
|
||||
});
|
||||
}
|
||||
});
|
||||
} : function () {
|
||||
@@ -135,7 +135,7 @@
|
||||
},
|
||||
hideWhenEmpty: function () {
|
||||
return this.each(function () {
|
||||
$(this)[ $(this).html() ? "show" : "hide" ]();
|
||||
$(this)[$(this).html() ? "show" : "hide"]();
|
||||
});
|
||||
},
|
||||
url: function () {
|
||||
@@ -149,7 +149,7 @@
|
||||
return;
|
||||
// create the helper, h3 for title, div for url
|
||||
helper.parent = $('<div id="' + settings.id + '"><div class="body"></div></div>')
|
||||
// add to document
|
||||
// add to document
|
||||
.appendTo(document.body)
|
||||
// hide it at first
|
||||
.hide();
|
||||
@@ -197,8 +197,9 @@
|
||||
|
||||
event.cancelBubble = true;
|
||||
|
||||
if ($.tooltip.blocked || this == $.tooltip.current || (!this.tooltipText && !this.tooltipSrc && !settings(this).bodyHandler))
|
||||
if ($.tooltip.blocked || this == $.tooltip.current || (!this.tooltipText && !this.tooltipSrc && !settings(this).bodyHandler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// save current
|
||||
$.tooltip.current = this;
|
||||
@@ -239,7 +240,7 @@
|
||||
helper.body.show();
|
||||
var $this = $.tooltip.current;
|
||||
var tooltipSettings = settings($this) ? settings($this) : {};
|
||||
var fixedPosition = tooltipSettings.fixable ? tooltipSettings.fixable : false;
|
||||
var fixedPosition = $.tooltip.blocked;
|
||||
// fix PNG background for IE
|
||||
if (tooltipSettings.fixPNG)
|
||||
helper.parent.fixPNG();
|
||||
@@ -349,7 +350,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if( $selector !== undefined) {
|
||||
if ($selector !== undefined) {
|
||||
$selector.css({width: Math.floor(resizeW), height: Math.floor(resizeH)});
|
||||
}
|
||||
|
||||
@@ -365,11 +366,10 @@
|
||||
|
||||
// since event target can have different positionning, try to get common closest parent:
|
||||
var $eventTarget = $origEventTarget.closest('.diapo');
|
||||
|
||||
if ($eventTarget.length > 0) {
|
||||
// tooltip from records answer
|
||||
recordWidthOffset = 148; // remove size
|
||||
recordHeightOffset = 195;
|
||||
recordWidthOffset = $eventTarget.width()-2; // remove width with margin/2
|
||||
recordHeightOffset = $eventTarget.height()+2; // remove height with margin/2
|
||||
// change offsets:
|
||||
topOffset = 14;
|
||||
leftOffset = 1;
|
||||
@@ -499,7 +499,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var resizeProperties = {
|
||||
left: left,
|
||||
top: top
|
||||
@@ -532,7 +531,7 @@
|
||||
function show() {
|
||||
tID = null;
|
||||
var isBrowsable = false;
|
||||
if( $.tooltip.current !== null ) {
|
||||
if ($.tooltip.current !== null) {
|
||||
isBrowsable = settings($.tooltip.current).isBrowsable;
|
||||
}
|
||||
|
||||
@@ -548,7 +547,7 @@
|
||||
$(helper.parent[0])
|
||||
.unbind('mouseenter')
|
||||
.unbind('mouseleave')
|
||||
.mouseenter(function(){
|
||||
.mouseenter(function () {
|
||||
if (isBrowsable) {
|
||||
$.tooltip.currentHover = true;
|
||||
}
|
||||
@@ -575,6 +574,7 @@
|
||||
commonModule.showOverlay('_tooltip', 'body', unfix_tooltip, settings(this).fixableIndex);
|
||||
$('#tooltip .tooltip_closer').show().bind('click', unfix_tooltip);
|
||||
$.tooltip.blocked = true;
|
||||
positioning.apply(this, arguments);
|
||||
}
|
||||
|
||||
function visible() {
|
||||
@@ -613,7 +613,6 @@
|
||||
|
||||
// remove position helper classes
|
||||
helper.parent.removeClass("viewport-right").removeClass("viewport-bottom");
|
||||
|
||||
if (!settings($.tooltip.current).outside) {
|
||||
var left = helper.parent[0].offsetLeft;
|
||||
var top = helper.parent[0].offsetTop;
|
||||
@@ -667,10 +666,10 @@
|
||||
// hide helper and restore added classes and the title
|
||||
function hide(event) {
|
||||
var isBrowsable = false;
|
||||
if( $.tooltip.current !== null ) {
|
||||
if ($.tooltip.current !== null) {
|
||||
isBrowsable = settings($.tooltip.current).isBrowsable;
|
||||
}
|
||||
if( $.tooltip.currentHover && isBrowsable ) {
|
||||
if ($.tooltip.currentHover && isBrowsable) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -723,7 +722,7 @@ function unfix_tooltip() {
|
||||
|
||||
|
||||
$(document).bind('keydown', function (event) {
|
||||
if( $.tooltip === undefined ) return;
|
||||
if ($.tooltip === undefined) return;
|
||||
|
||||
if (event.keyCode == 27 && $.tooltip.blocked === true) {
|
||||
unfix_tooltip();
|
||||
|
@@ -30,6 +30,7 @@
|
||||
<ul class="unstyled">
|
||||
<li>{{ 'phraseanet:: adresse' | trans }} : {{ collection.get_databox().get_serialized_server_info() }}</li>
|
||||
<li>{{ 'admin::base:collection: numero de collection distante' | trans }} : {{ collection.get_coll_id() }}</li>
|
||||
<li>{{ 'admin::base:collection: numero de collection locale' | trans }} : {{ collection.get_base_id() }}</li>
|
||||
<li>{{ 'admin::base:collection: etat de la collection' | trans }} : {{ collection.is_active() ? "admin::base:collection: activer la collection"| trans : "admin::base:collection: descativer la collection"|trans }}</li>
|
||||
<li>{{ collection.get_record_amount() }} records <a class="ajax" target="rights" href="{{ path('admin_collection_display_document_details', { 'bas_id' : collection.get_base_id() }) }}">{{ 'phraseanet:: details' | trans }}</a></li>
|
||||
</ul>
|
||||
|
@@ -62,11 +62,11 @@
|
||||
<div class='well-small'>
|
||||
<ul class="pager">
|
||||
{% if previousPage %}
|
||||
<li class="previous"><a class='self-ajax' href="{{ path('prod_orders', {'page': previousPage}) }}"><i class="icon-arrow-left"></i>{{ 'Previous' | trans }}</a></li>
|
||||
<li class="previous"><a class="self-ajax btn btn-inverse" href="{{ path('prod_orders', {'page': previousPage, 'per-page': perPage}) }}">{{ 'Previous' | trans }} <i class="icon-arrow-left"></i></a></li>
|
||||
{% endif %}
|
||||
|
||||
{% if nextPage %}
|
||||
<li class="next"><a class='self-ajax' href="{{ path('prod_orders', {'page': nextPage}) }}"><i class="icon-arrow-right"></i>{{ 'Next' | trans }}</a></li>
|
||||
<li class="next"><a class="self-ajax btn btn-inverse" href="{{ path('prod_orders', {'page': nextPage, 'per-page': perPage}) }}"><i class="icon-arrow-right"></i> {{ 'Next' | trans }}</a></li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
|
@@ -56,8 +56,12 @@
|
||||
<table class="bottom actions" style="width:100%; table-layout:fixed;">
|
||||
<tr>
|
||||
<td style="text-align:left;text-overflow:ellipsis;overflow:hidden;">
|
||||
{% set collectionLogo = collection_logo(record.baseId) %}
|
||||
{% if collectionLogo is empty %}
|
||||
{{ record.collectionName }}
|
||||
{{ collection_logo(record.baseId) }}
|
||||
{% else %}
|
||||
{{ collectionLogo|raw }}
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
{% set l_width = 30 %}
|
||||
|
@@ -20,21 +20,18 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
|
||||
$app['notification.deliverer'] = $this->getMockBuilder(Deliverer::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_CREATE, function (Event $event) use (&$triggered) {
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_CREATE, function () use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
$client = $this->getClient();
|
||||
$client->request('POST', '/prod/order/', [
|
||||
|
||||
$response = $this->request('POST', '/prod/order/', [
|
||||
'lst' => $this->getRecord1()->getId(),
|
||||
'deadline' => '+10 minutes'
|
||||
]);
|
||||
|
||||
$this->assertTrue($client->getResponse()->isRedirect(), 'Response should be redirect');
|
||||
$url = parse_url($client->getResponse()->headers->get('location'));
|
||||
$this->assertTrue($response->isRedirect(), 'Response should be redirect');
|
||||
$url = parse_url($response->headers->get('location'));
|
||||
$var = [];
|
||||
parse_str($url['query'], $var);
|
||||
$this->assertTrue(!!$var['success'], 'Response should have a success parameter');
|
||||
@@ -45,9 +42,6 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
|
||||
$app['notification.deliverer'] = $this->getMockBuilder(Deliverer::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_CREATE, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
@@ -90,37 +84,53 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
|
||||
public function testSendOrder()
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$order = $this->createOneOrder('I need this pictures');
|
||||
|
||||
$this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailInfoOrderDelivered');
|
||||
$this->mockUserNotificationSettings('eventsmanager_notify_orderdeliver');
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_DELIVER, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
|
||||
$parameters = [];
|
||||
foreach ($order->getElements() as $element) {
|
||||
$parameters[] = $element->getId();
|
||||
}
|
||||
$response = $this->request('POST', '/prod/order/' . $order->getId() . '/send/', ['elements' => $parameters]);
|
||||
|
||||
$this->assertTrue($triggered, 'Order delivered listener not triggered');
|
||||
$this->assertTrue($response->isRedirect(), 'Could not validate some elements. not a redirect');
|
||||
|
||||
$url = parse_url($response->headers->get('location'));
|
||||
parse_str($url['query']);
|
||||
|
||||
$this->assertTrue(strpos($url['query'], 'success=1') === 0, 'Validation of elements is not successful');
|
||||
}
|
||||
|
||||
public function testSendOrderJson()
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$order = $this->createOneOrder('I need this pictures');
|
||||
|
||||
$this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailInfoOrderDelivered');
|
||||
$this->mockUserNotificationSettings('eventsmanager_notify_orderdeliver');
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_DELIVER, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
|
||||
$parameters = [];
|
||||
|
||||
foreach ($order->getElements() as $element) {
|
||||
$parameters[] = $element->getId();
|
||||
}
|
||||
|
||||
$response = $this->XMLHTTPRequest('POST', '/prod/order/' . $order->getId() . '/send/', ['elements' => $parameters]);
|
||||
|
||||
$this->assertTrue($response->isOk());
|
||||
$this->assertEquals('application/json', $response->headers->get('Content-Type'));
|
||||
$this->assertTrue($triggered, 'Order delivered listener not triggered');
|
||||
|
||||
$content = json_decode($response->getContent());
|
||||
|
||||
$this->assertTrue(is_object($content));
|
||||
$this->assertObjectHasAttribute('success', $content, $response->getContent());
|
||||
$this->assertTrue( ! ! $content->success, $response->getContent());
|
||||
@@ -130,10 +140,13 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
|
||||
public function testDenyOrder()
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$order = $this->createOneOrder('I need this pictures');
|
||||
|
||||
$this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailInfoOrderCancelled');
|
||||
$this->mockUserNotificationSettings('eventsmanager_notify_ordernotdelivered');
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_DENY, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
|
||||
$parameters = [];
|
||||
foreach ($order->getElements() as $element) {
|
||||
@@ -141,7 +154,10 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
}
|
||||
$client = $this->getClient();
|
||||
$client->request('POST', '/prod/order/' . $order->getId() . '/deny/', ['elements' => $parameters]);
|
||||
|
||||
$this->assertTrue($client->getResponse()->isRedirect());
|
||||
$this->assertTrue($triggered, 'Order denied listener not triggered');
|
||||
|
||||
$url = parse_url($client->getResponse()->headers->get('location'));
|
||||
$var = [];
|
||||
parse_str($url['query'], $var);
|
||||
@@ -150,19 +166,27 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
|
||||
public function testDenyOrderJson()
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$order = $this->createOneOrder('I need this pictures');
|
||||
|
||||
$this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailInfoOrderCancelled');
|
||||
$this->mockUserNotificationSettings('eventsmanager_notify_ordernotdelivered');
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_DENY, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
|
||||
$parameters = [];
|
||||
foreach ($order->getElements() as $element) {
|
||||
$parameters[] = $element->getId();
|
||||
}
|
||||
|
||||
$response = $this->XMLHTTPRequest('POST', '/prod/order/' . $order->getId() . '/deny/', ['elements' => $parameters]);
|
||||
|
||||
$this->assertTrue($response->isOk());
|
||||
$this->assertEquals('application/json', $response->headers->get('Content-Type'));
|
||||
$this->assertTrue($triggered, 'Order denied listener not triggered');
|
||||
|
||||
$content = json_decode($response->getContent());
|
||||
|
||||
$this->assertTrue(is_object($content));
|
||||
$this->assertObjectHasAttribute('success', $content, $response->getContent());
|
||||
$this->assertTrue( ! ! $content->success, $response->getContent());
|
||||
@@ -172,10 +196,13 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
|
||||
public function testTodo()
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$order = $this->createOneOrder('I need this pictures');
|
||||
|
||||
$this->mockNotificationDeliverer('Alchemy\Phrasea\Notification\Mail\MailInfoOrderDelivered');
|
||||
$this->mockUserNotificationSettings('eventsmanager_notify_orderdeliver');
|
||||
$triggered = false;
|
||||
$app['dispatcher']->addListener(PhraseaEvents::ORDER_DELIVER, function (Event $event) use (&$triggered) {
|
||||
$triggered = true;
|
||||
});
|
||||
|
||||
$parameters = [];
|
||||
foreach ($order->getElements() as $element) {
|
||||
@@ -183,8 +210,10 @@ class OrderTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
}
|
||||
$this->getClient()->request('POST', '/prod/order/' . $order->getId() . '/send/', ['elements' => $parameters]);
|
||||
|
||||
$app = $this->getApplication();
|
||||
$this->assertTrue($triggered, 'Order delivered listener not triggered');
|
||||
|
||||
$testOrder = $app['orm.em']->getRepository('Phraseanet:Order')->find($order->getId());
|
||||
|
||||
$this->assertEquals(0, $testOrder->getTodo());
|
||||
}
|
||||
|
||||
|
@@ -2231,4 +2231,19 @@ class LoginTest extends \PhraseanetAuthenticatedWebTestCase
|
||||
{
|
||||
return self::$DI['user'];
|
||||
}
|
||||
|
||||
private function mockNotificationsDeliverer(array &$expectedMails)
|
||||
{
|
||||
$app = $this->getApplication();
|
||||
$app['notification.deliverer'] = $this->getMockBuilder('Alchemy\Phrasea\Notification\Deliverer')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$app['notification.deliverer']->expects($this->any())
|
||||
->method('deliver')
|
||||
->will($this->returnCallback(function ($email, $receipt) use (&$expectedMails) {
|
||||
$this->assertTrue(isset($expectedMails[get_class($email)]));
|
||||
$expectedMails[get_class($email)]++;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@@ -421,9 +421,7 @@ abstract class PhraseanetTestCase extends WebTestCase
|
||||
|
||||
$app['notification.deliverer']->expects($this->any())
|
||||
->method('deliver')
|
||||
->will($this->returnCallback(function () {
|
||||
$this->fail('Notification deliverer must be mocked');
|
||||
}));
|
||||
->willReturn(0);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
|
24
www/api_dev.php
Normal file
24
www/api_dev.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?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;
|
||||
use Symfony\Component\Debug\ErrorHandler;
|
||||
|
||||
require_once __DIR__ . '/../lib/autoload.php';
|
||||
|
||||
error_reporting(0);
|
||||
|
||||
ErrorHandler::register();
|
||||
|
||||
$environment = getenv('APP_ENV') ?: Application::ENV_DEV;
|
||||
$app = require __DIR__ . '/../lib/Alchemy/Phrasea/Application/Api.php';
|
||||
|
||||
$app->run();
|
Reference in New Issue
Block a user