diff options
author | mamouneyya <mamoun.diraneyya@gmail.com> | 2010-08-31 18:04:21 +0300 |
---|---|---|
committer | mamouneyya <mamoun.diraneyya@gmail.com> | 2010-08-31 18:04:21 +0300 |
commit | 0b6664e8f9d19df025739bc4a0cf1821563d6b3d (patch) | |
tree | 5b1de2331d4a9d0eb8d97bbb74be6d794d6260a1 /modules | |
parent | 0a128bab0a788288c5291491a68bd1c9ab432825 (diff) | |
parent | 23d59dec7240dfa4bffe9d88f46a848e76ce0134 (diff) |
Merge remote branch 'gallery3/master'
Diffstat (limited to 'modules')
83 files changed, 1099 insertions, 768 deletions
diff --git a/modules/comment/controllers/admin_manage_comments.php b/modules/comment/controllers/admin_manage_comments.php index e451791f..0889dc4e 100644 --- a/modules/comment/controllers/admin_manage_comments.php +++ b/modules/comment/controllers/admin_manage_comments.php @@ -35,9 +35,9 @@ class Admin_Manage_Comments_Controller extends Admin_Controller { public function menu_labels() { $menu = $this->_menu($this->_counts()); json::reply(array((string) $menu->get("unpublished")->label, - (string) $menu->get("published")->label, - (string) $menu->get("spam")->label, - (string) $menu->get("deleted")->label)); + (string) $menu->get("published")->label, + (string) $menu->get("spam")->label, + (string) $menu->get("deleted")->label)); } public function queue($state) { @@ -51,8 +51,10 @@ class Admin_Manage_Comments_Controller extends Admin_Controller { $view->content->state = $state; $view->content->comments = ORM::factory("comment") ->order_by("created", "DESC") + ->order_by("id", "DESC") ->where("state", "=", $state) - ->limit(self::$items_per_page, ($page - 1) * self::$items_per_page) + ->limit(self::$items_per_page) + ->offset(($page - 1) * self::$items_per_page) ->find_all(); $view->content->pager = new Pagination(); $view->content->pager->initialize( diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php index 6ec4132b..ff0e9ce1 100644 --- a/modules/comment/controllers/comments.php +++ b/modules/comment/controllers/comments.php @@ -57,8 +57,8 @@ class Comments_Controller extends Controller { $view->comment = $comment; json::reply(array("result" => "success", - "view" => (string)$view, - "form" => (string)comment::get_add_form($item))); + "view" => (string)$view, + "form" => (string)comment::get_add_form($item))); } else { $form = comment::prefill_add_form($form); json::reply(array("result" => "error", "form" => (string)$form)); diff --git a/modules/comment/helpers/comment.php b/modules/comment/helpers/comment.php index 92a286c7..7aa007cb 100644 --- a/modules/comment/helpers/comment.php +++ b/modules/comment/helpers/comment.php @@ -45,6 +45,7 @@ class comment_Core { ->error_messages("required", t("You must enter a comment")); $group->hidden("item_id")->value($item->id); module::event("comment_add_form", $form); + module::event("captcha_protect_form", $form); $group->submit("")->value(t("Add"))->class("ui-state-default ui-corner-all"); return $form; diff --git a/modules/comment/views/comments.html.php b/modules/comment/views/comments.html.php index da45f57b..b524f5da 100644 --- a/modules/comment/views/comments.html.php +++ b/modules/comment/views/comments.html.php @@ -36,11 +36,11 @@ </a> <? if ($comment->author()->guest): ?> <?= t('on %date %name said', - array("date" => date("Y-M-d H:i:s", $comment->created), - "name" => html::clean($comment->author_name()))); ?> + array("date" => gallery::date_time($comment->created), + "name" => html::clean($comment->author_name()))); ?> <? else: ?> <?= t('on %date <a href="%url">%name</a> said', - array("date" => date("Y-M-d H:i:s", $comment->created), + array("date" => gallery::date_time($comment->created), "url" => user_profile::url($comment->author_id), "name" => html::clean($comment->author_name()))); ?> <? endif ?> diff --git a/modules/comment/views/user_profile_comments.html.php b/modules/comment/views/user_profile_comments.html.php index a2a641ba..377b2d95 100644 --- a/modules/comment/views/user_profile_comments.html.php +++ b/modules/comment/views/user_profile_comments.html.php @@ -4,8 +4,8 @@ <? foreach ($comments as $comment): ?> <li id="g-comment-<?= $comment->id ?>"> <p class="g-author"> - <?= t('on %date for %title ', - array("date" => date("Y-M-d H:i:s", $comment->created), + <?= t("on %date for %title ", + array("date" => gallery::date_time($comment->created), "title" => $comment->item()->title)); ?> <a href="<?= $comment->item()->url() ?>"> <?= $comment->item()->thumb_img(array(), 50) ?> diff --git a/modules/g2_import/controllers/g2.php b/modules/g2_import/controllers/g2.php index 2c6ad1b4..d260c9b4 100644 --- a/modules/g2_import/controllers/g2.php +++ b/modules/g2_import/controllers/g2.php @@ -35,12 +35,9 @@ class G2_Controller extends Controller { $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. + // 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) { diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index 4aa9e642..c3737f8f 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -178,7 +178,17 @@ class g2_import_Core { "module", "rewrite", "modrewrite.embeddedLocation", $g2_embed_location)); g2($gallery->getStorage()->checkPoint()); } - self::$g2_base_url = $g2_embed_location; + + if ($g2_embed_location) { + self::$g2_base_url = $g2_embed_location; + } else { + self::$g2_base_url = $GLOBALS["gallery"]->getUrlGenerator()->generateUrl( + array(), + array("forceSessionId" => false, + "htmlEntities" => false, + "urlEncode" => false, + "useAuthToken" => false)); + } return true; } @@ -442,6 +452,7 @@ class g2_import_Core { "title" => "title", "viewCount" => "view_count"); $direction_map = array( + 1 => "asc", ORDER_ASCENDING => "asc", ORDER_DESCENDING => "desc"); // Only consider G2's first sort order @@ -587,6 +598,20 @@ class g2_import_Core { $item->description = self::_decode_html_special_chars(self::extract_description($g2_item)); $item->owner_id = self::map($g2_item->getOwnerId()); $item->save(); + + // If the item has a preferred derivative with a rotation, then rotate this image + // accordingly. Should we obey scale rules as well? I vote no because rotation is less + // destructive -- you lose too much data from scaling. + $g2_preferred = g2(GalleryCoreApi::fetchPreferredSource($g2_item)); + if ($g2_preferred && $g2_preferred instanceof GalleryDerivative) { + if (preg_match("/rotate\|(-?\d+)/", $g2_preferred->getDerivativeOperations(), $matches)) { + $tmpfile = tempnam(TMPPATH, "rotate"); + gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $matches[1])); + $item->set_data_file($tmpfile); + $item->save(); + unlink($tmpfile); + } + } } catch (Exception $e) { $exception_info = (string) new G2_Import_Exception( t("Corrupt image '%path'", array("path" => $g2_path)), @@ -674,8 +699,7 @@ class g2_import_Core { $title = $g2_item->getTitle(); $title or $title = $g2_item->getPathComponent(); $messages[] = - t("<a href=\"%g2_url\">%title</a> from Gallery 2 could not be processed; " . - "(imported as <a href=\"%g3_url\">%title</a>)", + t("<a href=\"%g2_url\">%title</a> from Gallery 2 could not be processed; (imported as <a href=\"%g3_url\">%title</a>)", array("g2_url" => $g2_item_url, "g3_url" => $item->url(), "title" => $title)); @@ -831,17 +855,18 @@ class g2_import_Core { array("id" => $g2_comment_id, "exception" => (string)$e)); } + if (self::map($g2_comment->getId())) { + // Already imported + return; + } + $item_id = self::map($g2_comment->getParentId()); if (empty($item_id)) { // Item was not mapped. return; } - $text = $g2_comment->getSubject(); - if ($text) { - $text .= " "; - } - $text .= $g2_comment->getComment(); + $text = join("\n", array($g2_comment->getSubject(), $g2_comment->getComment())); $text = html_entity_decode($text); // Just import the fields we know about. Do this outside of the comment API for now so that @@ -858,7 +883,6 @@ class g2_import_Core { $comment->text = self::_transform_bbcode($text); $comment->state = "published"; $comment->server_http_host = $g2_comment->getHost(); - $comment->created = $g2_comment->getDate(); try { $comment->save(); } catch (Exception $e) { @@ -867,6 +891,16 @@ class g2_import_Core { array("id" => $g2_comment_id)), $e); } + + self::set_map($g2_comment->getId(), $comment->id, "comment"); + + // Backdate the creation date. We can't do this at creation time because + // Comment_Model::save() will override it. + db::update("comments") + ->set("created", $g2_comment->getDate()) + ->set("updated", $g2_comment->getDate()) + ->where("id", "=", $comment->id) + ->execute(); } /** diff --git a/modules/gallery/config/cookie.php b/modules/gallery/config/cookie.php index ded3bdaa..7f6ea265 100644 --- a/modules/gallery/config/cookie.php +++ b/modules/gallery/config/cookie.php @@ -37,10 +37,9 @@ $config['path'] = '/'; $config['expire'] = 0; /** - * Enable this option to only allow the cookie to be read when using the a - * secure protocol. + * Set the secure bit on the cookie if we're using HTTPS. */ -$config['secure'] = false; +$config['secure'] = !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on'; /** * Enable this option to disable the cookie from being accessed when using a diff --git a/modules/gallery/controllers/admin_maintenance.php b/modules/gallery/controllers/admin_maintenance.php index 3567b4f0..a9cc933c 100644 --- a/modules/gallery/controllers/admin_maintenance.php +++ b/modules/gallery/controllers/admin_maintenance.php @@ -226,4 +226,10 @@ class Admin_Maintenance_Controller extends Admin_Controller { "done" => (bool) $task->done))); } } + + public function maintenance_mode($value) { + access::verify_csrf(); + module::set_var("gallery", "maintenance_mode", $value); + url::redirect("admin/maintenance"); + } } diff --git a/modules/gallery/controllers/admin_theme_options.php b/modules/gallery/controllers/admin_theme_options.php index 15a42ee5..57f32f96 100644 --- a/modules/gallery/controllers/admin_theme_options.php +++ b/modules/gallery/controllers/admin_theme_options.php @@ -22,14 +22,14 @@ class Admin_Theme_Options_Controller extends Admin_Controller { $view = new Admin_View("admin.html"); $view->page_title = t("Theme options"); $view->content = new View("admin_theme_options.html"); - $view->content->form = theme::get_edit_form_admin(); + $view->content->form = $this->_get_edit_form_admin(); print $view; } public function save() { access::verify_csrf(); - $form = theme::get_edit_form_admin(); + $form = $this->_get_edit_form_admin(); if ($form->validate()) { module::set_var("gallery", "page_size", $form->edit_theme->page_size->value); @@ -58,6 +58,7 @@ class Admin_Theme_Options_Controller extends Admin_Controller { module::set_var("gallery", "header_text", $form->edit_theme->header_text->value); module::set_var("gallery", "footer_text", $form->edit_theme->footer_text->value); module::set_var("gallery", "show_credits", $form->edit_theme->show_credits->value); + module::set_var("gallery", "favicon_url", $form->edit_theme->favicon_url->value); module::event("theme_edit_form_completed", $form); @@ -70,5 +71,40 @@ class Admin_Theme_Options_Controller extends Admin_Controller { print $view; } } + + private 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->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")) + ->error_messages("valid_digit", t("You must enter a number")) + ->value(module::get_var("gallery", "page_size")); + $group->input("thumb_size")->label(t("Thumbnail size (in pixels)"))->id("g-thumb-size") + ->rules("required|valid_digit") + ->error_messages("required", t("You must enter a number")) + ->error_messages("valid_digit", t("You must enter a number")) + ->value(module::get_var("gallery", "thumb_size")); + $group->input("resize_size")->label(t("Resized image size (in pixels)"))->id("g-resize-size") + ->rules("required|valid_digit") + ->error_messages("required", t("You must enter a number")) + ->error_messages("valid_digit", t("You must enter a number")) + ->value(module::get_var("gallery", "resize_size")); + $group->input("favicon_url")->label(t("URL (or relative path) to your favicon.ico")) + ->id("g-favicon") + ->value(module::get_var("gallery", "favicon_url")); + $group->textarea("header_text")->label(t("Header text"))->id("g-header-text") + ->value(module::get_var("gallery", "header_text")); + $group->textarea("footer_text")->label(t("Footer text"))->id("g-footer-text") + ->value(module::get_var("gallery", "footer_text")); + $group->checkbox("show_credits")->label(t("Show site credits"))->id("g-footer-text") + ->checked(module::get_var("gallery", "show_credits")); + + module::event("theme_edit_form", $form); + + $group = $form->group("buttons"); + $group->submit("")->value(t("Save")); + return $form; + } } diff --git a/modules/gallery/controllers/admin_themes.php b/modules/gallery/controllers/admin_themes.php index e59eadaf..a88e1e89 100644 --- a/modules/gallery/controllers/admin_themes.php +++ b/modules/gallery/controllers/admin_themes.php @@ -31,10 +31,11 @@ class Admin_Themes_Controller extends Admin_Controller { private function _get_themes() { $themes = array(); foreach (scandir(THEMEPATH) as $theme_name) { + if ($theme_name[0] == ".") { + continue; + } + $theme_name = preg_replace("/[^a-zA-Z0-9\._-]/", "", $theme_name); if (file_exists(THEMEPATH . "$theme_name/theme.info")) { - if ($theme_name[0] == ".") { - continue; - } $themes[$theme_name] = theme::get_info($theme_name); } diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php index f3f5dee3..b0887195 100644 --- a/modules/gallery/controllers/albums.php +++ b/modules/gallery/controllers/albums.php @@ -68,7 +68,7 @@ class Albums_Controller extends Items_Controller { $template->set_global("item", $album); $template->set_global("children", $album->viewable()->children($page_size, $offset)); $template->set_global("children_count", $children_count); - $template->set_global("parents", $album->parents()); + $template->set_global("parents", $album->parents()->as_array()); // view calls empty() on this $template->content = new View("album.html"); // We can't use math in ORM or the query builder, so do this by hand. It's important @@ -132,7 +132,9 @@ class Albums_Controller extends Items_Controller { $album->description = $form->edit_item->description->value; $album->sort_column = $form->edit_item->sort_order->column->value; $album->sort_order = $form->edit_item->sort_order->direction->value; - $album->name = $form->edit_item->inputs["name"]->value; + if (array_key_exists("name", $form->edit_item->inputs)) { + $album->name = $form->edit_item->inputs["name"]->value; + } $album->slug = $form->edit_item->slug->value; $album->validate(); } catch (ORM_Validation_Exception $e) { diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php index 15b4279f..b17310c4 100644 --- a/modules/gallery/controllers/file_proxy.php +++ b/modules/gallery/controllers/file_proxy.php @@ -116,6 +116,8 @@ class File_Proxy_Controller extends Controller { throw new Kohana_404_Exception(); } + header("Content-Length: " . filesize($file)); + header("Pragma:"); // Check that the content hasn't expired or it wasn't changed since cached expires::check(2592000, $item->updated); @@ -127,7 +129,7 @@ class File_Proxy_Controller extends Controller { // Dump out the image. If the item is a movie, then its thumbnail will be a JPG. if ($item->is_movie() && $type != "albums") { - header("Content-type: image/jpeg"); + header("Content-Type: image/jpeg"); } else { header("Content-Type: $item->mime_type"); } diff --git a/modules/gallery/controllers/move.php b/modules/gallery/controllers/move.php deleted file mode 100644 index 7b2d6165..00000000 --- a/modules/gallery/controllers/move.php +++ /dev/null @@ -1,71 +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 Move_Controller extends Controller { - public function browse($source_id) { - $source = ORM::factory("item", $source_id); - access::required("view", $source); - access::required("edit", $source); - - $view = new View("move_browse.html"); - $view->source = $source; - $view->tree = $this->_get_tree_html($source, ORM::factory("item", 1)); - print $view; - } - - public function save($source_id) { - access::verify_csrf(); - $source = ORM::factory("item", $source_id); - $target = ORM::factory("item", Input::instance()->post("target_id")); - - access::required("view", $source); - access::required("edit", $source); - access::required("view", $target); - access::required("edit", $target); - - item::move($source, $target); - - json::reply(array("result" => "success", "location" => $target->url())); - } - - public function show_sub_tree($source_id, $target_id) { - $source = ORM::factory("item", $source_id); - $target = ORM::factory("item", $target_id); - access::required("view", $source); - access::required("edit", $source); - access::required("view", $target); - // show targets even if they're not editable because they may contain children which *are* - // editable - - print $this->_get_tree_html($source, $target); - } - - private function _get_tree_html($source, $target) { - $view = new View("move_tree.html"); - $view->source = $source; - $view->parent = $target; - $view->children = ORM::factory("item") - ->viewable() - ->where("type", "=", "album") - ->where("parent_id", "=", $target->id) - ->find_all(); - return $view; - } - -} diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php index 02d2a497..717eb8aa 100644 --- a/modules/gallery/controllers/movies.php +++ b/modules/gallery/controllers/movies.php @@ -41,7 +41,7 @@ class Movies_Controller extends Items_Controller { $template->set_global("item", $movie); $template->set_global("children", array()); $template->set_global("children_count", 0); - $template->set_global("parents", $movie->parents()); + $template->set_global("parents", $movie->parents()->as_array()); $template->set_global("next_item", $next_item); $template->set_global("previous_item", $previous_item); $template->set_global("sibling_count", $movie->parent()->viewable()->children_count($where)); diff --git a/modules/gallery/controllers/packager.php b/modules/gallery/controllers/packager.php index 835cb903..f463d0de 100644 --- a/modules/gallery/controllers/packager.php +++ b/modules/gallery/controllers/packager.php @@ -59,11 +59,7 @@ class Packager_Controller extends Controller { // numbers, keeping our install.sql file more stable. srand(0); - gallery_installer::install(true); - - module::load_modules(); - - foreach (array("user", "comment", "organize", "info", "rest", + foreach (array("gallery", "user", "comment", "organize", "info", "rest", "rss", "search", "slideshow", "tag") as $module_name) { module::install($module_name); module::activate($module_name); diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php index 8377e6c7..b22ac8e5 100644 --- a/modules/gallery/controllers/photos.php +++ b/modules/gallery/controllers/photos.php @@ -41,7 +41,7 @@ class Photos_Controller extends Items_Controller { $template->set_global("item", $photo); $template->set_global("children", array()); $template->set_global("children_count", 0); - $template->set_global("parents", $photo->parents()); + $template->set_global("parents", $photo->parents()->as_array()); $template->set_global("next_item", $next_item); $template->set_global("previous_item", $previous_item); $template->set_global("sibling_count", $photo->parent()->viewable()->children_count($where)); diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php index fee601d9..c34209da 100644 --- a/modules/gallery/controllers/quick.php +++ b/modules/gallery/controllers/quick.php @@ -36,25 +36,11 @@ class Quick_Controller extends Controller { } if ($degrees) { - gallery_graphics::rotate($item->file_path(), $item->file_path(), - array("degrees" => $degrees)); - - list($item->width, $item->height) = getimagesize($item->file_path()); - $item->resize_dirty= 1; - $item->thumb_dirty= 1; + $tmpfile = tempnam(TMPPATH, "rotate"); + gallery_graphics::rotate($item->file_path(), $tmpfile, array("degrees" => $degrees)); + $item->set_data_file($tmpfile); $item->save(); - - graphics::generate($item); - - // @todo: this is an inadequate way to regenerate album cover thumbnails after rotation. - foreach (ORM::factory("item") - ->where("album_cover_item_id", "=", $item->id) - ->find_all() as $target) { - copy($item->thumb_path(), $target->thumb_path()); - $target->thumb_width = $item->thumb_width; - $target->thumb_height = $item->thumb_height; - $target->save(); - } + unlink($tmpfile); } if (Input::instance()->get("page_type") == "collection") { diff --git a/modules/gallery/controllers/uploader.php b/modules/gallery/controllers/uploader.php index 87520032..fb496f60 100644 --- a/modules/gallery/controllers/uploader.php +++ b/modules/gallery/controllers/uploader.php @@ -50,7 +50,8 @@ class Uploader_Controller extends Controller { // 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]"); + "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"); @@ -101,6 +102,14 @@ class Uploader_Controller extends Controller { } } + public function status($success_count, $error_count) { + // The "errors" won't be properly pluralized :-/ + print t2("Uploaded %count photo (%error errors)", + "Uploaded %count photos (%error errors)", + $success_count, + array("error" => $error_count)); + } + public function finish() { access::verify_csrf(); diff --git a/modules/gallery/controllers/user_profile.php b/modules/gallery/controllers/user_profile.php index 726d3e51..e992655b 100644 --- a/modules/gallery/controllers/user_profile.php +++ b/modules/gallery/controllers/user_profile.php @@ -56,7 +56,7 @@ class User_Profile_Controller extends Controller { ->to($user->email) ->subject(html::clean($form->message->subject->value)) ->header("Mime-Version", "1.0") - ->header("Content-type", "text/html; charset=iso-8859-1") + ->header("Content-type", "text/html; charset=UTF-8") ->reply_to($form->message->reply_to->value) ->message(html::purify($form->message->message->value)) ->send(); diff --git a/modules/gallery/css/gallery.css b/modules/gallery/css/gallery.css index 08bd4749..8012c6cc 100644 --- a/modules/gallery/css/gallery.css +++ b/modules/gallery/css/gallery.css @@ -78,38 +78,26 @@ margin-bottom: 0 } +#g-add-photos-status-message { + float: right; +} + /* Permissions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #g-edit-permissions-form { - clear: both; + clear: both; } #g-edit-permissions-form th { text-align: center; } -#g-edit-permissions-form td { - background-image: none; -} - -#g-edit-permissions-form fieldset { - border: 1px solid #ccc; -} - #g-permissions .g-denied, #g-permissions .g-allowed { text-align: center; vertical-align: middle; } -#g-permissions .g-denied { - background-color: #fcc; -} - -#g-permissions .g-allowed { - background-color: #cfc; -} - /* Move items ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #g-move ul { diff --git a/modules/gallery/helpers/data_rest.php b/modules/gallery/helpers/data_rest.php new file mode 100644 index 00000000..98c98894 --- /dev/null +++ b/modules/gallery/helpers/data_rest.php @@ -0,0 +1,93 @@ +<?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. + */ + +/** + * This resource returns the raw contents of Item_Model data files. It's analogous to the + * file_proxy controller, but it uses the REST authentication model. + */ +class data_rest_Core { + static function get($request) { + $item = rest::resolve($request->url); + access::required("view", $item); + + $p = $request->params; + if (!isset($p->size) || !in_array($p->size, array("thumb", "resize", "full"))) { + throw new Rest_Exception("Bad Request", 400, array("errors" => array("size" => "invalid"))); + } + + switch ($p->size) { + case "thumb": + $file = $item->thumb_path(); + break; + + case "resize": + $file = $item->resize_path(); + break; + + case "full": + $file = $item->file_path(); + break; + } + + if (!file_exists($file)) { + throw new Kohana_404_Exception(); + } + + // Note: this code is roughly duplicated in data_rest, so if you modify this, please look to + // see if you should make the same change there as well. + // + // We don't have a cache buster in the url, so don't set cache headers here. + // We don't need to save the session for this request + Session::instance()->abort_save(); + + if ($item->is_album() && !$item->album_cover_item_id) { + // No thumbnail. Return nothing. + // @todo: what should we do here? + return; + } + + // Dump out the image. If the item is a movie, then its thumbnail will be a JPG. + if ($item->is_movie() && $p->size == "thumb") { + header("Content-Type: image/jpeg"); + } else if ($item->is_album()) { + header("Content-Type: " . $item->album_cover()->mime_type); + } else { + header("Content-Type: {$item->mime_type}"); + } + Kohana::close_buffers(false); + readfile($file); + + // We must exit here to keep the regular REST framework reply code from adding more bytes on + // at the end or tinkering with headers. + exit; + } + + static function resolve($id) { + $item = ORM::factory("item", $id); + if (!access::can("view", $item)) { + throw new Kohana_404_Exception(); + } + return $item; + } + + static function url($item, $size) { + return url::abs_site("rest/data/{$item->id}?size=$size"); + } +} diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index d4078209..3f83b23d 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -25,12 +25,14 @@ class gallery_Core { * down for maintenance" page. */ static function maintenance_mode() { - $maintenance_mode = Kohana::config("core.maintenance_mode", false, false); - - if (Router::$controller != "login" && !empty($maintenance_mode) && !identity::active_user()->admin) { - Router::$controller = "maintenance"; - Router::$controller_path = MODPATH . "gallery/controllers/maintenance.php"; - Router::$method = "index"; + if (Router::$controller != "login" && + Router::$controller != "combined" && + module::get_var("gallery", "maintenance_mode", 0) && + !identity::active_user()->admin) { + Session::instance()->set("continue_url", url::abs_site("admin/maintenance")); + Router::$controller = "login"; + Router::$controller_path = MODPATH . "gallery/controllers/login.php"; + Router::$method = "html"; } } @@ -58,7 +60,7 @@ class gallery_Core { * @return string */ static function date_time($timestamp) { - return date(module::get_var("gallery", "date_time_format", "Y-M-d H:i:s"), $timestamp); + return date(module::get_var("gallery", "date_time_format"), $timestamp); } /** @@ -67,7 +69,7 @@ class gallery_Core { * @return string */ static function date($timestamp) { - return date(module::get_var("gallery", "date_format", "Y-M-d"), $timestamp); + return date(module::get_var("gallery", "date_format"), $timestamp); } /** diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php index e3fa5e08..df5394c9 100644 --- a/modules/gallery/helpers/gallery_event.php +++ b/modules/gallery/helpers/gallery_event.php @@ -124,6 +124,20 @@ class gallery_event_Core { } } + static function item_updated_data_file($item) { + graphics::generate($item); + + // Update any places where this is the album cover + foreach (ORM::factory("item") + ->where("album_cover_item_id", "=", $item->id) + ->find_all() as $target) { + copy($item->thumb_path(), $target->thumb_path()); + $target->thumb_width = $item->thumb_width; + $target->thumb_height = $item->thumb_height; + $target->save(); + } + } + 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 @@ -433,7 +447,6 @@ class gallery_event_Core { break; } $cover_title = t("Choose as the album cover"); - $move_title = t("Move to another album"); $csrf = access::csrf_token(); @@ -464,17 +477,6 @@ class gallery_event_Core { ->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 - // after move - if ($theme->page_subtype() == "album") { - $options_menu - ->append(Menu::factory("dialog") - ->id("move") - ->label($move_title) - ->css_class("ui-icon-folder-open") - ->url(url::site("move/browse/$item->id"))); - } - $parent = $item->parent(); if (access::can("edit", $parent)) { // We can't make this item the highlight if it's an album with no album cover, or if it's diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index 39c35711..d1bfa656 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -23,7 +23,8 @@ class gallery_installer { $db->query("CREATE TABLE {access_caches} ( `id` int(9) NOT NULL auto_increment, `item_id` int(9), - PRIMARY KEY (`id`)) + PRIMARY KEY (`id`), + KEY (`item_id`)) DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {access_intents} ( @@ -114,7 +115,8 @@ class gallery_installer { KEY `parent_id` (`parent_id`), KEY `type` (`type`), KEY `random` (`rand_key`), - KEY `weight` (`weight` DESC)) + KEY `weight` (`weight` DESC), + KEY `left_ptr` (`left_ptr`)) DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {logs} ( @@ -144,8 +146,10 @@ class gallery_installer { `active` BOOLEAN default 0, `name` varchar(64) default NULL, `version` int(9) default NULL, + `weight` int(9) default NULL, PRIMARY KEY (`id`), - UNIQUE KEY(`name`)) + UNIQUE KEY(`name`), + KEY (`weight`)) DEFAULT CHARSET=utf8;"); $db->query("CREATE TABLE {outgoing_translations} ( @@ -295,7 +299,10 @@ class gallery_installer { module::set_var("gallery", "credits", (string) $powered_by_string); module::set_var("gallery", "simultaneous_upload_limit", 5); module::set_var("gallery", "admin_area_timeout", 90 * 60); - module::set_version("gallery", 30); + 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"); + module::set_version("gallery", 36); } static function upgrade($version) { @@ -554,7 +561,41 @@ class gallery_installer { if ($version == 29) { $db->query("ALTER TABLE {caches} ADD KEY (`key`);"); module::set_version("gallery", $version = 30); - } + } + + if ($version == 30) { + module::set_var("gallery", "maintenance_mode", 0); + module::set_version("gallery", $version = 31); + } + + if ($version == 31) { + $db->query("ALTER TABLE {modules} ADD COLUMN `weight` int(9) DEFAULT NULL"); + $db->query("ALTER TABLE {modules} ADD KEY (`weight`)"); + db::update("modules") + ->set("weight", new Database_Expression("`id`")) + ->execute(); + module::set_version("gallery", $version = 32); + } + + if ($version == 32) { + $db->query("ALTER TABLE {items} ADD KEY (`left_ptr`)"); + module::set_version("gallery", $version = 33); + } + + if ($version == 33) { + $db->query("ALTER TABLE {access_caches} ADD KEY (`item_id`)"); + module::set_version("gallery", $version = 34); + } + + if ($version == 34) { + module::set_var("gallery", "visible_title_length", 15); + module::set_version("gallery", $version = 35); + } + + if ($version == 35) { + module::set_var("gallery", "favicon_url", "lib/images/favicon.ico"); + module::set_version("gallery", $version = 36); + } } static function uninstall() { diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index da9fba49..0886aad0 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -20,13 +20,15 @@ class gallery_task_Core { 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_ALBUMS = 2; + const FIX_STATE_RUN_ALBUMS = 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; + const FIX_STATE_START_MISSING_ACCESS_CACHES = 8; + const FIX_STATE_RUN_MISSING_ACCESS_CACHES = 9; + const FIX_STATE_DONE = 10; static function available_tasks() { $dirty_count = graphics::find_dirty_images_query()->count_records(); @@ -56,8 +58,7 @@ class gallery_task_Core { $tasks[] = Task_Definition::factory() ->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")) + ->description(t("Fix a variety of problems that might cause your Gallery to act strangely. Requires maintenance mode.")) ->severity(log::SUCCESS); return $tasks; @@ -323,15 +324,14 @@ class gallery_task_Core { $total = $task->get("total"); if (empty($total)) { // 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"); + // album audit (permissions and bogus album covers): 1 operation for every album $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++; + // one operation for each missing slug, name and access cache + foreach (array("find_dupe_slugs", "find_dupe_names", "find_missing_access_caches") as $func) { + foreach (self::$func() as $row) { + $total++; + } } $task->set("total", $total); @@ -343,15 +343,24 @@ class gallery_task_Core { $completed = $task->get("completed"); $state = $task->get("state"); + if (!module::get_var("gallery", "maintenance_mode")) { + module::set_var("gallery", "maintenance_mode", 1); + } + // This is a state machine that checks each item in the database. It verifies the following // attributes for an item. // 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. + // 4. there are no album_cover_item_ids pointing to missing items // // 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. + // + // NOTE: the MPTT check will only traverse items that have valid parents. It's possible that + // we have some tree corruption where there are items with parent ids to non-existent items. + // We should probably do something about that. while ($state != self::FIX_STATE_DONE && microtime(true) - $start < 1.5) { switch ($state) { case self::FIX_STATE_START_MPTT: @@ -456,7 +465,7 @@ class gallery_task_Core { $task->set("stack", implode(" ", $stack)); $state = self::FIX_STATE_RUN_DUPE_NAMES; } else { - $state = self::FIX_STATE_START_PERMISSIONS; + $state = self::FIX_STATE_START_ALBUMS; } break; @@ -489,11 +498,11 @@ class gallery_task_Core { $completed++; if (empty($stack)) { - $state = self::FIX_STATE_START_PERMISSIONS; + $state = self::FIX_STATE_START_ALBUMS; } break; - case self::FIX_STATE_START_PERMISSIONS: + case self::FIX_STATE_START_ALBUMS: $stack = array(); foreach (db::build() ->select("id") @@ -503,23 +512,26 @@ class gallery_task_Core { $stack[] = $row->id; } $task->set("stack", implode(" ", $stack)); - $state = self::FIX_STATE_RUN_PERMISSIONS; + $state = self::FIX_STATE_RUN_ALBUMS; break; - case self::FIX_STATE_RUN_PERMISSIONS: + case self::FIX_STATE_RUN_ALBUMS: $stack = explode(" ", $task->get("stack")); $id = array_pop($stack); + $item = ORM::factory("item", $id); + if ($item->album_cover_item_id) { + $album_cover_item = ORM::factory("item", $item->album_cover_item_id); + if (!$album_cover_item->loaded()) { + $item->album_cover_item_id = null; + $item->save(); + } + } + $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); } @@ -530,6 +542,36 @@ class gallery_task_Core { $completed++; if (empty($stack)) { + $state = self::FIX_STATE_START_MISSING_ACCESS_CACHES; + } + break; + + case self::FIX_STATE_START_MISSING_ACCESS_CACHES: + $stack = array(); + foreach (self::find_missing_access_caches() as $row) { + $stack[] = $row->id; + } + if ($stack) { + $task->set("stack", implode(" ", $stack)); + $state = self::FIX_STATE_RUN_MISSING_ACCESS_CACHES; + } else { + $state = self::FIX_STATE_DONE; + } + break; + + case self::FIX_STATE_RUN_MISSING_ACCESS_CACHES: + $stack = explode(" ", $task->get("stack")); + $id = array_pop($stack); + $access_cache = ORM::factory("access_cache"); + $access_cache->item_id = $id; + $access_cache->save(); + $task->set("stack", implode(" ", $stack)); + $completed++; + if (empty($stack)) { + // 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()); $state = self::FIX_STATE_DONE; } break; @@ -543,6 +585,7 @@ class gallery_task_Core { $task->done = true; $task->state = "success"; $task->percent_complete = 100; + module::set_var("gallery", "maintenance_mode", 0); } else { $task->percent_complete = round(100 * $completed / $total); } @@ -574,4 +617,13 @@ class gallery_task_Core { ->group_by("parent_name") ->execute(); } + + static function find_missing_access_caches() { + return db::build() + ->select("items.id") + ->from("items") + ->join("access_caches", "items.id", "access_caches.item_id", "left") + ->where("access_caches.id", "is", null) + ->execute(); + } }
\ No newline at end of file diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index cc4d2e76..bb085ea5 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -338,8 +338,7 @@ class graphics_Core { } else { $toolkits->imagemagick->installed = false; $toolkits->imagemagick->error = - t("ImageMagick is installed, but PHP's open_basedir restriction " . - "prevents Gallery from using it."); + t("ImageMagick is installed, but PHP's open_basedir restriction prevents Gallery from using it."); } } else { $toolkits->imagemagick->installed = false; @@ -363,8 +362,7 @@ class graphics_Core { } else { $toolkits->graphicsmagick->installed = false; $toolkits->graphicsmagick->error = - t("GraphicsMagick is installed, but PHP's open_basedir restriction " . - "prevents Gallery from using it."); + t("GraphicsMagick is installed, but PHP's open_basedir restriction prevents Gallery from using it."); } } else { $toolkits->graphicsmagick->installed = false; diff --git a/modules/gallery/helpers/identity.php b/modules/gallery/helpers/identity.php index 5f1664ec..5de05948 100644 --- a/modules/gallery/helpers/identity.php +++ b/modules/gallery/helpers/identity.php @@ -66,17 +66,20 @@ class identity_Core { // The installer cannot set a user into the session, so it just sets an id which we should // upconvert into a user. - // @todo set the user name into the session instead of 2 and then use it to get the user object + // @todo set the user name into the session instead of 2 and then use it to get the + // user object if ($user === 2) { auth::login(IdentityProvider::instance()->admin_user()); } - if (!$session->get("group_ids")) { + // Cache the group ids for a day to trade off performance for security updates. + if (!$session->get("group_ids") || $session->get("group_ids_timeout", 0) < time()) { $ids = array(); foreach ($user->groups() as $group) { $ids[] = $group->id; } $session->set("group_ids", $ids); + $session->set("group_ids_timeout", time() + 86400); } } catch (Exception $e) { // Log it, so we at least have so notification that we swallowed the exception. diff --git a/modules/gallery/helpers/item_rest.php b/modules/gallery/helpers/item_rest.php index 6869181d..10f9e16a 100644 --- a/modules/gallery/helpers/item_rest.php +++ b/modules/gallery/helpers/item_rest.php @@ -126,6 +126,12 @@ class item_rest_Core { } } } + + // Replace the data file, if required + if (($item->is_photo() || $item->is_movie()) && isset($request->file)) { + $item->set_data_file($request->file); + } + $item->save(); if (isset($request->params->members) && $item->sort_column == "weight") { diff --git a/modules/gallery/helpers/items_rest.php b/modules/gallery/helpers/items_rest.php index 9cca9a54..f0b68d63 100644 --- a/modules/gallery/helpers/items_rest.php +++ b/modules/gallery/helpers/items_rest.php @@ -80,7 +80,7 @@ class items_rest_Core { "relationships" => rest::relationships("item", $item)); if ($item->type == "album") { $members = array(); - foreach ($item->children() as $child) { + foreach ($item->viewable()->children() as $child) { $members[] = rest::url("item", $child); } $item_rest["members"] = $members; diff --git a/modules/gallery/helpers/json.php b/modules/gallery/helpers/json.php index a39db27a..a88608aa 100644 --- a/modules/gallery/helpers/json.php +++ b/modules/gallery/helpers/json.php @@ -25,9 +25,7 @@ class json_Core { * @param mixed $message string or object to json encode and print */ static function reply($message) { - if (!headers_sent()) { - header("Content-Type: application/json; charset=" . Kohana::CHARSET); - } + header("Content-Type: application/json; charset=" . Kohana::CHARSET); print json_encode($message); } }
\ No newline at end of file diff --git a/modules/gallery/helpers/l10n_scanner.php b/modules/gallery/helpers/l10n_scanner.php index 2287a7ba..843c74f7 100644 --- a/modules/gallery/helpers/l10n_scanner.php +++ b/modules/gallery/helpers/l10n_scanner.php @@ -74,10 +74,21 @@ class l10n_scanner_Core { unset($raw_tokens); if (!empty($func_token_list["t"])) { - l10n_scanner::_parse_t_calls($tokens, $func_token_list["t"], $cache); + $errors = l10n_scanner::_parse_t_calls($tokens, $func_token_list["t"], $cache); + foreach ($errors as $line => $error) { + Kohana_Log::add( + "error", "Translation scanner error. " . + "file: " . substr($file, strlen(DOCROOT)) . ", line: $line, context: $error"); + } } + if (!empty($func_token_list["t2"])) { - l10n_scanner::_parse_plural_calls($tokens, $func_token_list["t2"], $cache); + $errors = l10n_scanner::_parse_plural_calls($tokens, $func_token_list["t2"], $cache); + foreach ($errors as $line => $error) { + Kohana_Log::add( + "error", "Translation scanner error. " . + "file: " . substr($file, strlen(DOCROOT)) . ", line: $line, context: $error"); + } } } @@ -91,6 +102,7 @@ class l10n_scanner_Core { } private static function _parse_t_calls(&$tokens, &$call_list, &$cache) { + $errors = array(); foreach ($call_list as $index) { $function_name = $tokens[$index++]; $parens = $tokens[$index++]; @@ -103,14 +115,21 @@ class l10n_scanner_Core { $message = self::_escape_quoted_string($first_param[1]); l10n_scanner::process_message($message, $cache); } else { - // t() found, but inside is something which is not a string literal. - // @todo Call status callback with error filename/line. + if (is_array($first_param) && ($first_param[0] == T_CONSTANT_ENCAPSED_STRING)) { + // Malformed string literals; escalate this + $errors[$first_param[2]] = + var_export(array($function_name, $parens, $first_param, $next_token), 1); + } else { + // t() found, but inside is something which is not a string literal. That's fine. + } } } } + return $errors; } private static function _parse_plural_calls(&$tokens, &$call_list, &$cache) { + $errors = array(); foreach ($call_list as $index) { $function_name = $tokens[$index++]; $parens = $tokens[$index++]; @@ -127,11 +146,17 @@ class l10n_scanner_Core { $plural = self::_escape_quoted_string($second_param[1]); l10n_scanner::process_message(array("one" => $singular, "other" => $plural), $cache); } else { - // t2() found, but inside is something which is not a string literal. - // @todo Call status callback with error filename/line. + if (is_array($first_param) && $first_param[0] == T_CONSTANT_ENCAPSED_STRING) { + $errors[$first_param[2]] = var_export( + array($function_name, $parens, $first_param, + $first_separator, $second_param, $next_token), 1); + } else { + // t2() found, but inside is something which is not a string literal. That's fine. + } } } } + return $errors; } /** diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 5134c7b3..ca6651f1 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -166,6 +166,16 @@ class module_Core { } else { module::set_version($module_name, 1); } + + // Set the weight of the new module, which controls the order in which the modules are + // loaded. By default, new modules are installed at the end of the priority list. Since the + // id field is monotonically increasing, the easiest way to guarantee that is to set the weight + // the same as the id. We don't know that until we save it for the first time + $module = ORM::factory("module")->where("name", "=", $module_name)->find(); + if ($module->loaded()) { + $module->weight = $module->id; + $module->save(); + } module::load_modules(); // Now the module is installed but inactive, so don't leave it in the active path @@ -314,7 +324,15 @@ class module_Core { self::$modules = array(); self::$active = array(); $kohana_modules = array(); - foreach (ORM::factory("module")->find_all() as $module) { + + // In version 32 we introduced a weight column so we can specify the module order + // If we try to use that blindly, we'll break earlier versions before they can even + // run the upgrader. + $modules = module::get_version("gallery") < 32 ? + ORM::factory("module")->find_all(): + ORM::factory("module")->order_by("weight")->find_all(); + + foreach ($modules as $module) { self::$modules[$module->name] = $module; if (!$module->active) { continue; diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index bbb5b66c..3e55eefe 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -57,23 +57,6 @@ class movie_Core { return $form; } - - static function getmoviesize($filename) { - $ffmpeg = self::find_ffmpeg(); - if (empty($ffmpeg)) { - throw new Exception("@todo MISSING_FFMPEG"); - } - - $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($filename) . " 2>&1"; - $result = `$cmd`; - if (preg_match("/Stream.*?Video:.*?(\d+)x(\d+)/", $result, $regs)) { - list ($width, $height) = array($regs[1], $regs[2]); - } else { - list ($width, $height) = array(0, 0); - } - return array($width, $height); - } - static function extract_frame($input_file, $output_file) { $ffmpeg = self::find_ffmpeg(); if (empty($ffmpeg)) { @@ -101,7 +84,7 @@ class movie_Core { } static function find_ffmpeg() { - if (!$ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) { + if (!($ffmpeg_path = module::get_var("gallery", "ffmpeg_path")) || !file_exists($ffmpeg_path)) { $graphics_path = module::get_var("gallery", "graphics_toolkit_path", null); putenv("PATH=" . getenv("PATH") . (empty($graphics_path) ? "" : ":$graphics_path") . @@ -114,4 +97,31 @@ class movie_Core { } return $ffmpeg_path; } + + + /** + * Return the width, height, mime_type and extension of the given movie file. + */ + static function get_file_metadata($file_path) { + $ffmpeg = self::find_ffmpeg(); + if (empty($ffmpeg)) { + throw new Exception("@todo MISSING_FFMPEG"); + } + + $cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($file_path) . " 2>&1"; + $result = `$cmd`; + if (preg_match("/Stream.*?Video:.*?(\d+)x(\d+)/", $result, $regs)) { + list ($width, $height) = array($regs[1], $regs[2]); + } else { + list ($width, $height) = array(0, 0); + } + + $pi = pathinfo($file_path); + $extension = isset($pi["extension"]) ? $pi["extension"] : "flv"; // No extension? Assume FLV. + $mime_type = in_array(strtolower($extension), array("mp4", "m4v")) ? + "video/mp4" : "video/x-flv"; + + return array($width, $height, $mime_type, $extension); + } + } diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php index 73cd60c0..a38b4fb2 100644 --- a/modules/gallery/helpers/photo.php +++ b/modules/gallery/helpers/photo.php @@ -77,4 +77,16 @@ class photo_Core { } return sprintf($format, $new_width, $new_height); } + + /** + * Return the width, height, mime_type and extension of the given image file. + */ + static function get_file_metadata($file_path) { + $image_info = getimagesize($file_path); + $width = $image_info[0]; + $height = $image_info[1]; + $mime_type = $image_info["mime"]; + $extension = image_type_to_extension($image_info[2], false); + return array($width, $height, $mime_type, $extension); + } } diff --git a/modules/gallery/helpers/theme.php b/modules/gallery/helpers/theme.php index 3589a5b7..1dc1f3b6 100644 --- a/modules/gallery/helpers/theme.php +++ b/modules/gallery/helpers/theme.php @@ -77,41 +77,8 @@ class theme_Core { $config->set("core.modules", $modules); } - 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->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")) - ->error_messages("valid_digit", t("You must enter a number")) - ->value(module::get_var("gallery", "page_size")); - $group->input("thumb_size")->label(t("Thumbnail size (in pixels)"))->id("g-thumb-size") - ->rules("required|valid_digit") - ->error_messages("required", t("You must enter a number")) - ->error_messages("valid_digit", t("You must enter a number")) - ->value(module::get_var("gallery", "thumb_size")); - $group->input("resize_size")->label(t("Resized image size (in pixels)"))->id("g-resize-size") - ->rules("required|valid_digit") - ->error_messages("required", t("You must enter a number")) - ->error_messages("valid_digit", t("You must enter a number")) - ->value(module::get_var("gallery", "resize_size")); - $group->textarea("header_text")->label(t("Header text"))->id("g-header-text") - ->value(module::get_var("gallery", "header_text")); - $group->textarea("footer_text")->label(t("Footer text"))->id("g-footer-text") - ->value(module::get_var("gallery", "footer_text")); - $group->checkbox("show_credits")->label(t("Show site credits"))->id("g-footer-text") - ->checked(module::get_var("gallery", "show_credits")); - - module::event("theme_edit_form", $form); - - $group = $form->group("buttons") - ->set_attr("style","border: none"); - $group->submit("")->value(t("Save")); - return $form; - } - static function get_info($theme_name) { - $theme_name = preg_replace("/[^\w]/", "", $theme_name); + $theme_name = preg_replace("/[^a-zA-Z0-9\._-]/", "", $theme_name); $file = THEMEPATH . "$theme_name/theme.info"; $theme_info = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); $theme_info->description = t($theme_info->description); diff --git a/modules/gallery/helpers/user_profile.php b/modules/gallery/helpers/user_profile.php index e5ebce84..d9cc8ace 100644 --- a/modules/gallery/helpers/user_profile.php +++ b/modules/gallery/helpers/user_profile.php @@ -35,19 +35,20 @@ class user_profile_Core { $group->input("reply_to") ->label(t("From:")) ->rules("required|length[1, 256]|valid_email") - ->error_messages("required", t("Field is required")) - ->error_messages("max_length", t("Field exceeds 256 bytes")) - ->error_messages("valid_email", t("Field is not a valid email address")); + ->error_messages("required", t("You must enter a valid email address")) + ->error_messages("max_length", t("Your email address is too long")) + ->error_messages("valid_email", t("You must enter a valid email address")); $group->input("subject") ->label(t("Subject:")) ->rules("required|length[1, 256]") - ->error_messages("required", t("Field is required")) - ->error_messages("max_length", t("Field exceeds 256 bytes")); + ->error_messages("required", t("Your message must have a subject")) + ->error_messages("max_length", t("Your subject is too long")); $group->textarea("message") ->label(t("Message:")) ->rules("required") - ->error_messages("required", t("Field is required")); + ->error_messages("required", t("You must enter a message")); module::event("user_profile_contact_form", $form); + module::event("captcha_protect_form", $form); $group->submit("")->value(t("Send")); return $form; } diff --git a/modules/gallery/images/missing_movie.png b/modules/gallery/images/missing_movie.png Binary files differindex fdc97779..fdc97779 100755..100644 --- a/modules/gallery/images/missing_movie.png +++ b/modules/gallery/images/missing_movie.png diff --git a/modules/gallery/libraries/Form_Uploadify.php b/modules/gallery/libraries/Form_Uploadify.php index e5b6d819..79477763 100644 --- a/modules/gallery/libraries/Form_Uploadify.php +++ b/modules/gallery/libraries/Form_Uploadify.php @@ -46,6 +46,8 @@ class Form_Uploadify_Core extends Form_Input { $v->album = $this->data["album"]; $v->script_data = $this->data["script_data"]; $v->simultaneous_upload_limit = module::get_var("gallery", "simultaneous_upload_limit"); + $v->movies_allowed = (bool) movie::find_ffmpeg(); + $v->suhosin_session_encrypt = (bool) ini_get("suhosin.session.encrypt"); return $v; } diff --git a/modules/gallery/libraries/IdentityProvider.php b/modules/gallery/libraries/IdentityProvider.php index 5f341c90..4ef07e1a 100644 --- a/modules/gallery/libraries/IdentityProvider.php +++ b/modules/gallery/libraries/IdentityProvider.php @@ -61,8 +61,7 @@ class IdentityProvider_Core { * Return a commen confirmation message */ static function confirmation_message() { - return t("Are you sure you want to change your Identity Provider? " . - "Continuing will delete all existing users."); + return t("Are you sure you want to change your Identity Provider? Continuing will delete all existing users."); } static function change_provider($new_provider) { @@ -113,8 +112,7 @@ class IdentityProvider_Core { } message::error( - t("Error attempting to enable \"%new_provider\" identity provider, " . - "reverted to \"%old_provider\" identity provider", + t("Error attempting to enable \"%new_provider\" identity provider, reverted to \"%old_provider\" identity provider", array("new_provider" => $new_provider, "old_provider" => $current_provider))); $restore_already_running = false; diff --git a/modules/gallery/libraries/MY_Kohana_Exception.php b/modules/gallery/libraries/MY_Kohana_Exception.php index 72cb2ac0..82899d7e 100644 --- a/modules/gallery/libraries/MY_Kohana_Exception.php +++ b/modules/gallery/libraries/MY_Kohana_Exception.php @@ -22,11 +22,15 @@ class Kohana_Exception extends Kohana_Exception_Core { * Dump out the full stack trace as part of the text representation of the exception. */ public static function text($e) { - return sprintf( - "%s [ %s ]: %s\n%s [ %s ]\n%s", - get_class($e), $e->getCode(), strip_tags($e->getMessage()), - $e->getFile(), $e->getLine(), - $e->getTraceAsString()); + if ($e instanceof Kohana_404_Exception) { + return "File not found: " . Router::$complete_uri; + } else { + return sprintf( + "%s [ %s ]: %s\n%s [ %s ]\n%s", + get_class($e), $e->getCode(), strip_tags($e->getMessage()), + $e->getFile(), $e->getLine(), + $e->getTraceAsString()); + } } /** @@ -41,16 +45,21 @@ class Kohana_Exception extends Kohana_Exception_Core { * data, such as session ids and passwords / hashes. */ public static function safe_dump($value, $key, $length=128, $max_level=5) { - return parent::dump(self::_sanitize_for_dump($value, $key), $length, $max_level); + return parent::dump(self::_sanitize_for_dump($value, $key, $max_level), $length, $max_level); } /** * Elides sensitive data which shouldn't be echoed to the client, * such as passwords, and other secrets. */ - /* Visible for testing*/ static function _sanitize_for_dump($value, $key=null) { + /* Visible for testing*/ static function _sanitize_for_dump($value, $key=null, $max_level) { // Better elide too much than letting something through. // Note: unanchored match is intended. + if (!$max_level) { + // Too much recursion; give up. We gave it our best shot. + return $value; + } + $sensitive_info_pattern = '/(password|pass|email|hash|private_key|session_id|session|g3sid|csrf|secret)/i'; if (preg_match($sensitive_info_pattern, $key) || @@ -63,7 +72,7 @@ class Kohana_Exception extends Kohana_Exception_Core { } else if ($value instanceof User_Model) { return get_class($value) . ' object for "' . $value->name . '" - details omitted for display'; } - return self::_sanitize_for_dump((array) $value, $key); + return self::_sanitize_for_dump((array) $value, $key, $max_level - 1); } else if (is_array($value)) { $result = array(); foreach ($value as $k => $v) { @@ -78,7 +87,7 @@ class Kohana_Exception extends Kohana_Exception_Core { if (is_object($v)) { $key_for_display .= ' (type: ' . get_class($v) . ')'; } - $result[$key_for_display] = self::_sanitize_for_dump($v, $actual_key); + $result[$key_for_display] = self::_sanitize_for_dump($v, $actual_key, $max_level - 1); } } else { $result = $value; diff --git a/modules/gallery/libraries/Theme_View.php b/modules/gallery/libraries/Theme_View.php index 6246c6f1..7a6bc1da 100644 --- a/modules/gallery/libraries/Theme_View.php +++ b/modules/gallery/libraries/Theme_View.php @@ -46,9 +46,11 @@ class Theme_View_Core extends Gallery_View { $this->set_global("thumb_proportion", $this->thumb_proportion()); } - $maintenance_mode = Kohana::config("core.maintenance_mode", false, false); - if ($maintenance_mode) { - message::warning(t("This site is currently in maintenance mode")); + if (module::get_var("gallery", "maintenance_mode", 0)) { + if (identity::active_user()->admin) { + message::warning(t("This site is currently in maintenance mode. Visit the <a href=\"%maintenance_url\">maintenance page</a>", array("maintenance_url" => url::site("admin/maintenance")))); + } else + message::warning(t("This site is currently in maintenance mode.")); } } @@ -234,6 +236,13 @@ class Theme_View_Core extends Gallery_View { case "thumb_bottom": case "thumb_info": case "thumb_top": + if ($function == "head") { + // Stash any CSS we have already; that came from the theme and we want theme CSS to + // override module CSs + $save_css = $this->css; + $this->css = array(); + } + $blocks = array(); if (method_exists("gallery_theme", $function)) { switch (count($args)) { @@ -273,6 +282,8 @@ class Theme_View_Core extends Gallery_View { } if ($function == "head") { + // Merge the theme CSS/JS at the end + $this->css = array_merge($this->css, $save_css); array_unshift($blocks, $this->combine_files($this->css, "css")); array_unshift($blocks, $this->combine_files($this->scripts, "javascript")); } diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index c00b7972..1db766e9 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -316,7 +316,7 @@ class Item_Model extends ORM_MPTT { unset($significant_changes["relative_url_cache"]); unset($significant_changes["relative_path_cache"]); - if (!empty($this->changed) && $significant_changes) { + if ((!empty($this->changed) && $significant_changes) || isset($this->data_file)) { $this->updated = time(); if (!$this->loaded()) { // Create a new item. @@ -341,30 +341,19 @@ class Item_Model extends ORM_MPTT { } // Get the width, height and mime type from our data file for photos and movies. - if ($this->is_movie() || $this->is_photo()) { - $pi = pathinfo($this->data_file); - + if ($this->is_photo() || $this->is_movie()) { if ($this->is_photo()) { - $image_info = getimagesize($this->data_file); - $this->width = $image_info[0]; - $this->height = $image_info[1]; - $this->mime_type = $image_info["mime"]; - - // Force an extension onto the name if necessary - if (empty($pi["extension"])) { - $pi["extension"] = image_type_to_extension($image_info[2], false); - $this->name .= "." . $pi["extension"]; - } - } else { - list ($this->width, $this->height) = movie::getmoviesize($this->data_file); - - // No extension? Assume FLV. - if (empty($pi["extension"])) { - $pi["extension"] = "flv"; - $this->name .= "." . $pi["extension"]; - } + list ($this->width, $this->height, $this->mime_type, $extension) = + photo::get_file_metadata($this->data_file); + } else if ($this->is_movie()) { + list ($this->width, $this->height, $this->mime_type, $extension) = + movie::get_file_metadata($this->data_file); + } - $this->mime_type = in_array(strtolower($pi["extension"]), array("mp4", "m4v")) ? "video/mp4" : "video/x-flv"; + // Force an extension onto the name if necessary + $pi = pathinfo($this->data_file); + if (empty($pi["extension"])) { + $this->name = "{$this->name}.$extension"; } } @@ -422,7 +411,9 @@ class Item_Model extends ORM_MPTT { } // This will almost definitely trigger another save, so put it at the end so that we're - // tail recursive. + // tail recursive. Null out the data file variable first, otherwise the next save will + // trigger an item_updated_data_file event. + $this->data_file = null; module::event("item_created", $this); } else { // Update an existing item @@ -479,7 +470,30 @@ class Item_Model extends ORM_MPTT { ->execute(); } + // Replace the data file, if requested. + // @todo: we don't handle the case where you swap in a file of a different mime type + // should we prevent that in validation? or in set_data_file() + if ($this->data_file && ($this->is_photo() || $this->is_movie())) { + copy($this->data_file, $this->file_path()); + + // Get the width, height and mime type from our data file for photos and movies. + if ($this->is_photo()) { + list ($this->width, $this->height) = photo::get_file_metadata($this->file_path()); + } else if ($this->is_movie()) { + list ($this->width, $this->height) = movie::get_file_metadata($this->file_path()); + } + $this->thumb_dirty = 1; + $this->resize_dirty = 1; + } + module::event("item_updated", $original, $this); + + if ($this->data_file) { + // Null out the data file variable here, otherwise this event will trigger another + // save() which will think that we're doing another file move. + $this->data_file = null; + module::event("item_updated_data_file", $this); + } } } else if (!empty($this->changed)) { // Insignificant changes only. Don't fire events or do any special checking to try to keep @@ -656,9 +670,9 @@ class Item_Model extends ORM_MPTT { public function resize_img($extra_attrs) { $attrs = array_merge($extra_attrs, array("src" => $this->resize_url(), - "alt" => $this->title, - "width" => $this->resize_width, - "height" => $this->resize_height) + "alt" => $this->title, + "width" => $this->resize_width, + "height" => $this->resize_height) ); // html::image forces an absolute url which we don't want return "<img" . html::attributes($attrs) . "/>"; @@ -765,8 +779,9 @@ class Item_Model extends ORM_MPTT { $this->rules["slug"] = array(); } - // Movies and photos must have data files - if (($this->is_photo() || $this->is_movie()) && !$this->loaded()) { + // Movies and photos must have data files. Verify the data file on new items, or if it has + // been replaced. + if (($this->is_photo() || $this->is_movie()) && $this->data_file) { $this->rules["name"]["callbacks"][] = array($this, "valid_data_file"); } } @@ -842,6 +857,17 @@ class Item_Model extends ORM_MPTT { } else if (filesize($this->data_file) == 0) { $v->add_error("name", "empty_data_file"); } + + if ($this->loaded()) { + if ($this->is_photo()) { + list ($a, $b, $mime_type) = photo::get_file_metadata($this->data_file); + } else if ($this->is_movie()) { + list ($a, $b, $mime_type) = movie::get_file_metadata($this->data_file); + } + if ($mime_type != $this->mime_type) { + $v->add_error("name", "cant_change_mime_type"); + } + } } /** @@ -949,14 +975,25 @@ class Item_Model extends ORM_MPTT { } unset($data["album_cover_item_id"]); - if (access::can("view_full", $this) && $this->is_photo()) { - $data["file_url"] = $this->file_url(true); + 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_photo()) { + $data["resize_url"] = rest::url("data", $this, "resize"); + if (access::user_can(identity::guest(), "view", $this)) { + $data["resize_url_public"] = $this->resize_url(true); + } } - if (($tmp = $this->resize_url(true)) && $this->is_photo()) { - $data["resize_url"] = $tmp; + $data["thumb_url"] = rest::url("data", $this, "thumb"); + if (access::user_can(identity::guest(), "view", $this)) { + $data["thumb_url_public"] = $this->thumb_url(true); } - $data["thumb_url"] = $this->thumb_url(true); + $data["can_edit"] = access::can("edit", $this); // Elide some internal-only data that is going to cause confusion in the client. diff --git a/modules/gallery/module.info b/modules/gallery/module.info index df2be978..44da9f2f 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,3 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 30 +version = 36 diff --git a/modules/gallery/tests/Gallery_Filters.php b/modules/gallery/tests/Gallery_Filters.php index 052990d5..1c07f93e 100644 --- a/modules/gallery/tests/Gallery_Filters.php +++ b/modules/gallery/tests/Gallery_Filters.php @@ -43,7 +43,6 @@ class GalleryCodeFilterIterator extends FilterIterator { strpos($path_name, MODPATH . "unit_test") !== false || strpos($path_name, MODPATH . "exif/lib") !== false || strpos($path_name, MODPATH . "user/lib/PasswordHash") !== false || - strpos($path_name, DOCROOT . "lib/swfupload") !== false || strpos($path_name, SYSPATH) !== false || strpos($path_name, MODPATH . "gallery/libraries/HTMLPurifier") !== false || substr($path_name, -1, 1) == "~"); diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index 907cfe24..bd123098 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -384,4 +384,35 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { $this->assert_same($photo->id, $album->album_cover_item_id); } + + public function replace_data_file_test() { + // Random photo is modules/gallery/tests/test.jpg which is 1024x768 and 6232 bytes. + $photo = test::random_photo(); + $this->assert_equal(1024, $photo->width); + $this->assert_equal(768, $photo->height); + $this->assert_equal(6232, filesize($photo->file_path())); + + // Random photo is gallery/images/imagemagick.jpg is 114x118 and 20337 bytes + $photo->set_data_file(MODPATH . "gallery/images/imagemagick.jpg"); + $photo->save(); + + $this->assert_equal(114, $photo->width); + $this->assert_equal(118, $photo->height); + $this->assert_equal(20337, filesize($photo->file_path())); + } + + public function replacement_data_file_must_be_same_mime_type_test() { + // Random photo is modules/gallery/tests/test.jpg + $photo = test::random_photo(); + $photo->set_data_file(MODPATH . "gallery/images/graphicsmagick.png"); + + try { + $photo->save(); + } catch (ORM_Validation_Exception $e) { + $this->assert_same(array("name" => "cant_change_mime_type"), $e->validation->errors()); + return; // pass + } + $this->assert_true(false, "Shouldn't get here"); + + } } diff --git a/modules/gallery/tests/Kohana_Exception_Test.php b/modules/gallery/tests/Kohana_Exception_Test.php index 48bc5184..df7cf9ff 100644 --- a/modules/gallery/tests/Kohana_Exception_Test.php +++ b/modules/gallery/tests/Kohana_Exception_Test.php @@ -37,22 +37,22 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { public function sanitize_for_dump_match_key_test() { $this->assert_equal("removed for display", - Kohana_Exception::_sanitize_for_dump("original value", "password")); + Kohana_Exception::_sanitize_for_dump("original value", "password", 5)); $this->assert_equal("original value", - Kohana_Exception::_sanitize_for_dump("original value", "meow")); + Kohana_Exception::_sanitize_for_dump("original value", "meow", 5)); } public function sanitize_for_dump_match_key_loosely_test() { $this->assert_equal("removed for display", - Kohana_Exception::_sanitize_for_dump("original value", "this secret key")); + Kohana_Exception::_sanitize_for_dump("original value", "this secret key", 5)); } public function sanitize_for_dump_match_value_test() { // Looks like a hash / secret value. $this->assert_equal("removed for display", - Kohana_Exception::_sanitize_for_dump("p$2a178b841c6391d6368f131", "meow")); + Kohana_Exception::_sanitize_for_dump("p$2a178b841c6391d6368f131", "meow", 5)); $this->assert_equal("original value", - Kohana_Exception::_sanitize_for_dump("original value", "meow")); + Kohana_Exception::_sanitize_for_dump("original value", "meow", 5)); } public function sanitize_for_dump_array_test() { @@ -64,7 +64,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { "three" => "removed for display"); $this->assert_equal($expected, - Kohana_Exception::_sanitize_for_dump($var, "ignored")); + Kohana_Exception::_sanitize_for_dump($var, "ignored", 5)); } public function sanitize_for_dump_nested_array_test() { @@ -73,7 +73,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { $expected = array("safe" => "original value 1", "safe 2" => array("some hash" => "removed for display")); $this->assert_equal($expected, - Kohana_Exception::_sanitize_for_dump($var, "ignored")); + Kohana_Exception::_sanitize_for_dump($var, "ignored", 5)); } public function sanitize_for_dump_user_test() { @@ -83,7 +83,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { $user->email = "value 2"; $user->full_name = "value 3"; $this->assert_equal('User_Model object for "john" - details omitted for display', - Kohana_Exception::_sanitize_for_dump($user, "ignored")); + Kohana_Exception::_sanitize_for_dump($user, "ignored", 5)); } public function sanitize_for_dump_database_test() { @@ -91,7 +91,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { array("connection" => array("user" => "john", "name" => "gallery_3"), "cache" => array())); $this->assert_equal("Kohana_Exception_Test_Database object - details omitted for display", - Kohana_Exception::_sanitize_for_dump($db, "ignored")); + Kohana_Exception::_sanitize_for_dump($db, "ignored", 5)); } public function sanitize_for_dump_nested_database_test() { @@ -104,7 +104,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { array("some" => "foo", "bar (type: Kohana_Exception_Test_Database)" => "Kohana_Exception_Test_Database object - details omitted for display"), - Kohana_Exception::_sanitize_for_dump($var, "ignored")); + Kohana_Exception::_sanitize_for_dump($var, "ignored", 5)); } public function sanitize_for_dump_object_test() { @@ -117,7 +117,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { "private: email_address" => "removed for display", "password" => "removed for display"); $this->assert_equal($expected, - Kohana_Exception::_sanitize_for_dump($obj, "ignored")); + Kohana_Exception::_sanitize_for_dump($obj, "ignored", 5)); } public function sanitize_for_dump_nested_object_test() { @@ -142,7 +142,7 @@ class Kohana_Exception_Test extends Gallery_Unit_Test_Case { "foo" => array("bar (type: User_Model)" => 'User_Model object for "john" - details omitted for display')); $this->assert_equal($expected, - Kohana_Exception::_sanitize_for_dump($obj, "ignored")); + Kohana_Exception::_sanitize_for_dump($obj, "ignored", 5)); } } diff --git a/modules/gallery/tests/Sendmail_Test.php b/modules/gallery/tests/Sendmail_Test.php index b20543d1..b9406047 100644 --- a/modules/gallery/tests/Sendmail_Test.php +++ b/modules/gallery/tests/Sendmail_Test.php @@ -65,14 +65,14 @@ class Sendmail_Test extends Gallery_Unit_Test_Case { "From: from@gallery3.com\n" . "Reply-To: public@gallery3.com\n" . "MIME-Version: 1.0\n" . - "Content-type: text/html; charset=iso-8859-1\r\n" . + "Content-Type: text/html; charset=UTF-8\r\n" . "Subject: Test Email Unit test\r\n\r\n" . "<html><body><p>This is an html msg</p></body></html>"; $result = Sendmail_For_Test::factory() ->to("receiver@someemail.com") ->subject("Test Email Unit test") ->header("MIME-Version", "1.0") - ->header("Content-type", "text/html; charset=iso-8859-1") + ->header("Content-Type", "text/html; charset=UTF-8") ->message("<html><body><p>This is an html msg</p></body></html>") ->send() ->send_text; diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt index 3c9b3afc..8b776fb9 100644 --- a/modules/gallery/tests/controller_auth_data.txt +++ b/modules/gallery/tests/controller_auth_data.txt @@ -14,7 +14,6 @@ modules/gallery/controllers/login.php auth_ajax modules/gallery/controllers/login.php html DIRTY_AUTH modules/gallery/controllers/login.php auth_html DIRTY_AUTH modules/gallery/controllers/logout.php index DIRTY_AUTH -modules/gallery/controllers/maintenance.php index DIRTY_AUTH modules/gallery/controllers/quick.php form_edit DIRTY_CSRF modules/gallery/controllers/upgrader.php index DIRTY_AUTH modules/gallery/controllers/uploader.php start DIRTY_AUTH @@ -26,6 +25,8 @@ modules/gallery/controllers/welcome_message.php index modules/organize/controllers/organize.php dialog DIRTY_CSRF modules/organize/controllers/organize.php add_album_fields DIRTY_AUTH modules/rest/controllers/rest.php index DIRTY_CSRF|DIRTY_AUTH +modules/rest/controllers/rest.php reset_api_key_confirm DIRTY_AUTH +modules/rest/controllers/rest.php reset_api_key DIRTY_AUTH modules/rest/controllers/rest.php __call DIRTY_CSRF|DIRTY_AUTH modules/rss/controllers/rss.php feed DIRTY_CSRF|DIRTY_AUTH modules/search/controllers/search.php index DIRTY_CSRF|DIRTY_AUTH diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 02483865..3eae3d07 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -77,23 +77,23 @@ modules/gallery/views/admin_languages.html.php 62 DIRTY form:: modules/gallery/views/admin_languages.html.php 63 DIRTY $display_name modules/gallery/views/admin_languages.html.php 65 DIRTY form::radio("default_locale",$code,($default_locale==$code),((isset($installed_locales[$code]))?'':'disabled="disabled"')) modules/gallery/views/admin_languages.html.php 113 DIRTY $share_translations_form -modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/gallery/views/admin_maintenance.html.php 24 DIRTY_ATTR log::severity_class($task->severity) -modules/gallery/views/admin_maintenance.html.php 25 DIRTY_ATTR log::severity_class($task->severity) -modules/gallery/views/admin_maintenance.html.php 26 DIRTY $task->name -modules/gallery/views/admin_maintenance.html.php 29 DIRTY $task->description -modules/gallery/views/admin_maintenance.html.php 70 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/gallery/views/admin_maintenance.html.php 70 DIRTY_ATTR $task->state=="stalled"?"g-warning":"" -modules/gallery/views/admin_maintenance.html.php 71 DIRTY_ATTR $task->state=="stalled"?"g-warning":"" -modules/gallery/views/admin_maintenance.html.php 72 DIRTY gallery::date_time($task->updated) -modules/gallery/views/admin_maintenance.html.php 75 DIRTY $task->name -modules/gallery/views/admin_maintenance.html.php 90 DIRTY $task->status -modules/gallery/views/admin_maintenance.html.php 141 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/gallery/views/admin_maintenance.html.php 141 DIRTY_ATTR $task->state=="success"?"g-success":"g-error" -modules/gallery/views/admin_maintenance.html.php 142 DIRTY_ATTR $task->state=="success"?"g-success":"g-error" -modules/gallery/views/admin_maintenance.html.php 143 DIRTY gallery::date_time($task->updated) -modules/gallery/views/admin_maintenance.html.php 146 DIRTY $task->name -modules/gallery/views/admin_maintenance.html.php 158 DIRTY $task->status +modules/gallery/views/admin_maintenance.html.php 40 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/gallery/views/admin_maintenance.html.php 40 DIRTY_ATTR log::severity_class($task->severity) +modules/gallery/views/admin_maintenance.html.php 41 DIRTY_ATTR log::severity_class($task->severity) +modules/gallery/views/admin_maintenance.html.php 42 DIRTY $task->name +modules/gallery/views/admin_maintenance.html.php 45 DIRTY $task->description +modules/gallery/views/admin_maintenance.html.php 86 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/gallery/views/admin_maintenance.html.php 86 DIRTY_ATTR $task->state=="stalled"?"g-warning":"" +modules/gallery/views/admin_maintenance.html.php 87 DIRTY_ATTR $task->state=="stalled"?"g-warning":"" +modules/gallery/views/admin_maintenance.html.php 88 DIRTY gallery::date_time($task->updated) +modules/gallery/views/admin_maintenance.html.php 91 DIRTY $task->name +modules/gallery/views/admin_maintenance.html.php 106 DIRTY $task->status +modules/gallery/views/admin_maintenance.html.php 157 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/gallery/views/admin_maintenance.html.php 157 DIRTY_ATTR $task->state=="success"?"g-success":"g-error" +modules/gallery/views/admin_maintenance.html.php 158 DIRTY_ATTR $task->state=="success"?"g-success":"g-error" +modules/gallery/views/admin_maintenance.html.php 159 DIRTY gallery::date_time($task->updated) +modules/gallery/views/admin_maintenance.html.php 162 DIRTY $task->name +modules/gallery/views/admin_maintenance.html.php 174 DIRTY $task->status modules/gallery/views/admin_maintenance_show_log.html.php 8 DIRTY_JS url::site("admin/maintenance/save_log/$task->id?csrf=$csrf") modules/gallery/views/admin_maintenance_show_log.html.php 13 DIRTY $task->name modules/gallery/views/admin_maintenance_task.html.php 55 DIRTY $task->name @@ -122,50 +122,52 @@ modules/gallery/views/admin_themes.html.php 76 DIRTY $info- modules/gallery/views/admin_themes.html.php 78 DIRTY $info->description modules/gallery/views/admin_themes_preview.html.php 8 DIRTY_ATTR $url modules/gallery/views/error_404.html.php 14 DIRTY $login_form -modules/gallery/views/error_admin.html.php 150 DIRTY $type -modules/gallery/views/error_admin.html.php 150 DIRTY $code -modules/gallery/views/error_admin.html.php 153 DIRTY $message -modules/gallery/views/error_admin.html.php 156 DIRTY_ATTR $error_id -modules/gallery/views/error_admin.html.php 161 DIRTY Kohana_Exception::debug_path($file) -modules/gallery/views/error_admin.html.php 161 DIRTY $line -modules/gallery/views/error_admin.html.php 166 DIRTY_ATTR ($num==$line)?"highlight":"" -modules/gallery/views/error_admin.html.php 166 DIRTY $num -modules/gallery/views/error_admin.html.php 166 DIRTY htmlspecialchars($row,ENT_NOQUOTES,Kohana::CHARSET) -modules/gallery/views/error_admin.html.php 178 DIRTY_ATTR $source_id -modules/gallery/views/error_admin.html.php 178 DIRTY_JS $source_id -modules/gallery/views/error_admin.html.php 178 DIRTY Kohana_Exception::debug_path($step["file"]) -modules/gallery/views/error_admin.html.php 178 DIRTY $step["line"] -modules/gallery/views/error_admin.html.php 180 DIRTY Kohana_Exception::debug_path($step["file"]) -modules/gallery/views/error_admin.html.php 180 DIRTY $step["line"] -modules/gallery/views/error_admin.html.php 187 DIRTY $step["function"] -modules/gallery/views/error_admin.html.php 188 DIRTY_ATTR $args_id -modules/gallery/views/error_admin.html.php 188 DIRTY_JS $args_id -modules/gallery/views/error_admin.html.php 192 DIRTY_ATTR $args_id -modules/gallery/views/error_admin.html.php 197 DIRTY $name -modules/gallery/views/error_admin.html.php 200 DIRTY Kohana_Exception::safe_dump($arg,$name) -modules/gallery/views/error_admin.html.php 208 DIRTY_ATTR $source_id -modules/gallery/views/error_admin.html.php 208 DIRTY_ATTR ($num==$step["line"])?"highlight":"" -modules/gallery/views/error_admin.html.php 208 DIRTY $num -modules/gallery/views/error_admin.html.php 208 DIRTY htmlspecialchars($row,ENT_NOQUOTES,Kohana::CHARSET) -modules/gallery/views/error_admin.html.php 218 DIRTY_ATTR $env_id=$error_id."environment" -modules/gallery/views/error_admin.html.php 218 DIRTY_JS $env_id -modules/gallery/views/error_admin.html.php 220 DIRTY_ATTR $env_id -modules/gallery/views/error_admin.html.php 222 DIRTY_ATTR $env_id=$error_id."environment_included" -modules/gallery/views/error_admin.html.php 222 DIRTY_JS $env_id -modules/gallery/views/error_admin.html.php 222 DIRTY count($included) -modules/gallery/views/error_admin.html.php 223 DIRTY_ATTR $env_id -modules/gallery/views/error_admin.html.php 228 DIRTY Kohana_Exception::debug_path($file) -modules/gallery/views/error_admin.html.php 235 DIRTY_ATTR $env_id=$error_id."environment_loaded" -modules/gallery/views/error_admin.html.php 235 DIRTY_JS $env_id -modules/gallery/views/error_admin.html.php 235 DIRTY count($included) -modules/gallery/views/error_admin.html.php 236 DIRTY_ATTR $env_id -modules/gallery/views/error_admin.html.php 241 DIRTY Kohana_Exception::debug_path($file) -modules/gallery/views/error_admin.html.php 249 DIRTY_ATTR $env_id="$error_id.environment".strtolower($var) -modules/gallery/views/error_admin.html.php 250 DIRTY_JS $env_id -modules/gallery/views/error_admin.html.php 250 DIRTY $var -modules/gallery/views/error_admin.html.php 251 DIRTY_ATTR $env_id -modules/gallery/views/error_admin.html.php 257 DIRTY $key -modules/gallery/views/error_admin.html.php 261 DIRTY Kohana_Exception::safe_dump($value,$key) +modules/gallery/views/error_admin.html.php 178 DIRTY @gallery_block::get("platform_info") +modules/gallery/views/error_admin.html.php 179 DIRTY @gallery_block::get("stats") +modules/gallery/views/error_admin.html.php 184 DIRTY $type +modules/gallery/views/error_admin.html.php 184 DIRTY $code +modules/gallery/views/error_admin.html.php 187 DIRTY $message +modules/gallery/views/error_admin.html.php 190 DIRTY_ATTR $error_id +modules/gallery/views/error_admin.html.php 195 DIRTY Kohana_Exception::debug_path($file) +modules/gallery/views/error_admin.html.php 195 DIRTY $line +modules/gallery/views/error_admin.html.php 200 DIRTY_ATTR ($num==$line)?"highlight":"" +modules/gallery/views/error_admin.html.php 200 DIRTY $num +modules/gallery/views/error_admin.html.php 200 DIRTY htmlspecialchars($row,ENT_NOQUOTES,Kohana::CHARSET) +modules/gallery/views/error_admin.html.php 212 DIRTY_ATTR $source_id +modules/gallery/views/error_admin.html.php 212 DIRTY_JS $source_id +modules/gallery/views/error_admin.html.php 212 DIRTY Kohana_Exception::debug_path($step["file"]) +modules/gallery/views/error_admin.html.php 212 DIRTY $step["line"] +modules/gallery/views/error_admin.html.php 214 DIRTY Kohana_Exception::debug_path($step["file"]) +modules/gallery/views/error_admin.html.php 214 DIRTY $step["line"] +modules/gallery/views/error_admin.html.php 221 DIRTY $step["function"] +modules/gallery/views/error_admin.html.php 222 DIRTY_ATTR $args_id +modules/gallery/views/error_admin.html.php 222 DIRTY_JS $args_id +modules/gallery/views/error_admin.html.php 226 DIRTY_ATTR $args_id +modules/gallery/views/error_admin.html.php 231 DIRTY $name +modules/gallery/views/error_admin.html.php 234 DIRTY Kohana_Exception::safe_dump($arg,$name) +modules/gallery/views/error_admin.html.php 242 DIRTY_ATTR $source_id +modules/gallery/views/error_admin.html.php 242 DIRTY_ATTR ($num==$step["line"])?"highlight":"" +modules/gallery/views/error_admin.html.php 242 DIRTY $num +modules/gallery/views/error_admin.html.php 242 DIRTY htmlspecialchars($row,ENT_NOQUOTES,Kohana::CHARSET) +modules/gallery/views/error_admin.html.php 252 DIRTY_ATTR $env_id=$error_id."environment" +modules/gallery/views/error_admin.html.php 252 DIRTY_JS $env_id +modules/gallery/views/error_admin.html.php 254 DIRTY_ATTR $env_id +modules/gallery/views/error_admin.html.php 256 DIRTY_ATTR $env_id=$error_id."environment_included" +modules/gallery/views/error_admin.html.php 256 DIRTY_JS $env_id +modules/gallery/views/error_admin.html.php 256 DIRTY count($included) +modules/gallery/views/error_admin.html.php 257 DIRTY_ATTR $env_id +modules/gallery/views/error_admin.html.php 262 DIRTY Kohana_Exception::debug_path($file) +modules/gallery/views/error_admin.html.php 269 DIRTY_ATTR $env_id=$error_id."environment_loaded" +modules/gallery/views/error_admin.html.php 269 DIRTY_JS $env_id +modules/gallery/views/error_admin.html.php 269 DIRTY count($included) +modules/gallery/views/error_admin.html.php 270 DIRTY_ATTR $env_id +modules/gallery/views/error_admin.html.php 275 DIRTY Kohana_Exception::debug_path($file) +modules/gallery/views/error_admin.html.php 283 DIRTY_ATTR $env_id="$error_id.environment".strtolower($var) +modules/gallery/views/error_admin.html.php 284 DIRTY_JS $env_id +modules/gallery/views/error_admin.html.php 284 DIRTY $var +modules/gallery/views/error_admin.html.php 285 DIRTY_ATTR $env_id +modules/gallery/views/error_admin.html.php 291 DIRTY $key +modules/gallery/views/error_admin.html.php 295 DIRTY Kohana_Exception::safe_dump($value,$key) modules/gallery/views/form_uploadify.html.php 9 DIRTY_JS url::file("lib/uploadify/uploadify.swf") modules/gallery/views/form_uploadify.html.php 10 DIRTY_JS url::site("uploader/add_photo/{$album->id}") modules/gallery/views/form_uploadify.html.php 14 DIRTY_JS url::file("lib/uploadify/cancel.png") @@ -191,7 +193,6 @@ modules/gallery/views/l10n_client.html.php 62 DIRTY form:: modules/gallery/views/l10n_client.html.php 67 DIRTY form::textarea("l10n-edit-plural-translation-other","",' rows="2"') modules/gallery/views/login_ajax.html.php 6 DIRTY_JS url::site("password/reset") modules/gallery/views/login_ajax.html.php 44 DIRTY $form -modules/gallery/views/maintenance.html.php 46 DIRTY auth::get_login_form("login/auth_html") modules/gallery/views/menu.html.php 4 DIRTY $menu->css_id?"id='$menu->css_id'":"" modules/gallery/views/menu.html.php 4 DIRTY_ATTR $menu->css_class modules/gallery/views/menu.html.php 6 DIRTY $element->render() @@ -268,7 +269,7 @@ modules/gallery/views/user_profile.html.php 34 DIRTY_ATTR $use modules/gallery/views/user_profile.html.php 43 DIRTY $info->view modules/image_block/views/image_block_block.html.php 3 DIRTY_JS $item->url() modules/image_block/views/image_block_block.html.php 4 DIRTY $item->thumb_img(array("class"=>"g-thumbnail")) -modules/info/views/info_block.html.php 22 DIRTY date("M j, Y H:i:s",$item->captured) +modules/info/views/info_block.html.php 22 DIRTY gallery::date_time($item->captured) modules/info/views/info_block.html.php 29 DIRTY_JS $item->owner->url modules/notification/views/comment_published.html.php 28 DIRTY_JS $comment->item()->abs_url() modules/notification/views/comment_published.html.php 29 DIRTY $comment->item()->abs_url() @@ -295,6 +296,7 @@ modules/organize/views/organize_dialog.html.php 136 DIRTY_ATTR requ 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 +modules/rest/views/reset_api_key_confirm.html.php 6 DIRTY $form modules/rss/views/feed.mrss.php 10 DIRTY $feed->uri modules/rss/views/feed.mrss.php 13 DIRTY_JS $feed->uri modules/rss/views/feed.mrss.php 16 DIRTY_JS $feed->previous_page_uri @@ -368,8 +370,8 @@ themes/admin_wind/views/admin.html.php 61 DIRTY $theme themes/admin_wind/views/admin.html.php 68 DIRTY $content themes/admin_wind/views/admin.html.php 74 DIRTY $sidebar themes/admin_wind/views/admin.html.php 79 DIRTY $theme->admin_footer() -themes/admin_wind/views/admin.html.php 81 DIRTY $theme->admin_credits() -themes/admin_wind/views/admin.html.php 85 DIRTY $theme->admin_page_bottom() +themes/admin_wind/views/admin.html.php 82 DIRTY $theme->admin_credits() +themes/admin_wind/views/admin.html.php 87 DIRTY $theme->admin_page_bottom() themes/admin_wind/views/block.html.php 3 DIRTY_ATTR $anchor themes/admin_wind/views/block.html.php 5 DIRTY $id themes/admin_wind/views/block.html.php 5 DIRTY_ATTR $css_id diff --git a/modules/gallery/views/admin_maintenance.html.php b/modules/gallery/views/admin_maintenance.html.php index ad0e2f55..4bfc57f0 100644 --- a/modules/gallery/views/admin_maintenance.html.php +++ b/modules/gallery/views/admin_maintenance.html.php @@ -1,13 +1,29 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <div id="g-admin-maintenance" class="g-block"> - <h1> <?= t("Maintenance tasks") ?> </h1> - <p> - <?= t("Occasionally your Gallery will require some maintenance. Here are some tasks you can use to keep it running smoothly.") ?> - </p> + <h1> <?= t("Maintenance") ?> </h1> + <div class="g-block-content"> + <div id="g-maintenance-mode"> + <?= t("When you're performing maintenance on your Gallery, you can enable <b>maintenance mode</b> which prevents any non-admin from accessing your Gallery. Some of the tasks below will automatically put your Gallery in maintenance mode for you.") ?> + <ul id="g-action-status" class="g-message-block"> + <? if (module::get_var("gallery", "maintenance_mode")): ?> + <li class="g-warning"> + <?= t("Maintenance mode is <b>on</b>. Non admins cannot access your Gallery. <a href=\"%enable_maintenance_mode_url\">Turn off maintenance mode</a>", array("enable_maintenance_mode_url" => url::site("admin/maintenance/maintenance_mode/0?csrf=$csrf"))) ?> + </li> + <? else: ?> + <li class="g-info"> + <?= t("Maintenance mode is off. User access is permitted. <a href=\"%enable_maintenance_mode_url\">Turn on maintenance mode</a>", array("enable_maintenance_mode_url" => url::site("admin/maintenance/maintenance_mode/1?csrf=$csrf"))) ?> + </li> + <? endif ?> + </ul> + </div> + </div> <div class="g-block-content"> <div id="g-available-tasks"> - <h2> <?= t("Available tasks") ?> </h2> + <h2> <?= t("Maintenance tasks") ?> </h2> + <p> + <?= t("Occasionally your Gallery will require some maintenance. Here are some tasks you can use to keep it running smoothly.") ?> + </p> <table> <tr> <th> diff --git a/modules/gallery/views/admin_modules.html.php b/modules/gallery/views/admin_modules.html.php index 4d6fe5f0..f4ae965c 100644 --- a/modules/gallery/views/admin_modules.html.php +++ b/modules/gallery/views/admin_modules.html.php @@ -18,7 +18,7 @@ height: 400, width: 500, position: "center", - title: <?= t("Confirm Module Activation")->for_js() ?>, + title: <?= t("Confirm module activation")->for_js() ?>, buttons: { <?= t("Continue")->for_js() ?>: function() { $("form", this).submit(); diff --git a/modules/gallery/views/admin_theme_options.html.php b/modules/gallery/views/admin_theme_options.html.php index b4a90682..e452913e 100644 --- a/modules/gallery/views/admin_theme_options.html.php +++ b/modules/gallery/views/admin_theme_options.html.php @@ -1,35 +1,4 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> -<script type="text/javascript"> - $("#g-theme-options-form").ready(function() { - var contents = $("#g-theme-options-form fieldset:not(:last-child)"); - if (contents.length > 1) { - $("<div id='g-theme-options-form-tabs'>" + - " <ul class='tabnav'></ul>" + - "</div>").insertBefore("#g-theme-options-form fieldset:last-child"); - $(contents).each(function(index) { - var text = $("legend", this).text(); - var tabId = "tab_" + index; - var tabContentId = "tab_content_" + index; - if (text == "") { - text = <?= t("Tab_")->for_js() ?> + index; - } - $(".tabnav").append( - "<li><a id='" + tabId + "' href='#" + tabContentId + "'>" + text + "</a></li>"); - $("#g-theme-options-form-tabs").append( - "<div id='" + tabContentId + "' class='tabdiv'></div>"); - if ($("li.g-error", this).length > 0) { - $("#" + tabId).addClass("g-error"); - } - $("#" + tabContentId).append($("ul", this)); - $(this).remove(); - }); - $("#g-theme-options-form-tabs").tabs({}); - } else { - $("#g-theme-options-form fieldset:first legend").hide(); - } - }); -</script> - <div class="g-block"> <h1> <?= t("Theme options") ?> </h1> <div class="g-block-content"> diff --git a/modules/gallery/views/error_admin.html.php b/modules/gallery/views/error_admin.html.php index 40eb7374..af78c59c 100644 --- a/modules/gallery/views/error_admin.html.php +++ b/modules/gallery/views/error_admin.html.php @@ -20,7 +20,20 @@ margin: 20px auto; } - div#framework_error { + #framework_error { + height: 6em; + } + + #framework_error .crashlogo { + position: relative; + top: .3em; + font-size: 6.0em; + } + + #framework_error .title { + position: relative; + top: -2.5em; + padding: 0px; text-align: center; } @@ -102,8 +115,12 @@ .number { padding-right: 1em; } + + #g-platform h2, #g-stats h2 { + font-size: 1.1em; + } </style> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title><?= t("Something went wrong!") ?></title> <script type="text/javascript"> @@ -133,17 +150,34 @@ <body> <? try { $user = identity::active_user(); } catch (Exception $e) { } ?> <div class="big_box" id="framework_error"> - <h1> - <?= t("Dang... Something went wrong!") ?> - </h1> - <h2> - <?= t("We tried really hard, but it's broken.") ?> - </h2> + <div class="crashlogo"> + :-( + </div> + <div class="title"> + <h1> + <?= t("Dang... Something went wrong!") ?> + </h1> + <h2> + <?= t("We tried really hard, but it's broken.") ?> + </h2> + </div> </div> <div class="big_box" id="error_details"> <h2> <?= t("Hey wait, you're an admin! We can tell you stuff.") ?> </h2> + <p> + There's an error message below and you can find more details + in gallery3/var/logs (look for the file with the most recent + date on it). Stuck? Stop by the <a href="http://gallery.menalto.com/forum/96">Gallery 3 + Forums</a> and ask for help. You can also look at our list + of <a href="http://sourceforge.net/apps/trac/gallery/roadmap">open + tickets</a> to see if the problem you're seeing has been + reported. If you post a request, here's some useful + information to include: + <?= @gallery_block::get("platform_info") ?> + <?= @gallery_block::get("stats") ?> + </p> <div id="kohana_error"> <h3> <span class="type"> diff --git a/modules/gallery/views/error_user.html.php b/modules/gallery/views/error_user.html.php index 74c6a8fb..09ab752a 100644 --- a/modules/gallery/views/error_user.html.php +++ b/modules/gallery/views/error_user.html.php @@ -19,24 +19,42 @@ margin: 20px auto; } - div#framework_error { + #framework_error { + height: 8em; + } + + #framework_error .crashlogo { + position: relative; + top: .3em; + font-size: 6em; + } + + #framework_error .title { + position: relative; + top: -3em; text-align: center; + margin: 0 auto; } </style> - <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title><?= t("Something went wrong!") ?></title> </head> <body> <div class="big_box" id="framework_error"> - <h1> - <?= t("Dang... Something went wrong!") ?> - </h1> - <h2> - <?= t("We tried really hard, but it's broken.") ?> - </h2> - <p> - <?= t("Talk to your Gallery administrator for help fixing this!") ?> - </p> + <div class="crashlogo"> + :-( + </div> + <div class="title"> + <h1> + <?= t("Dang... Something went wrong!") ?> + </h1> + <h2> + <?= t("We tried really hard, but it's broken.") ?> + </h2> + <p> + <?= t("Talk to your Gallery administrator for help fixing this!") ?> + </p> + </div> </div> </body> </html> diff --git a/modules/gallery/views/form_uploadify.html.php b/modules/gallery/views/form_uploadify.html.php index 4f564b07..36f5f284 100644 --- a/modules/gallery/views/form_uploadify.html.php +++ b/modules/gallery/views/form_uploadify.html.php @@ -2,109 +2,162 @@ <script type="text/javascript" src="<?= url::file("lib/swfobject.js") ?>"></script> <script type="text/javascript" src="<?= url::file("lib/uploadify/jquery.uploadify.min.js") ?>"></script> <script type="text/javascript"> + <? $flash_minimum_version = "9.0.24" ?> + var success_count = 0; + var error_count = 0; + var updating = 0; $("#g-add-photos-canvas").ready(function () { - $("#g-uploadify").uploadify({ - width: 150, - height: 33, - uploader: "<?= url::file("lib/uploadify/uploadify.swf") ?>", - script: "<?= url::site("uploader/add_photo/{$album->id}") ?>", - scriptData: <?= json_encode($script_data) ?>, - fileExt: "*.gif;*.jpg;*.jpeg;*.png;*.flv;*.mp4;*.m4v;*.GIF;*.JPG;*.JPEG;*.PNG;*.FLV;*.MP4;*.M4V", - fileDesc: <?= t("Photos and movies")->for_js() ?>, - cancelImg: "<?= url::file("lib/uploadify/cancel.png") ?>", - simUploadLimit: <?= $simultaneous_upload_limit ?>, - wmode: "transparent", - hideButton: true, /* should be true */ - auto: true, - multi: true, - onAllComplete: function(filesUploaded, errors, allbytesLoaded, speed) { - $("#g-upload-cancel-all") - .addClass("ui-state-disabled") - .attr("disabled", "disabled"); - return true; - }, - onClearQueue: function(event) { - $("#g-upload-cancel-all") - .addClass("ui-state-disabled") - .attr("disabled", "disabled"); - return true; - }, - onComplete: function(event, queueID, fileObj, response, data) { - var re = /^error: (.*)$/i; - var msg = re.exec(response); - if (msg) { - $("#g-add-photos-status ul").append( - "<li class=\"g-error\">" + fileObj.name + " - " + msg[1] + "</li>"); - } else { - $("#g-add-photos-status ul").append( - "<li class=\"g-success\">" + fileObj.name + " - " + <?= t("Completed")->for_js() ?> + "</li>"); - } - return true; - }, - onError: function(event, queueID, fileObj, errorObj) { - var msg = " - "; - if (errorObj.type == "HTTP") { - if (errorObj.info == "500") { - msg += <?= t("Unable to process this file")->for_js() ?>; - // Server error - check server logs - } else if (errorObj.info == "404") { - msg += <?= t("The upload script was not found.")->for_js() ?>; - // Server script not found - } else { - // Server Error: status: errorObj.info - msg += (<?= t("Server error: __INFO__")->for_js() ?>.replace("__INFO__", errorObj.info)); - } - } else if (errorObj.type == "File Size") { - var sizelimit = $("#g-uploadify").uploadifySettings(sizeLimit); - msg += fileObj.name+' '+errorObj.type+' Limit: '+Math.round(d.sizeLimit/1024)+'KB'; - } else { - msg += (<?= t("Server error: __INFO__ (__TYPE__)")->for_js() ?> - .replace("__INFO__", errorObj.info) - .replace("__TYPE__", errorObj.type)); - } - $("#g-add-photos-status ul").append( - "<li class=\"g-error\">" + fileObj.name + msg + "</li>"); - $("#g-uploadify" + queueID).remove(); - }, - onSelect: function(event) { - if ($("#g-upload-cancel-all").hasClass("ui-state-disabled")) { + var update_status = function() { + if (updating) { + // poor man's mutex + setTimeout(function() { update_status(); }, 500); + } + updating = 1; + $.get("<?= url::site("uploader/status/_S/_E") ?>" + .replace("_S", success_count).replace("_E", error_count), + function(data) { + $("#g-add-photos-status-message").html(data); + updating = 0; + }); + }; + + if (swfobject.hasFlashPlayerVersion("<?= $flash_minimum_version ?>")) { + $("#g-uploadify").uploadify({ + width: 150, + height: 33, + uploader: "<?= url::file("lib/uploadify/uploadify.swf") ?>", + script: "<?= url::site("uploader/add_photo/{$album->id}") ?>", + scriptData: <?= json_encode($script_data) ?>, + fileExt: "*.gif;*.jpg;*.jpeg;*.png;*.GIF;*.JPG;*.JPEG;*.PNG<? if ($movies_allowed): ?>;*.flv;*.mp4;*.m4v;*.FLV;*.MP4;*.M4V<? endif ?>", + fileDesc: <?= t("Photos and movies")->for_js() ?>, + cancelImg: "<?= url::file("lib/uploadify/cancel.png") ?>", + simUploadLimit: <?= $simultaneous_upload_limit ?>, + wmode: "transparent", + hideButton: true, /* should be true */ + auto: true, + multi: true, + onAllComplete: function(filesUploaded, errors, allbytesLoaded, speed) { + $("#g-upload-cancel-all") + .addClass("ui-state-disabled") + .attr("disabled", "disabled"); + $("#g-upload-done") + .removeClass("ui-state-disabled") + .attr("disabled", null); + return true; + }, + onClearQueue: function(event) { $("#g-upload-cancel-all") + .addClass("ui-state-disabled") + .attr("disabled", "disabled"); + $("#g-upload-done") .removeClass("ui-state-disabled") .attr("disabled", null); + return true; + }, + onComplete: function(event, queueID, fileObj, response, data) { + var re = /^error: (.*)$/i; + var msg = re.exec(response); + $("#g-add-photos-status ul").append( + "<li id=\"q" + queueID + "\" class=\"g-success\">" + fileObj.name + " - " + + <?= t("Completed")->for_js() ?> + "</li>"); + setTimeout(function() { $("#q" + queueID).slideUp("slow") }, 5000); + success_count++; + update_status(); + return true; + }, + onError: function(event, queueID, fileObj, errorObj) { + var msg = " - "; + if (errorObj.type == "HTTP") { + if (errorObj.info == "500") { + msg += <?= t("Unable to process this file")->for_js() ?>; + // Server error - check server logs + } else if (errorObj.info == "404") { + msg += <?= t("The upload script was not found.")->for_js() ?>; + // Server script not found + } else { + // Server Error: status: errorObj.info + msg += (<?= t("Server error: __INFO__")->for_js() ?>.replace("__INFO__", errorObj.info)); + } + } else if (errorObj.type == "File Size") { + var sizelimit = $("#g-uploadify").uploadifySettings(sizeLimit); + msg += fileObj.name+' '+errorObj.type+' Limit: '+Math.round(d.sizeLimit/1024)+'KB'; + } else { + msg += (<?= t("Server error: __INFO__ (__TYPE__)")->for_js() ?> + .replace("__INFO__", errorObj.info) + .replace("__TYPE__", errorObj.type)); + } + $("#g-add-photos-status ul").append( + "<li class=\"g-error\">" + fileObj.name + msg + "</li>"); + $("#g-uploadify" + queueID).remove(); + error_count++; + update_status(); + }, + onSelect: function(event) { + if ($("#g-upload-cancel-all").hasClass("ui-state-disabled")) { + $("#g-upload-cancel-all") + .removeClass("ui-state-disabled") + .attr("disabled", null); + $("#g-upload-done") + .addClass("ui-state-disabled") + .attr("disabled", "disabled"); + } + return true; } - return true; - } - }); + }); + } else { + $(".requires-flash").hide(); + $(".no-flash").show(); + } }); </script> -<? if (ini_get("suhosin.session.encrypt")): ?> -<ul id="g-action-status" class="g-message-block"> - <li class="g-error"> - <?= t("Error: your server is configured to use the <a href=\"%encrypt_url\"><code>suhosin.session.encrypt</code></a> setting from <a href=\"%suhosin_url\">Suhosin</a>. You must disable this setting to upload photos.", - array("encrypt_url" => "http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.encrypt", - "suhosin_url" => "http://www.hardened-php.net/suhosin/")) ?> - </li> -</ul> -<? endif ?> +<div class="requires-flash"> + <? if ($suhosin_session_encrypt || !$movies_allowed): ?> + <div class="g-message-block g-info"> + <? if ($suhosin_session_encrypt): ?> + <p class="g-error"> + <?= t("Error: your server is configured to use the <a href=\"%encrypt_url\"><code>suhosin.session.encrypt</code></a> setting from <a href=\"%suhosin_url\">Suhosin</a>. You must disable this setting to upload photos.", + array("encrypt_url" => "http://www.hardened-php.net/suhosin/configuration.html#suhosin.session.encrypt", + "suhosin_url" => "http://www.hardened-php.net/suhosin/")) ?> + </p> + <? endif ?> -<div> - <p> - <?= t("Photos will be uploaded to album: ") ?> - </p> - <ul class="g-breadcrumbs ui-helper-clearfix"> - <? foreach ($album->parents() as $i => $parent): ?> - <li<? if ($i == 0) print " class=\"g-first\"" ?>> <?= html::clean($parent->title) ?> </li> - <? endforeach ?> - <li class="g-active"> <?= html::purify($album->title) ?> </li> - </ul> -</div> + <? if (!$movies_allowed): ?> + <p class="g-warning"> + <?= t("Can't find <i>ffmpeg</i> on your system. Movie uploading disabled. <a href=\"%help_url\">Help!</a>", array("help_url" => "http://codex.gallery2.org/Gallery3:FAQ#Why_does_it_say_I.27m_missing_ffmpeg.3F")) ?> + </p> + <? endif ?> + </div> + <? endif ?> + + <div> + <p> + <?= t("Photos will be uploaded to album: ") ?> + </p> + <ul class="g-breadcrumbs ui-helper-clearfix"> + <? foreach ($album->parents() as $i => $parent): ?> + <li<? if ($i == 0) print " class=\"g-first\"" ?>> <?= html::clean($parent->title) ?> </li> + <? endforeach ?> + <li class="g-active"> <?= html::purify($album->title) ?> </li> + </ul> + </div> -<div id="g-add-photos-canvas"> - <button id="g-add-photos-button" class="g-button ui-state-default ui-corner-all" href="#"><?= t("Select photos...") ?></button> - <span id="g-uploadify"></span> + <div id="g-add-photos-canvas"> + <button id="g-add-photos-button" class="g-button ui-state-default ui-corner-all" href="#"><?= t("Select photos...") ?></button> + <span id="g-uploadify"></span> + </div> + <div id="g-add-photos-status"> + <ul id="g-action-status" class="g-message-block"> + </ul> + </div> </div> -<div id="g-add-photos-status"> - <ul id="g-action-status" class="g-message-block"> - </ul> + +<div class="no-flash" style="display: none"> + <p> + <?= t("Your browser must have Adobe Flash Player version %flash_minimum_version or greater installed to use this feature.", array("flash_minimum_version" => $flash_minimum_version)) ?> + </p> + <a href="http://www.adobe.com/go/getflashplayer"> + <img src="<?= request::protocol() ?>://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" + alt=<?= t("Get Adobe Flash Player")->for_js() ?> /> + </a> </div> diff --git a/modules/gallery/views/form_uploadify_buttons.html.php b/modules/gallery/views/form_uploadify_buttons.html.php index d88bb6aa..e002d82d 100644 --- a/modules/gallery/views/form_uploadify_buttons.html.php +++ b/modules/gallery/views/form_uploadify_buttons.html.php @@ -1,8 +1,11 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> -<!-- Proxy the done request back to our form, since its been ajaxified --> -<button id="g-upload-done" class="ui-state-default ui-corner-all" onclick="$('#g-add-photos-form').submit();return false;"> +<div class="requires-flash"> + <!-- Proxy the done request back to our form, since its been ajaxified --> + <button id="g-upload-done" class="ui-state-default ui-corner-all" onclick="$('#g-add-photos-form').submit();return false;"> <?= t("Done") ?> -</button> -<button id="g-upload-cancel-all" class="ui-state-default ui-corner-all ui-state-disabled" onclick="$('#g-uploadify').uploadifyClearQueue();return false;" disabled="disabled"> - <?= t("Cancel All") ?> -</button> + </button> + <button id="g-upload-cancel-all" class="ui-state-default ui-corner-all ui-state-disabled" onclick="$('#g-uploadify').uploadifyClearQueue();return false;" disabled="disabled"> + <?= t("Cancel uploads") ?> + </button> + <span id="g-add-photos-status-message" /> +</div> diff --git a/modules/gallery/views/login_ajax.html.php b/modules/gallery/views/login_ajax.html.php index 88fe2389..a40d1950 100644 --- a/modules/gallery/views/login_ajax.html.php +++ b/modules/gallery/views/login_ajax.html.php @@ -43,7 +43,7 @@ <li id="g-login-form"> <?= $form ?> </li> - <? if (identity::is_writable()): ?> + <? if (identity::is_writable() && !module::get_var("gallery", "maintenance_mode")): ?> <li> <a href="#" id="g-password-reset" class="g-right g-text-small"><?= t("Forgot your password?") ?></a> </li> diff --git a/modules/gallery/views/maintenance.html.php b/modules/gallery/views/maintenance.html.php deleted file mode 100644 index 6351b6ab..00000000 --- a/modules/gallery/views/maintenance.html.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access.") ?> -<html> - <head> - <title> - <?= t("Gallery - maintenance mode") ?> - </title> - <style> - body { - background: #ccc; - } - form { - border: 1px solid #555; - background: #999; - width: 300px; - } - fieldset { - border: none; - } - fieldset legend { - font-size: 24px; - display: none !important; - padding-left: 0px; - } - ul { - list-style-type: none; - margin-top: 0px; - padding-left: 0px; - bullet-style: none; - } - ul li { - margin-left: 0px; - } - label { - width: 60px; - display: block; - } - </style> - </head> - <body> - <h1> - <?= t("Gallery - maintenance mode") ?> - </h1> - <p> - <?= t("This site is currently only accessible by site administrators.") ?> - </p> - <?= auth::get_login_form("login/auth_html") ?> - </body> -</html> - - diff --git a/modules/gallery/views/move_browse.html.php b/modules/gallery/views/move_browse.html.php deleted file mode 100644 index f77c724c..00000000 --- a/modules/gallery/views/move_browse.html.php +++ /dev/null @@ -1,50 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access.") ?> -<div> -<script type="text/javascript"> - var load_tree = function(target_id, locked) { - var load_url = "<?= url::site("move/show_sub_tree/{$source->id}/__TARGETID__") ?>"; - var node = $("#node_" + target_id); - $("#g-move .node a").removeClass("selected"); - node.find("a:first").addClass("selected"); - if (locked) { - $("#g-move-button").attr("disabled", "disabled"); - $("#g-move form input[name=target_id]").attr("value", ""); - } else { - $("#g-move-button").removeAttr("disabled"); - $("#g-move form input[name=target_id]").attr("value", target_id); - } - var sub_tree = $("#tree_" + target_id); - if (sub_tree.length) { - sub_tree.toggle(); - } else { - $.get(load_url.replace("__TARGETID__", target_id), {}, - function(data) { - node.html(data); - node.find("a:first").addClass("selected"); - }); - } - } -</script> -<h1 style="display:none" > - <? if ($source->type == "photo"): ?> - <?= t("Move this photo to a new album") ?> - <? elseif ($source->type == "movie"): ?> - <?= t("Move this movie to a new album") ?> - <? elseif ($source->type == "album"): ?> - <?= t("Move this album to a new album") ?> - <? endif ?> -</h1> -<div id="g-move"> - <ul id="tree_0"> - <li id="node_1" class="node"> - <?= $tree ?> - </li> - </ul> - <form method="post" action="<?= url::site("move/save/$source->id") ?>"> - <?= access::csrf_form_field() ?> - <input type="hidden" name="target_id" value="" /> - <input type="submit" id="g-move-button" value="<?= t("Move")->for_html_attr() ?>" - disabled="disabled" class="submit" /> - </form> -</div> -</div> diff --git a/modules/gallery/views/move_tree.html.php b/modules/gallery/views/move_tree.html.php deleted file mode 100644 index e629e1bb..00000000 --- a/modules/gallery/views/move_tree.html.php +++ /dev/null @@ -1,19 +0,0 @@ -<?php defined("SYSPATH") or die("No direct script access.") ?> -<?= $parent->thumb_img(array(), 25); ?> -<? if (!access::can("edit", $parent) || $source->contains($parent)): ?> -<a href="javascript:load_tree('<?= $parent->id ?>',1)"> <?= html::clean($parent->title) ?> <?= t("(locked)") ?> </a> -<? else: ?> -<a href="javascript:load_tree('<?= $parent->id ?>',0)"> <?= html::clean($parent->title) ?></a> -<? endif ?> -<ul id="tree_<?= $parent->id ?>"> - <? foreach ($children as $child): ?> - <li id="node_<?= $child->id ?>" class="node"> - <?= $child->thumb_img(array(), 25); ?> - <? if (!access::can("edit", $child) || $source->contains($child)): ?> - <a href="javascript:load_tree('<?= $child->id ?>',1)"> <?= html::clean($child->title) ?> <?= t("(locked)") ?></a> - <? else: ?> - <a href="javascript:load_tree('<?= $child->id ?>',0)"> <?= html::clean($child->title) ?> </a> - <? endif ?> - </li> - <? endforeach ?> -</ul> diff --git a/modules/gallery_unit_test/views/kohana_unit_test_cli.php b/modules/gallery_unit_test/views/kohana_unit_test_cli.php index a0de0f52..61dae7dd 100644 --- a/modules/gallery_unit_test/views/kohana_unit_test_cli.php +++ b/modules/gallery_unit_test/views/kohana_unit_test_cli.php @@ -71,7 +71,7 @@ foreach ($results as $class => $methods) { } echo "+", str_repeat("=", 87), "+", str_repeat("=", 10), "+\n"; - printf("| %-40.40s %-13.13s %-13.13s %-13.13s %-13.13s |\n", + printf("| %-40.40s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s |\n", $class, "Score: {$stats[$class]['score']}", "Total: {$stats[$class]['total']}", @@ -81,7 +81,7 @@ foreach ($results as $class => $methods) { echo "+", str_repeat("=", 98), "+\n\n\n"; } -printf(" %-40.40s %-13.13s %-13.13s %-13.13s %-13.13s\n", +printf(" %-40.40s %-10.10s %-10.10s %-10.10s %-10.10s %-10.10s\n", "TOTAL", "Score: " . ($totals["total"] ? 100 * ($totals["passed"] / $totals["total"]) : 0), "Total: {$totals['total']}", diff --git a/modules/info/views/info_block.html.php b/modules/info/views/info_block.html.php index ac177ee7..ebe9bd28 100644 --- a/modules/info/views/info_block.html.php +++ b/modules/info/views/info_block.html.php @@ -19,7 +19,7 @@ <? if ($item->captured): ?> <li> <strong class="caption"><?= t("Captured:") ?></strong> - <?= date("M j, Y H:i:s", $item->captured)?> + <?= gallery::date_time($item->captured)?> </li> <? endif ?> <? if ($item->owner): ?> diff --git a/modules/notification/helpers/notification.php b/modules/notification/helpers/notification.php index 0cf536bc..e4212203 100644 --- a/modules/notification/helpers/notification.php +++ b/modules/notification/helpers/notification.php @@ -185,7 +185,7 @@ class notification { ->to($email) ->subject($pending->subject) ->header("Mime-Version", "1.0") - ->header("Content-type", "text/html; charset=utf-8") + ->header("Content-Type", "text/html; charset=UTF-8") ->message($pending->body) ->send(); $pending->delete(); @@ -199,7 +199,7 @@ class notification { ->to($email) ->subject(t("Multiple events have occurred")) // @todo fix this terrible subject line ->header("Mime-Version", "1.0") - ->header("Content-type", "text/html; charset=utf-8") + ->header("Content-Type", "text/html; charset=UTF-8") ->message($text) ->send(); } @@ -213,7 +213,7 @@ class notification { ->to($subscribers) ->subject($subject) ->header("Mime-Version", "1.0") - ->header("Content-type", "text/html; charset=utf-8") + ->header("Content-Type", "text/html; charset=UTF-8") ->message($text) ->send(); } else { diff --git a/modules/notification/helpers/notification_event.php b/modules/notification/helpers/notification_event.php index df9dbe48..5cd10de8 100644 --- a/modules/notification/helpers/notification_event.php +++ b/modules/notification/helpers/notification_event.php @@ -21,15 +21,6 @@ class notification_event_Core { // The assumption is that the exception was logged at a lower level, but we // don't want to screw up the processing that was generating the notification // so we don't pass the exception up the call stack - static function item_updated($original, $new) { - try { - notification::send_item_updated($original, $new); - } catch (Exception $e) { - Kohana_Log::add("error", "@todo notification_event::item_updated() failed"); - Kohana_Log::add("error", $e->getMessage() . "\n" . $e->getTraceAsString()); - } - } - static function item_created($item) { try { notification::send_item_add($item); diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 3005eb67..2b6e4186 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -31,18 +31,18 @@ class Organize_Controller extends Controller { $sort_fields[$field] = (string)$description; } $sort_order = array("ASC" => (string)t("Ascending"), "DESC" => (string)t("Descending")); - $file_filter = json_encode( - array("photo" => array("label" => "Images", - "types" => array("*.jpg", "*.jpeg", "*.png", "*.gif")), - "movie" => array("label" => "Movies", "types" => array("*.flv", "*.mp4", "*.m4v")))); + $file_filter = json_encode(array( + "photo" => array("label" => "Images", "types" => array("*.jpg", "*.jpeg", "*.png", "*.gif")), + "movie" => array("label" => "Movies", "types" => array("*.flv", "*.mp4", "*.m4v")))); $v = new View("organize_dialog.html"); $v->album = $album; - $v->domain = $input->server("SERVER_NAME"); + $v->domain = $input->server("HTTP_HOST"); $v->access_key = rest::access_key(); $v->file_filter = addslashes($file_filter); $v->sort_order = addslashes(json_encode($sort_order)); $v->sort_fields = addslashes(json_encode($sort_fields)); + $v->selected_id = Input::instance()->get("selected_id", null); $v->rest_uri = url::site("rest") . "/"; $v->controller_uri = url::site("organize") . "/"; $v->swf_uri = url::file("modules/organize/lib/Gallery3WebClient.swf?") . diff --git a/modules/organize/helpers/organize_event.php b/modules/organize/helpers/organize_event.php index ae05fb5d..2f997600 100644 --- a/modules/organize/helpers/organize_event.php +++ b/modules/organize/helpers/organize_event.php @@ -32,13 +32,23 @@ class organize_event_Core { } static function context_menu($menu, $theme, $item) { - if ($item->is_album() && access::can("edit", $item)) { - $menu->get("options_menu") - ->append(Menu::factory("dialog") - ->id("organize") - ->label(t("Organize album")) - ->css_class("ui-icon-folder-open g-organize-link") - ->url(url::site("organize/dialog/{$item->id}"))); + if (access::can("edit", $item)) { + if ($item->is_album()) { + $menu->get("options_menu") + ->append(Menu::factory("dialog") + ->id("organize") + ->label(t("Organize album")) + ->css_class("ui-icon-folder-open g-organize-link") + ->url(url::site("organize/dialog/{$item->id}"))); + } else { + $parent = $item->parent(); + $menu->get("options_menu") + ->append(Menu::factory("dialog") + ->id("move") + ->label(t("Move to another album")) + ->css_class("ui-icon-folder-open g-organize-link") + ->url(url::site("organize/dialog/{$parent->id}?selected_id={$item->id}"))); + } } } @@ -51,8 +61,7 @@ class organize_event_Core { static function module_change($changes) { if (!module::is_active("rest") || in_array("rest", $changes->deactivate)) { site_status::warning( - t("The Organize module requires the Rest module. " . - "<a href=\"%url\">Activate the Rest module now</a>", + t("The Organize module requires the Rest module. <a href=\"%url\">Activate the Rest module now</a>", array("url" => html::mark_clean(url::site("admin/modules")))), "organize_needs_rest"); } else { diff --git a/modules/organize/helpers/organize_installer.php b/modules/organize/helpers/organize_installer.php index bbe6fc65..2faa598b 100644 --- a/modules/organize/helpers/organize_installer.php +++ b/modules/organize/helpers/organize_installer.php @@ -22,12 +22,15 @@ class organize_installer { site_status::clear("organize_needs_rest"); } + static function install() { + module::set_version("organize", $version = 2); + } + static function upgrade($version) { if ($version == 1) { if (!module::is_active("rest")) { site_status::warning( - t("The Organize module requires the Rest module. " . - "<a href=\"%url\">Activate the Rest module now</a>", + t("The Organize module requires the Rest module. <a href=\"%url\">Activate the Rest module now</a>", array("url" => html::mark_clean(url::site("admin/modules")))), "organize_needs_rest"); } diff --git a/modules/organize/lib/Gallery3WebClient.swf b/modules/organize/lib/Gallery3WebClient.swf Binary files differindex 40249a73..b82c8a42 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 4cc6385e..b76813ad 100644 --- a/modules/organize/views/organize_dialog.html.php +++ b/modules/organize/views/organize_dialog.html.php @@ -1,10 +1,6 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> <script type="text/javascript" src="<?= url::file("lib/swfobject.js") ?>"></script> <style type="text/css" media="screen"> - #flashContent { - //display:none; - } - .g-organize { padding: 0; margins: 0; @@ -21,10 +17,10 @@ </style> <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(); - }); + $("#g-dialog").bind("dialogclose", function(event, ui) { + // @todo do a call to organize/closing to end the batch + window.location.reload(); + }); function closeOrganizeDialog() { $("#g-dialog").dialog("close"); @@ -94,6 +90,7 @@ sortOrder: "<?= $sort_order ?>", sortFields: "<?= $sort_fields ?>", albumId: "<?= $album->id ?>", + selectedId: "<?= $selected_id ?>", restUri: "<?= $rest_uri ?>", controllerUri: "<?= $controller_uri ?>" }; @@ -129,8 +126,7 @@ <h1 style="display:none"><?= t("Organize :: %name", array("name" => html::purify($album->title))) ?></h1> <div id="flashContent"> <p> - <?= t("To use the Organize feature, please ensure that Adobe Flash Player version %flash_minimum_version " . - "or greater is installed.", array("flash_minimum_version" => $flash_minimum_version)) ?> + <?= t("Your browser must have Adobe Flash Player version %flash_minimum_version or greater installed to use this feature.", array("flash_minimum_version" => $flash_minimum_version)) ?> </p> <a href="http://www.adobe.com/go/getflashplayer"> <img src="<?= request::protocol() ?>://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" diff --git a/modules/recaptcha/helpers/recaptcha_event.php b/modules/recaptcha/helpers/recaptcha_event.php index fda998e1..f185f92b 100644 --- a/modules/recaptcha/helpers/recaptcha_event.php +++ b/modules/recaptcha/helpers/recaptcha_event.php @@ -18,21 +18,17 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class recaptcha_event_Core { - static function user_profile_contact_form($form) { + static function captcha_protect_form($form) { if (module::get_var("recaptcha", "public_key")) { - $form->message->recaptcha("recaptcha")->label("")->id("g-recaptcha"); - } - } + foreach ($form->inputs as $input) { + if ($input instanceof Form_Group) { + $input->recaptcha("recaptcha")->label("")->id("g-recaptcha"); + return; + } + } - static function comment_add_form($form) { - if (module::get_var("recaptcha", "public_key")) { - $form->add_comment->recaptcha("recaptcha")->label("")->id("g-recaptcha"); - } - } - - static function register_add_form($form) { - if (module::get_var("recaptcha", "public_key")) { - $form->register_user->recaptcha("recaptcha")->label("")->id("g-recaptcha"); + // If we haven't returned yet, then add the captcha at the end of the form + $form->recaptcha("recaptcha")->label("")->id("g-recaptcha"); } } diff --git a/modules/rest/controllers/rest.php b/modules/rest/controllers/rest.php index bf2f0a54..a721ff2b 100644 --- a/modules/rest/controllers/rest.php +++ b/modules/rest/controllers/rest.php @@ -37,6 +37,22 @@ class Rest_Controller extends Controller { rest::reply(rest::access_key()); } + public function reset_api_key_confirm() { + $form = new Forge("rest/reset_api_key", "", "post", array("id" => "g-reset-api-key")); + $group = $form->group("confirm_reset")->label(t("Confirm resetting your REST API key")); + $group->submit("")->value(t("Reset")); + $v = new View("reset_api_key_confirm.html"); + $v->form = $form; + print $v; + } + + public function reset_api_key() { + access::verify_csrf(); + rest::reset_access_key(); + message::success(t("Your REST API key has been reset.")); + json::reply(array("result" => "success")); + } + public function __call($function, $args) { try { $input = Input::instance(); diff --git a/modules/gallery/controllers/maintenance.php b/modules/rest/helpers/registry_rest.php index 27673ff0..e9c8b955 100644 --- a/modules/gallery/controllers/maintenance.php +++ b/modules/rest/helpers/registry_rest.php @@ -17,8 +17,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Maintenance_Controller extends Controller { - function index() { - print new View("maintenance.html"); - } -}
\ No newline at end of file +class registry_rest_Core { + static function get($request) { + $results = array(); + foreach (module::active() as $module) { + foreach (glob(MODPATH . "{$module->name}/helpers/*_rest.php") as $filename) { + $results[] = str_replace("_rest.php", "", basename($filename)); + } + } + return array_unique($results); + } +} diff --git a/modules/rest/helpers/rest.php b/modules/rest/helpers/rest.php index 644779da..d5ed0452 100644 --- a/modules/rest/helpers/rest.php +++ b/modules/rest/helpers/rest.php @@ -24,8 +24,28 @@ class rest_Core { Session::instance()->abort_save(); header("X-Gallery-API-Version: " . rest::API_VERSION); - if (Input::instance()->get("output") == "html") { - header("Content-type: text/html"); + switch (Input::instance()->get("output", "json")) { + case "json": + json::reply($data); + break; + + case "jsonp": + if (!($callback = Input::instance()->get("callback", ""))) { + throw new Rest_Exception( + "Bad Request", 400, array("errors" => array("callback" => "missing"))); + } + + if (preg_match('/^[$A-Za-z_][0-9A-Za-z_]*$/', $callback) == 1) { + header("Content-type: application/javascript; charset=UTF-8"); + print "$callback(" . json_encode($data) . ")"; + } else { + throw new Rest_Exception( + "Bad Request", 400, array("errors" => array("callback" => "invalid"))); + } + break; + + case "html": + header("Content-type: text/html; charset=UTF-8"); if ($data) { $html = preg_replace( "#([\w]+?://[\w]+[^ \'\"\n\r\t<]*)#ise", "'<a href=\"\\1\" >\\1</a>'", @@ -34,8 +54,10 @@ class rest_Core { $html = t("Empty response"); } print "<pre>$html</pre>"; - } else { - json::reply($data); + break; + + default: + throw new Rest_Exception("Bad Request", 400); } } @@ -65,6 +87,16 @@ class rest_Core { identity::set_active_user($user); } + static function reset_access_key() { + $key = ORM::factory("user_access_key") + ->where("user_id", "=", identity::active_user()->id) + ->find(); + if ($key->loaded()) { + $key->delete(); + } + return rest::access_key(); + } + static function access_key() { $key = ORM::factory("user_access_key") ->where("user_id", "=", identity::active_user()->id) diff --git a/modules/rest/helpers/rest_event.php b/modules/rest/helpers/rest_event.php index f23b9a58..d8c69e94 100644 --- a/modules/rest/helpers/rest_event.php +++ b/modules/rest/helpers/rest_event.php @@ -55,13 +55,6 @@ class rest_event { } /** - * Called when user is editing their own form - */ - static function user_edit_form($user, $form) { - self::_get_access_key_form($user, $form); - } - - /** * Get the form fields for user edit */ static function _get_access_key_form($user, $form) { @@ -104,6 +97,6 @@ class rest_event { $key->save(); } $view->rest_key = $key->access_key; - $data->content[] = (object)array("title" => t("REST api"), "view" => $view); + $data->content[] = (object)array("title" => t("REST API"), "view" => $view); } } diff --git a/modules/rest/views/reset_api_key_confirm.html.php b/modules/rest/views/reset_api_key_confirm.html.php new file mode 100644 index 00000000..3aae2a9a --- /dev/null +++ b/modules/rest/views/reset_api_key_confirm.html.php @@ -0,0 +1,7 @@ +<?php defined("SYSPATH") or die("No direct script access.") ?> +<div id="g-rest-reset-api-key" class="ui-helper-clearfix"> + <p> + <?= t("Do you really want to reset your REST API key? Any clients that use this key will need to be updated with the new value.") ?> + </p> + <?= $form ?> +</div> diff --git a/modules/rest/views/user_profile_rest.html.php b/modules/rest/views/user_profile_rest.html.php index e81f3d0b..3e5d3dbf 100644 --- a/modules/rest/views/user_profile_rest.html.php +++ b/modules/rest/views/user_profile_rest.html.php @@ -4,6 +4,9 @@ <li id="g-rest-key"> <p> <?= t("<b>Key</b>: %key", array("key" => $rest_key)) ?> + <a class="g-button ui-state-default ui-corner-all g-dialog-link" href="<?= url::site("rest/reset_api_key_confirm") ?>"> + <?= t("reset") ?> + </a> </p> </li> </ul> diff --git a/modules/search/views/search.html.php b/modules/search/views/search.html.php index 2e139ecf..3436a00c 100644 --- a/modules/search/views/search.html.php +++ b/modules/search/views/search.html.php @@ -8,10 +8,10 @@ <ul> <li> <label for="q"><?= t("Search the gallery") ?></label> - <input name="q" id="q" type="text" value="<?= html::clean_attribute($q) ?>"/> + <input name="q" id="q" type="text" value="<?= html::clean_attribute($q) ?>" class="text" /> </li> <li> - <input type="submit" value="<?= t("Search")->for_html_attr() ?>" /> + <input type="submit" value="<?= t("Search")->for_html_attr() ?>" class="submit" /> </li> </ul> </fieldset> diff --git a/modules/search/views/search_link.html.php b/modules/search/views/search_link.html.php index 481d0c82..dd3a76a4 100644 --- a/modules/search/views/search_link.html.php +++ b/modules/search/views/search_link.html.php @@ -3,10 +3,10 @@ <ul> <li> <label for="g-search"><?= t("Search the gallery") ?></label> - <input type="text" name="q" id="g-search"/> + <input type="text" name="q" id="g-search" class="text" /> </li> <li> - <input type="submit" value="<?= t("Go")->for_html_attr() ?>" /> + <input type="submit" value="<?= t("Go")->for_html_attr() ?>" class="submit" /> </li> </ul> </form> diff --git a/modules/server_add/helpers/server_add_event.php b/modules/server_add/helpers/server_add_event.php index 631af02f..fd4ade71 100644 --- a/modules/server_add/helpers/server_add_event.php +++ b/modules/server_add/helpers/server_add_event.php @@ -22,7 +22,7 @@ class server_add_event_Core { $menu->get("settings_menu") ->append(Menu::factory("link") ->id("server_add") - ->label(t("Server Add")) + ->label(t("Server add")) ->url(url::site("admin/server_add"))); } @@ -35,7 +35,7 @@ class server_add_event_Core { $menu->get("add_menu") ->append(Menu::factory("dialog") ->id("server_add") - ->label(t("Server Add")) + ->label(t("Server add")) ->url(url::site("server_add/browse/$item->id"))); } } diff --git a/modules/slideshow/helpers/slideshow_event.php b/modules/slideshow/helpers/slideshow_event.php index 6cb5d019..167fa7ff 100644 --- a/modules/slideshow/helpers/slideshow_event.php +++ b/modules/slideshow/helpers/slideshow_event.php @@ -27,8 +27,7 @@ class slideshow_event_Core { static function module_change($changes) { if (!module::is_active("rss") || in_array("rss", $changes->deactivate)) { site_status::warning( - t("The Slideshow module requires the RSS module. " . - "<a href=\"%url\">Activate the RSS module now</a>", + t("The Slideshow module requires the RSS module. <a href=\"%url\">Activate the RSS module now</a>", array("url" => html::mark_clean(url::site("admin/modules")))), "slideshow_needs_rss"); } else { diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index 575720a8..2e5eac5f 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -61,7 +61,7 @@ class Password_Controller extends Controller { ->to($user->email) ->subject(t("Password Reset Request")) ->header("Mime-Version", "1.0") - ->header("Content-type", "text/html; charset=iso-8859-1") + ->header("Content-type", "text/html; charset=UTF-8") ->message($message->render()) ->send(); diff --git a/modules/user/controllers/users.php b/modules/user/controllers/users.php index d13cccb2..6bb4967f 100644 --- a/modules/user/controllers/users.php +++ b/modules/user/controllers/users.php @@ -41,7 +41,7 @@ class Users_Controller extends Controller { // Translate ORM validation errors into form error messages foreach ($e->validation->errors() as $key => $error) { $form->edit_user->inputs[$key]->add_error($error, 1); - } + } $valid = false; } @@ -55,7 +55,7 @@ class Users_Controller extends Controller { module::event("user_edit_form_completed", $user, $form); message::success(t("User information updated")); json::reply(array("result" => "success", - "resource" => url::site("users/{$user->id}"))); + "resource" => url::site("users/{$user->id}"))); } else { json::reply(array("result" => "error", "html" => (string)$form)); } @@ -87,7 +87,7 @@ class Users_Controller extends Controller { module::event("user_auth", $user); module::event("user_password_change", $user); json::reply(array("result" => "success", - "resource" => url::site("users/{$user->id}"))); + "resource" => url::site("users/{$user->id}"))); } else { log::warning("user", t("Failed password change for %name", array("name" => $user->name))); $name = $user->name; @@ -121,7 +121,7 @@ class Users_Controller extends Controller { message::success(t("Email address changed")); module::event("user_auth", $user); json::reply(array("result" => "success", - "resource" => url::site("users/{$user->id}"))); + "resource" => url::site("users/{$user->id}"))); } else { log::warning("user", t("Failed email change for %name", array("name" => $user->name))); $name = $user->name; @@ -189,7 +189,7 @@ class Users_Controller extends Controller { $group->password("password")->label(t("Current password"))->id("g-password") ->callback("auth::validate_too_many_failed_auth_attempts") ->callback("user::valid_password") - ->error_messages("invalid", t("Incorrect password")) + ->error_messages("invalid_password", t("Incorrect password")) ->error_messages( "too_many_failed_auth_attempts", t("Too many incorrect passwords. Try again later")); |