From 495c76f729372e09f7511967c63948e36303e3d7 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 2 Jul 2009 05:11:03 -0700 Subject: Eliminate temporary variables by passing the $item into the view and making API calls on the item. --- modules/server_add/views/server_add_tree_dialog.html.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 8b296987..e2aa5d44 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -7,17 +7,17 @@ });
-

p::clean($album_title))) ?>

+

p::clean($item->title))) ?>

- "post")) ?> + "post")) ?>
-- cgit v1.2.3 From e5b6193b26cf0f8509a98f7913a1d87fa354da05 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 2 Jul 2009 11:23:40 -0700 Subject: Partial pass of server_add cleanup. It's broken at this stage since I've redone the browsing code but I have not implemented the adding code. 1) Rename index() to browse() since index is too generic. 2) Simplify the data that we pass to _dialog and _tree 3) Change _tree to return list items only, so that the outer dialog can be a
    for consistency. 4) Simplify the data structures so that we're not tracking checked vs. unchecked status in the PHP code, it's all done in jquery where we can do it with just a line or two of JS 5) use glob() which pretty much entirely replaces _get_children --- modules/server_add/controllers/server_add.php | 103 +++++++++------------ modules/server_add/helpers/server_add_menu.php | 2 +- modules/server_add/js/server_add.js | 52 +++++++++-- modules/server_add/views/server_add_tree.html.php | 29 +++--- .../views/server_add_tree_dialog.html.php | 25 ++--- 5 files changed, 117 insertions(+), 94 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index 4cd3cec7..45ec0a2e 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -18,26 +18,38 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Server_Add_Controller extends Controller { - public function index($id) { - $paths = unserialize(module::get_var("server_add", "authorized_paths")); - + public function browse($id) { if (!user::active()->admin) { access::forbidden(); } + + $paths = unserialize(module::get_var("server_add", "authorized_paths")); + foreach (array_keys($paths) as $path) { + $files[$path] = basename($path); + } + $item = ORM::factory("item", $id); $view = new View("server_add_tree_dialog.html"); $view->item = $item; + $view->tree = new View("server_add_tree.html"); + $view->tree->files = $files; + print $view; + } - $tree = new View("server_add_tree.html"); - $tree->data = array(); - $tree->checked = false; - $tree->tree_id = "tree_$id"; - foreach (array_keys($paths) as $path) { - $tree->data[$path] = array("path" => $path, "is_dir" => true); + private function _validate_path($path) { + if (!is_readable($path) || is_link($path)) { + throw new Exception("@todo BAD_PATH"); } - $view->tree = $tree->__toString(); - print $view; + + $authorized_paths = unserialize(module::get_var("server_add", "authorized_paths")); + foreach (array_keys($authorized_paths) as $valid_path) { + if (strpos($path, $valid_path) === 0) { + return; + } + } + + throw new Exception("@todo BAD_PATH"); } public function children() { @@ -45,31 +57,32 @@ class Server_Add_Controller extends Controller { access::forbidden(); } - $paths = unserialize(module::get_var("server_add", "authorized_paths")); - $path_valid = false; - $path = $this->input->post("path"); - $checked = $this->input->post("checked") == "true"; + $path = $this->input->get("path"); + $this->_validate_path($path); - foreach (array_keys($paths) as $valid_path) { - if ($path_valid = strpos($path, $valid_path) === 0) { - break; + $tree = new View("server_add_tree.html"); + $tree->files = array(); + $tree->tree_id = substr(md5($path), 10); + + foreach (glob("$path/*") as $file) { + if (!is_readable($file)) { + continue; } - } - if (empty($path_valid)) { - throw new Exception("@todo BAD_PATH"); - } - if (!is_readable($path) || is_link($path)) { - kohana::show_404(); - } + if (!is_dir($file)) { + $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); + if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) { + continue; + } + } - $tree = new View("server_add_tree.html"); - $tree->data = $this->_get_children($path); - $tree->checked = $checked; - $tree->tree_id = "tree_" . md5($path); + $tree->files[$file] = basename($file); + } print $tree; } + /* ================================================================================ */ + function start($id) { if (!user::active()->admin) { access::forbidden(); @@ -237,36 +250,4 @@ class Server_Add_Controller extends Controller { return $count; } - - private function _get_children($path) { - $directory_list = $file_list = array(); - $files = new DirectoryIterator($path); - foreach ($files as $file) { - if ($file->isDot() || $file->isLink()) { - continue; - } - $filename = $file->getFilename(); - if ($filename[0] != ".") { - if ($file->isDir()) { - $directory_list[$filename] = array("path" => $file->getPathname(), "is_dir" => true); - } else { - $extension = strtolower(substr(strrchr($filename, '.'), 1)); - if ($file->isReadable() && - in_array($extension, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) { - $file_list[$filename] = array("path" => $file->getPathname(), "is_dir" => false); - } - } - } - } - - ksort($directory_list); - ksort($file_list); - - // We can't use array_merge here because if a file name is numeric, it will - // get renumbered, so lets do it ourselves - foreach ($file_list as $file => $fileinfo) { - $directory_list[$file] = $fileinfo; - } - return $directory_list; - } } \ No newline at end of file diff --git a/modules/server_add/helpers/server_add_menu.php b/modules/server_add/helpers/server_add_menu.php index 23878913..0f01eb64 100644 --- a/modules/server_add/helpers/server_add_menu.php +++ b/modules/server_add/helpers/server_add_menu.php @@ -38,7 +38,7 @@ class server_add_menu_Core { $server_add = Menu::factory("dialog") ->id("server_add") ->label(t("Add from server")) - ->url(url::site("server_add/index/$item->id")); + ->url(url::site("server_add/browse/$item->id")); $add_photos_item = $menu->get("add_photos_item"); $add_photos_menu = $menu->get("add_photos_menu"); diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js index e2526dbe..47340c45 100644 --- a/modules/server_add/js/server_add.js +++ b/modules/server_add/js/server_add.js @@ -1,3 +1,44 @@ +function open_close_branch(path, id) { + var parent = $("#file_" + id); + var children = $("#tree_" + id); + var icon = parent.find(".ui-icon:first"); + + if (!children.html()) { + parent.addClass("gLoadingSmall"); + $.ajax({ + url: GET_CHILDREN_URL.replace("__PATH__", path), + success: function(data, textStatus) { + children.html(data); + parent.removeClass("gLoadingSmall"); + + // Propagate checkbox value + children.find("input[type=checkbox]").attr( + "checked", parent.find("input[type=checkbox]:first").attr("checked")); + }, + }); + } + + children.slideToggle("fast", function() { + if (children.is(":hidden")) { + icon.addClass("ui-icon-plus"); + icon.removeClass("ui-icon-minus"); + } else { + icon.addClass("ui-icon-minus"); + icon.removeClass("ui-icon-plus"); + parent.removeClass("gCollapsed"); + } + }); +} + +function click_node(checkbox) { + var parent = $(checkbox).parents("li").get(0); + var checked = $(checkbox).attr("checked"); + $(parent).find("input[type=checkbox]").attr("checked", checked); +} + +/* ================================================================================ */ + +/* var paused = false; var task = null; @@ -82,16 +123,6 @@ function get_url(uri, task_id) { return url; } -function checkbox_click(checkbox) { - var parent = $(checkbox).parents("li").get(0); - var checked = $(checkbox).attr("checked"); - if (!$(parent).hasClass("gCollapsed")) { - $(parent).find(".gCheckboxTree input[type=checkbox]").attr("checked", checked); - } - var checkboxes = $("#gServerAdd :checkbox[checked]"); - $("#gServerAdd form :submit").attr("disabled", checkboxes.length == 0); -} - function load_children(icon) { $("#gDialog").addClass("gDialogLoadingLarge"); var parent = icon.parentNode; @@ -203,3 +234,4 @@ function display_upload_error(error) { }); } +*/ diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php index 44f6bfbc..f8205a8b 100644 --- a/modules/server_add/views/server_add_tree.html.php +++ b/modules/server_add/views/server_add_tree.html.php @@ -1,12 +1,19 @@ -
      - $file_info): ?> -
    • "> - - - - - -
    • - -
    + $name): ?> + +
  • "> + + + + + + + +
  • + + +
  • + diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index e2aa5d44..6e4db620 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -1,26 +1,29 @@ - +

    p::clean($item->title))) ?>

      parents() as $parent): ?> -
    • title) ?>
    • +
    • + title) ?> +
    • -
    • title) ?>
    • +
    • + title) ?> +
    - "post")) ?> -
    + "post")) ?> + +
      -
    +
