From d66c496fb1007bbd0b1640496808000c573d95fd Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 25 Jun 2010 06:45:09 -0700 Subject: Change the theme option page to display using tabs if the site theme has an admin page. --- modules/gallery/helpers/theme.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index 980ee11a..a390645f 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -70,7 +70,7 @@ class theme_Core { static function get_edit_form_admin() { $form = new Forge("admin/theme_options/save/", "", null, array("id" =>"g-theme-options-form")); - $group = $form->group("edit_theme"); + $group = $form->group("edit_theme")->label(t("Theme Layout")); $group->input("page_size")->label(t("Items per page"))->id("g-page-size") ->rules("required|valid_digit") ->error_messages("required", t("You must enter a number")) @@ -95,7 +95,8 @@ class theme_Core { module::event("theme_edit_form", $form); - $group = $form->group("buttons"); + $group = $form->group("buttons") + ->set_attr("style","border: none"); $group->submit("")->value(t("Save")); return $form; } -- cgit v1.2.3 From e380f19ee29ee1f524aee2d4ebbf4c49f120fb19 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 25 Jun 2010 10:17:06 -0700 Subject: Fix an issue where a preview of the admin view would not work. --- modules/gallery/helpers/theme.php | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index a390645f..4730d296 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -53,6 +53,15 @@ class theme_Core { if (file_exists(THEMEPATH . self::$site_theme_name . "/admin")) { array_unshift($modules, THEMEPATH . self::$site_theme_name . "/admin"); } + // Admins can override the site theme, temporarily. This lets us preview themes. + if (identity::active_user()->admin && $override = $input->get("theme")) { + if (file_exists(THEMEPATH . $override)) { + self::$admin_theme_name = $override; + } else { + Kohana_Log::add("error", "Missing override theme: '$override'"); + } + } + array_unshift($modules, THEMEPATH . self::$admin_theme_name); } else { // Admins can override the site theme, temporarily. This lets us preview themes. if (identity::active_user()->admin && $override = $input->get("theme")) { -- cgit v1.2.3 From 8ecf28d3efa258d790d6cb31947407deb7149797 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Fri, 25 Jun 2010 10:23:11 -0700 Subject: Better fix for the problem that a preview of an admin theme was not showing up. --- modules/gallery/helpers/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index 4730d296..419d986f 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -57,11 +57,11 @@ class theme_Core { if (identity::active_user()->admin && $override = $input->get("theme")) { if (file_exists(THEMEPATH . $override)) { self::$admin_theme_name = $override; + array_unshift($modules, THEMEPATH . self::$admin_theme_name); } else { Kohana_Log::add("error", "Missing override theme: '$override'"); } } - array_unshift($modules, THEMEPATH . self::$admin_theme_name); } else { // Admins can override the site theme, temporarily. This lets us preview themes. if (identity::active_user()->admin && $override = $input->get("theme")) { -- cgit v1.2.3 From 6b619e1098d770670b50553564b96bacec4a3f0c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 26 Jun 2010 12:00:14 -0700 Subject: Differentiate in our logs between missing site and admin theme overrides. --- modules/gallery/helpers/theme.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index 419d986f..c2980149 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -59,7 +59,7 @@ class theme_Core { self::$admin_theme_name = $override; array_unshift($modules, THEMEPATH . self::$admin_theme_name); } else { - Kohana_Log::add("error", "Missing override theme: '$override'"); + Kohana_Log::add("error", "Missing override admin theme: '$override'"); } } } else { @@ -68,7 +68,7 @@ class theme_Core { if (file_exists(THEMEPATH . $override)) { self::$site_theme_name = $override; } else { - Kohana_Log::add("error", "Missing override theme: '$override'"); + Kohana_Log::add("error", "Missing override site theme: '$override'"); } } array_unshift($modules, THEMEPATH . self::$site_theme_name); -- cgit v1.2.3 From 5767971f433ca22f152fb348901d2f4336913038 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 26 Jun 2010 12:00:55 -0700 Subject: Sentence casing. --- modules/gallery/helpers/theme.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index c2980149..3589a5b7 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -79,7 +79,7 @@ class theme_Core { static function get_edit_form_admin() { $form = new Forge("admin/theme_options/save/", "", null, array("id" =>"g-theme-options-form")); - $group = $form->group("edit_theme")->label(t("Theme Layout")); + $group = $form->group("edit_theme")->label(t("Theme layout")); $group->input("page_size")->label(t("Items per page"))->id("g-page-size") ->rules("required|valid_digit") ->error_messages("required", t("You must enter a number")) -- cgit v1.2.3 From 0d424a635d12eee59d2080fa7ffa32a248b0fd5c Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 3 Jul 2010 14:25:33 -0700 Subject: When we delete an item, make sure that we scrub it from any other items that may have it in the album_cover_item_id column. Fixes ticket #1172. --- modules/gallery/helpers/gallery_event.php | 9 +++++++++ modules/gallery/tests/Item_Helper_Test.php | 7 +++++-- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 82f42d98..40ea50fa 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -98,6 +98,15 @@ class gallery_event_Core { static function item_deleted($item) { access::delete_item($item); + // Find any other albums that had the deleted item as the album cover and null it out. + // In some cases this may leave us with a missing album cover up in this item's parent + // hierarchy, but in most cases it'll work out fine. + foreach (ORM::factory("item") + ->where("album_cover_item_id", "=", $item->id) + ->find_all() as $parent) { + item::remove_album_cover($parent); + } + $parent = $item->parent(); if (!$parent->album_cover_item_id) { // Assume we deleted the album cover and pick a new one. Choosing the first photo in the diff --git a/modules/gallery/tests/Item_Helper_Test.php b/modules/gallery/tests/Item_Helper_Test.php index 00229973..eb2458cb 100644 --- a/modules/gallery/tests/Item_Helper_Test.php +++ b/modules/gallery/tests/Item_Helper_Test.php @@ -111,15 +111,18 @@ class Item_Helper_Test extends Gallery_Unit_Test_Case { $this->assert_not_same($rand, $photo2->slug); } - public function delete_cover_photo_picks_new_album_cover() { - $album = test::random_album(); + public function delete_cover_photo_picks_new_album_cover_test() { + $parent = test::random_album(); + $album = test::random_album($parent); $photo1 = test::random_photo($album); // At this point, $photo1 is the album cover. We verify this in // Item_Model_Test::first_photo_becomes_album_cover $photo2 = test::random_photo($album); $photo1->delete(); $album->reload(); + $parent->reload(); $this->assert_same($photo2->id, $album->album_cover_item_id); + $this->assert_same($photo2->id, $parent->album_cover_item_id); } } -- cgit v1.2.3 From 60126adc7e73ec6e70ee5033abf5032ac6b88305 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 4 Jul 2010 20:40:50 -0700 Subject: In the site menu, say "Delete album", "Delete photo" or "Delete movie" as appropriate for the item type. Fixes ticket #1175. --- modules/gallery/helpers/gallery_event.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 40ea50fa..272fd205 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -228,14 +228,17 @@ class gallery_event_Core { case "album": $option_text = t("Album options"); $edit_text = t("Edit album"); + $delete_text = t("Delete album"); break; case "movie": $option_text = t("Movie options"); $edit_text = t("Edit movie"); + $delete_text = t("Delete movie"); break; default: $option_text = t("Photo options"); $edit_text = t("Edit photo"); + $delete_text = t("Delete photo"); } $menu->append($options_menu = Menu::factory("submenu") @@ -309,7 +312,7 @@ class gallery_event_Core { ->append( Menu::factory("dialog") ->id("delete") - ->label(t("Delete this photo")) + ->label($delete_text) ->css_class("ui-icon-trash") ->css_class("g-quick-delete") ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))); -- cgit v1.2.3 From 8493a3d36f597e183490ae880b35a3d98f50a045 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Mon, 5 Jul 2010 08:23:17 -0700 Subject: If the admin request originates as a dialog link, don't display the entire page when reauthenticating the administrator. Just put the form in the dialog. --- lib/gallery.dialog.js | 3 ++- modules/gallery/controllers/admin.php | 11 ++++++-- modules/gallery/controllers/reauthenticate.php | 20 ++------------ modules/gallery/helpers/reauthenticate.php | 36 ++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 21 deletions(-) create mode 100644 modules/gallery/helpers/reauthenticate.php (limited to 'modules/gallery/helpers') diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index 6ec8c634..dd1a5663 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -26,7 +26,8 @@ $("#g-dialog").gallery_show_loading(); - $.get(sHref, function(data) { + var url = sHref + (sHref.indexOf("?") == -1 ? "?" : "&") + "g-in-dialog"; + $.get(url, function(data) { $("#g-dialog").html(data).gallery_show_loading(); if ($("#g-dialog form").length) { diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php index c460f58c..d9bee284 100644 --- a/modules/gallery/controllers/admin.php +++ b/modules/gallery/controllers/admin.php @@ -38,7 +38,8 @@ class Admin_Controller extends Controller { return self::_reauth_check(); } if (auth::must_reauth_for_admin_area()) { - return self::_prompt_for_reauth($controller_name, $args); + print self::_prompt_for_reauth($controller_name, $args); + return; } if (request::method() == "post") { @@ -85,7 +86,13 @@ class Admin_Controller extends Controller { // Avoid anti-phishing protection by passing the url as session variable. Session::instance()->set("continue_url", url::abs_current(true)); } - url::redirect("reauthenticate"); + + // Check that we we not in a dialog. If we are, then use an ajax response. + if (strpos(Router::$query_string, "g-in-dialog") === false) { + url::redirect("reauthenticate"); + } else { + return reauthenticate::get_authenticate_form(); + } } } diff --git a/modules/gallery/controllers/reauthenticate.php b/modules/gallery/controllers/reauthenticate.php index acb27f6a..9ddaff2e 100644 --- a/modules/gallery/controllers/reauthenticate.php +++ b/modules/gallery/controllers/reauthenticate.php @@ -22,7 +22,7 @@ class Reauthenticate_Controller extends Controller { if (!identity::active_user()->admin) { access::forbidden(); } - return self::_show_form(self::_form()); + return self::_show_form(reauthenticate::get_authenticate_form()); } public function auth() { @@ -31,7 +31,7 @@ class Reauthenticate_Controller extends Controller { } access::verify_csrf(); - $form = self::_form(); + $form = reauthenticate::get_authenticate_form(); $valid = $form->validate(); $user = identity::active_user(); if ($valid) { @@ -54,20 +54,4 @@ class Reauthenticate_Controller extends Controller { $view->content->user_name = identity::active_user()->name; print $view; } - - private static function _form() { - $form = new Forge("reauthenticate/auth", "", "post", array("id" => "g-reauthenticate-form")); - $form->set_attr('class', "g-narrow"); - $form->hidden("continue_url")->value(Session::instance()->get("continue_url", "admin")); - $group = $form->group("reauthenticate")->label(t("Re-authenticate")); - $group->password("password")->label(t("Password"))->id("g-password")->class(null) - ->callback("auth::validate_too_many_failed_auth_attempts") - ->callback("user::valid_password") - ->error_messages("invalid_password", t("Incorrect password")) - ->error_messages( - "too_many_failed_auth_attempts", - t("Too many incorrect passwords. Try again later")); - $group->submit("")->value(t("Submit")); - return $form; - } } diff --git a/modules/gallery/helpers/reauthenticate.php b/modules/gallery/helpers/reauthenticate.php new file mode 100644 index 00000000..1ad90e15 --- /dev/null +++ b/modules/gallery/helpers/reauthenticate.php @@ -0,0 +1,36 @@ + "g-reauthenticate-form")); + $form->set_attr('class', "g-narrow"); + $form->hidden("continue_url")->value(Session::instance()->get("continue_url", "admin")); + $group = $form->group("reauthenticate")->label(t("Re-authenticate")); + $group->password("password")->label(t("Password"))->id("g-password")->class(null) + ->callback("auth::validate_too_many_failed_auth_attempts") + ->callback("user::valid_password") + ->error_messages("invalid_password", t("Incorrect password")) + ->error_messages( + "too_many_failed_auth_attempts", + t("Too many incorrect passwords. Try again later")); + $group->submit("")->value(t("Submit")); + return $form; + } +} -- cgit v1.2.3 From 226d1f714635995722fe7927f8ec049fe3890011 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Mon, 5 Jul 2010 08:58:36 -0700 Subject: Revert "If the admin request originates as a dialog link, don't display the entire page when reauthenticating the administrator. Just put the form in the dialog." This reverts commit 8493a3d36f597e183490ae880b35a3d98f50a045. --- lib/gallery.dialog.js | 3 +-- modules/gallery/controllers/admin.php | 11 ++------ modules/gallery/controllers/reauthenticate.php | 20 ++++++++++++-- modules/gallery/helpers/reauthenticate.php | 36 -------------------------- 4 files changed, 21 insertions(+), 49 deletions(-) delete mode 100644 modules/gallery/helpers/reauthenticate.php (limited to 'modules/gallery/helpers') diff --git a/lib/gallery.dialog.js b/lib/gallery.dialog.js index dd1a5663..6ec8c634 100644 --- a/lib/gallery.dialog.js +++ b/lib/gallery.dialog.js @@ -26,8 +26,7 @@ $("#g-dialog").gallery_show_loading(); - var url = sHref + (sHref.indexOf("?") == -1 ? "?" : "&") + "g-in-dialog"; - $.get(url, function(data) { + $.get(sHref, function(data) { $("#g-dialog").html(data).gallery_show_loading(); if ($("#g-dialog form").length) { diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php index d9bee284..c460f58c 100644 --- a/modules/gallery/controllers/admin.php +++ b/modules/gallery/controllers/admin.php @@ -38,8 +38,7 @@ class Admin_Controller extends Controller { return self::_reauth_check(); } if (auth::must_reauth_for_admin_area()) { - print self::_prompt_for_reauth($controller_name, $args); - return; + return self::_prompt_for_reauth($controller_name, $args); } if (request::method() == "post") { @@ -86,13 +85,7 @@ class Admin_Controller extends Controller { // Avoid anti-phishing protection by passing the url as session variable. Session::instance()->set("continue_url", url::abs_current(true)); } - - // Check that we we not in a dialog. If we are, then use an ajax response. - if (strpos(Router::$query_string, "g-in-dialog") === false) { - url::redirect("reauthenticate"); - } else { - return reauthenticate::get_authenticate_form(); - } + url::redirect("reauthenticate"); } } diff --git a/modules/gallery/controllers/reauthenticate.php b/modules/gallery/controllers/reauthenticate.php index 9ddaff2e..acb27f6a 100644 --- a/modules/gallery/controllers/reauthenticate.php +++ b/modules/gallery/controllers/reauthenticate.php @@ -22,7 +22,7 @@ class Reauthenticate_Controller extends Controller { if (!identity::active_user()->admin) { access::forbidden(); } - return self::_show_form(reauthenticate::get_authenticate_form()); + return self::_show_form(self::_form()); } public function auth() { @@ -31,7 +31,7 @@ class Reauthenticate_Controller extends Controller { } access::verify_csrf(); - $form = reauthenticate::get_authenticate_form(); + $form = self::_form(); $valid = $form->validate(); $user = identity::active_user(); if ($valid) { @@ -54,4 +54,20 @@ class Reauthenticate_Controller extends Controller { $view->content->user_name = identity::active_user()->name; print $view; } + + private static function _form() { + $form = new Forge("reauthenticate/auth", "", "post", array("id" => "g-reauthenticate-form")); + $form->set_attr('class', "g-narrow"); + $form->hidden("continue_url")->value(Session::instance()->get("continue_url", "admin")); + $group = $form->group("reauthenticate")->label(t("Re-authenticate")); + $group->password("password")->label(t("Password"))->id("g-password")->class(null) + ->callback("auth::validate_too_many_failed_auth_attempts") + ->callback("user::valid_password") + ->error_messages("invalid_password", t("Incorrect password")) + ->error_messages( + "too_many_failed_auth_attempts", + t("Too many incorrect passwords. Try again later")); + $group->submit("")->value(t("Submit")); + return $form; + } } diff --git a/modules/gallery/helpers/reauthenticate.php b/modules/gallery/helpers/reauthenticate.php deleted file mode 100644 index 1ad90e15..00000000 --- a/modules/gallery/helpers/reauthenticate.php +++ /dev/null @@ -1,36 +0,0 @@ - "g-reauthenticate-form")); - $form->set_attr('class', "g-narrow"); - $form->hidden("continue_url")->value(Session::instance()->get("continue_url", "admin")); - $group = $form->group("reauthenticate")->label(t("Re-authenticate")); - $group->password("password")->label(t("Password"))->id("g-password")->class(null) - ->callback("auth::validate_too_many_failed_auth_attempts") - ->callback("user::valid_password") - ->error_messages("invalid_password", t("Incorrect password")) - ->error_messages( - "too_many_failed_auth_attempts", - t("Too many incorrect passwords. Try again later")); - $group->submit("")->value(t("Submit")); - return $form; - } -} -- cgit v1.2.3 From 1d40c62f53b37445b5f62a65ce76f4b3ecfb2d4f Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 5 Jul 2010 19:46:19 -0700 Subject: Updated version for RC2 --- README | 9 +++++---- modules/gallery/helpers/gallery.php | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/README b/README index a00d18cb..67efff4b 100644 --- a/README +++ b/README @@ -9,10 +9,11 @@ interface. SECURITY (& INTENDED AUDIENCE): -This is the second release candidate of Gallery 3.0. We're putting it -out there so that we can find out if we overlooked any small things. -We expect the final version to be virtually identical. You can -install it on public websites and use it freely -- we recommend it! +This is the second (and hopefully final) release candidate of Gallery +3.0. We're putting it out there so that we can find out if we +overlooked any small things. We expect the final version to be +virtually identical. You can install it on public websites and use it +freely -- we recommend it! Note: - We've contracted a professional security audit, received their results diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 7f7db10b..d4078209 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class gallery_Core { - const VERSION = "3.0 RC1 (Santa Fe)"; + const VERSION = "3.0 RC2 (Santa Fe)"; /** * If Gallery is in maintenance mode, then force all non-admins to get routed to a "This site is -- cgit v1.2.3 From 307e47c3d01c1bbbe294b8339a2f531a5156eb90 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 10 Jul 2010 11:45:45 -0700 Subject: Pass along the from_id when editing albums in the context menu, and also pass it along in the form creation code. This fixes ticket #1183. --- modules/gallery/helpers/album.php | 2 +- modules/gallery/helpers/gallery_event.php | 17 ++++++++--------- modules/gallery/helpers/movie.php | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 0baae631..0ac5e8b0 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -58,7 +58,7 @@ class album_Core { static function get_edit_form($parent) { $form = new Forge( "albums/update/{$parent->id}", "", "post", array("id" => "g-edit-album-form")); - $form->hidden("from_id"); + $form->hidden("from_id")->value($parent->id); $group = $form->group("edit_item")->label(t("Edit Album")); $group->input("title")->label(t("Title"))->value($parent->title) diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 272fd205..ba6dd99d 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -249,7 +249,7 @@ class gallery_event_Core { $options_menu->append(Menu::factory("dialog") ->id("edit_item") ->label($edit_text) - ->url(url::site("form/edit/{$item->type}s/$item->id"))); + ->url(url::site("form/edit/{$item->type}s/$item->id?from_id={$item->id}"))); } if ($item->is_album()) { @@ -263,7 +263,6 @@ class gallery_event_Core { } $csrf = access::csrf_token(); - $theme_item = $theme->item(); $page_type = $theme->page_type(); if ($can_edit && $item->is_photo() && graphics::can("rotate")) { $options_menu @@ -274,7 +273,7 @@ class gallery_event_Core { ->css_class("ui-icon-rotate-ccw") ->ajax_handler("function(data) { " . "\$.gallery_replace_image(data, \$('$item_css_selector')) }") - ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))) + ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&from_id={$item->id}&page_type=$page_type"))) ->append( Menu::factory("ajax_link") ->id("rotate_cw") @@ -282,7 +281,7 @@ class gallery_event_Core { ->css_class("ui-icon-rotate-cw") ->ajax_handler("function(data) { " . "\$.gallery_replace_image(data, \$('$item_css_selector')) }") - ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))); + ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&from_id={$item->id}&page_type=$page_type"))); } if ($item->id != item::root()->id) { @@ -315,7 +314,7 @@ class gallery_event_Core { ->label($delete_text) ->css_class("ui-icon-trash") ->css_class("g-quick-delete") - ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))); + ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&from_id={$item->id}&page_type=$page_type"))); } } } @@ -416,7 +415,7 @@ class gallery_event_Core { ->id("edit") ->label($edit_title) ->css_class("ui-icon-pencil") - ->url(url::site("quick/form_edit/$item->id?from_id=$theme_item->id"))); + ->url(url::site("quick/form_edit/$item->id?from_id={$theme_item->id}"))); if ($item->is_photo() && graphics::can("rotate")) { $options_menu @@ -427,7 +426,7 @@ class gallery_event_Core { ->css_class("ui-icon-rotate-ccw") ->ajax_handler("function(data) { " . "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }") - ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))) + ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&from_id={$theme_item->id}&page_type=$page_type"))) ->append( Menu::factory("ajax_link") ->id("rotate_cw") @@ -435,7 +434,7 @@ class gallery_event_Core { ->css_class("ui-icon-rotate-cw") ->ajax_handler("function(data) { " . "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }") - ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))); + ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&from_id={$theme_item->id}&page_type=$page_type"))); } // @todo Don't move photos from the photo page; we don't yet have a good way of redirecting @@ -474,7 +473,7 @@ class gallery_event_Core { ->id("delete") ->label($delete_title) ->css_class("ui-icon-trash") - ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&from_id=$theme_item->id&page_type=$page_type"))); + ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&from_id={$theme_item->id}&page_type=$page_type"))); } if ($item->is_album()) { diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index 6333eaf2..bbb5b66c 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -26,7 +26,7 @@ class movie_Core { static function get_edit_form($movie) { $form = new Forge("movies/update/$movie->id", "", "post", array("id" => "g-edit-movie-form")); - $form->hidden("from_id"); + $form->hidden("from_id")->value($movie->id); $group = $form->group("edit_item")->label(t("Edit Movie")); $group->input("title")->label(t("Title"))->value($movie->title) ->error_messages("required", t("You must provide a title")) -- cgit v1.2.3 From 7ca201b11819ca5bfbcbe76f43bfe7d706c0f27f Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 10 Jul 2010 11:59:29 -0700 Subject: Pass along the from_id in item::get_delete_form() and then check to see if we're deleting the album we're inside in quick::delete. If we delete the album we're currently viewing, redirect to the parent. This fixes ticket #1185. --- modules/gallery/controllers/quick.php | 4 +++- modules/gallery/helpers/item.php | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 6cfbbc62..52f15e7d 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -119,7 +119,9 @@ class Quick_Controller extends Controller { $item->delete(); message::success($msg); - if (Input::instance()->get("page_type") == "collection") { + $from_id = Input::instance()->get("from_id"); + if (Input::instance()->get("page_type") == "collection" && + $from_id != $id /* deleted the item we were viewing */) { print json_encode(array("result" => "success", "reload" => 1)); } else { print json_encode(array("result" => "success", diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index aef68c6e..8fea49cc 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -158,8 +158,10 @@ class item_Core { */ static function get_delete_form($item) { $page_type = Input::instance()->get("page_type"); + $from_id = Input::instance()->get("from_id"); $form = new Forge( - "quick/delete/$item->id?page_type=$page_type", "", "post", array("id" => "g-confirm-delete")); + "quick/delete/$item->id?page_type=$page_type&from_id=$from_id", "", + "post", array("id" => "g-confirm-delete")); $group = $form->group("confirm_delete")->label(t("Confirm Deletion")); $group->submit("")->value(t("Delete")); $form->script("") -- cgit v1.2.3 From b20f9123dc0cc4bc70597910e12eb18ec0eef2c2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 10 Jul 2010 18:25:23 -0700 Subject: Wrap album deletes in a batch so that we can handle lots of cascading deletes in bulk. This lets us avoid the problem where we continually choose and delete album covers which makes deletes really slow. It probably also avoids huge amounts of notification emails (untested). Fixes ticket #1190. --- modules/gallery/controllers/quick.php | 11 ++++++++++- modules/gallery/helpers/gallery_event.php | 33 +++++++++++++++++++++++++------ 2 files changed, 37 insertions(+), 7 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index 52f15e7d..08a33138 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -116,7 +116,16 @@ class Quick_Controller extends Controller { } $parent = $item->parent(); - $item->delete(); + + if ($item->is_album()) { + // Album delete will trigger deletes for all children. Do this in a batch so that we can be + // smart about notifications, album cover updates, etc. + batch::start(); + $item->delete(); + batch::stop(); + } else { + $item->delete(); + } message::success($msg); $from_id = Input::instance()->get("from_id"); diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index ba6dd99d..60520690 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -109,14 +109,35 @@ class gallery_event_Core { $parent = $item->parent(); if (!$parent->album_cover_item_id) { - // Assume we deleted the album cover and pick a new one. Choosing the first photo in the - // album is logical, but it's not the most efficient in the case where we're deleting all - // the photos in the album one at a time since we'll probably delete them in order which - // means that we'll be resetting the album cover each time. - if ($child = $parent->children(1)->current()) { - item::make_album_cover($child); + // Assume that we deleted the album cover + if (batch::in_progress()) { + // Remember that this parent is missing an album cover, for later. + $batch_missing_album_cover = Session::instance()->get("batch_missing_album_cover", array()); + $batch_missing_album_cover[$parent->id] = 1; + Session::instance()->set("batch_missing_album_cover", $batch_missing_album_cover); + } else { + // Choose the first child as the new cover. + if ($child = $parent->children(1)->current()) { + item::make_album_cover($child); + } + } + } + } + + static function batch_complete() { + // Set the album covers for any items that where we probably deleted the album cover during + // this batch. The item may have been deleted, so don't count on it being around. Choose the + // first child as the new album cover. + // NOTE: if the first child doesn't have an album cover, then this won't work. + foreach (array_keys(Session::instance()->get("batch_missing_album_cover", array())) as $id) { + $item = ORM::factory("item", $id); + if ($item->loaded() && !$item->album_cover_item_id) { + if ($child = $item->children(1)->current()) { + item::make_album_cover($child); + } } } + Session::instance()->delete("batch_missing_album_cover"); } static function item_moved($item, $old_parent) { -- cgit v1.2.3 From eb19192c4e7b9433c16b1acc14fa5c1242e27bc1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sat, 10 Jul 2010 18:51:57 -0700 Subject: If the target of an item move has no album cover, make the newly moved item the album cover. Fixes ticket #1196. --- modules/gallery/helpers/gallery_event.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 60520690..76bd9ee7 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -142,6 +142,11 @@ class gallery_event_Core { static function item_moved($item, $old_parent) { access::recalculate_permissions($item->parent()); + + // If the new parent doesn't have an album cover, make this it. + if (!$item->parent()->album_cover_item_id) { + item::make_album_cover($item); + } } static function user_login($user) { -- cgit v1.2.3 From fe2881a22aabd0ab5cb971809db6f325c3ce22d3 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 15 Jul 2010 12:37:44 -0700 Subject: Rename Flash_Uploader to just Uploader. Modules that want to replace this will just replace the controller. This makes overriding that much easier in the future. --- modules/gallery/controllers/flash_uploader.php | 125 ------------------------- modules/gallery/controllers/uploader.php | 125 +++++++++++++++++++++++++ modules/gallery/helpers/gallery_event.php | 4 +- modules/gallery/views/form_uploadify.html.php | 2 +- themes/wind/views/album.html.php | 2 +- 5 files changed, 129 insertions(+), 129 deletions(-) delete mode 100644 modules/gallery/controllers/flash_uploader.php create mode 100644 modules/gallery/controllers/uploader.php (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/controllers/flash_uploader.php b/modules/gallery/controllers/flash_uploader.php deleted file mode 100644 index 6bfdd851..00000000 --- a/modules/gallery/controllers/flash_uploader.php +++ /dev/null @@ -1,125 +0,0 @@ -is_album()) { - $item = $item->parent(); - } - - print json_encode(array("form" => (string)$this->_get_add_form($item))); - //print $this->_get_add_form($item); - } - - public function start() { - access::verify_csrf(); - batch::start(); - } - - public function add_photo($id) { - $album = ORM::factory("item", $id); - access::required("view", $album); - 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,m4v]"); - - if ($form->validate() && $file_validation->validate()) { - $temp_filename = upload::save("Filedata"); - try { - $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", "m4v"))) { - $item->type = "movie"; - $item->save(); - log::success("content", t("Added a movie"), - html::anchor("movies/$item->id", t("view movie"))); - } else { - $item->type = "photo"; - $item->save(); - log::success("content", t("Added a photo"), - html::anchor("photos/$item->id", t("view photo"))); - } - - module::event("add_photos_form_completed", $item, $form); - } catch (Exception $e) { - // 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()); - - // Ugh. I hate to use instanceof, But this beats catching the exception separately since - // we mostly want to treat it the same way as all other exceptions - if ($e instanceof ORM_Validation_Exception) { - Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1)); - } - - if (file_exists($temp_filename)) { - unlink($temp_filename); - } - header("HTTP/1.1 500 Internal Server Error"); - print "ERROR: " . $e->getMessage(); - return; - } - unlink($temp_filename); - print "FILEID: $item->id"; - } else { - header("HTTP/1.1 400 Bad Request"); - print "ERROR: " . t("Invalid upload"); - } - } - - public function finish() { - access::verify_csrf(); - - batch::stop(); - print json_encode(array("result" => "success")); - } - - private function _get_add_form($album) { - $form = new Forge("flash_uploader/finish", "", "post", array("id" => "g-add-photos-form")); - $group = $form->group("add_photos") - ->label(t("Add photos to %album_title", array("album_title" => html::purify($album->title)))); - $group->uploadify("uploadify")->album($album); - - $group = $form->group("actions"); - $group->uploadify_buttons(""); - - module::event("add_photos_form", $album, $form); - - return $form; - } -} diff --git a/modules/gallery/controllers/uploader.php b/modules/gallery/controllers/uploader.php new file mode 100644 index 00000000..38e22cee --- /dev/null +++ b/modules/gallery/controllers/uploader.php @@ -0,0 +1,125 @@ +is_album()) { + $item = $item->parent(); + } + + print json_encode(array("form" => (string)$this->_get_add_form($item))); + //print $this->_get_add_form($item); + } + + public function start() { + access::verify_csrf(); + batch::start(); + } + + public function add_photo($id) { + $album = ORM::factory("item", $id); + access::required("view", $album); + 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,m4v]"); + + if ($form->validate() && $file_validation->validate()) { + $temp_filename = upload::save("Filedata"); + try { + $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", "m4v"))) { + $item->type = "movie"; + $item->save(); + log::success("content", t("Added a movie"), + html::anchor("movies/$item->id", t("view movie"))); + } else { + $item->type = "photo"; + $item->save(); + log::success("content", t("Added a photo"), + html::anchor("photos/$item->id", t("view photo"))); + } + + module::event("add_photos_form_completed", $item, $form); + } catch (Exception $e) { + // 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()); + + // Ugh. I hate to use instanceof, But this beats catching the exception separately since + // we mostly want to treat it the same way as all other exceptions + if ($e instanceof ORM_Validation_Exception) { + Kohana_Log::add("error", "Validation errors: " . print_r($e->validation->errors(), 1)); + } + + if (file_exists($temp_filename)) { + unlink($temp_filename); + } + header("HTTP/1.1 500 Internal Server Error"); + print "ERROR: " . $e->getMessage(); + return; + } + unlink($temp_filename); + print "FILEID: $item->id"; + } else { + header("HTTP/1.1 400 Bad Request"); + print "ERROR: " . t("Invalid upload"); + } + } + + public function finish() { + access::verify_csrf(); + + batch::stop(); + print json_encode(array("result" => "success")); + } + + private function _get_add_form($album) { + $form = new Forge("uploader/finish", "", "post", array("id" => "g-add-photos-form")); + $group = $form->group("add_photos") + ->label(t("Add photos to %album_title", array("album_title" => html::purify($album->title)))); + $group->uploadify("uploadify")->album($album); + + $group = $form->group("actions"); + $group->uploadify_buttons(""); + + module::event("add_photos_form", $album, $form); + + return $form; + } +} diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 76bd9ee7..f90f8843 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -237,7 +237,7 @@ class gallery_event_Core { $add_menu->append(Menu::factory("dialog") ->id("add_photos_item") ->label(t("Add photos")) - ->url(url::site("flash_uploader/app/$item->id"))); + ->url(url::site("uploader/index/$item->id"))); if ($item->is_album()) { $add_menu->append(Menu::factory("dialog") ->id("add_album_item") @@ -508,7 +508,7 @@ class gallery_event_Core { ->id("add_item") ->label(t("Add a photo")) ->css_class("ui-icon-plus") - ->url(url::site("flash_uploader/app/$item->id"))) + ->url(url::site("uploader/index/$item->id"))) ->append(Menu::factory("dialog") ->id("add_album") ->label(t("Add an album")) diff --git a/modules/gallery/views/form_uploadify.html.php b/modules/gallery/views/form_uploadify.html.php index 937a37b6..6e18a85c 100644 --- a/modules/gallery/views/form_uploadify.html.php +++ b/modules/gallery/views/form_uploadify.html.php @@ -7,7 +7,7 @@ width: 150, height: 33, uploader: "", - script: "id}") ?>", + script: "id}") ?>", scriptData: , fileExt: "*.gif;*.jpg;*.jpeg;*.png;*.flv;*.mp4;*.m4v;*.GIF;*.JPG;*.JPEG;*.PNG;*.FLV;*.MP4;*.M4V", fileDesc: for_js() ?>, diff --git a/themes/wind/views/album.html.php b/themes/wind/views/album.html.php index b9072e2b..de196be0 100644 --- a/themes/wind/views/album.html.php +++ b/themes/wind/views/album.html.php @@ -29,7 +29,7 @@ admin || access::can("add", $item)): ?> - id") ?> + id") ?>
  • Add some.", array("attrs" => html::mark_clean("href=\"$addurl\" class=\"g-dialog-link\""))) ?>
  • -- cgit v1.2.3 From 86a91c11cf8e2af8d100ee8a982a299d341ef032 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 15 Jul 2010 12:51:35 -0700 Subject: Redirect users away from admin to the main site if you click logout on the admin dashboard. Fixes ticket #1201 --- modules/gallery/helpers/gallery_event.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index f90f8843..bdcfc67a 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -206,8 +206,10 @@ class gallery_event_Core { $menu->append(Menu::factory("link") ->id("user_menu_logout") ->css_id("g-logout-link") - ->url(url::site("logout?csrf=$csrf&continue_url=" . - urlencode($continue_url))) + ->url( + Router::$controller == "admin" ? + url::site("") : + url::site("logout?csrf=$csrf&continue_url=" . urlencode($continue_url))) ->label(t("Logout"))); } } -- cgit v1.2.3 From 9e9eed11872f995f899f7d00205377c3407af308 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 20 Jul 2010 06:42:20 -0700 Subject: Oops! Proper fix for #1201. My last fix just redirected back to the main site, and didn't actually log you out. --- modules/gallery/helpers/gallery_event.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index bdcfc67a..e3fa5e08 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -193,7 +193,9 @@ class gallery_event_Core { ->url(user_profile::url($user->id)) ->label($user->display_name())); - if (isset($theme->item)) { + if (Router::$controller == "admin") { + $continue_url = url::site(""); + } else if (isset($theme->item)) { if (access::user_can(identity::guest(), "view", $theme->item)) { $continue_url = $theme->item->abs_url(); } else { @@ -206,10 +208,7 @@ class gallery_event_Core { $menu->append(Menu::factory("link") ->id("user_menu_logout") ->css_id("g-logout-link") - ->url( - Router::$controller == "admin" ? - url::site("") : - url::site("logout?csrf=$csrf&continue_url=" . urlencode($continue_url))) + ->url(url::site("logout?csrf=$csrf&continue_url=" . urlencode($continue_url))) ->label(t("Logout"))); } } -- cgit v1.2.3 From 9db310186a276f4cd2d07534a7184a801ae4f167 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 20 Jul 2010 12:22:52 -0700 Subject: Use Session::get_once() instead of Session::get() followed by Session::delete(); --- modules/gallery/helpers/gallery_theme.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index 62deb831..0d7cc44a 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -79,8 +79,7 @@ class gallery_theme_Core { return L10n_Client_Controller::l10n_form(); } - if ($session->get("after_install")) { - $session->delete("after_install"); + if ($session->get_once("after_install")) { return new View("welcome_message_loader.html"); } } -- cgit v1.2.3 From 6899af367b7766a6c7afa0f3e551b8d82230fd3f Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 20 Jul 2010 12:45:04 -0700 Subject: Cleanup on the Admin > Languages page. Hide the fieldset and legend in the theme, since they don't add any value. Change l10n_client::_server_url() to use the short style GMC urls and make the API a little tighter. --- modules/gallery/controllers/admin_languages.php | 2 +- modules/gallery/helpers/l10n_client.php | 13 ++++++------- modules/gallery/views/admin_languages.html.php | 3 +++ themes/admin_wind/css/screen.css | 11 +++++++++++ 4 files changed, 21 insertions(+), 8 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php index 0f134fcd..2e993816 100644 --- a/modules/gallery/controllers/admin_languages.php +++ b/modules/gallery/controllers/admin_languages.php @@ -109,7 +109,7 @@ class Admin_Languages_Controller extends Admin_Controller { private function _share_translations_form() { $form = new Forge("admin/languages/share", "", "post", array("id" => "g-share-translations-form")); $group = $form->group("sharing") - ->label(t("Sharing your own translations with the Gallery community is easy. Please do!")); + ->label("Translations API Key"); $api_key = l10n_client::api_key(); $server_link = l10n_client::server_api_key_url(); $group->input("api_key") diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php index f45f502d..52c13c78 100644 --- a/modules/gallery/helpers/l10n_client.php +++ b/modules/gallery/helpers/l10n_client.php @@ -20,13 +20,12 @@ class l10n_client_Core { - private static function _server_url() { - return "http://gallery.menalto.com/index.php"; + private static function _server_url($path) { + return "http://gallery.menalto.com/translations/$path"; } static function server_api_key_url() { - return self::_server_url() . "?q=translations/userkey/" . - self::client_token(); + return self::_server_url("userkey/" . self::client_token()); } static function client_token() { @@ -53,7 +52,7 @@ class l10n_client_Core { static function validate_api_key($api_key) { $version = "1.0"; - $url = self::_server_url() . "?q=translations/status"; + $url = self::_server_url("status"); $signature = self::_sign($version, $api_key); list ($response_data, $response_status) = remote::post( @@ -123,7 +122,7 @@ class l10n_client_Core { } $request_data = json_encode($request); - $url = self::_server_url() . "?q=translations/fetch"; + $url = self::_server_url("fetch"); list ($response_data, $response_status) = remote::post($url, array("data" => $request_data)); if (!remote::success($response_status)) { throw new Exception("@todo TRANSLATIONS_FETCH_REQUEST_FAILED " . $response_status); @@ -208,7 +207,7 @@ class l10n_client_Core { // @todo reduce memory consumption, e.g. free $request $request_data = json_encode($request); - $url = self::_server_url() . "?q=translations/submit"; + $url = self::_server_url("submit"); $signature = self::_sign($request_data); list ($response_data, $response_status) = remote::post( diff --git a/modules/gallery/views/admin_languages.html.php b/modules/gallery/views/admin_languages.html.php index d4b7b0c1..01d1ce3f 100644 --- a/modules/gallery/views/admin_languages.html.php +++ b/modules/gallery/views/admin_languages.html.php @@ -107,6 +107,9 @@

    +

    + +

    diff --git a/themes/admin_wind/css/screen.css b/themes/admin_wind/css/screen.css index 937c4d15..2ea60402 100644 --- a/themes/admin_wind/css/screen.css +++ b/themes/admin_wind/css/screen.css @@ -419,6 +419,17 @@ th { color: #FF0000 !important; } +/* Language options ~~~~~~~~~~~~~~~~~~~~~~~~ */ +#g-share-translations-form fieldset { + border: 0px; + margin: 0px; + padding: 0px; +} + +#g-share-translations-form fieldset legend { + display: none; +} + /** ******************************************************************* * 5) Navigation and menus *********************************************************************/ -- cgit v1.2.3 From 2cf51983535ffa498c38b02328e30fe307ec6827 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 21 Jul 2010 11:34:19 -0700 Subject: Null out relative_path_cache and relative_url_cache after we update the pointers in case the hierarchy was adversely affected by actions when the MPTT pointers were desynced. Fixes ticket #1235. --- modules/gallery/helpers/gallery_task.php | 2 ++ 1 file changed, 2 insertions(+) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index bc128b3e..96ea7c0d 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -381,6 +381,8 @@ class gallery_task_Core { db::build() ->update("items") ->set("right_ptr", $value) + ->set("relative_path_cache", null) + ->set("relative_url_cache", null) ->where("id", "=", $id) ->execute(); } -- cgit v1.2.3 From 663f079e8565d8bd565b1f8cdf85cb8f0269c87b Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 22 Jul 2010 14:08:08 -0700 Subject: Properly handle the case where the album_cover_item_id points to an invalid (probably deleted) item. Fixes ticket #1238. --- modules/gallery/helpers/graphics.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index 7ff09d13..cc4d2e76 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -117,7 +117,18 @@ class graphics_Core { static function generate($item) { if ($item->is_album()) { if (!$cover = $item->album_cover()) { - // This album has no cover; there's nothing to generate. + // This album has no cover; there's nothing to generate. Because of an old bug, it's + // possible that there's an album cover item id that points to an invalid item. In that + // case, just null out the album cover item id. It's not optimal to do that at this low + // level, but it's not trivial to find these cases quickly in an upgrade script and if we + // don't do this, the album may be permanently marked as "needs rebuilding" + // + // ref: http://sourceforge.net/apps/trac/gallery/ticket/1172 + // http://gallery.menalto.com/node/96926 + if ($item->album_cover_item_id) { + $item->album_cover_item_id = null; + $item->save(); + } return; } $input_file = $cover->file_path(); -- cgit v1.2.3 From 108fff735cd0882f4b1ced4c2352fcd44247467e Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 22 Jul 2010 15:53:00 -0700 Subject: Initialize $request in submit_translations(). Fixes ticket #1239. --- modules/gallery/helpers/l10n_client.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php index 52c13c78..43cc2036 100644 --- a/modules/gallery/helpers/l10n_client.php +++ b/modules/gallery/helpers/l10n_client.php @@ -194,12 +194,15 @@ class l10n_client_Core { // @todo Batch requests (max request size) // @todo include base_revision in submission / how to handle resubmissions / edit fights? + $request = new stdClass(); foreach (db::build() ->select("key", "message", "locale", "base_revision", "translation") ->from("outgoing_translations") ->execute() as $row) { $key = $row->key; if (!isset($request->{$key})) { + $request->{$key} = new stdClass(); + $request->{$key}->translations = new stdClass(); $request->{$key}->message = json_encode(unserialize($row->message)); } $request->{$key}->translations->{$row->locale} = json_encode(unserialize($row->translation)); -- cgit v1.2.3 From a331611049f6541cf37f993fa3c29535d387f972 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Wed, 21 Jul 2010 08:15:21 -0700 Subject: Partial fix for #1225. Create a json reply helper that sets the content type to application/json and then json encodes the reply. --- modules/gallery/helpers/json.php | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 modules/gallery/helpers/json.php (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/json.php b/modules/gallery/helpers/json.php new file mode 100644 index 00000000..5fcdc268 --- /dev/null +++ b/modules/gallery/helpers/json.php @@ -0,0 +1,34 @@ + Date: Sun, 25 Jul 2010 10:05:09 -0700 Subject: Don't use hardcoded id 1 as the everybody group; it won't work with alternative auth schemes. --- modules/gallery/helpers/access.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 87b6b313..d3f680d2 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -627,7 +627,8 @@ class access_Core { * apply the view and view_full permissions to guest users. */ private static function _update_htaccess_files($album, $group, $perm_name, $value) { - if ($group->id != 1 || !($perm_name == "view" || $perm_name == "view_full")) { + if ($group->id != identity::everybody()->id || + !($perm_name == "view" || $perm_name == "view_full")) { return; } -- cgit v1.2.3 From 5be9ae3250fab24631c0fc6b900ffccd9b1755f2 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 25 Jul 2010 11:10:42 -0700 Subject: Add a new maintenance task that resyncs album .htaccess files with database access intents. Use this to fix up .htaccess files after you relocate your Gallery. Fixes ticket #1252. --- modules/gallery/helpers/access.php | 14 +++++--- modules/gallery/helpers/gallery_task.php | 59 +++++++++++++++++++++++++++++++- 2 files changed, 68 insertions(+), 5 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index d3f680d2..b1384c19 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -222,7 +222,7 @@ class access_Core { self::_update_access_non_view_cache($group, $perm_name, $album); } - self::_update_htaccess_files($album, $group, $perm_name, $value); + self::update_htaccess_files($album, $group, $perm_name, $value); model_cache::clear(); } @@ -623,10 +623,16 @@ class access_Core { } /** - * Maintain .htacccess files to prevent direct access to albums, resizes and thumbnails when we - * apply the view and view_full permissions to guest users. + * Rebuild the .htaccess files that prevent direct access to albums, resizes and thumbnails. We + * call this internally any time we change the view or view_full permissions for guest users. + * This function is only public because we use it in maintenance tasks. + * + * @param Item_Model the album + * @param Group_Model the group whose permission is changing + * @param string the permission name + * @param string the new permission value (eg access::DENY) */ - private static function _update_htaccess_files($album, $group, $perm_name, $value) { + public static function update_htaccess_files($album, $group, $perm_name, $value) { if ($group->id != identity::everybody()->id || !($perm_name == "view" || $perm_name == "view_full")) { return; diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 96ea7c0d..4b5e9e93 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -50,7 +50,14 @@ class gallery_task_Core { ->callback("gallery_task::fix_mptt") ->name(t("Fix Album/Photo hierarchy")) ->description(t("Fix problems where your album/photo breadcrumbs are out of " . - "sync with your actual hierarchy.")) + "sync with your actual hierarchy")) + ->severity(log::SUCCESS); + + $tasks[] = Task_Definition::factory() + ->callback("gallery_task::fix_permissions") + ->name(t("Fix permissions")) + ->description(t("Resynchronize database permissions with the .htaccess " . + "files in your gallery3/var directory")) ->severity(log::SUCCESS); return $tasks; @@ -386,4 +393,54 @@ class gallery_task_Core { ->where("id", "=", $id) ->execute(); } + + static function fix_permissions($task) { + $start = microtime(true); + + $total = $task->get("total"); + if (empty($total)) { + $everybody_id = identity::everybody()->id; + $stack = array(); + foreach (db::build() + ->select("id") + ->from("access_intents") + ->where("view_{$everybody_id}", "=", 0) + ->or_where("view_full_{$everybody_id}", "=", 0) + ->execute() as $row) { + $stack[] = $row->id; + } + + $task->set("total", $total = count($stack)); + $task->set("stack", implode(" ", $stack)); + $task->set("completed", 0); + } + + $stack = explode(" ", $task->get("stack")); + $completed = $task->get("completed"); + + while ($stack && microtime(true) - $start < 1.5) { + $album = ORM::factory("item", array_pop($stack)); + $everybody = identity::everybody(); + if (!access::group_can($everybody, "view", $album)) { + access::update_htaccess_files($album, identity::everybody(), "view", access::DENY); + } else { + // It's one or the other, so if they have view then they don't have view_full + access::update_htaccess_files($album, identity::everybody(), "view_full", access::DENY); + } + $completed++; + } + + $task->set("stack", implode(" ", $stack)); + $task->set("completed", $completed); + + if ($total == $completed) { + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + } else { + $task->percent_complete = round(100 * $completed / $total); + } + $task->status = t2("One album updated", "%count / %total albums updated", $completed, + array("total" => $total)); + } } \ No newline at end of file -- cgit v1.2.3 From 52f1c4b8c6a3a4043fcca3901a659b140b77f9d9 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 27 Jul 2010 10:49:47 -0700 Subject: Don't invoke a graphics toolkit when setting the album cover from a clean thumbnail; we can just copy it over. Should be a decent perf improvement in many cases. Fixes ticket #1255. --- modules/gallery/helpers/item.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index 8fea49cc..092904a5 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -105,9 +105,15 @@ class item_Core { model_cache::clear(); $parent->album_cover_item_id = $item->is_album() ? $item->album_cover_item_id : $item->id; - $parent->thumb_dirty = 1; + if ($item->thumb_dirty) { + $parent->thumb_dirty = 1; + graphics::generate($parent); + } else { + copy($item->thumb_path(), $parent->thumb_path()); + $parent->thumb_width = $item->thumb_width; + $parent->thumb_height = $item->thumb_height; + } $parent->save(); - graphics::generate($parent); $grand_parent = $parent->parent(); if ($grand_parent && access::can("edit", $grand_parent) && $grand_parent->album_cover_item_id == null) { -- cgit v1.2.3 From dd955781aaa9c1ee9e780b6b2c545878a47bbf21 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 27 Jul 2010 19:54:41 -0700 Subject: "public static" ==> "static" to match code conventions. --- modules/gallery/helpers/access.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index b1384c19..f1ea00c0 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -632,7 +632,7 @@ class access_Core { * @param string the permission name * @param string the new permission value (eg access::DENY) */ - public static function update_htaccess_files($album, $group, $perm_name, $value) { + static function update_htaccess_files($album, $group, $perm_name, $value) { if ($group->id != identity::everybody()->id || !($perm_name == "view" || $perm_name == "view_full")) { return; -- cgit v1.2.3 From b3c1b4633c55b14bfed607336ca213cb2fda4447 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Wed, 28 Jul 2010 22:42:04 -0700 Subject: Combine the Fix MPTT and Fix Permissions tasks into one magical fix-it task. --- modules/gallery/helpers/gallery_task.php | 166 ++++++++++++------------------- 1 file changed, 65 insertions(+), 101 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 4b5e9e93..54acd8c8 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -18,8 +18,9 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class gallery_task_Core { - const MPTT_LEFT = 0; - const MPTT_RIGHT = 1; + const FIX_STATE_MPTT_LEFT = 0; + const FIX_STATE_MPTT_RIGHT = 1; + const FIX_STATE_ALBUM_PERMISSIONS = 2; static function available_tasks() { $dirty_count = graphics::find_dirty_images_query()->count_records(); @@ -47,17 +48,10 @@ class gallery_task_Core { ->severity(log::SUCCESS); $tasks[] = Task_Definition::factory() - ->callback("gallery_task::fix_mptt") - ->name(t("Fix Album/Photo hierarchy")) - ->description(t("Fix problems where your album/photo breadcrumbs are out of " . - "sync with your actual hierarchy")) - ->severity(log::SUCCESS); - - $tasks[] = Task_Definition::factory() - ->callback("gallery_task::fix_permissions") - ->name(t("Fix permissions")) - ->description(t("Resynchronize database permissions with the .htaccess " . - "files in your gallery3/var directory")) + ->callback("gallery_task::fix") + ->name(t("Fix your Gallery")) + ->description(t("Fix up a variety of little problems that might be causing " . + "your Gallery to act a little weird")) ->severity(log::SUCCESS); return $tasks; @@ -317,13 +311,13 @@ class gallery_task_Core { } } - static function fix_mptt($task) { + static function fix($task) { $start = microtime(true); $total = $task->get("total"); if (empty($total)) { $task->set("total", $total = db::build()->count_records("items")); - $task->set("stack", "1:" . self::MPTT_LEFT); + $task->set("stack", item::root()->id . ":" . self::FIX_STATE_ALBUM_PERMISSIONS); $task->set("ptr", 1); $task->set("completed", 0); } @@ -332,21 +326,68 @@ class gallery_task_Core { $stack = explode(" ", $task->get("stack")); $completed = $task->get("completed"); - // Implement a depth-first tree walk using a stack. Not the most efficient, but it's simple. + // This is a state machine that checks each item in the database. It verifies the following + // attributes for an item. + // 1. The .htaccess permission files for restricted items exist and are well formed. + // 2. Left and right MPTT pointers are correct + // 3. The relative_path_cache and relative_url_cache values are set to null. + // + // We'll do a depth-first tree walk over our hierarchy using only the adjacency data because + // we don't trust MPTT here (that might be what we're here to fix!). Avoid avoid using ORM + // calls as much as possible since they're expensive. while ($stack && microtime(true) - $start < 1.5) { list($id, $state) = explode(":", array_pop($stack)); switch ($state) { - case self::MPTT_LEFT: - self::fix_mptt_set_left($id, $ptr++); - $item = ORM::factory("item", $id); - array_push($stack, $id . ":" . self::MPTT_RIGHT); - foreach (self::fix_mptt_children($id) as $child) { - array_push($stack, $child->id . ":" . self::MPTT_LEFT); + case self::FIX_STATE_ALBUM_PERMISSIONS: + $everybody = identity::everybody(); + $view_col = "view_{$everybody->id}"; + $view_full_col = "view_full_{$everybody->id}"; + $intent = ORM::factory("access_intent")->where("item_id", "=", $id)->find(); + + // Only load the item if we're going to use it below + if ($intent->$view_col === access::DENY || + $intent->$view_full_col === access::DENY) { + $item = ORM::factory("item", $id); + } + if ($intent->$view_col === access::DENY) { + access::update_htaccess_files($item, $everybody, "view", access::DENY); + } + if ($intent->$view_full_col === access::DENY) { + access::update_htaccess_files($item, $everybody, "view_full", access::DENY); + } + array_push($stack, "$id:" . self::FIX_STATE_MPTT_LEFT); + break; + + case self::FIX_STATE_MPTT_LEFT: + db::build() + ->update("items") + ->set("left_ptr", $ptr++) + ->where("id", "=", $id) + ->execute(); + array_push($stack, "$id:" . self::FIX_STATE_MPTT_RIGHT); + + foreach (db::build() + ->select(array("id", "type")) + ->from("items") + ->where("parent_id", "=", $id) + ->order_by("left_ptr", "ASC") + ->execute() as $child) { + if ($child->type == "album") { + array_push($stack, "{$child->id}:" . self::FIX_STATE_ALBUM_PERMISSIONS); + } else { + array_push($stack, "{$child->id}:" . self::FIX_STATE_MPTT_LEFT); + } } break; - case self::MPTT_RIGHT: - self::fix_mptt_set_right($id, $ptr++); + case self::FIX_STATE_MPTT_RIGHT: + db::build() + ->update("items") + ->set("right_ptr", $ptr++) + ->set("relative_path_cache", null) + ->set("relative_url_cache", null) + ->where("id", "=", $id) + ->execute(); $completed++; break; } @@ -366,81 +407,4 @@ class gallery_task_Core { $task->status = t2("One row updated", "%count / %total rows updated", $completed, array("total" => $total)); } - - static function fix_mptt_children($parent_id) { - return db::build() - ->select("id") - ->from("items") - ->where("parent_id", "=", $parent_id) - ->order_by("left_ptr", "ASC") - ->execute(); - } - - static function fix_mptt_set_left($id, $value) { - db::build() - ->update("items") - ->set("left_ptr", $value) - ->where("id", "=", $id) - ->execute(); - } - - static function fix_mptt_set_right($id, $value) { - db::build() - ->update("items") - ->set("right_ptr", $value) - ->set("relative_path_cache", null) - ->set("relative_url_cache", null) - ->where("id", "=", $id) - ->execute(); - } - - static function fix_permissions($task) { - $start = microtime(true); - - $total = $task->get("total"); - if (empty($total)) { - $everybody_id = identity::everybody()->id; - $stack = array(); - foreach (db::build() - ->select("id") - ->from("access_intents") - ->where("view_{$everybody_id}", "=", 0) - ->or_where("view_full_{$everybody_id}", "=", 0) - ->execute() as $row) { - $stack[] = $row->id; - } - - $task->set("total", $total = count($stack)); - $task->set("stack", implode(" ", $stack)); - $task->set("completed", 0); - } - - $stack = explode(" ", $task->get("stack")); - $completed = $task->get("completed"); - - while ($stack && microtime(true) - $start < 1.5) { - $album = ORM::factory("item", array_pop($stack)); - $everybody = identity::everybody(); - if (!access::group_can($everybody, "view", $album)) { - access::update_htaccess_files($album, identity::everybody(), "view", access::DENY); - } else { - // It's one or the other, so if they have view then they don't have view_full - access::update_htaccess_files($album, identity::everybody(), "view_full", access::DENY); - } - $completed++; - } - - $task->set("stack", implode(" ", $stack)); - $task->set("completed", $completed); - - if ($total == $completed) { - $task->done = true; - $task->state = "success"; - $task->percent_complete = 100; - } else { - $task->percent_complete = round(100 * $completed / $total); - } - $task->status = t2("One album updated", "%count / %total albums updated", $completed, - array("total" => $total)); - } } \ No newline at end of file -- cgit v1.2.3 From 7b8ed1079624eefae8d83fac89caa0eaa3fc9ef4 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Thu, 29 Jul 2010 21:47:52 -0700 Subject: Add recovery code for dupe slugs and dupe names to the general purpose Fix task. Fixes ticket #1260. --- modules/gallery/helpers/gallery_task.php | 263 +++++++++++++++++++++++++------ 1 file changed, 215 insertions(+), 48 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 54acd8c8..da9fba49 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -18,9 +18,15 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class gallery_task_Core { - const FIX_STATE_MPTT_LEFT = 0; - const FIX_STATE_MPTT_RIGHT = 1; - const FIX_STATE_ALBUM_PERMISSIONS = 2; + const FIX_STATE_START_MPTT = 0; + const FIX_STATE_RUN_MPTT = 1; + const FIX_STATE_START_PERMISSIONS = 2; + const FIX_STATE_RUN_PERMISSIONS = 3; + const FIX_STATE_START_DUPE_SLUGS = 4; + const FIX_STATE_RUN_DUPE_SLUGS = 5; + const FIX_STATE_START_DUPE_NAMES = 6; + const FIX_STATE_RUN_DUPE_NAMES = 7; + const FIX_STATE_DONE = 8; static function available_tasks() { $dirty_count = graphics::find_dirty_images_query()->count_records(); @@ -316,29 +322,194 @@ class gallery_task_Core { $total = $task->get("total"); if (empty($total)) { - $task->set("total", $total = db::build()->count_records("items")); - $task->set("stack", item::root()->id . ":" . self::FIX_STATE_ALBUM_PERMISSIONS); + // mptt: 2 operations for every item + // permissions: 1 operation for every album + // dupe slugs: 1 operation for each unique conflicted slug + $total = 2 * db::build()->count_records("items"); + $total += db::build()->where("type", "=", "album")->count_records("items"); + foreach (self::find_dupe_slugs() as $row) { + $total++; + } + foreach (self::find_dupe_names() as $row) { + $total++; + } + + $task->set("total", $total); + $task->set("state", $state = self::FIX_STATE_START_MPTT); $task->set("ptr", 1); $task->set("completed", 0); } - $ptr = $task->get("ptr"); - $stack = explode(" ", $task->get("stack")); $completed = $task->get("completed"); + $state = $task->get("state"); // This is a state machine that checks each item in the database. It verifies the following // attributes for an item. - // 1. The .htaccess permission files for restricted items exist and are well formed. - // 2. Left and right MPTT pointers are correct + // 1. Left and right MPTT pointers are correct + // 2. The .htaccess permission files for restricted items exist and are well formed. // 3. The relative_path_cache and relative_url_cache values are set to null. // // We'll do a depth-first tree walk over our hierarchy using only the adjacency data because // we don't trust MPTT here (that might be what we're here to fix!). Avoid avoid using ORM // calls as much as possible since they're expensive. - while ($stack && microtime(true) - $start < 1.5) { - list($id, $state) = explode(":", array_pop($stack)); + while ($state != self::FIX_STATE_DONE && microtime(true) - $start < 1.5) { switch ($state) { - case self::FIX_STATE_ALBUM_PERMISSIONS: + case self::FIX_STATE_START_MPTT: + $task->set("ptr", $ptr = 1); + $task->set("stack", item::root()->id . ":L"); + $state = self::FIX_STATE_RUN_MPTT; + break; + + case self::FIX_STATE_RUN_MPTT: + $ptr = $task->get("ptr"); + $stack = explode(" ", $task->get("stack")); + list ($id, $ptr_mode) = explode(":", array_pop($stack)); + if ($ptr_mode == "L") { + $stack[] = "$id:R"; + db::build() + ->update("items") + ->set("left_ptr", $ptr++) + ->where("id", "=", $id) + ->execute(); + + foreach (db::build() + ->select(array("id")) + ->from("items") + ->where("parent_id", "=", $id) + ->order_by("left_ptr", "ASC") + ->execute() as $child) { + array_push($stack, "{$child->id}:L"); + } + } else if ($ptr_mode == "R") { + db::build() + ->update("items") + ->set("right_ptr", $ptr++) + ->set("relative_path_cache", null) + ->set("relative_url_cache", null) + ->where("id", "=", $id) + ->execute(); + } + $task->set("ptr", $ptr); + $task->set("stack", implode(" ", $stack)); + $completed++; + + if (empty($stack)) { + $state = self::FIX_STATE_START_DUPE_SLUGS; + } + break; + + + case self::FIX_STATE_START_DUPE_SLUGS: + $stack = array(); + foreach (self::find_dupe_slugs() as $row) { + list ($parent_id, $slug) = explode(":", $row->parent_slug, 2); + $stack[] = join(":", array($parent_id, $slug)); + } + if ($stack) { + $task->set("stack", implode(" ", $stack)); + $state = self::FIX_STATE_RUN_DUPE_SLUGS; + } else { + $state = self::FIX_STATE_START_DUPE_NAMES; + } + break; + + case self::FIX_STATE_RUN_DUPE_SLUGS: + $stack = explode(" ", $task->get("stack")); + list ($parent_id, $slug) = explode(":", array_pop($stack)); + + // We want to leave the first one alone and update all conflicts to be random values. + $fixed = 0; + $conflicts = ORM::factory("item") + ->where("parent_id", "=", $parent_id) + ->where("slug", "=", $slug) + ->find_all(1, 1); + if ($conflicts->count() && $conflict = $conflicts->current()) { + $task->log("Fixing conflicting slug for item id {$conflict->id}"); + db::build() + ->update("items") + ->set("slug", $slug . "-" . (string)rand(1000, 9999)) + ->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:$slug"; + break; + } + $task->set("stack", implode(" ", $stack)); + $completed++; + + if (empty($stack)) { + $state = self::FIX_STATE_START_DUPE_NAMES; + } + break; + + case self::FIX_STATE_START_DUPE_NAMES: + $stack = array(); + foreach (self::find_dupe_names() as $row) { + list ($parent_id, $name) = explode(":", $row->parent_name, 2); + $stack[] = join(":", array($parent_id, $name)); + } + if ($stack) { + $task->set("stack", implode(" ", $stack)); + $state = self::FIX_STATE_RUN_DUPE_NAMES; + } else { + $state = self::FIX_STATE_START_PERMISSIONS; + } + break; + + case self::FIX_STATE_RUN_DUPE_NAMES: + $stack = explode(" ", $task->get("stack")); + list ($parent_id, $name) = explode(":", array_pop($stack)); + + $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", "=", $name) + ->find_all(1, 1); + if ($conflicts->count() && $conflict = $conflicts->current()) { + $task->log("Fixing conflicting name for item id {$conflict->id}"); + db::build() + ->update("items") + ->set("name", $name . "-" . (string)rand(1000, 9999)) + ->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:$name"; + break; + } + $task->set("stack", implode(" ", $stack)); + $completed++; + + if (empty($stack)) { + $state = self::FIX_STATE_START_PERMISSIONS; + } + break; + + case self::FIX_STATE_START_PERMISSIONS: + $stack = array(); + foreach (db::build() + ->select("id") + ->from("items") + ->where("type", "=", "album") + ->execute() as $row) { + $stack[] = $row->id; + } + $task->set("stack", implode(" ", $stack)); + $state = self::FIX_STATE_RUN_PERMISSIONS; + break; + + case self::FIX_STATE_RUN_PERMISSIONS: + $stack = explode(" ", $task->get("stack")); + $id = array_pop($stack); + $everybody = identity::everybody(); $view_col = "view_{$everybody->id}"; $view_full_col = "view_full_{$everybody->id}"; @@ -355,56 +526,52 @@ class gallery_task_Core { if ($intent->$view_full_col === access::DENY) { access::update_htaccess_files($item, $everybody, "view_full", access::DENY); } - array_push($stack, "$id:" . self::FIX_STATE_MPTT_LEFT); - break; - - case self::FIX_STATE_MPTT_LEFT: - db::build() - ->update("items") - ->set("left_ptr", $ptr++) - ->where("id", "=", $id) - ->execute(); - array_push($stack, "$id:" . self::FIX_STATE_MPTT_RIGHT); + $task->set("stack", implode(" ", $stack)); + $completed++; - foreach (db::build() - ->select(array("id", "type")) - ->from("items") - ->where("parent_id", "=", $id) - ->order_by("left_ptr", "ASC") - ->execute() as $child) { - if ($child->type == "album") { - array_push($stack, "{$child->id}:" . self::FIX_STATE_ALBUM_PERMISSIONS); - } else { - array_push($stack, "{$child->id}:" . self::FIX_STATE_MPTT_LEFT); - } + if (empty($stack)) { + $state = self::FIX_STATE_DONE; } break; - - case self::FIX_STATE_MPTT_RIGHT: - db::build() - ->update("items") - ->set("right_ptr", $ptr++) - ->set("relative_path_cache", null) - ->set("relative_url_cache", null) - ->where("id", "=", $id) - ->execute(); - $completed++; - break; } } - $task->set("stack", implode(" ", $stack)); - $task->set("ptr", $ptr); + $task->set("state", $state); $task->set("completed", $completed); - if ($total == $completed) { + if ($state == self::FIX_STATE_DONE) { $task->done = true; $task->state = "success"; $task->percent_complete = 100; } else { $task->percent_complete = round(100 * $completed / $total); } - $task->status = t2("One row updated", "%count / %total rows updated", $completed, + $task->status = t2("One operation complete", "%count / %total operations complete", $completed, array("total" => $total)); } + + static function find_dupe_slugs() { + return db::build() + ->select_distinct( + array("parent_slug" => new Database_Expression("CONCAT(`parent_id`, ':', `slug`)"))) + ->select("id") + ->select(array("C" => "COUNT(\"*\")")) + ->from("items") + ->having("C", ">", 1) + ->group_by("parent_slug") + ->execute(); + } + + static function find_dupe_names() { + return db::build() + ->select_distinct( + array("parent_name" => new Database_Expression("CONCAT(`parent_id`, ':', `name`)"))) + ->select("id") + ->select(array("C" => "COUNT(\"*\")")) + ->from("items") + ->where("type", "<>", "album") + ->having("C", ">", 1) + ->group_by("parent_name") + ->execute(); + } } \ No newline at end of file -- cgit v1.2.3 From cd50fde5dea97f10d8eb62e0e2058846ce9abdfe Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sun, 1 Aug 2010 08:57:22 -0700 Subject: Specify the charset on the content type header --- modules/gallery/helpers/json.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/json.php b/modules/gallery/helpers/json.php index 5fcdc268..bbd835e9 100644 --- a/modules/gallery/helpers/json.php +++ b/modules/gallery/helpers/json.php @@ -27,7 +27,7 @@ class json_Core { */ static function reply($message) { if (!headers_sent()) { - header("Content-Type: application/json"); + header("Content-Type: application/json; charset=" . Kohana::CHARSET); } print json_encode($message); } -- cgit v1.2.3 From bf7115cf5a732cea2d498971ec94d2ade3b2fcdd Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 1 Aug 2010 10:19:36 -0700 Subject: Write appropriate PHPdoc for json::reply. --- modules/gallery/helpers/json.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'modules/gallery/helpers') diff --git a/modules/gallery/helpers/json.php b/modules/gallery/helpers/json.php index bbd835e9..a39db27a 100644 --- a/modules/gallery/helpers/json.php +++ b/modules/gallery/helpers/json.php @@ -19,11 +19,10 @@ */ class json_Core { /** - * Does the active user have this permission on this item? + * JSON Encode a reply to the browser and set the content type to specify that it's a JSON + * payload. * - * @param string $perm_name - * @param Item_Model $item - * @return boolean + * @param mixed $message string or object to json encode and print */ static function reply($message) { if (!headers_sent()) { -- cgit v1.2.3