Commit 5e8c4217 authored by Ghislain Loas's avatar Ghislain Loas

dev #58111 show new features notification

parent a3a86f11
'58111' =>
['Label' => $this->_('Ouvrir automatiquement la note de version à la première connection d'un administrateur'),
'Desc' => '',
'Image' => '',
'Video' => '',
'Category' => '',
'Right' => function($feature_description, $user) {return true;},
'Wiki' => '',
'Test' => '',
'Date' => '2018-02-21'],
\ No newline at end of file
- ticket #58111 : Ouvrir automatiquement la note de version à la première connection d'un administrateur
\ No newline at end of file
......@@ -71,4 +71,12 @@ class Admin_FeatureController extends ZendAfi_Controller_Action {
$feature->getLabel()));
$this->_redirectToIndex();
}
public function stopTrackingAction() {
if((new Class_Feature())->stopTracking())
$this->_helper->notify($this->_('Vous ne serez plus notifié des nouvelles fonctionnalités jusqu\'à la prochaine mise à jour du logicel.'));
$this->_redirectToIndex();
}
}
\ No newline at end of file
......@@ -337,7 +337,9 @@ class Class_AdminVarLoader extends Storm_Model_Loader {
'CNIL_CONSENT_ENABLE' => Class_AdminVar_Meta::newOnOff('Affiche la demande de consentement avant l\'insertion de cookies ou autres traceurs'),
'BUID' => Class_AdminVar_Meta::newRawText($this->_('Identifiant unique (attention: la modification de cette variable impactera les outils de suivi de cette installation)'))->bePrivate(),
'STATUS_REPORT_PUSH_URL' => Class_AdminVar_Meta::newRawText($this->_('URL destinataire du rapport d\'état du système (0 pour désactiver)'), ['value' => 'http://pola.afi-sa.net/smile.php'])->bePrivate(),
'STATUS_REPORT_TAGS' => Class_AdminVar_Meta::newMultiInput($this->_('Liste des tags à ajouter au rapport d\'état du système'))->bePrivate()];
'STATUS_REPORT_TAGS' => Class_AdminVar_Meta::newMultiInput($this->_('Liste des tags à ajouter au rapport d\'état du système'))->bePrivate(),
'FEATURES_TRACKING_ENABLE' => Class_AdminVar_Meta::newOnOff('Affiche les dernières modifications apportés au logiciel Bokeh')->bePrivate()
];
}
......
......@@ -22,10 +22,20 @@
class Class_Feature {
use
Trait_Translator,
Trait_StaticFileSystem;
Trait_StaticFileSystem,
Trait_TimeSource,
Trait_Translator;
protected static $_features;
protected static
$_features,
$_cookie_jar;
/** @category testing */
public static function setCookieJar($cookie_jar) {
static::$_cookie_jar = $cookie_jar;
}
public function hasNew() {
......@@ -108,4 +118,94 @@ class Class_Feature {
->setId($id)
->updateAttributes($feature);
}
protected function _getCookieJar() {
return static::$_cookie_jar
? static::$_cookie_jar
: new Class_Feature_CookieJar();
}
public function trackFeatures() {
if (!Class_AdminVar::get('FEATURES_TRACKING_ENABLE'))
return;
if(!$user = Class_Users::getIdentity())
return;
if(!$user->isAdmin())
return;
if(!$features = $this->findNewFor($user))
return;
$this->_session = new Zend_Session_Namespace($this->_getCookieJar()->getKey());
if (isset($_COOKIE[$this->_getCookieJar()->getKey()]))
return;
if ($this->_session->seen)
return;
$this->_session->seen = true;
$features_url = Class_Url::absolute(['module' => 'admin',
'controller' => 'feature',
'action' => 'index'], null, true);
$stop_tracking_url = Class_Url::absolute(['module' => 'admin',
'controller' => 'feature',
'action' => 'stop-tracking'], null, true);
$content = [];
foreach($features as $feature)
$content[] = sprintf('<li>%s</li>', $feature->getLabel());
$content = sprintf('<ul>%s</ul>', implode($content));
$content = sprintf('<h2>%s</h2>',
$this->_('Nouvelles fonctionnalités depuis votre dernière connexion : '))
. $content;
$buttons = sprintf('<button class="admin-button" onclick="window.open(\'%s\', \'_top\');">%s</button>',
$features_url,
$this->_('En savoir plus'))
. sprintf('<button class="admin-button" onclick="window.open(\'%s\', \'_top\')">%s</button>',
$stop_tracking_url,
$this->_('Ne plus m\'avertir'));
$buttons = sprintf('<div class="button_wrapper">%s</div>', $buttons);
$content .= $buttons;
$content = sprintf('<div class="features">%s</div>', $content);
Class_ScriptLoader::getInstance()
->notify($content,
false,
10,
'new_features');
}
public function stopTracking() {
$this->_getCookieJar()->getKey();
$this->_session = new Zend_Session_Namespace($this->_getCookieJar()->getKey());
return $this->_getCookieJar()
->setcookie($this->_getCookieJar()->getKey(),
'1',
$this->getTimeSource()->time() + (3600 * 24 * 30 * 6));
}
}
class Class_Feature_CookieJar {
public function setcookie() {
call_user_func_array('setcookie', func_get_args());
}
public function getKey() {
return 'tracking_features_' . str_replace('.', '_', BOKEH_RELEASE_NUMBER);
}
}
\ No newline at end of file
......@@ -338,9 +338,11 @@ class Class_ScriptLoader {
public function loadNotificationJS() {
Class_Admin_Skin::current()->renderButtonCssOn($this);
return $this
->addScript(URL_ADMIN_JS.'notification/js/jquery_notification_v.1')
->addStyleSheet(URL_ADMIN_JS.'notification/css/jquery_notification')
->addAdminStyleSheet('notification')
->addSkinStyleSheet('notification');
}
......
<?php
/**
* Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
class ZendAfi_Controller_Plugin_FeaturesTracking extends Zend_Controller_Plugin_Abstract {
function preDispatch(Zend_Controller_Request_Abstract $request) {
(new Class_Feature())->trackFeatures();
}
}
......@@ -298,6 +298,7 @@ class Bokeh_Engine {
->registerPlugin(new ZendAfi_Controller_Plugin_InspectorGadget())
->registerPlugin(new ZendAfi_Controller_Plugin_CnilConsent())
->registerPlugin(new ZendAfi_Controller_Plugin_Redmine())
->registerPlugin(new ZendAfi_Controller_Plugin_FeaturesTracking())
->setParam('useDefaultControllerAlways', false);
}
......
#info_message.new_features {
background: var(--main-text);
height: 100%;
}
#info_message.new_features > div {
background: var(--button);
margin: 10%;
width: 80%;
}
#info_message .features {
text-align: left;
}
#info_message .features ul,
#info_message .features li{
padding: 0 0 1ex 1em;
list-style-type: initial;
}
#info_message .features .button_wrapper {
text-align: center;
}
#info_message.new_features .info_close_btn {
float: right;
}
#info_message.new_features .info_close_btn:after {
content: 'X';
display: block;
}
\ No newline at end of file
......@@ -33,7 +33,9 @@ function showNotification(params){
msgclass = 'info_bg'; // over write the message to information message
} else if(options['type'] == 'warning'){
msgclass = 'warn_bg'; // over write the message to warning message
}
} else {
msgclass = options['type']; // over write class
}
// Parent Div container
var container = '<div id="info_message" role="alert" class="'+msgclass+'"><div class="center_auto"><div class="info_message_text message_area">';
......
<?php
/**
* Copyright (c) 2012-2017, Agence Française Informatique (AFI). All rights reserved.
*
* BOKEH is free software; you can redistribute it and/or modify
* it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
* the Free Software Foundation.
*
* There are special exceptions to the terms and conditions of the AGPL as it
* is applied to this software (see README file).
*
* BOKEH is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
* along with BOKEH; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
abstract class IndexControllerFeaturesTrackingTestCase extends Admin_AbstractControllerTestCase {
protected $_storm_default_to_volatile = true;
protected $_expected_message = 'Nouvelles fonctionnalit\u00e9s depuis votre derni\u00e8re connexion :';
protected $_cookie_jar;
public function setUp() {
parent::setUp();
$this->fixture('Class_AdminVar', ['id' => 'FEATURES_TRACKING_ENABLE',
'valeur' => true]);
Class_Feature::setTimeSource($this->mock()
->whenCalled('time')
->answers(strtotime('2018-02-21 11:51:54')));
Class_Feature::setCookieJar($this->_cookie_jar =
$this->mock()
->whenCalled('setcookie')
->answers(null)
->whenCalled('getKey')
->answers('tracking_features_7_11_20')
->beStrict());
}
public function tearDown() {
Class_Feature::setCookieJar(null);
$_COOKIE = [];
parent::tearDown();
}
}
class IndexControllerFeaturesTrackingFirstVisitTest
extends IndexControllerFeaturesTrackingTestCase {
public function setUp() {
parent::setUp();
$this->dispatch('/', true);
}
/** @test */
public function shouldDisplayNewFeaturesMessage() {
$this->assertXPathContentContains('//script', $this->_expected_message, $this->_response->getBody());
}
}
class IndexControllerFeaturesTrackingTrackingFirstVisitWithAdminVarDisabledTest
extends IndexControllerFeaturesTrackingTestCase {
public function setUp() {
parent::setUp();
$this->fixture('Class_AdminVar', ['id' => 'FEATURES_TRACKING_ENABLE',
'valeur' => false]);
$this->dispatch('/', true);
}
/** @test */
public function shouldNotDisplayNewFeaturesMessage() {
$this->assertNotXPathContentContains('//script', $this->_expected_message);
}
}
class IndexControllerFeaturesTrackingSecondVisitTest
extends IndexControllerFeaturesTrackingTestCase {
public function setUp() {
parent::setUp();
$this->dispatch('/', true);
$this->_response->setBody('');
Class_ScriptLoader::resetInstance();
$this->dispatch('/', true);
}
/** @test */
public function shouldNotDisplayNewFeaturesMessage() {
$this->assertNotXPathContentContains('//script', $this->_expected_message);
}
/** @test */
public function shouldNotSetCookieFor6Months() {
$this->assertFalse($this->_cookie_jar->methodHasBeenCalled('setcookie'));
}
}
class IndexControllerFeaturesTrackingExistingCookieVisitTest
extends IndexControllerFeaturesTrackingTestCase {
/** @test */
public function shouldNotDisplayNewFeaturesMessage() {
$_COOKIE['tracking_features_' . BOKEH_RELEASE_NUMBER] = 1;
$this->dispatch('/', true);
$this->assertNotXPathContentContains('//script', $this->_expected_message);
}
}
class IndexControllerFeaturesTrackingUntrackTest
extends IndexControllerFeaturesTrackingTestCase {
public function setUp() {
parent::setUp();
Class_Feature::setCookieJar($this->_cookie_jar = $this->mock()
->whenCalled('setcookie')
->with('tracking_features_7_11_20',
1,
1534762314)
->answers($_COOKIE = ['tracking_features_7_11_20' => 1])
->whenCalled('getKey')
->answers('tracking_features_7_11_20'));
$this->dispatch('/admin/feature/stop-tracking', true);
}
/** @test */
public function shouldNotDisplayNewFeaturesMessage() {
$this->assertEquals(1, $_COOKIE['tracking_features_7_11_20']);
}
/** @test */
public function shouldSetCookie() {
$this->assertTrue($this->_cookie_jar->methodHasBeenCalled('setcookie'));
}
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment