PHRAS-46 #fix

PHRAS-16 #time 40h
This commit is contained in:
Jean-Yves Gaulier
2014-05-06 12:08:04 +02:00
committed by Nicolas Le Goff
parent 5563c34b8c
commit 192c2fbb55
17 changed files with 253 additions and 49 deletions

View File

@@ -136,6 +136,8 @@ use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents; use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Generator\UrlGenerator; use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Form\FormFactory; use Symfony\Component\Form\FormFactory;
use Symfony\Component\Form\FormTypeInterface; use Symfony\Component\Form\FormTypeInterface;
@@ -788,6 +790,94 @@ class Application extends SilexApplication
$this->mount('/datafiles/', new Datafiles()); $this->mount('/datafiles/', new Datafiles());
// log real human activity on application, to keep session alive
$app = $this;
$this->before(function(Request $request) use ($app) {
static $modulesIds = array(
"prod" => 1,
"client" => 2,
"admin" => 3,
"thesaurus" => 5,
"report" => 10,
"lightbox" => 6,
);
$pathInfo = explode('/', $request->getPathInfo());
if(count($pathInfo) < 2) {
return;
}
$moduleName = strtolower($pathInfo[1]);
if(!array_key_exists($moduleName, $modulesIds) ) { // || !($app['authentication']->isAuthenticated()) ) {
return;
}
// this route is polled by js in admin/databox to refresh infos (progress bar...)
if(preg_match("#^/admin/databox/[0-9]+/informations/documents/#", $request->getPathInfo()) == 1) {
return;
}
// this route is polled by js in admin/tasks to refresh tasks status
if($request->getPathInfo() == "/admin/task-manager/tasks/" && $request->getContentType() == 'json') {
return;
}
// if we are already disconnected (ex. from another window), quit immediatly
if(!($app['authentication']->isAuthenticated())) {
if($request->isXmlHttpRequest()) {
$r = new Response("End-Session", 403);
}
else {
$r = new RedirectResponse($app["url_generator"]->generate("homepage"));
}
$r->headers->set('X-Phraseanet-End-Session', '1');
return $r;
}
$session = $app['EM']->find('Entities\Session', $app['session']->get('session_id'));
$idle = 0;
if(isset($app["phraseanet.configuration"]["session"]["idle"])) {
$idle = (int)($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
$app['authentication']->closeAccount();
if($request->isXmlHttpRequest()) {
$r = new Response("End-Session", 403);
}
else {
$r = new RedirectResponse($app["url_generator"]->generate("homepage"));
}
$r->headers->set('X-Phraseanet-End-Session', '1');
return $r;
}
$moduleId = $modulesIds[$moduleName];
$session->setUpdated(new \DateTime());
if (!$session->hasModuleId($moduleId)) {
$module = new \Entities\SessionModule();
$module->setModuleId($moduleId);
$module->setSession($session);
$session->addModule($module);
$app['EM']->persist($module);
} else {
$app['EM']->persist($session->getModuleById($moduleId)->setUpdated(new \DateTime()));
}
$app['EM']->persist($session);
$app['EM']->flush();
});
$this->mount('/admin/', new AdminRoot()); $this->mount('/admin/', new AdminRoot());
$this->mount('/admin/dashboard', new Dashboard()); $this->mount('/admin/dashboard', new Dashboard());
$this->mount('/admin/collection', new Collection()); $this->mount('/admin/collection', new Collection());

View File

@@ -17,6 +17,8 @@ use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Alchemy\Phrasea\Controller\Root\Session;
/** /**
* *
* @license http://opensource.org/licenses/gpl-3.0 GPLv3 * @license http://opensource.org/licenses/gpl-3.0 GPLv3
@@ -28,7 +30,6 @@ class Root implements ControllerProviderInterface
public function connect(Application $app) public function connect(Application $app)
{ {
$controllers = $app['controllers_factory']; $controllers = $app['controllers_factory'];
$app['firewall']->addMandatoryAuthentication($controllers); $app['firewall']->addMandatoryAuthentication($controllers);
$controllers->before(function (Request $request) use ($app) { $controllers->before(function (Request $request) use ($app) {

View File

@@ -766,7 +766,7 @@ class Login implements ControllerProviderInterface
$feeds = $public_feeds->get_feeds(); $feeds = $public_feeds->get_feeds();
array_unshift($feeds, $public_feeds->get_aggregate()); array_unshift($feeds, $public_feeds->get_aggregate());
$form = $app->form(new PhraseaAuthenticationForm()); $form = $app->form(new PhraseaAuthenticationForm($app));
$form->setData(array( $form->setData(array(
'redirect' => $request->query->get('redirect') 'redirect' => $request->query->get('redirect')
)); ));
@@ -788,7 +788,7 @@ class Login implements ControllerProviderInterface
*/ */
public function authenticate(PhraseaApplication $app, Request $request) public function authenticate(PhraseaApplication $app, Request $request)
{ {
$form = $app->form(new PhraseaAuthenticationForm()); $form = $app->form(new PhraseaAuthenticationForm($app));
$redirector = function (array $params = array()) use ($app) { $redirector = function (array $params = array()) use ($app) {
return $app->redirectPath('homepage', $params); return $app->redirectPath('homepage', $params);
}; };
@@ -1079,7 +1079,7 @@ class Login implements ControllerProviderInterface
$session->setToken($token)->setNonce($nonce); $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']->persist($session);
$app['EM']->flush(); $app['EM']->flush();

View File

@@ -38,6 +38,8 @@ class Session implements ControllerProviderInterface
$controllers->post('/update/', $this->call('updateSession')) $controllers->post('/update/', $this->call('updateSession'))
->bind('update_session'); ->bind('update_session');
$controllers->post('/notifications/', $this->call('getNotifications'))
->bind('get_notifications');
$controller = $controllers->post('/delete/{id}', $this->call('deleteSession')) $controller = $controllers->post('/delete/{id}', $this->call('deleteSession'))
->bind('delete_session'); ->bind('delete_session');
@@ -47,6 +49,76 @@ class Session implements ControllerProviderInterface
return $controllers; 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 * Check session state
* *

View File

@@ -14,9 +14,17 @@ namespace Alchemy\Phrasea\Form\Login;
use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints as Assert; use Symfony\Component\Validator\Constraints as Assert;
use Silex\Application;
class PhraseaAuthenticationForm extends AbstractType class PhraseaAuthenticationForm extends AbstractType
{ {
private $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function buildForm(FormBuilderInterface $builder, array $options) public function buildForm(FormBuilderInterface $builder, array $options)
{ {
$builder->add('login', 'text', array( $builder->add('login', 'text', array(
@@ -37,12 +45,11 @@ class PhraseaAuthenticationForm extends AbstractType
), ),
)); ));
$builder->add('remember-me', 'checkbox', array( $builder->add('remember-me', $this->app['phraseanet.configuration']['session']['idle'] < 1 ? 'checkbox' : 'hidden', array(
'label' => _('Remember me'), 'label' => $this->app['phraseanet.configuration']['session']['idle'] < 1 ? _('Remember me') : "",
'mapped' => false, 'mapped' => false,
'required' => false, 'required' => false,
'attr' => array( 'attr' => array(
'checked' => 'checked',
'value' => '1', 'value' => '1',
) )
)); ));

View File

@@ -157,3 +157,8 @@ api_cors:
expose_headers: [] expose_headers: []
max_age: 0 max_age: 0
hosts: [] hosts: []
session:
idle: 0
# 1 week
lifetime: 604800

View File

@@ -245,6 +245,11 @@
<script type="text/javascript"> <script type="text/javascript">
function refreshDatabaseInformations() function refreshDatabaseInformations()
{ {
// stop the refresh if the page changed
if($("#thesaurus_indexed_bar").length == 0) {
return;
}
$.ajax({ $.ajax({
type: "GET", type: "GET",
url: "/admin/databox/{{ databox.get_sbas_id() }}/informations/documents/", url: "/admin/databox/{{ databox.get_sbas_id() }}/informations/documents/",
@@ -284,13 +289,14 @@
$("#printLogoDIV_OK").hide(); $("#printLogoDIV_OK").hide();
$("#printLogoDIV_NONE").show(); $("#printLogoDIV_NONE").show();
} }
// refresh every 10 sec.
setTimeout("refreshDatabaseInformations();", 10000);
} }
}); });
setTimeout("refreshDatabaseInformations();", 10000);
} }
$(document).ready(function(){ $(document).ready(function(){
refreshDatabaseInformations();
$('#is_indexable').bind('change', function(){ $('#is_indexable').bind('change', function(){
var form = $(this).closest('form'); var form = $(this).closest('form');
@@ -385,6 +391,9 @@
enableFormsCallback(data.result); enableFormsCallback(data.result);
} }
}); });
// start the refresh of the page content (progress bar etc...)
setTimeout("refreshDatabaseInformations();", 2000);
}); });
</script> </script>

