2013-04-28 16:52:41 +02:00
< ? php
/**
* EGroupware : Preferences app UI for settings / preferences
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < rb @ stylite . de >
* @ package preferences
2016-04-30 19:16:36 +02:00
* @ copyright ( c ) 2013 - 16 by Ralf Becker < rb @ stylite . de >
2013-04-28 16:52:41 +02:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
* @ version $Id $
*/
2016-04-30 19:16:36 +02:00
use EGroupware\Api ;
2023-01-11 22:18:01 +01:00
use EGroupware\Api\Etemplate\Widget\Select ;
2016-04-30 19:16:36 +02:00
use EGroupware\Api\Framework ;
use EGroupware\Api\Egw ;
2022-08-31 14:14:53 +02:00
use EGroupware\Api\Image ;
2016-04-30 19:16:36 +02:00
use EGroupware\Api\Vfs ;
use EGroupware\Api\Etemplate ;
2013-04-28 16:52:41 +02:00
/**
2016-04-30 19:16:36 +02:00
* UI for settings / Api\Preferences
2013-04-28 16:52:41 +02:00
*/
class preferences_settings
{
/**
* Methods callable via menuaction
* @ var array
*/
public $public_functions = array (
'index' => true ,
);
/**
* App we work on
* @ var string
*/
public $appname = 'preferences' ;
/**
* Preferences read by call_hook
* @ var array
*/
public $settings = array ();
/**
* Edit preferences
*
2014-10-21 11:15:42 +02:00
* @ param array $content = null
* @ param string $msg = ''
2013-04-28 16:52:41 +02:00
*/
function index ( array $content = null , $msg = '' )
{
2016-04-30 19:16:36 +02:00
$tpl = new Etemplate ( 'preferences.settings' );
2013-04-28 16:52:41 +02:00
if ( ! is_array ( $content ))
{
2013-12-06 01:02:16 +01:00
$appname = isset ( $_GET [ 'appname' ]) && $_GET [ 'appname' ] != 'preferences' &&
isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $_GET [ 'appname' ]]) ? $_GET [ 'appname' ] : 'common' ;
2013-05-03 15:08:08 +02:00
$type = 'user' ;
$account_id = $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ];
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ] &&
isset ( $_GET [ 'account_id' ]) && ( int ) $_GET [ 'account_id' ] &&
$GLOBALS [ 'egw' ] -> accounts -> exists (( int ) $_GET [ 'account_id' ]))
2013-04-28 16:52:41 +02:00
{
2013-05-03 15:08:08 +02:00
$account_id = ( int ) $_GET [ 'account_id' ];
$type = $_GET [ 'account_id' ] < 0 ? 'group' : 'user' ;
2018-08-21 14:42:44 +02:00
$is_admin = true ;
2013-04-28 16:52:41 +02:00
}
2013-12-06 01:02:16 +01:00
$content [ 'current_app' ] = isset ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $_GET [ 'current_app' ]]) ? $_GET [ 'current_app' ] : $appname ;
2013-05-03 15:08:08 +02:00
}
else
{
2019-04-10 19:19:41 +02:00
$is_admin = $content [ 'is_admin' ] || $content [ 'type' ] != 'user' ;
2013-05-09 12:41:38 +02:00
//error_log(__METHOD__."(".array2string($content).")");
2021-10-06 16:07:47 +02:00
if ( ! empty ( $content [ 'button' ]))
2013-04-28 16:52:41 +02:00
{
2019-02-12 22:13:45 +01:00
$button = key ( $content [ 'button' ]);
2013-12-02 18:38:15 +01:00
$appname = $content [ 'old_appname' ] ? $content [ 'old_appname' ] : 'common' ;
2013-05-03 15:08:08 +02:00
switch ( $button )
2013-04-28 16:52:41 +02:00
{
2013-05-03 15:08:08 +02:00
case 'save' :
case 'apply' :
2014-07-13 12:27:46 +02:00
// check if user has rights to store preferences for $type and $account_id
if ( $content [ 'old_type' ] !== 'user' && ! $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ])
{
2016-04-30 19:16:36 +02:00
throw new Api\Exception\NoPermission\Admin ;
2014-07-13 12:27:46 +02:00
}
2013-05-03 17:25:11 +02:00
list ( $type , $account_id ) = explode ( ':' , $content [ 'old_type' ]);
2013-05-10 09:50:30 +02:00
// merge prefs of all tabs together again
$prefs = array ();
foreach ( $content as $name => $val )
{
if ( is_array ( $val ) && strpos ( $name , 'tab' ) === 0 )
{
$prefs = array_merge ( $prefs , $val );
}
}
2013-05-10 19:22:14 +02:00
//error_log(__METHOD__."() button=$button, content=".array2string($content).' --> prefs='.array2string($prefs));;;
if ( $account_id && $account_id != $GLOBALS [ 'egw' ] -> preferences -> get_account_id ())
2013-05-03 17:25:11 +02:00
{
2013-05-10 19:22:14 +02:00
$GLOBALS [ 'egw' ] -> preferences -> set_account_id ( $account_id );
2013-05-03 17:25:11 +02:00
$GLOBALS [ 'egw' ] -> preferences -> read_repository ();
}
$attribute = $type == 'group' ? 'user' : $type ;
2023-03-16 16:25:48 +01:00
$require_reload = self :: fetchRequireToReload ( $appname , $type );
$old_values = array_intersect_key ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ $appname ], array_flip ( $require_reload ));
2018-08-21 14:42:44 +02:00
if ( ! ( $msg = $this -> process_array ( $GLOBALS [ 'egw' ] -> preferences -> $attribute , $prefs , $content [ 'types' ], $appname , $attribute , $content )))
2013-05-03 17:25:11 +02:00
{
2013-10-03 11:23:18 +02:00
$msg_type = 'success' ;
$msg = lang ( 'Preferences saved.' );
2014-04-03 12:25:21 +02:00
// do we need to reload whole framework
2023-03-16 16:25:48 +01:00
if ( ! empty ( $require_reload ))
2014-04-03 12:25:21 +02:00
{
if ( $account_id && $GLOBALS [ 'egw' ] -> preferences -> get_account_id () != $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ])
{
$GLOBALS [ 'egw' ] -> preferences -> set_account_id ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ]);
}
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ] = $GLOBALS [ 'egw' ] -> preferences -> read_repository ();
2023-03-16 16:25:48 +01:00
$new_values = array_intersect_key ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ][ $appname ], array_flip ( $require_reload ));
2014-04-03 12:25:21 +02:00
//error_log(__METHOD__."() ".__LINE__.": old_values=".array2string($old_values).", new_values=".array2string($new_values));
if ( $old_values != $new_values )
{
2016-04-30 19:16:36 +02:00
Framework :: refresh_opener ( $msg , null , null , null , null , null , null , $msg_type );
2014-04-03 12:25:21 +02:00
}
}
2020-07-31 09:47:49 +02:00
// update client-side Api\Preferences in response (only current user/session)
Framework :: ajax_get_preference ( $appname );
// ask every affected client to reload preferences, if affected ($appname prefs loaded and member of group for group prefs)
$push = new Api\Json\Push ( $account_id > 0 ? ( int ) $account_id : Api\Json\Push :: ALL );
$push -> call ( 'egw.reload_preferences' , $appname , $account_id ? ( int ) $account_id : 0 );
2013-05-03 17:25:11 +02:00
}
2013-05-03 15:08:08 +02:00
}
2013-12-06 01:02:16 +01:00
if ( in_array ( $button , array ( 'save' , 'cancel' )))
2013-12-02 18:38:15 +01:00
{
2016-04-30 19:16:36 +02:00
Api\Json\Response :: get () -> call ( 'egw.message' , $msg , $msg_type );
Framework :: window_close ();
2013-12-02 18:38:15 +01:00
}
2013-05-03 15:08:08 +02:00
}
2013-05-03 17:25:11 +02:00
$appname = $content [ 'appname' ] ? $content [ 'appname' ] : 'common' ;
list ( $type , $account_id ) = explode ( ':' , $content [ 'type' ]);
2013-05-03 15:08:08 +02:00
//_debug_array($prefs);
}
2013-05-10 19:22:14 +02:00
if ( $account_id && $account_id != $GLOBALS [ 'egw' ] -> preferences -> get_account_id ())
2013-05-03 15:08:08 +02:00
{
2013-05-10 19:22:14 +02:00
$GLOBALS [ 'egw' ] -> preferences -> set_account_id ( $account_id );
2013-05-03 15:08:08 +02:00
$GLOBALS [ 'egw' ] -> preferences -> read_repository ();
}
2013-05-10 20:00:33 +02:00
$preserve = array ( 'types' => array ());
2013-07-25 18:07:41 +02:00
// preserv open tab, if appname is not chanaged
if ( ! isset ( $content [ 'old_appname' ]) || $content [ 'old_appname' ] == $content [ 'appname' ] ||
$content [ 'old_appname' ] == 'common' && ! $content [ 'appname' ])
{
$old_tab = $content [ 'tabs' ];
}
2013-12-06 01:02:16 +01:00
// we need to run under calling app, to be able to restore it to it's index page after
2014-04-01 17:49:08 +02:00
$preserve [ 'current_app' ] = $content [ 'current_app' ];
$GLOBALS [ 'egw_info' ][ 'flags' ][ 'currentapp' ] = $content [ 'current_app' ] == 'common' ?
'preferences' : $content [ 'current_app' ];
2016-04-30 19:16:36 +02:00
Framework :: includeCSS ( 'preferences' , 'app' );
2013-12-06 01:02:16 +01:00
2013-05-10 09:50:30 +02:00
// if not just saved, call validation before, to be able to show failed validation of current prefs
if ( ! isset ( $button ))
{
$attribute = $type == 'group' ? 'user' : $type ;
$msg = $this -> process_array ( $GLOBALS [ 'egw' ] -> preferences -> $attribute ,
2018-08-21 14:42:44 +02:00
( array ) $GLOBALS [ 'egw' ] -> preferences -> { $attribute }[ $appname ], $preserve [ 'types' ], $appname , $attribute , $content , true );
2013-05-10 09:50:30 +02:00
}
2014-05-28 12:03:57 +02:00
$sel_options = $readonlys = null ;
2014-10-21 11:15:42 +02:00
$data = $this -> get_content ( $appname , $type , $sel_options , $readonlys , $preserve [ 'types' ], $tpl );
2022-10-11 21:14:55 +02:00
if ( $data [ 'appname' ] == 'common' )
{
// 'common' is not in the options list, we use the empty label for common
$data [ 'appname' ] = '' ;
}
2014-10-21 11:15:42 +02:00
$preserve [ 'appname' ] = $preserve [ 'old_appname' ] = $data [ 'appname' ];
$preserve [ 'type' ] = $preserve [ 'old_type' ] = $data [ 'type' ];
2018-08-21 14:42:44 +02:00
$preserve [ 'is_admin' ] = $is_admin ;
2018-08-22 12:26:56 +02:00
// preserve the old values since we need them for admin cmd data comparison
$preserve [ 'old_values' ] = array ();
foreach ( $data as $key => $val )
{
if ( is_array ( $val ) && strpos ( $key , 'tab' ) === 0 )
{
foreach ( $val as $k => $v )
{
if ( ! is_int ( $k )) $preserve [ 'old_values' ][ $k ] = $v ;
}
}
}
2014-10-21 11:15:42 +02:00
if ( isset ( $old_tab )) $data [ 'tabs' ] = $old_tab ;
2014-05-28 12:03:57 +02:00
2016-04-30 19:16:36 +02:00
if ( $msg ) Framework :: message ( $msg , $msg_type ? $msg_type : 'error' );
2013-05-10 09:50:30 +02:00
2014-10-21 11:15:42 +02:00
$tpl -> exec ( 'preferences.preferences_settings.index' , $data , $sel_options , $readonlys , $preserve , 2 );
2013-05-03 15:08:08 +02:00
}
2023-03-16 16:25:48 +01:00
/**
* Fetch preferences of given app where they have reload attribute set to true
* @ param string $appname app name
* @ param string $type 'user' , 'default' , 'forced'
* @ return array
* @ throws Api\Exception\AssertionFailed
*/
static function fetchRequireToReload ( $appname , $type )
{
$keys = [];
if ( $appname == 'common' )
{
// none app pref names here since we can't read them via hooks
$keys = [ 'template_color' , 'template_custom_color' , 'sidebox_custom_color' ];
$settings = Api\Hooks :: single ( array (
'account_id' => $GLOBALS [ 'egw' ] -> preferences -> get_account_id (),
'location' => 'settings' ,
'type' => $type ), 'preferences' );
}
else
{
$settings = Api\Hooks :: single ( array (
'account_id' => $GLOBALS [ 'egw' ] -> preferences -> get_account_id (),
'location' => 'settings' ,
'type' => $type ), $appname );
}
foreach ( $settings as $key => $value )
{
if ( $value [ 'reload' ]) $keys [] = $key ;
}
return $keys ;
}
2018-08-21 14:42:44 +02:00
/**
* run admin command instance
*
* @ param array $content
* @ param array $values
* @ param string $account_id
*/
2018-08-23 15:24:13 +02:00
static function admin_cmd_run ( $content , $values , $account_id , $type , $appname )
2018-08-21 14:42:44 +02:00
{
2018-08-23 15:24:13 +02:00
$changes = array_udiff_assoc ( $values , $content [ 'old_values' ], function ( $a , $b )
{
2019-06-17 23:48:38 +02:00
if ( $a == '**NULL**' && empty ( $b ) || empty ( $a ) && $b == '**NULL**' )
{
return 0 ;
}
2018-08-23 15:24:13 +02:00
// some prefs are still comma-delimitered
if ( is_array ( $a ) != is_array ( $b ))
{
2019-06-17 23:48:38 +02:00
if ( ! is_array ( $a )) $a = is_null ( $a ) ? array () : explode ( ',' , $a );
if ( ! is_array ( $b )) $b = is_null ( $b ) ? array () : explode ( ',' , $b );
2018-08-23 15:24:13 +02:00
}
return ( int )( $a != $b );
2018-08-22 12:26:56 +02:00
});
$old = array_intersect_key ( $content [ 'old_values' ], $changes );
2018-08-23 15:24:13 +02:00
if ( $changes )
{
$cmd = new admin_cmd_edit_preferences ( $account_id , $type , $appname , $changes , $old , ( array ) $content [ 'admin_cmd' ]);
return $cmd -> run ();
}
return lang ( 'Nothing to save.' );
2018-08-21 14:42:44 +02:00
}
2013-05-03 17:25:11 +02:00
/**
* Verify and save preferences
*
2013-05-10 09:50:30 +02:00
* @ param array & $repository values get updated here
* @ param array $values new values
* @ param array $types setting - name => type
2013-05-03 17:25:11 +02:00
* @ param string $appname appname or 'common'
2013-05-10 09:50:30 +02:00
* @ param string $type 'user' , 'default' , 'forced'
2018-08-21 14:42:44 +02:00
* @ param array $content
2014-10-21 11:15:42 +02:00
* @ param boolean $only_verify = false
2013-05-03 17:25:11 +02:00
* @ return string with verification error or null on success
*/
2018-08-21 14:42:44 +02:00
function process_array ( array & $repository , array $values , array $types , $appname , $type , $content , $only_verify = false )
2013-05-03 17:25:11 +02:00
{
2017-01-23 16:01:23 +01:00
//fetch application specific settings from a hook
$settings = Api\Hooks :: single ( array (
'account_id' => $GLOBALS [ 'egw' ] -> preferences -> get_account_id (),
'location' => 'settings' ,
'type' => $type ), $appname );
2013-05-03 17:25:11 +02:00
//_debug_array($repository);
$prefs = & $repository [ $appname ];
unset ( $prefs [ '' ]);
2018-08-22 12:26:56 +02:00
2013-05-03 17:25:11 +02:00
//_debug_array($values);exit;
2019-11-01 18:10:01 +01:00
foreach ( $values as $var => & $value )
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
// type specific validation
switch (( string ) $types [ $var ])
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
case 'password' : // dont write empty password-fields
if ( empty ( $value )) continue 2 ;
break ;
case 'vfs_file' :
case 'vfs_dir' :
case 'vfs_dirs' :
if ( $value === '' )
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
// empty is always allowed
// If forced, empty == not set
if ( $type == 'forced' )
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
unset ( $prefs [ $var ]);
// need to call preferences::delete, to also set affective prefs!
if ( ! $only_verify ) $GLOBALS [ 'egw' ] -> preferences -> delete ( $appname , $var , $type );
continue 2 ;
2013-05-03 17:25:11 +02:00
}
}
2013-05-10 09:50:30 +02:00
elseif ( $types [ $var ] == 'vfs_file' )
2013-05-03 17:25:11 +02:00
{
2016-04-30 19:16:36 +02:00
if ( $value [ 0 ] != '/' || ! Vfs :: stat ( $value ) || Vfs :: is_dir ( $value ))
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
$error = lang ( '%1 is no existing vfs file!' , htmlspecialchars ( $value ));
2013-05-03 17:25:11 +02:00
}
2013-05-10 09:50:30 +02:00
}
else
{
// split multiple comma or whitespace separated directories
// to still allow space or comma in dirnames, we also use the trailing slash of all pathes to split
foreach ( $types [ $var ] == 'vfs_dir' ? array ( $value ) : preg_split ( '/[,\s]+\//' , $value ) as $n => $dir )
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
if ( $n ) $dir = '/' . $dir ; // re-adding trailing slash removed by split
2016-04-30 19:16:36 +02:00
if ( $dir [ 0 ] != '/' || ! Vfs :: stat ( $dir ) || ! Vfs :: is_dir ( $dir ))
2013-05-03 17:25:11 +02:00
{
2013-05-10 09:50:30 +02:00
$error .= ( $error ? ' ' : '' ) . lang ( '%1 is no existing vfs directory!' , $dir );
2013-05-03 17:25:11 +02:00
}
}
}
2013-05-10 09:50:30 +02:00
break ;
2019-06-17 23:48:38 +02:00
case 'multiselect' :
if ( empty ( $value ) && $type == 'forced' )
{
$value = '**NULL**' ;
}
break ;
2013-05-10 17:56:35 +02:00
case 'Array' : // notify
2016-09-19 11:06:58 +02:00
// Make sure the application translation is loaded
Api\Translation :: add_app ( $appname );
2013-05-10 09:50:30 +02:00
$value = $GLOBALS [ 'egw' ] -> preferences -> lang_notify ( $value , $types [ $var ], True );
break ;
}
2014-01-20 18:51:46 +01:00
if ( isset ( $value ) && $value !== '' && $value !== '**NULL**' && $value !== array ())
2013-05-10 09:50:30 +02:00
{
2017-01-23 16:01:23 +01:00
if ( is_array ( $value ) && ! $settings [ $var ][ 'no_sel_options' ]) $value = implode ( ',' , $value ); // multiselect
2013-05-10 09:50:30 +02:00
2013-05-03 17:25:11 +02:00
$prefs [ $var ] = $value ;
// need to call preferences::add, to also set affective prefs!
if ( ! $only_verify ) $GLOBALS [ 'egw' ] -> preferences -> add ( $appname , $var , $prefs [ $var ], $type );
}
else
{
unset ( $prefs [ $var ]);
2013-05-10 09:50:30 +02:00
2013-05-03 17:25:11 +02:00
// need to call preferences::delete, to also set affective prefs!
if ( ! $only_verify ) $GLOBALS [ 'egw' ] -> preferences -> delete ( $appname , $var , $type );
}
}
// the following hook can be used to verify the prefs
// if you return something else than False, it is treated as an error-msg and
// displayed to the user (the prefs are not saved)
//
2016-04-30 19:16:36 +02:00
if (( $error .= Api\Hooks :: single ( array (
2014-01-28 11:16:24 +01:00
'location' => 'verify_settings' ,
2014-05-28 12:03:57 +02:00
'prefs' => & $repository [ $appname ],
'type' => $type ,
'preprocess' => $only_verify ,
2013-05-03 17:25:11 +02:00
),
$appname
)))
{
return $error ;
}
2018-08-21 14:42:44 +02:00
if ( ! $only_verify )
2013-05-03 17:25:11 +02:00
{
2019-06-17 23:48:38 +02:00
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( True , $type );
2018-08-21 14:42:44 +02:00
if ( $content [ 'is_admin' ])
{
2019-01-10 15:06:05 +01:00
if (( $account_id = $GLOBALS [ 'egw' ] -> preferences -> get_account_id ()) < 0 && $type == 'user' ) $type = 'group' ;
self :: admin_cmd_run ( $content , $values , $account_id , $type , $appname );
2018-08-21 14:42:44 +02:00
}
// certain common prefs (language, template, ...) require the session to be re-created
if ( $appname == 'common' )
{
Egw :: invalidate_session_cache ();
}
2024-02-13 09:31:45 +01:00
// update $GLOBALS['egw_info']['user']['preferences'] as some hooks called use that can return or set old values (e.g. calendar default-alarm(-wholeday))
if ( $type === 'user' && $GLOBALS [ 'egw' ] -> preferences -> get_account_id () == $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ])
{
$GLOBALS [ 'egw_info' ][ 'user' ][ 'preferences' ] = $GLOBALS [ 'egw' ] -> preferences -> data ;
}
2013-05-03 17:25:11 +02:00
}
return null ;
}
2024-08-22 10:52:16 +02:00
public static function defaultLabel ( string $type = 'user' )
{
switch ( $type )
{
default :
case 'user' :
return lang ( 'Use default' );
case 'default' :
case 'group' :
return lang ( 'No default' );
case 'forced' ;
return lang ( 'Users choice' );
}
}
2013-05-03 15:08:08 +02:00
/**
* Get content , sel_options and readonlys for given appname and type
*
2013-05-03 17:25:11 +02:00
* @ param string $appname appname or 'common'
2013-05-03 15:08:08 +02:00
* @ param string $type
* @ param array & $sel_options
* @ param array & $readonlys
2013-05-10 09:50:30 +02:00
* @ param array & $types on return setting - name => setting - type
2019-03-20 18:14:31 +01:00
* @ param Api\Etemplate | etemplate $tpl
2016-04-30 19:16:36 +02:00
* @ throws Api\Exception\WrongParameter
2013-05-03 15:08:08 +02:00
* @ return array content
*/
2013-05-10 09:50:30 +02:00
function get_content ( $appname , $type , & $sel_options , & $readonlys , & $types , $tpl )
2013-05-03 15:08:08 +02:00
{
2014-07-18 13:46:10 +02:00
if ( ! $this -> call_hook ( $appname , $type , $GLOBALS [ 'egw' ] -> preferences -> get_account_id ()))
2013-05-03 15:08:08 +02:00
{
2016-04-30 19:16:36 +02:00
throw new Api\Exception\WrongParameter ( " Could not find settings for application: " . $appname );
2013-05-03 15:08:08 +02:00
}
$attribute = $type == 'group' ? 'user' : $type ;
2013-05-10 19:22:14 +02:00
//error_log(__METHOD__."('$appname', '$type' ) attribute='$attribute', preferences->account_id=".$GLOBALS['egw']->preferences->get_account_id());
2013-05-03 15:08:08 +02:00
//_debug_array($this->settings); exit;
$sel_options = $readonlys = $content = $tabs = array ();
// disable all but first tab and name current tab "tab1", for apps not using sections
$tab = 'tab1' ;
foreach ( $this -> settings as $setting )
{
if ( ! is_array ( $setting )) continue ;
2019-01-10 23:54:04 +01:00
if ( $type != 'forced' && $setting [ 'name' ] && ( string ) $GLOBALS [ 'egw' ] -> preferences -> forced [ $appname ][ $setting [ 'name' ]] !== '' )
2013-05-03 15:08:08 +02:00
{
continue ; // forced preferences are not displayed, unless we edit them
}
2013-05-10 09:50:30 +02:00
$types [ $setting [ 'name' ]] = $old_type = $setting [ 'type' ];
switch ( $old_type )
2013-05-03 15:08:08 +02:00
{
case 'section' :
$tab = 'tab' . ( 1 + count ( $tabs ));
2013-05-09 11:38:12 +02:00
$tabs [] = array (
'id' => $tab ,
2024-03-21 09:28:27 +01:00
'content' => $tab ,
2013-05-09 11:38:12 +02:00
'template' => 'preferences.settings.tab1' ,
'label' => $setting [ 'title' ],
);
2013-05-03 15:08:08 +02:00
// fall through
case 'subsection' : // is in old code, but never seen it used
continue 2 ;
2013-04-28 16:52:41 +02:00
2013-05-10 09:50:30 +02:00
case 'notify' :
2021-10-20 15:03:41 +02:00
$vars = $GLOBALS [ 'egw' ] -> preferences -> vars ? ? [];
2013-05-10 17:56:35 +02:00
if ( is_array ( $setting [ 'values' ])) $vars += $setting [ 'values' ];
$GLOBALS [ 'egw' ] -> preferences -> { $attribute }[ $appname ][ $setting [ 'name' ]] =
$GLOBALS [ 'egw' ] -> preferences -> lang_notify ( $GLOBALS [ 'egw' ] -> preferences -> { $attribute }[ $appname ][ $setting [ 'name' ]], $vars );
$types [ $setting [ 'name' ]] = $vars ; // store vars for re-translation, instead type "notify"
2013-05-10 18:39:42 +02:00
if ( $setting [ 'help' ] && ( $setting [ 'run_lang' ] || ! isset ( $setting [ 'run_lang' ])))
2013-05-10 17:56:35 +02:00
{
$setting [ 'help' ] = lang ( $setting [ 'help' ]);
}
$setting [ 'help' ] .= '<p><b>' . lang ( 'Substitutions and their meanings:' ) . '</b>' ;
foreach ( $vars as $var => $var_help )
{
$lname = ( $lname = lang ( $var )) == $var . '*' ? $var : $lname ;
$setting [ 'help' ] .= " <br> \n " . '<b>$$' . $lname . '$$</b>: ' . $var_help ;
}
$setting [ 'help' ] .= " </p> \n " ;
2013-05-10 18:39:42 +02:00
$setting [ 'run_lang' ] = false ; // already done now
2013-05-10 17:56:35 +02:00
// handle as textarea
2013-05-10 09:50:30 +02:00
case 'textarea' :
2022-10-18 21:30:22 +02:00
$setting [ 'type' ] = 'et2-textarea' ;
if ( ! empty ( $setting [ 'rows' ]))
2013-05-10 10:24:15 +02:00
{
2022-10-18 21:30:22 +02:00
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'rows' , $setting [ 'rows' ]);
2013-05-10 10:24:15 +02:00
}
2013-05-10 09:50:30 +02:00
break ;
2013-05-03 17:25:11 +02:00
case 'password' :
2013-05-03 15:08:08 +02:00
case 'vfs_file' :
case 'vfs_dir' :
case 'vfs_dirs' :
case 'input' :
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-textbox' ;
2013-05-03 15:08:08 +02:00
break ;
case 'check' :
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-select' ;
2013-05-03 15:08:08 +02:00
$setting [ 'values' ] = array ( '1' => lang ( 'yes' ), '0' => lang ( 'no' ));
break ;
2022-07-13 18:52:11 +02:00
case 'select' :
$setting [ 'type' ] = 'et2-select' ;
break ;
2013-05-03 15:08:08 +02:00
case 'multiselect' :
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-select' ;
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'multiple' , true );
2013-05-03 15:08:08 +02:00
break ;
2022-07-19 15:17:16 +02:00
case 'select-tab' :
case 'select-tabs' :
$setting [ 'type' ] = 'et2-select-tab' ;
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'allowFreeEntries' , true );
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'multiple' , $old_type === 'select-tabs' );
break ;
2022-07-19 18:28:44 +02:00
case 'select-cat' : // using application=$appname and global=true
$setting [ 'type' ] = 'et2-select-cat' ;
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'application' , $appname );
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'global_categories' , true );
break ;
2013-05-03 15:08:08 +02:00
case 'color' :
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-colorpicker' ;
2013-05-03 15:08:08 +02:00
break ;
2014-06-06 13:59:20 +02:00
case 'date-duration' :
2022-07-13 18:52:11 +02:00
if ( ! isset ( $setting [ 'size' ]))
{
$setting [ 'size' ] = 'm,dhm,24,1' ;
}
2014-06-06 13:59:20 +02:00
$attrs = explode ( ',' , $setting [ 'size' ]);
foreach ( array ( " data_format " , " display_format " , " hours_per_day " , " empty_not_0 " , " short_labels " ) as $n => $name )
{
if (( string ) $attrs [ $n ] !== '' ) $tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , $name , $attrs [ $n ]);
}
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-date-duration' ;
2014-06-06 13:59:20 +02:00
break ;
2017-01-13 15:13:44 +01:00
case 'taglist' :
2022-07-13 18:52:11 +02:00
if ( $setting [ 'no_sel_options' ])
2017-01-13 15:13:44 +01:00
{
2022-07-13 18:52:11 +02:00
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'autocomplete_url' , '' );
2022-08-05 20:20:46 +02:00
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'allowFreeEntries' , true );
2017-01-13 15:13:44 +01:00
}
2022-07-13 18:52:11 +02:00
$setting [ 'type' ] = 'et2-select' ;
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , 'multiple' , true );
2017-01-13 15:13:44 +01:00
break ;
2013-05-03 15:08:08 +02:00
}
// move values/options to sel_options array
2024-08-22 10:52:16 +02:00
if ( isset ( $setting [ 'values' ]) && is_array ( $setting [ 'values' ]) && empty ( $setting [ 'no_sel_options' ]))
2013-05-03 15:08:08 +02:00
{
2024-08-22 10:52:16 +02:00
// if you use an et2-* widget as type, it's your responsibility to encode options correct!
if ( str_starts_with ( $old_type , 'et2-' ))
{
$setting [ 'attributes' ][ 'placeholder' ] = self :: defaultLabel ( $type );
}
else
2013-05-03 15:08:08 +02:00
{
2024-08-22 10:52:16 +02:00
Select :: fix_encoded_options ( $setting [ 'values' ], true );
if ( $old_type != 'multiselect' && $old_type != 'notify' && $old_type != 'et2-tree-dropdown' )
2013-05-03 15:08:08 +02:00
{
2024-08-22 10:52:16 +02:00
if ( $type === 'forced' )
{
2023-01-06 17:21:45 +01:00
$setting [ 'values' ] = array_merge (
2024-08-22 10:52:16 +02:00
array ([ 'value' => '**NULL**' , 'label' => self :: defaultLabel ( $type )]),
2023-01-06 17:21:45 +01:00
$setting [ 'values' ]
);
2024-08-22 10:52:16 +02:00
}
else
{
2023-01-06 17:21:45 +01:00
$setting [ 'values' ] = array_merge (
2024-08-22 10:52:16 +02:00
array ([ 'value' => '' , 'label' => self :: defaultLabel ( $type )]),
2023-01-06 17:21:45 +01:00
$setting [ 'values' ]
);
2024-08-22 10:52:16 +02:00
}
2013-05-03 15:08:08 +02:00
}
}
$sel_options [ $setting [ 'name' ]] = $setting [ 'values' ];
}
if ( $type == 'user' )
{
2024-08-22 10:52:16 +02:00
$default = $GLOBALS [ 'egw' ] -> preferences -> group [ $appname ][ $setting [ 'name' ]] ? :
2013-05-10 19:22:14 +02:00
$GLOBALS [ 'egw' ] -> preferences -> default [ $appname ][ $setting [ 'name' ]];
2014-01-10 10:08:40 +01:00
// replace default value(s) for selectboxes with selectbox labels
if ( isset ( $setting [ 'values' ]) && is_array ( $setting [ 'values' ]))
2013-05-03 15:08:08 +02:00
{
2014-01-10 10:08:40 +01:00
$default = self :: get_default_label ( $default , $setting [ 'values' ]);
2013-04-28 16:52:41 +02:00
}
2013-05-10 18:39:42 +02:00
if ( is_array ( $types [ $setting [ 'name' ]])) // translate the substitution names
{
$default = $GLOBALS [ 'egw' ] -> preferences -> lang_notify ( $default , $types [ $setting [ 'name' ]]);
}
}
if ( $setting [ 'help' ] && ( $setting [ 'run_lang' ] || ! isset ( $setting [ 'run_lang' ])))
{
$setting [ 'help' ] = lang ( $setting [ 'help' ]);
2013-04-28 16:52:41 +02:00
}
2013-05-03 15:08:08 +02:00
$content [ $tab ][] = array (
2022-07-13 18:52:11 +02:00
'name' => $setting [ 'name' ],
'type' => $setting [ 'type' ],
'label' => preg_replace ( '|<br[ /]*>|i' , " \n " , $setting [ 'label' ]),
'help' => lang ( $setting [ 'help' ]), // is html
'default' => ( string ) $default !== '' ? lang ( 'Default' ) . ': ' . $default : null ,
'onchange' => $setting [ 'onchange' ]
2013-05-03 15:08:08 +02:00
);
2022-07-13 18:52:11 +02:00
2022-07-14 21:22:48 +02:00
foreach ( $setting [ 'attributes' ] as $attr => $attr_value )
{
$tpl -> setElementAttribute ( $tab . '[' . $setting [ 'name' ] . ']' , $attr , $attr_value );
}
2013-05-10 20:00:33 +02:00
//error_log("appname=$appname, attribute=$attribute, setting=".array2string($setting));
2013-05-03 15:08:08 +02:00
$content [ $tab ][ $setting [ 'name' ]] = $GLOBALS [ 'egw' ] -> preferences -> { $attribute }[ $appname ][ $setting [ 'name' ]];
//if ($old_type == 'multiselect') $content[$tab][$setting['name']] = explode(',', $content[$tab][$setting['name']]);
}
2013-05-09 11:38:12 +02:00
// defining used tabs on run-time
2014-04-22 18:09:26 +02:00
if ( $tabs )
{
2023-01-11 21:21:01 +01:00
$tpl -> setElementAttribute ( 'tabs' , 'extraTabs' , $tabs );
2014-04-22 18:09:26 +02:00
}
else
{
// Modifications are kept in the request, so reset to just one
2023-01-11 21:21:01 +01:00
$tpl -> setElementAttribute ( 'tabs' , 'extraTabs' , array (
array (
'id' => 'tab1' ,
2024-03-30 07:31:08 +01:00
'content' => 'tab1' ,
2023-01-11 21:21:01 +01:00
'template' => 'preferences.settings.tab1' ,
'label' => 'general settings'
)));
2014-04-22 18:09:26 +02:00
}
2013-05-03 15:08:08 +02:00
$content [ 'appname' ] = $appname ;
$sel_options [ 'appname' ] = array ();
2016-04-30 19:16:36 +02:00
foreach ( Api\Hooks :: implemented ( 'settings' ) as $app )
2013-05-03 15:08:08 +02:00
{
2014-10-21 11:15:42 +02:00
if ( $app != 'preferences' && $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ $app ])
2013-05-03 15:08:08 +02:00
{
2022-08-31 14:14:53 +02:00
$sel_options [ 'appname' ][ $app ] = [
'value' => $app ,
'label' => $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ][ 'title' ],
'icon' => Image :: find ( $app , 'navbar' )
];
2013-05-03 15:08:08 +02:00
}
}
natcasesort ( $sel_options [ 'appname' ]);
2013-05-03 17:25:11 +02:00
$sel_options [ 'type' ] = array (
'user' => 'Your preferences' ,
'default' => 'Default preferences' ,
'forced' => 'Forced preferences' ,
);
2014-07-13 12:27:46 +02:00
if ( $GLOBALS [ 'egw_info' ][ 'user' ][ 'apps' ][ 'admin' ])
2013-05-03 15:08:08 +02:00
{
$content [ 'type' ] = $type ;
2013-05-10 19:22:14 +02:00
if (( $id = $GLOBALS [ 'egw' ] -> preferences -> get_account_id ()) != $GLOBALS [ 'egw_info' ][ 'user' ][ 'account_id' ])
2013-05-03 15:08:08 +02:00
{
2013-05-10 19:22:14 +02:00
$content [ 'type' ] .= ':' . $id ;
2016-04-30 19:16:36 +02:00
$sel_options [ 'type' ][ $content [ 'type' ]] = Api\Accounts :: username ( $GLOBALS [ 'egw' ] -> preferences -> account_id );
2013-10-03 11:23:18 +02:00
2013-09-17 18:26:45 +02:00
// Restrict app list to apps the user has access to
$user_apps = $GLOBALS [ 'egw' ] -> acl -> get_user_applications ( $id );
$sel_options [ 'appname' ] = array_intersect_key ( $sel_options [ 'appname' ], $user_apps );
2013-05-03 15:08:08 +02:00
}
2014-01-21 19:06:07 +01:00
foreach ( $GLOBALS [ 'egw' ] -> accounts -> search ( array ( 'type' => 'groups' , 'order' => 'account_lid' )) as $account_id => $group )
2013-05-03 15:08:08 +02:00
{
2016-04-30 19:16:36 +02:00
$sel_options [ 'type' ][ 'group:' . $account_id ] = lang ( 'Preferences' ) . ' ' . Api\Accounts :: format_username ( $group [ 'account_lid' ], '' , '' , $account_id );
2013-05-03 15:08:08 +02:00
}
2013-04-28 16:52:41 +02:00
}
else
{
2013-05-03 15:08:08 +02:00
$content [ 'type' ] = 'user' ;
2013-05-03 17:25:11 +02:00
$readonlys [ 'type' ] = true ;
2013-04-28 16:52:41 +02:00
}
2013-05-03 15:08:08 +02:00
//_debug_array($content); exit;
//_debug_array($sel_options); //exit;
return $content ;
2013-04-28 16:52:41 +02:00
}
2014-01-10 10:08:40 +01:00
/**
* Get label for given default value ( s )
*
* @ param string | array $default default value ( s ) to get label for
* @ param array $values values optional including optgroups
2014-10-21 11:15:42 +02:00
* @ param boolean $lang = true
2014-01-10 10:08:40 +01:00
* @ return string comma - separated and translated labels
*/
protected static function get_default_label ( $default , array $values , $lang = true )
{
// explode comma-separated multiple default values
if ( ! is_array ( $default ) && ! isset ( $values [ $default ]) && strpos ( $default , ',' ) !== false )
{
$labels = explode ( ',' , $default );
}
else
{
$labels = ( array ) $default ;
}
foreach ( $labels as & $def )
{
2023-06-15 18:11:04 +02:00
if ( isset ( $values [ $def ]) && ( ! is_array ( $values [ $def ]) || $values [ $def ][ 'value' ] == $def ))
2014-01-10 10:08:40 +01:00
{
$def = is_array ( $values [ $def ]) ? $values [ $def ][ 'label' ] : $values [ $def ];
}
2023-06-15 18:11:04 +02:00
else // value could be in an optgroup or array with label & value keys
2014-01-10 10:08:40 +01:00
{
foreach ( $values as $value )
{
if ( is_array ( $value ) && ! isset ( $value [ 'label' ]) && isset ( $value [ $def ]))
{
$def = is_array ( $value [ $def ]) ? $value [ $def ][ 'label' ] : $value [ $def ];
break ;
}
2023-06-05 16:00:33 +02:00
elseif ( is_array ( $value ) && isset ( $value [ 'label' ]) && $value [ 'value' ] == $def )
{
$def = $value [ 'label' ];
}
2014-01-10 10:08:40 +01:00
}
}
if ( $lang ) $def = lang ( $def );
}
$label = implode ( ', ' , $labels );
//error_log(__METHOD__."(".array2string($default).', '.array2string($values).") returning $label");
return $label ;
}
2013-04-28 16:52:41 +02:00
/**
* Get preferences by calling various hooks to supply them
*
* Sets $this -> appname and $this -> settings
*
2013-05-03 17:25:11 +02:00
* @ param string $appname appname or 'common'
2014-10-21 11:15:42 +02:00
* @ param string $type = 'user' 'default' , 'forced' , 'user' or 'group'
* @ param int | string $account_id = null account_id for user or group prefs , or " forced " or " default "
2013-04-28 16:52:41 +02:00
* @ return boolean
*/
2014-07-18 13:46:10 +02:00
protected function call_hook ( $appname , $type = 'user' , $account_id = null )
2013-04-28 16:52:41 +02:00
{
2013-05-03 17:25:11 +02:00
$this -> appname = $appname == 'common' ? 'preferences' : $appname ;
2013-04-28 16:52:41 +02:00
2013-11-26 18:55:51 +01:00
// Set framework here to make sure we get the right settings for user's [newly] selected template
$GLOBALS [ 'egw_info' ][ 'server' ][ 'template_set' ] = $GLOBALS [ 'egw' ] -> preferences -> data [ 'common' ][ 'template_set' ];
2016-04-30 19:16:36 +02:00
Api\Translation :: add_app ( $this -> appname );
2013-04-28 16:52:41 +02:00
if ( $this -> appname != 'preferences' )
{
2016-04-30 19:16:36 +02:00
Api\Translation :: add_app ( 'preferences' ); // we need the prefs translations too
2013-04-28 16:52:41 +02:00
}
2019-03-20 18:14:31 +01:00
$this -> settings = Api\Preferences :: settings ( $appname , $type , $account_id );
2013-05-03 15:08:08 +02:00
2013-04-28 16:52:41 +02:00
/* Remove ui-only settings */
if ( $this -> xmlrpc )
{
foreach ( $this -> settings as $key => $valarray )
{
if ( ! $valarray [ 'xmlrpc' ])
{
unset ( $this -> settings [ $key ]);
}
}
}
else
{
/* Here we include the settings hook file for the current template , if it exists .
This is not handled by the hooks class and is only valid if not using xml - rpc .
*/
$tmpl_settings = EGW_SERVER_ROOT . $GLOBALS [ 'egw' ] -> framework -> template_dir . '/hook_settings.inc.php' ;
if ( $this -> appname == 'preferences' && file_exists ( $tmpl_settings ))
{
include ( $tmpl_settings );
$this -> settings = array_merge ( $this -> settings , $GLOBALS [ 'settings' ]);
}
}
// check if we have a default/forced value from the settings hook,
// which is NOT stored as default currently
// --> store it as default, to allow to propagate defaults to existing installations
foreach ( $this -> settings as $name => $data )
{
// only set not yet set default prefs, so user is able to unset it again with ""
// (only works with type vfs_*, other types delete empty values!)
if ( ! isset ( $GLOBALS [ 'egw' ] -> preferences -> default [ $appname ][ $name ]) &&
2014-07-24 11:53:04 +02:00
(( string ) $data [ 'default' ] !== '' || ( string ) $data [ 'forced' ] !== '' ))
2013-04-28 16:52:41 +02:00
{
$default = ( string ) $data [ 'forced' ] !== '' ? $data [ 'forced' ] : $data [ 'default' ];
//echo "<p>".__METHOD__."($appname) $this->appname/$appname/$name=$default NOT yet set!</p>\n";
$GLOBALS [ 'egw' ] -> preferences -> default [ $appname ][ $name ] = $default ;
$need_update = true ;
}
}
if ( $need_update )
{
$GLOBALS [ 'egw' ] -> preferences -> save_repository ( false , 'default' , true );
}
if ( $this -> debug )
{
_debug_array ( $this -> settings );
}
return True ;
}
2022-07-19 15:17:16 +02:00
}