summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gallery/controllers/simple_uploader.php40
-rw-r--r--modules/gallery/helpers/gallery_event.php16
-rw-r--r--modules/gallery/helpers/photo.php112
-rw-r--r--modules/gallery/models/item.php139
4 files changed, 151 insertions, 156 deletions
diff --git a/modules/gallery/controllers/simple_uploader.php b/modules/gallery/controllers/simple_uploader.php
index 5d32e35f..7a7e7557 100644
--- a/modules/gallery/controllers/simple_uploader.php
+++ b/modules/gallery/controllers/simple_uploader.php
@@ -40,39 +40,45 @@ class Simple_Uploader_Controller extends Controller {
access::required("add", $album);
access::verify_csrf();
+ // The Flash uploader not call /start directly, so simulate it here for now.
+ if (!batch::in_progress()) {
+ batch::start();
+ }
+
+ $form = $this->_get_add_form($album);
+
+ // Uploadify adds its own field to the form, so validate that separately.
$file_validation = new Validation($_FILES);
$file_validation->add_rules(
"Filedata", "upload::valid", "upload::required", "upload::type[gif,jpg,jpeg,png,flv,mp4]");
- if ($file_validation->validate()) {
- // SimpleUploader.swf does not yet call /start directly, so simulate it here for now.
- if (!batch::in_progress()) {
- batch::start();
- }
+ if ($form->validate() && $file_validation->validate()) {
$temp_filename = upload::save("Filedata");
try {
- $name = substr(basename($temp_filename), 10); // Skip unique identifier Kohana adds
- $title = item::convert_filename_to_title($name);
+ $item = ORM::factory("item");
+ $item->name = substr(basename($temp_filename), 10); // Skip unique identifier Kohana adds
+ $item->title = item::convert_filename_to_title($item->name);
+ $item->parent_id = $album->id;
+ $item->set_data_file($temp_filename);
+
$path_info = @pathinfo($temp_filename);
if (array_key_exists("extension", $path_info) &&
in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) {
- $item = movie::create($album, $temp_filename, $name, $title);
+ $item->type = "movie";
+ $item->save();
log::success("content", t("Added a movie"),
html::anchor("movies/$item->id", t("view movie")));
} else {
- $item = photo::create($album, $temp_filename, $name, $title);
+ $item->type = "photo";
+ $item->save();
log::success("content", t("Added a photo"),
html::anchor("photos/$item->id", t("view photo")));
}
- // We currently have no way of showing errors if validation fails, so only call our event
- // handlers if validation passes.
- $form = $this->_get_add_form($album);
- if ($form->validate()) {
- module::event("add_photos_form_completed", $item, $form);
- }
+ module::event("add_photos_form_completed", $item, $form);
} catch (Exception $e) {
- Kohana_Log::add("alert", $e->__toString());
+ // The Flash uploader has no good way of reporting complex errors, so just keep it simple.
+ Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString());
if (file_exists($temp_filename)) {
unlink($temp_filename);
}
@@ -84,7 +90,7 @@ class Simple_Uploader_Controller extends Controller {
print "FILEID: $item->id";
} else {
header("HTTP/1.1 400 Bad Request");
- print "ERROR: " . t("Invalid Upload");
+ print "ERROR: " . t("Invalid upload");
}
}
diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php
index 679d65c2..9452e855 100644
--- a/modules/gallery/helpers/gallery_event.php
+++ b/modules/gallery/helpers/gallery_event.php
@@ -73,6 +73,22 @@ class gallery_event_Core {
static function item_created($item) {
access::add_item($item);
+
+ if ($item->is_photo() || $item->is_movie()) {
+ // Build our thumbnail/resizes.
+ try {
+ graphics::generate($item);
+ } catch (Exception $e) {
+ log::failure("Unable to create a thumbnail for item id {$item->id}");
+ Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString());
+ }
+
+ // If the parent has no cover item, make this it.
+ $parent = $item->parent();
+ if (access::can("edit", $parent) && $parent->album_cover_item_id == null) {
+ item::make_album_cover($item);
+ }
+ }
}
static function item_deleted($item) {
diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php
index aeae7f56..74e30409 100644
--- a/modules/gallery/helpers/photo.php
+++ b/modules/gallery/helpers/photo.php
@@ -24,118 +24,6 @@
* Note: by design, this class does not do any permission checking.
*/
class photo_Core {
- /**
- * Create a new photo.
- * @param integer $parent parent album
- * @param string $filename path to the photo file on disk
- * @param string $name the filename to use for this photo in the album
- * @param integer $title the title of the new photo
- * @param string $description (optional) the longer description of this photo
- * @param string $slug (optional) the url component for this photo
- * @return Item_Model
- */
- static function create($parent, $filename, $name, $title,
- $description=null, $owner_id=null, $slug=null) {
- if (!$parent->loaded() || !$parent->is_album()) {
- throw new Exception("@todo INVALID_PARENT");
- }
-
- if (!is_file($filename)) {
- throw new Exception("@todo MISSING_IMAGE_FILE");
- }
-
- if (strpos($name, "/")) {
- throw new Exception("@todo NAME_CANNOT_CONTAIN_SLASH");
- }
-
- // We don't allow trailing periods as a security measure
- // ref: http://dev.kohanaphp.com/issues/684
- if (rtrim($name, ".") != $name) {
- throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD");
- }
-
- if (filesize($filename) == 0) {
- throw new Exception("@todo EMPTY_INPUT_FILE");
- }
-
- $image_info = getimagesize($filename);
-
- // Force an extension onto the name
- $pi = pathinfo($filename);
- if (empty($pi["extension"])) {
- $pi["extension"] = image_type_to_extension($image_info[2], false);
- $name .= "." . $pi["extension"];
- }
-
- if (empty($slug)) {
- $slug = item::convert_filename_to_slug($name);
- }
-
- $photo = ORM::factory("item");
- $photo->type = "photo";
- $photo->title = $title;
- $photo->description = $description;
- $photo->name = $name;
- $photo->owner_id = $owner_id ? $owner_id : identity::active_user()->id;
- $photo->width = $image_info[0];
- $photo->height = $image_info[1];
- $photo->mime_type = empty($image_info['mime']) ? "application/unknown" : $image_info['mime'];
- $photo->thumb_dirty = 1;
- $photo->resize_dirty = 1;
- $photo->sort_column = "weight";
- $photo->slug = $slug;
-
- // Randomize the name or slug if there's a conflict
- // @todo Improve this. Random numbers are not user friendly
- while (ORM::factory("item")
- ->where("parent_id", "=", $parent->id)
- ->and_open()
- ->where("name", "=", $photo->name)
- ->or_where("slug", "=", $photo->slug)
- ->close()
- ->find()->id) {
- $rand = rand();
- $photo->name = "{$name}.$rand.{$pi['extension']}";
- $photo->slug = "{$slug}-$rand";
- }
-
- // This saves the photo
- $photo->add_to_parent($parent);
-
- /*
- * If the thumb or resize already exists then rename it. We need to do this after the save
- * because the resize_path and thumb_path both call relative_path which caches the
- * path. Before add_to_parent the relative path will be incorrect.
- */
- if (file_exists($photo->resize_path()) ||
- file_exists($photo->thumb_path())) {
- $photo->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"];
- $photo->save();
- }
-
- copy($filename, $photo->file_path());
-
- // @todo: publish this from inside Item_Model::save() when we refactor to the point where
- // there's only one save() happening here.
- module::event("item_created", $photo);
-
- // Build our thumbnail/resizes. If we fail to build thumbnail/resize we assume that the image
- // is bad in some way and discard it.
- try {
- graphics::generate($photo);
- } catch (Exception $e) {
- $photo->delete();
- throw $e;
- }
-
- // If the parent has no cover item, make this it.
- if (access::can("edit", $parent) && $parent->album_cover_item_id == null) {
- item::make_album_cover($photo);
- }
-
- return $photo;
- }
-
static function get_edit_form($photo) {
$form = new Forge("photos/update/$photo->id", "", "post", array("id" => "g-edit-photo-form"));
$form->hidden("from_id");
diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php
index 46b0304e..977b9771 100644
--- a/modules/gallery/models/item.php
+++ b/modules/gallery/models/item.php
@@ -20,13 +20,13 @@
class Item_Model extends ORM_MPTT {
protected $children = 'items';
protected $sorting = array();
+ protected $data_file = null;
var $rules = array(
"name" => array("rules" => array("length[0,255]", "required")),
"title" => array("rules" => array("length[0,255]", "required")),
"slug" => array("rules" => array("length[0,255]", "required")),
"description" => array("rules" => array("length[0,65535]")),
- "parent_id" => array("rules" => array("Item_Model::valid_parent")),
"type" => array("rules" => array("Item_Model::valid_type")),
);
@@ -175,6 +175,14 @@ class Item_Model extends ORM_MPTT {
}
/**
+ * Specify the path to the data file associated with this item. To actually associate it,
+ * you still have to call save().
+ */
+ public function set_data_file($data_file) {
+ $this->data_file = $data_file;
+ }
+
+ /**
* Return the server-relative url to this item, eg:
* /gallery3/index.php/BobsWedding?page=2
* /gallery3/index.php/BobsWedding/Eating-Cake.jpg
@@ -304,7 +312,7 @@ class Item_Model extends ORM_MPTT {
}
$this->relative_path_cache = implode($names, "/");
$this->relative_url_cache = implode($slugs, "/");
- $this->save();
+ return $this;
}
/**
@@ -319,7 +327,7 @@ class Item_Model extends ORM_MPTT {
}
if (!isset($this->relative_path_cache)) {
- $this->_build_relative_caches();
+ $this->_build_relative_caches()->save();
}
return $this->relative_path_cache;
}
@@ -334,7 +342,7 @@ class Item_Model extends ORM_MPTT {
}
if (!isset($this->relative_url_cache)) {
- $this->_build_relative_caches();
+ $this->_build_relative_caches()->save();
}
return $this->relative_url_cache;
}
@@ -368,6 +376,7 @@ class Item_Model extends ORM_MPTT {
unset($significant_changes["relative_url_cache"]);
unset($significant_changes["relative_path_cache"]);
+
if (!empty($this->changed) && $significant_changes) {
$this->updated = time();
if (!$this->loaded()) {
@@ -386,15 +395,37 @@ class Item_Model extends ORM_MPTT {
if (empty($this->owner_id)) {
$this->owner_id = identity::active_user()->id;
}
+
+ // Make an url friendly slug from the name, if necessary
if (empty($this->slug)) {
$tmp = pathinfo($this->name, PATHINFO_FILENAME);
$tmp = preg_replace("/[^A-Za-z0-9-_]+/", "-", $tmp);
$this->slug = trim($tmp, "-");
}
- // Randomize the name or slug if there's a conflict
+ if ($this->is_movie() || $this->is_photo()) {
+ $image_info = getimagesize($this->data_file);
+
+ if ($this->is_photo()) {
+ $this->width = $image_info[0];
+ $this->height = $image_info[1];
+ $this->mime_type =
+ empty($image_info['mime']) ? "application/unknown" : $image_info['mime'];
+ }
+
+ // Force an extension onto the name if necessary
+ $pi = pathinfo($this->data_file);
+ if (empty($pi["extension"])) {
+ $pi["extension"] = image_type_to_extension($image_info[2], false);
+ $this->name .= "." . $pi["extension"];
+ }
+
+ }
+
+ // Randomize the name or slug if there's a conflict. Preserve the extension.
// @todo Improve this. Random numbers are not user friendly
- $base_name = $this->name;
+ $base_name = pathinfo($this->name, PATHINFO_FILENAME);
+ $base_ext = pathinfo($this->name, PATHINFO_EXTENSION);
$base_slug = $this->slug;
while (ORM::factory("item")
->where("parent_id", "=", $this->parent_id)
@@ -404,19 +435,46 @@ class Item_Model extends ORM_MPTT {
->close()
->find()->id) {
$rand = rand();
- $this->name = "$base_name-$rand";
+ if ($base_ext) {
+ $this->name = "$base_name-$rand.$base_ext";
+ } else {
+ $this->name = "$base_name-$rand";
+ }
$this->slug = "$base_slug-$rand";
}
parent::save();
- // Call this after we finish saving so that the paths are correct.
- if ($this->is_album()) {
+ // Build our url caches and save again. If we could depend on a save happening later we
+ // could defer this 2nd save.
+ $this->_build_relative_caches();
+ parent::save();
+
+ // Take any actions that we can only do once all our paths are set correctly after saving.
+ switch ($this->type) {
+ case "album":
mkdir($this->file_path());
mkdir(dirname($this->thumb_path()));
mkdir(dirname($this->resize_path()));
+ break;
+
+ case "photo":
+ // The thumb or resize may already exist in the case where a movie and a photo generate
+ // a thumbnail of the same name (eg, foo.flv movie and foo.jpg photo will generate
+ // foo.jpg thumbnail). If that happens, randomize and save again.
+ if (file_exists($this->resize_path()) ||
+ file_exists($this->thumb_path())) {
+ $pi = pathinfo($this->name);
+ $this->name = $pi["filename"] . "-" . rand() . "." . $pi["extension"];
+ parent::save();
+ }
+
+ copy($this->data_file, $this->file_path());
+ break;
}
+ // This will almost definitely trigger another save, so put it at the end so that we're
+ // tail recursive.
module::event("item_created", $this);
} else {
// Update an existing item
@@ -691,8 +749,8 @@ class Item_Model extends ORM_MPTT {
if (!$array) {
// The root item has different rules for the name and slug.
if ($this->id == 1) {
- $this->rules["name"]["rules"][] = "length[0]";
- $this->rules["slug"]["rules"][] = "length[0]";
+ $this->rules["name"] = array("rules" => array("length[0]"));
+ $this->rules["slug"] = array("rules" => array("length[0]"));
}
// Names and slugs can't conflict
@@ -700,20 +758,28 @@ class Item_Model extends ORM_MPTT {
$this->rules["slug"]["callbacks"][] = array($this, "valid_slug");
}
+ // Movies and photos must have data files
+ if ($this->is_photo() || $this->is_movie() && !$this->loaded()) {
+ $this->rules["name"]["callbacks"][] = array($this, "valid_data_file");
+ }
+
+ // All items must have a legal parent
+ $this->rules["parent_id"]["callbacks"][] = array($this, "valid_parent");
+
parent::validate($array);
}
/**
* Validate that the desired slug does not conflict.
*/
- public function valid_slug(Validation $v, $value) {
- if (preg_match("/[^A-Za-z0-9-_]/", $value)) {
+ public function valid_slug(Validation $v, $field) {
+ if (preg_match("/[^A-Za-z0-9-_]/", $this->slug)) {
$v->add_error("slug", "not_url_safe");
} else if (db::build()
->from("items")
->where("parent_id", "=", $this->parent_id)
->where("id", "<>", $this->id)
- ->where("slug", "=", $value)
+ ->where("slug", "=", $this->slug)
->count_records()) {
$v->add_error("slug", "conflict");
}
@@ -723,36 +789,55 @@ class Item_Model extends ORM_MPTT {
* Validate the item name. It can't conflict with other names, can't contain slashes or
* trailing periods.
*/
- public function valid_name(Validation $v, $value) {
- if (strpos($value, "/") !== false) {
+ public function valid_name(Validation $v, $field) {
+ if (strpos($this->name, "/") !== false) {
$v->add_error("name", "no_slashes");
- } else if (rtrim($value, ".") !== $value) {
+ } else if (rtrim($this->name, ".") !== $this->name) {
$v->add_error("name", "no_trailing_period");
} else if (db::build()
->from("items")
->where("parent_id", "=", $this->parent_id)
->where("id", "<>", $this->id)
- ->where("name", "=", $value)
+ ->where("name", "=", $this->name)
->count_records()) {
$v->add_error("name", "conflict");
}
}
/**
- * Make sure that the type is valid.
+ * Make sure that the data file is well formed (it exists and isn't empty).
*/
- static function valid_type($value) {
- return in_array($value, array("album", "photo", "movie"));
+ public function valid_data_file(Validation $v, $field) {
+ if (!is_file($this->data_file)) {
+ $v->add_error("file", "bad_path");
+ } else if (filesize($this->data_file) == 0) {
+ $v->add_error("file", "empty_file");
+ }
}
/**
* Make sure that the parent id refers to an album.
*/
- static function valid_parent($value) {
- return db::build()
- ->from("items")
- ->where("id", "=", $value)
- ->where("type", "=", "album")
- ->count_records() == 1;
+ public function valid_parent(Validation $v, $field) {
+ if ($this->id == 1) {
+ if ($this->parent_id != 0) {
+ $v->add_error("parent_id", "invalid");
+ }
+ } else {
+ if (db::build()
+ ->from("items")
+ ->where("id", "=", $this->parent_id)
+ ->where("type", "=", "album")
+ ->count_records() != 1) {
+ $v->add_error("parent_id", "invalid");
+ }
+ }
+ }
+
+ /**
+ * Make sure that the type is valid.
+ */
+ static function valid_type($value) {
+ return in_array($value, array("album", "photo", "movie"));
}
}