View File

@@ -45,20 +45,20 @@
reset_template_ask_choice: '{{ 'Would you like to reset rights before applying the template?' | trans | e('js') }}' reset_template_ask_choice: '{{ 'Would you like to reset rights before applying the template?' | trans | e('js') }}'
}; };
function sessionactive(){ function pollNotifications(){
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/session/update/", url: "{{ path('get_notifications') }}",
dataType: 'json', dataType: 'json',
data: { data: {
module : 3, module : 3,
usr : {{ app['authentication'].getUser().get_id() }} usr : {{ app['authentication'].getUser().get_id() }}
}, },
error: function(){ error: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
timeout: function(){ timeout: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
success: function(data){ success: function(data){
if(data) if(data)
@@ -66,7 +66,7 @@
var t = 120000; var t = 120000;
if(data.apps && parseInt(data.apps)>1) if(data.apps && parseInt(data.apps)>1)
t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000)); t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000));
window.setTimeout("sessionactive();", t); window.setTimeout("pollNotifications();", t);
return; return;
} }
@@ -160,7 +160,7 @@
$(document).ready( $(document).ready(
function(){ function(){
resize(); resize();
setTimeout('sessionactive();',15000); setTimeout('pollNotifications();',15000);
activeTree(true); activeTree(true);
} }
); );

