diff --git a/composer.json b/composer.json
index dc4f2b0ffd..62ecab7dfb 100644
--- a/composer.json
+++ b/composer.json
@@ -5,6 +5,29 @@
"config": {
"bin-dir" : "bin/"
},
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/alchemy-fr/tcpdf-clone"
+ },
+ {
+ "type": "git",
+ "url": "https://github.com/romainneutron/ProcessManager.git"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/nlegoff/PHP-FFmpeg"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/nlegoff/Mediavorus"
+ },
+ {
+ "type": "vcs",
+ "url": "https://github.com/nlegoff/Media-Alchemyst"
+ }
+ ],
+ "minimum-stability" : "dev",
"require": {
"php" : ">=5.4",
"alchemy/oauth2php" : "1.0.0",
@@ -28,8 +51,8 @@
"jms/serializer" : "~0.10",
"jms/translation-bundle" : "~1.1",
"justinrainbow/json-schema" : "~1.3",
- "mediavorus/mediavorus" : "~0.4.0",
- "media-alchemyst/media-alchemyst" : "~0.4, >=0.4.4",
+ "mediavorus/mediavorus" : "dev-fix-video-dim as 0.4.3",
+ "media-alchemyst/media-alchemyst" : "0.4.x@dev",
"monolog/monolog" : "~1.3",
"mrclay/minify" : "~2.1.6",
"neutron/process-manager" : "2.0.x-dev@dev",
@@ -38,7 +61,7 @@
"neutron/sphinxsearch-api" : "~2.0.6",
"neutron/recaptcha" : "~0.1.0",
"neutron/temporary-filesystem" : "~2.1",
- "php-ffmpeg/php-ffmpeg" : "~0.4, >=0.4.3",
+ "php-ffmpeg/php-ffmpeg" : "dev-fix-aspect-ratio as 0.4.4",
"php-xpdf/php-xpdf" : "~0.2.1",
"phpexiftool/phpexiftool" : "~0.3",
"react/zmq" : "~0.2",
@@ -70,10 +93,6 @@
{
"type": "git",
"url": "https://github.com/alchemy-fr/tcpdf-clone"
- },
- {
- "type": "git",
- "url": "https://github.com/romainneutron/ProcessManager.git"
}
],
"autoload": {
diff --git a/composer.lock b/composer.lock
index ee3ca8c62d..13ffb9420e 100644
--- a/composer.lock
+++ b/composer.lock
@@ -1,9 +1,10 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
- "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
+ "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
],
- "hash": "2b68364c4ebb09b6f5c3902e0afdcc1a",
+ "hash": "6dbba3e72a44255a6292ee8fedbce88e",
"packages": [
{
"name": "alchemy-fr/tcpdf-clone",
@@ -2018,26 +2019,26 @@
},
{
"name": "media-alchemyst/media-alchemyst",
- "version": "0.4.4",
+ "version": "dev-master",
"source": {
"type": "git",
- "url": "https://github.com/alchemy-fr/Media-Alchemyst.git",
- "reference": "067599fd669b86ff3a1cfb344730014b4a339b7e"
+ "url": "https://github.com/nlegoff/Media-Alchemyst.git",
+ "reference": "e812e631b74ebb0c7b3dd5f4e981d84a7b3c4029"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/alchemy-fr/Media-Alchemyst/zipball/067599fd669b86ff3a1cfb344730014b4a339b7e",
- "reference": "067599fd669b86ff3a1cfb344730014b4a339b7e",
+ "url": "https://api.github.com/repos/nlegoff/Media-Alchemyst/zipball/e812e631b74ebb0c7b3dd5f4e981d84a7b3c4029",
+ "reference": "e812e631b74ebb0c7b3dd5f4e981d84a7b3c4029",
"shasum": ""
},
"require": {
"alchemy/ghostscript": "~0.4.0",
"imagine/imagine": "0.6.x@dev",
- "mediavorus/mediavorus": "~0.4.2",
+ "mediavorus/mediavorus": "dev-fix-video-dim as 0.4.3",
"monolog/monolog": "~1.0",
"neutron/temporary-filesystem": "~2.1",
"php": ">=5.3.3",
- "php-ffmpeg/php-ffmpeg": "~0.4.2",
+ "php-ffmpeg/php-ffmpeg": "dev-fix-aspect-ratio as 0.4.4",
"php-mp4box/php-mp4box": "~0.3.0",
"php-unoconv/php-unoconv": "~0.3.0",
"pimple/pimple": "~1.0",
@@ -2062,7 +2063,6 @@
"MediaAlchemyst": "src"
}
},
- "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -2087,20 +2087,23 @@
"video",
"video processing"
],
- "time": "2014-01-31 11:32:50"
+ "support": {
+ "source": "https://github.com/nlegoff/Media-Alchemyst/tree/master"
+ },
+ "time": "2014-06-10 13:51:13"
},
{
"name": "mediavorus/mediavorus",
- "version": "0.4.3",
+ "version": "dev-fix-video-dim",
"source": {
"type": "git",
- "url": "https://github.com/romainneutron/MediaVorus.git",
- "reference": "7cc8c0b8d3440eaff9aa68fff2185216fd72bd75"
+ "url": "https://github.com/nlegoff/Mediavorus.git",
+ "reference": "f11cd2453d5acbc6ac52421dc4edd760433b1515"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/romainneutron/MediaVorus/zipball/7cc8c0b8d3440eaff9aa68fff2185216fd72bd75",
- "reference": "7cc8c0b8d3440eaff9aa68fff2185216fd72bd75",
+ "url": "https://api.github.com/repos/nlegoff/Mediavorus/zipball/f11cd2453d5acbc6ac52421dc4edd760433b1515",
+ "reference": "f11cd2453d5acbc6ac52421dc4edd760433b1515",
"shasum": ""
},
"require": {
@@ -2133,7 +2136,6 @@
"MediaVorus": "src"
}
},
- "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -2148,7 +2150,10 @@
"keywords": [
"metadata"
],
- "time": "2014-01-06 15:45:32"
+ "support": {
+ "source": "https://github.com/nlegoff/Mediavorus/tree/fix-video-dim"
+ },
+ "time": "2014-06-10 14:03:47"
},
{
"name": "monolog/monolog",
@@ -2597,16 +2602,16 @@
},
{
"name": "php-ffmpeg/php-ffmpeg",
- "version": "0.4.4",
+ "version": "dev-fix-aspect-ratio",
"source": {
"type": "git",
- "url": "https://github.com/alchemy-fr/PHP-FFmpeg.git",
- "reference": "8dfaf1815802614352bbd10eac7299a100bf9757"
+ "url": "https://github.com/nlegoff/PHP-FFmpeg.git",
+ "reference": "c2ea1ca7ab0a4da0e876e36c8cddbfa4d92dbba6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/alchemy-fr/PHP-FFmpeg/zipball/8dfaf1815802614352bbd10eac7299a100bf9757",
- "reference": "8dfaf1815802614352bbd10eac7299a100bf9757",
+ "url": "https://api.github.com/repos/nlegoff/PHP-FFmpeg/zipball/c2ea1ca7ab0a4da0e876e36c8cddbfa4d92dbba6",
+ "reference": "c2ea1ca7ab0a4da0e876e36c8cddbfa4d92dbba6",
"shasum": ""
},
"require": {
@@ -2627,7 +2632,7 @@
"type": "library",
"extra": {
"branch-alias": {
- "dev-master": "0.4-dev"
+ "dev-master": "0.5-dev"
}
},
"autoload": {
@@ -2635,7 +2640,6 @@
"FFMpeg": "src"
}
},
- "notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -2662,7 +2666,10 @@
"video",
"video processing"
],
- "time": "2013-12-17 16:54:46"
+ "support": {
+ "source": "https://github.com/nlegoff/PHP-FFmpeg/tree/fix-aspect-ratio"
+ },
+ "time": "2014-06-10 10:27:04"
},
{
"name": "php-mp4box/php-mp4box",
@@ -4900,9 +4907,20 @@
}
],
"aliases": [
-
+ {
+ "alias": "0.4.3",
+ "alias_normalized": "0.4.3.0",
+ "version": "dev-fix-video-dim",
+ "package": "mediavorus/mediavorus"
+ },
+ {
+ "alias": "0.4.4",
+ "alias_normalized": "0.4.4.0",
+ "version": "dev-fix-aspect-ratio",
+ "package": "php-ffmpeg/php-ffmpeg"
+ }
],
- "minimum-stability": "stable",
+ "minimum-stability": "dev",
"stability-flags": {
"alchemy/task-manager": 20,
"alchemy/zippy": 20,
@@ -4913,6 +4931,10 @@
"doctrine/migrations": 20,
"behat/behat": 20,
"behat/gherkin": 20
+ "mediavorus/mediavorus": 20,
+ "media-alchemyst/media-alchemyst": 20,
+ "php-ffmpeg/php-ffmpeg": 20,
+ "doctrine/data-fixtures": 20
},
"platform": {
"php": ">=5.4"
diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml
index 1aa6447925..1cd3d7c1f7 100644
--- a/config/configuration.sample.yml
+++ b/config/configuration.sample.yml
@@ -4,6 +4,8 @@ languages:
default: 'fr'
main:
maintenance: false
+ languages: []
+ key: ''
database:
host: 127.0.0.1
port: 3306
@@ -169,6 +171,9 @@ registration-fields:
-
name: company
required: true
+ -
+ name: lastname
+ required: true
-
name: firstname
required: true
@@ -184,3 +189,15 @@ h264-pseudo-streaming:
type: nginx
mapping: []
plugins: []
+api_cors:
+ enabled: false
+ allow_credentials: false
+ allow_origin: []
+ allow_headers: []
+ allow_methods: []
+ expose_headers: []
+ max_age: 0
+ hosts: []
+session:
+ idle: 0
+ lifetime: 604800 # 1 week
diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php
index 8dc85e9913..675930e302 100644
--- a/lib/Alchemy/Phrasea/Application.php
+++ b/lib/Alchemy/Phrasea/Application.php
@@ -67,8 +67,6 @@ use Alchemy\Phrasea\Controller\Root\Session;
use Alchemy\Phrasea\Controller\Setup as SetupController;
use Alchemy\Phrasea\Controller\Thesaurus\Thesaurus;
use Alchemy\Phrasea\Controller\Thesaurus\Xmlhttp as ThesaurusXMLHttp;
-use Alchemy\Phrasea\Controller\Utils\ConnectionTest;
-use Alchemy\Phrasea\Controller\Utils\PathFileTest;
use Alchemy\Phrasea\Controller\User\Notifications;
use Alchemy\Phrasea\Controller\User\Preferences;
use Alchemy\Phrasea\Core\PhraseaExceptionHandler;
@@ -101,6 +99,7 @@ use Alchemy\Phrasea\Core\Provider\LocaleServiceProvider;
use Alchemy\Phrasea\Core\Provider\ManipulatorServiceProvider;
use Alchemy\Phrasea\Core\Provider\NotificationDelivererServiceProvider;
use Alchemy\Phrasea\Core\Provider\ORMServiceProvider;
+use Alchemy\Phrasea\Core\Provider\PhraseaEventServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseanetServiceProvider;
use Alchemy\Phrasea\Core\Provider\PluginServiceProvider;
use Alchemy\Phrasea\Core\Provider\PhraseaVersionServiceProvider;
@@ -121,6 +120,7 @@ use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Form\Extension\HelpTypeExtension;
use Alchemy\Phrasea\Twig\JSUniqueID;
+use Alchemy\Phrasea\Twig\Fit;
use Alchemy\Phrasea\Twig\Camelize;
use Alchemy\Phrasea\Twig\BytesConverter;
use Alchemy\Phrasea\Utilities\CachedTranslator;
@@ -155,8 +155,8 @@ use XPDF\XPDFServiceProvider;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
-use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\FormTypeInterface;
@@ -317,8 +317,10 @@ class Application extends SilexApplication
$this->register(new SessionHandlerServiceProvider());
$this->register(new SessionServiceProvider(), [
- 'session.test' => $this->getEnvironment() === static::ENV_TEST
+ 'session.test' => $this->getEnvironment() === static::ENV_TEST,
+ 'session.storage.options' => array('cookie_lifetime' => 0)
]);
+
$this['session.storage.test'] = $this->share(function ($app) {
return new MockArraySessionStorage();
});
@@ -378,6 +380,7 @@ class Application extends SilexApplication
$this->register(new FileServeServiceProvider());
$this->register(new ManipulatorServiceProvider());
$this->register(new PluginServiceProvider());
+ $this->register(new PhraseaEventServiceProvider());
$this['phraseanet.exception_handler'] = $this->share(function ($app) {
$handler = PhraseaExceptionHandler::register($app['debug']);
@@ -471,12 +474,12 @@ class Application extends SilexApplication
$this['dispatcher'] = $this->share(
$this->extend('dispatcher', function ($dispatcher, Application $app) {
- $dispatcher->addListener(KernelEvents::REQUEST, [$app, 'initSession'], 254);
- $dispatcher->addListener(KernelEvents::RESPONSE, [$app, 'addUTF8Charset'], -128);
- $dispatcher->addSubscriber(new LogoutSubscriber());
- $dispatcher->addSubscriber(new PhraseaLocaleSubscriber($app));
- $dispatcher->addSubscriber(new MaintenanceSubscriber($app));
- $dispatcher->addSubscriber(new CookiesDisablerSubscriber($app));
+ $dispatcher->addListener(KernelEvents::RESPONSE, array($app, 'addUTF8Charset'), -128);
+ $dispatcher->addSubscriber($app['phraseanet.logout-subscriber']);
+ $dispatcher->addSubscriber($app['phraseanet.locale-subscriber']);
+ $dispatcher->addSubscriber($app['phraseanet.maintenance-subscriber']);
+ $dispatcher->addSubscriber($app['phraseanet.cookie-disabler-subscriber']);
+ $dispatcher->addSubscriber($app['phraseanet.session-manager-subscriber']);
$dispatcher->addSubscriber(new PhraseaInstallSubscriber($app));
return $dispatcher;
@@ -557,25 +560,6 @@ class Application extends SilexApplication
return $this->redirect($this->url($route, $parameters));
}
- public function initSession(GetResponseEvent $event)
- {
- if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
- return;
- }
-
- if (false !== stripos($event->getRequest()->server->get('HTTP_USER_AGENT'), 'flash')
- && $event->getRequest()->getRequestUri() === '/prod/upload/') {
-
- if (null !== $sessionId = $event->getRequest()->request->get('php_session_id')) {
-
- $request = $event->getRequest();
- $request->cookies->set($this['session']->getName(), $sessionId);
-
- return $request;
- }
- }
- }
-
public function addUTF8Charset(FilterResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
@@ -642,6 +626,7 @@ class Application extends SilexApplication
// add filters truncate, wordwrap, nl2br
$twig->addExtension(new \Twig_Extensions_Extension_Text());
$twig->addExtension(new JSUniqueID());
+ $twig->addExtension(new Fit());
$twig->addExtension(new Camelize());
$twig->addExtension(new BytesConverter());
@@ -667,23 +652,32 @@ class Application extends SilexApplication
return ConnectedUsers::appName($app['translator'], $value);
}));
$twig->addFilter(new \Twig_SimpleFilter('escapeSimpleQuote', function ($value) {
- $ret = str_replace("'", "\\'", $value);
-
- return $ret;
+ return str_replace("'", "\\'", $value);
}));
- $twig->addFilter(new \Twig_SimpleFilter('thesaurus', function (\Twig_Environment $twig, $value) {
- if (!$value instanceof \ThesaurusValue) {
- return str_replace(['[[em]]', '[[/em]]'], ['', ''], twig_escape_filter($twig, $value));
- }
- return "getField()->get_databox()->get_sbas_id() . "','"
- . str_replace("'", "\\'", $value->getQuery())
- . "', '"
- . str_replace("'", "\\'", $value->getField()->get_name())
- . "');return(false);\">"
- . str_replace(['[[em]]', '[[/em]]'], ['', ''], twig_escape_filter($twig, $value->getValue()))
- . "";
- }, ['needs_environment' => true, 'is_safe' => ['html']]));
+ $twig->addFilter(new \Twig_SimpleFilter('highlight', function (\Twig_Environment $twig, $string) {
+ return str_replace(array('[[em]]', '[[/em]]'), array('', ''), $string);
+ }, array('needs_environment' => true,'is_safe' => array('html'))));
+
+ $twig->addFilter(new \Twig_SimpleFilter('linkify', function (\Twig_Environment $twig, $string) {
+ return preg_replace(
+ "(([^']{1})((https?|file):((/{2,4})|(\\{2,4}))[\w:#%/;$()~_?/\-=\\\.&]*)([^']{1}))"
+ , '$1 $2 $7'
+ , $string
+ );
+ }, array('needs_environment' => true, 'is_safe' => array('html'))));
+
+ $twig->addFilter(new \Twig_SimpleFilter('bounce', function (\Twig_Environment $twig, $fieldValue, $fieldName, $searchRequest, $sbasId) {
+ // bounce value if it is present in thesaurus as well
+ return ""
+ . $fieldValue
+ . "";
+
+ }, array('needs_environment' => true, 'is_safe' => array('html'))));
$twig->addFilter(new \Twig_SimpleFilter('escapeDoubleQuote', function ($value) {
return str_replace('"', '\"', $value);
@@ -843,8 +837,6 @@ class Application extends SilexApplication
$this->mount('/admin/fields', new Fields());
$this->mount('/admin/task-manager', new TaskManager());
$this->mount('/admin/subdefs', new Subdefs());
- $this->mount('/admin/tests/connection', new ConnectionTest());
- $this->mount('/admin/tests/pathurl', new PathFileTest());
$this->mount('/client/', new ClientRoot());
$this->mount('/client/baskets', new ClientBasket());
@@ -881,8 +873,6 @@ class Application extends SilexApplication
$this->mount('/session/', new Session());
$this->mount('/setup', new SetupController());
- $this->mount('/setup/connection_test/', new ConnectionTest());
- $this->mount('/setup/test/', new PathFileTest());
$this->mount('/report/', new ReportRoot());
$this->mount('/report/activity', new ReportActivity());
diff --git a/lib/Alchemy/Phrasea/Application/Api.php b/lib/Alchemy/Phrasea/Application/Api.php
index 72d6ce0895..e962ab1df7 100644
--- a/lib/Alchemy/Phrasea/Application/Api.php
+++ b/lib/Alchemy/Phrasea/Application/Api.php
@@ -12,13 +12,14 @@
namespace Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application as PhraseaApplication;
+use Alchemy\Phrasea\Core\Event\Subscriber\ApiCorsSubscriber;
+use Alchemy\Phrasea\Core\PhraseaEvents;
use Alchemy\Phrasea\Controller\Api\Oauth2;
use Alchemy\Phrasea\Controller\Api\Result;
use Alchemy\Phrasea\Controller\Api\V1;
use Alchemy\Phrasea\Core\Event\ApiResultEvent;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiOauth2ErrorsSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\ApiExceptionHandlerSubscriber;
-use Alchemy\Phrasea\Core\PhraseaEvents;
use Monolog\Logger;
use Monolog\Processor\WebProcessor;
use Silex\Application as SilexApplication;
@@ -71,6 +72,8 @@ return call_user_func(function ($environment = PhraseaApplication::ENV_PROD) {
$app->after(function (Request $request, Response $response) use ($app) {
$app['dispatcher']->dispatch(PhraseaEvents::API_RESULT, new ApiResultEvent($request, $response));
});
+ $app['dispatcher']->addSubscriber(new ApiCorsSubscriber($app));
+ $app['dispatcher']->dispatch(PhraseaEvents::API_LOAD_END, new ApiLoadEndEvent());
return $app;
}, isset($environment) ? $environment : PhraseaApplication::ENV_PROD);
diff --git a/lib/Alchemy/Phrasea/Border/Manager.php b/lib/Alchemy/Phrasea/Border/Manager.php
index cdfda37873..ff31a90754 100644
--- a/lib/Alchemy/Phrasea/Border/Manager.php
+++ b/lib/Alchemy/Phrasea/Border/Manager.php
@@ -15,6 +15,8 @@ use Alchemy\Phrasea\Border\Checker\CheckerInterface;
use Alchemy\Phrasea\Border\Attribute\AttributeInterface;
use Alchemy\Phrasea\Metadata\Tag\TfArchivedate;
use Alchemy\Phrasea\Metadata\Tag\TfQuarantine;
+use Alchemy\Phrasea\Metadata\Tag\TfBasename;
+use Alchemy\Phrasea\Metadata\Tag\TfFilename;
use Alchemy\Phrasea\Metadata\Tag\TfRecordid;
use Alchemy\Phrasea\Border\Attribute\Metadata as MetadataAttr;
use Alchemy\Phrasea\Model\Entities\LazaretAttribute;
@@ -242,20 +244,37 @@ class Manager
)
)
);
+ $file->addAttribute(
+ new MetadataAttr(
+ new Metadata(
+ new TfBasename(), new MonoValue(pathinfo($file->getOriginalName(), PATHINFO_BASENAME))
+ )
+ )
+ );
+ $file->addAttribute(
+ new MetadataAttr(
+ new Metadata(
+ new TfFilename(), new MonoValue(pathinfo($file->getOriginalName(), PATHINFO_FILENAME))
+ )
+ )
+ );
$newMetadata = $file->getMedia()->getMetadatas()->toArray();
-
foreach ($file->getAttributes() as $attribute) {
switch ($attribute->getName()) {
-
- /**
- * @todo implement METATAG aka metadata by fieldname (where as
- * current metadata is metadata by source.
- */
case AttributeInterface::NAME_METAFIELD:
$values = $attribute->getValue();
$value = $attribute->getField()->is_multi() ? new Multi($values) : new MonoValue(array_pop($values));
- $newMetadata[] = new Metadata($attribute->getField()->get_tag(), $value);
+
+ $tag = $attribute->getField()->get_tag();
+
+ if ($tag instanceof \Alchemy\Phrasea\Metadata\Tag\Nosource) {
+ $tag->setTagname($attribute->getField()->get_name());
+ $_meta = new Metadata($tag, $value);
+ } else {
+ $_meta = new Metadata($attribute->getField()->get_tag(), $value);
+ }
+ $newMetadata[] = $_meta;
break;
case AttributeInterface::NAME_METADATA:
@@ -342,7 +361,6 @@ class Manager
$attribute->setName($fileAttribute->getName());
$attribute->setValue($fileAttribute->asString());
$attribute->setLazaretFile($lazaretFile);
-
$lazaretFile->addAttribute($attribute);
$this->app['EM']->persist($attribute);
diff --git a/lib/Alchemy/Phrasea/Border/MimeGuesserConfiguration.php b/lib/Alchemy/Phrasea/Border/MimeGuesserConfiguration.php
index ba8395ffc3..cfda50f3e9 100644
--- a/lib/Alchemy/Phrasea/Border/MimeGuesserConfiguration.php
+++ b/lib/Alchemy/Phrasea/Border/MimeGuesserConfiguration.php
@@ -16,7 +16,6 @@ use MediaVorus\Utils\AudioMimeTypeGuesser;
use MediaVorus\Utils\PostScriptMimeTypeGuesser;
use MediaVorus\Utils\RawImageMimeTypeGuesser;
use MediaVorus\Utils\VideoMimeTypeGuesser;
-use Symfony\Component\HttpFoundation\File\MimeType\FileBinaryMimeTypeGuesser;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser;
class MimeGuesserConfiguration
@@ -36,7 +35,6 @@ class MimeGuesserConfiguration
{
$guesser = MimeTypeGuesser::getInstance();
- $guesser->register(new FileBinaryMimeTypeGuesser());
$guesser->register(new RawImageMimeTypeGuesser());
$guesser->register(new PostScriptMimeTypeGuesser());
$guesser->register(new AudioMimeTypeGuesser());
diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Collection.php b/lib/Alchemy/Phrasea/Controller/Admin/Collection.php
index 4cb73b1f04..9464111cc3 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Collection.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Collection.php
@@ -254,11 +254,11 @@ class Collection implements ControllerProviderInterface
}
if ('json' === $app['request']->getRequestFormat()) {
- return $app->json([
- 'success' => $success,
- 'msg' => $msg,
- 'bas_id' => $collection->get_base_id()
- ]);
+ return $app->json(array(
+ 'success' => $success,
+ 'msg' => $msg,
+ 'bas_id' => $collection->get_base_id()
+ ));
}
return $app->redirectPath('admin_display_collection', [
diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Root.php b/lib/Alchemy/Phrasea/Controller/Admin/Root.php
index 14044eadb3..bb3dc8955a 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Root.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Root.php
@@ -12,6 +12,8 @@
namespace Alchemy\Phrasea\Controller\Admin;
use Alchemy\Phrasea\Exception\SessionNotFound;
+use Alchemy\Phrasea\Helper\DatabaseHelper;
+use Alchemy\Phrasea\Helper\PathHelper;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
@@ -24,7 +26,6 @@ class Root implements ControllerProviderInterface
$app['controller.admin.root'] = $this;
$controllers = $app['controllers_factory'];
-
$app['firewall']->addMandatoryAuthentication($controllers);
$controllers->before(function (Request $request) use ($app) {
@@ -447,6 +448,24 @@ class Root implements ControllerProviderInterface
->assert('bit', '\d+')
->bind('database_submit_statusbit');
+ $controllers->get('/tests/connection/mysql/', function (Application $app, Request $request) {
+ $dbHelper = new DatabaseHelper($app, $request);
+
+ return $app->json($dbHelper->checkConnection());
+ });
+
+ $controllers->get('/tests/pathurl/path/', function (Application $app, Request $request) {
+ $pathHelper = new PathHelper($app, $request);
+
+ return $app->json($pathHelper->checkPath());
+ });
+
+ $controllers->get('/tests/pathurl/url/', function (Application $app, Request $request) {
+ $pathHelper = new PathHelper($app, $request);
+
+ return $app->json($pathHelper->checkUrl());
+ });
+
return $controllers;
}
}
diff --git a/lib/Alchemy/Phrasea/Controller/Admin/Users.php b/lib/Alchemy/Phrasea/Controller/Admin/Users.php
index 5e51e9deee..5d61aa41fc 100644
--- a/lib/Alchemy/Phrasea/Controller/Admin/Users.php
+++ b/lib/Alchemy/Phrasea/Controller/Admin/Users.php
@@ -194,7 +194,7 @@ class Users implements ControllerProviderInterface
}
$filename = sprintf('user_export_%s.csv', date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $userTable) {
+ $response = new CSVFileResponse($filename, function () use ($app, $userTable) {
$app['csv.exporter']->export('php://output', $userTable);
});
@@ -341,7 +341,7 @@ class Users implements ControllerProviderInterface
} while (count($results) > 0);
$filename = sprintf('user_export_%s.csv', date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $buffer) {
+ $response = new CSVFileResponse($filename, function () use ($app, $buffer) {
$app['csv.exporter']->export('php://output', $buffer);
});
@@ -521,7 +521,7 @@ class Users implements ControllerProviderInterface
return $app->redirectPath('users_display_import_file', ['error' => 'file-invalid']);
}
- $equivalenceToMysqlField = self::getEquivalenceToMysqlField();
+ $equivalenceToMysqlField = Users::getEquivalenceToMysqlField();
$loginDefined = $pwdDefined = $mailDefined = false;
$loginNew = [];
$out = [
@@ -531,7 +531,7 @@ class Users implements ControllerProviderInterface
$nbUsrToAdd = 0;
$lines = array();
- $app['csv.interpreter']->addObserver(function(array $row) use (&$lines) {
+ $app['csv.interpreter']->addObserver(function (array $row) use (&$lines) {
$lines[] = $row;
});
$app['csv.lexer']->parse($file->getPathname(), $app['csv.interpreter']);
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php b/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php
index 7ae2b21ad4..aa2ae7b5fe 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/DoDownload.php
@@ -97,7 +97,8 @@ class DoDownload implements ControllerProviderInterface
'list' => $list,
'records' => $records,
'token' => $token,
- 'anonymous' => $request->query->get('anonymous', false)
+ 'anonymous' => $request->query->get('anonymous', false),
+ 'type' => $request->query->get('type', \Session_Logger::EVENT_EXPORTDOWNLOAD)
]));
}
@@ -143,12 +144,12 @@ class DoDownload implements ControllerProviderInterface
$app->abort(404, 'Download file not found');
}
- $app['dispatcher']->addListener(KernelEvents::TERMINATE, function (PostResponseEvent $event) use ($list, $app) {
+ $app['dispatcher']->addListener(KernelEvents::RESPONSE, function (PostResponseEvent $event) use ($list, $app) {
\set_export::log_download(
$app,
$list,
- $event->getRequest()->request->get('type'),
- (null !== $event->getRequest()->request->get('anonymous') ? true : false),
+ $event->getRequest()->get('type'),
+ !!$event->getRequest->get('anonymous', false),
(isset($list['email']) ? $list['email'] : '')
);
});
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Edit.php b/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
index 7389611c28..c0ddc149c7 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Edit.php
@@ -345,7 +345,7 @@ class Edit implements ControllerProviderInterface
$editDirty = true;
}
- if (is_array($rec['metadatas'])) {
+ if (isset($rec['metadatas']) && is_array($rec['metadatas'])) {
$record->set_metadatas($rec['metadatas']);
}
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Export.php b/lib/Alchemy/Phrasea/Controller/Prod/Export.php
index d97f8f47b0..6385e482f3 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Export.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Export.php
@@ -228,7 +228,7 @@ class Export implements ControllerProviderInterface
$remaingEmails = $destMails;
- $url = $app->url('prepare_download', ['token' => $token->getValue(), 'anonymous']);
+ $url = $app->url('prepare_download', ['token' => $token->getValue(), 'anonymous' => false, 'type' => \Session_Logger::EVENT_EXPORTMAIL]);
$emitter = new Emitter($app['authentication']->getUser()->getDisplayName(), $app['authentication']->getUser()->getEmail());
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Language.php b/lib/Alchemy/Phrasea/Controller/Prod/Language.php
index 6c5fa73802..0700729108 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Language.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Language.php
@@ -22,8 +22,9 @@ class Language implements ControllerProviderInterface
$controller = $app['controllers_factory'];
- $controller->get("/", function (Application $app) {
+ $app['firewall']->addMandatoryAuthentication($controller);
+ $controller->get("/", function (Application $app) {
$out = [];
$out['thesaurusBasesChanged'] = $app->trans('prod::recherche: Attention : la liste des bases selectionnees pour la recherche a ete changee.');
$out['confirmDel'] = $app->trans('paniers::Vous etes sur le point de supprimer ce panier. Cette action est irreversible. Souhaitez-vous continuer ?');
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Push.php b/lib/Alchemy/Phrasea/Controller/Prod/Push.php
index a92379c7a4..a4fdc54c87 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Push.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Push.php
@@ -32,7 +32,7 @@ class Push implements ControllerProviderInterface
protected function getUserFormatter(Application $app)
{
return function (User $user) use ($app) {
- $subtitle = array_filter([$user->getJob(), $user->getCompany()]);
+ $subtitle = array_filter([$user->getPosition(), $user->getCompany()]);
return [
'type' => 'USER',
@@ -217,12 +217,17 @@ class Push implements ControllerProviderInterface
$app['EM']->flush();
- $url = $app->url('lightbox_compare', [
- 'basket' => $Basket->getId(),
- 'LOG' => $app['manipulator.token']->createBasketAccessToken($Basket, $user_receiver),
- ]);
+ $arguments = array(
+ 'ssel_id' => $Basket->getId(),
+ );
- $receipt = $request->get('recept') ? $app['authentication']->getUser()->getEmail() : '';
+ if (!$app['phraseanet.registry']->get('GV_force_push_authentication') || !$request->get('force_authentication')) {
+ $arguments['LOG'] = $app['manipulator.token']->createBasketAccessToken($Basket, $user_receiver);
+ }
+
+ $url = $app->url('lightbox_compare', $arguments);
+
+ $receipt = $request->get('recept') ? $app['authentication']->getUser()->get_email() : '';
$params = [
'from' => $app['authentication']->getUser()->getId(),
diff --git a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php
index ff06b8c1b3..f2047b7e14 100644
--- a/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php
+++ b/lib/Alchemy/Phrasea/Controller/Prod/Tooltip.php
@@ -99,12 +99,10 @@ class Tooltip implements ControllerProviderInterface
public function displayPreview(Application $app, $sbas_id, $record_id)
{
- $record = new \record_adapter($app, $sbas_id, $record_id);
-
- return $app['twig']->render(
- 'prod/Tooltip/Preview.html.twig'
- , ['record' => $record, 'not_wrapped' => true]
- );
+ return $app['twig']->render('prod/Tooltip/Preview.html.twig', array(
+ 'record' => new \record_adapter($app, $sbas_id, $record_id),
+ 'not_wrapped' => true
+ ));
}
public function displayCaption(Application $app, $sbas_id, $record_id, $context)
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Activity.php b/lib/Alchemy/Phrasea/Controller/Report/Activity.php
index daa452bc82..031195c6bf 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Activity.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Activity.php
@@ -309,8 +309,6 @@ class Activity implements ControllerProviderInterface
$activity->setConfig(false);
-
-
if ($request->request->get('printcsv') == 'on') {
$activity->setHasLimit(false);
$activity->setPrettyString(false);
@@ -862,13 +860,13 @@ class Activity implements ControllerProviderInterface
$result = $report->getResult();
array_unshift($result, $headers);
- $collection = new CallbackCollection($result, function($row) use ($report) {
+ $collection = new CallbackCollection($result, function ($row) use ($report) {
// restrict to displayed fields
return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
});
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $response = new CSVFileResponse($filename, function () use ($app, $collection) {
$app['csv.exporter']->export('php://output', $collection);
});
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Informations.php b/lib/Alchemy/Phrasea/Controller/Report/Informations.php
index 1dafb005ce..85fdc46895 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Informations.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Informations.php
@@ -520,13 +520,13 @@ class Informations implements ControllerProviderInterface
$result = $report->getResult();
array_unshift($result, $headers);
- $collection = new CallbackCollection($result, function($row) use ($report) {
+ $collection = new CallbackCollection($result, function ($row) use ($report) {
// restrict fields to the displayed ones
return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
});
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $response = new CSVFileResponse($filename, function () use ($app, $collection) {
$app['csv.exporter']->export('php://output', $collection);
});
diff --git a/lib/Alchemy/Phrasea/Controller/Report/Root.php b/lib/Alchemy/Phrasea/Controller/Report/Root.php
index 5b0b84e954..dbf5b0ac76 100644
--- a/lib/Alchemy/Phrasea/Controller/Report/Root.php
+++ b/lib/Alchemy/Phrasea/Controller/Report/Root.php
@@ -18,7 +18,6 @@ use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\JsonResponse;
-use Symfony\Component\HttpFoundation\ResponseHeaderBag;
class Root implements ControllerProviderInterface
{
@@ -486,28 +485,28 @@ class Root implements ControllerProviderInterface
$result = array();
$result[] = array_keys($conf_nav);
- foreach($report['nav']['result'] as $row) {
+ foreach ($report['nav']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_os);
- foreach($report['os']['result'] as $row) {
+ foreach ($report['os']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_res);
- foreach($report['res']['result'] as $row) {
+ foreach ($report['res']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_mod);
- foreach($report['mod']['result'] as $row) {
+ foreach ($report['mod']['result'] as $row) {
$result[] = array_values($row);
};
$result[] = array_keys($conf_combo);
- foreach($report['combo']['result'] as $row) {
+ foreach ($report['combo']['result'] as $row) {
$result[] = array_values($row);
};
$filename = sprintf('report_export_info_%s.csv', date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $result) {
+ $response = new CSVFileResponse($filename, function () use ($app, $result) {
$app['csv.exporter']->export('php://output', $result);
});
@@ -686,13 +685,13 @@ class Root implements ControllerProviderInterface
$result = $report->getResult();
array_unshift($result, $headers);
- $collection = new CallbackCollection($result, function($row) use ($report) {
+ $collection = new CallbackCollection($result, function ($row) use ($report) {
// restrict fields to the displayed ones
return array_map('strip_tags', array_intersect_key($row, $report->getDisplay()));
});
$filename = sprintf('report_export_%s_%s.csv', $type, date('Ymd'));
- $response = new CSVFileResponse($filename, function() use ($app, $collection) {
+ $response = new CSVFileResponse($filename, function () use ($app, $collection) {
$app['csv.exporter']->export('php://output', $collection);
});
diff --git a/lib/Alchemy/Phrasea/Controller/Root/Developers.php b/lib/Alchemy/Phrasea/Controller/Root/Developers.php
index 9406b7cc6f..f3e8643572 100644
--- a/lib/Alchemy/Phrasea/Controller/Root/Developers.php
+++ b/lib/Alchemy/Phrasea/Controller/Root/Developers.php
@@ -64,6 +64,10 @@ class Developers implements ControllerProviderInterface
->assert('application', '\d+')
->bind('submit_application_callback');
+ $controllers->post('/application/{id}/webhook/', $this->call('renewAppWebhook'))
+ ->assert('id', '\d+')
+ ->bind('submit_application_webhook');
+
return $controllers;
}
@@ -111,6 +115,30 @@ class Developers implements ControllerProviderInterface
return $app->json(['success' => true]);
}
+
+ /**
+ * Change application webhook
+ *
+ * @param Application $app A Silex application where the controller is mounted on
+ * @param Request $request The current request
+ * @param integer $id The application id
+ * @return JsonResponse
+ */
+ public function renewAppWebhook(Application $app, Request $request, $id)
+ {
+ if (!$request->isXmlHttpRequest() || !array_key_exists($request->getMimeType('json'), array_flip($request->getAcceptableContentTypes()))) {
+ $app->abort(400, _('Bad request format, only JSON is allowed'));
+ }
+
+ if (null !== $request->request->get("webhook")) {
+ $app['manipulator.api-application']->setWebhook($request->request->get("webhook"));
+ } else {
+ return $app->json(['success' => false]);
+ }
+
+ return $app->json(array('success' => true));
+ }
+
/**
* Authorize application to use a grant password type.
*
diff --git a/lib/Alchemy/Phrasea/Controller/Root/Login.php b/lib/Alchemy/Phrasea/Controller/Root/Login.php
index 546403921b..8b4e8ca2e6 100644
--- a/lib/Alchemy/Phrasea/Controller/Root/Login.php
+++ b/lib/Alchemy/Phrasea/Controller/Root/Login.php
@@ -284,6 +284,12 @@ class Login implements ControllerProviderInterface
unset($requestData['geonameid-completer']);
}
+ // Remove multiselect field for validation this field is added client side
+ // with bootstrap multiselect plugin
+ if (isset($requestData['multiselect'])) {
+ unset($requestData['multiselect']);
+ }
+
$form->bind($requestData);
$data = $form->getData();
@@ -717,7 +723,7 @@ class Login implements ControllerProviderInterface
$feeds = $app['repo.feeds']->findBy(['public' => true], ['updatedOn' => 'DESC']);
- $form = $app->form(new PhraseaAuthenticationForm());
+ $form = $app->form(new PhraseaAuthenticationForm($app));
$form->setData([
'redirect' => $request->query->get('redirect')
]);
@@ -739,7 +745,7 @@ class Login implements ControllerProviderInterface
*/
public function authenticate(PhraseaApplication $app, Request $request)
{
- $form = $app->form(new PhraseaAuthenticationForm());
+ $form = $app->form(new PhraseaAuthenticationForm($app));
$redirector = function (array $params = []) use ($app) {
return $app->redirectPath('homepage', $params);
};
@@ -1027,7 +1033,7 @@ class Login implements ControllerProviderInterface
$session->setToken($token)->setNonce($nonce);
- $response->headers->setCookie(new Cookie('persistent', $token));
+ $response->headers->setCookie(new Cookie('persistent', $token, time() + $app['phraseanet.configuration']['session']['lifetime']));
$app['EM']->persist($session);
$app['EM']->flush();
diff --git a/lib/Alchemy/Phrasea/Controller/Root/Session.php b/lib/Alchemy/Phrasea/Controller/Root/Session.php
index 5386cfc027..123f1d32da 100644
--- a/lib/Alchemy/Phrasea/Controller/Root/Session.php
+++ b/lib/Alchemy/Phrasea/Controller/Root/Session.php
@@ -28,6 +28,9 @@ class Session implements ControllerProviderInterface
$controllers->post('/update/', 'controller.session:updateSession')
->bind('update_session');
+ $controllers->post('/notifications/', 'controller.session:getNotifications')
+ ->bind('list_notifications');
+
$controller = $controllers->post('/delete/{id}', 'controller.session:deleteSession')
->bind('delete_session');
@@ -36,6 +39,76 @@ class Session implements ControllerProviderInterface
return $controllers;
}
+ /**
+ * Check things to notify
+ *
+ * @param Application $app
+ * @param Request $request
+ * @return JsonResponse
+ */
+ public function getNotifications(Application $app, Request $request)
+ {
+ if (!$request->isXmlHttpRequest()) {
+ $app->abort(400);
+ }
+
+ $ret = array(
+ 'status' => 'unknown',
+ 'message' => '',
+ 'notifications' => false,
+ 'changed' => array()
+ );
+
+ if ($app['authentication']->isAuthenticated()) {
+ $usr_id = $app['authentication']->getUser()->get_id();
+ if ($usr_id != $request->request->get('usr')) { // I logged with another user
+ $ret['status'] = 'disconnected';
+
+ return $app->json($ret);
+ }
+ } else {
+ $ret['status'] = 'disconnected';
+
+ return $app->json($ret);
+ }
+
+ try {
+ $app['phraseanet.appbox']->get_connection();
+ } catch (\Exception $e) {
+ return $app->json($ret);
+ }
+
+ if (1 > $moduleId = (int) $request->request->get('module')) {
+ $ret['message'] = 'Missing or Invalid `module` parameter';
+
+ return $app->json($ret);
+ }
+
+ $ret['status'] = 'ok';
+
+ $ret['notifications'] = $app['twig']->render('prod/notifications.html.twig', array(
+ 'notifications' => $app['events-manager']->get_notifications()
+ ));
+
+ $baskets = $app['EM']->getRepository('\Entities\Basket')->findUnreadActiveByUser($app['authentication']->getUser());
+
+ foreach ($baskets as $basket) {
+ $ret['changed'][] = $basket->getId();
+ }
+
+ if (in_array($app['session']->get('phraseanet.message'), array('1', null))) {
+ if ($app['phraseanet.configuration']['main']['maintenance']) {
+ $ret['message'] .= _('The application is going down for maintenance, please logout.');
+ }
+
+ if ($app['phraseanet.registry']->get('GV_message_on')) {
+ $ret['message'] .= strip_tags($app['phraseanet.registry']->get('GV_message'));
+ }
+ }
+
+ return $app->json($ret);
+ }
+
/**
* Check session state
*
diff --git a/lib/Alchemy/Phrasea/Controller/Setup.php b/lib/Alchemy/Phrasea/Controller/Setup.php
index f800a0b140..043affcf01 100644
--- a/lib/Alchemy/Phrasea/Controller/Setup.php
+++ b/lib/Alchemy/Phrasea/Controller/Setup.php
@@ -12,6 +12,8 @@
namespace Alchemy\Phrasea\Controller;
use Alchemy\Phrasea\Application;
+use Alchemy\Phrasea\Helper\DatabaseHelper;
+use Alchemy\Phrasea\Helper\PathHelper;
use Alchemy\Phrasea\Setup\Requirements\BinariesRequirements;
use Alchemy\Phrasea\Setup\Requirements\FilesystemRequirements;
use Alchemy\Phrasea\Setup\Requirements\LocalesRequirements;
@@ -46,6 +48,24 @@ class Setup implements ControllerProviderInterface
$controllers->post('/installer/install/', 'controller.setup:doInstall')
->bind('install_do_install');
+ $controllers->get('/connection_test/mysql/', function (Application $app, Request $request) {
+ $dbHelper = new DatabaseHelper($app, $request);
+
+ return $app->json($dbHelper->checkConnection());
+ });
+
+ $controllers->get('/test/path/', function (Application $app, Request $request) {
+ $pathHelper = new PathHelper($app, $request);
+
+ return $app->json($pathHelper->checkPath());
+ });
+
+ $controllers->get('/test/url/', function (Application $app, Request $request) {
+ $pathHelper = new PathHelper($app, $request);
+
+ return $app->json($pathHelper->checkUrl());
+ });
+
return $controllers;
}
diff --git a/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php b/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php
index 8bd0c4e692..8ce1462e8b 100644
--- a/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php
+++ b/lib/Alchemy/Phrasea/Controller/Thesaurus/Xmlhttp.php
@@ -739,7 +739,7 @@ class Xmlhttp implements ControllerProviderInterface
public function OpenBranchJson(Application $app, Request $request)
{
- if (null === $lng = $request->get('lng')) {
+ if (null === ($lng = $request->get('lng'))) {
$data = explode('_', $app['locale']);
if (count($data) > 0) {
$lng = $data[0];
@@ -750,6 +750,15 @@ class Xmlhttp implements ControllerProviderInterface
$sbid = (int) $request->get('sbid');
+ $lcoll = '';
+ $collections = $app['authentication']->getUser()->ACL()
+ ->get_granted_base(array(), array($sbid)); // array(), $sbid);
+ foreach ($collections as $collection) {
+ $lcoll .= ($lcoll?",":"") . $collection->get_coll_id();
+ }
+ $site = $app['phraseanet.configuration']['main']['key'];
+ $usr_id = $app['authentication']->getUser()->get_id();
+
$tids = explode('.', $request->get('id'));
$thid = implode('.', $tids);
@@ -765,11 +774,14 @@ class Xmlhttp implements ControllerProviderInterface
if ($lthid == 1) {
$dthid = str_replace('.', 'd', $thid);
- $sql = 'SELECT COUNT(DISTINCT record_id) AS n
- FROM thit WHERE value LIKE :like ';
+ $sql = 'SELECT COUNT(DISTINCT r.record_id) AS n
+ FROM (thit AS t INNER JOIN record AS r USING(record_id))
+ INNER JOIN collusr AS c ON c.site=:site AND c.usr_id=:usr_id AND r.coll_id=c.coll_id
+ WHERE t.value LIKE :like AND r.coll_id IN('.$lcoll.') AND (r.status^c.mask_xor)&c.mask_and=0';
+ $sqlparm = array(':like' => $dthid . '%', ':site'=>$site, ':usr_id'=>$usr_id);
$stmt = $connbas->prepare($sql);
- $stmt->execute([':like' => $dthid . '%']);
+ $stmt->execute($sqlparm);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
@@ -778,14 +790,16 @@ class Xmlhttp implements ControllerProviderInterface
}
$sql = 'SELECT
- SUBSTRING_INDEX(SUBSTR(value, ' . ($lthid + 1) . '), "d", 1) AS k ,
- COUNT(DISTINCT record_id) AS n
- FROM thit
- WHERE value LIKE :like
+ SUBSTRING_INDEX(SUBSTR(t.value, ' . ($lthid + 1) . '), "d", 1) AS k ,
+ COUNT(DISTINCT t.record_id) AS n
+ FROM (thit AS t INNER JOIN record AS r USING(record_id))
+ INNER JOIN collusr AS c ON c.site=:site AND c.usr_id=:usr_id AND r.coll_id=c.coll_id
+ WHERE t.value LIKE :like AND r.coll_id IN('.$lcoll.') AND (r.status^c.mask_xor)&c.mask_and=0
GROUP BY k';
+ $sqlparm = array(':like' => $dthid . '%', ':site'=>$site, ':usr_id'=>$usr_id);
$stmt = $connbas->prepare($sql);
- $stmt->execute([':like' => $dthid . '%']);
+ $stmt->execute(array(':like' => $dthid . '%'));
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
@@ -795,14 +809,16 @@ class Xmlhttp implements ControllerProviderInterface
} elseif (strlen($thid) > 1) {
$dthid = str_replace('.', 'd', $thid);
$sql = 'SELECT
- SUBSTRING_INDEX(SUBSTR(value, ' . ($lthid) . '), \'d\', 1) AS k ,
- COUNT(DISTINCT record_id) AS n
- FROM thit
- WHERE value LIKE :like
+ SUBSTRING_INDEX(SUBSTR(t.value, ' . ($lthid) . '), \'d\', 1) AS k ,
+ COUNT(DISTINCT t.record_id) AS n
+ FROM (thit AS t INNER JOIN record AS r USING(record_id))
+ INNER JOIN collusr AS c ON c.site=:site AND c.usr_id=:usr_id AND r.coll_id=c.coll_id
+ WHERE t.value LIKE :like AND r.coll_id IN('.$lcoll.') AND (r.status^c.mask_xor)&c.mask_and=0
GROUP BY k';
+ $sqlparm = array(':like' => $dthid . '%', ':site'=>$site, ':usr_id'=>$usr_id);
$stmt = $connbas->prepare($sql);
- $stmt->execute([':like' => $dthid . '%']);
+ $stmt->execute($sqlparm);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
@@ -811,14 +827,16 @@ class Xmlhttp implements ControllerProviderInterface
}
$sql = 'SELECT
- SUBSTRING_INDEX(SUBSTR(value, ' . ($lthid + 2) . '), \'d\', 1) AS k ,
- COUNT(DISTINCT record_id) AS n
- FROM thit
- WHERE value LIKE :like
+ SUBSTRING_INDEX(SUBSTR(t.value, ' . ($lthid + 2) . '), \'d\', 1) AS k ,
+ COUNT(DISTINCT t.record_id) AS n
+ FROM (thit AS t INNER JOIN record AS r USING(record_id))
+ INNER JOIN collusr AS c ON c.site=:site AND c.usr_id=:usr_id AND r.coll_id=c.coll_id
+ WHERE t.value LIKE :like AND r.coll_id IN('.$lcoll.') AND (r.status^c.mask_xor)&c.mask_and=0
GROUP BY k';
+ $sqlparm = array(':like' => $dthid . '%', ':site'=>$site, ':usr_id'=>$usr_id);
$stmt = $connbas->prepare($sql);
- $stmt->execute([':like' => $dthid . '%']);
+ $stmt->execute($sqlparm);
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
@@ -905,7 +923,7 @@ class Xmlhttp implements ControllerProviderInterface
$html .= '
' . "\n";
- if ($request->get('sortsy') && $request->get('lng')) {
+ if ($request->get('sortsy') && $lng != '') {
ksort($tts, SORT_STRING);
} elseif ($request->get('type') == 'C') {
$tts = array_reverse($tts);
diff --git a/lib/Alchemy/Phrasea/Controller/Utils/ConnectionTest.php b/lib/Alchemy/Phrasea/Controller/Utils/ConnectionTest.php
deleted file mode 100644
index a1df538367..0000000000
--- a/lib/Alchemy/Phrasea/Controller/Utils/ConnectionTest.php
+++ /dev/null
@@ -1,99 +0,0 @@
-get('/mysql/', function (Application $app) {
-
- $request = $app['request'];
- $hostname = $request->query->get('hostname', '127.0.0.1');
- $port = (int) $request->query->get('port', 3306);
- $user = $request->query->get('user');
- $password = $request->query->get('password');
- $dbname = $request->query->get('dbname');
-
- $connection_ok = $db_ok = $is_databox = $is_appbox = $empty = false;
-
- try {
- $conn = $app['dbal.provider']->get([
- 'host' => $hostname,
- 'port' => $port,
- 'user' => $user,
- 'password' => $password,
- ]);
- $conn->connect();
- $connection_ok = true;
- } catch (\Exception $e) {
-
- }
-
- if ($dbname && $connection_ok === true) {
- try {
- $conn = $app['dbal.provider']->get([
- 'host' => $hostname,
- 'port' => $port,
- 'user' => $user,
- 'password' => $password,
- 'dbname' => $dbname,
- ]);
- $conn->connect();
- $db_ok = true;
-
- $sql = "SHOW TABLE STATUS";
- $stmt = $conn->prepare($sql);
- $stmt->execute();
-
- $empty = $stmt->rowCount() === 0;
-
- $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
- $stmt->closeCursor();
-
- foreach ($rs as $row) {
- if ($row["Name"] === 'sitepreff') {
- $is_appbox = true;
- }
- if ($row["Name"] === 'pref') {
- $is_databox = true;
- }
- }
- } catch (\Exception $e) {
-
- }
- }
-
- $datas = [
- 'connection' => $connection_ok
- , 'database' => $db_ok
- , 'is_empty' => $empty
- , 'is_appbox' => $is_appbox
- , 'is_databox' => $is_databox
- ];
-
- return $app->json($datas);
- });
-
- return $controllers;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Controller/Utils/PathFileTest.php b/lib/Alchemy/Phrasea/Controller/Utils/PathFileTest.php
deleted file mode 100644
index 7627ea6282..0000000000
--- a/lib/Alchemy/Phrasea/Controller/Utils/PathFileTest.php
+++ /dev/null
@@ -1,46 +0,0 @@
-get('/path/', function (Application $app, Request $request) {
- return $app->json([
- 'exists' => file_exists($request->query->get('path'))
- , 'file' => is_file($request->query->get('path'))
- , 'dir' => is_dir($request->query->get('path'))
- , 'readable' => is_readable($request->query->get('path'))
- , 'writeable' => is_writable($request->query->get('path'))
- , 'executable' => is_executable($request->query->get('path'))
- ]);
- });
-
- $controllers->get('/url/', function (Application $app, Request $request) {
- return $app->json(['code' => \http_query::getHttpCodeFromUrl($request->query->get('url'))]);
- });
-
- return $controllers;
- }
-}
diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiCorsSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiCorsSubscriber.php
new file mode 100644
index 0000000000..f1f4ab2e3b
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/ApiCorsSubscriber.php
@@ -0,0 +1,207 @@
+app = $app;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ KernelEvents::REQUEST => array('onKernelRequest', 128),
+ );
+ }
+
+ public function onKernelRequest(GetResponseEvent $event)
+ {
+ if (!$this->app['phraseanet.configuration']['api_cors']['enabled']) {
+ return;
+ }
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ return;
+ }
+ $request = $event->getRequest();
+
+ if (!preg_match('{api/v(\d+)}i', $request->getPathInfo() ?: '/')) {
+ return;
+ }
+
+ // skip if not a CORS request
+ if (!$request->headers->has('Origin') || $request->headers->get('Origin') == $request->getSchemeAndHttpHost()) {
+ return;
+ }
+
+ $options = array_merge(array(
+ 'allow_credentials'=> false,
+ 'allow_origin'=> array(),
+ 'allow_headers'=> array(),
+ 'allow_methods'=> array(),
+ 'expose_headers'=> array(),
+ 'max_age'=> 0,
+ 'hosts'=> array(),
+ ), $this->app['phraseanet.configuration']['api_cors']);
+
+ // skip if the host is not matching
+ if (!$this->checkHost($request, $options)) {
+ return;
+ }
+ // perform preflight checks
+ if ('OPTIONS' === $request->getMethod()) {
+ $event->setResponse($this->getPreflightResponse($request, $options));
+
+ return;
+ }
+ if (!$this->checkOrigin($request, $options)) {
+ $response = new Response('', 403, array('Access-Control-Allow-Origin' => 'null'));
+ $event->setResponse($response);
+
+ return;
+ }
+
+ $this->app['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'));
+ $this->options = $options;
+ }
+
+ public function onKernelResponse(FilterResponseEvent $event)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ return;
+ }
+
+ $response = $event->getResponse();
+ $request = $event->getRequest();
+ // add CORS response headers
+ $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
+ if ($this->options['allow_credentials']) {
+ $response->headers->set('Access-Control-Allow-Credentials', 'true');
+ }
+ if ($this->options['expose_headers']) {
+ $response->headers->set('Access-Control-Expose-Headers', strtolower(implode(', ', $this->options['expose_headers'])));
+ }
+ }
+
+ protected function getPreflightResponse(Request $request, array $options)
+ {
+ $response = new Response();
+
+ if ($options['allow_credentials']) {
+ $response->headers->set('Access-Control-Allow-Credentials', 'true');
+ }
+ if ($options['allow_methods']) {
+ $response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
+ }
+ if ($options['allow_headers']) {
+ $headers = in_array('*', $options['allow_headers'])
+ ? $request->headers->get('Access-Control-Request-Headers')
+ : implode(', ', array_map('strtolower', $options['allow_headers']));
+ $response->headers->set('Access-Control-Allow-Headers', $headers);
+ }
+ if ($options['max_age']) {
+ $response->headers->set('Access-Control-Max-Age', $options['max_age']);
+ }
+
+ if (!$this->checkOrigin($request, $options)) {
+ $response->headers->set('Access-Control-Allow-Origin', 'null');
+
+ return $response;
+ }
+
+ $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
+
+ // check request method
+ if (!in_array(strtoupper($request->headers->get('Access-Control-Request-Method')), $options['allow_methods'], true)) {
+ $response->setStatusCode(405);
+
+ return $response;
+ }
+
+ /**
+ * We have to allow the header in the case-set as we received it by the client.
+ * Firefox f.e. sends the LINK method as "Link", and we have to allow it like this or the browser will deny the
+ * request.
+ */
+ if (!in_array($request->headers->get('Access-Control-Request-Method'), $options['allow_methods'], true)) {
+ $options['allow_methods'][] = $request->headers->get('Access-Control-Request-Method');
+ $response->headers->set('Access-Control-Allow-Methods', implode(', ', $options['allow_methods']));
+ }
+
+ // check request headers
+ $headers = $request->headers->get('Access-Control-Request-Headers');
+ if ($options['allow_headers'] !== true && $headers) {
+ $headers = trim(strtolower($headers));
+ foreach (preg_split('{, *}', $headers) as $header) {
+ if (in_array($header, self::$simpleHeaders, true)) {
+ continue;
+ }
+ if (!in_array($header, $options['allow_headers'], true)) {
+ $response->setStatusCode(400);
+ $response->setContent('Unauthorized header '.$header);
+ break;
+ }
+ }
+ }
+
+ return $response;
+ }
+
+ protected function checkOrigin(Request $request, array $options)
+ {
+ // check origin
+ $origin = $request->headers->get('Origin');
+ if (in_array('*', $options['allow_origin']) || in_array($origin, $options['allow_origin'])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ protected function checkHost(Request $request, array $options)
+ {
+ if (count($options['hosts']) === 0) {
+ return true;
+ }
+
+ foreach ($options['hosts'] as $hostRegexp) {
+ if (preg_match('{'.$hostRegexp.'}i', $request->getHost())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Core/Event/Subscriber/SessionManagerSubscriber.php b/lib/Alchemy/Phrasea/Core/Event/Subscriber/SessionManagerSubscriber.php
new file mode 100644
index 0000000000..0b3481a059
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Event/Subscriber/SessionManagerSubscriber.php
@@ -0,0 +1,157 @@
+app = $app;
+ }
+
+ public static function getSubscribedEvents()
+ {
+ return array(
+ KernelEvents::REQUEST => array(
+ array('initSession', Application::EARLY_EVENT),
+ array('checkSessionActivity', Application::LATE_EVENT)
+ )
+ );
+ }
+
+ public function initSession(GetResponseEvent $event)
+ {
+ if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
+ return;
+ }
+
+ if ($this->isFlashUploadRequest($event->getRequest())) {
+ if (null !== $sessionId = $event->getRequest()->request->get('php_session_id')) {
+
+ $request = $event->getRequest();
+ $request->cookies->set($this->app['session']->getName(), $sessionId);
+
+ return $request;
+ }
+ }
+ }
+
+ /**log real human activity on application, to keep session alive*/
+ public function checkSessionActivity(GetResponseEvent $event)
+ {
+ $modulesIds = array(
+ "prod" => 1,
+ "client" => 2,
+ "admin" => 3,
+ "thesaurus" => 5,
+ "report" => 10,
+ "lightbox" => 6,
+ );
+
+ $pathInfo = array_filter(explode('/', $event->getRequest()->getPathInfo()));
+
+ if (count($pathInfo) < 1) {
+ return;
+ }
+ $moduleName = strtolower($pathInfo[1]);
+
+ if (!array_key_exists($moduleName, $modulesIds) ) {
+ return;
+ }
+ // this route is polled by js in admin/databox to refresh infos (progress bar...)
+ if (preg_match("#^/admin/databox/[0-9]+/informations/documents/#", $event->getRequest()->getPathInfo()) == 1) {
+ return;
+ }
+ // this route is polled by js in admin/tasks to refresh tasks status
+ if ($event->getRequest()->getPathInfo() == "/admin/task-manager/tasks/" && $event->getRequest()->getContentType() == 'json') {
+ return;
+ }
+
+ if ($this->isFlashUploadRequest($event->getRequest())) {
+ return;
+ }
+
+ if ($event->getRequest()->query->has('LOG')) {
+ return;
+ }
+
+ // if we are already disconnected (ex. from another window), quit immediatly
+ if (!($this->app['authentication']->isAuthenticated())) {
+ if ($event->getRequest()->isXmlHttpRequest()) {
+ $response = new Response("End-Session", 403);
+ } else {
+ $response = new RedirectResponse($this->app["url_generator"]->generate("homepage", array("redirect"=>'..' . $event->getRequest()->getPathInfo())));
+ }
+ $response->headers->set('X-Phraseanet-End-Session', '1');
+
+ $event->setResponse($response);
+
+ return;
+ }
+ $session = $this->app['EM']->find('Entities\Session', $this->app['session']->get('session_id'));
+
+ $idle = 0;
+ if (isset($this->app["phraseanet.configuration"]["session"]["idle"])) {
+ $idle = (int) ($this->app["phraseanet.configuration"]["session"]["idle"]);
+ }
+ $now = new \DateTime();
+ $dt = $now->getTimestamp() - $session->getUpdated()->getTimestamp();
+ if ($idle > 0 && $dt > $idle) {
+ // we must disconnet due to idletime
+ $this->app['authentication']->closeAccount();
+ if ($event->getRequest()->isXmlHttpRequest()) {
+ $response = new Response("End-Session", 403);
+ } else {
+ $response = new RedirectResponse($this->app["url_generator"]->generate("homepage", array("redirect"=>'..' . $event->getRequest()->getPathInfo())));
+ }
+ $response->headers->set('X-Phraseanet-End-Session', '1');
+
+ $event->setResponse($response);
+
+ return;
+ }
+ $moduleId = $modulesIds[$moduleName];
+
+ $session->setUpdated(new \DateTime());
+
+ if (!$session->hasModuleId($moduleId)) {
+ $module = new SessionModule();
+ $module->setModuleId($moduleId);
+ $module->setSession($session);
+ $session->addModule($module);
+
+ $this->app['EM']->persist($module);
+ } else {
+ $this->app['EM']->persist($session->getModuleById($moduleId)->setUpdated(new \DateTime()));
+ }
+ $this->app['EM']->persist($session);
+ $this->app['EM']->flush();
+ }
+
+ private function isFlashUploadRequest(Request $request)
+ {
+ return false !== stripos($request->server->get('HTTP_USER_AGENT'), 'flash')
+ && $request->getRequestUri() === '/prod/upload/';
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php
index be841339f3..540224149f 100644
--- a/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php
+++ b/lib/Alchemy/Phrasea/Core/Provider/CSVServiceProvider.php
@@ -26,8 +26,9 @@ class CSVServiceProvider implements ServiceProviderInterface
{
$app['csv.exporter.config'] = $app->share(function () {
$config = new ExporterConfig();
+
return $config
- ->setDelimiter(",")
+ ->setDelimiter(";")
->setEnclosure('"')
->setEscape("\\")
->setToCharset('UTF-8')
@@ -40,7 +41,14 @@ class CSVServiceProvider implements ServiceProviderInterface
});
$app['csv.lexer.config'] = $app->share(function ($app) {
- return new LexerConfig();
+ $lexer = new LexerConfig();
+ $lexer->setDelimiter(';')
+ ->setEnclosure('"')
+ ->setEscape("\\")
+ ->setToCharset('UTF-8')
+ ->setFromCharset('UTF-8');
+
+ return $lexer;
});
$app['csv.lexer'] = $app->share(function ($app) {
diff --git a/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php
new file mode 100644
index 0000000000..1fda4c978b
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Core/Provider/PhraseaEventServiceProvider.php
@@ -0,0 +1,46 @@
+share(function (Application $app) {
+ return new LogoutSubscriber();
+ });
+ $app['phraseanet.locale-subscriber'] = $app->share(function (Application $app) {
+ return new PhraseaLocaleSubscriber($app);
+ });
+ $app['phraseanet.maintenance-subscriber'] = $app->share(function (Application $app) {
+ return new MaintenanceSubscriber($app);
+ });
+ $app['phraseanet.cookie-disabler-subscriber'] = $app->share(function (Application $app) {
+ return new CookiesDisablerSubscriber($app);
+ });
+ $app['phraseanet.session-manager-subscriber'] = $app->share(function (Application $app) {
+ return new SessionManagerSubscriber($app);
+ });
+ }
+
+ public function boot(Application $app)
+ {
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php b/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php
index 19863dfcee..da223582a7 100644
--- a/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php
+++ b/lib/Alchemy/Phrasea/Core/Response/CSVFileResponse.php
@@ -40,4 +40,4 @@ class CSVFileResponse extends StreamedResponse
false === preg_match('/^[\x20-\x7e]*$/', $filename) ? '' : preg_replace('/[^(x20-x7F)]*$/', '', $filename)
));
}
-}
\ No newline at end of file
+}
diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaAuthenticationForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaAuthenticationForm.php
index 8a1074f728..ac8d529845 100644
--- a/lib/Alchemy/Phrasea/Form/Login/PhraseaAuthenticationForm.php
+++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaAuthenticationForm.php
@@ -14,9 +14,17 @@ namespace Alchemy\Phrasea\Form\Login;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert;
+use Silex\Application;
class PhraseaAuthenticationForm extends AbstractType
{
+ private $app;
+
+ public function __construct(Application $app)
+ {
+ $this->app = $app;
+ }
+
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('login', 'text', [
@@ -37,15 +45,22 @@ class PhraseaAuthenticationForm extends AbstractType
],
]);
- $builder->add('remember-me', 'checkbox', [
- 'label' => 'Remember me',
- 'mapped' => false,
- 'required' => false,
- 'attr' => [
- 'checked' => 'checked',
- 'value' => '1',
- ]
- ]);
+ if ($this->app['phraseanet.configuration']['session']['idle'] < 1) {
+ $builder->add('remember-me', 'checkbox' , array(
+ 'label' => _('Remember me'),
+ 'mapped' => false,
+ 'required' => false,
+ 'attr' => array(
+ 'value' => '1',
+ )
+ ));
+ } else {
+ $builder->add('remember-me', 'hidden' , array(
+ 'label' => '',
+ 'mapped' => false,
+ 'required' => false
+ ));
+ }
$builder->add('redirect', 'hidden', [
'required' => false,
diff --git a/lib/Alchemy/Phrasea/Helper/DatabaseHelper.php b/lib/Alchemy/Phrasea/Helper/DatabaseHelper.php
new file mode 100644
index 0000000000..244ec4519c
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Helper/DatabaseHelper.php
@@ -0,0 +1,70 @@
+request->query->get('hostname', '127.0.0.1');
+ $port = (int) $this->request->query->get('port', 3306);
+ $user = $this->request->query->get('user');
+ $password = $this->request->query->get('password');
+ $dbname = $this->request->query->get('dbname');
+
+ $connection_ok = $db_ok = $is_databox = $is_appbox = $empty = false;
+
+ try {
+ $conn = new \connection_pdo('test', $hostname, $port, $user, $password, null, array(), false);
+ $connection_ok = true;
+ } catch (\Exception $e) {
+
+ }
+
+ if ($dbname && $connection_ok === true) {
+ try {
+ $conn = new \connection_pdo('test', $hostname, $port, $user, $password, $dbname, array(), false);
+ $db_ok = true;
+
+ $sql = "SHOW TABLE STATUS";
+ $stmt = $conn->prepare($sql);
+ $stmt->execute();
+
+ $empty = $stmt->rowCount() === 0;
+
+ $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ foreach ($rs as $row) {
+ if ($row["Name"] === 'sitepreff') {
+ $is_appbox = true;
+ }
+ if ($row["Name"] === 'pref') {
+ $is_databox = true;
+ }
+ }
+ } catch (\Exception $e) {
+
+ }
+ }
+
+ return array(
+ 'connection' => $connection_ok,
+ 'database' => $db_ok,
+ 'is_empty' => $empty,
+ 'is_appbox' => $is_appbox,
+ 'is_databox' => $is_databox
+ );
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Helper/PathHelper.php b/lib/Alchemy/Phrasea/Helper/PathHelper.php
new file mode 100644
index 0000000000..2093a5f2fe
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Helper/PathHelper.php
@@ -0,0 +1,34 @@
+ file_exists($this->request->query->get('path')),
+ 'file' => is_file($this->request->query->get('path')),
+ 'dir' => is_dir($this->request->query->get('path')),
+ 'readable' => is_readable($this->request->query->get('path')),
+ 'writeable' => is_writable($this->request->query->get('path')),
+ 'executable' => is_executable($this->request->query->get('path')),
+ );
+ }
+
+ public function checkUrl()
+ {
+ return array('code' => \http_query::getHttpCodeFromUrl($this->request->query->get('url')));
+ }
+}
diff --git a/lib/Alchemy/Phrasea/Metadata/Tag/Nosource.php b/lib/Alchemy/Phrasea/Metadata/Tag/Nosource.php
index b3797ed4a8..012f45f073 100644
--- a/lib/Alchemy/Phrasea/Metadata/Tag/Nosource.php
+++ b/lib/Alchemy/Phrasea/Metadata/Tag/Nosource.php
@@ -26,8 +26,13 @@ class Nosource extends AbstractTag
protected $Writable = false;
protected $Description = 'An empty source';
+ public function setTagname($name)
+ {
+ $this->Name = $name;
+ }
+
public function getTagname()
{
- return '';
+ return $this->Name;
}
}
diff --git a/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php
index 17e559645c..a14cbbc6f1 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/Phrasea/PhraseaEngine.php
@@ -623,18 +623,14 @@ class PhraseaEngine implements SearchEngineInterface
$sxe = @simplexml_load_string($res['xml']);
foreach ($fields as $name => $field) {
- if ($sxe && $sxe->description && $sxe->description->$name) {
- $val = [];
- foreach ($sxe->description->$name as $value) {
- $val[] = (string) $value;
+ $newValues = array();
+ if ($sxe && $sxe->description && $sxe->description->{$name}) {
+ foreach ($sxe->description->{$name} as $value) {
+ $newValues[(string) $value['meta_id']] = (string) $value;
}
- $separator = $field['separator'] ? $field['separator'][0] : '';
- $val = implode(' ' . $separator . ' ', $val);
- } else {
- $val = $field['value'];
- }
- $ret[] = $val;
+ $ret[$name] = $newValues;
+ }
}
return $ret;
diff --git a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php
index 2cb03e92cd..6eb35d69b7 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php
@@ -23,6 +23,7 @@ class SearchEngineOptions
const TYPE_AUDIO = 'audio';
const TYPE_DOCUMENT = 'document';
const TYPE_FLASH = 'flash';
+ const TYPE_UNKNOWN = 'unknown';
const TYPE_ALL = '';
const SORT_RELEVANCE = 'relevance';
const SORT_CREATED_ON = 'created_on';
@@ -378,6 +379,9 @@ class SearchEngineOptions
case self::TYPE_IMAGE:
$this->record_type = self::TYPE_IMAGE;
break;
+ case self::TYPE_UNKNOWN:
+ $this->record_type = self::TYPE_UNKNOWN;
+ break;
}
return $this;
diff --git a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
index 0515c1b43a..a9e72e5e51 100644
--- a/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
+++ b/lib/Alchemy/Phrasea/SearchEngine/SphinxSearch/SphinxSearchEngine.php
@@ -519,40 +519,7 @@ class SphinxSearchEngine implements SearchEngineInterface
*/
public function excerpt($query, $fields, \record_adapter $record, SearchEngineOptions $options = null)
{
- if (null === $options) {
- $options = new SearchEngineOptions();
- }
-
- $this->applyOptions($options);
-
- $index = '';
- // in this case search is done on metas
- if ($options->getFields() || $options->getBusinessFieldsOn()) {
- if ($options->isStemmed() && $options->getLocale()) {
- $index = 'metadatas' . $this->CRCdatabox($record->get_databox()) . '_stemmed_' . $options->getLocale();
- } else {
- $index = 'metadatas' . $this->CRCdatabox($record->get_databox());
- }
- } else {
- if ($options->isStemmed() && $options->getLocale()) {
- $index = 'documents' . $this->CRCdatabox($record->get_databox()) . '_stemmed_' . $options->getLocale();
- } else {
- $index = 'documents' . $this->CRCdatabox($record->get_databox());
- }
- }
-
- $opts = [
- 'before_match' => "[[em]]",
- 'after_match' => "[[/em]]",
- ];
-
- $fields_to_send = [];
-
- foreach ($fields as $k => $f) {
- $fields_to_send[$k] = $f['value'];
- }
-
- return $this->sphinx->BuildExcerpts($fields_to_send, $index, $query, $opts);
+ return array();
}
/**
diff --git a/lib/Alchemy/Phrasea/Security/Firewall.php b/lib/Alchemy/Phrasea/Security/Firewall.php
index aee33cbdb0..2528a1331a 100644
--- a/lib/Alchemy/Phrasea/Security/Firewall.php
+++ b/lib/Alchemy/Phrasea/Security/Firewall.php
@@ -111,10 +111,14 @@ class Firewall
return $this;
}
- public function requireAuthentication()
+ public function requireAuthentication(Request $request = null)
{
+ $params = array();
+ if (null !== $request) {
+ $params['redirect'] = '..' . $request->getPathInfo();
+ }
if (!$this->app['authentication']->isAuthenticated()) {
- return new RedirectResponse($this->app->path('homepage'));
+ return new RedirectResponse($this->app->path('homepage', $params));
}
}
@@ -127,7 +131,7 @@ class Firewall
$app = $this->app;
$controllers->before(function (Request $request) use ($app) {
- if (null !== $response = $app['firewall']->requireAuthentication()) {
+ if (null !== $response = $app['firewall']->requireAuthentication($request)) {
return $response;
}
});
diff --git a/lib/Alchemy/Phrasea/Twig/Fit.php b/lib/Alchemy/Phrasea/Twig/Fit.php
new file mode 100644
index 0000000000..a4bb2c1bba
--- /dev/null
+++ b/lib/Alchemy/Phrasea/Twig/Fit.php
@@ -0,0 +1,89 @@
+ new \Twig_Function_Method($this, 'fitIn')
+ );
+ }
+
+ public function fitIn(array $content, array $box)
+ {
+ $contentRatio = $content['width'] / $content['height'];
+ $boxRatio = $box['width'] / $box['height'];
+
+ if ($contentRatio > $boxRatio) {
+ if ($box['width'] > $content['width']) {
+ $width = $content['width'];
+ } else {
+ $width = $box['width'];
+ }
+
+ $height = $width / $content['width'] * $content['height'];
+
+ $left = 0;
+ $top = 0;
+
+ if ($contentRatio > 1) {
+ // mode landscape
+ $top = ($box['height'] - $height) / 2;
+ } elseif ($contentRatio < 1) {
+ // mode portrait
+ $left = ($box['width'] - $width) / 2;
+ } else {
+ // square mode
+ $top = ($box['height'] - $height) / 2;
+ $left = ($box['width'] - $width) / 2;
+ }
+ } else {
+ if ($box['height'] > $content['height']) {
+ $height = $content['height'];
+ } else {
+ $height = $box['height'];
+ }
+
+ $width = $height * $contentRatio;
+
+ $left = 0;
+ $top = 0;
+
+ if ($contentRatio > 1) {
+ // mode landscape
+ $top = ($box['height'] - $height) / 2;
+ } elseif ($contentRatio < 1) {
+ // mode portrait
+ $left = ($box['width'] - $width) / 2;;
+ } else {
+ // square mode
+ $top = ($box['height'] - $height) / 2;
+ $left = ($box['width'] - $width) / 2;;
+ }
+ }
+
+ return array(
+ 'width' => round($width),
+ 'height' => round($height),
+ 'top' => round($top),
+ 'left' => round($left)
+ );
+ }
+}
diff --git a/lib/classes/API/Webhook.php b/lib/classes/API/Webhook.php
new file mode 100644
index 0000000000..413ff913a9
--- /dev/null
+++ b/lib/classes/API/Webhook.php
@@ -0,0 +1,95 @@
+appbox = $appbox;
+ $this->id = $id;
+ $sql = 'SELECT `type`, `data`, created
+ FROM api_webhooks
+ WHERE id = :id';
+ $stmt = $this->appbox->get_connection()->prepare($sql);
+ $stmt->execute(array(':id' => $id));
+ $row = $stmt->fetch(\PDO::FETCH_ASSOC);
+
+ if (!$row) {
+ throw new RuntimeException('Webhooks not found');
+ }
+
+ $stmt->closeCursor();
+
+ $this->type = $row['type'];
+ $this->data = json_decode($row['data']);
+ $this->created = new \DateTime($row['created']);
+ }
+
+ public function delete()
+ {
+ $sql = 'DELETE FROM api_webhooks WHERE id = :id';
+
+ $stmt = $this->appbox->get_connection()->prepare($sql);
+ $stmt->execute(array(':id' => $this->id));
+ $stmt->closeCursor();
+
+ return;
+ }
+
+ public static function create(appbox $appbox, $type, array $data)
+ {
+ $sql = 'INSERT INTO api_webhooks (id, `type`, `data`, created)
+ VALUES (null, :type, :data, NOW())';
+
+ $stmt = $appbox->get_connection()->prepare($sql);
+ $stmt->execute(array(
+ 'type' => $type,
+ 'data' => json_encode($data),
+ ));
+ $stmt->closeCursor();
+
+ return new API_Webhook($appbox, $appbox->get_connection()->lastInsertId());
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getCreated()
+ {
+ return $this->created;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+}
diff --git a/lib/classes/Feed/Adapter.php b/lib/classes/Feed/Adapter.php
new file mode 100644
index 0000000000..dc90224b9c
--- /dev/null
+++ b/lib/classes/Feed/Adapter.php
@@ -0,0 +1,722 @@
+app = $app;
+ $this->id = (int) $id;
+
+ $this->load();
+
+ return $this;
+ }
+
+ protected function load()
+ {
+ try {
+ $datas = $this->get_data_from_cache();
+
+ $this->title = $datas['title'];
+ $this->subtitle = $datas['subtitle'];
+ $this->collection = $datas['base_id'] ? collection::get_from_base_id($this->app, $datas['base_id']) : null;
+ $this->created_on = $datas['created_on'];
+ $this->updated_on = $datas['updated_on'];
+ $this->public = $datas['public'];
+
+ return $this;
+ } catch (\Exception $e) {
+
+ }
+
+ $sql = 'SELECT id, title, subtitle, created_on, updated_on, base_id, public
+ FROM feeds WHERE id = :feed_id';
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':feed_id' => $this->id));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ if (!$row)
+ throw new NotFoundHttpException('Feed not found');
+
+ $this->title = $row['title'];
+ $this->subtitle = $row['subtitle'];
+ if (!is_null($row['base_id']))
+ $this->collection = collection::get_from_base_id($this->app, $row['base_id']);
+ $this->created_on = new DateTime($row['created_on']);
+ $this->updated_on = new DateTime($row['updated_on']);
+ $this->public = !!$row['public'];
+
+ $base_id = $this->collection instanceof collection ? $this->collection->get_base_id() : null;
+
+ $datas = array(
+ 'title' => $this->title
+ , 'subtitle' => $this->subtitle
+ , 'base_id' => $base_id
+ , 'created_on' => $this->created_on
+ , 'updated_on' => $this->updated_on
+ , 'public' => $this->public
+ );
+
+ $this->set_data_to_cache($datas);
+
+ return $this;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function get_icon_url()
+ {
+ if ($this->icon_url) {
+ return $this->icon_url;
+ }
+
+ $url = '/skins/icons/rss32.gif';
+
+ $file = $this->app['root.path']
+ . '/www/custom/feed_' . $this->get_id() . '.jpg';
+
+ if (file_exists($file)) {
+ $url = '/custom/feed_' . $this->get_id() . '.jpg';
+ }
+
+ $this->icon_url = $url;
+
+ return $this->icon_url;
+ }
+
+ /**
+ *
+ * @param string $file The path to the file
+ * @return Feed_Adapter
+ */
+ public function set_icon($file)
+ {
+ if (!file_exists($file)) {
+ throw new \Alchemy\Phrasea\Exception\InvalidArgumentException('File does not exists');
+ }
+
+ $config_file = $this->app['root.path'] . '/config/feed_' . $this->get_id() . '.jpg';
+ $www_file = $this->app['root.path'] . '/www/custom/feed_' . $this->get_id() . '.jpg';
+
+ copy($file, $config_file);
+ copy($file, $www_file);
+ $this->icon_url = null;
+
+ return $this;
+ }
+
+ public function set_created_on(DateTime $created_on)
+ {
+ $sql = 'UPDATE feeds SET created_on = :created_on
+ WHERE id = :feed_id';
+ $params = array(
+ ':created_on' => $created_on->format(DATE_ISO8601)
+ , ':feed_id' => $this->get_id()
+ );
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $stmt->closeCursor();
+ $this->created_on = $created_on;
+ $this->delete_data_from_cache();
+
+ return $this;
+ }
+
+ public function reset_icon()
+ {
+ $config_file = $this->app['root.path']
+ . '/config/feed_' . $this->get_id() . '.jpg';
+ $www_file = $this->app['root.path']
+ . '/www/custom/feed_' . $this->get_id() . '.jpg';
+
+ if (is_file($config_file))
+ unlink($config_file);
+ if (is_file($www_file))
+ unlink($www_file);
+
+ $this->icon_url = null;
+
+ return $this;
+ }
+
+ /**
+ *
+ * @return boolean
+ */
+ public function is_aggregated()
+ {
+ return false;
+ }
+
+ /**
+ *
+ * @param User_Adapter $user
+ * @return boolean
+ */
+ public function is_owner(User_Adapter $user)
+ {
+ $this->load_publishers();
+
+ if (!$this->owner) {
+ return false;
+ }
+
+ return $this->owner->get_user()->get_id() === $user->get_id();
+ }
+
+ /**
+ *
+ * @param User_Adapter $user
+ * @return boolean
+ */
+ public function is_publisher(User_Adapter $user)
+ {
+ return in_array($user->get_id(), array_keys($this->get_publishers()));
+ }
+
+ /**
+ * Tells if a user has access to the feed
+ *
+ * @param User_Adapter $user
+ * @return type
+ */
+ public function has_access(User_Adapter $user)
+ {
+ if ($this->get_collection() instanceof collection) {
+ return $user->ACL()->has_access_to_base($this->collection->get_base_id());
+ }
+
+ return true;
+ }
+
+ /**
+ *
+ * @return boolean
+ */
+ public function is_public()
+ {
+ if ($this->get_collection() instanceof collection) {
+ return false;
+ }
+
+ return $this->public;
+ }
+
+ /**
+ *
+ * @return array
+ */
+ public function get_publishers()
+ {
+ return $this->load_publishers();
+ }
+
+ /**
+ *
+ * @return collection
+ */
+ public function get_collection()
+ {
+ return $this->collection;
+ }
+
+ /**
+ *
+ * @param User_Adapter $user
+ * @return Feed_Adapter
+ */
+ public function add_publisher(User_Adapter $user)
+ {
+ if (in_array($user->get_id(), array_keys($this->get_publishers()))) {
+ return $this;
+ }
+
+ Feed_Publisher_Adapter::create($this->app, $user, $this, false);
+ $this->publishers = null;
+
+ return $this;
+ }
+
+ /**
+ *
+ * @return array
+ */
+ protected function load_publishers()
+ {
+ if (is_array($this->publishers)) {
+ return $this->publishers;
+ }
+
+ $sql = 'SELECT id, usr_id, owner FROM feed_publishers
+ WHERE feed_id = :feed_id';
+
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':feed_id' => $this->id));
+ $rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ foreach ($rs as $row) {
+ try {
+ $publisher = new Feed_Publisher_Adapter($this->app, $row['id']);
+ } catch (\Exception_Feed_PublisherNotFound $e) {
+ continue;
+ }
+ $this->publishers[$row['usr_id']] = $publisher;
+ if ($publisher->is_owner()) {
+ $this->owner = $publisher;
+ }
+ }
+
+ return $this->publishers;
+ }
+
+ /**
+ *
+ * @return int
+ */
+ public function get_id()
+ {
+ return $this->id;
+ }
+
+ /**
+ *
+ * @param collection $collection
+ * @return Feed_Adapter
+ */
+ public function set_collection(collection $collection = null)
+ {
+ $base_id = null;
+ if ($collection instanceof collection) {
+ $base_id = $collection->get_base_id();
+ }
+
+ $sql = 'UPDATE feeds SET base_id = :base_id, updated_on = NOW()
+ WHERE id = :feed_id';
+ $params = array(':base_id' => $base_id, ':feed_id' => $this->get_id());
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $stmt->closeCursor();
+ $this->collection = $collection;
+ $this->delete_data_from_cache();
+
+ return $this;
+ }
+
+ /**
+ *
+ * @param boolean $boolean
+ * @return Feed_Adapter
+ */
+ public function set_public($boolean)
+ {
+ $boolean = !!$boolean;
+ $sql = 'UPDATE feeds SET public = :public, updated_on = NOW()
+ WHERE id = :feed_id';
+
+ $params = array(
+ ':public' => $boolean ? '1' : '0',
+ ':feed_id' => $this->get_id()
+ );
+
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $stmt->closeCursor();
+ $this->public = $boolean;
+ $this->delete_data_from_cache();
+
+ $feed_collection = new Feed_Collection($this->app, array());
+ $feed_collection->delete_data_from_cache(Feed_Collection::CACHE_PUBLIC);
+
+ return $this;
+ }
+
+ /**
+ *
+ * @param string $title
+ * @return Feed_Adapter
+ */
+ public function set_title($title)
+ {
+ $title = trim(strip_tags($title));
+
+ if ($title === '')
+ throw new Exception_InvalidArgument();
+
+ $sql = 'UPDATE feeds SET title = :title, updated_on = NOW()
+ WHERE id = :feed_id';
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':title' => $title, ':feed_id' => $this->get_id()));
+ $stmt->closeCursor();
+ $this->title = $title;
+ $this->delete_data_from_cache();
+
+ return $this;
+ }
+
+ /**
+ *
+ * @param string $subtitle
+ * @return Feed_Adapter
+ */
+ public function set_subtitle($subtitle)
+ {
+ $subtitle = strip_tags($subtitle);
+
+ $sql = 'UPDATE feeds SET subtitle = :subtitle, updated_on = NOW()
+ WHERE id = :feed_id';
+ $params = array(':subtitle' => $subtitle, ':feed_id' => $this->get_id());
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $stmt->closeCursor();
+ $this->subtitle = $subtitle;
+ $this->delete_data_from_cache();
+
+ return $this;
+ }
+
+ public static function create(Application $app, User_Adapter $user, $title, $subtitle)
+ {
+ $sql = 'INSERT INTO feeds (id, title, subtitle, created_on, updated_on)
+ VALUES (null, :title, :subtitle, NOW(), NOW())';
+ $stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':title' => $title, ':subtitle' => $subtitle));
+ $stmt->closeCursor();
+
+ $feed_id = $app['phraseanet.appbox']->get_connection()->lastInsertId();
+
+ $feed = new self($app, $feed_id);
+
+ Feed_Publisher_Adapter::create($app, $user, $feed, true);
+
+ return $feed;
+ }
+
+ public static function load_with_user(Application $app, User_Adapter $user, $id)
+ {
+ $feed = new self($app, $id);
+ $coll = $feed->get_collection();
+ if (
+ $feed->is_public()
+ || $coll === null
+ || in_array($coll->get_base_id(), array_keys($user->ACL()->get_granted_base()))
+ ) {
+ return $feed;
+ }
+
+ throw new NotFoundHttpException('Feed not found');
+ }
+
+ /**
+ *
+ * @return int
+ */
+ public function get_count_total_entries()
+ {
+ try {
+ return $this->get_data_from_cache(self::CACHE_ENTRY_NUMBER);
+ } catch (\Exception $e) {
+
+ }
+
+ $sql = 'SELECT count(id) as number
+ FROM feed_entries WHERE feed_id = :feed_id';
+
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':feed_id' => $this->get_id()));
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ $number = $row ? (int) $row['number'] : 0;
+ $stmt->closeCursor();
+
+ $this->set_data_to_cache($number, self::CACHE_ENTRY_NUMBER);
+
+ return $number;
+ }
+
+ /**
+ *
+ * @return void
+ */
+ public function delete()
+ {
+ $this->reset_icon();
+ while ($this->get_count_total_entries() > 0) {
+ $entries_coll = $this->get_entries(0, 10);
+ foreach ($entries_coll->get_entries() as $entry) {
+ $entry->delete();
+ }
+ unset($entries_coll);
+ $this->delete_data_from_cache(self::CACHE_ENTRY_NUMBER);
+ }
+
+ foreach ($this->get_publishers() as $publishers)
+ $publishers->delete();
+
+ $sql = 'DELETE FROM feed_tokens WHERE feed_id = :feed_id';
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':feed_id' => $this->get_id()));
+ $stmt->closeCursor();
+
+ $sql = 'DELETE FROM feeds WHERE id = :feed_id';
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute(array(':feed_id' => $this->get_id()));
+ $stmt->closeCursor();
+
+ $this->delete_data_from_cache();
+
+ $feed_coll = new Feed_Collection($this->app, array());
+ $feed_coll->delete_data_from_cache(Feed_Collection::CACHE_PUBLIC);
+
+ return;
+ }
+
+ /**
+ *
+ * @param int $offset_start
+ * @param int $how_many
+ * @return Feed_Entry_Collection
+ */
+ public function get_entries($offset_start, $how_many)
+ {
+ $offset_start = (int) $offset_start;
+ $how_many = $how_many > self::MAX_ENTRIES ? self::MAX_ENTRIES : (int) $how_many;
+
+ $sql = 'SELECT id
+ FROM feed_entries
+ WHERE feed_id = :feed_id
+ ORDER BY id DESC
+ LIMIT ' . $offset_start . ', ' . $how_many;
+
+ $params = array(
+ ':feed_id' => $this->get_id()
+ );
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $rs = $stmt->fetchAll(PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ $result = new Feed_Entry_Collection();
+
+ foreach ($rs as $row) {
+ $entry = new Feed_Entry_Adapter($this->app, $this, $row['id']);
+ $result->add_entry($entry);
+ }
+
+ return $result;
+ }
+
+ /**
+ *
+ * @param registryInterface $registry
+ * @param string $format
+ * @param int $page
+ * @return Feed_Link
+ */
+ public function get_homepage_link(registryInterface $registry, $format, $page = null)
+ {
+ if (!$this->is_public()) {
+ return null;
+ }
+
+ switch ($format) {
+ case self::FORMAT_ATOM:
+ return new Feed_Link(
+ sprintf('%s/feeds/feed/%s/atom/%s'
+ , rtrim($registry->get('GV_ServerName'), '/')
+ , $this->get_id()
+ , ($page ? '?page=' . $page : '')
+ )
+ , sprintf('%s - %s', $this->get_title(), 'Atom')
+ , 'application/atom+xml'
+ );
+ break;
+ case self::FORMAT_RSS:
+ default:
+ return new Feed_Link(
+ sprintf('%s/feeds/feed/%s/rss/%s'
+ , rtrim($registry->get('GV_ServerName'), '/')
+ , $this->get_id()
+ , ($page ? '?page=' . $page : '')
+ )
+ , sprintf('%s - %s', $this->get_title(), 'RSS')
+ , 'application/rss+xml'
+ );
+ break;
+ }
+ }
+
+ /**
+ *
+ * @param User_Adapter $user
+ * @param boolean $renew
+ * @return string
+ */
+ protected function get_token(User_Adapter $user, $renew = false)
+ {
+ $cache_key = self::CACHE_USER_TOKEN . '_' . $user->get_id();
+ try {
+ if (!$renew) {
+ return $this->get_data_from_cache($cache_key);
+ }
+ } catch (\Exception $e) {
+
+ }
+
+ $sql = 'SELECT token FROM feed_tokens
+ WHERE usr_id = :usr_id AND feed_id = :feed_id
+ AND aggregated IS NULL';
+
+ $params = array(
+ ':usr_id' => $user->get_id(),
+ ':feed_id' => $this->get_id()
+ );
+
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $row = $stmt->fetch(PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ if (!$row || $renew === true) {
+ $token = random::generatePassword(12, random::LETTERS_AND_NUMBERS);
+ $sql = 'REPLACE INTO feed_tokens (id, token, feed_id, usr_id, aggregated)
+ VALUES (null, :token, :feed_id, :usr_id, :aggregated)';
+
+ $params = array(
+ ':token' => $token
+ , ':feed_id' => $this->get_id()
+ , ':usr_id' => $user->get_id()
+ , ':aggregated' => null
+ );
+
+ $stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
+ $stmt->execute($params);
+ $this->delete_data_from_cache($cache_key);
+ } else {
+ $token = $row['token'];
+ }
+
+ $this->set_data_to_cache($token, $cache_key);
+
+ return $token;
+ }
+
+ /**
+ *
+ * @param registryInterface $registry
+ * @param User_Adapter $user
+ * @param string $format
+ * @param int $page
+ * @param boolean $renew_token
+ * @return Feed_Link
+ */
+ public function get_user_link(registryInterface $registry, User_Adapter $user, $format, $page = null, $renew_token = false)
+ {
+ switch ($format) {
+ case self::FORMAT_ATOM:
+ return new Feed_Link(
+ sprintf('%s/feeds/userfeed/%s/%s/atom/'
+ , rtrim($registry->get('GV_ServerName'), '/')
+ , $this->get_token($user, $renew_token)
+ , $this->get_id()
+ , ($page ? '?page=' . $page : '')
+ )
+ , sprintf('%s - %s', $this->get_title(), 'Atom')
+ , 'application/atom+xml'
+ );
+ break;
+ case self::FORMAT_RSS:
+ return new Feed_Link(
+ sprintf('%s/feeds/userfeed/%s/%s/rss/%s'
+ , rtrim($registry->get('GV_ServerName'), '/')
+ , $this->get_token($user, $renew_token)
+ , $this->get_id()
+ , ($page ? '?page=' . $page : '')
+ )
+ , sprintf('%s - %s', $this->get_title(), 'RSS')
+ , 'application/rss+xml'
+ );
+ break;
+ }
+ }
+
+ public function get_cache_key($option = null)
+ {
+ return 'feed_adapter_' . $this->get_id() . '_' . ($option ? '_' . $option : '');
+ }
+
+ public function get_data_from_cache($option = null)
+ {
+ return $this->app['phraseanet.appbox']->get_data_from_cache($this->get_cache_key($option));
+ }
+
+ public function set_data_to_cache($value, $option = null, $duration = 0)
+ {
+ return $this->app['phraseanet.appbox']->set_data_to_cache($value, $this->get_cache_key($option), $duration);
+ }
+
+ public function delete_data_from_cache($option = null)
+ {
+ return $this->app['phraseanet.appbox']->delete_data_from_cache($this->get_cache_key($option));
+ }
+}
diff --git a/lib/classes/caption/Field/ThesaurusValue.php b/lib/classes/caption/Field/ThesaurusValue.php
index 86c76f6f9e..8554dd70a9 100644
--- a/lib/classes/caption/Field/ThesaurusValue.php
+++ b/lib/classes/caption/Field/ThesaurusValue.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-class ThesaurusValue
+class caption_Field_ThesaurusValue
{
/** @var string */
private $value;
diff --git a/lib/classes/caption/Field/Value.php b/lib/classes/caption/Field/Value.php
index 9d1d29f98a..e36b9fca38 100644
--- a/lib/classes/caption/Field/Value.php
+++ b/lib/classes/caption/Field/Value.php
@@ -51,7 +51,20 @@ class caption_Field_Value implements cache_cacheableInterface
protected $record;
protected $app;
- protected static $localCache = [];
+ /**
+ * Query to ask to the search engine to bounce to the current value;
+ * This property is set if the value is matched against a thesaurus value;
+ *
+ * @var string
+ */
+ protected $qjs;
+
+ /**
+ * Tells whether the value is matched against a thesaurus value.
+ */
+ protected $isThesaurusValue;
+
+ protected static $localCache = array();
/**
*
@@ -71,6 +84,11 @@ class caption_Field_Value implements cache_cacheableInterface
$this->retrieveValues();
}
+ public function getQjs()
+ {
+ return $this->qjs;
+ }
+
protected function retrieveValues()
{
try {
@@ -336,7 +354,6 @@ class caption_Field_Value implements cache_cacheableInterface
public function highlight_thesaurus()
{
$value = $this->getValue();
-
$databox = $this->databox_field->get_databox();
$XPATH_thesaurus = $databox->get_xpath_thesaurus();
@@ -374,18 +391,33 @@ class caption_Field_Value implements cache_cacheableInterface
if($context_noacc != "")
$note += ($node->getAttribute("k") == $context_noacc) ? 1 : 0;
if ($note > $bestnote) {
- $bestnote = $note;
$bestnode = $node;
}
}
- if ($bestnode) {
- list($term, $context) = $this->splitTermAndContext(str_replace(["[[em]]", "[[/em]]"], ["", ""], $value));
- $qjs = $term . ($context ? '['.$context.']' : '');
- $value = new ThesaurusValue($bestnode->getAttribute('v'), $this->databox_field, $qjs);
+ if ($bestnode) {
+ list($term, $context) = $this->splitTermAndContext(str_replace(array("[[em]]", "[[/em]]"), array("", ""), $value));
+ // a value has been found in thesaurus, update value & set the query to bounce to the value
+ $this->value = $bestnode->getAttribute('v');
+ $this->qjs = $term . ($context ? '['.$context.']' : '');
+ $this->isThesaurusValue = true;
+ } else {
+ $this->isThesaurusValue = false;
}
- return $value;
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isThesaurusValue()
+ {
+ if (null === $this->isThesaurusValue) {
+ $this->highlight_thesaurus();
+ }
+
+ return $this->isThesaurusValue;
}
/**
@@ -466,6 +498,11 @@ class caption_Field_Value implements cache_cacheableInterface
unset(self::$localCache[$this->get_cache_key($option)]);
}
+ public function __toString()
+ {
+ return $this->value;
+ }
+
public static function purge()
{
self::$localCache = [];
diff --git a/lib/classes/caption/field.php b/lib/classes/caption/field.php
index 9a9d06d886..e720ca73d2 100644
--- a/lib/classes/caption/field.php
+++ b/lib/classes/caption/field.php
@@ -197,27 +197,27 @@ class caption_field implements cache_cacheableInterface
*
* @return mixed
*/
- public function get_serialized_values($custom_separator = false, $highlightTheso = false)
+ public function get_serialized_values($custom_separator = false, $highlight = false)
{
- if ($this->databox_field->is_multi() === true) {
- if ($custom_separator !== false)
- $separator = $custom_separator;
- else
- $separator = $this->databox_field->get_separator();
-
- return self::serialize_value($this->values, $separator, $highlightTheso);
- } else {
- foreach ($this->values as $value) {
- /* @var $value Caption_Field_Value */
- if ($highlightTheso) {
- return $value->highlight_thesaurus();
- } else {
- return $value->getValue();
- }
- }
+ if (0 === count($this->values)) {
+ return null;
}
- return null;
+ if ($this->is_multi()) {
+ $separator = $custom_separator !== false ? $custom_separator : $this->databox_field->get_separator();
+
+ return self::serialize_value($this->values, $separator, $highlight);
+ }
+
+ $value = current($this->values);
+
+ /* @var $value Caption_Field_Value */
+ if ($highlight) {
+ return $value->highlight_thesaurus();
+ }
+
+ return $value->getValue();
+
}
/**
@@ -256,17 +256,6 @@ class caption_field implements cache_cacheableInterface
return $this->databox_field;
}
- /**
- *
- * @return string
- */
- public function highlight_thesaurus()
- {
- $value = $this->get_serialized_values(false, true);
-
- return $value;
- }
-
/**
*
* @param string $serialized_value
diff --git a/lib/classes/caption/record.php b/lib/classes/caption/record.php
index 5fcad7f13b..6a3bdb2197 100644
--- a/lib/classes/caption/record.php
+++ b/lib/classes/caption/record.php
@@ -174,55 +174,40 @@ class caption_record implements caption_interface, cache_cacheableInterface
*/
public function get_highlight_fields($highlight = '', Array $grep_fields = null, SearchEngineInterface $searchEngine = null, $includeBusiness = false, SearchEngineOptions $options = null)
{
- return $this->highlight_fields($highlight, $grep_fields, $searchEngine, $includeBusiness, $options);
- }
-
- /**
- * @todo move this fun in caption_field object
- * @param string $highlight
- * @param array $grep_fields
- * @param SearchEngineInterface $searchEngine
- * @return array
- */
- protected function highlight_fields($highlight, Array $grep_fields = null, SearchEngineInterface $searchEngine = null, $includeBusiness = false, SearchEngineOptions $options = null)
- {
- $fields = [];
+ $fields = array();
foreach ($this->get_fields($grep_fields, $includeBusiness) as $meta_struct_id => $field) {
-
- $value = preg_replace(
- "(([^']{1})((https?|file):((/{2,4})|(\\{2,4}))[\w:#%/;$()~_?/\-=\\\.&]*)([^']{1}))"
- , '$1 $2 $7'
- , $highlight ? $field->highlight_thesaurus() : $field->get_serialized_values(false, false)
- );
-
- $fields[$field->get_name()] = [
- 'value' => $value,
- /** @Ignore */
- 'label' => $field->get_databox_field()->get_label($this->app['locale']),
+ $values = array();
+ foreach ($field->get_values() as $metaId => $v) {
+ $values[$metaId] = array(
+ 'value' => $v->getValue(),
+ 'from_thesaurus' => $highlight ? $v->isThesaurusValue() : false,
+ 'qjs' => $v->getQjs(),
+ );
+ }
+ $fields[$field->get_name()] = array(
+ 'values' => $values,
+ 'name' => $field->get_name(),
+ 'label' => $field->get_databox_field()->get_label($this->app['locale.I18n']),
'separator' => $field->get_databox_field()->get_separator(),
- ];
+ 'sbas_id' => $field->get_databox_field()->get_databox()->get_sbas_id()
+ );
}
if ($searchEngine instanceof SearchEngineInterface) {
$ret = $searchEngine->excerpt($highlight, $fields, $this->record, $options);
+ // sets highlighted value from search engine, highlighted values will now
+ // be surrounded by [[em]][[/em]] tags
if ($ret) {
- $n = -1;
-
foreach ($fields as $key => $value) {
- $n++;
-
- if (!isset($fields[$key])) {
+ if (!isset($ret[$key])) {
continue;
}
- if (strpos($fields[$key]['value'], ' $newValue) {
+ $fields[$key]['values'][$metaId]['value'] = $newValue;
}
-
- //if(strpos($fields[$key]['value'], 'path = $app['root.path'] . "/config/status/" . urlencode($sbas_params[$sbas_id]["host"]) . "-" . urlencode($sbas_params[$sbas_id]["port"]) . "-" . urlencode($sbas_params[$sbas_id]["dbname"]);
- $url = $this->url = "/custom/status/" . urlencode($sbas_params[$sbas_id]["host"]) . "-" . urlencode($sbas_params[$sbas_id]["port"]) . "-" . urlencode($sbas_params[$sbas_id]["dbname"]);
+ $uniqid = md5(implode('-', array(
+ $sbas_params[$sbas_id]["host"],
+ $sbas_params[$sbas_id]["port"],
+ $sbas_params[$sbas_id]["dbname"]
+ )));
+
+ $path = $this->path = $app['root.path'] . "/config/status/" . $uniqid;
+ $url = $this->url = "/custom/status/" . $uniqid;
$databox = $app['phraseanet.appbox']->get_databox((int) $sbas_id);
$xmlpref = $databox->get_structure();
diff --git a/lib/classes/eventsmanager/notify/feed.php b/lib/classes/eventsmanager/notify/feed.php
index c159b93a4d..56c72c4dd7 100644
--- a/lib/classes/eventsmanager/notify/feed.php
+++ b/lib/classes/eventsmanager/notify/feed.php
@@ -44,7 +44,6 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
];
$dom_xml = new DOMDocument('1.0', 'UTF-8');
-
$dom_xml->preserveWhiteSpace = false;
$dom_xml->formatOutput = true;
@@ -58,7 +57,11 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
$dom_xml->appendChild($root);
- $datas = $dom_xml->saveXml();
+ $data = $dom_xml->saveXml();
+
+ API_Webhook::create($this->app['phraseanet.appbox'], API_Webhook::NEW_FEED_ENTRY, array_merge(
+ array('feed_id' => $entry->get_feed()->get_id()), $params
+ ));
$Query = new \User_Query($this->app);
@@ -74,11 +77,6 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
$start = 0;
$perLoop = 100;
- $from = [
- 'email' => $entry->getAuthorEmail(),
- 'name' => $entry->getAuthorName()
- ];
-
do {
$results = $Query->limit($start, $perLoop)->execute()->get_results();
@@ -108,7 +106,7 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
}
}
- $this->broker->notify($user_to_notif->getId(), __CLASS__, $datas, $mailed);
+ $this->broker->notify($user_to_notif->getId(), __CLASS__, $data, $mailed);
}
$start += $perLoop;
} while (count($results) > 0);
@@ -118,13 +116,13 @@ class eventsmanager_notify_feed extends eventsmanager_notifyAbstract
/**
*
- * @param Array $datas
+ * @param Array $data
* @param boolean $unread
* @return Array
*/
- public function datas($datas, $unread)
+ public function datas($data, $unread)
{
- $sx = simplexml_load_string($datas);
+ $sx = simplexml_load_string($data);
$entry = $this->app['repo.feed-entries']->find((int) $sx->entry_id);
diff --git a/lib/classes/media/subdef.php b/lib/classes/media/subdef.php
index b10703e2b9..2a7af2739a 100644
--- a/lib/classes/media/subdef.php
+++ b/lib/classes/media/subdef.php
@@ -200,13 +200,12 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
$stmt->closeCursor();
if ($row) {
-
$this->width = (int) $row['width'];
$this->size = (int) $row['size'];
$this->height = (int) $row['height'];
$this->mime = $row['mime'];
$this->file = $row['file'];
- $this->etag = $row['etag'];
+ $this->etag = $row['etag'] !== null ? $row['etag'] : md5(time() . $row['path'] .$row['file']);
$this->path = p4string::addEndSlash($row['path']);
$this->is_substituted = ! ! $row['substit'];
$this->subdef_id = (int) $row['subdef_id'];
@@ -742,7 +741,7 @@ class media_subdef extends media_abstract implements cache_cacheableInterface
return;
}
- if (in_array($this->mime, ['video/mp4'])) {
+ if ($this->app['phraseanet.h264-factory']->isH264Enabled() && in_array($this->mime, array('video/mp4'))) {
if (null !== $url = $this->app['phraseanet.h264']->getUrl($this->get_pathfile())) {
$this->url = $url;
diff --git a/lib/classes/module/report/connexion.php b/lib/classes/module/report/connexion.php
index 5de7a838e6..4ca87eb6c6 100644
--- a/lib/classes/module/report/connexion.php
+++ b/lib/classes/module/report/connexion.php
@@ -91,8 +91,9 @@ class module_report_connexion extends module_report
/**
* @desc build the result from the specified sql
- * @param array $champ all the field from the request displayed in a array
- * @param string $sql the request from buildreq
+ * @param array $champ all the field from the request displayed in a array
+ * @param string $sql the request from buildreq
+ * @return $this->result
*/
protected function buildResult(Application $app, $rs)
{
diff --git a/lib/classes/module/report/download.php b/lib/classes/module/report/download.php
index 7d033372dc..0ef7de517d 100644
--- a/lib/classes/module/report/download.php
+++ b/lib/classes/module/report/download.php
@@ -94,8 +94,9 @@ class module_report_download extends module_report
/**
* @desc build the result from the specified sql
- * @param array $champ all the field from the request displayed in a array
- * @param string $sql the request from buildreq
+ * @param array $champ all the field from the request displayed in a array
+ * @param string $sql the request from buildreq
+ * @return $this->result
*/
protected function buildResult(Application $app, $rs)
{
diff --git a/lib/classes/patch/384alpha2a.php b/lib/classes/patch/384alpha2a.php
new file mode 100644
index 0000000000..8fa47afb7f
--- /dev/null
+++ b/lib/classes/patch/384alpha2a.php
@@ -0,0 +1,78 @@
+release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $appbox, Application $app)
+ {
+ $finder = new Finder();
+ $fs = new Filesystem();
+ foreach ($finder->files()->in($app['root.path'].'/config/status') as $file) {
+ if (!$file->isFile()) {
+ continue;
+ }
+ $fileName = $file->getFileName();
+ $chunks = explode('-', $fileName);
+
+ if (count($chunks) < 4) {
+ continue;
+ }
+
+ $suffix = array_pop($chunks);
+ $uniqid = md5(implode('-', $chunks));
+
+ $fs->rename($file->getRealPath(), $app['root.path'].'/config/status/' . $uniqid . '-' . $suffix);
+
+ if ($fs->exists($app['root.path'] . '/www/custom/status/' . $file->getFileName())) {
+ $fs->remove($app['root.path'] . '/www/custom/status/' . $file->getFileName());
+ }
+ }
+
+ $app['filesystem']->mirror($app['root.path'] . '/config/status/', $app['root.path'] . '/www/custom/status/');
+ }
+}
diff --git a/lib/classes/patch/384alpha3a.php b/lib/classes/patch/384alpha3a.php
new file mode 100644
index 0000000000..ec274b0545
--- /dev/null
+++ b/lib/classes/patch/384alpha3a.php
@@ -0,0 +1,68 @@
+release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $appbox, Application $app)
+ {
+ $config = $app['phraseanet.configuration']->getConfig();
+
+ $config['api_cors'] = array(
+ 'enabled' => false,
+ 'allow_credentials' => false,
+ 'allow_origin' => array(),
+ 'allow_headers' => array(),
+ 'allow_methods' => array(),
+ 'expose_headers' => array(),
+ 'max_age' => 0,
+ 'hosts' => array(),
+ );
+
+ $app['phraseanet.configuration']->setConfig($config);
+
+ return true;
+ }
+}
diff --git a/lib/classes/patch/384alpha4a.php b/lib/classes/patch/384alpha4a.php
new file mode 100644
index 0000000000..5f0bf58a36
--- /dev/null
+++ b/lib/classes/patch/384alpha4a.php
@@ -0,0 +1,62 @@
+release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $appbox, Application $app)
+ {
+ $config = $app['phraseanet.configuration']->getConfig();
+
+ $config['session'] = array(
+ 'idle' => 0,
+ 'lifetime' => 604800,
+ );
+
+ $app['phraseanet.configuration']->setConfig($config);
+
+ return true;
+ }
+}
diff --git a/lib/classes/patch/384alpha5a.php b/lib/classes/patch/384alpha5a.php
new file mode 100644
index 0000000000..bcb76a3e80
--- /dev/null
+++ b/lib/classes/patch/384alpha5a.php
@@ -0,0 +1,57 @@
+release;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function require_all_upgrades()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function concern()
+ {
+ return $this->concern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function apply(base $databox, Application $app)
+ {
+ $sql = "UPDATE log_docs SET `action`='mail' WHERE `action`='download' AND LOCATE('@', comment)";
+ $stmt = $databox->get_connection()->prepare($sql);
+ $stmt->execute();
+
+ return true;
+ }
+}
diff --git a/lib/classes/record/adapter.php b/lib/classes/record/adapter.php
index 53eab6893b..d7f855ee67 100644
--- a/lib/classes/record/adapter.php
+++ b/lib/classes/record/adapter.php
@@ -895,12 +895,12 @@ class record_adapter implements record_Interface, cache_cacheableInterface
}
if (count($fields_to_retrieve) > 0) {
- $retrieved_fields = $this->get_caption()->get_highlight_fields($highlight, $fields_to_retrieve, $searchEngine, false, $options);
- $titles = [];
- foreach ($retrieved_fields as $key => $value) {
- if (trim($value['value'] === ''))
- continue;
- $titles[] = $value['value'];
+ $retrieved_fields = $this->get_caption()->get_highlight_fields($highlight, $fields_to_retrieve, $searchEngine);
+ $titles = array();
+ foreach ($retrieved_fields as $value) {
+ foreach ($value['values'] as $v) {
+ $titles[] = $v['value'];
+ }
}
$title = trim(implode(' - ', $titles));
}
diff --git a/lib/classes/record/preview.php b/lib/classes/record/preview.php
index 5eacf2e20e..3ddb20ff19 100644
--- a/lib/classes/record/preview.php
+++ b/lib/classes/record/preview.php
@@ -463,7 +463,7 @@ class record_preview extends record_adapter
$width = 350;
$height = 150;
- $url = Url::factory('http://chart.apis.google.com/chart?' .
+ $url = Url::factory('https://chart.googleapis.com/chart?' .
'chs=' . $width . 'x' . $height .
'&chd=t:' . implode(',', $views) .
'&cht=lc' .
@@ -544,7 +544,7 @@ class record_preview extends record_adapter
$width = 550;
$height = 100;
- $url = Url::factory('http://chart.apis.google.com/chart?'
+ $url = Url::factory('https://chart.googleapis.com/chart?'
. 'cht=p3&chf=bg,s,00000000&chd=t:'
. implode(',', $referrers)
. '&chs=' . $width . 'x' . $height
@@ -619,7 +619,7 @@ class record_preview extends record_adapter
$width = 250;
$height = 150;
- $url = Url::factory('http://chart.apis.google.com/chart?' .
+ $url = Url::factory('https://chart.googleapis.com/chart?' .
'chs=' . $width . 'x' . $height .
'&chd=t:' . implode(',', $dwnls) .
'&cht=lc' .
diff --git a/lib/classes/set/export.php b/lib/classes/set/export.php
index 4fd651d1fb..5e6f45d5f8 100644
--- a/lib/classes/set/export.php
+++ b/lib/classes/set/export.php
@@ -761,12 +761,7 @@ class set_export extends set_abstract
$tmplog = [];
$files = $list['files'];
- $event_names = [
- 'mail-export' => Session_Logger::EVENT_EXPORTMAIL,
- 'download' => Session_Logger::EVENT_EXPORTDOWNLOAD
- ];
-
- $event_name = isset($event_names[$type]) ? $event_names[$type] : Session_Logger::EVENT_EXPORTDOWNLOAD;
+ $event_name = in_array($type, array(Session_Logger::EVENT_EXPORTMAIL,Session_Logger::EVENT_EXPORTDOWNLOAD)) ? $type : Session_Logger::EVENT_EXPORTDOWNLOAD;
foreach ($files as $record) {
foreach ($record["subdefs"] as $o => $obj) {
@@ -774,8 +769,7 @@ class set_export extends set_abstract
$record_object = new record_adapter($app, $sbas_id, $record['record_id']);
- $app['phraseanet.logger']($record_object->get_databox())
- ->log($record_object, $event_name, $o, $comment);
+ $app['phraseanet.logger']($record_object->get_databox())->log($record_object, $event_name, $o, $comment);
if ($o != "caption") {
$log["rid"] = $record_object->get_record_id();
@@ -792,6 +786,12 @@ class set_export extends set_abstract
}
}
+ $export_types = array(
+ 'download' => 0,
+ 'mail-export' => 2,
+ 'ftp' => 4
+ );
+
$list_base = array_unique(array_keys($tmplog));
if (!$anonymous) {
diff --git a/lib/classes/task/period/apiwebhooks.php b/lib/classes/task/period/apiwebhooks.php
new file mode 100644
index 0000000000..20532cd272
--- /dev/null
+++ b/lib/classes/task/period/apiwebhooks.php
@@ -0,0 +1,144 @@
+get_connection()->prepare('SELECT id, `type`, `data` FROM api_webhooks');
+ $stmt->execute();
+ $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ return $rs;
+ }
+
+ protected function processOneContent(appbox $appbox, array $row)
+ {
+ $data = null;
+ switch ($row['type']) {
+ case \API_Webhook::NEW_FEED_ENTRY:
+ $data = $this->processNewFeedEntry($row);
+ }
+
+ if (null === $data) {
+ return;
+ }
+ $urls = $this->getApplicationHookUrls($appbox);
+ $this->sendData($urls, $data);
+ }
+
+ protected function postProcessOneContent(appbox $appbox, array $row)
+ {
+ $w = new API_Webhook($appbox, $row['id']);
+ $w->delete();
+ }
+
+ protected function getApplicationHookUrls(appbox $appbox)
+ {
+ $stmt = $appbox->get_connection()->prepare('
+ SELECT webhook_url
+ FROM api_applications
+ WHERE webhook_url IS NOT NULL
+ ');
+ $stmt->execute();
+ $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
+ $stmt->closeCursor();
+
+ return array_map(function ($row) {
+ return $row['webhook_url'];
+ }, $rows);
+ }
+
+ protected function sendData(array $urls, array $data)
+ {
+ if (count($urls) === 0) {
+ return;
+ }
+ $client = new GuzzleClient();
+ $body = json_encode($data);
+ $requests = array();
+ foreach ($urls as $url) {
+ $requests[] = $client->createRequest('POST', $url, array(
+ 'Content-Type' => 'application/vnd.phraseanet.event+json'
+ ), $body);
+ }
+ $client->send($requests);
+ }
+
+ protected function processNewFeedEntry(array $row)
+ {
+ $data = json_decode($row['data']);
+ if (!isset($data->{"feed_id"}) || !isset($data->{"entry_id"})) {
+ return;
+ }
+ $feed = new Feed_Adapter($this->dependencyContainer, $data->{"feed_id"});
+ $entry = new \Feed_Entry_Adapter($this->dependencyContainer, $feed, $data->{"entry_id"});
+ $query = new \User_Query($this->dependencyContainer);
+
+ $query->include_phantoms(true)
+ ->include_invite(false)
+ ->include_templates(false)
+ ->email_not_null(true);
+
+ if ($entry->get_feed()->get_collection()) {
+ $query->on_base_ids(array($entry->get_feed()->get_collection()->get_base_id()));
+ }
+
+ $start = 0;
+ $perLoop = 100;
+ $users = array();
+
+ do {
+ $results = $query->limit($start, $perLoop)->execute()->get_results();
+ foreach ($results as $user) {
+ $users[] = array(
+ 'email' => $user->get_email(),
+ 'firstname' => $user->get_firstname() ?: null,
+ 'lastname' => $user->get_lastname() ?: null,
+ );
+ }
+ $start += $perLoop;
+ } while (count($results) > 0);
+
+ return array(
+ 'event' => $row['type'],
+ 'users_were_notified' => !!$data->{"notify_email"},
+ 'feed' => array(
+ 'id' => $feed->get_id(),
+ 'title' => $feed->get_title(),
+ 'description' => $feed->get_subtitle() ?: null,
+ ),
+ 'entry' => array(
+ 'id' => $entry->get_id(),
+ 'author' => array(
+ 'name' => $entry->get_author_name(),
+ 'email' => $entry->get_author_email()
+ ),
+ 'title' => $entry->get_title(),
+ 'description' => $entry->get_subtitle() ?: null,
+ ),
+ 'users' => $users
+ );
+ }
+}
diff --git a/lib/conf.d/bases_structure.xml b/lib/conf.d/bases_structure.xml
index 84ba2894f7..90c65ff1a8 100644
--- a/lib/conf.d/bases_structure.xml
+++ b/lib/conf.d/bases_structure.xml
@@ -924,6 +924,65 @@
InnoDB
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ key
+ char(32)
+
+
+
+
+ ascii_bin
+
+
+ value
+ varchar(1024)
+
+
+
+
+
+
+ type
+ enum('string','boolean','array','integer','text','binary','timezone','enum_multi','enum')
+
+
+ string
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ UNIQUE
+ UNIQUE
+
+ key
+
+
+
+ InnoDB
+
+
+
+
+
@@ -1072,6 +1131,145 @@
InnoDB
+
+
+
+
+ date_modif
+ datetime
+
+
+
+
+ 0000-00-00 00:00:00
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+ 0
+
+
+
+ base_id
+ int(11) unsigned
+
+
+
+
+ 0
+
+
+
+ en_cours
+
+ tinyint(3)
+
+
+
+ 0
+
+
+
+
+ refuser
+ tinyint(3) unsigned
+
+
+
+ 0
+
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ usr_id
+ base_id
+ en_cours
+
+
+
+ InnoDB
+
+
+
+
+ id
+ int(11) unsigned
+
+
+ auto_increment
+
+
+
+
+ name
+
+ char(50)
+
+
+
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+ 0
+
+
+
+
+ query
+ char(255)
+
+
+
+
+
+
+
+
+ bases
+ char(255)
+
+
+
+
+
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ usr_id
+ name
+
+
+
+ id
+ UNIQUE
+
+ id
+
+
+
+ InnoDB
+
+
@@ -1149,6 +1347,325 @@
InnoDB
+
+
+
+ id
+
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+
+
+ crash
+ tinyint(3) unsigned
+
+
+
+ 0
+
+
+
+
+ nbretry
+ tinyint(3) unsigned
+
+
+
+
+ 5
+
+
+
+ mail
+ char(255)
+
+
+
+
+
+
+
+
+ addr
+ char(255)
+
+
+
+
+
+
+
+
+ ssl
+ tinyint(1) unsigned
+
+
+
+
+ 0
+
+
+
+ login
+
+ char(255)
+
+
+
+
+
+
+
+
+ pwd
+ char(255)
+
+
+
+
+
+
+
+
+ passif
+ tinyint(1) unsigned
+
+
+
+ 0
+
+
+
+
+ destfolder
+ char(255)
+ YES
+
+
+
+
+
+
+
+ sendermail
+ char(255)
+
+ YES
+
+
+
+
+
+
+ text_mail_sender
+
+ longtext
+
+
+
+
+
+
+
+
+ text_mail_receiver
+ longtext
+
+
+
+
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+ 0
+
+
+
+ date
+ datetime
+
+
+ 0000-00-00 00:00:00
+
+
+
+ foldertocreate
+ char(255)
+ YES
+
+
+
+
+
+ logfile
+ tinyint(1) unsigned
+
+
+ 0
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ usr_id
+ INDEX
+
+ usr_id
+
+
+
+ crash
+ INDEX
+
+ crash
+
+
+
+ nbretry
+ INDEX
+
+ nbretry
+
+
+
+ InnoDB
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ ftp_export_id
+ int(11) unsigned
+
+
+ 0
+
+
+
+ base_id
+ int(11) unsigned
+
+
+ 0
+
+
+
+ record_id
+ int(11) unsigned
+
+
+ 0
+
+
+
+ subdef
+ char(255)
+
+
+ 0
+
+
+
+ filename
+ char(255)
+
+
+
+
+
+
+ folder
+ char(255)
+
+
+
+
+
+
+ businessfields
+ tinyint(1) unsigned
+ YES
+
+
+
+
+
+ error
+ tinyint(1) unsigned
+
+
+ 0
+
+
+
+ done
+ tinyint(1) unsigned
+
+
+ 0
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ ftp_export_id
+ INDEX
+
+ ftp_export_id
+
+
+
+ done
+ INDEX
+
+ done
+
+
+
+ error
+ INDEX
+
+ error
+
+
+
+ InnoDB
+
+
@@ -1234,6 +1751,157 @@
InnoDB
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+
+
+ created_on
+ datetime
+
+
+
+
+
+
+ usage
+ longtext
+
+
+
+
+
+
+ deadline
+ datetime
+
+
+
+
+
+
+ ssel_id
+ int(11) unsigned
+ YES
+
+
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ usr
+ INDEX
+
+ usr_id
+
+
+
+ InnoDB
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ order_id
+ int(11) unsigned
+
+
+
+
+
+
+ base_id
+ int(11) unsigned
+
+
+
+
+
+
+ record_id
+ int(11) unsigned
+
+
+
+
+
+
+ order_master_id
+ int(11) unsigned
+ YES
+
+
+
+
+
+ deny
+ tinyint(1)
+ YES
+
+
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ triplet
+ UNIQUE
+
+ order_id
+ base_id
+ record_id
+
+
+
+ order_id
+ INDEX
+
+ order_id
+
+
+
+ InnoDB
+
+
@@ -1534,6 +2202,43 @@
0000-00-00 00:00:00
+
+ schedstatus
+
+ enum('stopped','stopping','started','tostop')
+
+
+
+ stopped
+
+ ascii_bin
+
+
+ schedqtime
+ datetime
+
+
+ 0000-00-00 00:00:00
+
+
+
+ schedpid
+ int(11)
+ YES
+
+
+
+
+
+
+
+ schedulerkey
+ char(20)
+ YES
+
+
+
+
@@ -1559,10 +2264,1240 @@
0000-00-00
+ stopped
+
+
InnoDB
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+
+
+ feed_id
+ int(11) unsigned
+
+
+
+
+
+
+ owner
+ tinyint(11) unsigned
+ YES
+
+
+
+
+
+ created_on
+ datetime
+
+
+
+
+
+
+ added_by
+ int(11) unsigned
+
+
+
+
+
+
+
+
+ id
+ PRIMARY
+
+ id
+
+
+
+ couple
+ UNIQUE
+
+ usr_id
+ feed_id
+
+
+
+ owners
+ UNIQUE
+
+ owner
+ feed_id
+
+
+
+ InnoDB
+
+
+
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ title
+ varchar(128)
+
+
+
+
+
+
+ subtitle
+ varchar(8192)
+
+
+
+
+
+
+ created_on
+ datetime
+
+
+
+
+
+
+ updated_on
+ datetime
+
+
+
+
+
+
+ base_id
+ int(11) unsigned
+ YES
+
+
+
+
+
+ public
+ tinyint(1) unsigned
+
+
+ 0
+
+
+
+
+
+ id
+ PRIMARY
+
+ id
+
+
+
+ base_id
+ INDEX
+
+ base_id
+
+
+
+ InnoDB
+
+
+
+
+
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ token
+ varchar(12)
+
+
+
+
+
+
+ feed_id
+ int(11) unsigned
+ YES
+
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+
+
+ aggregated
+ tinyint(1) unsigned
+ YES
+
+
+
+
+
+
+
+ id
+ PRIMARY
+
+ id
+
+
+
+ token
+ INDEX
+
+ token
+
+
+
+ usr_id
+ INDEX
+
+ usr_id
+
+
+
+ feed_id
+ INDEX
+
+ feed_id
+
+
+
+ aggregated
+ INDEX
+
+ aggregated
+
+
+
+ unikaggregated
+ UNIQUE
+
+ aggregated
+ usr_id
+
+
+
+ unikfeed
+ UNIQUE
+
+ feed_id
+ usr_id
+
+
+
+ InnoDB
+
+
+
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ feed_id
+ int(11) unsigned
+
+
+
+
+
+
+ publisher
+ int(11) unsigned
+
+
+
+
+
+
+ title
+ varchar(128)
+
+
+
+
+
+
+ author_name
+ varchar(128)
+
+
+
+
+
+
+ author_email
+ varchar(128)
+
+
+
+
+
+
+ description
+ varchar(8192)
+
+
+
+
+
+
+ created_on
+ datetime
+
+
+
+
+
+
+ updated_on
+ datetime
+
+
+
+
+
+
+
+
+ id
+ PRIMARY
+
+ id
+
+
+
+ InnoDB
+
+
+
+
+
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ entry_id
+ int(11) unsigned
+
+
+
+
+
+
+ sbas_id
+ int(11) unsigned
+
+
+
+
+
+
+ record_id
+ int(11) unsigned
+
+
+
+
+
+
+ ord
+ int(11) unsigned
+
+
+
+
+
+
+
+
+ id
+ PRIMARY
+
+ id
+
+
+
+ element
+ INDEX
+
+ sbas_id
+ record_id
+
+
+
+ sbas_id
+ INDEX
+
+ sbas_id
+
+
+
+ record_id
+ INDEX
+
+ record_id
+
+
+
+ InnoDB
+
+
+
+
+ task_id
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+ usr_id_owner
+ int(11) unsigned
+
+
+ 0
+
+
+
+ pid
+ int(11) unsigned
+ YES
+
+
+
+
+
+ status
+ enum('stopped','started','starting','stopping','tostart','tostop','manual','torestart')
+
+
+ stopped
+
+ ascii_bin
+
+
+ crashed
+ int(2) unsigned
+
+
+ 0
+
+
+
+ active
+ int(1) unsigned
+
+
+ 0
+
+
+
+ name
+ varchar(100)
+
+
+
+
+
+
+ last_exec_time
+ datetime
+
+
+ 0000-00-00 00:00:00
+
+
+
+ class
+ varchar(100)
+
+
+
+
+
+
+ settings
+ text
+
+
+
+
+
+
+ completed
+ tinyint(4)
+
+
+ -1
+
+
+
+ runner
+ char(20)
+
+
+ -1
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ task_id
+
+
+
+ InnoDB
+
+
+
+
+ id
+ int(11) unsigned
+
+ auto_increment
+
+
+ value
+ char(16)
+
+
+ ascii_bin
+
+
+ type
+ enum('FEED_ENTRY', 'view','validate','password','rss','email','download')
+
+
+ ascii_bin
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+ datas
+ longtext
+ YES
+
+
+
+ created_on
+ datetime
+
+
+
+
+ expire_on
+ datetime
+ YES
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ id
+
+
+
+ value
+ UNIQUE
+
+ value
+
+
+
+ expire
+ INDEX
+
+ expire_on
+
+
+
+ type
+ INDEX
+
+ type
+
+
+
+ InnoDB
+
+
+
+
+ usr_id
+
+ int(11) unsigned
+
+ auto_increment
+
+
+
+
+
+ ldap_created
+ int(1) unsigned
+
+
+
+ 0
+
+
+
+
+ usr_sexe
+ int(1) unsigned
+ YES
+
+
+
+
+
+ usr_nom
+ varchar(50)
+
+
+
+
+
+
+
+
+ usr_prenom
+
+ varchar(50)
+
+
+
+
+
+
+
+
+ usr_login
+ varchar(128)
+
+
+
+
+
+ utf8_bin
+
+
+
+ usr_password
+ varchar(128)
+
+
+
+
+
+
+ utf8_bin
+
+
+ usr_mail
+
+ varchar(64)
+ YES
+
+
+
+
+
+
+
+ usr_creationdate
+ datetime
+
+
+
+ 0000-00-00 00:00:00
+
+
+
+
+ usr_modificationdate
+ datetime
+
+
+
+ 0000-00-00 00:00:00
+
+
+
+
+ adresse
+ text
+
+
+
+
+
+
+
+
+ ville
+ varchar(64)
+
+
+
+
+
+
+
+
+ cpostal
+ varchar(32)
+
+
+
+
+
+
+
+
+ tel
+ varchar(32)
+
+
+
+
+
+
+
+
+ fax
+
+ varchar(32)
+
+
+
+
+
+
+
+
+ fonction
+ varchar(64)
+
+
+
+
+
+
+
+
+ societe
+ varchar(64)
+
+
+
+
+
+
+
+
+ activite
+ varchar(200)
+
+
+
+
+
+
+
+
+ code8
+ int(10) unsigned
+
+
+
+
+ 0
+
+
+
+ pays
+ varchar(64)
+
+ YES
+
+
+
+
+
+
+
+ last_conn
+ datetime
+
+
+
+ 0000-00-00 00:00:00
+
+
+
+
+ model_of
+ int(11) unsigned
+
+
+
+ 0
+
+
+
+
+ create_db
+ tinyint(3)
+
+
+
+
+ 0
+
+
+
+ activeFTP
+ tinyint(1)
+
+
+
+
+ 0
+
+
+
+ addrFTP
+
+ varchar(128)
+
+
+
+
+
+
+
+ sslFTP
+
+ tinyint(1) unsigned
+
+
+
+ 0
+
+
+
+
+ loginFTP
+ varchar(128)
+
+
+
+
+
+
+
+
+ pwdFTP
+ varchar(128)
+
+
+
+
+
+
+
+
+ destFTP
+ varchar(128)
+
+
+
+
+
+
+
+
+ passifFTP
+ tinyint(1) unsigned
+
+
+
+
+ 0
+
+
+
+ retryFTP
+ tinyint(1) unsigned
+
+
+
+
+ 5
+
+
+
+ defaultftpdatasent
+ int(11) unsigned
+
+
+
+
+ 0
+
+
+
+ prefixFTPfolder
+
+ varchar(100)
+
+
+
+
+
+
+
+ lastModel
+ varchar(50)
+
+
+
+
+
+
+ canchgprofil
+ tinyint(1)
+
+
+
+
+ 1
+
+
+
+ canchgftpprofil
+ tinyint(1) unsigned
+
+
+
+
+ 1
+
+
+
+ invite
+
+ tinyint(1) unsigned
+
+
+
+ 0
+
+
+
+ mail_locked
+
+ tinyint(1) unsigned
+
+
+
+ 0
+
+
+
+ geonameid
+
+ int(7) unsigned
+ YES
+
+
+
+
+
+
+ updated
+
+ tinyint(1) unsigned
+
+
+
+ 0
+
+
+
+ locale
+ enum('fr_FR','en_GB','en_US','ar_SA','de_DE','es_LA','zh_CN','nb_NO')
+ YES
+
+
+
+ ascii_bin
+
+
+ mail_notifications
+ tinyint(1) unsigned
+
+
+ 1
+
+
+
+ request_notifications
+ tinyint(1) unsigned
+
+
+ 1
+
+
+
+ push_list
+ text
+
+
+
+
+
+
+ timezone
+ varchar(128)
+
+
+
+
+
+
+ salted_password
+ tinyint(1) unsigned
+
+
+ 0
+
+
+
+ nonce
+ char(16)
+ YES
+
+ utf8_bin
+
+
+
+
+
+ PRIMARY
+ PRIMARY
+
+ usr_id
+
+
+
+ usr_login
+ UNIQUE
+
+ usr_login
+
+
+
+ usr_mail
+ INDEX
+
+ usr_mail
+
+
+
+ unique_usr_mail
+ UNIQUE
+
+ usr_mail
+
+
+
+ model_of
+ INDEX
+
+ model_of
+
+
+
+ salted_password
+ INDEX
+
+ salted_password
+
+
+
+ invite
+ INDEX
+
+ invite
+
+
+
+
+
+ null
+ 2
+ null
+ autoregister
+ autoregister
+ NOW()
+ NOW()
+ 0000-00-00 00:00:00
+ 0
+ 0
+ 0
+ 0
+ 5
+ 5
+ 0
+ 0
+
+
+
+ null
+ 2
+ null
+ invite
+ invite
+ NOW()
+ NOW()
+ 0000-00-00 00:00:00
+ 0
+ 0
+ 0
+ 0
+ 5
+ 5
+ 0
+ 0
+
+
+
+ InnoDB
+
+
+
+
+ usr_id
+ int(11) unsigned
+
+
+
+
+
+
+ prop
+ char(128)
+
+
+ 0
+
+
+
+ value
+ varbinary(32768)
+ YES
+
+ 0
+
+
+
+
+
+ couple
+ UNIQUE
+
+ prop
+ usr_id
+
+
+
+ usr_id
+ INDEX
+
+ usr_id
+
+
+
+ InnoDB
+
@@ -3258,25 +5193,25 @@
ToU
- fr
+ fr_FR
NOW()
ToU
- nl
+ ar_SA
NOW()
ToU
- de
+ de_DE
NOW()
ToU
- en
+ en_GB
NOW()
diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml
index e1ea10930e..f310952ced 100644
--- a/lib/conf.d/configuration.yml
+++ b/lib/conf.d/configuration.yml
@@ -4,6 +4,7 @@ languages:
default: 'fr'
main:
maintenance: false
+ key: ''
database:
host: 'sql-host'
port: 3306
@@ -172,6 +173,9 @@ registration-fields:
-
name: company
required: true
+ -
+ name: lastname
+ required: true
-
name: firstname
required: true
@@ -187,3 +191,16 @@ h264-pseudo-streaming:
type: nginx
mapping: []
plugins: []
+api_cors:
+ enabled: false
+ allow_credentials: false
+ allow_origin: []
+ allow_headers: []
+ allow_methods: []
+ expose_headers: []
+ max_age: 0
+ hosts: []
+session:
+ idle: 0
+ # 1 week
+ lifetime: 604800
diff --git a/lib/conf.d/minifyGroupsConfig.php b/lib/conf.d/minifyGroupsConfig.php
index 78346343a5..721594bb41 100644
--- a/lib/conf.d/minifyGroupsConfig.php
+++ b/lib/conf.d/minifyGroupsConfig.php
@@ -8,13 +8,19 @@
* You may wish to use the Minify URI Builder app to suggest
* changes. http://yourdomain/min/builder/
* */
-$groups = [
- 'authentication_css' => [
+$groups = array(
+ 'account' => array(
+ '//include/jslibs/jquery.contextmenu_scroll.js',
+ '//assets/jquery.cookie/jquery.cookie.js',
+ '//include/jquery.common.js',
+ '//skins/account/account.js'
+ ),
+ 'authentication_css' => array(
'//assets/normalize-css/normalize.css',
'//assets/build/login.css',
'//assets/font-awesome/css/font-awesome.css',
'//assets/jquery.ui/themes/base/jquery.ui.autocomplete.css'
- ],
+ ),
'authentication' => [
'//assets/modernizr/modernizr.js',
'//assets/requirejs/require.js',
diff --git a/templates/web/account/base.html.twig b/templates/web/account/base.html.twig
index 0024a15e61..a88aaebcbc 100644
--- a/templates/web/account/base.html.twig
+++ b/templates/web/account/base.html.twig
@@ -4,11 +4,39 @@
{% extends "common/index_bootstrap.html.twig" %}
{% block stylesheet %}
-
+
+
{% endblock %}
{% block javascript %}
-
+
{% endblock %}
{% block content %}
@@ -46,6 +74,7 @@
+
{% block scripts %}
diff --git a/templates/web/admin/index.html.twig b/templates/web/admin/index.html.twig
index 97c3e1a22e..873a431e00 100644
--- a/templates/web/admin/index.html.twig
+++ b/templates/web/admin/index.html.twig
@@ -28,6 +28,34 @@
bodySize.x = $(window).width();
}
+ function pollNotifications(){
+ $.ajax({
+ type: "POST",
+ url: "{{ path('list_notifications') }}",
+ dataType: 'json',
+ data: {
+ module : 3,
+ usr : {{ app['authentication'].getUser().get_id() }}
+ },
+ error: function(){
+ window.setTimeout("pollNotifications();", 10000);
+ },
+ timeout: function(){
+ window.setTimeout("pollNotifications();", 10000);
+ },
+ success: function(data){
+ if(data)
+ manageSession(data);
+ var t = 120000;
+ if(data.apps && parseInt(data.apps)>1)
+ t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000));
+ window.setTimeout("pollNotifications();", t);
+
+ return;
+ }
+ });
+ }
+
var language = {
serverName: '{{ app['conf'].get('servername') | e('js') }}',
serverError: '{{ 'phraseanet::erreur: Une erreur est survenue, si ce probleme persiste, contactez le support technique' | trans | e('js') }}',
@@ -55,6 +83,102 @@
$(window).bind('resize',function(){resize();});
resize();
});
+ }
+
+ function enableFormsCallback(datas)
+ {
+ $('#right-ajax').removeClass('loading').html(datas);
+ enableForms($('#right-ajax form:not(.no-ajax)'));
+
+ $.each($('#right-ajax a:not(.no-ajax)'),function(i, el){
+ enableLink($(el));
+ });
+ return;
+ }
+
+ function enableLink(link) {
+
+ $(link).bind('click',function(event){
+
+ var dest = link.attr('href');
+
+ if(dest && dest.indexOf('#') !== 0) {
+ $('#right-ajax').empty().addClass('loading').parent().show();
+
+ $.get(dest, function(data) {
+ enableFormsCallback(data);
+ });
+ return false;
+ }
+
+ });
+ }
+
+ function activeTree(click)
+ {
+ $('#FNDR').treeview({
+ collapsed: true,
+ animated: "medium"
+ });
+
+ $.each($('#tree a[target=right]'),function(){
+ var dest = $(this).attr('href');
+
+ $(this).bind('click',function(){
+ $('#right-ajax').empty().addClass('loading').parent().show();
+
+ $.get(dest, function(data) {
+ enableFormsCallback(data);
+ });
+ $('#tree .selected').removeClass('selected');
+ $(this).parent().addClass('selected');
+
+ return false;
+ });
+
+ $(this).removeAttr('target');
+ });
+ if(click === true)
+ {
+ if($('#tree .selected').length > 0)
+ $('#tree .selected a').trigger('click');
+ else
+ $('.zone_online_users').trigger('click');
+ }
+ }
+
+ $(document).ready(
+ function(){
+ resize();
+ setTimeout('pollNotifications();',15000);
+ activeTree(true);
+ }
+ );
+
+ function resize()
+ {
+ bodySize.y = $(window).height() - $('#mainMenu').outerHeight();
+ bodySize.x = $(window).width();
+ }
+
+ $(window).bind('resize',function(){resize();});
+
+ function reloadTree(position, click){
+ $.ajax({
+ type: "GET",
+ url: "/admin/tree/",
+ data: {
+ position : position
+ },
+ success: function(datas){
+ $('#FNDR').empty().append(datas);
+ activeTree(click);
+
+ return;
+ }
+ });
+ }
+
{% endblock %}
diff --git a/templates/web/admin/tree.html.twig b/templates/web/admin/tree.html.twig
index d3084986d5..afce212740 100644
--- a/templates/web/admin/tree.html.twig
+++ b/templates/web/admin/tree.html.twig
@@ -186,17 +186,13 @@
{% endif %}
- {% if (app['acl'].get(app['authentication'].getUser()).has_right_on_base( collection.get_base_id(), 'canadmin')) %}
- {% if (app['acl'].get(app['authentication'].getUser()).has_right_on_base( collection.get_base_id(), 'canmodifrecord')
- and app['acl'].get(app['authentication'].getUser()).has_right_on_base( collection.get_base_id(), 'manage')
- and app['acl'].get(app['authentication'].getUser()).has_right_on_sbas( sbas_id, 'bas_manage') ) %}
+ {% if app['acl'].get(app['authentication'].getUser()).has_right_on_base( collection.get_base_id(), 'canadmin')) %}
-
{{ 'admin::utilisateurs: utilisateurs' | trans }}
- {% endif %}
{% endif %}
diff --git a/templates/web/client/index.html.twig b/templates/web/client/index.html.twig
index e35625cc3e..63a083c94b 100644
--- a/templates/web/client/index.html.twig
+++ b/templates/web/client/index.html.twig
@@ -1,7 +1,7 @@
{{ app['conf'].get(['registry', 'general', 'title']) }} Client
-
+