summaryrefslogtreecommitdiff
path: root/modules/server_add
diff options
context:
space:
mode:
authorBharat Mediratta <bharat@menalto.com>2009-07-11 05:03:36 -0700
committerBharat Mediratta <bharat@menalto.com>2009-07-11 05:03:36 -0700
commit954ab5a5051edb67eca8ae74283a80a226e39672 (patch)
treee27757f7ea82d064d2cd9a38b295648b4073f850 /modules/server_add
parent8e8a9f728b4e04f281eacc1467e79f55cb2343c5 (diff)
Further simplify server_add (and bump it to version 3).
Now we don't have checkboxes, but instead we restrict you to selecting directories and albums from only one level in the hierarchy. This makes it easier for us to make sure that we properly create the hierarchy that you want and avoid confusion about what's going to wind up where. Modify Server_Add_File_Model to have a parent_id and item_id and then modify them as we go so that we can build up a tree structure there *before* we create any items. This makes it much easier to figure out where a new item is going to go and get rid of a bunch of probably buggy code in the main task.
Diffstat (limited to 'modules/server_add')
-rw-r--r--modules/server_add/controllers/server_add.php199
-rw-r--r--modules/server_add/helpers/server_add_installer.php8
-rw-r--r--modules/server_add/js/server_add.js67
-rw-r--r--modules/server_add/module.info2
-rw-r--r--modules/server_add/views/server_add_tree.html.php56
5 files changed, 152 insertions, 180 deletions
diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php
index 08e01858..6056d7cd 100644
--- a/modules/server_add/controllers/server_add.php
+++ b/modules/server_add/controllers/server_add.php
@@ -29,51 +29,58 @@ class Server_Add_Controller extends Admin_Controller {
$view->item = $item;
$view->tree = new View("server_add_tree.html");
$view->tree->files = $files;
+ $view->tree->parents = array();
print $view;
}
public function children() {
$path = $this->input->get("path");
- if (!server_add::is_valid_path($path)) {
- throw new Exception("@todo BAD_PATH");
- }
$tree = new View("server_add_tree.html");
$tree->files = array();
- $tree->tree_id = substr(md5($path), 10);
+ $tree->parents = array();
- foreach (glob("$path/*") as $file) {
- if (!is_readable($file)) {
- continue;
+ // Make a tree with the parents back up to the authorized path, and all the children under the
+ // current path.
+ if (server_add::is_valid_path($path)) {
+ $tree->parents[] = $path;
+ while (server_add::is_valid_path(dirname($tree->parents[0]))) {
+ array_unshift($tree->parents, dirname($tree->parents[0]));
}
- if (!is_dir($file)) {
- $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
- if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) {
+ foreach (glob("$path/*") as $file) {
+ if (!is_readable($file)) {
continue;
}
- }
+ if (!is_dir($file)) {
+ $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+ if (!in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) {
+ continue;
+ }
+ }
- $tree->files[] = $file;
+ $tree->files[] = $file;
+ }
+ } else {
+ // Missing or invalid path; print out the list of authorized path
+ $paths = unserialize(module::get_var("server_add", "authorized_paths"));
+ foreach (array_keys($paths) as $path) {
+ $tree->files[] = $path;
+ }
}
print $tree;
}
+ /**
+ * Begin the task of adding photos.
+ */
public function start() {
access::verify_csrf();
-
$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);
- // 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)) {
- $selections[$path] = array();
- } else if (is_file($path)) {
- $selections[dirname($path)][] = $path;
+ if (server_add::is_valid_path($path)) {
+ $paths[] = array($path, null);
}
}
@@ -81,8 +88,7 @@ class Server_Add_Controller extends Admin_Controller {
->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" => $item->id, "selections" => $selections));
+ $task = task::create($task_def, array("item_id" => $item->id, "queue" => $paths));
print json_encode(
array("result" => "started",
@@ -90,6 +96,9 @@ class Server_Add_Controller extends Admin_Controller {
"url" => url::site("server_add/run/$task->id?csrf=" . access::csrf_token())));
}
+ /**
+ * Run the task of adding photos
+ */
function run($task_id) {
access::verify_csrf();
@@ -110,49 +119,48 @@ class Server_Add_Controller extends Admin_Controller {
* 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;
$task->status = t("Starting up");
batch::start();
break;
- case "build-file-list": /* 0% to 10% */
+ 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.
+ // with a deep hierarchy and we don't want to go over our time quota. The queue is in the
+ // form [path, parent_id] where the parent_id refers to another Server_Add_File_Model. We
+ // have this extra level of abstraction because we don't know its Item_Model id yet.
$queue = $task->get("queue");
while ($queue && microtime(true) - $start < 0.5) {
- $file = array_shift($queue);
- if (is_dir($file)) {
- $entry = ORM::factory("server_add_file");
- $entry->task_id = $task->id;
- $entry->file = $file;
- $entry->save();
-
- $children = empty($selections[$file]) ? glob("$file/*") : $selections[$file];
- } else {
- $children = array($file);
- }
-
- foreach ($children as $child) {
- $entry = ORM::factory("server_add_file");
- $entry->task_id = $task->id;
- $entry->file = $child;
- $entry->save();
+ list($file, $parent_entry_id) = array_shift($queue);
+ $entry = ORM::factory("server_add_file");
+ $entry->task_id = $task->id;
+ $entry->file = $file;
+ $entry->parent_id = $parent_entry_id;
+ $entry->save();
+ foreach (glob("$file/*") as $child) {
if (is_dir($child)) {
- $queue[] = $child;
+ $queue[] = array($child, $entry->id);
+ } else {
+ $ext = strtolower(pathinfo($child, PATHINFO_EXTENSION));
+ if (in_array($ext, array("gif", "jpeg", "jpg", "png", "flv", "mp4"))) {
+ $child_entry = ORM::factory("server_add_file");
+ $child_entry->task_id = $task->id;
+ $child_entry->file = $child;
+ $child_entry->parent_id = $entry->id;
+ $child_entry->save();
+ }
}
}
}
+
// 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.
@@ -168,79 +176,67 @@ class Server_Add_Controller extends Admin_Controller {
$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");
+ case "add-files": // 10% to 100%
+ $completed_files = $task->get("completed_files", 0);
$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.
+ // will create albums first. Ignore entries which already have an Item_Model attached,
+ // they're done.
$entries = ORM::factory("server_add_file")
->where("task_id", $task->id)
+ ->where("item_id", null)
->orderby("id", "ASC")
->limit(10)
->find_all();
if ($entries->count() == 0) {
+ // Out of entries, we're done.
$task->set("mode", "done");
}
- $item = model_cache::get("item", $item_id);
+ $owner_id = user::active()->id;
foreach ($entries as $entry) {
if (microtime(true) - $start > 0.5) {
break;
}
- $relative_path = self::_relative_path($entry->file);
- $name = basename($relative_path);
+ // Look up the parent item for this entry. By now it should exist, but if none was
+ // specified, then this belongs as a child of the current item.
+ $parent_entry = ORM::factory("server_add_file", $entry->parent_id);
+ if (!$parent_entry->loaded) {
+ $parent = ORM::factory("item", $task->get("item_id"));
+ } else {
+ $parent = ORM::factory("item", $parent_entry->item_id);
+ }
+
+ $name = basename($entry->file);
$title = item::convert_filename_to_title($name);
if (is_dir($entry->file)) {
- $parent_path = dirname($relative_path);
- if (isset($albums[$parent_path]) && $parent_id = $albums[$parent_path]) {
- $parent = ORM::factory("item", $parent_id);
- } else {
- $parent = $item;
- }
- $album = album::create($parent, $name, $title, null, user::active()->id);
- $albums[$relative_path] = $album->id;
- $task->set("albums", $albums);
+ $album = album::create($parent, $name, $title, null, $owner_id);
+ $entry->item_id = $album->id;
} else {
- // Find the nearest selected parent. We check to see if any of the candidate parents
- // were selected in the UI and if so, we use that. Otherwise, we fall back to making
- // the parent the current item.
- $parent_path = $relative_path;
- $parent = null;
- do {
- if (strpos($parent_path, "/") !== false) {
- if (array_key_exists($parent_path, $albums)) {
- $parent = ORM::factory("item", $albums[$parent_path]);
- } else {
- $parent_path = dirname($parent_path);
- }
- } else {
- $parent = $item;
- }
- } while (!$parent);
-
$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);
+ $photo = photo::create($parent, $entry->file, $name, $title, null, $owner_id);
+ $entry->item_id = $photo->id;
} else if (in_array($extension, array("flv", "mp4"))) {
- movie::create($parent, $entry->file, $name, $title, null, user::active()->id);
+ $movie = movie::create($parent, $entry->file, $name, $title, null, $owner_id);
+ $entry->item_id = $movie->id;
} else {
- $task->log("Skipping unknown file type: $relative_path");
- // Unsupported type
- // @todo: $task->log this
+ // This should never happen, because we don't add stuff to the list that we can't
+ // process. But just in, case.. set this to a non-null value so that we skip this
+ // entry.
+ $entry->item_id = 0;
+ $task->log("Skipping unknown file type: $entry->file");
}
}
$completed_files++;
- $entry->delete();
+ $entry->save();
}
$task->set("completed_files", $completed_files);
$task->status = t("Adding photos and albums (%completed of %total)",
@@ -254,33 +250,10 @@ class Server_Add_Controller extends Admin_Controller {
$task->done = true;
$task->state = "success";
$task->percent_complete = 100;
+ ORM::factory("server_add_file")->where("task_id", $task->id)->delete_all();
message::info(t2("Successfully added one photo",
- "Successfully added %count photos",
+ "Successfully added %count photos and albums",
$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);
- }
- }
-
- throw new Exception("@todo BAD_PATH");
- }
}
diff --git a/modules/server_add/helpers/server_add_installer.php b/modules/server_add/helpers/server_add_installer.php
index 6956a72c..4cc34207 100644
--- a/modules/server_add/helpers/server_add_installer.php
+++ b/modules/server_add/helpers/server_add_installer.php
@@ -22,8 +22,10 @@ class server_add_installer {
$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,
+ `item_id` int(9),
+ `parent_id` int(9),
+ `task_id` int(9) NOT NULL,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
module::set_version("server_add", 2);
@@ -40,6 +42,10 @@ class server_add_installer {
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
module::set_version("server_add", $version = 2);
+ } else if ($version == 2) {
+ $db->query("ALTER TABLE {server_add_files} ADD COLUMN `item_id` int(9)");
+ $db->query("ALTER TABLE {server_add_files} ADD COLUMN `parent_id` int(9)");
+ module::set_version("server_add", $version = 3);
}
}
diff --git a/modules/server_add/js/server_add.js b/modules/server_add/js/server_add.js
index 1a78d733..989555cc 100644
--- a/modules/server_add/js/server_add.js
+++ b/modules/server_add/js/server_add.js
@@ -1,51 +1,9 @@
/**
- * We've clicked the + icon next to a directory. Load up children of this
- * directory from the server and display them.
+ * Manage file selection state.
*/
-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");
- }
- });
-}
-
-/**
- * We've clicked a checkbox. Propagate the value downwards as necessary.
- */
-function click_node(checkbox) {
- var parent = $(checkbox).parents("li").get(0);
- var checked = $(checkbox).attr("checked");
- $(parent).find("input[type=checkbox]").attr("checked", checked);
-
- // @todo if we uncheck all the children for a parent, we should uncheck the
- // parent itself, otherwise in the code we'll add the entire parent since if
- // we find an album as a leaf, we assume that it's never been expanded in the UI.
- if ($("#gServerAddTree").find("input[type=checkbox]").is(":checked")) {
+function select_file(li) {
+ $(li).toggleClass("selected");
+ if ($("#gServerAdd span.selected").length) {
$("#gServerAddAddButton").enable(true);
$("#gServerAddAddButton").removeClass("ui-state-disabled");
} else {
@@ -54,11 +12,24 @@ function click_node(checkbox) {
}
}
+/**
+ * Load a new directory
+ */
+function open_dir(path) {
+ $.ajax({
+ url: GET_CHILDREN_URL.replace("__PATH__", path),
+ success: function(data, textStatus) {
+ $("#gServerAddTree").html(data);
+ }
+ });
+}
+
function start_add() {
var paths = [];
- $.each($("#gServerAdd :checkbox[checked]"), function () {
- paths.push(this.value);
+ $.each($("#gServerAdd span.selected"), function () {
+ paths.push($(this).attr("file"));
});
+
$.ajax({
url: START_URL,
type: "POST",
diff --git a/modules/server_add/module.info b/modules/server_add/module.info
index 1c99d280..295d3beb 100644
--- a/modules/server_add/module.info
+++ b/modules/server_add/module.info
@@ -1,3 +1,3 @@
name = Server Add
description = Allows authorized users to load images directly from your web server
-version = 2
+version = 3
diff --git a/modules/server_add/views/server_add_tree.html.php b/modules/server_add/views/server_add_tree.html.php
index 74bc40e0..254a9da0 100644
--- a/modules/server_add/views/server_add_tree.html.php
+++ b/modules/server_add/views/server_add_tree.html.php
@@ -1,19 +1,41 @@
<?php defined("SYSPATH") or die("No direct script access.") ?>
-<? foreach ($files as $file): ?>
-<? $id = substr(md5($file), 10) ?>
-<li id="file_<?= $id ?>" class="<?= is_file($file) ? "gFile" : "gDirectory gCollapsed ui-icon-left" ?>">
- <? if (is_dir($file)): ?>
- <span onclick="open_close_branch('<?=$file?>', '<?=$id?>')" class="ui-icon ui-icon-plus"></span>
- <? endif ?>
- <label>
- <?= form::checkbox("path[]", $file, false, "onclick=click_node(this)") ?>
- <?= p::clean(basename($file)) ?>
- </label>
- <? if (is_dir($file)): ?>
- <ul id="tree_<?= $id ?>" style="display: none"></ul>
- <? endif ?>
+<li class="ui-icon-left">
+ <span class="ui-icon ui-icon-folder-open"></span>
+ <span ondblclick="open_dir('')">
+ <?= t("All") ?>
+ </span>
+ <ul>
+
+ <? foreach ($parents as $dir): ?>
+ <li class="ui-icon-left">
+ <span class="ui-icon ui-icon-folder-open"></span>
+ <span ondblclick="open_dir('<?= $dir ?>')">
+ <?= basename($dir) ?>
+ </span>
+ <ul>
+ <? endforeach ?>
+
+ <? foreach ($files as $file): ?>
+ <li class="ui-icon-left">
+ <span class="ui-icon <?= is_dir($file) ? "ui-icon-folder-collapsed" : "ui-icon-document" ?>"></span>
+ <span onclick="select_file(this)"
+ <? if (is_dir($file)): ?>
+ ondblclick="open_dir($(this).attr('file'))"
+ <? endif ?>
+ file="<?= $file ?>"
+ >
+ <?= p::clean(basename($file)) ?>
+ </span>
+ </li>
+ <? endforeach ?>
+ <? if (!$files): ?>
+ <li> <i> <?= t("empty") ?> </i> </li>
+ <? endif ?>
+
+ <? foreach ($parents as $dir): ?>
+ </ul>
+ </li>
+ <? endforeach ?>
+
+ </ul>
</li>
-<? endforeach ?>
-<? if (!$files): ?>
-<li class="gFile"> <i> <?= t("empty") ?> </i> </li>
-<? endif ?>