View File

@@ -438,20 +438,20 @@
document.styleSheets[0][propname][3].style.height = (w)+"px"; // .h160px document.styleSheets[0][propname][3].style.height = (w)+"px"; // .h160px
} }
function sessionactive(){ function pollNotifications(){
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/session/update/", url: "/session/notifications/",
dataType: 'json', dataType: 'json',
data: { data: {
app : 2, app : 2,
usr : {{ app['authentication'].getUser().get_id() }} usr : {{ app['authentication'].getUser().get_id() }}
}, },
error: function(){ error: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
timeout: function(){ timeout: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
success: function(data){ success: function(data){
if(data) if(data)
@@ -459,7 +459,7 @@
var t = 120000; var t = 120000;
if(data.apps && parseInt(data.apps)>1) if(data.apps && parseInt(data.apps)>1)
t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000)); t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000));
window.setTimeout("sessionactive();", t); window.setTimeout("pollNotifications();", t);
return; return;
} }

View File

@@ -1017,24 +1017,25 @@
</script> </script>
<script type="text/javascript" src="{{ path('minifier', { 'g' : 'prod' }) }}"></script> <script type="text/javascript" src="{{ path('minifier', { 'g' : 'prod' }) }}"></script>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function(){
$(document).ready(function() {
p4.reg_delete="{% if app['authentication'].getUser().getPrefs("warning_on_delete_story") %}true{% else %}false{% endif %}"; p4.reg_delete="{% if app['authentication'].getUser().getPrefs("warning_on_delete_story") %}true{% else %}false{% endif %}";
}); });
function sessionactive(){ function pollNotifications(){
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "{{ path('update_session') }}", url: "{{ path('get_notifications') }}",
dataType: "json", dataType: "json",
data: { data: {
module : 1, module : 1,
usr : {{app['authentication'].getUser().get_id()}} usr : {{app['authentication'].getUser().get_id()}}
}, },
error: function(){ error: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
timeout: function(){ timeout: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
success: function(data){ success: function(data){
if(data) if(data)
@@ -1042,7 +1043,7 @@
var t = 120000; var t = 120000;
if(data.apps && parseInt(data.apps)>1) if(data.apps && parseInt(data.apps)>1)
t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 60000)); t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 60000));
window.setTimeout("sessionactive();", t); window.setTimeout("pollNotifications();", t);
return; return;
} }

View File

@@ -95,35 +95,40 @@
{ {
document.getElementById("desktop").scrollTop = 0; document.getElementById("desktop").scrollTop = 0;
} }
var xhr_object; var xhr_object;
function sessionactive(){ function pollNotifications(){
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/session/update/", url: "/session/notifications/",
dataType: 'json', dataType: 'json',
data: { data: {
module : 5, module : 5,
usr : {{ app['authentication'].getUser().get_id() }} usr : {{ app['authentication'].getUser().get_id() }}
}, },
error: function(){ error: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
timeout: function(){ timeout: function(){
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
success: function(data){ success: function(data){
if(data && typeof(data.status) && data.status == "disconnected") {
alert("Session expirée");
self.location.replace(self.location.href);
}
//if(manageSession(data)) //if(manageSession(data))
var t = 120000; var t = 5000; // 120000;
if(data.apps && parseInt(data.apps)>1) if(data.apps && parseInt(data.apps)>1)
t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000)); t = Math.round((Math.sqrt(parseInt(data.apps)-1) * 1.3 * 120000));
window.setTimeout("sessionactive();", t); window.setTimeout("pollNotifications();", t);
return; return;
} }
}) })
}; };
sessionactive(); window.setTimeout("pollNotifications();", 10000);
</script> </script>
</head> </head>

