diff --git a/admin/admin-cli.php b/admin/admin-cli.php index e2da0c7e7d..18069bd564 100755 --- a/admin/admin-cli.php +++ b/admin/admin-cli.php @@ -89,6 +89,31 @@ switch($action) return list_exit_codes(); default: + // we allow to call admin_cmd classes directly, if they define the constant SETUP_CLI_CALLABLE + if (substr($action,0,2) == '--' && class_exists($class = str_replace('-','_',substr($action,2))) && + is_subclass_of($class,'admin_cmd') && @constant($class.'::SETUP_CLI_CALLABLE')) + { + $args = array(); + $args['domain'] = array_shift($arg0s); // domain must be first argument, to ensure right domain get's selected in header-include + foreach($arg0s as $arg) + { + list($name,$value) = explode('=',$arg,2); + if(property_exists('admin_cmd',$name)) // dont allow to overwrite admin_cmd properties + { + throw new egw_exception_wrong_userinput(lang("Invalid argument '%1' !!!",$arg),90); + } + if (substr($name,-1) == ']') // allow 1-dim. arrays + { + list($name,$sub) = explode('[',substr($name,0,-1),2); + $args[$name][$sub] = $value; + } + else + { + $args[$name] = $value; + } + } + return run_command(new $class($args)); + } usage($action); break; } diff --git a/admin/inc/class.admin_cmd_check_cats.inc.php b/admin/inc/class.admin_cmd_check_cats.inc.php new file mode 100644 index 0000000000..ac171ba460 --- /dev/null +++ b/admin/inc/class.admin_cmd_check_cats.inc.php @@ -0,0 +1,54 @@ + + * @package admin + * @copyright (c) 2012 by Ralf Becker + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @version $Id$ + */ + +/** + * admin command: check categories for not (longer) existing accounts + */ +class admin_cmd_check_cats extends admin_cmd +{ + const SETUP_CLI_CALLABLE = true; + + /** + * Constructor + * + * @param array $data=array() default parm from parent class, no real parameters + */ + function __construct($data=array()) + { + admin_cmd::__construct($data); + } + + /** + * give or remove run rights from a given account and application + * + * @param boolean $check_only=false only run the checks (and throw the exceptions), but not the command itself + * @return string success message + */ + protected function exec($check_only=false) + { + if ($check_only) return true; + + admin_cmd::_instanciate_accounts(); + + return lang("%1 categories of not (longer) existing accounts deleted.", categories::delete_orphans()); + } + + /** + * Return a title / string representation for a given command, eg. to display it + * + * @return string + */ + function __tostring() + { + return lang('Check categories for not (longer) existing accounts'); + } +} diff --git a/phpgwapi/inc/class.accounts.inc.php b/phpgwapi/inc/class.accounts.inc.php index 07140d41f8..61738c03d1 100644 --- a/phpgwapi/inc/class.accounts.inc.php +++ b/phpgwapi/inc/class.accounts.inc.php @@ -529,10 +529,13 @@ class accounts $this->backend->delete($id); + self::cache_invalidate($invalidate); + // delete all acl_entries belonging to that user or group $GLOBALS['egw']->acl->delete_account($id); - self::cache_invalidate($invalidate); + // delete all categories belonging to that user or group + $GLOBALS['egw']->cats->delete_account($id); return true; } diff --git a/phpgwapi/inc/class.categories.inc.php b/phpgwapi/inc/class.categories.inc.php index a96e6ca773..eaa7aba109 100644 --- a/phpgwapi/inc/class.categories.inc.php +++ b/phpgwapi/inc/class.categories.inc.php @@ -129,7 +129,7 @@ class categories $this->app_name = $app_name; $this->db = $GLOBALS['egw']->db; - if (is_null(self::$cache)) // sould not be necessary, as cache is load and restored by egw object + if (is_null(self::$cache)) // should not be necessary, as cache is load and restored by egw object { self::init_cache(); } @@ -994,6 +994,77 @@ class categories } } + /** + * Delete categories belonging to a given account, when account got deleted + * + * @param int $account_id + * @param int $new_owner=null for users data can be transfered to new owner + * @return int number of deleted or modified categories + */ + public static function delete_account($account_id, $new_owner=null) + { + if (is_null(self::$cache)) self::init_cache(); + + $deleted = 0; + foreach(self::$cache as $cat_id => $data) + { + if ($data['owner'] && ($owners = explode(',', $data['owner'])) && ($owner_key = array_search($account_id, $owners)) !== false) + { + // delete category if account_id is single owner and no new owner or owner is a group + if (count($owners) == 1 && (!$new_owner || $account_id < 0)) + { + if (!isset($cat)) + { + $cat = new categories($new_owner, $data['appname']); + } + $cat->delete($cat_id, false, true); + } + else + { + unset($owners[$owner_key]); + if ($new_owner && $account_id > 0) $owners[] = $new_owner; + $data['owner'] = implode(',', $owners); + // app_name have to match cat to update! + if (!isset($cat) || $cat->app_name != $data['appname']) + { + $cat = new categories($new_owner, $data['appname']); + } + $cat->add($data); + } + ++$deleted; + } + } + return $deleted; + } + + /** + * Delete categories with not (longer) existing owners + * + * @return int number of deleted categories + */ + public static function delete_orphans() + { + if (is_null(self::$cache)) self::init_cache(); + + $checked = array(); + $deleted = 0; + foreach(self::$cache as $cat_id => $data) + { + foreach(explode(',', $data['owner']) as $owner) + { + if ($owner && !in_array($owner, $checked)) + { + if (!$GLOBALS['egw']->accounts->exists($owner)) + { + $deleted += self::delete_account($owner); + } + $checked[] = $owner; + } + } + } + return $deleted; + } + /** ******************************** old / deprecated functions *********************************** */