diff options
60 files changed, 593 insertions, 386 deletions
@@ -25,9 +25,15 @@ # you'll get an "Internal Server Error". # # <FilesMatch "(\.(class|fla|inc|sql|txt|gitignore)|(README|LICENSE))$"> +# Order deny,allow +# Deny from all +# </FilesMatch> +# <FilesMatch "robots.txt"> # Order allow,deny +# Allow from all # </FilesMatch> + # Improve performance by uncommenting this block. It tells the # browser that your images don't change very often so it won't keep # asking for them. If you get an error after uncommenting this, make @@ -73,9 +73,12 @@ if (PHP_SAPI == "cli") { break; default: - print "To install:\n php index.php install -d database -h host -u user -p password -x table_prefix \n\n\n"; - print "To upgrade:\n php index.php upgrade\n\n\n"; - print "Developer-only features:\n ** CAUTION! THESE FEATURES -WILL- DAMAGE YOUR INSTALL **\n"; + print "To install:\n"; + print " php index.php install -d database -h host -u user -p password -x table_prefix \n\n"; + print "To upgrade:\n"; + print " php index.php upgrade\n\n"; + print "Developer-only features:\n"; + print " ** CAUTION! THESE FEATURES -WILL- DAMAGE YOUR INSTALL **\n"; print " php index.php package # create new installer files\n"; print " php index.php test # run unit tests\n"; exit(1); diff --git a/installer/install.sql b/installer/install.sql index 7a40918d..52654faf 100644 --- a/installer/install.sql +++ b/installer/install.sql @@ -244,7 +244,7 @@ CREATE TABLE {modules} ( KEY `weight` (`weight`) ) AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO {modules} VALUES (1,1,'gallery',38,1); +INSERT INTO {modules} VALUES (1,1,'gallery',40,1); INSERT INTO {modules} VALUES (2,1,'user',3,2); INSERT INTO {modules} VALUES (3,1,'comment',3,3); INSERT INTO {modules} VALUES (4,1,'organize',2,4); @@ -395,7 +395,7 @@ CREATE TABLE {vars} ( `value` text, PRIMARY KEY (`id`), UNIQUE KEY `module_name` (`module_name`,`name`) -) AUTO_INCREMENT=49 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=51 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO {vars} VALUES (NULL,'gallery','active_site_theme','wind'); INSERT INTO {vars} VALUES (NULL,'gallery','active_admin_theme','admin_wind'); @@ -422,6 +422,8 @@ INSERT INTO {vars} VALUES (NULL,'gallery','email_reply_to','unknown@unknown.com' INSERT INTO {vars} VALUES (NULL,'gallery','choose_default_tookit','1'); INSERT INTO {vars} VALUES (NULL,'gallery','email_line_length','70'); INSERT INTO {vars} VALUES (NULL,'gallery','email_header_separator','s:1:\"\n\";'); +INSERT INTO {vars} VALUES (NULL,'gallery','show_user_profiles_to','registered_users'); +INSERT INTO {vars} VALUES (NULL,'gallery','extra_binary_paths','/usr/local/bin:/opt/local/bin:/opt/bin'); INSERT INTO {vars} VALUES (NULL,'comment','spam_caught','0'); INSERT INTO {vars} VALUES (NULL,'comment','access_permissions','everybody'); INSERT INTO {vars} VALUES (NULL,'gallery','blocks_site_sidebar','a:4:{i:9;a:2:{i:0;s:7:\"gallery\";i:1;s:8:\"language\";}i:10;a:2:{i:0;s:4:\"info\";i:1;s:8:\"metadata\";}i:11;a:2:{i:0;s:3:\"rss\";i:1;s:9:\"rss_feeds\";}i:12;a:2:{i:0;s:3:\"tag\";i:1;s:3:\"tag\";}}'); diff --git a/lib/gallery.common.js b/lib/gallery.common.js index 69452f39..2dbd7c7c 100644 --- a/lib/gallery.common.js +++ b/lib/gallery.common.js @@ -24,8 +24,12 @@ if (container == null) { container = 'div'; } - $(this).html("<" + container + " class=\"g-valign\">" + $(this).html() + "</" + container + ">"); - var el = $(this).children(container + ".g-valign"); + var el = $(this).find(".g-valign"); + if (!el.length) { + $(this).html("<" + container + " class=\"g-valign\">" + $(this).html() + + "</" + container + ">"); + el = $(this).children(container + ".g-valign"); + } var elh = $(el).height(); var ph = $(this).height(); var nh = (ph - elh) / 2; @@ -119,32 +123,32 @@ }; // Ajax handler for replacing an image, used in Ajax thumbnail rotation - $.gallery_replace_image = function(data, thumb) { - $(thumb).attr({src: data.src, width: data.width, height: data.height}); - if (typeof gallery_image_replaced_hook == 'function') { - gallery_image_replaced_hook(data, thumb); - } + $.gallery_replace_image = function(data, img_selector) { + $(img_selector).attr({src: data.src, width: data.width, height: data.height}); + $(img_selector).trigger("gallery.change"); }; // Initialize context menus $.fn.gallery_context_menu = function() { if ($(".g-context-menu li").length) { - var hover_target = ".g-context-menu"; - var in_progress = 0; - $(hover_target + " *").removeAttr('title'); - $(hover_target + " ul").hide(); - $(hover_target).hover( + var hover_target = $(this).find(".g-context-menu"); + if (hover_target.attr("context_menu_initialized")) { + return; + } + var list = $(hover_target).find("ul"); + hover_target.find("*").removeAttr('title'); + list.hide(); + hover_target.hover( function() { - if (in_progress == 0) { - $(this).find("ul").slideDown("fast", function() { in_progress = 1; }); - $(this).find(".g-dialog-link").gallery_dialog(); - $(this).find(".g-ajax-link").gallery_ajax(); - } + list.stop(true, true).slideDown("fast"); + $(this).find(".g-dialog-link").gallery_dialog(); + $(this).find(".g-ajax-link").gallery_ajax(); }, function() { - $(this).find("ul").slideUp("slow", function() { in_progress = 0; }); + list.stop(true, true).slideUp("slow"); } ); + hover_target.attr("context_menu_initialized", 1); } }; diff --git a/modules/comment/controllers/admin_manage_comments.php b/modules/comment/controllers/admin_manage_comments.php index 0889dc4e..49bd85d5 100644 --- a/modules/comment/controllers/admin_manage_comments.php +++ b/modules/comment/controllers/admin_manage_comments.php @@ -25,7 +25,7 @@ class Admin_Manage_Comments_Controller extends Admin_Controller { db::build() ->delete("comments") ->where("state", "IN", array("deleted", "spam")) - ->where("updated", "<", "UNIX_TIMESTAMP() - 86400 * 7") + ->where("updated", "<", new Database_Expression("UNIX_TIMESTAMP() - 86400 * 7")) ->execute(); // Redirect to the appropriate queue diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index ff0e9ce1..ded9743e 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -45,6 +45,7 @@ class Comments_Controller extends Controller { switch ($key) { case "guest_name": $key = "name"; break; case "guest_email": $key = "email"; break; + case "guest_url": $key = "url"; break; } $form->add_comment->inputs[$key]->add_error($error, 1); } diff --git a/modules/comment/helpers/comment.php b/modules/comment/helpers/comment.php index 7aa007cb..958f2f3d 100644 --- a/modules/comment/helpers/comment.php +++ b/modules/comment/helpers/comment.php @@ -38,7 +38,8 @@ class comment_Core { ->error_messages("invalid", t("You must enter a valid email address")); $group->input("url") ->label(t("Website (hidden)")) - ->id("g-url"); + ->id("g-url") + ->error_messages("url", t("You must enter a valid url")); $group->textarea("text") ->label(t("Comment")) ->id("g-text") diff --git a/modules/exif/helpers/exif_task.php b/modules/exif/helpers/exif_task.php index a754865a..5963d03f 100644 --- a/modules/exif/helpers/exif_task.php +++ b/modules/exif/helpers/exif_task.php @@ -50,7 +50,7 @@ class exif_task_Core { ->where("exif_records.item_id", "IS", null) ->or_where("exif_records.dirty", "=", 1) ->close() - ->find_all() as $item) { + ->find_all(100) as $item) { // The query above can take a long time, so start the timer after its done // to give ourselves a little time to actually process rows. if (!isset($start)) { @@ -60,7 +60,7 @@ class exif_task_Core { exif::extract($item); $completed++; - if (microtime(true) - $start > 1.5) { + if (microtime(true) - $start > .75) { break; } } diff --git a/modules/g2_import/controllers/g2.php b/modules/g2_import/controllers/g2.php index d260c9b4..0f51173a 100644 --- a/modules/g2_import/controllers/g2.php +++ b/modules/g2_import/controllers/g2.php @@ -34,38 +34,44 @@ class G2_Controller extends Controller { $path = $input->get("path"); $id = $input->get("g2_itemId"); - if ($id) { - // Requests by id are either core.DownloadItem or core.ShowItem requests. Later versions of - // Gallery 2 don't specify g2_view if it's the default (core.ShowItem). And in some cases - // (bbcode, embedding) people are using the id style URLs although URL rewriting is enabled. - $where = array(array("g2_id", "=", $id)); - $view = $input->get("g2_view"); - if ($view) { - $where[] = array("g2_url", "like", "%g2_view=$view%"); - } // else: Assuming that the first search hit is sufficiently good. - } else if ($path) { - $where = array(array("g2_url", "=", $path)); - } else { - throw new Kohana_404_Exception(); - } + if ($path || $id) { + if ($id) { + // Requests by id are either core.DownloadItem or core.ShowItem requests. Later versions of + // Gallery 2 don't specify g2_view if it's the default (core.ShowItem). And in some cases + // (bbcode, embedding) people are using the id style URLs although URL rewriting is enabled. + $where = array(array("g2_id", "=", $id)); + $view = $input->get("g2_view"); + if ($view) { + $where[] = array("g2_url", "like", "%g2_view=$view%"); + } // else: Assuming that the first search hit is sufficiently good. + } else if ($path) { + $where = array(array("g2_url", "IN", array($path, str_replace(" ", "+", $path)))); + } else { + throw new Kohana_404_Exception(); + } - $g2_map = ORM::factory("g2_map") - ->merge_where($where) - ->find(); + $g2_map = ORM::factory("g2_map") + ->merge_where($where) + ->find(); - if (!$g2_map->loaded()) { - throw new Kohana_404_Exception(); - } + if (!$g2_map->loaded()) { + throw new Kohana_404_Exception(); + } - $item = ORM::factory("item", $g2_map->g3_id); - if (!$item->loaded()) { - throw new Kohana_404_Exception(); + $item = ORM::factory("item", $g2_map->g3_id); + if (!$item->loaded()) { + throw new Kohana_404_Exception(); + } + $resource_type = $g2_map->resource_type; + } else { + $item = item::root(); + $resource_type = "album"; } access::required("view", $item); // Redirect the user to the new url - switch ($g2_map->resource_type) { + switch ($resource_type) { case "thumbnail": url::redirect($item->thumb_url(true)); diff --git a/modules/g2_import/css/g2_import.css b/modules/g2_import/css/g2_import.css deleted file mode 100644 index d53564d7..00000000 --- a/modules/g2_import/css/g2_import.css +++ /dev/null @@ -1,30 +0,0 @@ -#g-admin-g2-import-notes { - padding-bottom: 20px; -} - -#g-admin-g2-import-details { - padding-top: 20px; -} - -#g-admin-g2-import-details .g-warning { - margin-top: 4px; -} - -#g-admin-g2-import-details .g-info { - padding: 2px; - border: 1px solid #999; - margin-bottom: 10px; -} - -#g-admin-g2-import-notes p, -#g-admin-g2-import-details .g-info p { - padding: 0; - margin: 0; -} - -#g-admin-g2-import-notes ul li, -#g-admin-g2-import .g-info ul li { - padding-left: 0; - margin-left: 20px; - list-style-type: disc; -} diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index c3737f8f..515eb73d 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -452,9 +452,9 @@ class g2_import_Core { "title" => "title", "viewCount" => "view_count"); $direction_map = array( - 1 => "asc", - ORDER_ASCENDING => "asc", - ORDER_DESCENDING => "desc"); + 1 => "ASC", + ORDER_ASCENDING => "ASC", + ORDER_DESCENDING => "DESC"); // Only consider G2's first sort order $g2_order = explode("|", $g2_album->getOrderBy() . ""); $g2_order = $g2_order[0]; diff --git a/modules/g2_import/helpers/g2_import_theme.php b/modules/g2_import/helpers/g2_import_theme.php deleted file mode 100644 index 788253f9..00000000 --- a/modules/g2_import/helpers/g2_import_theme.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access."); -/** - * Gallery - a web based photo album viewer and editor - * Copyright (C) 2000-2010 Bharat Mediratta - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. - */ -class g2_import_theme_Core { - static function head($theme) { - $theme->css("g2_import.css"); - } - - static function admin_head($theme) { - $theme->css("g2_import.css"); - } -}
\ No newline at end of file diff --git a/modules/g2_import/views/admin_g2_import.html.php b/modules/g2_import/views/admin_g2_import.html.php index 8ec4b5ce..564bea9f 100644 --- a/modules/g2_import/views/admin_g2_import.html.php +++ b/modules/g2_import/views/admin_g2_import.html.php @@ -6,29 +6,10 @@ </p> <div class="g-block-content"> - <div id="g-admin-g2-import-notes"> - <h2> <?= t("Notes") ?> </h2> - <p> - <?= t("The import process is a work in progress with some known issues:") ?> - </p> - <ul> - <li> - <?= t("Gallery 3 does not support per-user / per-item permissions. <b>Review permissions after your import is done.</b>") ?> - </li> - <li> - <?= t("The only supported file formats are JPG, PNG and GIF, FLV and MP4. Other formats will be skipped.") ?> - </li> - <li> - <?= t("Deactivating the <b>notification</b>, <b>search</b> and <b>exif</b> modules during your import will make it go faster.") ?> - </li> - <li> - <?= t("The eAccelerator PHP performance extension is known to cause issues. If you're using eAccelerator and having problems, please disable it while you do your import. One way to do that is to put <code>php_value eaccelerator.enable 0</code> in gallery3/.htaccess") ?> - </li> - </ul> - </div> - <?= $form ?> + </div> + <div class="g-block-content"> <? if (g2_import::is_initialized()): ?> <div id="g-admin-g2-import-details"> <h2> <?= t("Import") ?> </h2> @@ -53,59 +34,65 @@ "url" => html::mark_clean(url::site("admin/theme_options")))) ?> </li> <? endif ?> + + <li class="g-info"> + <?= t("Your Gallery 2 has the following importable data in it:") ?> + <p> + <?= t2("1 user", "%count users", $g2_stats["users"]) ?>, + <?= t2("1 group", "%count groups", $g2_stats["groups"]) ?>, + <?= t2("1 album", "%count albums", $g2_stats["albums"]) ?>, + <?= t2("1 photo", "%count photos", $g2_stats["photos"]) ?>, + <?= t2("1 movie", "%count movies", $g2_stats["movies"]) ?>, + <?= t2("1 comment", "%count comments", $g2_stats["comments"]) ?>, + <?= t2("1 tagged photo/movie/album", + "%count tagged photos/movies/albums", $g2_stats["tags"]) ?> + </p> + </li> </ul> - <div class="g-message-block g-info"> - <p> - <?= t("Your Gallery 2 has the following importable data in it") ?> - </p> - <ul> - <li> - <?= t2("1 user", "%count users", $g2_stats["users"]) ?> - </li> - <li> - <?= t2("1 group", "%count groups", $g2_stats["groups"]) ?> - </li> - <li> - <?= t2("1 album", "%count albums", $g2_stats["albums"]) ?> - </li> + <p> + <a class="g-button g-dialog-link ui-state-default ui-corner-all" + href="<?= url::site("admin/maintenance/start/g2_import_task::import?csrf=$csrf") ?>"> + <?= t("Begin import!") ?> + </a> + </p> + </div> + + <div class="g-block-content"> + <div id="g-admin-g2-import-notes"> + <h2> <?= t("Notes") ?> </h2> + <ul class="enumeration"> <li> - <?= t2("1 photo", "%count photos", $g2_stats["photos"]) ?> + <?= t("Gallery 3 does not support per-user / per-item permissions. <b>Review permissions after your import is done.</b>") ?> </li> <li> - <?= t2("1 movie", "%count movies", $g2_stats["movies"]) ?> + <?= t("The only supported file formats are JPG, PNG and GIF, FLV and MP4. Other formats will be skipped.") ?> </li> <li> - <?= t2("1 comment", "%count comments", $g2_stats["comments"]) ?> + <?= t("Deactivating the <b>notification</b>, <b>search</b> and <b>exif</b> modules during your import will make it go faster.") ?> </li> <li> - <?= t2("1 tagged photo/movie/album", - "%count tagged photos/movies/albums", $g2_stats["tags"]) ?> + <?= t("The eAccelerator and XCache PHP performance extensions are known to cause issues. If you're using either of those and are having problems, please disable them while you do your import. Add the following lines: <pre>%lines</pre> to gallery3/.htaccess and remove them when the import is done.", array("lines" => "\n\n php_value eaccelerator.enable 0\n php_value xcache.cacher off\n php_value xcache.optimizer off\n\n")) ?> </li> </ul> </div> - - <p> - <a class="g-button g-dialog-link ui-state-default ui-corner-all" - href="<?= url::site("admin/maintenance/start/g2_import_task::import?csrf=$csrf") ?>"> - <?= t("Begin import!") ?> - </a> - </p> </div> - <div> - <h2> <?= t("Migrating from Gallery 2") ?> </h2> - <p> - <?= t("Once your migration is complete, put this block at the top of your gallery2/.htaccess file and all Gallery 2 urls will be redirected to Gallery 3") ?> - </p> + <div class="g-block-content"> + <div> + <h2> <?= t("Migrating from Gallery 2") ?> </h2> + <p> + <?= t("Once your migration is complete, put this block at the top of your gallery2/.htaccess file and all Gallery 2 urls will be redirected to Gallery 3") ?> + </p> - <textarea rows="2"><IfModule mod_rewrite.c> + <textarea rows="4" cols="60"><IfModule mod_rewrite.c> Options +FollowSymLinks RewriteEngine On RewriteBase <?= html::clean(g2_import::$g2_base_url) ?> RewriteRule ^(.*)$ <?= url::site("g2/map?path=\$1") ?> [QSA,L,R=301] </IfModule></textarea> + </div> + <? endif ?> </div> - <? endif ?> </div> </div> diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php index a9cc933c..7729d797 100644 --- a/modules/gallery/controllers/admin_maintenance.php +++ b/modules/gallery/controllers/admin_maintenance.php @@ -48,6 +48,13 @@ class Admin_Maintenance_Controller extends Admin_Controller { $view->content->finished_tasks = ORM::factory("task") ->where("done", "=", 1)->order_by("updated", "DESC")->find_all(); print $view; + + // Do some maintenance while we're in here + db::build() + ->delete("caches") + ->where("expiration", "<>", 0) + ->where("expiration", "<=", time()) + ->execute(); } /** diff --git a/modules/gallery/controllers/admin_modules.php b/modules/gallery/controllers/admin_modules.php index f5af9a5a..650b7e9e 100644 --- a/modules/gallery/controllers/admin_modules.php +++ b/modules/gallery/controllers/admin_modules.php @@ -95,12 +95,17 @@ class Admin_Modules_Controller extends Admin_Controller { $activated_names[] = t($info->name); } } catch (Exception $e) { + message::warning(t("An error occurred while installing the <b>%module_name</b> module", + array("module_name" => $info->name))); Kohana_Log::add("error", (string)$e); } } module::event("module_change", $changes); + // If modules need upgrading, this will get recreated + site_status::clear("upgrade_now"); + // @todo this type of collation is questionable from an i18n perspective if ($activated_names) { message::success(t("Activated: %names", array("names" => join(", ", $activated_names)))); diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index c34209da..3db4f5df 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -36,7 +36,8 @@ class Quick_Controller extends Controller { } if ($degrees) { - $tmpfile = tempnam(TMPPATH, "rotate"); + $tmpfile = tempnam(TMPPATH, "rotate") . "." . + pathinfo($item->file_path(), PATHINFO_EXTENSION); gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $degrees)); $item->set_data_file($tmpfile); $item->save(); diff --git a/modules/gallery/controllers/reauthenticate.php b/modules/gallery/controllers/reauthenticate.php index 0486c0fe..53a96374 100644 --- a/modules/gallery/controllers/reauthenticate.php +++ b/modules/gallery/controllers/reauthenticate.php @@ -19,12 +19,19 @@ */ class Reauthenticate_Controller extends Controller { public function index() { + $is_ajax = Session::instance()->get_once("is_ajax_request", request::is_ajax()); if (!identity::active_user()->admin) { - access::forbidden(); + if ($is_ajax) { + // We should never be able to get here since Admin_Controller::_reauth_check() won't work + // for non-admins. + access::forbidden(); + } else { + url::redirect(item::root()->abs_url()); + } } + // On redirects from the admin controller, the ajax request indicator is lost, // so we store it in the session. - $is_ajax = Session::instance()->get_once("is_ajax_request", request::is_ajax()); if ($is_ajax) { $v = new View("reauthenticate.html"); $v->form = self::_form(); diff --git a/modules/gallery/controllers/upgrader.php b/modules/gallery/controllers/upgrader.php index cb940b46..b2646874 100644 --- a/modules/gallery/controllers/upgrader.php +++ b/modules/gallery/controllers/upgrader.php @@ -39,10 +39,12 @@ class Upgrader_Controller extends Controller { } } + $failed = Input::instance()->get("failed"); $view = new View("upgrader.html"); $view->can_upgrade = identity::active_user()->admin || $session->get("can_upgrade"); $view->upgrade_token = $upgrade_token; $view->available = module::available(); + $view->failed = $failed ? explode(",", $failed) : array(); $view->done = $available_upgrades == 0; print $view; } @@ -52,8 +54,16 @@ class Upgrader_Controller extends Controller { // @todo this may screw up some module installers, but we don't have a better answer at // this time. $_SERVER["HTTP_HOST"] = "example.com"; - } else if (!identity::active_user()->admin && !Session::instance()->get("can_upgrade", false)) { - access::forbidden(); + } else { + if (!identity::active_user()->admin && !Session::instance()->get("can_upgrade", false)) { + access::forbidden(); + } + + try { + access::verify_csrf(); + } catch (Exception $e) { + url::redirect("upgrader"); + } } $available = module::available(); @@ -65,20 +75,36 @@ class Upgrader_Controller extends Controller { } // Then upgrade the rest + $failed = array(); foreach (module::available() as $id => $module) { if ($id == "gallery") { continue; } if ($module->active && $module->code_version != $module->version) { - module::upgrade($id); + try { + module::upgrade($id); + } catch (Exception $e) { + // @todo assume it's MODULE_FAILED_TO_UPGRADE for now + $failed[] = $id; + } } } + // If the upgrade failed, this will get recreated + site_status::clear("upgrade_now"); + if (php_sapi_name() == "cli") { - print "Upgrade complete\n"; + if ($failed) { + print "Upgrade completed ** WITH FAILURES **\n"; + print "The following modules were not successfully upgraded:\n"; + print " " . implode($failed, "\n ") . "\n"; + print "Try getting newer versions or deactivating those modules\n"; + } else { + print "Upgrade complete\n"; + } } else { - url::redirect("upgrader"); + url::redirect("upgrader?failed=" . join(",", $failed)); } } } diff --git a/modules/gallery/controllers/user_profile.php b/modules/gallery/controllers/user_profile.php index e992655b..4922416c 100644 --- a/modules/gallery/controllers/user_profile.php +++ b/modules/gallery/controllers/user_profile.php @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class User_Profile_Controller extends Controller { + public function show($id) { // If we get here, then we should have a user id other than guest. $user = identity::lookup_user($id); @@ -25,6 +26,10 @@ class User_Profile_Controller extends Controller { throw new Kohana_404_Exception(); } + if (!$this->_can_view_profile_pages($user)) { + throw new Kohana_404_Exception(); + } + $v = new Theme_View("page.html", "other", "profile"); $v->page_title = t("%name Profile", array("name" => $user->display_name())); $v->content = new View("user_profile.html"); @@ -44,12 +49,20 @@ class User_Profile_Controller extends Controller { public function contact($id) { $user = identity::lookup_user($id); + if (!$this->_can_view_profile_pages($user)) { + throw new Kohana_404_Exception(); + } + print user_profile::get_contact_form($user); } public function send($id) { access::verify_csrf(); $user = identity::lookup_user($id); + if (!$this->_can_view_profile_pages($user)) { + throw new Kohana_404_Exception(); + } + $form = user_profile::get_contact_form($user); if ($form->validate()) { Sendmail::factory() @@ -66,4 +79,30 @@ class User_Profile_Controller extends Controller { json::reply(array("result" => "error", "html" => (string)$form)); } } + + private function _can_view_profile_pages($user) { + if (!$user->loaded()) { + return false; + } + + if ($user->id == identity::active_user()->id) { + // You can always view your own profile + return true; + } + + switch (module::get_var("gallery", "show_user_profiles_to")) { + case "admin_users": + return identity::active_user()->admin; + + case "registered_users": + return !identity::active_user()->guest; + + case "everybody": + return true; + + default: + // Fail in private mode on an invalid setting + return false; + } + } } diff --git a/modules/gallery/css/upgrader.css b/modules/gallery/css/upgrader.css index d1b74c31..8610016e 100644 --- a/modules/gallery/css/upgrader.css +++ b/modules/gallery/css/upgrader.css @@ -58,6 +58,10 @@ tr.upgradeable td.gallery { color: #00d; } +tr.failed td { + color: red; +} + p { font-size: .9em; } @@ -120,12 +124,28 @@ div#dialog div { opacity: 0.5; } +.failed { + color: red; +} + pre { display: inline; margin: 0px; padding: 0px; } +div#upgrade_button { + margin-bottom: 20px; +} + +div#welcome_message { + margin-left: 30px; +} + +#logo { + margin-left: 14px; +} + .rtl { direction: rtl; } @@ -153,3 +173,11 @@ pre { .rtl div#dialog a.close { float: left; } + +.rtl div#welcome_message { + padding-right: 30px; +} + +.rtl #logo { + padding-right: 12px; +} diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 86ea9572..52a36298 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -263,15 +263,15 @@ class access_Core { } /** - * Recalculate the permissions for a given item and its hierarchy. $item must be an album. + * Recalculate the permissions for an album's hierarchy. */ - static function recalculate_permissions($item) { + static function recalculate_album_permissions($album) { foreach (self::_get_all_groups() as $group) { foreach (ORM::factory("permission")->find_all() as $perm) { if ($perm->name == "view") { - self::_update_access_view_cache($group, $item); + self::_update_access_view_cache($group, $album); } else { - self::_update_access_non_view_cache($group, $perm->name, $item); + self::_update_access_non_view_cache($group, $perm->name, $album); } } } @@ -279,6 +279,28 @@ class access_Core { } /** + * Recalculate the permissions for a single photo. + */ + static function recalculate_photo_permissions($photo) { + $parent = $photo->parent(); + $parent_access_cache = ORM::factory("access_cache")->where("item_id", "=", $parent->id)->find(); + $photo_access_cache = ORM::factory("access_cache")->where("item_id", "=", $photo->id)->find(); + foreach (self::_get_all_groups() as $group) { + foreach (ORM::factory("permission")->find_all() as $perm) { + $field = "{$perm->name}_{$group->id}"; + if ($perm->name == "view") { + $photo->$field = $parent->$field; + } else { + $photo_access_cache->$field = $parent_access_cache->$field; + } + } + } + $photo_access_cache->save(); + $photo->save(); + model_cache::clear(); + } + + /** * Register a permission so that modules can use it. * * @param string $name The internal name for for this permission diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php index 0ac5e8b0..89185e50 100644 --- a/modules/gallery/helpers/album.php +++ b/modules/gallery/helpers/album.php @@ -114,6 +114,7 @@ class album_Core { "captured" => t("Date captured"), "created" => t("Date uploaded"), "title" => t("Title"), + "name" => t("File name"), "updated" => t("Date modified"), "view_count" => t("Number of views"), "rand_key" => t("Random")); diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 9430231c..ca8c92c9 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -44,7 +44,8 @@ class gallery_Core { if (Router::$controller != "login" && Router::$controller != "combined" && identity::active_user()->guest && - !access::user_can(identity::guest(), "view", item::root())) { + !access::user_can(identity::guest(), "view", item::root()) && + php_sapi_name() != "cli") { if (Router::$controller == "admin") { // At this point we're in the admin theme and it doesn't have a themed login page, so // we can't just swap in the login controller and have it work. So redirect back to the diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index 0ba98025..b59bb9b9 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -118,8 +118,8 @@ class gallery_event_Core { $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()) { + // Choose the first viewable child as the new cover. + if ($child = $parent->viewable()->children(1)->current()) { item::make_album_cover($child); } } @@ -157,7 +157,11 @@ class gallery_event_Core { } static function item_moved($item, $old_parent) { - access::recalculate_permissions($item->parent()); + if ($item->is_album()) { + access::recalculate_album_permissions($item->parent()); + } else { + access::recalculate_photo_permissions($item); + } // If the new parent doesn't have an album cover, make this it. if (!$item->parent()->album_cover_item_id) { @@ -211,9 +215,9 @@ class gallery_event_Core { if (Router::$controller == "admin") { $continue_url = url::abs_site(""); - } else if (isset($theme->item)) { + } else if ($item = $theme->item()) { if (access::user_can(identity::guest(), "view", $theme->item)) { - $continue_url = $theme->item->abs_url(); + $continue_url = $item->abs_url(); } else { $continue_url = item::root()->abs_url(); } diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index c23bcca8..83961d6b 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -302,14 +302,14 @@ class gallery_installer { module::set_var("gallery", "maintenance_mode", 0); module::set_var("gallery", "visible_title_length", 15); module::set_var("gallery", "favicon_url", "lib/images/favicon.ico"); - - // Sendmail configuration module::set_var("gallery", "email_from", ""); module::set_var("gallery", "email_reply_to", ""); module::set_var("gallery", "email_line_length", 70); module::set_var("gallery", "email_header_separator", serialize("\n")); + module::set_var("gallery", "show_user_profiles_to", "registered_users"); + module::set_var("gallery", "extra_binary_paths", "/usr/local/bin:/opt/local/bin:/opt/bin"); - module::set_version("gallery", 38); + module::set_version("gallery", 40); } static function upgrade($version) { @@ -627,6 +627,16 @@ class gallery_installer { } module::set_version("gallery", $version = 38); } + + if ($version == 38) { + module::set_var("gallery", "show_user_profiles_to", "registered_users"); + module::set_version("gallery", $version = 39); + } + + if ($version == 39) { + module::set_var("gallery", "extra_binary_paths", "/usr/local/bin:/opt/local/bin:/opt/bin"); + module::set_version("gallery", $version = 40); + } } static function uninstall() { diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 0886aad0..3b173928 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -571,7 +571,7 @@ class gallery_task_Core { // The new cache rows are there, but they're incorrectly populated so we have to fix // them. If this turns out to be too slow, we'll have to refactor // access::recalculate_permissions to allow us to do it in slices. - access::recalculate_permissions(item::root()); + access::recalculate_album_permissions(item::root()); $state = self::FIX_STATE_DONE; } break; @@ -596,7 +596,7 @@ class gallery_task_Core { static function find_dupe_slugs() { return db::build() ->select_distinct( - array("parent_slug" => new Database_Expression("CONCAT(`parent_id`, ':', `slug`)"))) + array("parent_slug" => new Database_Expression("CONCAT(`parent_id`, ':', LOWER(`slug`))"))) ->select("id") ->select(array("C" => "COUNT(\"*\")")) ->from("items") @@ -608,7 +608,7 @@ class gallery_task_Core { static function find_dupe_names() { return db::build() ->select_distinct( - array("parent_name" => new Database_Expression("CONCAT(`parent_id`, ':', `name`)"))) + array("parent_name" => new Database_Expression("CONCAT(`parent_id`, ':', LOWER(`name`))"))) ->select("id") ->select(array("C" => "COUNT(\"*\")")) ->from("items") diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index bb085ea5..2868a28d 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -314,9 +314,10 @@ class graphics_Core { $toolkits->graphicsmagick->error = t("GraphicsMagick requires the <b>exec</b> function"); } else { $graphics_path = module::get_var("gallery", "graphics_toolkit_path", null); + $extra_binary_paths = module::get_var("gallery", "extra_binary_paths", null); putenv("PATH=" . getenv("PATH") . (empty($graphics_path) ? "" : ":$graphics_path") . - ":/usr/local/bin:/opt/local/bin:/opt/bin"); + ":" . $extra_binary_paths); // @todo: consider refactoring the two segments below into a loop since they are so // similar. diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index 1f5473ff..d1e72260 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -92,6 +92,7 @@ class locales_Core { $l["ko_KR"] = "한국어"; // Korean $l["lt_LT"] = "Lietuvių"; // Lithuanian $l["lv_LV"] = "Latviešu"; // Latvian + $l["mk_MK"] = "Македонски јазик"; // Macedonian $l["nl_NL"] = "Nederlands"; // Dutch $l["no_NO"] = "Norsk bokmål"; // Norwegian $l["pl_PL"] = "Polski"; // Polish diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 736b6854..7863520e 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -99,6 +99,10 @@ class module_Core { $m->code_version = $m->version; $m->version = self::get_version($module_name); $m->locked = false; + + if ($m->active && $m->version != $m->code_version) { + site_status::warning(t("Some of your modules are out of date. <a href=\"%upgrader_url\">Upgrade now!</a>", array("upgrader_url" => url::site("upgrader"))), "upgrade_now"); + } } // Lock certain modules @@ -139,7 +143,7 @@ class module_Core { } /** - * Allow modules to indicate the impact of deactivating the specifeid module + * Allow modules to indicate the impact of deactivating the specified module * @param string $module_name * @return array an array of warning or error messages to be displayed */ @@ -214,10 +218,10 @@ class module_Core { static function upgrade($module_name) { $version_before = module::get_version($module_name); $installer_class = "{$module_name}_installer"; + $available = module::available(); if (method_exists($installer_class, "upgrade")) { call_user_func_array(array($installer_class, "upgrade"), array($version_before)); } else { - $available = module::available(); if (isset($available->$module_name->code_version)) { module::set_version($module_name, $available->$module_name->code_version); } else { @@ -234,6 +238,10 @@ class module_Core { "version_before" => $version_before, "version_after" => $version_after))); } + + if ($version_after != $available->$module_name->code_version) { + throw new Exception("@todo MODULE_FAILED_TO_UPGRADE"); + } } /** diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index 3e55eefe..50339541 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -86,9 +86,10 @@ class movie_Core { static function find_ffmpeg() { if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) || !file_exists($ffmpeg_path)) { $graphics_path = module::get_var("gallery", "graphics_toolkit_path", null); + $extra_binary_paths = module::get_var("gallery", "extra_binary_paths", null); putenv("PATH=" . getenv("PATH") . (empty($graphics_path) ? "" : ":$graphics_path") . - ":/usr/local/bin:/opt/local/bin:/opt/bin"); + ":" . $extra_binary_paths); if (function_exists("exec")) { $ffmpeg_path = exec("which ffmpeg"); } diff --git a/modules/gallery/libraries/drivers/Cache/Database.php b/modules/gallery/libraries/drivers/Cache/Database.php index 9ada52e1..b7822811 100644 --- a/modules/gallery/libraries/drivers/Cache/Database.php +++ b/modules/gallery/libraries/drivers/Cache/Database.php @@ -179,20 +179,6 @@ class Cache_Database_Driver extends Cache_Driver { } /** - * Deletes all cache files that are older than the current time. - */ - public function delete_expired() { - // Delete all expired caches - $status = db::build() - ->delete("caches") - ->where("expiration", "<>", 0) - ->where("expiration", "<=", time()) - ->execute(); - - return count($status) > 0; - } - - /** * Empty the cache */ public function delete_all() { diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 34c22021..7bcf1f31 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Item_Model extends ORM_MPTT { +class Item_Model_Core extends ORM_MPTT { protected $children = "items"; protected $sorting = array(); protected $data_file = null; @@ -357,26 +357,7 @@ class Item_Model extends ORM_MPTT { } } - // Randomize the name or slug if there's a conflict. Preserve the extension. - // @todo Improve this. Random numbers are not user friendly - $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) - ->and_open() - ->where("name", "=", $this->name) - ->or_where("slug", "=", $this->slug) - ->close() - ->find()->id) { - $rand = rand(); - if ($base_ext) { - $this->name = "$base_name-$rand.$base_ext"; - } else { - $this->name = "$base_name-$rand"; - } - $this->slug = "$base_slug-$rand"; - } + $this->_randomize_name_or_slug_on_conflict(); parent::save(); @@ -427,6 +408,8 @@ class Item_Model extends ORM_MPTT { $this->relative_url_cache = null; } + $this->_randomize_name_or_slug_on_conflict(); + parent::save(); // Now update the filesystem and any database caches if there were significant value @@ -505,6 +488,33 @@ class Item_Model 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 + */ + 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) + ->and_open() + ->where("name", "=", $this->name) + ->or_where("slug", "=", $this->slug) + ->close() + ->find()->id) { + $rand = rand(); + if ($base_ext) { + $this->name = "$base_name-$rand.$base_ext"; + } else { + $this->name = "$base_name-$rand"; + } + $this->slug = "$base_slug-$rand"; + } + } + + /** * Return the Item_Model representing the cover for this album. * @return Item_Model or null if there's no cover */ @@ -530,7 +540,7 @@ class Item_Model extends ORM_MPTT { * the first child in the album is at position 1. */ public function get_position($child, $where=array()) { - if ($this->sort_order == "DESC") { + if (!strcasecmp($this->sort_order, "DESC")) { $comp = ">"; } else { $comp = "<"; @@ -977,23 +987,30 @@ class Item_Model extends ORM_MPTT { $data["web_url"] = $this->abs_url(); - if (access::can("view_full", $this) && !$this->is_album()) { - $data["file_url"] = rest::url("data", $this, "full"); - } - if (access::user_can(identity::guest(), "view_full", $this)) { - $data["file_url_public"] = $this->file_url(true); + if (!$this->is_album()) { + if (access::can("view_full", $this)) { + $data["file_url"] = rest::url("data", $this, "full"); + $data["file_size"] = filesize($this->file_path()); + } + if (access::user_can(identity::guest(), "view_full", $this)) { + $data["file_url_public"] = $this->file_url(true); + } } if ($this->is_photo()) { $data["resize_url"] = rest::url("data", $this, "resize"); + $data["resize_size"] = filesize($this->resize_path()); if (access::user_can(identity::guest(), "view", $this)) { $data["resize_url_public"] = $this->resize_url(true); } } - $data["thumb_url"] = rest::url("data", $this, "thumb"); - if (access::user_can(identity::guest(), "view", $this)) { - $data["thumb_url_public"] = $this->thumb_url(true); + if ($this->has_thumb()) { + $data["thumb_url"] = rest::url("data", $this, "thumb"); + $data["thumb_size"] = filesize($this->thumb_path()); + if (access::user_can(identity::guest(), "view", $this)) { + $data["thumb_url_public"] = $this->thumb_url(true); + } } $data["can_edit"] = access::can("edit", $this); diff --git a/modules/gallery/module.info b/modules/gallery/module.info index cc3b2723..1155ddf7 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,3 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 38 +version = 40 diff --git a/modules/gallery/tests/Access_Helper_Test.php b/modules/gallery/tests/Access_Helper_Test.php index c092e3fd..32b3020f 100644 --- a/modules/gallery/tests/Access_Helper_Test.php +++ b/modules/gallery/tests/Access_Helper_Test.php @@ -359,11 +359,13 @@ class Access_Helper_Test extends Gallery_Unit_Test_Case { $public_album = test::random_album(); $public_photo = test::random_photo($public_album); access::allow(identity::everybody(), "view", $public_album); + access::allow(identity::everybody(), "edit", $public_album); item::root()->reload(); // Account for MPTT changes $private_album = test::random_album(); access::deny(identity::everybody(), "view", $private_album); + access::deny(identity::everybody(), "edit", $private_album); $private_photo = test::random_photo($private_album); // Make sure that we now have a public photo and private photo. @@ -385,6 +387,8 @@ class Access_Helper_Test extends Gallery_Unit_Test_Case { // Make sure that the public_photo is now private, and the private_photo is now public. $this->assert_false(access::group_can(identity::everybody(), "view", $public_photo)); + $this->assert_false(access::group_can(identity::everybody(), "edit", $public_photo)); $this->assert_true(access::group_can(identity::everybody(), "view", $private_photo)); + $this->assert_true(access::group_can(identity::everybody(), "edit", $private_photo)); } } diff --git a/modules/gallery/tests/Cache_Test.php b/modules/gallery/tests/Cache_Test.php index 4c65698a..e8d8b6f4 100644 --- a/modules/gallery/tests/Cache_Test.php +++ b/modules/gallery/tests/Cache_Test.php @@ -85,26 +85,6 @@ class Cache_Test extends Gallery_Unit_Test_Case { $this->assert_equal(array($id3 => $value3), $data, "Expected id3"); } - public function cache_delete_expired_test() { - $id1 = md5(rand()); - $value1 = array("field1" => "value1", "field2" => "value2"); - $this->_driver->set(array($id1 => $value1), array("tag1", "tag2"), -84600); - - $id2 = md5(rand()); - $value2 = array("field3" => "value3", "field4" => "value4"); - $this->_driver->set(array($id2 => $value2), array("tag2", "tag3"), -846000); - - $id3 = md5(rand()); - $value3 = array("field5" => "value5", "field6" => "value6"); - $this->_driver->set(array($id3 => $value3), array("tag3", "tag4"), -84600); - - $data = $this->_driver->delete_expired(); - - $this->assert_false($this->_driver->exists($id1), "$id1 should have been deleted"); - $this->assert_false($this->_driver->exists($id2), "$id2 should have been deleted"); - $this->assert_false($this->_driver->exists($id3), "$id3 should have been deleted"); - } - public function cache_delete_id_test() { $id1 = md5(rand()); $value1 = array("field1" => "value1", "field2" => "value2"); diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index bd123098..90c54e3c 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -136,20 +136,17 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_true(false, "Shouldn't get here"); } - public function item_rename_fails_with_existing_name_test() { + public function item_rename_over_existing_name_gets_uniqified_test() { // Create a test photo $item = test::random_photo(); $item2 = test::random_photo(); - try { - $item->name = $item2->name; - $item->save(); - } catch (ORM_Validation_Exception $e) { - $this->assert_true(in_array("conflict", $e->validation->errors())); - return; - } + $item->name = $item2->name; + $item->save(); - $this->assert_false(true, "rename should conflict"); + // 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() { @@ -208,24 +205,21 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_equal("file", file_get_contents($photo->file_path())); } - public function move_album_fails_conflicting_target_test() { + public function move_album_with_conflicting_target_gets_uniqified_test() { $album = test::random_album(); $source = test::random_album_unsaved($album); $source->name = $album->name; $source->save(); // $source and $album have the same name, so if we move $source into the root they should - // conflict. + // conflict and get randomized - try { - $source->parent_id = item::root()->id; - $source->save(); - } catch (ORM_Validation_Exception $e) { - $this->assert_equal( - array("name" => "conflict", "slug" => "conflict"), $e->validation->errors()); - return; - } - $this->assert_true(false, "Shouldn't get here"); + $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)); } public function move_album_fails_wrong_target_type_test() { @@ -245,7 +239,7 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_true(false, "Shouldn't get here"); } - public function move_photo_fails_conflicting_target_test() { + public function move_photo_with_conflicting_target_gets_uniqified_test() { $photo1 = test::random_photo(); $album = test::random_album(); $photo2 = test::random_photo_unsaved($album); @@ -253,18 +247,17 @@ 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. + // conflict and get uniqified. - try { - $photo2->parent_id = item::root()->id; - $photo2->save(); - } catch (Exception $e) { - // pass - $this->assert_equal( - array("name" => "conflict", "slug" => "conflict"), $e->validation->errors()); - return; - } - $this->assert_true(false, "Shouldn't get here"); + $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 should become foo + $this->assert_true(preg_match("/{$photo1->slug}/", $photo2->name)); } public function move_album_inside_descendent_fails_test() { diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt index 212577c7..9ea6043a 100644 --- a/modules/gallery/tests/controller_auth_data.txt +++ b/modules/gallery/tests/controller_auth_data.txt @@ -15,7 +15,7 @@ modules/gallery/controllers/login.php html modules/gallery/controllers/login.php auth_html DIRTY_AUTH modules/gallery/controllers/logout.php index DIRTY_AUTH modules/gallery/controllers/quick.php form_edit DIRTY_CSRF -modules/gallery/controllers/upgrader.php index DIRTY_AUTH +modules/gallery/controllers/upgrader.php index DIRTY_CSRF|DIRTY_AUTH modules/gallery/controllers/uploader.php start DIRTY_AUTH modules/gallery/controllers/uploader.php status DIRTY_AUTH modules/gallery/controllers/uploader.php finish DIRTY_AUTH @@ -34,7 +34,7 @@ modules/search/controllers/search.php index modules/server_add/controllers/admin_server_add.php autocomplete DIRTY_CSRF modules/server_add/controllers/server_add.php children DIRTY_CSRF modules/tag/controllers/admin_tags.php index DIRTY_CSRF -modules/tag/controllers/tags.php show DIRTY_CSRF|DIRTY_AUTH +modules/tag/controllers/tag.php __call DIRTY_CSRF|DIRTY_AUTH modules/tag/controllers/tags.php autocomplete DIRTY_CSRF|DIRTY_AUTH modules/user/controllers/password.php reset DIRTY_AUTH modules/user/controllers/password.php do_reset DIRTY_CSRF|DIRTY_AUTH diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 4405dad3..a714b3e5 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -42,7 +42,7 @@ modules/digibug/views/digibug_form.html.php 4 DIRTY form:: modules/digibug/views/digibug_form.html.php 6 DIRTY form::hidden($key,$value) modules/exif/views/exif_dialog.html.php 14 DIRTY $details[$i]["caption"] modules/exif/views/exif_dialog.html.php 21 DIRTY $details[$i]["caption"] -modules/g2_import/views/admin_g2_import.html.php 30 DIRTY $form +modules/g2_import/views/admin_g2_import.html.php 9 DIRTY $form modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY_ATTR text::alternate("g-odd","g-even") modules/gallery/views/admin_advanced_settings.html.php 22 DIRTY $var->module_name modules/gallery/views/admin_block_log_entries.html.php 4 DIRTY_ATTR log::severity_class($entry->severity) @@ -58,9 +58,9 @@ modules/gallery/views/admin_block_photo_stream.html.php 6 DIRTY photo: modules/gallery/views/admin_block_photo_stream.html.php 7 DIRTY_ATTR $photo->thumb_url() modules/gallery/views/admin_dashboard.html.php 5 DIRTY_JS $csrf modules/gallery/views/admin_dashboard.html.php 35 DIRTY $blocks -modules/gallery/views/admin_graphics.html.php 24 DIRTY newView("admin_graphics_none.html") -modules/gallery/views/admin_graphics.html.php 26 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true)) -modules/gallery/views/admin_graphics.html.php 33 DIRTY newView("admin_graphics_$id.html",array("tk"=>$tk->$id,"is_active"=>false)) +modules/gallery/views/admin_graphics.html.php 25 DIRTY newView("admin_graphics_none.html") +modules/gallery/views/admin_graphics.html.php 27 DIRTY newView("admin_graphics_$active.html",array("tk"=>$tk->$active,"is_active"=>true)) +modules/gallery/views/admin_graphics.html.php 34 DIRTY newView("admin_graphics_$id.html",array("tk"=>$tk->$id,"is_active"=>false)) modules/gallery/views/admin_graphics_gd.html.php 2 DIRTY_ATTR $is_active?" g-selected":"" modules/gallery/views/admin_graphics_gd.html.php 2 DIRTY_ATTR $tk->installed?" g-installed-toolkit":" g-unavailable" modules/gallery/views/admin_graphics_gd.html.php 19 DIRTY $tk->error @@ -248,14 +248,15 @@ modules/gallery/views/permissions_form.html.php 80 DIRTY_JS $permi modules/gallery/views/permissions_form.html.php 80 DIRTY_JS $item->id modules/gallery/views/quick_delete_confirm.html.php 11 DIRTY $form modules/gallery/views/reauthenticate.html.php 9 DIRTY $form -modules/gallery/views/upgrader.html.php 59 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 63 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 71 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable" -modules/gallery/views/upgrader.html.php 72 DIRTY_ATTR $id -modules/gallery/views/upgrader.html.php 76 DIRTY $module->version -modules/gallery/views/upgrader.html.php 79 DIRTY $module->code_version -modules/gallery/views/upgrader.html.php 101 DIRTY_ATTR $done?"muted":"" -modules/gallery/views/upgrader.html.php 104 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 76 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 94 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR $module->version==$module->code_version?"current":"upgradeable" +modules/gallery/views/upgrader.html.php 102 DIRTY_ATTR in_array($id,$failed)?"failed":"" +modules/gallery/views/upgrader.html.php 103 DIRTY_ATTR $id +modules/gallery/views/upgrader.html.php 107 DIRTY $module->version +modules/gallery/views/upgrader.html.php 110 DIRTY $module->code_version +modules/gallery/views/upgrader.html.php 120 DIRTY_ATTR $done?"muted":"" +modules/gallery/views/upgrader.html.php 123 DIRTY_ATTR $done?"muted":"" modules/gallery/views/user_languages_block.html.php 2 DIRTY form::dropdown("g-select-session-locale",$installed_locales,$selected) modules/gallery/views/user_profile.html.php 34 DIRTY_ATTR $user->avatar_url(40,$theme->url(,true)) modules/gallery/views/user_profile.html.php 43 DIRTY $info->view @@ -273,19 +274,19 @@ modules/notification/views/item_updated.html.php 20 DIRTY_JS $item- modules/notification/views/item_updated.html.php 20 DIRTY $item->abs_url() modules/notification/views/user_profile_notification.html.php 5 DIRTY_ATTR $subscription->id modules/notification/views/user_profile_notification.html.php 6 DIRTY_JS $subscription->url -modules/organize/views/organize_dialog.html.php 86 DIRTY_JS $domain -modules/organize/views/organize_dialog.html.php 87 DIRTY_JS $access_key -modules/organize/views/organize_dialog.html.php 88 DIRTY_JS request::protocol() -modules/organize/views/organize_dialog.html.php 89 DIRTY_JS $file_filter -modules/organize/views/organize_dialog.html.php 90 DIRTY_JS $sort_order -modules/organize/views/organize_dialog.html.php 91 DIRTY_JS $sort_fields -modules/organize/views/organize_dialog.html.php 92 DIRTY_JS $album->id -modules/organize/views/organize_dialog.html.php 93 DIRTY_JS $selected_id -modules/organize/views/organize_dialog.html.php 94 DIRTY_JS $rest_uri -modules/organize/views/organize_dialog.html.php 95 DIRTY_JS $controller_uri -modules/organize/views/organize_dialog.html.php 101 DIRTY_JS $flash_minimum_version="10.0.0" -modules/organize/views/organize_dialog.html.php 119 DIRTY_JS $swf_uri -modules/organize/views/organize_dialog.html.php 132 DIRTY_ATTR request::protocol() +modules/organize/views/organize_dialog.html.php 94 DIRTY_JS $domain +modules/organize/views/organize_dialog.html.php 95 DIRTY_JS $access_key +modules/organize/views/organize_dialog.html.php 96 DIRTY_JS request::protocol() +modules/organize/views/organize_dialog.html.php 97 DIRTY_JS $file_filter +modules/organize/views/organize_dialog.html.php 98 DIRTY_JS $sort_order +modules/organize/views/organize_dialog.html.php 99 DIRTY_JS $sort_fields +modules/organize/views/organize_dialog.html.php 100 DIRTY_JS $album->id +modules/organize/views/organize_dialog.html.php 101 DIRTY_JS $selected_id +modules/organize/views/organize_dialog.html.php 102 DIRTY_JS $rest_uri +modules/organize/views/organize_dialog.html.php 103 DIRTY_JS $controller_uri +modules/organize/views/organize_dialog.html.php 109 DIRTY_JS $flash_minimum_version="10.0.0" +modules/organize/views/organize_dialog.html.php 127 DIRTY_JS $swf_uri +modules/organize/views/organize_dialog.html.php 140 DIRTY_ATTR request::protocol() modules/recaptcha/views/admin_recaptcha.html.php 11 DIRTY $form modules/recaptcha/views/admin_recaptcha.html.php 23 DIRTY_JS $public_key modules/recaptcha/views/form_recaptcha.html.php 7 DIRTY_JS $public_key @@ -330,23 +331,25 @@ modules/server_add/views/server_add_tree_dialog.html.php 4 DIRTY_JS url::s modules/server_add/views/server_add_tree_dialog.html.php 21 DIRTY $tree modules/tag/views/admin_tags.html.php 45 DIRTY_ATTR $tag->id modules/tag/views/admin_tags.html.php 46 DIRTY $tag->count -modules/tag/views/tag_block.html.php 25 DIRTY $cloud -modules/tag/views/tag_block.html.php 27 DIRTY $form +modules/tag/views/tag_block.html.php 26 DIRTY $cloud +modules/tag/views/tag_block.html.php 28 DIRTY $form modules/tag/views/tag_cloud.html.php 4 DIRTY_ATTR (int)(($tag->count/$max_count)*7) modules/tag/views/tag_cloud.html.php 5 DIRTY $tag->count modules/tag/views/tag_cloud.html.php 6 DIRTY_JS $tag->url() modules/user/views/admin_users.html.php 3 DIRTY_JS url::site("admin/users/add_user_to_group/__USERID__/__GROUPID__?csrf=$csrf") modules/user/views/admin_users.html.php 26 DIRTY_JS url::site("admin/users/group/__GROUPID__") modules/user/views/admin_users.html.php 36 DIRTY_JS url::site("admin/users/remove_user_from_group/__USERID__/__GROUPID__?csrf=$csrf") -modules/user/views/admin_users.html.php 71 DIRTY_ATTR $user->id -modules/user/views/admin_users.html.php 71 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/user/views/admin_users.html.php 71 DIRTY_ATTR $user->admin?"g-admin":"" modules/user/views/admin_users.html.php 72 DIRTY_ATTR $user->id -modules/user/views/admin_users.html.php 73 DIRTY_ATTR $user->avatar_url(20,$theme->url(,true)) -modules/user/views/admin_users.html.php 87 DIRTY ($user->last_login==0)?"":gallery::date($user->last_login) -modules/user/views/admin_users.html.php 123 DIRTY_ATTR $group->id -modules/user/views/admin_users.html.php 123 DIRTY_ATTR ($group->special?"g-default-group":"") -modules/user/views/admin_users.html.php 125 DIRTY $v +modules/user/views/admin_users.html.php 72 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/user/views/admin_users.html.php 72 DIRTY_ATTR $user->admin?"g-admin":"" +modules/user/views/admin_users.html.php 73 DIRTY_ATTR $user->id +modules/user/views/admin_users.html.php 74 DIRTY_ATTR $user->avatar_url(20,$theme->url(,true)) +modules/user/views/admin_users.html.php 88 DIRTY ($user->last_login==0)?"":gallery::date($user->last_login) +modules/user/views/admin_users.html.php 91 DIRTY db::build()->from("items")->where("owner_id","=",$user->id)->count_records() +modules/user/views/admin_users.html.php 127 DIRTY_ATTR $group->id +modules/user/views/admin_users.html.php 127 DIRTY_ATTR ($group->special?"g-default-group":"") +modules/user/views/admin_users.html.php 129 DIRTY $v +modules/user/views/admin_users_delete_user.html.php 6 DIRTY $form modules/user/views/admin_users_group.html.php 24 DIRTY_JS $user->id modules/user/views/admin_users_group.html.php 24 DIRTY_JS $group->id modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $width diff --git a/modules/gallery/views/admin_block_platform.html.php b/modules/gallery/views/admin_block_platform.html.php index b1b8a2f9..379ab0aa 100644 --- a/modules/gallery/views/admin_block_platform.html.php +++ b/modules/gallery/views/admin_block_platform.html.php @@ -18,4 +18,7 @@ <li> <?= t("Server load: %load_average", array("load_average" => $load_average)) ?> </li> + <li> + <?= t("Graphics toolkit: %toolkit", array("toolkit" => module::get_var("gallery", "graphics_toolkit"))) ?> + </li> </ul> diff --git a/modules/gallery/views/admin_graphics.html.php b/modules/gallery/views/admin_graphics.html.php index 3a48e087..ae76f1e1 100644 --- a/modules/gallery/views/admin_graphics.html.php +++ b/modules/gallery/views/admin_graphics.html.php @@ -16,6 +16,7 @@ <h1> <?= t("Graphics settings") ?> </h1> <p> <?= t("Gallery needs a graphics toolkit in order to manipulate your photos. Please choose one from the list below.") ?> + <?= t("Can't decide which toolkit to choose? <a href=\"%url\">We can help!</a>", array("url" => "http://codex.gallery2.org/Gallery3:Choosing_A_Graphics_Toolkit")) ?> </p> <div class="g-block-content"> diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php index 0ce24ef8..1ec49c77 100644 --- a/modules/gallery/views/upgrader.html.php +++ b/modules/gallery/views/upgrader.html.php @@ -10,7 +10,7 @@ </head> <body<? if (locales::is_rtl()) { echo ' class="rtl"'; } ?>> <div id="outer"> - <img src="<?= url::file("modules/gallery/images/gallery.png") ?>" /> + <img id="logo" src="<?= url::file("modules/gallery/images/gallery.png") ?>" /> <div id="inner"> <? if ($can_upgrade): ?> <div id="dialog" style="visibility: hidden"> @@ -31,6 +31,12 @@ array("url" => html::mark_clean(url::base()))) ?> </p> </div> + <div id="failed" style="display: none"> + <h1> <?= t("Some modules failed to upgrade!") ?> </h1> + <p> + <?= t("Failed modules are <span class=\"failed\">highlighted</span>. Try getting newer versions or <a href=\"%admin_modules\">deactivating those modules</a>.", array("admin_modules" => url::site("admin/modules"))) ?> + </p> + </div> </div> <script type="text/javascript"> $(document).ready(function() { @@ -41,6 +47,10 @@ <? if ($done): ?> show_done(); <? endif ?> + + <? if ($failed): ?> + show_failed(); + <? endif ?> }); var show_busy = function() { @@ -55,10 +65,31 @@ $("#done").show(); $("#dialog_close_link").show(); } + + var show_failed = function() { + $("#dialog").css("visibility", "visible"); + $("#failed").show(); + $("#dialog_close_link").show(); + } </script> - <p class="<?= $done ? "muted" : "" ?>"> - <?= t("Welcome to the Gallery upgrader. One click and you're done!") ?> - </p> + <div id="welcome_message"> + <p class="<?= $done ? "muted" : "" ?>"> + <?= t("Welcome to the Gallery upgrader. One click and you're done!") ?> + </p> + </div> + + <? if ($done): ?> + <div id="upgrade_button" class="button muted"> + <?= t("Upgrade all") ?> + </div> + <? else: ?> + <div id="upgrade_button" class="button button-active"> + <a id="upgrade_link" href="<?= url::site("upgrader/upgrade?csrf=" . access::csrf_token()) ?>"> + <?= t("Upgrade all") ?> + </a> + </div> + <? endif ?> + <table> <tr class="<?= $done ? "muted" : "" ?>"> <th class="name"> <?= t("Module name") ?> </th> @@ -68,7 +99,7 @@ <? foreach ($available as $id => $module): ?> <? if ($module->active): ?> - <tr class="<?= $module->version == $module->code_version ? "current" : "upgradeable" ?>" > + <tr class="<?= $module->version == $module->code_version ? "current" : "upgradeable" ?> <?= in_array($id, $failed) ? "failed" : "" ?>" > <td class="name <?= $id ?>"> <?= t($module->name) ?> </td> @@ -85,18 +116,6 @@ <? endforeach ?> </table> - <? if ($done): ?> - <div class="button muted"> - <?= t("Upgrade all") ?> - </div> - <? else: ?> - <div class="button button-active"> - <a id="upgrade_link" href="<?= url::site("upgrader/upgrade") ?>"> - <?= t("Upgrade all") ?> - </a> - </div> - <? endif ?> - <? if (@$inactive): ?> <p class="<?= $done ? "muted" : "" ?>"> <?= t("The following modules are inactive and don't require an upgrade.") ?> diff --git a/modules/notification/helpers/notification_installer.php b/modules/notification/helpers/notification_installer.php index 78f72194..2ba25298 100644 --- a/modules/notification/helpers/notification_installer.php +++ b/modules/notification/helpers/notification_installer.php @@ -30,13 +30,14 @@ class notification_installer { DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE IF NOT EXISTS {pending_notifications} ( `id` int(9) NOT NULL auto_increment, + `locale` char(10) default NULL, `email` varchar(128) NOT NULL, `subject` varchar(255) NOT NULL, `text` text, PRIMARY KEY (`id`)) DEFAULT CHARSET=utf8;"); - module::set_version("notification", 1); + module::set_version("notification", 2); } static function upgrade($version) { diff --git a/modules/organize/lib/Gallery3WebClient.swf b/modules/organize/lib/Gallery3WebClient.swf Binary files differindex b82c8a42..356a1a2f 100644 --- a/modules/organize/lib/Gallery3WebClient.swf +++ b/modules/organize/lib/Gallery3WebClient.swf diff --git a/modules/organize/views/organize_dialog.html.php b/modules/organize/views/organize_dialog.html.php index b76813ad..3ea1143d 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -19,13 +19,21 @@ <script type="text/javascript"> $("#g-dialog").bind("dialogclose", function(event, ui) { // @todo do a call to organize/closing to end the batch - window.location.reload(); + if ($(this).data("reload.location")) { + window.location = $(this).data("reload.location"); + } else { + window.location.reload(); + } }); function closeOrganizeDialog() { $("#g-dialog").dialog("close"); } + function setLocation(url) { + $("#g-dialog").data("reload.location", url); + } + function setTitle(title) { $("#ui-dialog-title-g-dialog").text(<?= t("Organize :: ")->for_js() ?> + title); } diff --git a/modules/rest/views/error_rest.json.php b/modules/rest/views/error_rest.json.php index 179ce7f9..8c99ef45 100644 --- a/modules/rest/views/error_rest.json.php +++ b/modules/rest/views/error_rest.json.php @@ -1,2 +1,6 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> +<? +// Log error response to ease debugging +Kohana_Log::add("error", "Rest error details: " . print_r($e->response, 1)); +?> <?= json_encode($e->response);
\ No newline at end of file diff --git a/modules/search/helpers/search_task.php b/modules/search/helpers/search_task.php index 08f75d66..48a6688b 100644 --- a/modules/search/helpers/search_task.php +++ b/modules/search/helpers/search_task.php @@ -47,7 +47,7 @@ class search_task_Core { ->join("search_records", "items.id", "search_records.item_id", "left") ->where("search_records.item_id", "IS", null) ->or_where("search_records.dirty", "=", 1) - ->find_all() as $item) { + ->find_all(100) as $item) { // The query above can take a long time, so start the timer after its done // to give ourselves a little time to actually process rows. if (!isset($start)) { @@ -57,7 +57,7 @@ class search_task_Core { search::update($item); $completed++; - if (microtime(true) - $start > 1.5) { + if (microtime(true) - $start > .75) { break; } } diff --git a/modules/tag/controllers/tag.php b/modules/tag/controllers/tag.php new file mode 100644 index 00000000..0e924f3d --- /dev/null +++ b/modules/tag/controllers/tag.php @@ -0,0 +1,49 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2010 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class Tag_Controller extends Controller { + public function __call($function, $args) { + $tag_name = $function; + $tag = ORM::factory("tag")->where("name", "=", $tag_name)->find(); + $page_size = module::get_var("gallery", "page_size", 9); + $page = (int) Input::instance()->get("page", "1"); + $children_count = $tag->items_count(); + $offset = ($page-1) * $page_size; + $max_pages = max(ceil($children_count / $page_size), 1); + + // Make sure that the page references a valid offset + if ($page < 1) { + url::redirect($album->abs_url()); + } else if ($page > $max_pages) { + url::redirect($album->abs_url("page=$max_pages")); + } + + $template = new Theme_View("page.html", "collection", "tag"); + $template->set_global("page", $page); + $template->set_global("max_pages", $max_pages); + $template->set_global("page_size", $page_size); + $template->set_global("tag", $tag); + $template->set_global("children", $tag->items($page_size, $offset)); + $template->set_global("children_count", $children_count); + $template->content = new View("dynamic.html"); + $template->content->title = t("Tag: %tag_name", array("tag_name" => $tag->name)); + + print $template; + } +} diff --git a/modules/tag/controllers/tags.php b/modules/tag/controllers/tags.php index bc657644..aa39b6cd 100644 --- a/modules/tag/controllers/tags.php +++ b/modules/tag/controllers/tags.php @@ -18,34 +18,6 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class Tags_Controller extends Controller { - public function show($tag_id) { - $tag = ORM::factory("tag", $tag_id); - $page_size = module::get_var("gallery", "page_size", 9); - $page = (int) Input::instance()->get("page", "1"); - $children_count = $tag->items_count(); - $offset = ($page-1) * $page_size; - $max_pages = max(ceil($children_count / $page_size), 1); - - // Make sure that the page references a valid offset - if ($page < 1) { - url::redirect($album->abs_url()); - } else if ($page > $max_pages) { - url::redirect($album->abs_url("page=$max_pages")); - } - - $template = new Theme_View("page.html", "collection", "tag"); - $template->set_global("page", $page); - $template->set_global("max_pages", $max_pages); - $template->set_global("page_size", $page_size); - $template->set_global("tag", $tag); - $template->set_global("children", $tag->items($page_size, $offset)); - $template->set_global("children_count", $children_count); - $template->content = new View("dynamic.html"); - $template->content->title = t("Tag: %tag_name", array("tag_name" => $tag->name)); - - print $template; - } - public function index() { // Far from perfection, but at least require view permission for the root album $album = ORM::factory("item", 1); diff --git a/modules/tag/css/tag.css b/modules/tag/css/tag.css index 6d6438e3..8a64960a 100644 --- a/modules/tag/css/tag.css +++ b/modules/tag/css/tag.css @@ -19,6 +19,12 @@ display: none; } +#g-tag-cloud ul li.size0 a { + color: #9cf; + font-size: 70%; + font-weight: 100; +} + #g-tag-cloud ul li.size1 a { color: #9cf; font-size: 80%; diff --git a/modules/tag/models/tag.php b/modules/tag/models/tag.php index e8bd69c5..269a0f39 100644 --- a/modules/tag/models/tag.php +++ b/modules/tag/models/tag.php @@ -124,7 +124,7 @@ class Tag_Model extends ORM { * @param string $query the query string (eg "page=3") */ public function url($query=null) { - $url = url::site("tags/show/$this->id"); + $url = url::site("tag/{$this->name}"); if ($query) { $url .= "?$query"; } diff --git a/modules/tag/views/tag_block.html.php b/modules/tag/views/tag_block.html.php index 8b887282..cc204c72 100644 --- a/modules/tag/views/tag_block.html.php +++ b/modules/tag/views/tag_block.html.php @@ -7,7 +7,8 @@ max: 30, multiple: true, multipleSeparator: ',', - cacheLength: 1 + cacheLength: 1, + selectFirst: false, } ); $("#g-add-tag-form").ajaxForm({ @@ -24,4 +25,4 @@ <div id="g-tag-cloud" ref="<?= url::site("tags") ?>"> <?= $cloud ?> </div> -<?= $form ?>
\ No newline at end of file +<?= $form ?> diff --git a/modules/user/controllers/admin_users.php b/modules/user/controllers/admin_users.php index 24478aa5..c22fcc2e 100644 --- a/modules/user/controllers/admin_users.php +++ b/modules/user/controllers/admin_users.php @@ -95,7 +95,10 @@ class Admin_Users_Controller extends Admin_Controller { if (empty($user)) { throw new Kohana_404_Exception(); } - print $this->_get_user_delete_form_admin($user); + $v = new View("admin_users_delete_user.html"); + $v->user = $user; + $v->form = $this->_get_user_delete_form_admin($user); + print $v; } public function edit_user($id) { @@ -364,8 +367,8 @@ class Admin_Users_Controller extends Admin_Controller { $form = new Forge("admin/users/delete_user/$user->id", "", "post", array("id" => "g-delete-user-form")); $group = $form->group("delete_user")->label( - t("Are you sure you want to delete user %name?", array("name" => $user->name))); - $group->submit("")->value(t("Delete user %name", array("name" => $user->name))); + t("Delete user %name?", array("name" => $user->display_name()))); + $group->submit("")->value(t("Delete")); return $form; } diff --git a/modules/user/helpers/user.php b/modules/user/helpers/user.php index 55153263..be50d6d1 100644 --- a/modules/user/helpers/user.php +++ b/modules/user/helpers/user.php @@ -36,6 +36,20 @@ class user_Core { } /** + * Return an admin user. Prefer the currently logged in user, if possible. + * + * @return User_Model + */ + static function admin_user() { + $active = identity::active_user(); + if ($active->admin) { + return $active; + } + + return ORM::factory("user")->where("admin", "=", 1)->order_by("id", "ASC")->find(); + } + + /** * Is the password provided correct? * * @param user User Model diff --git a/modules/user/libraries/drivers/IdentityProvider/Gallery.php b/modules/user/libraries/drivers/IdentityProvider/Gallery.php index 44433ad7..73ac9bd0 100644 --- a/modules/user/libraries/drivers/IdentityProvider/Gallery.php +++ b/modules/user/libraries/drivers/IdentityProvider/Gallery.php @@ -32,7 +32,7 @@ class IdentityProvider_Gallery_Driver implements IdentityProvider_Driver { * @see IdentityProvider_Driver::guest. */ public function admin_user() { - return self::lookup_user(2); + return user::admin_user(); } /** diff --git a/modules/user/models/user.php b/modules/user/models/user.php index 78d74aa3..b28288be 100644 --- a/modules/user/models/user.php +++ b/modules/user/models/user.php @@ -88,6 +88,10 @@ class User_Model extends ORM implements User_Definition { * @return ORM User_Model */ public function save() { + if ($this->full_name === null) { + $this->full_name = ""; + } + if (!$this->loaded()) { // New user $this->add(group::everybody()); diff --git a/modules/user/views/admin_users.html.php b/modules/user/views/admin_users.html.php index b2526bd8..f067cae8 100644 --- a/modules/user/views/admin_users.html.php +++ b/modules/user/views/admin_users.html.php @@ -64,6 +64,7 @@ <th><?= t("Full name") ?></th> <th><?= t("Email") ?></th> <th><?= t("Last login") ?></th> + <th><?= t("Albums/Photos") ?></th> <th><?= t("Actions") ?></th> </tr> @@ -87,6 +88,9 @@ <?= ($user->last_login == 0) ? "" : gallery::date($user->last_login) ?> </td> <td> + <?= db::build()->from("items")->where("owner_id", "=", $user->id)->count_records() ?> + </td> + <td> <a href="<?= url::site("admin/users/edit_user_form/$user->id") ?>" open_text="<?= t("Close") ?>" class="g-panel-link g-button ui-state-default ui-corner-all ui-icon-left"> diff --git a/modules/user/views/admin_users_delete_user.html.php b/modules/user/views/admin_users_delete_user.html.php new file mode 100644 index 00000000..44777ae5 --- /dev/null +++ b/modules/user/views/admin_users_delete_user.html.php @@ -0,0 +1,7 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<div id="g-admin-users-delete-user"> + <p> + <?= t("Really delete <b>%name</b>? Any photos, movies or albums owned by this user will transfer ownership to <b>%new_owner</b>.", array("name" => $user->display_name(), "new_owner" => identity::active_user()->display_name())) ?> + </p> + <?= $form ?> +</div> diff --git a/themes/admin_wind/css/screen.css b/themes/admin_wind/css/screen.css index eda79b97..0d891149 100644 --- a/themes/admin_wind/css/screen.css +++ b/themes/admin_wind/css/screen.css @@ -222,6 +222,11 @@ th { background-color: #fff; } +ul.enumeration li { + list-style-type: disc; + margin-left: 20px; +} + /*** ****************************************************************** * 3) Page layout containers *********************************************************************/ diff --git a/themes/wind/js/ui.init.js b/themes/wind/js/ui.init.js index a4fc0e2f..2c67bf3a 100644 --- a/themes/wind/js/ui.init.js +++ b/themes/wind/js/ui.init.js @@ -90,9 +90,18 @@ $(document).ready(function() { $(this).css("top", 0).css("left", 0); // Remove the placeholder and hover class from the item $(this).removeClass("g-hover-item"); + $(this).gallery_valign(); $("#g-place-holder").remove(); } ); + + // Realign any thumbnails that change so that when we rotate a thumb it stays centered. + $(".g-item").bind("gallery.change", function() { + $(".g-item").each(function() { + $(this).height($(this).find("img").height() + 2); + }); + $(".g-item").equal_heights().gallery_valign(); + }); } // Photo/Item item view diff --git a/themes/wind/views/photo.html.php b/themes/wind/views/photo.html.php index cb830e23..b42ab987 100644 --- a/themes/wind/views/photo.html.php +++ b/themes/wind/views/photo.html.php @@ -12,7 +12,7 @@ // After the image is rotated or replaced we have to reload the image dimensions // so that the full size view isn't distorted. - gallery_image_replaced_hook = function(data, thumb) { + $("#g-photo").bind("gallery.change", function() { $.ajax({ url: "<?= url::site("items/dimensions/" . $theme->item()->id) ?>", dataType: "json", @@ -20,7 +20,7 @@ full_dims = data.full; } }); - } + }); }); </script> <? endif ?> |