View File

@@ -82,9 +82,15 @@ $(document).ready(function () {
} }
}); });
set_notif_position(); $(document).ajaxError(function( event, jqxhr, settings, exception ) {
if(jqxhr.status == 403 && jqxhr.getResponseHeader("X-Phraseanet-End-Session") == "1") {
disconnected();
}
});
set_notif_position();
}); });
@@ -334,6 +340,7 @@ function infoDialog(el) {
} }
}).dialog('open').css({'overflow-x': 'auto', 'overflow-y': 'auto'}); }).dialog('open').css({'overflow-x': 'auto', 'overflow-y': 'auto'});
} }
function manageSession(data, showMessages) { function manageSession(data, showMessages) {
if (typeof(showMessages) == "undefined") if (typeof(showMessages) == "undefined")
showMessages = false; showMessages = false;
@@ -438,15 +445,20 @@ function showModal(cas, options) {
content = language.serverDisconnected; content = language.serverDisconnected;
escape = false; escape = false;
callback = function (e) { callback = function (e) {
self.location.replace(self.location.href) self.location.replace(self.location.href);
}; };
break; break;
default: default:
break; break;
} }
if(typeof(p4.Alerts) == "undefined") {
alert("disconnected");
self.location.replace(self.location.href);
}
else {
p4.Alerts(options.title, content, callback); p4.Alerts(options.title, content, callback);
}
return; return;
} }

View File

@@ -105,7 +105,7 @@ $(document).ready(function () {
$(this).removeClass("hover"); $(this).removeClass("hover");
}); });
sessionactive(); window.setTimeout("pollNotifications();", 10000);
resize(); resize();
$(window).resize(function () { $(window).resize(function () {
resize(); resize();

View File

@@ -236,3 +236,7 @@ input.checkbox{
.ui-dialog-titlebar { .ui-dialog-titlebar {
min-height: 20px; min-height: 20px;
} }
.ui-dialog[aria-describedby="p4_alerts"]{
z-index:2000 !important;
}

View File

@@ -6,7 +6,6 @@ var p4 = p4 || {};
if ($('#p4_alerts').length === 0) { if ($('#p4_alerts').length === 0) {
$('body').append('<div id="p4_alerts"></div>'); $('body').append('<div id="p4_alerts"></div>');
} }
return $('#p4_alerts'); return $('#p4_alerts');
} }
@@ -21,7 +20,6 @@ var p4 = p4 || {};
else else
dialog.dialog('close'); dialog.dialog('close');
}; };
if (dialog.data('ui-dialog')) { if (dialog.data('ui-dialog')) {
dialog.dialog('destroy'); dialog.dialog('destroy');
} }

View File

@@ -1131,7 +1131,7 @@ $(document).ready(function () {
initLook(); initLook();
setTimeout("sessionactive();", 30000); setTimeout("pollNotifications();", 10000);
$(this).bind('keydown', function (event) { $(this).bind('keydown', function (event) {
var cancelKey = false; var cancelKey = false;

View File

@@ -1067,21 +1067,21 @@ function resize() {
$('.answers:visible').height(Math.round(bodySize.y - $('.answers:visible').offset().top)); $('.answers:visible').height(Math.round(bodySize.y - $('.answers:visible').offset().top));
}; };
//update session
function sessionactive() { function pollNotifications() {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/session/update/", url: "/session/notifications/",
dataType: 'json', dataType: 'json',
data: { data: {
module: 10, module: 10,
usr: usrId usr: usrId
}, },
error: function () { error: function () {
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
timeout: function () { timeout: function () {
window.setTimeout("sessionactive();", 10000); window.setTimeout("pollNotifications();", 10000);
}, },
success: function (data) { success: function (data) {
if (data) { if (data) {
@@ -1091,10 +1091,10 @@ function sessionactive() {
if (data.apps && parseInt(data.apps) > 1) { if (data.apps && parseInt(data.apps) > 1) {
t = Math.round((Math.sqrt(parseInt(data.apps) - 1) * 1.3 * 120000)); t = Math.round((Math.sqrt(parseInt(data.apps) - 1) * 1.3 * 120000));
} }
window.setTimeout("sessionactive();", t); window.setTimeout("pollNotifications();", t);
return; return;
} }
}); });
}; };
sessionactive(); window.setTimeout("pollNotifications();", 10000);