From f5e79189ed095c22dbd22e5ac9ba679af3fdf2e2 Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Wed, 24 Jun 2009 00:20:58 -0600 Subject: [PATCH] Convert Maintenance:: (from CVS HEAD) to Horde_LoginTasks::. --- framework/LoginTasks/lib/Horde/LoginTasks.php | 282 +++++++++++++++++++++ framework/LoginTasks/lib/Horde/LoginTasks/Task.php | 85 +++++++ .../LoginTasks/lib/Horde/LoginTasks/Tasklist.php | 148 +++++++++++ framework/LoginTasks/package.xml | 94 +++++++ 4 files changed, 609 insertions(+) create mode 100644 framework/LoginTasks/lib/Horde/LoginTasks.php create mode 100644 framework/LoginTasks/lib/Horde/LoginTasks/Task.php create mode 100644 framework/LoginTasks/lib/Horde/LoginTasks/Tasklist.php create mode 100644 framework/LoginTasks/package.xml diff --git a/framework/LoginTasks/lib/Horde/LoginTasks.php b/framework/LoginTasks/lib/Horde/LoginTasks.php new file mode 100644 index 000000000..88865f39a --- /dev/null +++ b/framework/LoginTasks/lib/Horde/LoginTasks.php @@ -0,0 +1,282 @@ + + * @package Horde_LoginTasks + */ +class Horde_LoginTasks +{ + /* Interval settings. */ + // Do task yearly (First login after/on January 1). + const YEARLY = 1; + // Do task monthly (First login after/on first of month). + const MONTHLY = 2; + // Do task weekly (First login after/on a Sunday). + const WEEKLY = 3; + // Do task daily (First login of the day). + const DAILY = 4; + // Do task every login. + const EVERY = 5; + // Do task on first login only. + const FIRST_LOGIN = 6; + + /* Display styles. */ + const DISPLAY_CONFIRM_NO = 1; + const DISPLAY_CONFIRM_YES = 2; + const DISPLAY_AGREE = 3; + const DISPLAY_NOTICE = 4; + const DISPLAY_NONE = 5; + + /* Priority settings */ + const PRIORITY_HIGH = 1; + const PRIORITY_NORMAL = 2; + + /** + * Singleton instance. + * + * @var array + */ + static protected $_instances = array(); + + /** + * The Horde_LoginTasks_Tasklist object for this login. + * + * @var Horde_LoginTasks_Tasklist + */ + protected $_tasklist; + + /** + * Was the tasklist init'd in this access? + * + * @var boolean + */ + protected $_init = false; + + /** + * Attempts to return a reference to a concrete Horde_LoginTasks + * instance based on $app. It will only create a new instance + * if no instance with the same parameters currently exists. + * + * This method must be invoked as: + * $var = &Horde_LoginTasks::singleton($app[, $params]); + * + * @param string $app See self::__construct(). + * @param string $url The URL to redirect to when finished. + * + * @return Horde_LoginTasks The singleton instance. + */ + static public function singleton($app, $url = null) + { + if (empty(self::$_instances[$app])) { + self::$_instances[$app] = new Horde_LoginTasks($app, $url); + } + + return self::$_instances[$app]; + } + + /** + * Constructor. + * + * @param string $app The name of the Horde application. + * @param string $url The URL to redirect to when finished. + */ + protected function __construct($app, $url) + { + $this->_app = $app; + + /* Retrieves a cached tasklist or make sure one is created. */ + if (isset($_SESSION['horde_logintasks'][$app])) { + $this->_tasklist = unserialize($_SESSION['horde_logintasks'][$app]); + } else { + $this->_createTaskList($url); + $this->_init = true; + } + } + + /** + * Destructor. + */ + public function __destruct() + { + $_SESSION['horde_logintasks'][$this->_app] = serialize($this->_tasklist); + } + + /** + * Creates the list of login tasks that are available for this session + * (stored in a Horde_LoginTasks_Tasklist object). + * + * @param string $url The URL to redirect to when finished. + */ + protected function _createTaskList($url) + { + /* Create a new Horde_LoginTasks_Tasklist object. */ + $this->_tasklist = new Horde_LoginTasks_Tasklist($url); + + /* Get last task run date(s). */ + $old_error = error_reporting(); + $last_logintasks = unserialize($GLOBALS['prefs']->getValue('last_logintasks')); + error_reporting($old_error); + if (!is_array($last_logintasks)) { + $last_logintasks = array(); + } + + /* If this application handles Horde auth, need to add Horde tasks + * here. */ + $app_list = array($this->_app); + if (strnatcasecmp($this->_app, Auth::getProvider()) === 0) { + array_unshift($app_list, 'horde'); + } + + foreach ($app_list as $app) { + $fileroot = $GLOBALS['registry']->get('fileroot', $app); + if (!is_null($fileroot) && + is_dir($fileroot . '/lib/LoginTasks/Task')) { + foreach (scandir($fileroot . '/lib/LoginTasks/Task') as $file) { + if (stripos($file, '.php') !== false) { + $classname = $app . '_LoginTasks_Task_' . substr($file, 0, -4); + if (class_exists($classname)) { + $tasks[$classname] = $app; + if (!isset($lasttasks[$app])) { + $lasttasks[$app] = empty($last_logintasks[$app]) + ? 0 + : getdate($last_logintasks[$app]); + } + } + } + } + } + } + + if (empty($tasks)) { + return; + } + + /* Create time objects for today's date and last task run date. */ + $cur_date = getdate(); + + foreach ($tasks as $classname => $app) { + $ob = new $classname(); + + /* If marked inactive, skip the task. */ + if (!$ob->active) { + continue; + } + + $addtask = false; + + if (empty($lasttasks[$app])) { + /* If timestamp is empty (= 0), this is the first time the + user has logged in. Don't run any other login task + operations on the first login. */ + $addtask = ($ob->interval == self::FIRST_LOGIN); + } else { + switch ($ob->interval) { + case self::YEARLY: + $addtask = ($cur_date['year'] > $lasttasks[$app]['year']); + break; + + case self::MONTHLY: + $addtask = (($cur_date['year'] > $lasttasks[$app]['year']) || ($cur_date['mon'] > $lasttasks[$app]['mon'])); + break; + + case self::WEEKLY: + $addtask = (($cur_date['wday'] < $lasttasks[$app]['wday']) || ((time() - 604800) > $this->_lastRun)); + break; + + case self::DAILY: + $addtask = (($cur_date['year'] > $lasttasks[$app]['year']) || ($cur_date['yday'] > $lasttasks[$app]['yday'])); + break; + + case self::EVERY: + $addtask = true; + break; + } + } + + if ($addtask) { + $this->_tasklist->addTask($ob); + } + } + } + + /** + * Do operations needed for this login. + * + * This function will generate the list of tasks to perform during this + * login and will redirect to the login tasks page if necessary. This is + * the function that should be called from the application upon login. + */ + public function runTasks() + { + if ($this->_tasklist === true) { + return; + } + + /* Perform ready tasks now. */ + foreach ($this->_tasklist->ready() as $key => $val) { + if (($val->display == self::DISPLAY_AGREE) || + ($val->display == self::DISPLAY_NOTICE) || + Horde_Util::getFormData('logintasks_confirm_' . $key)) { + $val->execute(); + } + } + + $need_display = $this->_tasklist->needDisplay(); + $tasklist_target = $this->_tasklist->target; + + /* If we've successfully completed every task in the list (or skipped + * it), record now as the last time login tasks was run. */ + if (empty($need_display)) { + $lasttasks = unserialize($GLOBALS['prefs']->getValue('last_logintasks')); + $lasttasks[$this->_app] = time(); + if (strnatcasecmp($this->_app, Auth::getProvider()) === 0) { + $lasttasks['horde'] = time(); + } + $GLOBALS['prefs']->setValue('last_logintasks', serialize($lasttasks)); + + /* This will prevent us from having to store the entire tasklist + * object in the session, while still indicating we have + * completed the login tasks for this application. */ + $this->_tasklist = true; + } + + if ($this->_init && $need_display) { + header('Location: ' . $this->getLoginTasksUrl()); + exit; + } elseif (!$this->_init && !$need_display) { + header('Location: ' . $tasklist_target); + exit; + } + } + + /** + * Generate the list of tasks that need to be displayed. + * + * This is the function called from the login tasks page every time it + * is loaded. + * + * @return array The list of tasks that need to be displayed. + */ + public function displayTasks() + { + return $this->_tasklist->needDisplay(true); + } + + /** + * Generated the login tasks URL. + * + * @return string The login tasks URL. + */ + public function getLoginTasksUrl() + { + return Horde_Util::addParameter(Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/logintasks.php', true), array('app' => $this->_app)); + } + +} diff --git a/framework/LoginTasks/lib/Horde/LoginTasks/Task.php b/framework/LoginTasks/lib/Horde/LoginTasks/Task.php new file mode 100644 index 000000000..1fc7552ae --- /dev/null +++ b/framework/LoginTasks/lib/Horde/LoginTasks/Task.php @@ -0,0 +1,85 @@ + + * @package Horde_LoginTasks + */ +abstract class Horde_LoginTasks_Task +{ + /** + * Should the task be run? + * + * @var boolean + */ + public $active = true; + + /** + * The interval at which to run the task. + * + * @var integer + */ + public $interval = Horde_LoginTasks::MONTHLY; + + /** + * The style of the page output. + * + * [1] Horde_LoginTasks::DISPLAY_CONFIRM_NO + * Horde_LoginTasks::DISPLAY_CONFIRM_YES + * Each output from describe() will have a checkbox associated + * with it. For each checkbox selected, execute() for that task will + * be run. More than 1 confirmation message can be displayed on the + * confirmation page at once. + * + * DISPLAY_CONFIRM_YES will be checked by default, DISPLAY_CONFIRM_NO + * will be unchecked by default. + * + * [2] Horde_LoginTasks::DISPLAY_AGREE + * The output from describe() should be text asking the user to + * agree/disagree to specified terms. If 'yes' is selected, the POST + * variable 'agree' will be set. If 'no' is selected, the POST variable + * 'not_agree' will be set. In either case, execute() will ALWAYS be + * run. + * This style will be displayed on its own confirmation page. + * + * [3] Horde_LoginTasks::DISPLAY_NOTICE + * The output from describe() should be any non-interactive text + * desired. There will be a single 'Click to Continue' button below + * this text. execute() will ALWAYS be run. + * This style will be displayed on its own confirmation page. + * + * [4] Horde_LoginTasks::DISPLAY_NONE + * Don't display any confirmation to the user. + * + * @var integer + */ + public $display = Horde_LoginTasks::DISPLAY_CONFIRM_YES; + + /** + * The priority of the task. + * + * @var integer + */ + public $priority = Horde_LoginTasks::PRIORITY_NORMAL; + + /** + * Do login task (if it has been confirmed). + * + * @return boolean Whether the login task was successful. + */ + abstract public function execute(); + + /** + * Return description information for the login task. + * + * @return string Description that will be displayed on the login task + * confirmation page. + */ + abstract public function describe(); + +} diff --git a/framework/LoginTasks/lib/Horde/LoginTasks/Tasklist.php b/framework/LoginTasks/lib/Horde/LoginTasks/Tasklist.php new file mode 100644 index 000000000..af5dc0516 --- /dev/null +++ b/framework/LoginTasks/lib/Horde/LoginTasks/Tasklist.php @@ -0,0 +1,148 @@ + + * @package Horde_LoginTasks + */ +class Horde_LoginTasks_Tasklist +{ + /** + * The URL of the web page to load after login tasks are complete. + * + * @var string + */ + public $target; + + /** + * The list of tasks to run during this login. + * + * KEY: Task name + * VALUE: array => ( + * 'display' => boolean, + * 'task' => integer + * ) + * + * @var array + */ + protected $_tasks = array(); + + /** + * Internal flag for addTask(). + * + * @var boolean + */ + protected $_addFlag = false; + + /** + * Current task location pointer. + * + * @var integer + */ + protected $_ptr = null; + + /** + * Constructor. + * + * @param string $url The target URL to redirect to when finished. + */ + public function __construct($url) + { + $this->target = $url; + } + + /** + * Adds a task to the tasklist. + * + * @param Horde_LoginTasks_Task $task The task to execute. + */ + public function addTask($task) + { + $tmp = array( + 'display' => false, + 'task' => $task + ); + + if (($task->display == Horde_LoginTasks::DISPLAY_AGREE) || + ($task->display == Horde_LoginTasks::DISPLAY_NOTICE)) { + $tmp['display'] = true; + $this->_addFlag = false; + } elseif (($task->display != Horde_LoginTasks::DISPLAY_NONE) && + !$this->_addFlag) { + $tmp['display'] = true; + $this->_addFlag = true; + } + + switch ($task->priority) { + case Horde_LoginTasks::PRIORITY_HIGH: + array_unshift($this->_tasks, $tmp); + break; + + case Horde_LoginTasks::PRIORITY_NORMAL: + $this->_tasks[] = $tmp; + break; + } + } + + /** + * Returns the list of tasks to perform. + * + * @return array The list of tasks to perform. + */ + public function ready() + { + $tmp = array(); + + reset($this->_tasks); + while (list($k, $v) = each($this->_tasks)) { + if ($v['display'] && + (is_null($this->_ptr) || ($k > $this->_ptr))) { + break; + } + $tmp[] = $v['task']; + } + + if (!is_null($this->_ptr)) { + $this->_tasks = array_slice($this->_tasks, $this->_ptr); + $this->_ptr = 0; + } + + return $tmp; + } + + /** + * Returns the next batch of tasks that need display. + * + * @param boolean $advance If true, advance the internal pointer. + * + * @return array The list of tasks to display. + */ + public function needDisplay($advance = false) + { + $tmp = array(); + $display = null; + + reset($this->_tasks); + while (list($k, $v) = each($this->_tasks)) { + if (!$v['display'] || + (!is_null($display) && ($v['task']->display != $display))) { + break; + } + $tmp[] = $v['task']; + $display = $v['task']->display; + } + + if ($advance) { + $this->_ptr = count($tmp); + } + + return $tmp; + } + +} diff --git a/framework/LoginTasks/package.xml b/framework/LoginTasks/package.xml new file mode 100644 index 000000000..dd1514bce --- /dev/null +++ b/framework/LoginTasks/package.xml @@ -0,0 +1,94 @@ + + + LoginTasks + pear.horde.org + Horde Login Tasks System + The Horde_LoginTasks:: class provides a set of methods for dealing with tasks run upon login to Horde applications. + + + Michael Slusarz + slusarz + slusarz@horde.org + yes + + 2009-06-23 + + 0.1.0 + 0.1.0 + + + beta + beta + + LGPL + * Renamed Maintenance:: -> Horde_LoginTasks::. + * Initial Horde 4 package. + + + + + + + + + + + + + + + + + 5.2.0 + + + 1.5.4 + + + Util + pear.horde.org + + + + + + + + + + + + + 2006-05-08 + + + 0.0.2 + 0.0.2 + + + alpha + alpha + + LGPL + Converted to package.xml 2.0 for pear.horde.org + + + 2003-07-05 + + 0.0.1 + 0.0.1 + + + alpha + alpha + + LGPL + Initial release as a PEAR package + + + + + -- 2.11.0