diff options
Diffstat (limited to 'modules/organize/controllers')
| -rw-r--r-- | modules/organize/controllers/organize.php | 620 | 
1 files changed, 159 insertions, 461 deletions
| diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 898be509..76a22b73 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -18,181 +18,82 @@   * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA  02110-1301, USA.   */  class Organize_Controller extends Controller { -  private static $_MICRO_THUMB_SIZE = 90; -  private static $_MICRO_THUMB_PADDING = 5; - -  function index($item_id=1) { -    $item = ORM::factory("item", $item_id); -    $root = ($item->id == 1) ? $item : ORM::factory("item", 1); -    access::required("view", $item); -    access::required("edit", $item); - -    $v = new View("organize.html"); -    $v->root = $root; -    $v->item = $item; -    $v->album_tree = $this->tree($item, $root); -    $v->button_pane = new View("organize_button_pane.html"); -    print $v; -  } - -  function content($item_id) { +  function dialog($item_id) {      $item = ORM::factory("item", $item_id); +    $root = $item->id == 1 ? $item : ORM::factory("item", 1);      access::required("view", $item);      access::required("edit", $item); -    $width = $this->input->get("width"); -    $height = $this->input->get("height"); -    $offset = $this->input->get("offset", 0); -    $thumbsize = self::$_MICRO_THUMB_SIZE + 2 * self::$_MICRO_THUMB_PADDING; -    $page_size = ceil($width / $thumbsize) * ceil($height / $thumbsize); - -    $v = new View("organize_thumb_grid.html"); -    $v->children = $item->children($page_size, $offset); -    $v->thumbsize = self::$_MICRO_THUMB_SIZE; -    $v->padding = self::$_MICRO_THUMB_PADDING; -    $v->offset = $offset; +    $v = new View("organize_dialog.html"); +    $v->title = $item->title; +    $parents = array(); +    foreach ($item->parents() as $parent) { +      $parents[$parent->id] = 1; +    } +    $parents[$item->id] = 1; -    print json_encode(array("count" => $v->children->count(), -                            "data" => $v->__toString())); +    $v->album_tree = self::_tree($root, $parents); +    $v->micro_thumb_grid = self::_get_micro_thumb_grid($item, 0); +    print $v;    } -  function header($item_id) { +  function content($item_id, $offset) {      $item = ORM::factory("item", $item_id);      access::required("view", $item);      access::required("edit", $item); - -    print json_encode( -      array("title" => p::purify($item->title), -            "description" => empty($item->description) ? "" : p::purify($item->description))); +    print self::_get_micro_thumb_grid($item, $offset);    } -  function tree($item, $parent) { -    access::required("view", $item); -    access::required("edit", $item); - -    $albums = ORM::factory("item") -      ->where(array("parent_id" => $parent->id, "type" => "album")) -      ->orderby(array("title" => "ASC")) -      ->find_all(); - -    $v = new View("organize_album.html"); -    $v->album = $parent; -    $v->selected = $parent->id == $item->id; - -    if ($albums->count()) { -      $v->album_icon = $parent->id == 1 || $v->selected ? "ui-icon-minus" : "ui-icon-plus"; -    } else { -      $v->album_icon = ""; -    } - -    $v->children = ""; -    foreach ($albums as $album) { -      $v->children .= $this->tree($item, $album); -    } -    return $v->__toString(); -  } - -  function startTask($operation, $id) { +  function move($target_id) {      access::verify_csrf(); -    $items = $this->input->post("item"); - -    $item = ORM::factory("item", $id); -    access::required("view", $item); -    access::required("edit", $item); - -    $definition = $this->_getOperationDefinition($item, $operation);      $task_def = Task_Definition::factory() -      ->callback("organize_task::run") -      ->description($definition["description"]) -      ->name($definition["name"]); -    $task = task::create($task_def, array("items" => $items, "position" => 0, "target" => $id, -                                          "type" => $definition["type"], -                                          "batch" => ceil(count($items) * .1))); -    // @todo If there is only one item then call task_run($task->id); Maybe even change js so -    // we can call finish as well. -    batch::start(); +      ->callback("Organize_Controller::move_task_handler") +      ->description(t("Move images")) +      ->name(t("Move Images")); +    $task = task::create($task_def, array("target_id" => $target_id, +                                          "source_ids" => $this->input->post("source_ids"))); +      print json_encode(        array("result" => "started", -            "runningMsg" => $definition["runningMsg"], -            "pauseMsg" => "<div class=\"gWarning\">{$definition['pauseMsg']}</div>", -            "resumeMsg" => "<div class=\"gWarning\">{$definition['resumeMsg']}</div>", -            "task" => array("id" => $task->id, -                            "percent_complete" => $task->percent_complete, -                            "type" => $task->get("type"), -                            "status" => $task->status, -                            "state" => $task->state, -                            "done" => $task->done))); +            "status" => $task->status, +            "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token())));    } -  function runTask($task_id) { +  function rearrange($target_id, $before) {      access::verify_csrf(); +    $target = ORM::factory("item", $target_id); +    $parent = $target->parent(); +    access::required("view", $parent); +    access::required("edit", $parent); -    $task = task::run($task_id); -    if (!$task->loaded || $task->owner_id != user::active()->id) { -      access::forbidden(); -    } +    $task_def = Task_Definition::factory() +      ->callback("Organize_Controller::rearrange_task_handler") +      ->description(t("Rearrange Image")) +      ->name(t("Rearrange Images")); +    $task = task::create($task_def, array("target_id" => $target_id, "before" => $before, +                                          "parent_id" => $parent->id, +                                          "weight" => item::get_max_weight(), +                                          "total" => $parent->children_count(), +                                          "source_ids" => $this->input->post("source_ids"))); -    print json_encode(array("result" => $task->done ? $task->state : "in_progress", -                            "task" => array("id" => $task->id, -                                            "percent_complete" => $task->percent_complete, -                                            "type" => $task->get("type"), -                                            "post_process" => $task->get("post_process"), -                                            "status" => $task->status, -                                            "state" => $task->state, -                                            "done" => $task->done))); +    print json_encode( +      array("result" => "started", +            "status" => $task->status, +            "url" => url::site("organize/run/$task->id?csrf=" . access::csrf_token())));    } -  function finishTask($task_id) { -    access::verify_csrf(); - -    $task = ORM::factory("task", $task_id); -    if (!$task->loaded || $task->owner_id != user::active()->id) { -      access::forbidden(); -    } - -    if ($task->done) { -      $item = ORM::factory("item", (int)$task->get("target")); -      $type = $task->get("type"); -      switch ($type) { -      case "albumCover": -        $task->status = t("Album cover set for '%album'", array("album" => $item->title)); -        break; -      case "delete": -        $task->status = t("Selection deleted"); -        break; -      case "move": -        $task->status = t("Move to '%album' completed", array("album" => $item->title)); -        break; -      case "rearrange": -        try { -          $item->sort_column = "weight"; -          $item->save(); -          $task->status = t("Rearrange for '%album' completed", array("album" => $item->title)); -        } catch (Exception $e) { -          $task->state = "error"; -          $task->status = $e->getMessage(); -        } -        break; -      case "rotateCcw": -      case "rotateCw": -        $task->status = t("Rotation completed"); -        break; -      } -      $task->save(); -   } - -    batch::stop(); -    print json_encode(array("result" => "success", -                            "task" => array( -                              "id" => $task->id, -                              "percent_complete" => $task->percent_complete, -                              "status" => $task->status, -                              "state" => $task->state, -                              "done" => $task->done))); +  private static function _get_micro_thumb_grid($item, $offset) { +    $v = new View("organize_thumb_grid.html"); +    $v->item = $item; +    $v->offset = $offset; +    return $v;    } -  function cancelTask($task_id) { +  /** +   * Run the task +   */ +  function run($task_id) {      access::verify_csrf();      $task = ORM::factory("task", $task_id); @@ -200,341 +101,138 @@ class Organize_Controller extends Controller {        access::forbidden();      } -    if (!$task->done) { -      $task->done = 1; -      $task->state = "cancelled"; -      $type = $task->get("type"); -      switch ($type) { -      case "move": -        $task->status = t("Move to album was cancelled prior to completion"); -        break; -      case "rearrange": -         $task->status = t("Rearrange album was cancelled prior to completion"); -      case "rotateCcw": -      case "rotateCw": -        $task->status = t("Rotation was cancelled prior to completion"); -        break; +    $task = task::run($task_id); +    $results = array("done" => $task->done, "status" => $task->status, +                     "percent_complete" => $task->percent_complete); +    foreach (array("tree", "content") as $data) { +      $value = $task->get($data, false); +      if ($value !== false) { +        $results[$data] = $value;        } -      $task->save();      } - -    batch::stop(); -    print json_encode(array("result" => "success", -                            "task" => array( -                              "id" => $task->id, -                              "percent_complete" => $task->percent_complete, -                              "status" => $task->status, -                              "state" => $task->state, -                              "done" => $task->done))); +    print json_encode($results);    } -  function editForm() { -    $event_parms = new stdClass(); -    $event_parms->panes = array(); -    $event_parms->itemids = $this->input->get("item"); - -    // The following code should be done more dynamically i.e. use the event mechanism -    if (count($event_parms->itemids) == 1) { -      $item = ORM::factory("item") -        ->in("id", $event_parms->itemids[0]) -        ->find(); +  private static function _tree($item, $parents) { +    $v = new View("organize_tree.html"); +    $v->album = $item; +    $keys = array_keys($parents); +    $v->selected = end($keys) == $item->id; +    $v->can_edit= access::can("edit", $item); +    $v->children = array(); +    $v->album_icon = "gBranchEmpty"; -      access::required("view", $item); -      access::required("edit", $item); - -      $event_parms->panes[] = array( -        "label" => $item->is_album() ? t("Edit Album") : t("Edit Photo"), -        "content" => organize::get_general_edit_form($item)); - -      if ($item->is_album()) { -        $event_parms->panes[] = array("label" => t("Sort Order"), -                                      "content" => organize::get_sort_edit_form($item)); +    $albums = $item->children(null, 0, array("type" => "album"), array("title" => "ASC")); +    foreach ($albums as $album) { +      if (access::can("view", $album)) { +        $v->children[] = self::_tree($album, $parents);        }      } - -    $event_parms->panes[] = array("label" => t("Manage Tags"), -                                  "content" => organize::get_tag_form($event_parms->itemids)); - -    $v = new View("organize_edit.html"); -    $v->panes = $event_parms->panes; -    print $v->render(); -  } - -  // Handlers for the album/photo edit.  Probably should be in modules/gallery -  public function general() { -    access::verify_csrf(); - -    $itemids = $this->input->post("item"); -    $item = ORM::factory("item") -      ->in("id", $itemids[0]) -      ->find(); -    access::required("view", $item); -    access::required("edit", $item); - -    $form = organize::get_general_edit_form($item); -    if ($form->validate()) { -      $orig = clone $item; -      $item->title = $form->title->value; -      $item->description = $form->description->value; -      $item->rename($form->dirname->value); -      $item->save(); - -      if ($item->is_album()) { -        log::success("content", "Updated album", "<a href=\"albums/$item->id\">view</a>"); -        $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); -      } else { -        log::success("content", "Updated photo", "<a href=\"photos/$item->id\">view</a>"); -        $message = t("Saved photo %photo_title", array("photo_title" => p::purify($item->title))); -      } -      print json_encode(array("form" => $form->__toString(), "message" => $message)); -    } else { -      print json_encode(array("form" => $form->__toString())); +    if (count($v->children)) { +      $v->album_icon = empty($parents[$item->id]) ? "ui-icon-plus" : "ui-icon-minus";      } +    return $v;    } -  public function reset_general() { -    $itemids = Input::instance()->get("item"); -    $item = ORM::factory("item") -      ->in("id", $itemids[0]) -      ->find(); -    access::required("view", $item); -    access::required("edit", $item); - -    print organize::get_general_edit_form($item); -  } - -  public function sort() { -    access::verify_csrf(); - -    $itemids = $this->input->post("item"); -    $item = ORM::factory("item") -      ->in("id", $itemids[0]) -      ->find(); -    access::required("view", $item); -    access::required("edit", $item); - -    $form = organize::get_sort_edit_form($item); -    if ($form->validate()) { -      $orig = clone $item; -      $item->sort_column = $form->column->value; -      $item->sort_order = $form->direction->value; -      $item->save(); - -      log::success("content", "Updated album", "<a href=\"albums/$item->id\">view</a>"); -      $message = t("Saved album %album_title", array("album_title" => p::purify($item->title))); -      print json_encode(array("form" => $form->__toString(), "message" => $message)); -    } else { -      print json_encode(array("form" => $form->__toString())); +  static function move_task_handler($task) { +    $start = microtime(true); +    if ($task->percent_complete == 0) { +      batch::start();      } -  } - -  public function reset_sort() { -    $itemids = Input::instance()->get("item"); -    $item = ORM::factory("item") -      ->in("id", $itemids[0]) -      ->find(); -    access::required("view", $item); -    access::required("edit", $item); - -    print organize::get_sort_edit_form($item); -  } - -  public function edit_tags() { -    access::verify_csrf(); - -    $itemids = explode("|", $this->input->post("item")); -    $form = organize::get_tag_form($itemids); -    $old_tags = $form->tags->value; -    if ($form->validate()) { - -      $old_tags = preg_split("/[;,\s]+/", $old_tags); -      sort($old_tags); -      $new_tags = preg_split("/[;,\s]+/", $form->tags->value); -      sort($new_tags); -      $HIGH_VALUE_STRING = "\256"; -      for ($old_index = $new_index = 0;;) { -        $old_tag = $old_index >= count($old_tags) ? $HIGH_VALUE_STRING : $old_tags[$old_index]; -        $new_tag = $new_index >= count($new_tags) ? $HIGH_VALUE_STRING : $new_tags[$new_index]; -        if ($old_tag == $HIGH_VALUE_STRING && $new_tag == $HIGH_VALUE_STRING) { -          break; -        } -        $matches = array(); -        $old_star = false; -        if (preg_match("/(.*)(\*)$/", $old_tag, $matches)) { -          $old_star = true; -          $old_tag = $matches[1]; -        } -        $new_star = false; -        if (preg_match("/(.*)(\*)$/", $new_tag, $matches)) { -          $new_star = true; -          $new_tag = $matches[1]; -        } -        if ($old_tag > $new_tag) { -          // Its missing in the old list so add it -          $this->_add_tag($new_tag, $itemids); -          $new_index++; -        } else if ($old_tag < $new_tag) { -          // Its missing in the new list so its been removed -          $this->_delete_tag($old_tag, $itemids); -          $old_index++; -        } else { -          if ($old_star && !$new_star) { -            // User wants tag to apply to all items, originally only on some of selected -            $this->_update_tag($old_tag, $itemids); -          } // Not changed ignore -          $old_index++; -          $new_index++; -        } +    $target = ORM::factory("item", $task->get("target_id")); +    $source_ids = $task->get("source_ids", array()); +    $idx = $task->get("current", 0); +    $count = 0; +    for (; $idx < count($source_ids) && microtime(true) - $start < 0.5; $idx++) { +      item::move(ORM::factory("item", $source_ids[$idx]), $target); +      $count++; +    } +    $task->set("current", $idx); +    $task->percent_complete = (int)($idx / count($source_ids) * 100); +    $task->status = t2("Moved one file", "Moved %count files", $count); +    if ($task->percent_complete == 100) { +      batch::stop(); +      $task->done = true; +      $task->state = "success"; +      $parents = array(); +      foreach ($target->parents() as $parent) { +        $parents[$parent->id] = 1;        } +      $parents[$target->id] = 1; +      // @TODO do we want to set a flag and then generate them in the run method so we don't +      // potentially store large data items in the task? +      $task->set("tree", self::_tree(ORM::factory("item", 1), $parents)->__toString()); +      $task->set("content", self::_get_micro_thumb_grid($target, 0)->__toString());      } -    print json_encode(array("form" => $form->__toString(), "message" => t("Tags updated")));    } -  public function reset_edit_tags() { -    $itemids = $this->input->get("item"); - -    print organize::get_tag_form($itemids); -  } +  static function rearrange_task_handler($task) { +    $phase = $task->get("phase", "before_drop"); +    $source_ids = $task->get("source_ids"); +    $parent = ORM::factory("item", $task->get("parent_id")); +    $weight = $task->get("weight"); +    $target_id = $task->get("target_id"); +    $is_before = $task->get("before") == "before"; -  private function _add_tag($new_tag, $itemids) { -    // Super lame security stopgap.  This code is going to get rewritten anyway. -    foreach ($itemids as $item_id) { -      $item = ORM::factory("item", $item_id); -      access::required("view", $item); -      access::required("edit", $item); +    // @todo at some point if we allow drag from album tree this needs to be changed +    if ($phase == "dropping") { +      $children = ORM::factory("item") +        ->where("parent_id", $parent->id) +        ->where("weight < ", $weight) +        ->in("id", $source_ids) +        ->orderby(array($parent->sort_column => $parent->sort_order)) +        ->find_all(); +      if ($children->count() == 0) { +        $phase = "after_drop"; +        $task->set("phase", $phase); +      }      } - -    $tag = ORM::factory("tag") -      ->where("name", $new_tag) -      ->find(); -    if ($tag->loaded) { -      $tag->count += count($itemids); -    } else { -      $tag->name = $new_tag; -      $tag->count = count($itemids); +    if ($phase != "dropping") { +      $dropping = false; +      $children = ORM::factory("item") +        ->where("parent_id", $parent->id) +        ->where("weight < ", $weight) +        ->in("id", $source_ids, true) +        ->orderby(array($parent->sort_column => $parent->sort_order)) +        ->find_all();      } -    $tag->save(); +    $completed = $task->get("completed", 0); -    $db = Database::instance(); -    foreach ($itemids as $item_id) { -      $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); -    } -  } +    $start = microtime(true); +    foreach ($children as $child) { +      $step = microtime(true); +      if (microtime(true) - $start > 0.5) { +        break; +      } +      if ($phase == "before_drop" && $child->id == $target_id && $is_before) { +        $task->set("dropping", true); +        $task->set("phase", "dropping"); +        break; +      } +      Database::instance()->query( +        "UPDATE {items} SET `weight` =  " . item::get_max_weight() . +        " WHERE `id` = " . $child->id); -  private function _delete_tag($new_tag, $itemids) { -    // Super lame security stopgap.  This code is going to get rewritten anyway. -    foreach ($itemids as $item_id) { -      $item = ORM::factory("item", $item_id); -      access::required("view", $item); -      access::required("edit", $item); +      $completed++; +      if ($phase == "before_drop" && $child->id == $task->get("target_id")) { +        $task->set("dropping", true); +        $task->set("phase", "dropping"); +        break; +      }      } - -    $tag = ORM::factory("tag") -      ->where("name", $new_tag) -      ->find(); -    $tag->count -= count($itemids); -    if ($tag->count > 0) { -      $tag->save(); +    if ($completed == $task->get("total")) { +      Database::instance()->query( +        "UPDATE {items} SET `sort_column` =  \"weight\"" . +        " WHERE `id` = " . $parent->id); +      module::event("album_rearrange", $parent); +      $task->done = true; +      $task->state = "success"; +      $task->set("content", self::_get_micro_thumb_grid($parent, 0)->__toString()); +      $task->percent_complete = 100;      } else { -      $tag->delete(); -    } - -    $ids = implode(", ", $itemids); -    Database::instance()->query( -      "DELETE FROM {items_tags} WHERE tag_id = {$tag->id} AND item_id IN ($ids);"); -  } - -  private function _update_tag($new_tag, $itemids) { -    // Super lame security stopgap.  This code is going to get rewritten anyway. -    foreach ($itemids as $item_id) { -      $item = ORM::factory("item", $item_id); -      access::required("view", $item); -      access::required("edit", $item); -    } - -    $tag = ORM::factory("tag") -      ->where("name", $new_tag) -      ->find(); - -    $db = Database::instance(); -    $ids = implode(", ", $itemids); -    $result = $db->query( -      "SELECT item_id FROM {items_tags} -        WHERE tag_id = {$tag->id} -          AND item_id IN ($ids)"); - -    $add_items = array_fill_keys($itemids, 1); -    foreach($result as $row) { -      unset($add_items[$row->item_id]); -    } -    $add_items = array_keys($add_items); -    $tag->count += count($add_items); -    $tag->save(); -    foreach ($add_items as $item_id) { -      $db->query("INSERT INTO {items_tags} SET item_id = $item_id, tag_id = {$tag->id};"); -    } -  } - -  private function _getOperationDefinition($item, $operation) { -    switch ($operation) { -    case "move": -      return array("description" => -                     t("Move albums and photos to '%name'", array("name" => $item->title)), -                   "name" => t("Move to '%name'", array("name" => $item->title)), -                   "type" => "move", -                   "runningMsg" => t("Move in progress"), -                   "pauseMsg" => t("The move operation was paused"), -                   "resumeMsg" => t("The move operation was resumed")); -      break; - -    case "rearrange": -      return array("description" => t("Rearrange the order of albums and photos"), -                   "name" => t("Rearrange: %name", array("name" => $item->title)), -                   "type" => "rearrange", -                   "runningMsg" => t("Rearrange in progress"), -                   "pauseMsg" => t("The rearrange operation was paused"), -                   "resumeMsg" => t("The rearrange operation was resumed")); -      break; - -    case "rotateCcw": -      return array("description" => t("Rotate the selected photos counter clockwise"), -                   "name" => t("Rotate images in %name", array("name" => $item->title)), -                   "type" => "rotateCcw", -                   "runningMsg" => t("Rotate Counter Clockwise in progress"), -                   "pauseMsg" => t("The rotate operation was paused"), -                   "resumeMsg" => t("The rotate operation was resumed")); -      break; - -    case "rotateCw": -      return array("description" => t("Rotate the selected photos clockwise"), -                   "name" => t("Rotate images in %name", array("name" => $item->title)), -                   "type" => "rotateCw", -                   "runningMsg" => t("Rotate Clockwise in progress"), -                   "pauseMsg" => t("The rotate operation was paused"), -                   "resumeMsg" => t("The rotate operation was resumed")); -      break; - -    case "delete": -      return array("description" => t("Delete selected photos / albums"), -                   "name" => t("Delete images in %name", array("name" => $item->title)), -                   "type" => "delete", -                   "runningMsg" => t("Delete images in progress"), -                   "pauseMsg" => t("The delete operation was paused"), -                   "resumeMsg" => t("The delete operation was resumed")); -      break; - -    case "albumCover": -      return array("description" => t("Reset Album Cover"), -                   "name" => t("Reset Album cover for %name", array("name" => $item->title)), -                   "type" => "albumCover", -                   "runningMsg" => t("Reset Album Cover in progress"), -                   "pauseMsg" => t("Reset album cover was paused"), -                   "resumeMsg" => t("Reset album cover was resumed")); -      break; - -    default: -      throw new Exception("Operation '$operation' is not implmented"); +      $task->percent_complete = (int)(100 * $completed / $task->get("total"));      } +    $task->set("completed", $completed);    }  } | 
