* Admin: session-list is generated now from egw_access_log table independent of readablity of sessions files in filesystem

- session_(dla|action) is stored in egw_access_log table
- notifications refresh via ajax set notification_heartbeat timestamp in egw_access_log
- if notification_heartbeat is set (happens only for browser sessions with popup notification) sessions get removed from session list one minute after browser is closed
- new static method egw_session::notifications_active($account_id) to check if given user has an open browser with notifications popup checking, to ensure popup notifications can fall back to email
--> REQUIRES DATABASE UPDATE / SETUP
This commit is contained in:
Ralf Becker 2011-04-13 14:11:09 +00:00
parent aecfe9d768
commit 5495491e78
15 changed files with 363 additions and 349 deletions

View File

@ -1,17 +1,17 @@
<?php <?php
/** /**
* eGgroupWare admin - accesslog * EGgroupware admin - access- and session-log
* *
* @link http://www.egroupware.org * @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de> * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package admin * @package admin
* @copyright (c) 2009 by Ralf Becker <RalfBecker-AT-outdoor-training.de> * @copyright (c) 2009-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$ * @version $Id$
*/ */
/** /**
* Show eGroupware access log * Show EGroupware access- and session-log
*/ */
class admin_accesslog class admin_accesslog
{ {
@ -22,6 +22,7 @@ class admin_accesslog
*/ */
public $public_functions = array( public $public_functions = array(
'index' => true, 'index' => true,
'sessions' => true,
); );
/** /**
@ -46,10 +47,6 @@ class admin_accesslog
*/ */
function __construct() function __construct()
{ {
if ($GLOBALS['egw']->acl->check('access_log_access',1,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
$this->so = new so_sql(self::APP,self::TABLE,null,'',true); $this->so = new so_sql(self::APP,self::TABLE,null,'',true);
} }
@ -63,34 +60,81 @@ class admin_accesslog
*/ */
function get_rows($query,&$rows,&$readonlys) function get_rows($query,&$rows,&$readonlys)
{ {
$heartbeat_limit = egw_session::heartbeat_limit();
if ($query['session_list']) // filter active sessions
{
$query['col_filter']['lo'] = null; // not logged out
$query['col_filter'][0] = 'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']);
$query['col_filter'][1] = "(notification_heartbeat IS NULL OR notification_heartbeat > $heartbeat_limit)";
}
$total = $this->so->get_rows($query,$rows,$readonlys); $total = $this->so->get_rows($query,$rows,$readonlys);
$no_kill = !$GLOBALS['egw']->acl->check('current_sessions_access',8,'admin') && !$query['session_list'];
foreach($rows as &$row) foreach($rows as &$row)
{ {
$row['sessionstatus'] = lang('success'); $row['sessionstatus'] = lang('success');
if (stripos($row['sessionid'],'blocked') !== False || stripos($row['sessionid'],'bad login') !== False) if ($row['notification_heartbeat'] > $heartbeat_limit)
{ {
$row['sessionstatus'] = $row['sessionid']; $row['sessionstatus'] = lang('active');
}
if (stripos($row['session_php'],'blocked') !== false ||
stripos($row['session_php'],'bad login') !== false ||
strpos($row['sessioin_php'],' ') !== false)
{
$row['sessionstatus'] = $row['session_php'];
} }
if ($row['lo']) { if ($row['lo']) {
$row['total'] = ($row['lo'] - $row['li']) / 60; $row['total'] = ($row['lo'] - $row['li']) / 60;
$row['sessionstatus'] = lang('logged out'); $row['sessionstatus'] = lang('logged out');
} }
// eg. for bad login or password
if (!$row['account_id']) $row['alt_loginid'] = $row['loginid'];
$readonlys['kill['.$row['sessionid'].']'] = $no_kill;
$readonlys['delete['.$row['sessionid'].']'] = $query['session_list'];
// do not allow to kill or select own session
if ($GLOBALS['egw']->session->sessionid_access_log == $row['sessionid'] && $query['session_list'])
{
$readonlys['kill['.$row['sessionid'].']'] = $readonlys['selected['.$row['sessionid'].']'] = true;
}
// do not allow to delete access log off active sessions
if (!$row['lo'] && $row['session_dla'] > time()-$GLOBALS['egw_info']['server']['sessions_timeout'] && !$query['session_list'])
{
$readonlys['delete['.$row['sessionid'].']'] = $readonlys['selected['.$row['sessionid'].']'] = true;
}
unset($row['session_php']); // for security reasons, do NOT give real PHP sessionid to UI
} }
$GLOBALS['egw_info']['flags']['app_header'] = lang('Admin').' - '.lang('View Access Log'). if ($query['session_list'])
{
$rows['no_total'] = $rows['no_lo'] = true;
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('Admin').' - '.
($query['session_list'] ? lang('View sessions') : lang('View Access Log')).
($query['col_filter']['account_id'] ? ': '.common::grab_owner_name($query['col_filter']['account_id']) : ''); ($query['col_filter']['account_id'] ? ': '.common::grab_owner_name($query['col_filter']['account_id']) : '');
return $total; return $total;
} }
/** /**
* Display the accesslog * Display the access log or session list
* *
* @param array $content * @param array $content=null
* @param string $msg=''
* @param boolean $sessions_list=false
*/ */
function index(array $content=null) function index(array $content=null, $msg='', $sessions_list=false)
{ {
//_debug_array($content); //_debug_array($content);
if (is_array($content)) $sessions_list = $content['nm']['session_list'];
// check if user has access to requested functionality
if ($GLOBALS['egw']->acl->check($sessions_list ? 'current_sessions_access' : 'access_log_access',1,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
if(!isset($content)) if(!isset($content))
{ {
@ -114,32 +158,71 @@ class admin_accesslog
{ {
$content['nm']['col_filter']['account_id'] = (int)$_GET['account_id']; $content['nm']['col_filter']['account_id'] = (int)$_GET['account_id'];
} }
if ($sessions_list)
{
$content['nm']['order'] = 'session_dla';
$content['nm']['options-selectcols'] = array(
'lo' => false,
'total' => false,
);
}
$content['nm']['session_list'] = $sessions_list;
} }
elseif(isset($content['nm']['rows']['delete'])) elseif(isset($content['nm']['rows']['delete']) || isset($content['delete']))
{ {
list($sessionid) = each($content['nm']['rows']['delete']); if (isset($content['nm']['rows']['delete']))
unset($content['nm']['rows']['delete']); {
list($sessionid) = each($content['nm']['rows']['delete']);
unset($content['nm']['rows']['delete']);
}
else
{
unset($content['delete']);
$sessionid = $content['nm']['rows']['selected'];
}
if ($sessionid && $this->so->delete(array('sessionid' => $sessionid))) if ($sessionid && $this->so->delete(array('sessionid' => $sessionid)))
{ {
$content['msg'] = lang('%1 log entries deleted.',1); $msg = lang('%1 log entries deleted.',1);
} }
else else
{ {
$content['msg'] = lang('Error deleting log entry!'); $msg = lang('Error deleting log entry!');
} }
} }
elseif(isset($content['delete'])) elseif(isset($content['nm']['rows']['kill']) || isset($content['kill']))
{ {
unset($content['delete']); if (isset($content['nm']['rows']['kill']))
if (($deleted = $this->so->delete(array('sessionid' => $content['nm']['rows']['selected']))))
{ {
$content['msg'] = lang('%1 log entries deleted.',$deleted); list($sessionid) = each($content['nm']['rows']['kill']);
$sessionid = array($sessionid);
unset($content['nm']['rows']['kill']);
} }
else else
{ {
$content['msg'] = lang('Error deleting log entry!'); unset($content['kill']);
$sessionid = $content['nm']['rows']['selected'];
}
if (($key = array_search($GLOBALS['egw']->session->sessionid_access_log, $sessionid)))
{
unset($sessionid[$key]); // dont allow to kill own sessions
}
if ($GLOBALS['egw']->acl->check('current_sessions_access',8,'admin'))
{
$msg = lang('Permission denied!');
}
else
{
foreach((array)$sessionid as $id)
{
$GLOBALS['egw']->session->destroy($id);
}
$msg = lang('%1 sessions killed',count($sessionid));
} }
} }
$readonlys['kill'] = !$sessions_list;
$readonlys['delete'] = $sessions_list;
$content['msg'] = $msg;
$content['percent'] = 100.0 * $GLOBALS['egw']->db->query( $content['percent'] = 100.0 * $GLOBALS['egw']->db->query(
'SELECT ((SELECT COUNT(*) FROM '.self::TABLE.' WHERE lo != 0) / COUNT(*)) FROM '.self::TABLE, 'SELECT ((SELECT COUNT(*) FROM '.self::TABLE.' WHERE lo != 0) / COUNT(*)) FROM '.self::TABLE,
__LINE__,__FILE__)->fetchColumn(); __LINE__,__FILE__)->fetchColumn();
@ -149,4 +232,15 @@ class admin_accesslog
'nm' => $content['nm'], 'nm' => $content['nm'],
)); ));
} }
/**
* Display session list
*
* @param array $content=null
* @param string $msg=''
*/
function sessions(array $content=null, $msg='')
{
return $this->index(null,$msg,true);
}
} }