+ "gServerPauseButton", "name" => "add", "disabled" => true, "class" => "submit", "style" => "display:none"), t("Pause")) ?> "gServerAddButton", "name" => "add", "disabled" => true, "class" => "submit"), t("Add")) ?> -- cgit v1.2.3 From d4075a4657eddcf1aca71de9996a421cd577ec36 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 2 Jul 2009 11:49:45 -0700 Subject: Only enable the [add] button when boxes are checked. --- modules/server_add/js/server_add.js | 8 ++++++++ modules/server_add/views/server_add_tree_dialog.html.php | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js index 918bd14b..ada09d65 100644 --- a/modules/server_add/js/server_add.js +++ b/modules/server_add/js/server_add.js @@ -41,6 +41,14 @@ function click_node(checkbox) { var parent = $(checkbox).parents("li").get(0); var checked = $(checkbox).attr("checked"); $(parent).find("input[type=checkbox]").attr("checked", checked); + + if ($("#gServerAddTree").find("input[type=checkbox]").is(":checked")) { + $("#gServerAddAddButton").attr("disabled", true); + $("#gServerAddAddButton").removeClass("ui-state-disabled"); + } else { + $("#gServerAddAddButton").attr("disabled", false); + $("#gServerAddAddButton").addClass("ui-state-disabled"); + } } /* ================================================================================ */ diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 6e4db620..723d388e 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -25,8 +25,10 @@ - "gServerPauseButton", "name" => "add", "disabled" => true, "class" => "submit", "style" => "display:none"), t("Pause")) ?> - "gServerAddButton", "name" => "add", "disabled" => true, "class" => "submit"), t("Add")) ?> + " style="display: none"> + "> -- cgit v1.2.3 From faabae5dae712ebff656abe8ebc493d8e031d4a3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 7 Jul 2009 21:16:36 -0700 Subject: Rework server_add. It's smaller and leaner now, storing the list of files out in a separate model for scalability. Removed the "pause" functionality. - Server_Add_Controller extends Admin_Controller so that we don't have to check for admin every time. - Task completion time now factors in the time it takes to walk the arbitrarily deep trees - Moved checkbox management entirely into JS using jQuery - Simplified the JS considerably --- modules/server_add/controllers/server_add.php | 348 ++++++++++----------- modules/server_add/helpers/server_add.php | 15 + .../server_add/helpers/server_add_installer.php | 22 +- modules/server_add/helpers/server_add_task.php | 85 ----- modules/server_add/js/server_add.js | 222 ++----------- modules/server_add/models/server_add_file.php | 21 ++ modules/server_add/module.info | 2 +- .../views/server_add_tree_dialog.html.php | 23 +- 8 files changed, 266 insertions(+), 472 deletions(-) delete mode 100644 modules/server_add/helpers/server_add_task.php create mode 100644 modules/server_add/models/server_add_file.php (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index e2b1b01a..288e6342 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -17,13 +17,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Server_Add_Controller extends Controller { +class Server_Add_Controller extends Admin_Controller { public function browse($id) { - if (!user::active()->admin) { - access::forbidden(); - } - - $paths = unserialize(module::get_var("server_add", "authorized_paths")); foreach (array_keys($paths) as $path) { $files[$path] = basename($path); @@ -37,28 +32,11 @@ class Server_Add_Controller extends Controller { print $view; } - private function _validate_path($path) { - if (!is_readable($path) || is_link($path)) { - throw new Exception("@todo BAD_PATH"); - } - - $authorized_paths = unserialize(module::get_var("server_add", "authorized_paths")); - foreach (array_keys($authorized_paths) as $valid_path) { - if (strpos($path, $valid_path) === 0) { - return; - } - } - - throw new Exception("@todo BAD_PATH"); - } - public function children() { - if (!user::active()->admin) { - access::forbidden(); - } - $path = $this->input->get("path"); - $this->_validate_path($path); + if (!server_add::is_valid_path($path)) { + throw new Exception("@todo BAD_PATH"); + } $tree = new View("server_add_tree.html"); $tree->files = array(); @@ -81,196 +59,194 @@ class Server_Add_Controller extends Controller { print $tree; } - public function add() { - if (!user::active()->admin) { - access::forbidden(); - } + public function start() { access::verify_csrf(); - $authorized_paths = unserialize(module::get_var("server_add", "authorized_paths")); + $item = ORM::factory("item", Input::instance()->get("item_id")); + // We're an admin so this isn't necessary, but we'll eventually open this up to non-admins and + // this also verifies that the item was loaded properly. + access::required("edit", $item); - // The paths we receive are full pathnames. Convert that into a tree structure to save space - // in our task. - foreach (Input::instance()->post("path") as $path) { + // Gather up all the paths and associate them by directory, so that we can locate any empty + // directories for the next round. + foreach (Input::instance()->post("paths") as $path) { if (is_dir($path)) { - $dirs[$path] = array(); + $selections[$path] = array(); } else if (is_file($path)) { - $dir = dirname($path); - $file = basename($path); - $dirs[$dir][] = $file; + $selections[dirname($path)][] = $path; } } - Kohana::log("alert",print_r($dirs,1)); - } - - /* ================================================================================ */ - - function start($id) { - if (!user::active()->admin) { - access::forbidden(); - } - access::verify_csrf(); - - $item = ORM::factory("item", $id); - $paths = unserialize(module::get_var("server_add", "authorized_paths")); - $input_files = $this->input->post("path"); - $collapsed = $this->input->post("collapsed"); - $files = array(); - $total_count = 0; - foreach (array_keys($paths) as $valid_path) { - $path_length = strlen($valid_path); - foreach ($input_files as $key => $path) { - if (!empty($path)) { - if ($valid_path != $path && strpos($path, $valid_path) === 0) { - $relative_path = substr(dirname($path), $path_length); - $name = basename($path); - $files[$valid_path][] = array("path" => $relative_path, - "parent_id" => $id, "name" => basename($path), - "type" => is_dir($path) ? "album" : "file"); - $total_count++; - } - if ($collapsed[$key] === "true") { - $total_count += $this->_select_children($id, $valid_path, $path, $files[$valid_path]); - } - unset($input_files[$key]); - unset($collapsed[$key]); - } - } - } - - if ($total_count == 0) { - print json_encode(array("result" => "success", - "url" => "", - "task" => array( - "id" => -1, "done" => 1, "percent_complete" => 100, - "status" => t("No eligible files, import cancelled")))); - return; - } - $task_def = Task_Definition::factory() - ->callback("server_add_task::add_from_server") + ->callback("Server_Add_Controller::add") ->description(t("Add photos or movies from the local server")) ->name(t("Add from server")); - $task = task::create($task_def, array("item_id" => $id, "next_path" => 0, "files" => $files, - "counter" => 0, "position" => 0, "total" => $total_count)); + $task = task::create( + $task_def, array("item_id" => $item->id, "selections" => $selections)); - batch::start(); - print json_encode(array("result" => "started", - "url" => url::site("server_add/add_photo/{$task->id}?csrf=" . - access::csrf_token()), - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "done" => $task->done))); + print json_encode( + array("result" => "started", + "url" => url::site("server_add/run/$task->id?csrf=" . access::csrf_token()))); } - function add_photo($task_id) { - if (!user::active()->admin) { - access::forbidden(); - } + function run($task_id) { access::verify_csrf(); - $task = task::run($task_id); - // @todo the task is already run... its a little late to check the access - if (!$task->loaded || $task->owner_id != user::active()->id) { - access::forbidden(); - } - - if ($task->done) { - switch ($task->state) { - case "success": - message::success(t("Add from server completed")); - break; - - case "error": - message::warning(t("Add from server completed with errors")); - break; - } - print json_encode(array("result" => "success", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "done" => $task->done))); - - } else { - print json_encode(array("result" => "in_progress", - "task" => array( - "id" => $task->id, - "percent_complete" => $task->percent_complete, - "status" => $task->status, - "done" => $task->done))); - } - } - - public function finish($id, $task_id) { - if (!user::active()->admin) { - access::forbidden(); - } - access::verify_csrf(); $task = ORM::factory("task", $task_id); - if (!$task->loaded || $task->owner_id != user::active()->id) { access::forbidden(); } - if (!$task->done) { - message::warning(t("Add from server was cancelled prior to completion")); - } - - batch::stop(); - print json_encode(array("result" => "success")); + $task = task::run($task_id); + print json_encode(array("done" => $task->done, + "percent_complete" => $task->percent_complete)); } - public function pause($id, $task_id) { - if (!user::active()->admin) { - access::forbidden(); - } - access::verify_csrf(); - $task = ORM::factory("task", $task_id); - if (!$task->loaded || $task->owner_id != user::active()->id) { - access::forbidden(); - } - - message::warning(t("Add from server was cancelled prior to completion")); - batch::stop(); - print json_encode(array("result" => "success")); - } + /** + * This is the task code that adds photos and albums. It first examines all the target files + * and creates a set of Server_Add_File_Models, then runs through the list of models and adds + * them one at a time. + */ + static function add($task) { + $selections = $task->get("selections"); + $mode = $task->get("mode", "init"); + $start = microtime(true); + $item_id = $task->get("item_id"); + + switch ($mode) { + case "init": + $task->set("mode", "build-file-list"); + $task->set("queue", array_keys($selections)); + $task->percent_complete = 0; + batch::start(); + break; + + case "build-file-list": /* 0% to 10% */ + // We can't fit an arbitrary number of paths in a task, so store them in a separate table. + // Don't use an iterator here because we can't get enough control over it when we're dealing + // with a deep hierarchy and we don't want to go over our time quota. + $queue = $task->get("queue"); + Kohana::log("alert",print_r($queue,1)); + while ($queue && microtime(true) - $start < 0.5) { + $file = array_shift($queue); + $entry = ORM::factory("server_add_file"); + $entry->task_id = $task->id; + $entry->file = $file; + $entry->save(); + + if (is_dir($file)) { + $queue = array_merge( + $queue, empty($selections[$file]) ? glob("$file/*") : $selections[$file]); + } + } + // We have no idea how long this can take because we have no idea how deep the tree + // hierarchy rabbit hole goes. Leave ourselves room here for 100 iterations and don't go + // over 10% in percent_complete. + $task->set("queue", $queue); + $task->percent_complete = min($task->percent_complete + 0.1, 10); + + if (!$queue) { + $task->set("mode", "add-files"); + $task->set( + "total_files", database::instance()->count_records( + "server_add_files", array("task_id" => $task->id))); + $task->set("albums", array()); + $task->set("completed", 0); + $task->percent_complete = 10; + } + break; + + case "add-files": /* 10% to 100% */ + $completed_files = $task->get("completed_files"); + $total_files = $task->get("total_files"); + $albums = $task->get("albums"); + + // Ordering by id ensures that we add them in the order that we created the entries, which + // will create albums first. + $entries = ORM::factory("server_add_file") + ->where("task_id", $task->id) + ->orderby("id", "ASC") + ->limit(10) + ->find_all(); + if ($entries->count() == 0) { + $task->set("mode", "done"); + } - private function _select_children($id, $valid_path, $path, &$files) { - $count = 0; - $children = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($path), - RecursiveIteratorIterator::SELF_FIRST); + $item = model_cache::get("item", $item_id); + foreach ($entries as $entry) { + if (microtime(true) - $start > 0.5) { + break; + } - $path_length = strlen($valid_path); - foreach($children as $name => $file){ - if ($file->isLink()) { - continue; - } - $filename = $file->getFilename(); - if ($filename[0] != ".") { - if ($file->isDir()) { - $relative_path = substr(dirname($file->getPathname()), $path_length); - $files[] = array("path" => $relative_path, - "parent_id" => $id, "name" => $filename, "type" => "album"); - $count++; + $relative_path = self::_relative_path($entry->file); + $name = basename($relative_path); + $title = item::convert_filename_to_title($name); + if (is_dir($entry->file)) { + if (isset($albums[$relative_path]) && $parent_id = $albums[$relative_path]) { + $parent = ORM::factory("item", $parent_id); + } else { + $album = album::create($item, $name, $title, null, user::active()->id); + $albums[$relative_path] = $album->id; + $task->set("albums", $albums); + } } else { - $extension = strtolower(substr(strrchr($filename, '.'), 1)); - if ($file->isReadable() && - in_array($extension, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) { - $relative_path = substr(dirname($file->getPathname()), $path_length); - $files[] = array("path" => $relative_path, - "parent_id" => $id, "name" => $filename, "type" => "file"); - $count++; + if (strpos($relative_path, "/") !== false) { + $parent = ORM::factory("item", $albums[dirname($relative_path)]); + } else { + $parent = $item; + } + + $extension = strtolower(pathinfo($name, PATHINFO_EXTENSION)); + if (in_array($extension, array("gif", "png", "jpg", "jpeg"))) { + photo::create($parent, $entry->file, $name, $title, null, user::active()->id); + } else if (in_array($extension, array("flv", "mp4"))) { + movie::create($parent, $entry->file, $name, $title, null, user::active()->id); + } else { + // Unsupported type + // @todo: $task->log this } } + + $completed_files++; + $entry->delete(); } + $task->set("completed_files", $completed_files); + $task->percent_complete = 10 + 100 * ($completed_files / $total_files); + Kohana::log("alert",print_r($task->as_array(),1)); + break; + + case "done": + batch::stop(); + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + message::info(t2("Successfully added one photo", + "Successfully added %count photos", + $task->get("completed_files"))); + } + } + /** + * Given a path that's somewhere in our authorized_paths list, return just the part that's + * relative to the nearest authorized path. + */ + static function _relative_path($path) { + static $authorized_paths; + // @todo this doesn't deal well with overlapping authorized paths, it'll just use the first one + // that matches. If we sort $authorized_paths by length in descending order, that should take + // care of the problem. + if (!$authorized_paths) { + $authorized_paths = + array_keys(unserialize(module::get_var("server_add", "authorized_paths"))); + } + + foreach ($authorized_paths as $candidate) { + $candidate = dirname($candidate); + if (strpos($path, $candidate) === 0) { + return substr($path, strlen($candidate) + 1); + } } - return $count; + throw new Exception("@todo BAD_PATH"); } -} \ No newline at end of file +} diff --git a/modules/server_add/helpers/server_add.php b/modules/server_add/helpers/server_add.php index f75a09d2..74f51ad9 100644 --- a/modules/server_add/helpers/server_add.php +++ b/modules/server_add/helpers/server_add.php @@ -31,4 +31,19 @@ class server_add_Core { site_status::clear("server_add_configuration"); } } + + static function is_valid_path($path) { + if (!is_readable($path) || is_link($path)) { + return false; + } + + $authorized_paths = unserialize(module::get_var("server_add", "authorized_paths")); + foreach (array_keys($authorized_paths) as $valid_path) { + if (strpos($path, $valid_path) === 0) { + return true; + } + } + + return false; + } } diff --git a/modules/server_add/helpers/server_add_installer.php b/modules/server_add/helpers/server_add_installer.php index c9d92e69..6956a72c 100644 --- a/modules/server_add/helpers/server_add_installer.php +++ b/modules/server_add/helpers/server_add_installer.php @@ -19,10 +19,30 @@ */ class server_add_installer { static function install() { - module::set_version("server_add", 1); + $db = Database::instance(); + $db->query("CREATE TABLE {server_add_files} ( + `id` int(9) NOT NULL auto_increment, + `task_id` int(9) NOT NULL, + `file` varchar(255) NOT NULL, + PRIMARY KEY (`id`)) + ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + module::set_version("server_add", 2); server_add::check_config(); } + static function upgrade($version) { + $db = Database::instance(); + if ($version == 1) { + $db->query("CREATE TABLE {server_add_files} ( + `id` int(9) NOT NULL auto_increment, + `task_id` int(9) NOT NULL, + `file` varchar(255) NOT NULL, + PRIMARY KEY (`id`)) + ENGINE=InnoDB DEFAULT CHARSET=utf8;"); + module::set_version("server_add", $version = 2); + } + } + static function deactivate() { site_status::clear("server_add_configuration"); } diff --git a/modules/server_add/helpers/server_add_task.php b/modules/server_add/helpers/server_add_task.php deleted file mode 100644 index 0482b47c..00000000 --- a/modules/server_add/helpers/server_add_task.php +++ /dev/null @@ -1,85 +0,0 @@ -context); - try { - $paths = array_keys(unserialize(module::get_var("server_add", "authorized_paths"))); - $path = $paths[$context["next_path"]]; - if (!empty($context["files"][$path])) { - $file = $context["files"][$path][$context["position"]]; - $parent = ORM::factory("item", $file["parent_id"]); - access::required("add", $parent); - if (!$parent->is_album()) { - throw new Exception("@todo BAD_ALBUM"); - } - - $name = $file["name"]; - if ($file["type"] == "album") { - $album = ORM::factory("item") - ->where("name", $name) - ->where("parent_id", $parent->id) - ->find(); - if (!$album->loaded) { - $album = album::create($parent, $name, $name, null, user::active()->id); - } - // Now that we have a new album. Go through the remaining files to import and change the - // parent_id of any file that has the same relative path as this album's path. - $album_path = "{$file['path']}/$name"; - for ($idx = $context["position"] + 1; $idx < count($context["files"][$path]); $idx++) { - if (strpos($context["files"][$path][$idx]["path"], $album_path) === 0) { - $context["files"][$path][$idx]["parent_id"] = $album->id; - } - } - } else { - $extension = strtolower(substr(strrchr($name, '.'), 1)); - $source_path = "$path{$file['path']}/$name"; - $title = item::convert_filename_to_title($name); - if (in_array($extension, array("flv", "mp4"))) { - $movie = movie::create($parent, $source_path, $name, $title, - null, user::active()->id); - } else { - $photo = photo::create($parent, $source_path, $name, $title, - null, user::active()->id); - } - } - - $context["counter"]++; - if (++$context["position"] >= count($context["files"][$path])) { - $context["next_path"]++; - $context["position"] = 0; - } - } else { - $context["next_path"]++; - } - } catch(Exception $e) { - $context["errors"][$path] = $e->getMessage(); - } - $task->context = serialize($context); - $task->state = "success"; - $task->percent_complete = ($context["counter"] / (float)$context["total"]) * 100; - $task->done = $context["counter"] == (float)$context["total"]; - } -} \ No newline at end of file diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js index 568ef91f..cba8c9ce 100644 --- a/modules/server_add/js/server_add.js +++ b/modules/server_add/js/server_add.js @@ -12,13 +12,13 @@ function open_close_branch(path, id) { $.ajax({ url: GET_CHILDREN_URL.replace("__PATH__", path), success: function(data, textStatus) { - children.html(data); - parent.removeClass("gLoadingSmall"); + children.html(data); + parent.removeClass("gLoadingSmall"); - // Propagate checkbox value - children.find("input[type=checkbox]").attr( - "checked", parent.find("input[type=checkbox]:first").attr("checked")); - }, + // Propagate checkbox value + children.find("input[type=checkbox]").attr( + "checked", parent.find("input[type=checkbox]:first").attr("checked")); + } }); } @@ -54,202 +54,38 @@ function click_node(checkbox) { } } -/* ================================================================================ */ - -/* -var paused = false; -var task = null; - -$("#gServerAdd").ready(function() { - init_server_add_form(); -}); - -function init_server_add_form() { - $("#gServerAdd #gServerAddButton").click(function(event) { - do_add(this, event); - }); - $("#gServerAdd #gServerPauseButton").click(function(event) { - event.preventDefault(); - paused = true; - }); - $(".gProgressBar").progressbar(); - $("#gServerAddTree ul").css("display", "block"); - $("#gServerAdd form").bind("form_closing", function(target) { - if (task != null && !task.done) { - $.ajax({async: false, - success: function(data, textStatus) { - document.location.reload(); - }, - dataType: "json", - type: "POST", - url: get_url("server_add/pause", task.id) - }); - } else { - document.location.reload(); - } - }); - set_click_events(); -} - -function set_click_events() { - $(".ui-icon").unbind("click"); - $(":checkbox").unbind("click"); - $(".ui-icon").click(function(event) { - open_close_branch(this, event); - }); - - $("input[type=checkbox]").click(function(event) { - checkbox_click(this); +function start_add() { + var paths = []; + $.each($("#gServerAdd :checkbox[checked]"), function () { + paths.push(this.value); }); -} - -function open_close_branch(icon, event) { - var parent = icon.parentNode; - var closed = $(icon).hasClass("ui-icon-plus"); - var children = $(parent).find(".gCheckboxTree"); - - if (closed) { - if (children.length == 0) { - load_children(icon); - } else { - toggle_branch("open", icon); - } - } else { - toggle_branch("close", icon); - } -} - -function toggle_branch(direction, icon) { - var parent = icon.parentNode; - var branch = $(parent).children(".gServerAddChildren"); - $(branch).slideToggle("fast", function() { - if (direction == "open") { - $(icon).addClass("ui-icon-minus"); - $(icon).removeClass("ui-icon-plus"); - $(parent).removeClass("gCollapsed"); - } else { - $(icon).addClass("ui-icon-plus"); - $(icon).removeClass("ui-icon-minus"); + $.ajax({ + url: START_URL, + type: "POST", + async: false, + data: { "paths[]": paths }, + dataType: "json", + success: function(data, textStatus) { + $("#gServerAdd .gProgressBar").progressbar("value", data.percent_complete); + setTimeout(function() { run_add(data.url); }, 0); } }); + return false; } -function get_url(uri, task_id) { - var url = $("#gServerAdd form").attr("action"); - url = url.replace("__ARGS__", uri); - url = url.replace("__TASK_ID__", !task_id ? "" : "/" + task_id); - return url; -} - -function load_children(icon) { - $("#gDialog").addClass("gDialogLoadingLarge"); - var parent = icon.parentNode; - var checkbox = $(parent).find("input[type=checkbox]"); - var parms = "&path=" + $(checkbox).attr("value"); - parms += "&checked=" + $(checkbox).is(":checked"); - parms += "&collapsed=" + $(parent).hasClass("gCollapsed"); - - $.ajax({success: function(data, textStatus) { - $(parent).children(".gServerAddChildren").html(data); - set_click_events(); - $("#gDialog").removeClass("gDialogLoadingLarge"); - toggle_branch("open", icon); - }, - data: parms, - dataType: "html", - type: "POST", - url: get_url("server_add/children") - }); -} - -function do_add(submit, event) { - event.preventDefault(); - - $("#gServerAdd #gServerAddButton").hide(); - $("#gServerAdd #gServerPauseButton").show(); - - var parms = ""; - if (!paused) { - $(".gProgressBar").progressbar("value", 0); - $(".gProgressBar").css("visibility", "visible"); - var check_list = $("#gServerAdd :checkbox[checked]"); - - var paths = ""; - var collapsed = ""; - $.each(check_list, function () { - var parent = $(this).parents("li")[0]; - paths += "&path[]=" + this.value; - collapsed += "&collapsed[]=" + $(parent).hasClass("gCollapsed"); - }); - parms = paths + collapsed; - } - paused = false; - - $.ajax({async: false, - data: parms, +function run_add(url) { + $.ajax({ + url: url, + async: false, dataType: "json", success: function(data, textStatus) { - var done = data.task.done; - if (done) { - task = null; - $("body").append("
" + data.task.status + "
"); - - $("#gNoFilesDialog").dialog({modal: true, - autoOpen: true, - title: FILE_IMPORT_WARNING}); - $(".gProgressBar").css("visibility", "hidden"); - $("#gServerAdd #gServerAddButton").show(); - $("#gServerAdd #gServerPauseButton").hide(); - return; - } - task = data.task; - var url = data.url; - while (!done && !paused) { - $.ajax({async: false, - success: function(data, textStatus) { - $(".gProgressBar").progressbar("value", data.task.percent_complete); - done = data.task.done; - }, - error: function(XMLHttpRequest, textStatus, errorThrown) { - paused = true; - display_upload_error(XMLHttpRequest.responseText); - }, - dataType: "json", - type: "POST", - url: url - }); - } - if (!paused) { - $.ajax({async: false, - success: function(data, textStatus) { - document.location.reload(); - }, - dataType: "json", - type: "POST", - url: get_url("server_add/finish", task.id) - }); + $("#gServerAdd .gProgressBar").progressbar("value", data.percent_complete); + if (data.done) { + $("#gServerAdd .gProgressBar").slideUp(); } else { - $("#gServerAdd #gServerAddButton").show(); - $("#gServerAdd #gServerPauseButton").hide(); + setTimeout(function() { run_add(url); }, 0); } - }, - type: "POST", - url: get_url("server_add/start") + } }); - - return false; -} - -function display_upload_error(error) { - $("body").append("
" + error + "
"); - $("#gServerAddError").dialog({ - autoOpen: true, - autoResize: false, - modal: true, - resizable: true, - width: 610, - height: $("#gDialog").height() - }); } -*/ diff --git a/modules/server_add/models/server_add_file.php b/modules/server_add/models/server_add_file.php new file mode 100644 index 00000000..8b1ed924 --- /dev/null +++ b/modules/server_add/models/server_add_file.php @@ -0,0 +1,21 @@ +
@@ -18,18 +19,28 @@ - "post")) ?> + id"), array("method" => "post")) ?>
+ + - " style="display: none"> - "> + "> - +
-- cgit v1.2.3 From b0429797fc7db5464717deffebdccc9705ca7820 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 9 Jul 2009 10:00:16 -0700 Subject: Use p::purify instead of p::clean --- modules/server_add/views/server_add_tree_dialog.html.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 8b13001f..0d56df7b 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -5,17 +5,17 @@
-

p::clean($item->title))) ?>

+

p::purify($item->title))) ?>

    parents() as $parent): ?>
  • - title) ?> + title) ?>
  • - title) ?> + title) ?>
