diff options
-rw-r--r-- | modules/gallery/controllers/admin_maintenance.php | 7 | ||||
-rw-r--r-- | modules/gallery/helpers/task.php | 9 | ||||
-rw-r--r-- | modules/gallery/views/admin_maintenance.html.php | 8 | ||||
-rw-r--r-- | modules/scheduler/controllers/admin_schedule.php | 105 | ||||
-rw-r--r-- | modules/scheduler/helpers/scheduler.php | 133 | ||||
-rw-r--r-- | modules/scheduler/helpers/scheduler_event.php | 64 | ||||
-rw-r--r-- | modules/scheduler/helpers/scheduler_installer.php | 42 | ||||
-rw-r--r-- | modules/scheduler/models/schedule.php | 33 | ||||
-rw-r--r-- | modules/scheduler/module.info | 3 | ||||
-rw-r--r-- | modules/scheduler/views/admin_schedule.html.php | 11 | ||||
-rw-r--r-- | modules/scheduler/views/admin_schedule_confirm.html.php | 4 | ||||
-rw-r--r-- | modules/scheduler/views/scheduler_definitions.html.php | 49 |
12 files changed, 464 insertions, 4 deletions
diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php index 3062ea09..487e77a6 100644 --- a/modules/gallery/controllers/admin_maintenance.php +++ b/modules/gallery/controllers/admin_maintenance.php @@ -44,6 +44,8 @@ class Admin_Maintenance_Controller extends Admin_Controller { $view->content->task_definitions = task::get_definitions(); $view->content->running_tasks = ORM::factory("task") ->where("done", "=", 0)->order_by("updated", "DESC")->find_all(); + $view->content->schedule_definitions = + module::is_active("scheduler") ? scheduler::get_definitions() : ""; $view->content->finished_tasks = ORM::factory("task") ->where("done", "=", 1)->order_by("updated", "DESC")->find_all(); print $view; @@ -56,13 +58,10 @@ class Admin_Maintenance_Controller extends Admin_Controller { public function start($task_callback) { access::verify_csrf(); - $tasks = task::get_definitions(); - $task = task::create($tasks[$task_callback], array()); + $task = task::start($task_callback); $view = new View("admin_maintenance_task.html"); $view->task = $task; - $task->log(t("Task %task_name started (task id %task_id)", - array("task_name" => $task->name, "task_id" => $task->id))); log::info("tasks", t("Task %task_name started (task id %task_id)", array("task_name" => $task->name, "task_id" => $task->id)), html::anchor("admin/maintenance", t("maintenance"))); diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php index 645850d1..aa0eb94d 100644 --- a/modules/gallery/helpers/task.php +++ b/modules/gallery/helpers/task.php @@ -35,6 +35,15 @@ class task_Core { return $tasks; } + static function start($task_callback, $context=array()) { + $tasks = task::get_definitions(); + $task = task::create($tasks[$task_callback], array()); + + $task->log(t("Task %task_name started (task id %task_id)", + array("task_name" => $task->name, "task_id" => $task->id))); + return $task; + } + static function create($task_def, $context) { $task = ORM::factory("task"); $task->callback = $task_def->callback; diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index ac597715..15d04caa 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -33,12 +33,20 @@ class="g-dialog-link g-button ui-icon-left ui-state-default ui-corner-all"> <?= t("run") ?> </a> + <? if (module::is_active("scheduler")): ?> + <a href="<?= url::site("form/add/admin/schedule/$task->callback?csrf=$csrf") ?>" + class="g-dialog-link g-button ui-icon-left ui-state-default ui-corner-all"> + <?= t("schedule") ?> + </a> + <? endif ?> </td> </tr> <? endforeach ?> </table> </div> + <?= $schedule_definitions ?> + <? if ($running_tasks->count()): ?> <div id="g-running-tasks"> <h2> <?= t("Running tasks") ?> </h2> diff --git a/modules/scheduler/controllers/admin_schedule.php b/modules/scheduler/controllers/admin_schedule.php new file mode 100644 index 00000000..6911cf86 --- /dev/null +++ b/modules/scheduler/controllers/admin_schedule.php @@ -0,0 +1,105 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Admin_Schedule_Controller extends Admin_Controller { + public function form_add($task_callback) { + access::verify_csrf(); + + $schedule = ORM::factory("schedule"); + $schedule->task_callback = $task_callback; + $schedule->next_run_datetime = time(); + $v = new View("admin_schedule.html"); + $v->form = scheduler::get_form("define", $schedule); + $v->method = "define"; + print $v; + } + + public function update_form($id) { + access::verify_csrf(); + + + $schedule = ORM::factory("schedule", $id); + $v = new View("admin_schedule.html"); + $v->form = scheduler::get_form("update", $schedule); + $v->method = "update"; + print $v; + } + + public function remove_form($id) { + access::verify_csrf(); + + $schedule = ORM::factory("schedule", $id); + + $v = new View("admin_schedule_confirm.html"); + $v->name = $schedule->name; + $v->form = new Forge("admin/schedule/remove/{$id}", "", "post", + array("id" => "g-remove-schedule")); + $group = $v->form->group("remove"); + $group->submit("")->value(t("Continue")); + print $v; + } + + public function remove($id) { + access::verify_csrf(); + $schedule = ORM::factory("schedule", $id); + $schedule->delete(); + + message::success(t("Removed scheduled task: %name", array("name" => $schedule->name))); + print json_encode(array("result" => "success", "reload" => 1)); + } + + public function define() { + $this->_handle_request("define"); + } + + public function update($id=null) { + $this->_handle_request("update", $id); + } + + private function _handle_request($method, $id=null) { + $schedule = ORM::factory("schedule", $id); + $form = scheduler::get_form($method, $schedule); + $valid = $form->validate(); + if ($valid) { + $schedule->name = $form->schedule_group->schedule_name->value; + $schedule->interval = $form->schedule_group->interval->value; + $schedule->next_run_datetime = + $this->_start_date($form->schedule_group->run_date->dow->selected, + $form->schedule_group->run_date->time->value); + $schedule->task_callback = $form->schedule_group->callback->value; + $schedule->save(); + if ($method == "define") { + message::success(t("Added scheduled task: %name", array("name" => $schedule->name))); + } else { + message::success(t("Updated scheduled task: %name", array("name" => $schedule->name))); + } + print json_encode(array("result" => "success", "reload" => 1)); + } else { + print json_encode(array("result" => "error", "form" => (string) $form)); + } + } + + private function _start_date($dow, $time) { + list ($hour, $minutes) = explode(":", $time); + $local_time = localtime(); + $days = ($dow < $local_time[6] ? 7 : 0) + $dow - $local_time[6]; + return + mktime($hour, $minutes, 0, $local_time[4] + 1, $local_time[3] + $days, 1900 + $local_time[5]); + } +} diff --git a/modules/scheduler/helpers/scheduler.php b/modules/scheduler/helpers/scheduler.php new file mode 100644 index 00000000..987b1b32 --- /dev/null +++ b/modules/scheduler/helpers/scheduler.php @@ -0,0 +1,133 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class scheduler_Core { + + static function intervals() { + static $intervals; + if (empty($intervals)) { + $intervals = array("3600" => t("Hourly"), "86400" => t("Daily"), + "604800" => t("Weekly"), "2419200" => t("Monthly")); + } + return $intervals; + } + + static function get_form($method, $schedule) { + if ($method == "define") { + $title = t("Create a scheduled event"); + $button_text = t("Create"); + } else { + $title = t("Update a scheduled event"); + $button_text = t("Update"); + } + + $id = empty($schedule->id) ? "" : "/$schedule->id"; + $form = new Forge("admin/schedule/$method{$id}", "", "post", + array("id" => "g-{$method}-schedule")); + $group = $form->group("schedule_group")->label($title); + $group->input("schedule_name") + ->label(t("Description")) + ->id("g-schedule-name") + ->rules("required|length[0, 128]") + ->error_messages("required", t("You must provide a description")) + ->error_messages("length", t("Your description is too long")) + ->value(!empty($schedule->name) ? $schedule->name : ""); + + list ($dow, $display_time) = scheduler::format_time($schedule->next_run_datetime); + $next = $group->group("run_date")->label(t("Scheduled Date")); + $next->dropdown("dow") + ->label(t("Day")) + ->id("g-schedule-day") + ->rules("required") + ->options(array(t("Sunday"), t("Monday"), t("Tuesday"), t("Wednesday"), + t("Thursday"), t("Friday"), t("Saturday"))) + ->selected($dow); + + $next->input("time") + ->label(t("Hour")) + ->id("g-schedule-time") + ->rules("required") + ->error_messages("required", t("You must provide a time")) + ->error_messages("time_invalid", t("Invalid time")) + ->callback("scheduler::valid_time") + ->value($display_time); + + // need to set the top padding to zero on g-define-schedule li.g-error + $group->dropdown("interval")->label(t("How often"))->id("g-schedule-frequency") + ->options(scheduler::intervals()) + ->rules("required") + ->error_messages("required", t("You must provide an interval")) + ->selected(!empty($schedule->interval) ? $schedule->interval : "2419200"); + $group->hidden("callback")->value($schedule->task_callback); + $group->submit("")->value($button_text); + + return $form; + } + + static function format_time($time) { + $local_time = localtime($time); + $display_time = str_pad($local_time[2], 2, "0", STR_PAD_LEFT) . ":" . + str_pad($local_time[1], 2, "0", STR_PAD_LEFT); + return array($local_time[6], $display_time); + } + + static function valid_time($field) { + if (preg_match("/([0-9]{1,2}):([0-9]{2})/", $field->value, $matches)) { + $hour = (int)$matches[1]; + $minutes = (int)$matches[2]; + if (!(0 <= $hour && $hour<= 23 || 0 <= $minutes && $minutes <= 59)) { + $field->add_error("time_invalid", 1); + } + } else { + $field->add_error("time_invalid", 1); + } + } + + static function get_definitions() { + $v = ""; + $events = ORM::factory("schedule") + ->order_by("next_run_datetime", "asc") + ->find_all(); + if ($events->count()) { + $v = new View("scheduler_definitions.html"); + $v->schedule_definitions = array(); + foreach ($events as $schedule) { + $entry[] = $schedule->id; + $entry[] = $schedule->name; + $run_date = strftime("%A, %b %e, %Y %H:%M ", $schedule->next_run_datetime); + $intervals = scheduler::intervals(); + $interval = $intervals[$schedule->interval]; + if (!empty($schedule->task_id)) { + $status = t("Running"); + } else if ($schedule->next_run_datetime < time()) { + $status = t("Overdue"); + } else { + $status = t("Scheduled"); + } + + $v->schedule_definitions[] = (object)array("id" => $schedule->id, + "name" => $schedule->name, + "run_date" => $run_date, + "interval" => $interval, + "status" => $status); + } + } + return $v; + } +}
\ No newline at end of file diff --git a/modules/scheduler/helpers/scheduler_event.php b/modules/scheduler/helpers/scheduler_event.php new file mode 100644 index 00000000..365b1df1 --- /dev/null +++ b/modules/scheduler/helpers/scheduler_event.php @@ -0,0 +1,64 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +class scheduler_event_Core { + /** + * At this point, the output has been sent to the browser, so we can take some time + * to run a schedule task. + */ + static function gallery_shutdown() { + try { + $schedule = ORM::factory("schedule") + ->where("next_run_datetime", "<=", time()) + ->where("busy", "!=", 1) + ->order_by("next_run_datetime") + ->find_all(1); + + if ($schedule->count()) { + $schedule = $schedule->current(); + $schedule->busy = true; + $schedule->save(); + + try { + if (empty($schedule->task_id)) { + $task = task::start($schedule->task_callback); + $schedule->task_id = $task->id; + } + + $task = task::run($schedule->task_id); + + if ($task->done) { + $schedule->next_run_datetime += $schedule->interval; + $schedule->task_id = null; + } + + $schedule->busy = false; + $schedule->save(); + } catch (Exception $e) { + $schedule->busy = false; + $schedule->save(); + throw $e; + } + } + } catch (Exception $e) { + Kohana_Log::add("error", (string)$e); + } + } +} diff --git a/modules/scheduler/helpers/scheduler_installer.php b/modules/scheduler/helpers/scheduler_installer.php new file mode 100644 index 00000000..46be4a81 --- /dev/null +++ b/modules/scheduler/helpers/scheduler_installer.php @@ -0,0 +1,42 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class scheduler_installer { + static function install() { + $db = Database::instance(); + $db->query("CREATE TABLE {schedules} ( + `id` int(9) NOT NULL auto_increment, + `name` varchar(128) NOT NULL, + `task_callback` varchar(128) NOT NULL, + `task_id` int(9) NULL, + `next_run_datetime` int(9) NOT NULL, + `interval` int(9) NOT NULL, + `busy` bool NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + KEY `run_date` (`next_run_datetime`, `busy`), + UNIQUE KEY (`name`)) + DEFAULT CHARSET=utf8;"); + module::set_version("scheduler", $version = 1); + } + + static function uninstall() { + $db = Database::instance(); + $db->query("DROP TABLE IF EXISTS {schedules}"); + } +} diff --git a/modules/scheduler/models/schedule.php b/modules/scheduler/models/schedule.php new file mode 100644 index 00000000..b83b5738 --- /dev/null +++ b/modules/scheduler/models/schedule.php @@ -0,0 +1,33 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2009 Bharat Mediratta + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Schedule_Model extends ORM { + public function tasks() { + return ORM::factory("task") + ->join("schedules_tasks", "task.id", "schedules_tasks.task_id") + ->where("schedule_id", "=", $this->id) + ->find_all(); + } + + public function add_task($task) { + db::build() + ->insert("schedules_tasks", array("schedule_id" => $this->id,"task_id" => $task->id)) + ->execute(); + } +} diff --git a/modules/scheduler/module.info b/modules/scheduler/module.info new file mode 100644 index 00000000..15355dfb --- /dev/null +++ b/modules/scheduler/module.info @@ -0,0 +1,3 @@ +name = "Scheduler" +description = "Schedule tasks to run at specific times and intervals" +version = 1 diff --git a/modules/scheduler/views/admin_schedule.html.php b/modules/scheduler/views/admin_schedule.html.php new file mode 100644 index 00000000..3d45dc53 --- /dev/null +++ b/modules/scheduler/views/admin_schedule.html.php @@ -0,0 +1,11 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<style> +#g-define-schedule fieldset fieldset li { + margin-right: .5em; +} + +#g-schedule-time { + width: 40px !important; +} +</style> +<?= $form ?> diff --git a/modules/scheduler/views/admin_schedule_confirm.html.php b/modules/scheduler/views/admin_schedule_confirm.html.php new file mode 100644 index 00000000..5d09654d --- /dev/null +++ b/modules/scheduler/views/admin_schedule_confirm.html.php @@ -0,0 +1,4 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<h1 style="display:none"><?= t("Confirm task removal") ?></h1> +<p class="g-warning"><?= t("Really remove the task: %name", array("name" => $name)) ?></p> +<?= $form ?> diff --git a/modules/scheduler/views/scheduler_definitions.html.php b/modules/scheduler/views/scheduler_definitions.html.php new file mode 100644 index 00000000..0ab46f2b --- /dev/null +++ b/modules/scheduler/views/scheduler_definitions.html.php @@ -0,0 +1,49 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<div id="g-sheduled-tasks"> + <h2> <?= t("Scheduled tasks") ?> </h2> + <table> + <tr> + <th> + <?= t("Name") ?> + </th> + <th> + <?= t("Next run") ?> + </th> + <th> + <?= t("Interval") ?> + </th> + <th> + <?= t("Status") ?> + </th> + <th> + <?= t("Action") ?> + </th> + </tr> + <? foreach ($schedule_definitions as $entry): ?> + <tr class="<?= text::alternate("g-odd", "g-even") ?>"> + <td> + <?= html::clean($entry->name) ?> + </td> + <td> + <?= html::clean($entry->run_date) ?> + </td> + <td> + <?= html::clean($entry->interval) ?> + </td> + <td> + <?= html::clean($entry->status) ?> + </td> + <td> + <a href="<?= url::site("admin/schedule/update_form/$entry->id?csrf=$csrf") ?>" + class="g-dialog-link g-button ui-icon-left ui-state-default ui-corner-all"> + <?= t("edit") ?> + </a> + <a href="<?= url::site("admin/schedule/remove_form/$entry->id?csrf=$csrf") ?>" + class="g-dialog-link g-button ui-icon-left ui-state-default ui-corner-all"> + <?= t("remove") ?> + </a> + </td> + </tr> + <? endforeach ?> + </table> +</div> |