View File

@ -83,7 +83,7 @@ class admin_prefs_sidebox_hooks
if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin')) if (! $GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
{ {
$file['View Sessions'] = egw::link('/index.php','menuaction=admin.uicurrentsessions.list_sessions'); $file['View Sessions'] = egw::link('/index.php','menuaction=admin.admin_accesslog.sessions');
} }
if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin')) if (! $GLOBALS['egw']->acl->check('access_log_access',1,'admin'))

View File

@ -1,71 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - Administration *
* http://www.egroupware.org *
* This file written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class bocurrentsessions
{
var $ui;
var $so;
var $public_functions = array(
'kill' => True
);
function total()
{
return $GLOBALS['egw']->session->session_count();
}
function list_sessions($start,$order,$sort)
{
$values = $GLOBALS['egw']->session->session_list($start,$sort,$order);
while (list(,$value) = @each($values))
{
if (strpos($value['session_lid'],'@') !== false)
{
$t = explode('@',$value['session_lid']);
$session_lid = $t[0];
}
else
{
$session_lid = $value['session_lid'];
}
$tmp = time() - $value['session_dla'];
$secs = $tmp % 60;
$mins = (($tmp - $secs) % 3600) / 60;
$hours = ($tmp - ($mins * 60) - $secs) / 3600;
$_values[] = array(
'session_id' => $value['session_id'],
'session_lid' => $session_lid,
'session_ip' => $value['session_ip'],
'session_logintime' => $GLOBALS['egw']->common->show_date($value['session_logintime']),
'session_action' => $value['session_action'],
'session_dla' => $value['session_dla'],
'session_idle' => str_pad($hours, 2, '0', STR_PAD_LEFT) . ':' . str_pad($mins, 2, '0', STR_PAD_LEFT) . ':' . str_pad($secs, 2, '0', STR_PAD_LEFT)
);
}
return $_values;
}
function kill()
{
if ($_GET['ksession'] &&
($GLOBALS['sessionid'] != $_GET['ksession']) &&
! $GLOBALS['egw']->acl->check('current_sessions_access',8,'admin'))
{
$GLOBALS['egw']->session->destroy($_GET['ksession'],0);
}
$this->ui =& CreateObject('admin.uicurrentsessions');
$this->ui->list_sessions();
}
}

View File

