summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.build_number2
-rw-r--r--installer/install.sql2
-rw-r--r--modules/gallery/helpers/gallery_installer.php43
-rw-r--r--modules/gallery/helpers/gallery_task.php113
-rw-r--r--modules/gallery/helpers/item.php63
-rw-r--r--modules/gallery/models/item.php127
-rw-r--r--modules/gallery/module.info2
-rw-r--r--modules/gallery/tests/Item_Model_Test.php194
8 files changed, 419 insertions, 127 deletions
diff --git a/.build_number b/.build_number
index 1c2725f0..1d2b9988 100644
--- a/.build_number
+++ b/.build_number
@@ -3,4 +3,4 @@
; process. You don't need to edit it. In fact..
;
; DO NOT EDIT THIS FILE BY HAND!
-build_number=298
+build_number=299
diff --git a/installer/install.sql b/installer/install.sql
index b01c5a7c..70cf0c86 100644
--- a/installer/install.sql
+++ b/installer/install.sql
@@ -244,7 +244,7 @@ CREATE TABLE {modules} (
KEY `weight` (`weight`)
) AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
/*!40101 SET character_set_client = @saved_cs_client */;
-INSERT INTO {modules} VALUES (1,1,'gallery',53,1);
+INSERT INTO {modules} VALUES (1,1,'gallery',54,1);
INSERT INTO {modules} VALUES (2,1,'user',4,2);
INSERT INTO {modules} VALUES (3,1,'comment',7,3);
INSERT INTO {modules} VALUES (4,1,'organize',4,4);
diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php
index fe651a4e..86ff7ce5 100644
--- a/modules/gallery/helpers/gallery_installer.php
+++ b/modules/gallery/helpers/gallery_installer.php
@@ -315,7 +315,7 @@ class gallery_installer {
module::set_var("gallery", "lock_timeout", 1);
module::set_var("gallery", "movie_extract_frame_time", 3);
- module::set_version("gallery", 53);
+ module::set_version("gallery", 54);
}
static function upgrade($version) {
@@ -743,6 +743,47 @@ class gallery_installer {
module::set_var("gallery", "movie_extract_frame_time", 3);
module::set_version("gallery", $version = 53);
}
+
+ if ($version == 53) {
+ // In v54, we changed how we check for name and slug conflicts in Item_Model. Previously,
+ // we checked the whole filename. As a result, "foo.jpg" and "foo.png" were not considered
+ // conflicting if their slugs were different (a rare case in practice since server_add and
+ // uploader would give them both the same slug "foo"). Now, we check the filename without its
+ // extension. This upgrade stanza fixes any conflicts where they were previously allowed.
+
+ // This might be slow, but if it times out it can just pick up where it left off.
+
+ // Find and loop through each conflict (e.g. "foo.jpg", "foo.png", and "foo.flv" are one
+ // conflict; "bar.jpg", "bar.png", and "bar.flv" are another)
+ foreach (db::build()
+ ->select_distinct(array("parent_base_name" =>
+ db::expr("CONCAT(`parent_id`, ':', LOWER(SUBSTR(`name`, 1, LOCATE('.', `name`) - 1)))")))
+ ->select(array("C" => "COUNT(\"*\")"))
+ ->from("items")
+ ->where("type", "<>", "album")
+ ->having("C", ">", 1)
+ ->group_by("parent_base_name")
+ ->execute() as $conflict) {
+ list ($parent_id, $base_name) = explode(":", $conflict->parent_base_name, 2);
+ $base_name_escaped = Database::escape_for_like($base_name);
+ // Loop through the items for each conflict
+ foreach (db::build()
+ ->from("items")
+ ->select("id")
+ ->where("type", "<>", "album")
+ ->where("parent_id", "=", $parent_id)
+ ->where("name", "LIKE", "{$base_name_escaped}.%")
+ ->limit(1000000) // required to satisfy SQL syntax (no offset without limit)
+ ->offset(1) // skips the 0th item
+ ->execute() as $row) {
+ set_time_limit(30);
+ $item = ORM::factory("item", $row->id);
+ $item->name = $item->name; // this will force Item_Model to check for conflicts on save
+ $item->save();
+ }
+ }
+ module::set_version("gallery", $version = 54);
+ }
}
static function uninstall() {
diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php
index 8eb981a2..856d2639 100644
--- a/modules/gallery/helpers/gallery_task.php
+++ b/modules/gallery/helpers/gallery_task.php
@@ -26,11 +26,13 @@ class gallery_task_Core {
const FIX_STATE_RUN_DUPE_SLUGS = 5;
const FIX_STATE_START_DUPE_NAMES = 6;
const FIX_STATE_RUN_DUPE_NAMES = 7;
- const FIX_STATE_START_REBUILD_ITEM_CACHES = 8;
- const FIX_STATE_RUN_REBUILD_ITEM_CACHES = 9;
- const FIX_STATE_START_MISSING_ACCESS_CACHES = 10;
- const FIX_STATE_RUN_MISSING_ACCESS_CACHES = 11;
- const FIX_STATE_DONE = 12;
+ const FIX_STATE_START_DUPE_BASE_NAMES = 8;
+ const FIX_STATE_RUN_DUPE_BASE_NAMES = 9;
+ const FIX_STATE_START_REBUILD_ITEM_CACHES = 10;
+ const FIX_STATE_RUN_REBUILD_ITEM_CACHES = 11;
+ const FIX_STATE_START_MISSING_ACCESS_CACHES = 12;
+ const FIX_STATE_RUN_MISSING_ACCESS_CACHES = 13;
+ const FIX_STATE_DONE = 14;
static function available_tasks() {
$dirty_count = graphics::find_dirty_images_query()->count_records();
@@ -348,8 +350,9 @@ class gallery_task_Core {
// album audit (permissions and bogus album covers): 1 operation for every album
$total += db::build()->where("type", "=", "album")->count_records("items");
- // one operation for each missing slug, name and access cache
- foreach (array("find_dupe_slugs", "find_dupe_names", "find_missing_access_caches") as $func) {
+ // one operation for each dupe slug, dupe name, dupe base name, and missing access cache
+ foreach (array("find_dupe_slugs", "find_dupe_names", "find_dupe_base_names",
+ "find_missing_access_caches") as $func) {
foreach (self::$func() as $row) {
$total++;
}
@@ -489,11 +492,12 @@ class gallery_task_Core {
$task->set("stack", implode(" ", $stack));
$state = self::FIX_STATE_RUN_DUPE_NAMES;
} else {
- $state = self::FIX_STATE_START_ALBUMS;
+ $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
}
break;
case self::FIX_STATE_RUN_DUPE_NAMES:
+ // NOTE: This does *not* attempt to fix the file system!
$stack = explode(" ", $task->get("stack"));
list ($parent_id, $name) = explode(":", array_pop($stack));
@@ -505,9 +509,16 @@ class gallery_task_Core {
->find_all(1, 1);
if ($conflicts->count() && $conflict = $conflicts->current()) {
$task->log("Fixing conflicting name for item id {$conflict->id}");
+ if (!$conflict->is_album() && preg_match("/^(.*)(\.[^\.\/]*?)$/", $conflict->name, $matches)) {
+ $item_base_name = $matches[1];
+ $item_extension = $matches[2]; // includes a leading dot
+ } else {
+ $item_base_name = $conflict->name;
+ $item_extension = "";
+ }
db::build()
->update("items")
- ->set("name", $name . "-" . (string)rand(1000, 9999))
+ ->set("name", $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension)
->where("id", "=", $conflict->id)
->execute();
@@ -522,6 +533,74 @@ class gallery_task_Core {
$completed++;
if (empty($stack)) {
+ $state = self::FIX_STATE_START_DUPE_BASE_NAMES;
+ }
+ break;
+
+ case self::FIX_STATE_START_DUPE_BASE_NAMES:
+ $stack = array();
+ foreach (self::find_dupe_base_names() as $row) {
+ list ($parent_id, $base_name) = explode(":", $row->parent_base_name, 2);
+ $stack[] = join(":", array($parent_id, $base_name));
+ }
+ if ($stack) {
+ $task->set("stack", implode(" ", $stack));
+ $state = self::FIX_STATE_RUN_DUPE_BASE_NAMES;
+ } else {
+ $state = self::FIX_STATE_START_ALBUMS;
+ }
+ break;
+
+ case self::FIX_STATE_RUN_DUPE_BASE_NAMES:
+ // NOTE: This *does* attempt to fix the file system! So, it must go *after* run_dupe_names.
+ $stack = explode(" ", $task->get("stack"));
+ list ($parent_id, $base_name) = explode(":", array_pop($stack));
+ $base_name_escaped = Database::escape_for_like($base_name);
+
+ $fixed = 0;
+ // We want to leave the first one alone and update all conflicts to be random values.
+ $conflicts = ORM::factory("item")
+ ->where("parent_id", "=", $parent_id)
+ ->where("name", "LIKE", "{$base_name_escaped}.%")
+ ->where("type", "<>", "album")
+ ->find_all(1, 1);
+ if ($conflicts->count() && $conflict = $conflicts->current()) {
+ $task->log("Fixing conflicting name for item id {$conflict->id}");
+ if (preg_match("/^(.*)(\.[^\.\/]*?)$/", $conflict->name, $matches)) {
+ $item_base_name = $matches[1]; // unlike $base_name, this always maintains capitalization
+ $item_extension = $matches[2]; // includes a leading dot
+ } else {
+ $item_base_name = $conflict->name;
+ $item_extension = "";
+ }
+ // Unlike conflicts found in run_dupe_names, these items are likely to have an intact
+ // file system. Let's use the item save logic to rebuild the paths and rename the files
+ // if possible.
+ try {
+ $conflict->name = $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension;
+ $conflict->validate();
+ // If we get here, we're safe to proceed with save
+ $conflict->save();
+ } catch (Exception $e) {
+ // Didn't work. Edit database directly without fixing file system.
+ db::build()
+ ->update("items")
+ ->set("name", $item_base_name . "-" . (string)rand(1000, 9999) . $item_extension)
+ ->where("id", "=", $conflict->id)
+ ->execute();
+ }
+
+ // We fixed one conflict, but there might be more so put this parent back on the stack
+ // and try again. We won't consider it completed when we don't fix a conflict. This
+ // guarantees that we won't spend too long fixing one set of conflicts, and that we
+ // won't stop before all are fixed.
+ $stack[] = "$parent_id:$base_name";
+ break;
+ }
+ $task->set("stack", implode(" ", $stack));
+ $completed++;
+
+ if (empty($stack)) {
$state = self::FIX_STATE_START_ALBUMS;
}
break;
@@ -669,18 +748,32 @@ class gallery_task_Core {
}
static function find_dupe_names() {
+ // looking for photos, movies, and albums
return db::build()
->select_distinct(
array("parent_name" => db::expr("CONCAT(`parent_id`, ':', LOWER(`name`))")))
->select("id")
->select(array("C" => "COUNT(\"*\")"))
->from("items")
- ->where("type", "<>", "album")
->having("C", ">", 1)
->group_by("parent_name")
->execute();
}
+ static function find_dupe_base_names() {
+ // looking for photos or movies, not albums
+ return db::build()
+ ->select_distinct(
+ array("parent_base_name" => db::expr("CONCAT(`parent_id`, ':', LOWER(SUBSTR(`name`, 1, LOCATE('.', `name`) - 1)))")))
+ ->select("id")
+ ->select(array("C" => "COUNT(\"*\")"))
+ ->from("items")
+ ->where("type", "<>", "album")
+ ->having("C", ">", 1)
+ ->group_by("parent_base_name")
+ ->execute();
+ }
+
static function find_empty_item_caches($limit) {
return db::build()
->select("items.id")
diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php
index b2c4cadf..386eeb08 100644
--- a/modules/gallery/helpers/item.php
+++ b/modules/gallery/helpers/item.php
@@ -39,55 +39,28 @@ class item_Core {
}
}
- $source->parent_id = $target->id;
-
- // Moving may result in name or slug conflicts. If that happens, try up to 5 times to pick a
- // random name (or slug) to avoid the conflict.
$orig_name = $source->name;
- $orig_name_filename = pathinfo($source->name, PATHINFO_FILENAME);
- $orig_name_extension = pathinfo($source->name, PATHINFO_EXTENSION);
- $orig_slug = $source->slug;
- for ($i = 0; $i < 5; $i++) {
- try {
- $source->save();
- if ($orig_name != $source->name) {
- switch ($source->type) {
- case "album":
- message::info(
- t("Album <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
- array("old_name" => $orig_name, "new_name" => $source->name)));
- break;
-
- case "photo":
- message::info(
- t("Photo <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
- array("old_name" => $orig_name, "new_name" => $source->name)));
- break;
+ $source->parent_id = $target->id;
+ $source->save();
+ if ($orig_name != $source->name) {
+ switch ($source->type) {
+ case "album":
+ message::info(
+ t("Album <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
+ array("old_name" => $orig_name, "new_name" => $source->name)));
+ break;
- case "movie":
- message::info(
- t("Movie <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
- array("old_name" => $orig_name, "new_name" => $source->name)));
- break;
- }
- }
+ case "photo":
+ message::info(
+ t("Photo <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
+ array("old_name" => $orig_name, "new_name" => $source->name)));
break;
- } catch (ORM_Validation_Exception $e) {
- $rand = rand(10, 99);
- $errors = $e->validation->errors();
- if (isset($errors["name"])) {
- $source->name = $orig_name_filename . "-{$rand}." . $orig_name_extension;
- unset($errors["name"]);
- }
- if (isset($errors["slug"])) {
- $source->slug = $orig_slug . "-{$rand}";
- unset($errors["slug"]);
- }
- if ($errors) {
- // There were other validation issues-- we don't know how to handle those
- throw $e;
- }
+ case "movie":
+ message::info(
+ t("Movie <b>%old_name</b> renamed to <b>%new_name</b> to avoid a conflict",
+ array("old_name" => $orig_name, "new_name" => $source->name)));
+ break;
}
}
diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php
index bbfeee47..e4b997aa 100644
--- a/modules/gallery/models/item.php
+++ b/modules/gallery/models/item.php
@@ -338,10 +338,11 @@ class Item_Model_Core extends ORM_MPTT {
if (empty($this->slug)) {
$this->slug = item::convert_filename_to_slug(pathinfo($this->name, PATHINFO_FILENAME));
- // If the filename is all invalid characters, then the slug may be empty here. Pick a
- // random value.
+ // If the filename is all invalid characters, then the slug may be empty here. We set a
+ // generic name ("photo", "movie", or "album") based on its type, then rely on
+ // check_and_fix_conflicts to ensure it doesn't conflict with another name.
if (empty($this->slug)) {
- $this->slug = (string)rand(1000, 9999);
+ $this->slug = $this->type;
}
}
@@ -362,7 +363,7 @@ class Item_Model_Core extends ORM_MPTT {
}
}
- $this->_randomize_name_or_slug_on_conflict();
+ $this->_check_and_fix_conflicts();
parent::save();
@@ -382,16 +383,6 @@ class Item_Model_Core extends ORM_MPTT {
case "photo":
case "movie":
- // 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"] . "-" . random::int() . "." . $pi["extension"];
- parent::save();
- }
-
copy($this->data_file, $this->file_path());
break;
}
@@ -435,7 +426,7 @@ class Item_Model_Core extends ORM_MPTT {
$this->relative_url_cache = null;
}
- $this->_randomize_name_or_slug_on_conflict();
+ $this->_check_and_fix_conflicts();
parent::save();
@@ -528,30 +519,60 @@ class Item_Model_Core extends ORM_MPTT {
/**
* Check to see if there's another item that occupies the same name or slug that this item
- * intends to use, and if so choose a new name/slug while preserving the extension.
- * @todo Improve this. Random numbers are not user friendly
+ * intends to use, and if so choose a new name/slug while preserving the extension. Since this
+ * checks the name without its extension, it covers possible collisions with thumbs and resizes
+ * as well (e.g. between the thumbs of movie "foo.flv" and photo "foo.jpg").
*/
- private function _randomize_name_or_slug_on_conflict() {
- $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)
- ->where("id", $this->id ? "<>" : "IS NOT", $this->id)
- ->and_open()
- ->where("name", "=", $this->name)
- ->or_where("slug", "=", $this->slug)
- ->close()
- ->find()->id) {
- $rand = random::int();
- if ($base_ext) {
- $this->name = "$base_name-$rand.$base_ext";
+ private function _check_and_fix_conflicts() {
+ $suffix_num = 1;
+ $suffix = "";
+ if ($this->is_album()) {
+ while (db::build()
+ ->from("items")
+ ->where("parent_id", "=", $this->parent_id)
+ ->where("id", $this->id ? "<>" : "IS NOT", $this->id)
+ ->and_open()
+ ->where("name", "=", "{$this->name}{$suffix}")
+ ->or_where("slug", "=", "{$this->slug}{$suffix}")
+ ->close()
+ ->count_records()) {
+ $suffix = "-" . (($suffix_num <= 99) ? sprintf("%02d", $suffix_num++) : random::int());
+ }
+ if ($suffix) {
+ $this->name = "{$this->name}{$suffix}";
+ $this->slug = "{$this->slug}{$suffix}";
+ $this->relative_path_cache = null;
+ $this->relative_url_cache = null;
+ }
+ } else {
+ // Split the filename into its base and extension. This uses a regexp similar to
+ // legal_file::change_extension (which isn't always the same as pathinfo).
+ if (preg_match("/^(.*)(\.[^\.\/]*?)$/", $this->name, $matches)) {
+ $base_name = $matches[1];
+ $extension = $matches[2]; // includes a leading dot
} else {
- $this->name = "$base_name-$rand";
+ $base_name = $this->name;
+ $extension = "";
+ }
+ $base_name_escaped = Database::escape_for_like($base_name);
+ // Note: below query uses LIKE with wildcard % at end, which is still sargable (i.e. quick)
+ while (db::build()
+ ->from("items")
+ ->where("parent_id", "=", $this->parent_id)
+ ->where("id", $this->id ? "<>" : "IS NOT", $this->id)
+ ->and_open()
+ ->where("name", "LIKE", "{$base_name_escaped}{$suffix}.%")
+ ->or_where("slug", "=", "{$this->slug}{$suffix}")
+ ->close()
+ ->count_records()) {
+ $suffix = "-" . (($suffix_num <= 99) ? sprintf("%02d", $suffix_num++) : random::int());
+ }
+ if ($suffix) {
+ $this->name = "{$base_name}{$suffix}{$extension}";
+ $this->slug = "{$this->slug}{$suffix}";
+ $this->relative_path_cache = null;
+ $this->relative_url_cache = null;
}
- $this->slug = "$base_slug-$rand";
- $this->relative_path_cache = null;
- $this->relative_url_cache = null;
}
}
@@ -871,14 +892,32 @@ class Item_Model_Core extends ORM_MPTT {
}
}
- if (db::build()
- ->from("items")
- ->where("parent_id", "=", $this->parent_id)
- ->where("name", "=", $this->name)
- ->merge_where($this->id ? array(array("id", "<>", $this->id)) : null)
- ->count_records()) {
- $v->add_error("name", "conflict");
- return;
+ if ($this->is_album()) {
+ if (db::build()
+ ->from("items")
+ ->where("parent_id", "=", $this->parent_id)
+ ->where("name", "=", $this->name)
+ ->merge_where($this->id ? array(array("id", "<>", $this->id)) : null)
+ ->count_records()) {
+ $v->add_error("name", "conflict");
+ return;
+ }
+ } else {
+ if (preg_match("/^(.*)(\.[^\.\/]*?)$/", $this->name, $matches)) {
+ $base_name = $matches[1];
+ } else {
+ $base_name = $this->name;
+ }
+ $base_name_escaped = Database::escape_for_like($base_name);
+ if (db::build()
+ ->from("items")
+ ->where("parent_id", "=", $this->parent_id)
+ ->where("name", "LIKE", "{$base_name_escaped}.%")
+ ->merge_where($this->id ? array(array("id", "<>", $this->id)) : null)
+ ->count_records()) {
+ $v->add_error("name", "conflict");
+ return;
+ }
}
if ($this->parent_id == 1 && Kohana::auto_load("{$this->slug}_Controller")) {
diff --git a/modules/gallery/module.info b/modules/gallery/module.info
index 566ca2eb..b6cefe39 100644
--- a/modules/gallery/module.info
+++ b/modules/gallery/module.info
@@ -1,6 +1,6 @@
name = "Gallery 3"
description = "Gallery core application"
-version = 53
+version = 54
author_name = "Gallery Team"
author_url = "http://codex.galleryproject.org/Gallery:Team"
info_url = "http://codex.galleryproject.org/Gallery3:Modules:gallery"
diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php
index c45bbc3c..41361b32 100644
--- a/modules/gallery/tests/Item_Model_Test.php
+++ b/modules/gallery/tests/Item_Model_Test.php
@@ -136,19 +136,6 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$this->assert_true(false, "Shouldn't get here");
}
- public function item_rename_over_existing_name_gets_uniqified_test() {
- // Create a test photo
- $item = test::random_photo();
- $item2 = test::random_photo();
-
- $item->name = $item2->name;
- $item->save();
-
- // foo.jpg should become foo-####.jpg
- $this->assert_true(
- preg_match("/" . str_replace(".jpg", "", $item2->name) . "-\d+\.jpg/", $item->name));
- }
-
public function move_album_test() {
$album2 = test::random_album();
$album1 = test::random_album($album2);
@@ -205,7 +192,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$this->assert_equal($fullsize_file, file_get_contents($photo->file_path()));
}
- public function move_album_with_conflicting_target_gets_uniqified_test() {
+ public function move_album_with_conflicting_target_gets_uniquified_test() {
$album = test::random_album();
$source = test::random_album_unsaved($album);
$source->name = $album->name;
@@ -217,9 +204,9 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$source->parent_id = item::root()->id;
$source->save();
- // foo should become foo-####
- $this->assert_true(preg_match("/{$album->name}-\d+/", $source->name));
- $this->assert_true(preg_match("/{$album->slug}-\d+/", $source->slug));
+ // foo should become foo-01
+ $this->assert_same("{$album->name}-01", $source->name);
+ $this->assert_same("{$album->slug}-01", $source->slug);
}
public function move_album_fails_wrong_target_type_test() {
@@ -239,7 +226,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$this->assert_true(false, "Shouldn't get here");
}
- public function move_photo_with_conflicting_target_gets_uniqified_test() {
+ public function move_photo_with_conflicting_target_gets_uniquified_test() {
$photo1 = test::random_photo();
$album = test::random_album();
$photo2 = test::random_photo_unsaved($album);
@@ -247,17 +234,16 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$photo2->save();
// $photo1 and $photo2 have the same name, so if we move $photo1 into the root they should
- // conflict and get uniqified.
+ // conflict and get uniquified.
$photo2->parent_id = item::root()->id;
$photo2->save();
- // foo.jpg should become foo-####.jpg
- $this->assert_true(
- preg_match("/" . str_replace(".jpg", "", $photo1->name) . "-\d+\.jpg/", $photo2->name));
+ // foo.jpg should become foo-01.jpg
+ $this->assert_same(pathinfo($photo1->name, PATHINFO_FILENAME) . "-01.jpg", $photo2->name);
- // foo should become foo
- $this->assert_true(preg_match("/{$photo1->slug}/", $photo2->name));
+ // foo should become foo-01
+ $this->assert_same("{$photo1->slug}-01", $photo2->slug);
}
public function move_album_inside_descendent_fails_test() {
@@ -535,4 +521,164 @@ class Item_Model_Test extends Gallery_Unit_Test_Case {
$album->name = $album->name . ".foo.bar";
$album->save();
}
+
+ public function no_conflict_when_parents_different_test() {
+ $parent1 = test::random_album();
+ $parent2 = test::random_album();
+ $photo1 = test::random_photo($parent1);
+ $photo2 = test::random_photo($parent2);
+
+ $photo2->name = $photo1->name;
+ $photo2->slug = $photo1->slug;
+ $photo2->save();
+
+ // photo2 has same name and slug as photo1 but different parent - no conflict.
+ $this->assert_same($photo1->name, $photo2->name);
+ $this->assert_same($photo1->slug, $photo2->slug);
+ }
+
+ public function fix_conflict_when_names_identical_test() {
+ $parent = test::random_album();
+ $photo1 = test::random_photo($parent);
+ $photo2 = test::random_photo($parent);
+
+ $photo1_orig_base = pathinfo($photo1->name, PATHINFO_FILENAME);
+ $photo2_orig_slug = $photo2->slug;
+
+ $photo2->name = $photo1->name;
+ $photo2->save();
+
+ // photo2 has same name as photo1 - conflict resolved by renaming with -01.
+ $this->assert_same("{$photo1_orig_base}-01.jpg", $photo2->name);
+ $this->assert_same("{$photo2_orig_slug}-01", $photo2->slug);
+ }
+
+ public function fix_conflict_when_slugs_identical_test() {
+ $parent = test::random_album();
+ $photo1 = test::random_photo($parent);
+ $photo2 = test::random_photo($parent);
+
+ $photo2_orig_base = pathinfo($photo2->name, PATHINFO_FILENAME);
+
+ $photo2->slug = $photo1->slug;
+ $photo2->save();
+
+ // photo2 has same slug as photo1 - conflict resolved by renaming with -01.
+ $this->assert_same("{$photo2_orig_base}-01.jpg", $photo2->name);
+ $this->assert_same("{$photo1->slug}-01", $photo2->slug);
+ }
+
+ public function no_conflict_when_parents_different_for_albums_test() {
+ $parent1 = test::random_album();
+ $parent2 = test::random_album();
+ $album1 = test::random_album($parent1);
+ $album2 = test::random_album($parent2);
+
+ $album2->name = $album1->name;
+ $album2->slug = $album1->slug;
+ $album2->save();
+
+ // album2 has same name and slug as album1 but different parent - no conflict.
+ $this->assert_same($album1->name, $album2->name);
+ $this->assert_same($album1->slug, $album2->slug);
+ }
+
+ public function fix_conflict_when_names_identical_for_albums_test() {
+ $parent = test::random_album();
+ $album1 = test::random_album($parent);
+ $album2 = test::random_album($parent);
+
+ $album2_orig_slug = $album2->slug;
+
+ $album2->name = $album1->name;
+ $album2->save();
+
+ // album2 has same name as album1 - conflict resolved by renaming with -01.
+ $this->assert_same("{$album1->name}-01", $album2->name);
+ $this->assert_same("{$album2_orig_slug}-01", $album2->slug);
+ }
+
+ public function fix_conflict_when_slugs_identical_for_albums_test() {
+ $parent = test::random_album();
+ $album1 = test::random_album($parent);
+ $album2 = test::random_album($parent);
+
+ $album2_orig_name = $album2->name;
+
+ $album2->slug = $album1->slug;
+ $album2->save();
+
+ // album2 has same slug as album1 - conflict resolved by renaming with -01.
+ $this->assert_same("{$album2_orig_name}-01", $album2->name);
+ $this->assert_same("{$album1->slug}-01", $album2->slug);
+ }
+
+ public function no_conflict_when_base_names_identical_between_album_and_photo_test() {
+ $parent = test::random_album();
+ $album = test::random_album($parent);
+ $photo = test::random_photo($parent);
+
+ $photo_orig_slug = $photo->slug;
+
+ $photo->name = "{$album->name}.jpg";
+ $photo->save();
+
+ // photo has same base name as album - no conflict.
+ $this->assert_same("{$album->name}.jpg", $photo->name);
+ $this->assert_same($photo_orig_slug, $photo->slug);
+ }
+
+ public function fix_conflict_when_full_names_identical_between_album_and_photo_test() {
+ $parent = test::random_album();
+ $photo = test::random_photo($parent);
+ $album = test::random_album($parent);
+
+ $album_orig_slug = $album->slug;
+
+ $album->name = $photo->name;
+ $album->save();
+
+ // album has same full name as album - conflict resolved by renaming with -01.
+ $this->assert_same("{$photo->name}-01", $album->name);
+ $this->assert_same("{$album_orig_slug}-01", $album->slug);
+ }
+
+ public function fix_conflict_when_slugs_identical_between_album_and_photo_test() {
+ $parent = test::random_album();
+ $album = test::random_album($parent);
+ $photo = test::random_photo($parent);
+
+ $photo_orig_base = pathinfo($photo->name, PATHINFO_FILENAME);
+
+ $photo->slug = $album->slug;
+ $photo->save();
+
+ // photo has same slug as album - conflict resolved by renaming with -01.
+ $this->assert_same("{$photo_orig_base}-01.jpg", $photo->name);
+ $this->assert_same("{$album->slug}-01", $photo->slug);
+ }
+
+ public function fix_conflict_when_base_names_identical_between_jpg_png_flv_test() {
+ $parent = test::random_album();
+ $item1 = test::random_photo($parent);
+ $item2 = test::random_photo($parent);
+ $item3 = test::random_movie($parent);
+
+ $item1_orig_base = pathinfo($item1->name, PATHINFO_FILENAME);
+ $item2_orig_slug = $item2->slug;
+ $item3_orig_slug = $item3->slug;
+
+ $item2->set_data_file(MODPATH . "gallery/images/graphicsmagick.png");
+ $item2->name = "{$item1_orig_base}.png";
+ $item2->save();
+
+ $item3->name = "{$item1_orig_base}.flv";
+ $item3->save();
+
+ // item2 and item3 have same base name as item1 - conflict resolved by renaming with -01 and -02.
+ $this->assert_same("{$item1_orig_base}-01.png", $item2->name);
+ $this->assert_same("{$item2_orig_slug}-01", $item2->slug);
+ $this->assert_same("{$item1_orig_base}-02.flv", $item3->name);
+ $this->assert_same("{$item3_orig_slug}-02", $item3->slug);
+ }
}