2007-11-27 04:20:28 +01:00
< ? php
/**
2016-04-27 21:12:20 +02:00
* EGgroupware admin - admin command : change an account_id
2007-11-27 04:20:28 +01:00
*
* @ link http :// www . egroupware . org
* @ author Ralf Becker < RalfBecker - AT - outdoor - training . de >
* @ package admin
2018-04-07 12:20:00 +02:00
* @ copyright ( c ) 2007 - 18 by Ralf Becker < RalfBecker - AT - outdoor - training . de >
2007-11-27 04:20:28 +01:00
* @ license http :// opensource . org / licenses / gpl - license . php GPL - GNU General Public License
*/
2016-04-27 21:12:20 +02:00
use EGroupware\Api ;
2012-01-31 09:16:40 +01:00
2007-11-27 04:20:28 +01:00
/**
* admin command : change an account_id
2018-04-07 12:20:00 +02:00
*
* @ property boolean $group_renumbered = false true : group ( s ) have been renumbered by LDAP --> SQL migration ,
* do NOT change egw_accounts . account_id and egw_acl where acl_appname = 'phpgw_group'
2007-11-27 04:20:28 +01:00
*/
2008-11-03 12:03:39 +01:00
class admin_cmd_change_account_id extends admin_cmd
2007-11-27 04:20:28 +01:00
{
/**
* Constructor
*
* @ param array $change array with old => new id pairs
*/
function __construct ( array $change )
{
2008-10-30 12:35:13 +01:00
if ( ! isset ( $change [ 'change' ]))
2007-11-27 04:20:28 +01:00
{
$change = array (
'change' => $change ,
);
}
admin_cmd :: __construct ( $change );
}
/**
2013-06-12 18:57:44 +02:00
* Query changes from all apps
*
* Apps mark columns containing account - ids in " meta " attribute as ( account | user | group )[ - ( abs | commasep | serialized )]
*
* @ return array appname => array ( table => array ( column ( s )))
2007-11-27 04:20:28 +01:00
*/
2013-06-12 18:57:44 +02:00
private function get_changes ()
{
2015-07-24 13:42:55 +02:00
// happens if one used "root_admin" and config-password
if ( empty ( $GLOBALS [ 'egw_info' ][ 'apps' ]))
{
2016-04-27 21:12:20 +02:00
$apps = new Api\Egw\Applications ();
2015-07-24 13:42:55 +02:00
$apps -> read_installed_apps ();
}
$changes = $setup_info = array ();
foreach ( array_keys ( $GLOBALS [ 'egw_info' ][ 'apps' ]) as $app )
2013-06-12 18:57:44 +02:00
{
if ( ! file_exists ( $path = EGW_SERVER_ROOT . '/' . $app . '/setup/setup.inc.php' ) || ! include ( $path )) continue ;
foreach (( array ) $setup_info [ $app ][ 'tables' ] as $table )
{
if ( ! ( $definition = $GLOBALS [ 'egw' ] -> db -> get_table_definitions ( $app , $table ))) continue ;
$cf = array ();
foreach ( $definition [ 'fd' ] as $col => $data )
{
if ( ! empty ( $data [ 'meta' ]))
{
foreach (( array ) $data [ 'meta' ] as $key => $val )
{
2015-07-24 13:42:55 +02:00
list ( $type , $subtype ) = explode ( '-' , $val . '-' );
2013-06-12 18:57:44 +02:00
if ( in_array ( $type , array ( 'account' , 'user' , 'group' )))
{
if ( ! is_numeric ( $key ) || ! empty ( $subtype ))
{
$col = array ( $col );
if ( ! is_numeric ( $key )) $col [] = $key ;
if ( ! empty ( $subtype )) $col [ '.type' ] = $subtype ;
}
$changes [ $app ][ $table ][] = $col ;
}
if ( in_array ( $type , array ( 'cfname' , 'cfvalue' )))
{
$cf [ $type ] = $col ;
}
}
}
}
// we have a custom field table and cfs containing accounts
if ( $cf && ! empty ( $cf [ 'cfname' ]) && ! empty ( $cf [ 'cfvalue' ]) &&
2016-04-27 21:12:20 +02:00
( $account_cfs = Api\Storage\Customfields :: get_account_cfs ( $app == 'phpgwapi' ? 'addressbook' : $app )))
2013-06-12 18:57:44 +02:00
{
foreach ( $account_cfs as $type => $names )
{
unset ( $subtype );
list ( $type , $subtype ) = explode ( '-' , $type );
$col = array ( $cf [ 'cfvalue' ]);
if ( ! empty ( $subtype )) $col [ '.type' ] = $subtype ;
$col [ $cf [ 'cfname' ]] = $names ;
$changes [ $app ][ $table ][] = $col ;
}
}
}
if ( isset ( $changes [ $app ])) ksort ( $changes [ $app ]);
}
ksort ( $changes );
//print_r($changes);
return $changes ;
}
2008-11-03 12:03:39 +01:00
2007-11-27 04:20:28 +01:00
/**
* give or remove run rights from a given account and application
2008-11-03 12:03:39 +01:00
*
2015-07-24 13:42:55 +02:00
* @ param boolean $check_only = false only run the checks ( and throw the exceptions ), but not the command itself
2007-11-27 04:20:28 +01:00
* @ return string success message
2016-04-27 21:12:20 +02:00
* @ throws Api\Exception\Permission\NoAdmin
* @ throws Api\Exception\WrongUserinput ( lang ( " Unknown account: %1 !!! " , $this -> account ), 15 );
* @ throws Api\Exception\WrongUserinput ( lang ( " Application '%1' not found (maybe not installed or misspelled)! " , $name ), 8 );
2007-11-27 04:20:28 +01:00
*/
protected function exec ( $check_only = false )
{
2018-04-07 12:20:00 +02:00
$errors = array ();
2007-11-27 04:20:28 +01:00
foreach ( $this -> change as $from => $to )
{
if ( ! ( int ) $from || ! ( int ) $to )
{
2018-04-07 12:20:00 +02:00
$errors [] = lang ( " Account-id's have to be integers! " );
2007-11-27 04:20:28 +01:00
}
2013-06-12 18:57:44 +02:00
if (( $from < 0 ) != ( $to < 0 ))
{
2018-04-07 12:20:00 +02:00
$errors [] = lang ( " Can NOT change users into groups, same sign required! " );
2013-06-12 18:57:44 +02:00
}
2018-04-07 12:20:00 +02:00
if ( ! $this -> group_renumbered )
2013-06-12 18:57:44 +02:00
{
2018-04-07 12:20:00 +02:00
if ( ! ( $from_exists = $GLOBALS [ 'egw' ] -> accounts -> exists ( $from )))
{
$errors [] = lang ( " Source account #%1 does NOT exist! " , $from );
}
if ( $from_exists !== ( $from > 0 ? 1 : 2 ))
{
$errors [] = lang ( " Group #%1 must have negative sign! " , $from );
}
if ( $GLOBALS [ 'egw' ] -> accounts -> exists ( $to ) && ! isset ( $this -> change [ $to ]))
{
$errors [] = lang ( " Destination account #%1 does exist and is NOT renamed itself! Can not merge Api \ Accounts, it will violate unique contains. Delete with transfer of data instead. " , $to );
}
2013-06-12 18:57:44 +02:00
}
2007-11-27 04:20:28 +01:00
}
2018-04-07 12:20:00 +02:00
if ( $errors )
{
throw new Api\Exception\WrongUserinput ( implode ( " \n " , $errors ), 16 );
}
2013-06-12 18:57:44 +02:00
$columns2change = $this -> get_changes ();
2007-11-27 04:20:28 +01:00
$total = 0 ;
2013-06-12 18:57:44 +02:00
foreach ( $columns2change as $app => $data )
2007-11-27 04:20:28 +01:00
{
2010-04-12 08:45:33 +02:00
if ( ! isset ( $GLOBALS [ 'egw_info' ][ 'apps' ][ $app ])) continue ; // $app is not installed
2007-11-27 04:20:28 +01:00
$db = clone ( $GLOBALS [ 'egw' ] -> db );
$db -> set_app ( $app );
2017-03-09 12:07:14 +01:00
if ( $check_only ) $db -> log_updates = $db -> readonly = true ;
2008-11-03 12:03:39 +01:00
2007-11-27 04:20:28 +01:00
foreach ( $data as $table => $columns )
{
2012-01-31 09:16:40 +01:00
$db -> column_definitions = $db -> get_table_definitions ( $app , $table );
$db -> column_definitions = $db -> column_definitions [ 'fd' ];
2007-11-27 04:20:28 +01:00
if ( ! $columns )
{
echo " $app : $table no columns with account-id's \n " ;
continue ; // noting to do for this table
}
if ( ! is_array ( $columns )) $columns = array ( $columns );
2008-11-03 12:03:39 +01:00
2007-11-27 04:20:28 +01:00
foreach ( $columns as $column )
{
$type = $where = null ;
if ( is_array ( $column ))
{
$type = $column [ '.type' ];
unset ( $column [ '.type' ]);
$where = $column ;
$column = array_shift ( $where );
}
2018-04-07 12:20:00 +02:00
if ( $this -> group_renumbered && $table == 'egw_accounts' && $column == 'account_id' )
{
continue ;
}
if ( $this -> group_renumbered && $table == 'egw_acl' )
{
$where [] = " acl_appname != 'phpgw_group' " ;
}
2008-11-03 12:03:39 +01:00
$total += ( $changed = self :: _update_account_id ( $this -> change , $db , $table , $column , $where , $type ));
2013-06-12 18:57:44 +02:00
if ( ! $check_only && $changed ) echo " $app : \t $table . $column $changed id's changed \n " ;
2007-11-27 04:20:28 +01:00
}
}
}
2013-06-12 18:57:44 +02:00
if ( ! $check_only )
{
foreach ( $GLOBALS [ 'egw_info' ][ 'apps' ] as $app => $data )
{
2018-03-12 21:21:01 +01:00
$total += ( $changed = Api\Framework\Favorites :: change_account_ids ( $app , $this -> change ));
if ( $changed ) echo " $app : \t $changed id's in favorites or index-state changed \n " ;
2013-06-12 18:57:44 +02:00
}
2018-03-14 14:21:36 +01:00
// call hooks, in case apps need additional changes
$args = $this -> change ;
$args [ 'location' ] = 'change_account_ids' ;
foreach ( Api\Hooks :: process ( $args , array (), true ) as $app => $changed )
{
$total += $changed ;
if ( $changed ) echo " $app : \t $changed id's changed by application hook \n " ;
}
2013-06-12 18:57:44 +02:00
}
2016-04-27 21:12:20 +02:00
if ( $total ) Api\Cache :: flush ( Api\Cache :: INSTANCE );
2013-06-12 18:57:44 +02:00
return lang ( " Total of %1 id's changed. " , $total ) . " \n " ;
2007-11-27 04:20:28 +01:00
}
2013-06-12 18:57:44 +02:00
/**
* Update DB with changed account ids
*
* @ param array $ids2change from - id => to - id pairs
2016-04-27 21:12:20 +02:00
* @ param Api\Db $db
2013-06-12 18:57:44 +02:00
* @ param string $table
* @ param string $column
* @ param array $where
* @ param string $type
* @ return int number of changed ids
*/
2016-04-27 21:12:20 +02:00
private static function _update_account_id ( array $ids2change , Api\Db $db , $table , $column , array $where = null , $type = null )
2007-11-27 04:20:28 +01:00
{
2013-06-12 18:57:44 +02:00
$update_sql = '' ;
foreach ( $ids2change as $from => $to )
2007-11-27 04:20:28 +01:00
{
2013-06-12 18:57:44 +02:00
$update_sql .= " WHEN " . $db -> quote ( $from , $db -> column_definitions [ $column ][ 'type' ]) . " THEN " . $db -> quote ( $to , $db -> column_definitions [ $column ][ 'type' ]) . " " ;
2007-11-27 04:20:28 +01:00
}
2013-06-12 18:57:44 +02:00
$update_sql .= 'END' ;
2007-11-27 04:20:28 +01:00
switch ( $type )
{
2013-06-12 18:57:44 +02:00
case 'commasep' :
case 'serialized' :
2007-11-27 04:20:28 +01:00
if ( ! $where ) $where = array ();
2013-06-12 18:57:44 +02:00
$select = $where ;
$select [] = " $column IS NOT NULL " ;
$select [] = " $column != '' " ;
2007-11-27 04:20:28 +01:00
$change = array ();
2013-06-12 18:57:44 +02:00
foreach ( $db -> select ( $table , 'DISTINCT ' . $column , $select , __LINE__ , __FILE__ ) as $row )
2007-11-27 04:20:28 +01:00
{
2015-07-24 13:42:55 +02:00
$ids = $type != 'serialized' ? explode ( ',' , $old_ids = $row [ $column ]) : json_php_unserialize ( $old_ids = $row [ $column ]);
2007-11-27 04:20:28 +01:00
foreach ( $ids as $key => $id )
{
2009-11-20 16:07:26 +01:00
if ( isset ( $ids2change [ $id ])) $ids [ $key ] = $ids2change [ $id ];
2007-11-27 04:20:28 +01:00
}
2015-07-24 13:42:55 +02:00
$ids2 = $type != 'serialized' ? implode ( ',' , $ids ) : serialize ( $ids );
if ( $ids2 != $old_ids )
2007-11-27 04:20:28 +01:00
{
2015-07-24 13:42:55 +02:00
$change [ $old_ids ] = $ids2 ;
2007-11-27 04:20:28 +01:00
}
}
$changed = 0 ;
foreach ( $change as $from => $to )
{
$db -> update ( $table , array ( $column => $to ), $where + array ( $column => $from ), __LINE__ , __FILE__ );
$changed += $db -> affected_rows ();
}
break ;
2008-11-03 12:03:39 +01:00
2013-06-12 18:57:44 +02:00
case 'abs' :
2008-11-03 12:03:39 +01:00
if ( ! $where ) $where = array ();
$where [ $column ] = array ();
2013-06-12 18:57:44 +02:00
foreach ( $ids2change as $from => $to )
2008-11-03 12:03:39 +01:00
{
2013-06-12 18:57:44 +02:00
$where [ $column ][] = abs ( $from );
2008-11-03 12:03:39 +01:00
}
2013-06-12 18:57:44 +02:00
$db -> update ( $table , $column . '= CASE ' . $column . ' ' . preg_replace ( '/-([0-9]+)/' , '\1' , $update_sql ), $where , __LINE__ , __FILE__ );
2008-11-03 12:03:39 +01:00
$changed = $db -> affected_rows ();
break ;
2013-06-12 18:57:44 +02:00
case 'prefs' : // prefs groups are shifted down by 2 as -1 and -2 are for default and forced prefs
2007-11-27 04:20:28 +01:00
if ( ! $where ) $where = array ();
$where [ $column ] = array ();
2013-06-12 18:57:44 +02:00
$update_sql = '' ;
foreach ( $ids2change as $from => $to )
2007-11-27 04:20:28 +01:00
{
2013-06-12 18:57:44 +02:00
if ( $from < 0 ) $from -= 2 ;
if ( $to < 0 ) $to -= 2 ;
$where [ $column ][] = $from ;
$update_sql .= 'WHEN ' . $db -> quote ( $from , $db -> column_definitions [ $column ][ 'type' ]) . ' THEN ' . $db -> quote ( $to , $db -> column_definitions [ $column ][ 'type' ]) . ' ' ;
2007-11-27 04:20:28 +01:00
}
2013-06-12 18:57:44 +02:00
$db -> update ( $table , $column . '= CASE ' . $column . ' ' . $update_sql . 'END' , $where , __LINE__ , __FILE__ );
2007-11-27 04:20:28 +01:00
$changed = $db -> affected_rows ();
break ;
2008-11-03 12:03:39 +01:00
2007-11-27 04:20:28 +01:00
default :
if ( ! $where ) $where = array ();
$where [ $column ] = array_keys ( $ids2change );
$db -> update ( $table , $column . '= CASE ' . $column . ' ' . $update_sql , $where , __LINE__ , __FILE__ );
$changed = $db -> affected_rows ();
break ;
}
return $changed ;
}
/**
* Return a title / string representation for a given command , eg . to display it
*
* @ return string
*/
function __tostring ()
{
$change = array ();
2015-07-24 13:42:55 +02:00
foreach ( $this -> change as $from => $to )
{
$change [] = $from . '->' . $to ;
}
2007-11-27 04:20:28 +01:00
return lang ( 'Change account_id' ) . ': ' . implode ( ', ' , $change );
}
}