-- cgit v1.2.3 From fad6c4783ebec8591e1b61bddcc7bd5f17d8cf0e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 9 Jul 2009 10:46:27 -0700 Subject: Add status output to make it clearer what's happening when you add files. --- modules/server_add/controllers/server_add.php | 13 +++++++++++-- modules/server_add/js/server_add.js | 4 +++- modules/server_add/views/server_add_tree_dialog.html.php | 9 ++++++--- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index 288e6342..638a4d63 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -86,6 +86,7 @@ class Server_Add_Controller extends Admin_Controller { print json_encode( array("result" => "started", + "status" => $task->status, "url" => url::site("server_add/run/$task->id?csrf=" . access::csrf_token()))); } @@ -99,6 +100,7 @@ class Server_Add_Controller extends Admin_Controller { $task = task::run($task_id); print json_encode(array("done" => $task->done, + "status" => $task->status, "percent_complete" => $task->percent_complete)); } @@ -117,6 +119,7 @@ class Server_Add_Controller extends Admin_Controller { case "init": $task->set("mode", "build-file-list"); $task->set("queue", array_keys($selections)); + $task->status = t("Starting up"); $task->percent_complete = 0; batch::start(); break; @@ -126,7 +129,6 @@ class Server_Add_Controller extends Admin_Controller { // Don't use an iterator here because we can't get enough control over it when we're dealing // with a deep hierarchy and we don't want to go over our time quota. $queue = $task->get("queue"); - Kohana::log("alert",print_r($queue,1)); while ($queue && microtime(true) - $start < 0.5) { $file = array_shift($queue); $entry = ORM::factory("server_add_file"); @@ -144,6 +146,10 @@ class Server_Add_Controller extends Admin_Controller { // over 10% in percent_complete. $task->set("queue", $queue); $task->percent_complete = min($task->percent_complete + 0.1, 10); + $task->status = t2("Found one file", "Found %count files", + Database::instance() + ->where("task_id", $task->id) + ->count_records("server_add_files")); if (!$queue) { $task->set("mode", "add-files"); @@ -202,6 +208,7 @@ class Server_Add_Controller extends Admin_Controller { } else if (in_array($extension, array("flv", "mp4"))) { movie::create($parent, $entry->file, $name, $title, null, user::active()->id); } else { + $task->log("Skipping unknown file type: $relative_path"); // Unsupported type // @todo: $task->log this } @@ -211,8 +218,10 @@ class Server_Add_Controller extends Admin_Controller { $entry->delete(); } $task->set("completed_files", $completed_files); + $task->status = t("Adding photos (%completed of %total)", + array("completed" => $completed_files, + "total" => $total_files)); $task->percent_complete = 10 + 100 * ($completed_files / $total_files); - Kohana::log("alert",print_r($task->as_array(),1)); break; case "done": diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js index cba8c9ce..1a78d733 100644 --- a/modules/server_add/js/server_add.js +++ b/modules/server_add/js/server_add.js @@ -66,6 +66,7 @@ function start_add() { data: { "paths[]": paths }, dataType: "json", success: function(data, textStatus) { + $("#gStatus").html(data.status); $("#gServerAdd .gProgressBar").progressbar("value", data.percent_complete); setTimeout(function() { run_add(data.url); }, 0); } @@ -79,9 +80,10 @@ function run_add(url) { async: false, dataType: "json", success: function(data, textStatus) { + $("#gStatus").html(data.status); $("#gServerAdd .gProgressBar").progressbar("value", data.percent_complete); if (data.done) { - $("#gServerAdd .gProgressBar").slideUp(); + $("#gProgress").slideUp(); } else { setTimeout(function() { run_add(url); }, 0); } diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 0d56df7b..bbad4e69 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -25,7 +25,10 @@ - + -- cgit v1.2.3 From 171522bf231e4fca13dd522e8f755e65a8d48b3b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 11 Jul 2009 07:23:31 -0700 Subject: Add a "close" button. --- modules/server_add/views/server_add_tree_dialog.html.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index bbad4e69..8e9c1c01 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -46,4 +46,8 @@ }); }); + +
-- cgit v1.2.3 From cbd80b5ff948e23a1fa8b0994291953d38f6a7bd Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 11 Jul 2009 07:37:49 -0700 Subject: Get rid of the form from server_add, we're not using it. Turn the cancel link into a themed close button which triggers a page reload. Add some padding to the left of the tree. --- .../server_add/views/server_add_tree_dialog.html.php | 17 +++++++++-------- themes/default/css/screen.css | 6 ++++++ 2 files changed, 15 insertions(+), 8 deletions(-) (limited to 'modules/server_add/views/server_add_tree_dialog.html.php') diff --git a/modules/server_add/views/server_add_tree_dialog.html.php b/modules/server_add/views/server_add_tree_dialog.html.php index 8e9c1c01..21952849 100644 --- a/modules/server_add/views/server_add_tree_dialog.html.php +++ b/modules/server_add/views/server_add_tree_dialog.html.php @@ -19,8 +19,6 @@ - id"), array("method" => "post")) ?> -
@@ -31,10 +29,16 @@
- "> + + + - + - diff --git a/themes/default/css/screen.css b/themes/default/css/screen.css index c4670a4d..0c65cd96 100644 --- a/themes/default/css/screen.css +++ b/themes/default/css/screen.css @@ -899,8 +899,14 @@ form .gError, /* Server Add */ +#gServerAdd button { + float: left; + margin-bottom: .5em; +} + #gServerAddTree { cursor: pointer; + padding-left: 4px; } #gServerAddTree li { -- cgit v1.2.3