@ -1,162 +0,0 @@
<?php
/**************************************************************************\
* eGroupWare - Administration *
* http://www.egroupware.org *
* This file written by Joseph Engo <jengo@phpgroupware.org> *
* -------------------------------------------- *
* This program is free software; you can redistribute it and/or modify it *
* under the terms of the GNU General Public License as published by the *
* Free Software Foundation; either version 2 of the License, or (at your *
* option) any later version. *
\**************************************************************************/
/* $Id$ */
class uicurrentsessions
{
var $template;
var $bo;
var $public_functions = array(
'list_sessions' => True,
'kill' => True
);
function uicurrentsessions()
{
if ($GLOBALS['egw']->acl->check('current_sessions_access',1,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
$this->template =& CreateObject('phpgwapi.Template',EGW_APP_TPL);
$this->bo =& CreateObject('admin.bocurrentsessions');
$this->nextmatchs =& CreateObject('phpgwapi.nextmatchs');
}
function header()
{
$GLOBALS['egw']->common->egw_header();
echo parse_navbar();
}
function store_location($info)
{
$GLOBALS['egw']->session->appsession('currentsessions_session_data','admin',$info);
}
function list_sessions()
{
$info = $GLOBALS['egw']->session->appsession('currentsessions_session_data','admin');
if (! is_array($info))
{
$info = array(
'start' => 0,
'sort' => 'DESC',
'order' => 'session_dla'
);
$this->store_location($info);
}
if (isset($_REQUEST['start']) || $_REQUEST['sort'] || $_REQUEST['order'])
{
if ($_REQUEST['start'] == 0 || $_REQUEST['start'] && $_REQUEST['start'] != $info['start'])
{
$info['start'] = $_REQUEST['start'];
}
if ($_REQUEST['sort'] && $_REQUEST['sort'] != $info['sort'])
{
$info['sort'] = $_REQUEST['sort'];
}
if ($_REQUEST['order'] && $_REQUEST['order'] != $info['order'])
{
$info['order'] = $_REQUEST['order'];
}
$this->store_location($info);
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('Admin').' - '.lang('List of current users');
$this->header();
$this->template->set_file('current','currentusers.tpl');
$this->template->set_block('current','list','list');
$this->template->set_block('current','row','row');
$can_view_action = !$GLOBALS['egw']->acl->check('current_sessions_access',2,'admin');
$can_view_ip = !$GLOBALS['egw']->acl->check('current_sessions_access',4,'admin');
$can_kill = !$GLOBALS['egw']->acl->check('current_sessions_access',8,'admin');
$total = $this->bo->total();
$this->template->set_var('left_next_matchs',$this->nextmatchs->left('/admin/currentusers.php',$info['start'],$total));
$this->template->set_var('right_next_matchs',$this->nextmatchs->right('/admin/currentusers.php',$info['start'],$total));
$this->template->set_var('start_total',$this->nextmatchs->show_hits($total,$info['start']));
$this->template->set_var('sort_loginid',$this->nextmatchs->show_sort_order($info['sort'],'session_lid',$info['order'],
'/admin/currentusers.php',lang('LoginID')));
$this->template->set_var('sort_ip',$this->nextmatchs->show_sort_order($info['sort'],'session_ip',$info['order'],
'/admin/currentusers.php',lang('IP')));
$this->template->set_var('sort_login_time',$this->nextmatchs->show_sort_order($info['sort'],'session_logintime',$info['order'],
'/admin/currentusers.php',lang('Login Time')));
$this->template->set_var('sort_action',$this->nextmatchs->show_sort_order($info['sort'],'session_action',$info['order'],
'/admin/currentusers.php',lang('Action')));
$this->template->set_var('sort_idle',$this->nextmatchs->show_sort_order($info['sort'],'session_dla',$info['order'],
'/admin/currentusers.php',lang('idle')));
$this->template->set_var('lang_kill',lang('Kill'));
$values = $this->bo->list_sessions($info['start'],$info['order'],$info['sort']);
while (list(,$value) = @each($values))
{
$this->nextmatchs->template_alternate_row_color($this->template);
$this->template->set_var('row_loginid',$value['session_lid']);
$this->template->set_var('row_ip',$can_view_ip?$value['session_ip']:'&nbsp;');
$this->template->set_var('row_logintime',$value['session_logintime']);
$this->template->set_var('row_idle',$value['session_idle']);
if ($value['session_action'] && $can_view_action)
{
$this->template->set_var('row_action',$GLOBALS['egw']->strip_html($value['session_action']));
}
else
{
$this->template->set_var('row_action','&nbsp;');
}
if ($value['session_id'] != $GLOBALS['egw_info']['user']['sessionid'] && $can_kill)
{
$this->template->set_var('row_kill','<a href="' . $GLOBALS['egw']->link('/index.php','menuaction=admin.uicurrentsessions.kill&ksession='
. $value['session_id'] . '&kill=true') . '">' . lang('Kill').'</a>');
}
else
{
$this->template->set_var('row_kill','&nbsp;');
}
$this->template->parse('rows','row',True);
}
$this->template->pfp('out','list');
}
function kill()
{
if ($GLOBALS['egw']->acl->check('current_sessions_access',8,'admin'))
{
$GLOBALS['egw']->redirect_link('/index.php');
}
$GLOBALS['egw_info']['flags']['app_header'] = lang('Admin').' - '.lang('Kill session');
$this->header();
$this->template->set_file('form','kill_session.tpl');
$this->template->set_var('lang_message',lang('Are you sure you want to kill this session ?'));
$this->template->set_var('link_no','<a href="' . $GLOBALS['egw']->link('/index.php','menuaction=admin.uicurrentsessions.list_sessions') . '">' . lang('No') . '</a>');
$this->template->set_var('link_yes','<a href="' . $GLOBALS['egw']->link('/index.php','menuaction=admin.bocurrentsessions.kill&ksession=' . $_GET['ksession']) . '">' . lang('Yes') . '</a>');
$this->template->pfp('out','form');
}
}

View File

@ -7,6 +7,7 @@
%1 log entries deleted. admin de %1 Protokolleinträge gelöscht. %1 log entries deleted. admin de %1 Protokolleinträge gelöscht.
%1 not found or not executable !!! admin de %1 nicht gefunden oder nicht ausführbar !!! %1 not found or not executable !!! admin de %1 nicht gefunden oder nicht ausführbar !!!
%1 rights for %2 and applications %3 admin de %1 Rechte für %2 und Anwendung(en) %3 %1 rights for %2 and applications %3 admin de %1 Rechte für %2 und Anwendung(en) %3
%1 sessions killed admin de %1 Sitzungen beendet
%1 user %2 admin de %1 Benutzer %2 %1 user %2 admin de %1 Benutzer %2
(default no, leave it off if you dont use it) admin de (Vorgabe Nein, ausgeschaltet lassen, wenn nicht benutzt) (default no, leave it off if you dont use it) admin de (Vorgabe Nein, ausgeschaltet lassen, wenn nicht benutzt)
(stored password will not be shown here) admin de (Gespeichertes Passwort wird hier nicht angezeigt) (stored password will not be shown here) admin de (Gespeichertes Passwort wird hier nicht angezeigt)
@ -28,8 +29,8 @@ account preferences admin de Einstellungen der Benutzerkonten
account-id's have to be integers! admin de Konten-ID`s müssen vom Typ Integer (Zahl) sein! account-id's have to be integers! admin de Konten-ID`s müssen vom Typ Integer (Zahl) sein!
acl manager admin de ACL-Manager acl manager admin de ACL-Manager
acl rights common de ACL-Rechte acl rights common de ACL-Rechte
action admin de Aktion action admin de Befehl
actions admin de Aktionen actions admin de Befehle
activate wysiwyg-editor admin de WYSIWYG Editor (formatierter Text) aktivieren activate wysiwyg-editor admin de WYSIWYG Editor (formatierter Text) aktivieren
add a category admin de Eine Kategorie hinzufügen add a category admin de Eine Kategorie hinzufügen
add a group admin de Eine Gruppe hinzufügen add a group admin de Eine Gruppe hinzufügen
@ -160,6 +161,7 @@ delete peer server admin de Server von Serververbund löschen
delete selected entries admin de Ausgewählte Einträge löschen delete selected entries admin de Ausgewählte Einträge löschen
delete the category admin de Kategorie löschen delete the category admin de Kategorie löschen
delete the group admin de Gruppe löschen delete the group admin de Gruppe löschen
delete the selected entries admin de Die ausgewählten Einträge löschen
delete this category admin de Kategorie löschen delete this category admin de Kategorie löschen
delete this group admin de Gruppe löschen delete this group admin de Gruppe löschen
delete this log entry admin de Diesen Protokolleintrag löschen delete this log entry admin de Diesen Protokolleintrag löschen
@ -330,6 +332,7 @@ kill admin de Beenden
kill session admin de Sitzung beenden kill session admin de Sitzung beenden
last %1 logins admin de Letze %1 Logins last %1 logins admin de Letze %1 Logins
last %1 logins for %2 admin de Letze %1 Logins für %2 last %1 logins for %2 admin de Letze %1 Logins für %2
last action admin de Letzte Aktion
last login admin de Letzter Login last login admin de Letzter Login
last login from admin de Letzer Login von last login from admin de Letzer Login von
last submission: admin de Letzte Absendung: last submission: admin de Letzte Absendung:

View File

@ -7,6 +7,7 @@
%1 log entries deleted. admin en %1 log entries deleted. %1 log entries deleted. admin en %1 log entries deleted.
%1 not found or not executable !!! admin en %1 not found or not executable !!! %1 not found or not executable !!! admin en %1 not found or not executable !!!
%1 rights for %2 and applications %3 admin en %1 rights for %2 and applications %3 %1 rights for %2 and applications %3 admin en %1 rights for %2 and applications %3
%1 sessions killed admin en %1 sessions killed
%1 user %2 admin en %1 user %2 %1 user %2 admin en %1 user %2
(default no, leave it off if you dont use it) admin en (default No, leave it off if you dont use it) (default no, leave it off if you dont use it) admin en (default No, leave it off if you dont use it)
(stored password will not be shown here) admin en (Stored password will not be shown here) (stored password will not be shown here) admin en (Stored password will not be shown here)
@ -160,6 +161,7 @@ delete peer server admin en Delete peer server
delete selected entries admin en Delete selected entries delete selected entries admin en Delete selected entries
delete the category admin en delete the category delete the category admin en delete the category
delete the group admin en delete the group delete the group admin en delete the group
delete the selected entries admin en Delete the selected entries
delete this category admin en delete this category delete this category admin en delete this category
delete this group admin en delete this group delete this group admin en delete this group
delete this log entry admin en Delete this log entry delete this log entry admin en Delete this log entry
@ -330,6 +332,7 @@ kill admin en Kill
kill session admin en Kill session kill session admin en Kill session
last %1 logins admin en Last %1 logins last %1 logins admin en Last %1 logins
last %1 logins for %2 admin en Last %1 logins for %2 last %1 logins for %2 admin en Last %1 logins for %2
last action admin en Last action
last login admin en last login last login admin en last login
last login from admin en last login from last login from admin en last login from
last submission: admin en Last submission: last submission: admin en Last submission:

View File

@ -2,7 +2,7 @@
/** /**
* eGroupWare - eTemplates for Application admin * eGroupWare - eTemplates for Application admin
* http://www.egroupware.org * http://www.egroupware.org
* generated by soetemplate::dump4setup() 2011-04-12 09:22 * generated by soetemplate::dump4setup() 2011-04-13 15:34
* *
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package admin * @package admin
@ -12,11 +12,11 @@
$templ_version=1; $templ_version=1;
$templ_data[] = array('name' => 'admin.accesslog','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:1:{s:2:"h1";s:6:",!@msg";}i:1;a:2:{s:1:"A";a:4:{s:4:"type";s:5:"label";s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:4:{s:4:"type";s:9:"nextmatch";s:4:"size";s:4:"rows";s:4:"name";s:2:"nm";s:4:"span";s:3:"all";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:3:{s:4:"type";s:5:"label";s:5:"label";s:32:"Percent of users that logged out";s:8:"readonly";s:1:"1";}i:2;a:5:{s:4:"type";s:5:"float";s:4:"name";s:7:"percent";s:4:"size";s:4:",,,1";s:5:"label";s:6:": %s %";s:8:"readonly";s:1:"1";}}s:1:"B";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";s:5:"align";s:5:"right";i:1;a:6:{s:4:"type";s:6:"button";s:4:"name";s:6:"delete";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"help";s:23:"Delete selected entries";s:7:"onclick";s:46:"return confirm(\'Delete the selected entries\');";}i:2;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:9:"arrow_ltr";s:7:"onclick";s:71:"toggle_all(this.form,form::name(\'nm[rows][selected][]\')); return false;";s:4:"span";s:15:",selectAllArrow";}}}}s:4:"rows";i:3;s:4:"cols";i:2;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '.selectAllArrow { padding-right: 12px; }','modified' => '1240661952',); $templ_data[] = array('name' => 'admin.accesslog','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:4:{i:0;a:1:{s:2:"h1";s:6:",!@msg";}i:1;a:2:{s:1:"A";a:4:{s:4:"span";s:13:"all,redItalic";s:5:"align";s:6:"center";s:4:"name";s:3:"msg";s:4:"type";s:5:"label";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:2;a:2:{s:1:"A";a:4:{s:4:"span";s:3:"all";s:4:"name";s:2:"nm";s:4:"size";s:20:"admin.accesslog.rows";s:4:"type";s:9:"nextmatch";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}i:3;a:2:{s:1:"A";a:4:{s:4:"size";s:6:"2,,0,0";s:4:"type";s:4:"hbox";i:1;a:3:{s:8:"readonly";s:4:"true";s:4:"type";s:5:"label";s:5:"label";s:32:"Percent of users that logged out";}i:2;a:6:{s:4:"type";s:5:"float";s:9:"precision";s:1:"1";s:5:"label";s:6:": %s %";s:8:"readonly";s:4:"true";s:4:"name";s:7:"percent";s:4:"size";s:1:",";}}s:1:"B";a:6:{s:5:"align";s:5:"right";s:4:"type";s:4:"hbox";i:1;a:6:{s:5:"label";s:6:"Delete";s:7:"onclick";s:46:"return confirm(\'Delete the selected entries\');";s:4:"name";s:6:"delete";s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:4:"help";s:23:"Delete selected entries";}i:2;a:5:{s:4:"type";s:6:"button";s:4:"size";s:5:"close";s:5:"label";s:4:"Kill";s:4:"name";s:4:"kill";s:7:"onclick";s:63:"return confirm(\'Are you sure you want to kill this session ?\');";}s:4:"size";s:1:"3";i:3;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:9:"arrow_ltr";s:5:"label";s:10:"Select all";s:7:"onclick";s:61:"toggle_all(this.form,form::name(\'selected[]\')); return false;";}}}}s:4:"cols";i:2;s:4:"rows";i:3;s:4:"size";s:4:"100%";}}','size' => '100%','style' => '.selectAllArrow { padding-right: 12px; }','modified' => '1302686599',);
$templ_data[] = array('name' => 'admin.accesslog.get_rows','template' => '','lang' => '','group' => '0','version' => '1.3.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";}i:1;a:4:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:7:"LoginID";s:4:"name";s:7:"loginid";}s:1:"B";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logintime";s:4:"name";s:2:"li";}s:1:"D";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logoutime";s:4:"name";s:2:"lo";}}i:2;a:4:{s:1:"A";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:15:"${row}[loginid]";s:8:"readonly";s:1:"1";}s:1:"B";a:3:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";s:7:"no_lang";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}}}s:4:"rows";i:2;s:4:"cols";i:4;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1164479930',); $templ_data[] = array('name' => 'admin.accesslog.get_rows','template' => '','lang' => '','group' => '0','version' => '1.3.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";}i:1;a:4:{s:1:"A";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:7:"LoginID";s:4:"name";s:7:"loginid";}s:1:"B";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"C";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logintime";s:4:"name";s:2:"li";}s:1:"D";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:9:"Logoutime";s:4:"name";s:2:"lo";}}i:2;a:4:{s:1:"A";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:15:"${row}[loginid]";s:8:"readonly";s:1:"1";}s:1:"B";a:3:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";s:7:"no_lang";s:1:"1";}s:1:"C";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"D";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}}}s:4:"rows";i:2;s:4:"cols";i:4;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1164479930',);
$templ_data[] = array('name' => 'admin.accesslog.rows','template' => '','lang' => '','group' => '0','version' => '1.7.002','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:3:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:1:"H";s:2:"1%";}i:1;a:8:{s:1:"A";a:3:{s:4:"type";s:23:"nextmatch-accountfilter";s:4:"size";s:7:"LoginID";s:4:"name";s:10:"account_id";}s:1:"B";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:12:"Login-Status";s:4:"name";s:13:"sessionstatus";}s:1:"C";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:7:"Loginid";s:4:"name";s:7:"loginid";}s:1:"D";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"E";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Login";s:4:"name";s:2:"li";}s:1:"F";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:6:"Logout";s:4:"name";s:2:"lo";}s:1:"G";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Total";s:4:"name";s:5:"total";}s:1:"H";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"label";s:5:"label";s:6:"Action";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:10:"Select all";s:7:"onclick";s:61:"toggle_all(this.form,form::name(\'selected[]\')); return false;";}}}i:2;a:8:{s:1:"A";a:3:{s:4:"type";s:14:"select-account";s:4:"name";s:18:"${row}[account_id]";s:8:"readonly";s:1:"1";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:21:"${row}[sessionstatus]";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:4:"name";s:15:"${row}[loginid]";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";}s:1:"E";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"F";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}s:1:"G";a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:13:"${row}[total]";s:8:"readonly";s:1:"1";s:4:"size";s:6:",hm,24";}s:1:"H";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"2,,0,0";i:1;a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:28:"delete[$row_cont[sessionid]]";s:4:"help";s:21:"Delete this log entry";s:7:"onclick";s:40:"return confirm(\'Delete this log entry\');";}i:2;a:3:{s:4:"type";s:8:"checkbox";s:4:"size";s:20:"$row_cont[sessionid]";s:4:"name";s:10:"selected[]";}s:5:"align";s:6:"center";}}}s:4:"rows";i:2;s:4:"cols";i:8;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1254816462',); $templ_data[] = array('name' => 'admin.accesslog.rows','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:6:{s:2:"c1";s:2:"th";s:2:"c2";s:3:"row";s:1:"G";s:10:",@no_total";s:1:"F";s:7:",@no_lo";s:1:"B";s:18:",@no_sessionstatus";s:1:"J";s:2:"1%";}i:1;a:10:{s:1:"A";a:3:{s:4:"type";s:23:"nextmatch-accountfilter";s:4:"size";s:7:"LoginID";s:4:"name";s:10:"account_id";}s:1:"B";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:12:"Login-Status";s:4:"name";s:13:"sessionstatus";}s:1:"C";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:7:"Loginid";s:4:"name";s:7:"loginid";}s:1:"D";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:2:"IP";s:4:"name";s:2:"ip";}s:1:"E";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:5:"Login";s:4:"name";s:2:"li";}s:1:"F";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:6:"Logout";s:4:"name";s:2:"lo";}s:1:"G";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:5:"Total";s:4:"name";s:5:"total";}s:1:"H";a:3:{s:4:"type";s:20:"nextmatch-sortheader";s:5:"label";s:4:"Idle";s:4:"name";s:11:"session_dla";}s:1:"I";a:3:{s:4:"type";s:16:"nextmatch-header";s:5:"label";s:11:"Last action";s:4:"name";s:14:"session_action";}s:1:"J";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:5:"label";s:5:"label";s:7:"Actions";s:5:"align";s:6:"center";}i:2;a:4:{s:4:"type";s:10:"buttononly";s:4:"size";s:5:"check";s:5:"label";s:10:"Select all";s:7:"onclick";s:61:"toggle_all(this.form,form::name(\'selected[]\')); return false;";}}}i:2;a:10:{s:1:"A";a:4:{s:4:"type";s:14:"select-account";s:4:"name";s:18:"${row}[account_id]";s:8:"readonly";s:1:"1";s:5:"label";s:22:"$row_cont[alt_loginid]";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:4:"name";s:21:"${row}[sessionstatus]";}s:1:"C";a:2:{s:4:"type";s:5:"label";s:4:"name";s:15:"${row}[loginid]";}s:1:"D";a:2:{s:4:"type";s:5:"label";s:4:"name";s:10:"${row}[ip]";}s:1:"E";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[li]";s:8:"readonly";s:1:"1";}s:1:"F";a:3:{s:4:"type";s:9:"date-time";s:4:"name";s:10:"${row}[lo]";s:8:"readonly";s:1:"1";}s:1:"G";a:4:{s:4:"type";s:13:"date-duration";s:4:"name";s:13:"${row}[total]";s:8:"readonly";s:1:"1";s:4:"size";s:6:",hm,24";}s:1:"H";a:3:{s:4:"type";s:10:"date-since";s:4:"name";s:19:"${row}[session_dla]";s:8:"readonly";s:1:"1";}s:1:"I";a:2:{s:4:"type";s:5:"label";s:4:"name";s:22:"${row}[session_action]";}s:1:"J";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:6:"3,,0,0";i:1;a:6:{s:4:"type";s:6:"button";s:4:"size";s:6:"delete";s:5:"label";s:6:"Delete";s:4:"name";s:28:"delete[$row_cont[sessionid]]";s:4:"help";s:21:"Delete this log entry";s:7:"onclick";s:40:"return confirm(\'Delete this log entry\');";}i:2;a:5:{s:4:"type";s:6:"button";s:4:"size";s:5:"close";s:5:"label";s:4:"Kill";s:4:"name";s:26:"kill[$row_cont[sessionid]]";s:7:"onclick";s:63:"return confirm(\'Are you sure you want to kill this session ?\');";}s:5:"align";s:6:"center";i:3;a:4:{s:4:"type";s:8:"checkbox";s:4:"size";s:20:"$row_cont[sessionid]";s:4:"name";s:10:"selected[]";s:5:"align";s:5:"right";}}}}s:4:"rows";i:2;s:4:"cols";i:10;s:4:"size";s:4:"100%";s:7:"options";a:1:{i:0;s:4:"100%";}}}','size' => '100%','style' => '','modified' => '1254816462',);
$templ_data[] = array('name' => 'admin.applications','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:9:"nextmatch";s:4:"size";s:4:"rows";s:4:"span";s:3:"all";s:4:"name";s:2:"nm";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:28:"Number applications serially";s:4:"name";s:6:"number";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:157:"Number the applications serially. If they are not numbered serially, sorting the applications could work wrong. This will not change the application\'s order.";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:7:"100%,,0";s:7:"options";a:2:{i:0;s:4:"100%";i:2;s:1:"0";}}}','size' => '100%,,0','style' => '','modified' => '1276610727',); $templ_data[] = array('name' => 'admin.applications','template' => '','lang' => '','group' => '0','version' => '1.7.001','data' => 'a:1:{i:0;a:6:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:4:{s:4:"type";s:9:"nextmatch";s:4:"size";s:4:"rows";s:4:"span";s:3:"all";s:4:"name";s:2:"nm";}}i:2;a:1:{s:1:"A";a:4:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";i:1;a:3:{s:4:"type";s:6:"button";s:5:"label";s:28:"Number applications serially";s:4:"name";s:6:"number";}i:2;a:2:{s:4:"type";s:5:"label";s:5:"label";s:157:"Number the applications serially. If they are not numbered serially, sorting the applications could work wrong. This will not change the application\'s order.";}}}}s:4:"rows";i:2;s:4:"cols";i:1;s:4:"size";s:7:"100%,,0";s:7:"options";a:2:{i:0;s:4:"100%";i:2;s:1:"0";}}}','size' => '100%,,0','style' => '','modified' => '1276610727',);

View File

@ -1,45 +1,58 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<!-- $Id$ --> <!-- $Id$ -->
<overlay> <overlay>
<template id="admin.accesslog.rows" template="" lang="" group="0" version="1.7.001"> <template id="admin.accesslog.rows" template="" lang="" group="0" version="1.9.001">
<grid width="100%"> <grid width="100%">
<columns> <columns>
<column/> <column/>
<column disabled="@no_sessionstatus"/>
<column/> <column/>
<column/> <column/>
<column/> <column/>
<column disabled="@no_lo"/>
<column disabled="@no_total"/>
<column/>
<column/> <column/>
<column width="1%"/> <column width="1%"/>
</columns> </columns>
<rows> <rows>
<row class="th"> <row class="th">
<nextmatch-accountfilter options="LoginID" id="account_id"/> <nextmatch-accountfilter options="LoginID" id="account_id"/>
<nextmatch-header label="Login-Status" id="sessionstatus"/>
<nextmatch-header label="Loginid" id="loginid"/>
<nextmatch-header label="IP" id="ip"/> <nextmatch-header label="IP" id="ip"/>
<nextmatch-sortheader label="Login" id="li"/> <nextmatch-sortheader label="Login" id="li"/>
<nextmatch-sortheader label="Logout" id="lo"/> <nextmatch-sortheader label="Logout" id="lo"/>
<nextmatch-header label="Total" id="total"/> <nextmatch-header label="Total" id="total"/>
<nextmatch-sortheader label="Idle" id="session_dla"/>
<nextmatch-header label="Last action" id="session_action"/>
<hbox> <hbox>
<description value="Action" align="center"/> <description value="Actions" align="center"/>
<buttononly options="check" label="Select all" onclick="toggle_all(this.form,form::name('selected[]')); return false;"/> <buttononly options="check" label="Select all" onclick="toggle_all(this.form,form::name('selected[]')); return false;"/>
</hbox> </hbox>
</row> </row>
<row class="row"> <row class="row">
<menulist> <menulist>
<menupopup type="select-account" id="${row}[account_id]" readonly="true"/> <menupopup type="select-account" id="${row}[account_id]" readonly="true" label="$row_cont[alt_loginid]"/>
</menulist> </menulist>
<description id="${row}[sessionstatus]"/>
<description id="${row}[loginid]"/>
<description id="${row}[ip]"/> <description id="${row}[ip]"/>
<date-time id="${row}[li]" readonly="true"/> <date-time id="${row}[li]" readonly="true"/>
<date-time id="${row}[lo]" readonly="true"/> <date-time id="${row}[lo]" readonly="true"/>
<date-duration id="${row}[total]" readonly="true" options=",hm,24"/> <date-duration id="${row}[total]" readonly="true" options=",hm,24"/>
<date-since id="${row}[session_dla]" readonly="true"/>
<description id="${row}[session_action]"/>
<hbox options="0,0" align="center"> <hbox options="0,0" align="center">
<button image="delete" label="Delete" id="delete[$row_cont[sessionid]]" statustext="Delete this log entry" onclick="return confirm('Delete this log entry');"/> <button image="delete" label="Delete" id="delete[$row_cont[sessionid]]" statustext="Delete this log entry" onclick="return confirm('Delete this log entry');"/>
<checkbox options="$row_cont[sessionid]" id="selected[]"/> <button image="close" label="Kill" id="kill[$row_cont[sessionid]]" onclick="return confirm('Are you sure you want to kill this session ?');"/>
<checkbox options="$row_cont[sessionid]" id="selected[]" align="right"/>
</hbox> </hbox>
</row> </row>
</rows> </rows>
</grid> </grid>
</template> </template>
<template id="admin.accesslog" template="" lang="" group="0" version="1.7.001"> <template id="admin.accesslog" template="" lang="" group="0" version="1.9.001">
<grid width="100%"> <grid width="100%">
<columns> <columns>
<column/> <column/>
@ -51,16 +64,17 @@
<description/> <description/>
</row> </row>
<row> <row>
<nextmatch options="admin.accesslog.rows" id="nm" span="all"/> <nextmatch span="all" id="nm" options="admin.accesslog.rows"/>
</row> </row>
<row> <row>
<hbox options="0,0"> <hbox options="0,0">
<description value="Percent of users that logged out" readonly="true"/> <description readonly="true" value="Percent of users that logged out"/>
<textbox type="float" id="percent" precision="1" label=": %s %" readonly="true"/> <textbox type="float" precision="1" label=": %s %" readonly="true" id="percent"/>
</hbox> </hbox>
<hbox align="right"> <hbox align="right">
<button id="delete" image="delete" label="Delete" statustext="Delete selected entries" onclick="return confirm('Delete the selected entries');"/> <button label="Delete" onclick="return confirm('Delete the selected entries');" id="delete" image="delete" statustext="Delete selected entries"/>
<buttononly options="arrow_ltr" onclick="toggle_all(this.form,form::name('nm[rows][selected][]')); return false;" class="selectAllArrow"/> <button image="close" label="Kill" id="kill" onclick="return confirm('Are you sure you want to kill this session ?');"/>
<buttononly options="arrow_ltr" label="Select all" onclick="toggle_all(this.form,form::name('selected[]')); return false;"/>
</hbox> </hbox>
</row> </row>
</rows> </rows>

View File

@ -1,38 +0,0 @@
<!-- BEGIN list -->
<br>
<table border="0" width="95%" align="center">
<tr>
{left_next_matchs}
<td align="center">{start_total}</td>
{right_next_matchs}
</tr>
</td>
<table border="0" width="95%" align="center" class="egwGridView_grid">
<tr class="th">
<td>{sort_loginid}</td>
<td>{sort_ip}</td>
<td>{sort_login_time}</td>
<td>{sort_action}</td>
<td>{sort_idle}</td>
<td>{lang_kill}</td>
</tr>
{rows}
</table>
<br>
<!-- END list -->
<!-- BEGIN row -->
<tr bgcolor="{tr_color}">
<td>{row_loginid}</td>
<td>{row_ip}</td>
<td>{row_logintime}</td>
<td>{row_action}</td>
<td>{row_idle}</td>
<td>{row_kill}</td>
</tr>
<!-- END row -->

View File

@ -439,7 +439,7 @@ abstract class egw_framework
{ {
if( $GLOBALS['egw_info']['user']['apps']['admin'] && $GLOBALS['egw_info']['user']['preferences']['common']['show_currentusers']) if( $GLOBALS['egw_info']['user']['apps']['admin'] && $GLOBALS['egw_info']['user']['preferences']['common']['show_currentusers'])
{ {
$current_users = '<a href="' . egw::link('/index.php','menuaction=admin.uicurrentsessions.list_sessions') . '">' . $current_users = '<a href="' . egw::link('/index.php','menuaction=admin.admin_accesslog.sessions') . '">' .
lang('Current users') . ': ' . $GLOBALS['egw']->session->session_count() . '</a>'; lang('Current users') . ': ' . $GLOBALS['egw']->session->session_count() . '</a>';
return $current_users; return $current_users;
} }

View File

@ -132,6 +132,13 @@ class egw_session
*/ */
var $kp3; var $kp3;
/**
* Primary key of egw_access_log row for updates
*
* @var int
*/
var $sessionid_access_log;
/** /**
* name of XML-RPC/SOAP method called * name of XML-RPC/SOAP method called
* *
@ -579,7 +586,7 @@ class egw_session
$this->register_session($this->login,$user_ip,$now,$this->session_flags); $this->register_session($this->login,$user_ip,$now,$this->session_flags);
if ($this->session_flags != 'A') // dont log anonymous sessions if ($this->session_flags != 'A') // dont log anonymous sessions
{ {
$this->log_access($this->sessionid,$login,$user_ip,$this->account_id); $this->sessionid_access_log = $this->log_access($this->sessionid,$login,$user_ip,$this->account_id);
} }
self::appsession('account_previous_login','phpgwapi',$GLOBALS['egw']->auth->previous_login); self::appsession('account_previous_login','phpgwapi',$GLOBALS['egw']->auth->previous_login);
$GLOBALS['egw']->accounts->update_lastlogin($this->account_id,$user_ip); $GLOBALS['egw']->accounts->update_lastlogin($this->account_id,$user_ip);
@ -640,10 +647,11 @@ class egw_session
/** /**
* Write or update (for logout) the access_log * Write or update (for logout) the access_log
* *
* @param string $sessionid id of session or 0 for unsuccessful logins * @param string|int $sessionid PHP sessionid or 0 for unsuccessful logins
* @param string $login account_lid (evtl. with domain) or '' for settion the logout-time * @param string $login account_lid (evtl. with domain) or '' for settion the logout-time
* @param string $user_ip ip to log * @param string $user_ip ip to log
* @param int $account_id numerical account_id * @param int $account_id numerical account_id
* @return int $sessionid primary key of egw_access_log for login, null otherwise
*/ */
private function log_access($sessionid,$login='',$user_ip='',$account_id='') private function log_access($sessionid,$login='',$user_ip='',$account_id='')
{ {
@ -652,17 +660,24 @@ class egw_session
if ($login) if ($login)
{ {
$GLOBALS['egw']->db->insert(self::ACCESS_LOG_TABLE,array( $GLOBALS['egw']->db->insert(self::ACCESS_LOG_TABLE,array(
'sessionid' => $sessionid, 'session_php' => $sessionid,
'loginid' => $login, 'loginid' => $login,
'ip' => $user_ip, 'ip' => $user_ip,
'li' => $now, 'li' => $now,
'lo' => 0,
'account_id'=> $account_id, 'account_id'=> $account_id,
),false,__LINE__,__FILE__); ),false,__LINE__,__FILE__);
$ret = $GLOBALS['egw']->db->get_last_insert_id(self::ACCESS_LOG_TABLE,'sessionid');
} }
else else
{ {
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array('lo' => $now),array('sessionid' => $sessionid),__LINE__,__FILE__); $GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
'lo' => $now
),is_numeric($sessionid) ? array(
'sessionid' => $sessionid,
) : array(
'session_php' => $sessionid,
),__LINE__,__FILE__);
} }
if ($GLOBALS['egw_info']['server']['max_access_log_age']) if ($GLOBALS['egw_info']['server']['max_access_log_age'])
{ {
@ -670,6 +685,8 @@ class egw_session
$GLOBALS['egw']->db->delete(self::ACCESS_LOG_TABLE,"li < $max_age",__LINE__,__FILE__); $GLOBALS['egw']->db->delete(self::ACCESS_LOG_TABLE,"li < $max_age",__LINE__,__FILE__);
} }
//error_log(__METHOD__."('$sessionid', '$login', '$user_ip', $account_id) returning ".array2string($ret));
return $ret;
} }
/** /**
@ -861,6 +878,10 @@ class egw_session
{ {
$this->update_dla(); $this->update_dla();
} }
elseif ($GLOBALS['egw_info']['flags']['currentapp'] == 'notifications')
{
$this->update_notification_heartbeat();
}
$this->account_id = $GLOBALS['egw']->accounts->name2id($this->account_lid,'account_lid','u'); $this->account_id = $GLOBALS['egw']->accounts->name2id($this->account_lid,'account_lid','u');
if (!$this->account_id) if (!$this->account_id)
{ {
@ -959,6 +980,15 @@ class egw_session
//echo 'DEBUG: Sessions: account_id is empty!<br>'."\n"; //echo 'DEBUG: Sessions: account_id is empty!<br>'."\n";
return false; return false;
} }
// query accesslog-id, if not set in session (session is made persistent after login!)
if (!$this->sessionid_access_log)
{
$this->sessionid_access_log = $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE,'sessionid',array(
'session_php' => $this->sessionid,
),__LINE__,__FILE__)->fetchColumn();
//error_log(__METHOD__."() sessionid=$this->sessionid --> sessionid_access_log=$this->sessionid_access_log");
}
if (self::ERROR_LOG_DEBUG) error_log("--> session::verify($sessionid) SUCCESS"); if (self::ERROR_LOG_DEBUG) error_log("--> session::verify($sessionid) SUCCESS");
return true; return true;
@ -971,16 +1001,23 @@ class egw_session
* @param string $kp3 * @param string $kp3
* @return boolean true on success, false on error * @return boolean true on success, false on error
*/ */
function destroy($sessionid, $kp3) function destroy($sessionid, $kp3='')
{ {
if (!$sessionid && $kp3) if (!$sessionid && $kp3)
{ {
return false; return false;
} }
$this->log_access($this->sessionid); // log logout-time $this->log_access($sessionid); // log logout-time
if (self::ERROR_LOG_DEBUG) error_log(__METHOD__."($sessionid,$kp3) parent::destroy()=$ret"); if (self::ERROR_LOG_DEBUG) error_log(__METHOD__."($sessionid,$kp3) parent::destroy()=$ret");
if (is_numeric($sessionid)) // do we have a access-log-id --> get PHP session id
{
$sessionid = $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE,'session_php',array(
'sessionid' => $sessionid,
),__LINE__,__FILE__)->fetchColumn();
}
$GLOBALS['egw']->hooks->process(array( $GLOBALS['egw']->hooks->process(array(
'location' => 'session_destroyed', 'location' => 'session_destroyed',
'sessionid' => $sessionid, 'sessionid' => $sessionid,
@ -1006,12 +1043,12 @@ class egw_session
} }
else else
{ {
$sessions = self::session_list(0,'','',true); $this->commit_session(); // close our own session
if (isset($sessions[$sessionid]) && session_module_name() == 'files') session_id($sessionid);
if (session_start())
{ {
//echo '<p>'.__METHOD__."($session_id): unlink('".$sessions[$sessionid]['php_session_file']."')</p>\n"; session_destroy();
@unlink($sessions[$sessionid]['php_session_file']);
} }
} }
return true; return true;
@ -1318,24 +1355,41 @@ class egw_session
} }
/** /**
* Update session_action and session_dla (session last used time), * Update session_action and session_dla (session last used time)
*/ */
private function update_dla() private function update_dla()
{ {
if (isset($_GET['menuaction'])) // This way XML-RPC users aren't always listed as xmlrpc.php
if ($this->xmlrpc_method_called)
{
$action = $this->xmlrpc_method_called;
}
elseif (isset($_GET['menuaction']))
{ {
$action = $_GET['menuaction']; $action = $_GET['menuaction'];
} }
else else
{ {
$action = $_SERVER['PHP_SELF']; $action = $_SERVER['PHP_SELF'];
// remove EGroupware path, if not installed in webroot
$egw_path = $GLOBALS['egw_info']['server']['webserver_url'];
if ($egw_path[0] != '/') $egw_path = parse_url($egw_path,PHP_URL_PATH);
if ($egw_path)
{
list(,$action) = explode($egw_path,$action,2);
}
} }
// This way XML-RPC users aren't always listed as // update dla in access-log table, if we have an access-log row (non-anonymous session)
// xmlrpc.php if ($this->sessionid_access_log)
if ($this->xmlrpc_method_called)
{ {
$action = $this->xmlrpc_method_called; $GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
'session_dla' => time(),
'session_action' => $action,
'lo' => null, // just in case it was (automatic) timed out before
),array(
'sessionid' => $this->sessionid_access_log,
),__LINE__,__FILE__);
} }
$_SESSION[self::EGW_SESSION_VAR]['session_dla'] = time(); $_SESSION[self::EGW_SESSION_VAR]['session_dla'] = time();
@ -1343,6 +1397,23 @@ class egw_session
if (self::ERROR_LOG_DEBUG) error_log(__METHOD__.'() _SESSION['.self::EGW_SESSION_VAR.']='.array2string($_SESSION[self::EGW_SESSION_VAR])); if (self::ERROR_LOG_DEBUG) error_log(__METHOD__.'() _SESSION['.self::EGW_SESSION_VAR.']='.array2string($_SESSION[self::EGW_SESSION_VAR]));
} }
/**
* Update notification_heartbeat time of session
*/
private function update_notification_heartbeat()
{
// update dla in access-log table, if we have an access-log row (non-anonymous session)
if ($this->sessionid_access_log)
{
$GLOBALS['egw']->db->update(self::ACCESS_LOG_TABLE,array(
'notification_heartbeat' => time(),
),array(
'sessionid' => $this->sessionid_access_log,
'lo IS NULL',
),__LINE__,__FILE__);
}
}
/** /**
* Read the diverse repositories / init classes with data from the just loged in user * Read the diverse repositories / init classes with data from the just loged in user
* *
@ -1471,32 +1542,80 @@ class egw_session
* Get a session list (of the current instance) * Get a session list (of the current instance)
* *
* @param int $start * @param int $start
* @param string $sort='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla * @param string $sort='DESC' ASC or DESC
* @param string $order='DESC' ASC or DESC * @param string $order='session_dla' session_lid, session_id, session_started, session_logintime, session_action, or (default) session_dla
* @param boolean $all_no_sort=False skip sorting and limiting to maxmatchs if set to true * @param boolean $all_no_sort=False skip sorting and limiting to maxmatchs if set to true
* @return array with sessions (values for keys as in $sort) or array() if not supported by session-handler * @return array with sessions (values for keys as in $sort)
*/ */
public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort=False) public static function session_list($start,$sort='DESC',$order='session_dla',$all_no_sort=False)
{ {
if (method_exists(self::$session_handler,'session_list')) $sessions = array();
if (!preg_match('/^[a-z0-9_ ,]+$/i',$order_by=$order.' '.$sort))
{ {
return call_user_func(array(self::$session_handler,'session_list'),$start,$sort,$order,$all_no_sort); $order_by = 'session_dla DESC';
} }
return array(); foreach($GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, '*', array(
'lo' => null,
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
'(notification_heartbeat IS NULL OR notification_heartbeat > '.self::heartbeat_limit().')',
), __LINE__, __FILE__, $all_no_sort ? false : $start, 'ORDER BY '.$order_by) as $row)
{
$sessions[$row['sessionid']] = $row;
}
return $sessions;
} }
/** /**
* Query number of sessions (not more then once every N secs) * Query number of sessions (not more then once every N secs)
* *
* @return int|boolean integer number of sessions or false if not supported by session-handler * @return int number of active sessions
*/ */
public static function session_count() public static function session_count()
{ {
if (method_exists(self::$session_handler,'session_count')) return $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, 'COUNT(*)', array(
'lo' => null,
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
'(notification_heartbeat IS NULL OR notification_heartbeat > '.self::heartbeat_limit().')',
), __LINE__, __FILE__)->fetchColumn();
}
/**
* Get limit / latest time of heartbeat for session to be active
*
* @return int TS in server-time
*/
public static function heartbeat_limit()
{
static $limit;
if (is_null($limit))
{ {
return call_user_func(array(self::$session_handler,'session_count')); $config = config::read('notifications');
if (!($popup_poll_interval = $config['popup_poll_interval']))
{
$popup_poll_interval = 60;
}
$limit = (int)(time() - $popup_poll_interval-10); // 10s grace periode
} }
return false; return $limit;
}
/**
* Check if given user can be reached via notifications
*
* Checks if notifications callback checked in not more then heartbeat_limit() seconds ago
*
* @param int $account_id
* @param int number of active sessions of given user with notifications running
*/
public static function notifications_active($account_id)
{
return $GLOBALS['egw']->db->select(self::ACCESS_LOG_TABLE, 'COUNT(*)', array(
'lo' => null,
'session_dla > '.(int)(time() - $GLOBALS['egw_info']['server']['sessions_timeout']),
'account_id' => $account_id,
'notifications_heartbeat > '.self::heartbeat_limit(),
), __LINE__, __FILE__)->fetchColumn();
} }
/* /*

View File

@ -616,7 +616,23 @@ class schema_proc
$blob_column_included = $auto_column_included = False; $blob_column_included = $auto_column_included = False;
foreach($aTableDef['fd'] as $name => $data) foreach($aTableDef['fd'] as $name => $data)
{ {
if ($aDefaults && isset($aDefaults[$name])) // use given default // new auto column with no default or explicit NULL as default (can be an existing column too!)
if ($data['type'] == 'auto' &&
(!isset($old_table_def['fd'][$name]) && (!$aDefaults || !isset($aDefaults[$name])) ||
$aDefaults && strtoupper($aDefaults[$name]) == 'NULL'))
{
$sequence_name = $sTableName.'_'.$name.'_seq';
switch($GLOBALS['egw_setup']->db->Type)
{
case 'mysql':
$value = 'NULL'; break;
case 'pgsql':
$value = "nextval('$sequence_name'::regclass)"; break;
default:
$value = "nextval('$sequence_name')"; break;
}
}
elseif ($aDefaults && isset($aDefaults[$name])) // use given default
{ {
$value = $aDefaults[$name]; $value = $aDefaults[$name];
} }
@ -690,10 +706,11 @@ class schema_proc
$Ok = $this->RenameTable($sTableName,$tmp_name); $Ok = $this->RenameTable($sTableName,$tmp_name);
} }
$Ok = $Ok && $this->CreateTable($sTableName,$aTableDef) && $Ok = $Ok && $this->CreateTable($sTableName,$aTableDef) &&
$this->m_odb->query("$extra INSERT INTO $sTableName (". $this->m_odb->query($sql_copy_data="$extra INSERT INTO $sTableName (".
implode(',',array_keys($aTableDef['fd'])). implode(',',array_keys($aTableDef['fd'])).
") SELEcT $distinct $select FROM $tmp_name",__LINE__,__FILE__) && ") SELEcT $distinct $select FROM $tmp_name",__LINE__,__FILE__) &&
$this->DropTable($tmp_name); $this->DropTable($tmp_name);
//error_log($sql_copy_data);
if (!$Ok) if (!$Ok)
{ {

View File

@ -12,7 +12,7 @@
/* Basic information about this app */ /* Basic information about this app */
$setup_info['phpgwapi']['name'] = 'phpgwapi'; $setup_info['phpgwapi']['name'] = 'phpgwapi';
$setup_info['phpgwapi']['title'] = 'eGroupWare API'; $setup_info['phpgwapi']['title'] = 'eGroupWare API';
$setup_info['phpgwapi']['version'] = '1.9.007'; $setup_info['phpgwapi']['version'] = '1.9.008';
$setup_info['phpgwapi']['versions']['current_header'] = '1.29'; $setup_info['phpgwapi']['versions']['current_header'] = '1.29';
$setup_info['phpgwapi']['enable'] = 3; $setup_info['phpgwapi']['enable'] = 3;
$setup_info['phpgwapi']['app_order'] = 1; $setup_info['phpgwapi']['app_order'] = 1;
@ -74,3 +74,4 @@ $setup_info['groupdav']['author'] = $setup_info['groupdav']['maintainer'] = arra
$setup_info['groupdav']['license'] = 'GPL'; $setup_info['groupdav']['license'] = 'GPL';
$setup_info['groupdav']['hooks']['preferences'] = 'groupdav_hooks::menus'; $setup_info['groupdav']['hooks']['preferences'] = 'groupdav_hooks::menus';
$setup_info['groupdav']['hooks']['settings'] = 'groupdav_hooks::settings'; $setup_info['groupdav']['hooks']['settings'] = 'groupdav_hooks::settings';

View File

@ -83,16 +83,20 @@ $phpgw_baseline = array(
), ),
'egw_access_log' => array( 'egw_access_log' => array(
'fd' => array( 'fd' => array(
'sessionid' => array('type' => 'char','precision' => '128','nullable' => False), 'sessionid' => array('type' => 'auto','nullable' => False,'comment' => 'primary key'),
'loginid' => array('type' => 'varchar','precision' => '64','nullable' => False), 'loginid' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'username used to login'),
'ip' => array('type' => 'varchar','precision' => '40','nullable' => False), 'ip' => array('type' => 'varchar','precision' => '40','nullable' => False,'comment' => 'ip of user'),
'li' => array('type' => 'int','precision' => '4','nullable' => False), 'li' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'TS if login'),
'lo' => array('type' => 'int','precision' => '4','default' => '0'), 'lo' => array('type' => 'int','precision' => '8','comment' => 'TD of logout'),
'account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0') 'account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'numerical account id'),
'session_dla' => array('type' => 'int','precision' => '8','comment' => 'TS of last user action'),
'session_action' => array('type' => 'varchar','precision' => '64','comment' => 'menuaction or path of last user action'),
'session_php' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'php session-id or error-message'),
'notification_heartbeat' => array('type' => 'int','precision' => '8','comment' => 'TS of last notification request')
), ),
'pk' => array(), 'pk' => array('sessionid'),
'fk' => array(), 'fk' => array(),
'ix' => array('li'), 'ix' => array('li','lo','session_dla','notification_heartbeat'),
'uc' => array() 'uc' => array()
), ),
'egw_hooks' => array( 'egw_hooks' => array(

View File

@ -173,3 +173,33 @@ function phpgwapi_upgrade1_9_006()
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.007'; return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.007';
} }
/**
* Add columns for session list (dla, action), make sessionid primary key and TS 64bit
*/
function phpgwapi_upgrade1_9_007()
{
$GLOBALS['egw_setup']->oProc->RefreshTable('egw_access_log',array(
'fd' => array(
'sessionid' => array('type' => 'auto','nullable' => False,'comment' => 'primary key'),
'loginid' => array('type' => 'varchar','precision' => '64','nullable' => False,'comment' => 'username used to login'),
'ip' => array('type' => 'varchar','precision' => '40','nullable' => False,'comment' => 'ip of user'),
'li' => array('type' => 'int','precision' => '8','nullable' => False,'comment' => 'TS if login'),
'lo' => array('type' => 'int','precision' => '8','comment' => 'TD of logout'),
'account_id' => array('type' => 'int','precision' => '4','nullable' => False,'default' => '0','comment' => 'numerical account id'),
'session_dla' => array('type' => 'int','precision' => '8','comment' => 'TS of last user action'),
'session_action' => array('type' => 'varchar','precision' => '64','comment' => 'menuaction or path of last user action'),
'session_php' => array('type' => 'char','precision' => '64','nullable' => False,'comment' => 'php session-id or error-message'),
'notification_heartbeat' => array('type' => 'int','precision' => '8','comment' => 'TS of last notification request')
),
'pk' => array('sessionid'),
'fk' => array(),
'ix' => array('li','lo','session_dla','notification_heartbeat'),
'uc' => array()
),array(
'session_php' => 'sessionid',
'sessionid' => 'NULL', // to NOT copy old sessionid, but create a new sequence
));
return $GLOBALS['setup_info']['phpgwapi']['currentver'] = '1.9.008';
}