diff options
86 files changed, 710 insertions, 549 deletions
@@ -24,7 +24,7 @@ # in your Apache2 config file before you uncomment this block or # you'll get an "Internal Server Error". # -# <FilesMatch "(\.(class|fla|inc|sql|txt|gitignore)|(README|LICENSE))$"> +# <FilesMatch "(\.(class|fla|gitignore|inc|ini|sql|txt)|(README|LICENSE))$"> # Order deny,allow # Deny from all # </FilesMatch> @@ -8,22 +8,19 @@ can easily create and share albums of photos via an intuitive interface. -SECURITY (& INTENDED AUDIENCE): -This is the second (and hopefully final) release candidate of Gallery -3.0. We're putting it out there so that we can find out if we -overlooked any small things. We expect the final version to be -virtually identical. You can install it on public websites and use it -freely -- we recommend it! - -Note: - - We've contracted a professional security audit, received their results - and resolved all the issues they found. - - You can upgrade from beta 1, but not from alpha releases. - -This version is intended for broad distribution. We stand ready to -support the product and help you to make the most of it. We welcome -theme and module developers to play with this release and start -turning out slick new designs for our happy users. +INTENDED AUDIENCE: +This version is intended for anybody who has a website. We stand +ready to support the product and help you to make the most of it. We +welcome theme and module developers to play with this release and +start turning out slick new designs for our happy users. If you have +questions or problems, you can get help in the Gallery forums: + + http://gallery.menalto.com/forum/96 + + +SECURITY: +We've contracted a professional security audit, received their results +and resolved all the issues they found. Did you find a security flaw? Please email security@gallery.menalto.com with the details and we'll fix it ASAP! @@ -37,6 +34,14 @@ SUPPORTED CONFIGURATION: - Database: MySQL 5 and newer. +INSTALLING AND UPGRADING INSTRUCTIONS: +For comprehensive instructions, The online User Guide is your best resource: + http://codex.gallery2.org/Gallery3:User_guide + +There are also simple instructions below. NOTE: You can upgrade from +beta 1 and beyond, but not from alpha releases. + + INSTALLATION VIA THE WEB: - Point your web browser at gallery3/installer/ and follow the instructions. @@ -56,7 +61,7 @@ INSTALLATION FROM THE COMMAND LINE: BUGS? Go to http://apps.sourceforge.net/trac/gallery/ click the "login" link and log in with your SourceForge username and password, then click the -"new ticket" button. Mark any issues you find with the "3.0" +"new ticket" button. Mark any issues you find with the "3.1" milestone and we'll try to get 'em done for the next release. diff --git a/installer/install.sql b/installer/install.sql index 52654faf..427a3283 100644 --- a/installer/install.sql +++ b/installer/install.sql @@ -244,7 +244,7 @@ CREATE TABLE {modules} ( KEY `weight` (`weight`) ) AUTO_INCREMENT=11 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; -INSERT INTO {modules} VALUES (1,1,'gallery',40,1); +INSERT INTO {modules} VALUES (1,1,'gallery',41,1); INSERT INTO {modules} VALUES (2,1,'user',3,2); INSERT INTO {modules} VALUES (3,1,'comment',3,3); INSERT INTO {modules} VALUES (4,1,'organize',2,4); @@ -395,7 +395,7 @@ CREATE TABLE {vars} ( `value` text, PRIMARY KEY (`id`), UNIQUE KEY `module_name` (`module_name`,`name`) -) AUTO_INCREMENT=51 DEFAULT CHARSET=utf8; +) AUTO_INCREMENT=35 DEFAULT CHARSET=utf8; /*!40101 SET character_set_client = @saved_cs_client */; INSERT INTO {vars} VALUES (NULL,'gallery','active_site_theme','wind'); INSERT INTO {vars} VALUES (NULL,'gallery','active_admin_theme','admin_wind'); @@ -405,29 +405,29 @@ INSERT INTO {vars} VALUES (NULL,'gallery','resize_size','640'); INSERT INTO {vars} VALUES (NULL,'gallery','default_locale','en_US'); INSERT INTO {vars} VALUES (NULL,'gallery','image_quality','75'); INSERT INTO {vars} VALUES (NULL,'gallery','image_sharpen','15'); +INSERT INTO {vars} VALUES (NULL,'gallery','blocks_dashboard_sidebar','a:4:{i:2;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"block_adder\";}i:3;a:2:{i:0;s:7:\"gallery\";i:1;s:5:\"stats\";}i:4;a:2:{i:0;s:7:\"gallery\";i:1;s:13:\"platform_info\";}i:5;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"project_news\";}}'); +INSERT INTO {vars} VALUES (NULL,'gallery','blocks_dashboard_center','a:3:{i:6;a:2:{i:0;s:7:\"gallery\";i:1;s:7:\"welcome\";}i:7;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"photo_stream\";}i:8;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"log_entries\";}}'); +INSERT INTO {vars} VALUES (NULL,'gallery','choose_default_tookit','1'); +INSERT INTO {vars} VALUES (NULL,'gallery','date_format','Y-M-d'); +INSERT INTO {vars} VALUES (NULL,'gallery','date_time_format','Y-M-d H:i:s'); INSERT INTO {vars} VALUES (NULL,'gallery','time_format','H:i:s'); INSERT INTO {vars} VALUES (NULL,'gallery','show_credits','1'); INSERT INTO {vars} VALUES (NULL,'gallery','credits','Powered by <a href=\"%url\">%gallery_version</a>'); INSERT INTO {vars} VALUES (NULL,'gallery','simultaneous_upload_limit','5'); INSERT INTO {vars} VALUES (NULL,'gallery','admin_area_timeout','5400'); INSERT INTO {vars} VALUES (NULL,'gallery','maintenance_mode','0'); -INSERT INTO {vars} VALUES (NULL,'gallery','blocks_dashboard_sidebar','a:4:{i:2;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"block_adder\";}i:3;a:2:{i:0;s:7:\"gallery\";i:1;s:5:\"stats\";}i:4;a:2:{i:0;s:7:\"gallery\";i:1;s:13:\"platform_info\";}i:5;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"project_news\";}}'); INSERT INTO {vars} VALUES (NULL,'gallery','visible_title_length','15'); -INSERT INTO {vars} VALUES (NULL,'gallery','date_time_format','Y-M-d H:i:s'); INSERT INTO {vars} VALUES (NULL,'gallery','favicon_url','lib/images/favicon.ico'); -INSERT INTO {vars} VALUES (NULL,'gallery','date_format','Y-M-d'); -INSERT INTO {vars} VALUES (NULL,'gallery','blocks_dashboard_center','a:3:{i:6;a:2:{i:0;s:7:\"gallery\";i:1;s:7:\"welcome\";}i:7;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"photo_stream\";}i:8;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"log_entries\";}}'); INSERT INTO {vars} VALUES (NULL,'gallery','email_from','unknown@unknown.com'); INSERT INTO {vars} VALUES (NULL,'gallery','email_reply_to','unknown@unknown.com'); -INSERT INTO {vars} VALUES (NULL,'gallery','choose_default_tookit','1'); INSERT INTO {vars} VALUES (NULL,'gallery','email_line_length','70'); INSERT INTO {vars} VALUES (NULL,'gallery','email_header_separator','s:1:\"\n\";'); INSERT INTO {vars} VALUES (NULL,'gallery','show_user_profiles_to','registered_users'); INSERT INTO {vars} VALUES (NULL,'gallery','extra_binary_paths','/usr/local/bin:/opt/local/bin:/opt/bin'); -INSERT INTO {vars} VALUES (NULL,'comment','spam_caught','0'); -INSERT INTO {vars} VALUES (NULL,'comment','access_permissions','everybody'); INSERT INTO {vars} VALUES (NULL,'gallery','blocks_site_sidebar','a:4:{i:9;a:2:{i:0;s:7:\"gallery\";i:1;s:8:\"language\";}i:10;a:2:{i:0;s:4:\"info\";i:1;s:8:\"metadata\";}i:11;a:2:{i:0;s:3:\"rss\";i:1;s:9:\"rss_feeds\";}i:12;a:2:{i:0;s:3:\"tag\";i:1;s:3:\"tag\";}}'); INSERT INTO {vars} VALUES (NULL,'gallery','identity_provider','user'); INSERT INTO {vars} VALUES (NULL,'user','mininum_password_length','5'); +INSERT INTO {vars} VALUES (NULL,'comment','spam_caught','0'); +INSERT INTO {vars} VALUES (NULL,'comment','access_permissions','everybody'); INSERT INTO {vars} VALUES (NULL,'rest','allow_guest_access','0'); INSERT INTO {vars} VALUES (NULL,'slideshow','max_scale','0'); diff --git a/installer/installer.php b/installer/installer.php index 53a5e3db..9a957b43 100644 --- a/installer/installer.php +++ b/installer/installer.php @@ -229,6 +229,10 @@ class installer { $errors[] = "Gallery requires <a href=\"http://php.net/manual/en/ini.core.php\">short_open_tag</a> to be on. Please enable it in your php.ini."; } + if (!function_exists("ctype_alpha")) { + $errors[] = "Gallery requires the <a href=\"http://php.net/manual/en/book.ctype.php\">PHP Ctype</a> extension. Please install it."; + } + return @$errors; } diff --git a/modules/comment/models/comment.php b/modules/comment/models/comment.php index 772e8b60..8f860a7b 100644 --- a/modules/comment/models/comment.php +++ b/modules/comment/models/comment.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Comment_Model extends ORM { +class Comment_Model_Core extends ORM { function item() { return ORM::factory("item", $this->item_id); } diff --git a/modules/digibug/controllers/digibug.php b/modules/digibug/controllers/digibug.php index 3c2bb115..88d1ace0 100644 --- a/modules/digibug/controllers/digibug.php +++ b/modules/digibug/controllers/digibug.php @@ -95,16 +95,11 @@ class Digibug_Controller extends Controller { if (!TEST_MODE) { // Dump out the image - header("Content-Type: $proxy->item->mime_type"); + header("Content-Type: {$proxy->item->mime_type}"); Kohana::close_buffers(false); $fd = fopen($file, "rb"); fpassthru($fd); fclose($fd); - - // If the request was for the image and not the thumb, then delete the proxy. - if ($type == "full") { - $proxy->delete(); - } } $this->_clean_expired(); diff --git a/modules/digibug/models/digibug_proxy.php b/modules/digibug/models/digibug_proxy.php index 0ce21649..2bff6ddb 100644 --- a/modules/digibug/models/digibug_proxy.php +++ b/modules/digibug/models/digibug_proxy.php @@ -17,6 +17,6 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Digibug_Proxy_Model extends ORM { +class Digibug_Proxy_Model_Core extends ORM { protected $belongs_to = array("item"); } diff --git a/modules/exif/models/exif_key.php b/modules/exif/models/exif_key.php index 3e9784ac..8ca63ada 100644 --- a/modules/exif/models/exif_key.php +++ b/modules/exif/models/exif_key.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Exif_Key_Model extends ORM { +class Exif_Key_Model_Core extends ORM { } diff --git a/modules/exif/models/exif_record.php b/modules/exif/models/exif_record.php index 8f87f6bc..03b8c982 100644 --- a/modules/exif/models/exif_record.php +++ b/modules/exif/models/exif_record.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Exif_Record_Model extends ORM { +class Exif_Record_Model_Core extends ORM { } diff --git a/modules/g2_import/helpers/g2_import.php b/modules/g2_import/helpers/g2_import.php index 515eb73d..8de5ce44 100644 --- a/modules/g2_import/helpers/g2_import.php +++ b/modules/g2_import/helpers/g2_import.php @@ -157,6 +157,7 @@ class g2_import_Core { $ret = GalleryEmbed::init(); if ($ret) { + Kohana_Log::add("error", "Gallery 2 call failed with: " . $ret->getAsText()); return false; } @@ -1199,6 +1200,11 @@ class g2_import_Core { $g2_map->g3_id = $g3_id; $g2_map->g2_id = $g2_id; $g2_map->resource_type = $resource_type; + + if (strpos($g2_url, self::$g2_base_url) === 0) { + $g2_url = substr($g2_url, strlen(self::$g2_base_url)); + } + $g2_map->g2_url = $g2_url; $g2_map->save(); self::$map[$g2_id] = $g3_id; @@ -1211,13 +1217,12 @@ class g2_import_Core { static function g2_url($params) { global $gallery; - $url = $gallery->getUrlGenerator()->generateUrl( + return $gallery->getUrlGenerator()->generateUrl( $params, array("forceSessionId" => false, "htmlEntities" => false, "urlEncode" => false, "useAuthToken" => false)); - return str_replace(self::$g2_base_url, "", $url); } static function lower_error_reporting() { diff --git a/modules/g2_import/models/g2_map.php b/modules/g2_import/models/g2_map.php index a20f48d6..8b96050d 100644 --- a/modules/g2_import/models/g2_map.php +++ b/modules/g2_import/models/g2_map.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class G2_Map_Model extends ORM { +class G2_Map_Model_Core extends ORM { } diff --git a/modules/g2_import/views/admin_g2_import.html.php b/modules/g2_import/views/admin_g2_import.html.php index 564bea9f..cb13363a 100644 --- a/modules/g2_import/views/admin_g2_import.html.php +++ b/modules/g2_import/views/admin_g2_import.html.php @@ -89,6 +89,7 @@ Options +FollowSymLinks RewriteEngine On RewriteBase <?= html::clean(g2_import::$g2_base_url) ?> + RewriteRule ^(.*)$ <?= url::site("g2/map?path=\$1") ?> [QSA,L,R=301] </IfModule></textarea> </div> diff --git a/modules/gallery/config/user_agents.php b/modules/gallery/config/user_agents.php new file mode 100644 index 00000000..24720046 --- /dev/null +++ b/modules/gallery/config/user_agents.php @@ -0,0 +1,122 @@ +<?php defined('SYSPATH') OR die('No direct access allowed.'); +/** + * This file contains four arrays of user agent data. It is used by the + * User Agent library to help identify browser, platform, robot, and + * mobile device data. The array keys are used to identify the device + * and the array values are used to set the actual name of the item. + * + * @package Kohana + * @author Kohana Team + * @copyright (c) 2007-2009 Kohana Team + * @license http://kohanaphp.com/license + */ + +$config['platform'] = array +( + 'windows nt 6.0' => 'Windows Vista', + 'windows nt 5.2' => 'Windows 2003', + 'windows nt 5.0' => 'Windows 2000', + 'windows nt 5.1' => 'Windows XP', + 'windows nt 4.0' => 'Windows NT', + 'winnt4.0' => 'Windows NT', + 'winnt 4.0' => 'Windows NT', + 'winnt' => 'Windows NT', + 'windows 98' => 'Windows 98', + 'win98' => 'Windows 98', + 'windows 95' => 'Windows 95', + 'win95' => 'Windows 95', + 'windows' => 'Unknown Windows OS', + 'os x' => 'Mac OS X', + 'intel mac' => 'Intel Mac', + 'ppc mac' => 'PowerPC Mac', + 'powerpc' => 'PowerPC', + 'ppc' => 'PowerPC', + 'cygwin' => 'Cygwin', + 'linux' => 'Linux', + 'debian' => 'Debian', + 'openvms' => 'OpenVMS', + 'sunos' => 'Sun Solaris', + 'amiga' => 'Amiga', + 'beos' => 'BeOS', + 'apachebench' => 'ApacheBench', + 'freebsd' => 'FreeBSD', + 'netbsd' => 'NetBSD', + 'bsdi' => 'BSDi', + 'openbsd' => 'OpenBSD', + 'os/2' => 'OS/2', + 'warp' => 'OS/2', + 'aix' => 'AIX', + 'irix' => 'Irix', + 'osf' => 'DEC OSF', + 'hp-ux' => 'HP-UX', + 'hurd' => 'GNU/Hurd', + 'unix' => 'Unknown Unix OS', +); + +/** + * The order of this array should NOT be changed. Many browsers return + * multiple browser types so we want to identify the sub-type first. + */ +$config['browser'] = array +( + 'Opera' => 'Opera', + 'MSIE' => 'Internet Explorer', + 'Internet Explorer' => 'Internet Explorer', + 'Shiira' => 'Shiira', + 'Firefox' => 'Firefox', + 'Chimera' => 'Chimera', + 'Phoenix' => 'Phoenix', + 'Firebird' => 'Firebird', + 'Camino' => 'Camino', + 'Netscape' => 'Netscape', + 'OmniWeb' => 'OmniWeb', + 'Chrome' => 'Chrome', + 'Safari' => 'Safari', + 'Konqueror' => 'Konqueror', + 'Epiphany' => 'Epiphany', + 'Galeon' => 'Galeon', + 'Mozilla' => 'Mozilla', + 'icab' => 'iCab', + 'lynx' => 'Lynx', + 'links' => 'Links', + 'hotjava' => 'HotJava', + 'amaya' => 'Amaya', + 'IBrowse' => 'IBrowse', +); + +$config['mobile'] = array +( + 'mobileexplorer' => 'Mobile Explorer', + 'openwave' => 'Open Wave', + 'opera mini' => 'Opera Mini', + 'operamini' => 'Opera Mini', + 'elaine' => 'Palm', + 'palmsource' => 'Palm', + 'digital paths' => 'Palm', + 'avantgo' => 'Avantgo', + 'xiino' => 'Xiino', + 'palmscape' => 'Palmscape', + 'nokia' => 'Nokia', + 'ericsson' => 'Ericsson', + 'blackBerry' => 'BlackBerry', + 'motorola' => 'Motorola', + 'iphone' => 'iPhone', + 'android' => 'Android', +); + +/** + * There are hundreds of bots but these are the most common. + */ +$config['robot'] = array +( + 'googlebot' => 'Googlebot', + 'msnbot' => 'MSNBot', + 'slurp' => 'Inktomi Slurp', + 'yahoo' => 'Yahoo', + 'askjeeves' => 'AskJeeves', + 'fastcrawler' => 'FastCrawler', + 'infoseek' => 'InfoSeek Robot 1.0', + 'lycos' => 'Lycos', + 'mj12bot' => 'MJ12bot', + 'speedy spider' => 'Speedy Spider', +);
\ No newline at end of file diff --git a/modules/gallery/controllers/packager.php b/modules/gallery/controllers/packager.php index f463d0de..bd51b93c 100644 --- a/modules/gallery/controllers/packager.php +++ b/modules/gallery/controllers/packager.php @@ -81,11 +81,6 @@ class Packager_Controller extends Controller { Database::instance()->query("TRUNCATE {caches}"); Database::instance()->query("TRUNCATE {sessions}"); Database::instance()->query("TRUNCATE {logs}"); - db::build() - ->delete("vars") - ->where("module_name", "=", "gallery") - ->where("name", "=", "_cache") - ->execute(); db::build()->update("users") ->set(array("password" => "")) ->where("id", "in", array(1, 2)) diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php index cf130401..d15bd816 100644 --- a/modules/gallery/helpers/MY_html.php +++ b/modules/gallery/helpers/MY_html.php @@ -26,7 +26,7 @@ class html extends html_Core { * unescaped HTML which is assumed to be safe. * * Example:<pre> - * <div><?= html::clean($php_var) ?> + * <div><?= html::clean($php_var) ?> * </pre> */ static function clean($html) { @@ -39,7 +39,7 @@ class html extends html_Core { * only non-malicious HTML. * * Example:<pre> - * <div><?= html::purify($item->title) ?> + * <div><?= html::purify($item->title) ?> * </pre> */ static function purify($html) { @@ -86,6 +86,6 @@ class html extends html_Core { * @return the string escaped for use in HTML attributes. */ static function clean_attribute($string) { - return self::clean($string)->for_html_attr(); + return html::clean($string)->for_html_attr(); } } diff --git a/modules/gallery/helpers/MY_remote.php b/modules/gallery/helpers/MY_remote.php index 3e13ba8d..a1d2a3d1 100644 --- a/modules/gallery/helpers/MY_remote.php +++ b/modules/gallery/helpers/MY_remote.php @@ -24,7 +24,7 @@ class remote extends remote_Core { /* Read the web page into a buffer */ list ($response_status, $response_headers, $response_body) = - self::do_request($url, 'POST', $extra_headers, $post_data_raw); + remote::do_request($url, 'POST', $extra_headers, $post_data_raw); return array($response_body, $response_status, $response_headers); } @@ -63,6 +63,9 @@ class remote extends remote_Core { * WebHelper_simple::_parseLocation logic. */ static function do_request($url, $method='GET', $headers=array(), $body='') { + if (!array_key_exists("User-Agent", $headers)) { + $headers["User-Agent"] = "Gallery3"; + } /* Convert illegal characters */ $url = str_replace(' ', '%20', $url); diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php index 52a36298..0b0dcbc1 100644 --- a/modules/gallery/helpers/access.php +++ b/modules/gallery/helpers/access.php @@ -79,7 +79,7 @@ class access_Core { * @return boolean */ static function can($perm_name, $item) { - return self::user_can(identity::active_user(), $perm_name, $item); + return access::user_can(identity::active_user(), $perm_name, $item); } /** @@ -102,7 +102,7 @@ class access_Core { $resource = $perm_name == "view" ? $item : model_cache::get("access_cache", $item->id, "item_id"); foreach ($user->groups() as $group) { - if ($resource->__get("{$perm_name}_{$group->id}") === self::ALLOW) { + if ($resource->__get("{$perm_name}_{$group->id}") === access::ALLOW) { return true; } } @@ -117,12 +117,12 @@ class access_Core { * @return boolean */ static function required($perm_name, $item) { - if (!self::can($perm_name, $item)) { + if (!access::can($perm_name, $item)) { if ($perm_name == "view") { // Treat as if the item didn't exist, don't leak any information. throw new Kohana_404_Exception(); } else { - self::forbidden(); + access::forbidden(); } } } @@ -138,7 +138,7 @@ class access_Core { static function group_can($group, $perm_name, $item) { $resource = $perm_name == "view" ? $item : model_cache::get("access_cache", $item->id, "item_id"); - return $resource->__get("{$perm_name}_{$group->id}") === self::ALLOW; + return $resource->__get("{$perm_name}_{$group->id}") === access::ALLOW; } /** @@ -168,14 +168,14 @@ class access_Core { return null; } - // For view permissions, if any parent is self::DENY, then those parents lock this one. + // For view permissions, if any parent is access::DENY, then those parents lock this one. // Return $lock = ORM::factory("item") ->where("left_ptr", "<=", $item->left_ptr) ->where("right_ptr", ">=", $item->right_ptr) ->where("items.id", "<>", $item->id) ->join("access_intents", "items.id", "access_intents.item_id") - ->where("access_intents.view_$group->id", "=", self::DENY) + ->where("access_intents.view_$group->id", "=", access::DENY) ->order_by("level", "DESC") ->limit(1) ->find(); @@ -222,7 +222,7 @@ class access_Core { self::_update_access_non_view_cache($group, $perm_name, $album); } - self::update_htaccess_files($album, $group, $perm_name, $value); + access::update_htaccess_files($album, $group, $perm_name, $value); model_cache::clear(); } @@ -414,7 +414,7 @@ class access_Core { static function verify_csrf() { $input = Input::instance(); if ($input->post("csrf", $input->get("csrf", null)) !== Session::instance()->get("csrf")) { - self::forbidden(); + access::forbidden(); } } @@ -437,7 +437,7 @@ class access_Core { * @return string */ static function csrf_form_field() { - return "<input type=\"hidden\" name=\"csrf\" value=\"" . self::csrf_token() . "\"/>"; + return "<input type=\"hidden\" name=\"csrf\" value=\"" . access::csrf_token() . "\"/>"; } /** @@ -488,7 +488,7 @@ class access_Core { "ALTER TABLE {access_intents} ADD `$field` BINARY DEFAULT NULL"); db::build() ->update("access_intents") - ->set($field, self::DENY) + ->set($field, access::DENY) ->where("item_id", "=", 1) ->execute(); model_cache::clear(); @@ -517,12 +517,12 @@ class access_Core { // DENY and this ALLOW cannot be obeyed. So in that case, back up the tree and find any // non-DEFAULT and non-ALLOW parent and propagate from there. If we can't find a matching // item, then its safe to propagate from here. - if ($access->$field !== self::DENY) { + if ($access->$field !== access::DENY) { $tmp_item = ORM::factory("item") ->where("left_ptr", "<", $item->left_ptr) ->where("right_ptr", ">", $item->right_ptr) ->join("access_intents", "access_intents.item_id", "items.id") - ->where("access_intents.$field", "=", self::DENY) + ->where("access_intents.$field", "=", access::DENY) ->order_by("left_ptr", "DESC") ->limit(1) ->find(); @@ -537,7 +537,7 @@ class access_Core { // that we can tell which permissions have been changed, and which ones need to be updated. db::build() ->update("items") - ->set($field, self::UNKNOWN) + ->set($field, access::UNKNOWN) ->where("left_ptr", ">=", $item->left_ptr) ->where("right_ptr", "<=", $item->right_ptr) ->execute(); @@ -548,20 +548,20 @@ class access_Core { ->where("left_ptr", ">=", $item->left_ptr) ->where("right_ptr", "<=", $item->right_ptr) ->where("type", "=", "album") - ->where("access_intents.$field", "IS NOT", self::INHERIT) + ->where("access_intents.$field", "IS NOT", access::INHERIT) ->order_by("level", "DESC") ->find_all(); foreach ($query as $row) { - if ($row->$field == self::ALLOW) { + if ($row->$field == access::ALLOW) { // Propagate ALLOW for any row that is still UNKNOWN. db::build() ->update("items") ->set($field, $row->$field) - ->where($field, "IS", self::UNKNOWN) // UNKNOWN is NULL so we have to use IS + ->where($field, "IS", access::UNKNOWN) // UNKNOWN is NULL so we have to use IS ->where("left_ptr", ">=", $row->left_ptr) ->where("right_ptr", "<=", $row->right_ptr) ->execute(); - } else if ($row->$field == self::DENY) { + } else if ($row->$field == access::DENY) { // DENY overwrites everything below it db::build() ->update("items") @@ -577,8 +577,8 @@ class access_Core { // the hierarchy, and all of those are safe to change to ALLOW. db::build() ->update("items") - ->set($field, self::ALLOW) - ->where($field, "IS", self::UNKNOWN) // UNKNOWN is NULL so we have to use IS + ->set($field, access::ALLOW) + ->where($field, "IS", access::UNKNOWN) // UNKNOWN is NULL so we have to use IS ->where("left_ptr", ">=", $item->left_ptr) ->where("right_ptr", "<=", $item->right_ptr) ->execute(); @@ -605,12 +605,12 @@ class access_Core { // // @todo To optimize this, we wouldn't need to propagate from the parent, we could just // propagate from here with the parent's intent. - if ($access->$field === self::INHERIT) { + if ($access->$field === access::INHERIT) { $tmp_item = ORM::factory("item") ->join("access_intents", "items.id", "access_intents.item_id") ->where("left_ptr", "<", $item->left_ptr) ->where("right_ptr", ">", $item->right_ptr) - ->where($field, "IS NOT", self::UNKNOWN) // UNKNOWN is NULL so we have to use IS NOT + ->where($field, "IS NOT", access::UNKNOWN) // UNKNOWN is NULL so we have to use IS NOT ->order_by("left_ptr", "DESC") ->limit(1) ->find(); @@ -626,11 +626,11 @@ class access_Core { ->join("items", "items.id", "access_intents.item_id") ->where("left_ptr", ">=", $item->left_ptr) ->where("right_ptr", "<=", $item->right_ptr) - ->where($field, "IS NOT", self::INHERIT) + ->where($field, "IS NOT", access::INHERIT) ->order_by("level", "ASC") ->find_all(); foreach ($query as $row) { - $value = ($row->$field === self::ALLOW) ? true : false; + $value = ($row->$field === access::ALLOW) ? true : false; db::build() ->update("access_caches") ->set($field, $value) @@ -683,7 +683,7 @@ class access_Core { } foreach ($dirs as $dir) { - if ($value === self::DENY) { + if ($value === access::DENY) { $fp = fopen("$dir/.htaccess", "w+"); fwrite($fp, "<IfModule mod_rewrite.c>\n"); fwrite($fp, " RewriteEngine On\n"); @@ -727,8 +727,18 @@ class access_Core { fclose($fp); } - list ($response) = remote::do_request(url::abs_file("var/security_test/verify")); - $works = $response == "HTTP/1.1 200 OK"; + // Proxy our authorization headers so that if the entire Gallery is covered by Basic Auth + // this callback will still work. + $headers = array(); + if (function_exists("apache_request_headers")) { + $arh = apache_request_headers(); + if (!empty($arh["Authorization"])) { + $headers["Authorization"] = $arh["Authorization"]; + } + } + list ($status, $headers, $body) = + remote::do_request(url::abs_file("var/security_test/verify"), "GET", $headers); + $works = ($status == "HTTP/1.1 200 OK") && ($body == "success"); } catch (Exception $e) { @dir::unlink(VARPATH . "security_test"); throw $e; diff --git a/modules/gallery/helpers/auth.php b/modules/gallery/helpers/auth.php index 48b5fc32..fa6242b9 100644 --- a/modules/gallery/helpers/auth.php +++ b/modules/gallery/helpers/auth.php @@ -74,13 +74,13 @@ class auth_Core { } static function validate_too_many_failed_logins($name_input) { - if (self::too_many_failures($name_input->value)) { + if (auth::too_many_failures($name_input->value)) { $name_input->add_error("too_many_failed_logins", 1); } } static function validate_too_many_failed_auth_attempts($form_input) { - if (self::too_many_failures(identity::active_user()->name)) { + if (auth::too_many_failures(identity::active_user()->name)) { $form_input->add_error("too_many_failed_auth_attempts", 1); } } diff --git a/modules/gallery/helpers/block_manager.php b/modules/gallery/helpers/block_manager.php index 4dcd6c32..2237b702 100644 --- a/modules/gallery/helpers/block_manager.php +++ b/modules/gallery/helpers/block_manager.php @@ -27,10 +27,10 @@ class block_manager_Core { } static function add($location, $module_name, $block_id) { - $blocks = self::get_active($location); + $blocks = block_manager::get_active($location); $blocks[rand()] = array($module_name, $block_id); - self::set_active($location, $blocks); + block_manager::set_active($location, $blocks); } static function activate_blocks($module_name) { @@ -38,25 +38,25 @@ class block_manager_Core { if (method_exists($block_class, "get_site_list")) { $blocks = call_user_func(array($block_class, "get_site_list")); foreach (array_keys($blocks) as $block_id) { - self::add("site_sidebar", $module_name, $block_id); + block_manager::add("site_sidebar", $module_name, $block_id); } } } static function remove($location, $block_id) { - $blocks = self::get_active($location); + $blocks = block_manager::get_active($location); unset($blocks[$block_id]); - self::set_active($location, $blocks); + block_manager::set_active($location, $blocks); } static function remove_blocks_for_module($location, $module_name) { - $blocks = self::get_active($location); + $blocks = block_manager::get_active($location); foreach ($blocks as $key => $block) { if ($block[0] == $module_name) { unset($blocks[$key]); } } - self::set_active($location, $blocks); + block_manager::set_active($location, $blocks); } static function deactivate_blocks($module_name) { @@ -64,14 +64,14 @@ class block_manager_Core { if (method_exists($block_class, "get_site_list")) { $blocks = call_user_func(array($block_class, "get_site_list")); foreach (array_keys($blocks) as $block_id) { - self::remove_blocks_for_module("site_sidebar", $module_name); + block_manager::remove_blocks_for_module("site_sidebar", $module_name); } } if (method_exists($block_class, "get_admin_list")) { $blocks = call_user_func(array($block_class, "get_admin_list")); foreach (array("dashboard_sidebar", "dashboard_center") as $location) { - self::remove_blocks_for_module($location, $module_name); + block_manager::remove_blocks_for_module($location, $module_name); } } } @@ -99,7 +99,7 @@ class block_manager_Core { } static function get_html($location, $theme=null) { - $active = self::get_active($location); + $active = block_manager::get_active($location); $result = ""; foreach ($active as $id => $desc) { if (method_exists("$desc[0]_block", "get")) { diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php index 3cf0eacd..2bb55ccb 100644 --- a/modules/gallery/helpers/gallery.php +++ b/modules/gallery/helpers/gallery.php @@ -18,13 +18,17 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class gallery_Core { - const VERSION = "3.0 RC2 (Santa Fe)"; + const VERSION = "3.0+ (git)"; /** * If Gallery is in maintenance mode, then force all non-admins to get routed to a "This site is * down for maintenance" page. */ static function maintenance_mode() { + // @todo: we need a mechanism here to identify controllers that are still legally accessible + // when the entire Gallery is in maintenance mode. Perhaps a controller class function or + // method? + // https://sourceforge.net/apps/trac/gallery/ticket/1411 if (Router::$controller != "login" && Router::$controller != "combined" && module::get_var("gallery", "maintenance_mode", 0) && @@ -41,8 +45,13 @@ class gallery_Core { * the login page. */ static function private_gallery() { + // @todo: we need a mechanism here to identify controllers that are still legally accessible + // when the entire Gallery is private. Perhaps a controller class function or method? + // https://sourceforge.net/apps/trac/gallery/ticket/1411 if (Router::$controller != "login" && Router::$controller != "combined" && + Router::$controller != "digibug" && + Router::$controller != "rest" && identity::active_user()->guest && !access::user_can(identity::guest(), "view", item::root()) && php_sapi_name() != "cli") { @@ -66,6 +75,11 @@ class gallery_Core { * request should implement the <module>_event::gallery_ready() handler. */ static function ready() { + // Don't keep a session for robots; it's a waste of database space. + if (request::user_agent("robot")) { + Session::instance()->abort_save(); + } + module::event("gallery_ready"); } diff --git a/modules/gallery/helpers/gallery_block.php b/modules/gallery/helpers/gallery_block.php index cb28cbcd..1d92d66d 100644 --- a/modules/gallery/helpers/gallery_block.php +++ b/modules/gallery/helpers/gallery_block.php @@ -70,12 +70,6 @@ class gallery_block_Core { $block->css_id = "g-platform"; $block->title = t("Platform information"); $block->content = new View("admin_block_platform.html"); - if (@is_readable("/proc/loadavg") && $first_line = current(@file("/proc/loadavg"))) { - $block->content->load_average = - join(" ", array_slice(explode(" ", $first_line), 0, 3)); - } else { - $block->content->load_average = t("Unavailable"); - } break; case "project_news": @@ -88,7 +82,7 @@ class gallery_block_Core { case "block_adder": $block->css_id = "g-block-adder"; $block->title = t("Dashboard content"); - $block->content = self::get_add_block_form(); + $block->content = gallery_block::get_add_block_form(); break; case "language": diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php index 83961d6b..3d82bc69 100644 --- a/modules/gallery/helpers/gallery_installer.php +++ b/modules/gallery/helpers/gallery_installer.php @@ -309,7 +309,7 @@ class gallery_installer { module::set_var("gallery", "show_user_profiles_to", "registered_users"); module::set_var("gallery", "extra_binary_paths", "/usr/local/bin:/opt/local/bin:/opt/bin"); - module::set_version("gallery", 40); + module::set_version("gallery", 41); } static function upgrade($version) { @@ -637,6 +637,11 @@ class gallery_installer { module::set_var("gallery", "extra_binary_paths", "/usr/local/bin:/opt/local/bin:/opt/bin"); module::set_version("gallery", $version = 40); } + + if ($version == 40) { + module::clear_var("gallery", "_cache"); + module::set_version("gallery", $version = 41); + } } static function uninstall() { diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php index 3b173928..e69ff91a 100644 --- a/modules/gallery/helpers/gallery_task.php +++ b/modules/gallery/helpers/gallery_task.php @@ -71,7 +71,12 @@ class gallery_task_Core { static function rebuild_dirty_images($task) { $errors = array(); try { - $result = graphics::find_dirty_images_query()->select("id")->execute(); + // Choose the dirty images in a random order so that if we run this task multiple times + // concurrently each task is rebuilding different images simultaneously. + $result = graphics::find_dirty_images_query()->select("id") + ->select(new Database_Expression("RAND() as r")) + ->order_by("r", "ASC") + ->execute(); $total_count = $task->get("total_count", $result->count()); $mode = $task->get("mode", "init"); if ($mode == "init") { @@ -84,6 +89,13 @@ class gallery_task_Core { $ignored = $task->get("ignored", array()); $i = 0; + + // If there's no work left to do, skip to the end. This can happen if we resume a task long + // after the work got done in some other task. + if (!$result->count()) { + $completed = $total_count; + } + foreach ($result as $row) { if (array_key_exists($row->id, $ignored)) { continue; diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php index 0d7cc44a..978c69a6 100644 --- a/modules/gallery/helpers/gallery_theme.php +++ b/modules/gallery/helpers/gallery_theme.php @@ -93,7 +93,7 @@ class gallery_theme_Core { } // Redirect to the root album when the admin session expires. - $admin_session_redirect_check = '<script type="text/javascript"> + $content = '<script type="text/javascript"> var adminReauthCheck = function() { $.ajax({url: "' . url::site("admin?reauth_check=1") . '", dataType: "json", @@ -105,11 +105,11 @@ class gallery_theme_Core { }; setInterval("adminReauthCheck();", 60 * 1000); </script>'; - print $admin_session_redirect_check; if ($session->get("l10n_mode", false)) { - return L10n_Client_Controller::l10n_form(); + $content .= "\n" . L10n_Client_Controller::l10n_form(); } + return $content; } static function credits() { diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php index dd521d84..edba6b76 100644 --- a/modules/gallery/helpers/graphics.php +++ b/modules/gallery/helpers/graphics.php @@ -50,7 +50,7 @@ class graphics_Core { $rule->active = true; $rule->save(); - self::mark_dirty($target == "thumb", $target == "resize"); + graphics::mark_dirty($target == "thumb", $target == "resize"); } /** @@ -67,7 +67,7 @@ class graphics_Core { ->where("operation", "=", $operation) ->execute(); - self::mark_dirty($target == "thumb", $target == "resize"); + graphics::mark_dirty($target == "thumb", $target == "resize"); } /** @@ -80,7 +80,7 @@ class graphics_Core { ->where("module_name", "=", $module_name) ->execute(); if (count($status)) { - self::mark_dirty(true, true); + graphics::mark_dirty(true, true); } } @@ -252,7 +252,7 @@ class graphics_Core { $db->execute(); } - $count = self::find_dirty_images_query()->count_records(); + $count = graphics::find_dirty_images_query()->count_records(); if ($count) { site_status::warning( t2("One of your photos is out of date. <a %attrs>Click here to fix it</a>", diff --git a/modules/gallery/helpers/identity.php b/modules/gallery/helpers/identity.php index 5ca024e9..f45f72c3 100644 --- a/modules/gallery/helpers/identity.php +++ b/modules/gallery/helpers/identity.php @@ -61,7 +61,7 @@ class identity_Core { $session = Session::instance(); if (!($user = $session->get("user"))) { - self::set_active_user($user = self::guest()); + identity::set_active_user($user = identity::guest()); } // The installer cannot set a user into the session, so it just sets an id which we should @@ -69,6 +69,7 @@ class identity_Core { // @todo set the user name into the session instead of 2 and then use it to get the // user object if ($user === 2) { + $session->delete("user"); // delete it so that identity code isn't confused by the integer auth::login(IdentityProvider::instance()->admin_user()); } @@ -127,7 +128,7 @@ class identity_Core { $session = Session::instance(); $session->set("user", $user); $session->delete("group_ids"); - self::load_user(); + identity::load_user(); } /** diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php index 092904a5..052b1c8e 100644 --- a/modules/gallery/helpers/item.php +++ b/modules/gallery/helpers/item.php @@ -218,7 +218,13 @@ class item_Core { } /** - * Return a query to get a random Item_Model, with optional filters + * Return a query to get a random Item_Model, with optional filters. + * Usage: item::random_query()->execute(); + * + * Note: You can add your own ->where() clauses but if your Gallery is + * small or your where clauses are over-constrained you may wind up with + * no item. You should try running this a few times in a loop if you + * don't get an item back. */ static function random_query() { // Pick a random number and find the item that's got nearest smaller number. diff --git a/modules/gallery/helpers/item_rest.php b/modules/gallery/helpers/item_rest.php index 10f9e16a..a8bc36ad 100644 --- a/modules/gallery/helpers/item_rest.php +++ b/modules/gallery/helpers/item_rest.php @@ -23,18 +23,19 @@ class item_rest_Core { * query the collection. You can specify them in any combination. * * scope=direct - * only return items that are immediately under this one + * Only return items that are immediately under this one * scope=all - * return items anywhere under this one + * Return items anywhere under this one * * name=<substring> - * only return items where the name contains this substring + * Only return items where the name contains this substring * * random=true - * return a single random item + * Return a single random item * * type=<comma separate list of photo, movie or album> - * limit the type to types in this list. eg, "type=photo,movie" + * Limit the type to types in this list, eg: "type=photo,movie". + * Also limits the types returned in the member collections (same behaviour as item_rest). */ static function get($request) { $item = rest::resolve($request->url); diff --git a/modules/gallery/helpers/items_rest.php b/modules/gallery/helpers/items_rest.php index f0b68d63..08aa3279 100644 --- a/modules/gallery/helpers/items_rest.php +++ b/modules/gallery/helpers/items_rest.php @@ -25,31 +25,34 @@ class items_rest_Core { * filter the results based on the specified type. Using the type parameter with the * ancestors_for parameter makes no sense and will be ignored. * - * urls=url1,url2,url3 - * return items that match the specified urls. Typically used to return the member detail + * urls=["url1","url2","url3"] + * Return items that match the specified urls. Typically used to return the member detail * * ancestors_for=url - * return the ancestors of the specified item + * Return the ancestors of the specified item * * type=<comma separate list of photo, movie or album> - * limit the type to types in this list. eg, "type=photo,movie" + * Limit the type to types in this list, eg: "type=photo,movie". + * Also limits the types returned in the member collections (same behaviour as item_rest). + * Ignored if ancestors_for is set. */ static function get($request) { $items = array(); + $types = array(); + if (isset($request->params->urls)) { + if (isset($request->params->type)) { + $types = explode(",", $request->params->type); + } + foreach (json_decode($request->params->urls) as $url) { - if (isset($request->params->type)) { - $types = explode(",", $request->params->type); - } $item = rest::resolve($url); - if (access::can("view", $item)) { - if (isset($types)) { - if (in_array($item->type, $types)) { - $items[] = items_rest::_format_restful_item($item); - } - } else { - $items[] = items_rest::_format_restful_item($item); - } + if (!access::can("view", $item)) { + continue; + } + + if (empty($types) || in_array($item->type, $types)) { + $items[] = items_rest::_format_restful_item($item, $types); } } } else if (isset($request->params->ancestors_for)) { @@ -57,9 +60,9 @@ class items_rest_Core { if (!access::can("view", $item)) { throw new Kohana_404_Exception(); } - $items[] = items_rest::_format_restful_item($item); + $items[] = items_rest::_format_restful_item($item, $types); while (($item = $item->parent()) != null) { - array_unshift($items, items_rest::_format_restful_item($item)); + array_unshift($items, items_rest::_format_restful_item($item, $types)); }; } @@ -74,14 +77,16 @@ class items_rest_Core { return $item; } - private static function _format_restful_item($item) { + private static function _format_restful_item($item, $types) { $item_rest = array("url" => rest::url("item", $item), "entity" => $item->as_restful_array(), "relationships" => rest::relationships("item", $item)); if ($item->type == "album") { $members = array(); foreach ($item->viewable()->children() as $child) { - $members[] = rest::url("item", $child); + if (empty($types) || in_array($child->type, $types)) { + $members[] = rest::url("item", $child); + } } $item_rest["members"] = $members; } diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php index 43cc2036..8c2685a8 100644 --- a/modules/gallery/helpers/l10n_client.php +++ b/modules/gallery/helpers/l10n_client.php @@ -40,14 +40,14 @@ class l10n_client_Core { } static function server_uid($api_key=null) { - $api_key = $api_key == null ? self::api_key() : $api_key; + $api_key = $api_key == null ? l10n_client::api_key() : $api_key; $parts = explode(":", $api_key); return empty($parts) ? 0 : $parts[0]; } private static function _sign($payload, $api_key=null) { - $api_key = $api_key == null ? self::api_key() : $api_key; - return md5($api_key . $payload . self::client_token()); + $api_key = $api_key == null ? l10n_client::api_key() : $api_key; + return md5($api_key . $payload . l10n_client::client_token()); } static function validate_api_key($api_key) { @@ -57,9 +57,9 @@ class l10n_client_Core { list ($response_data, $response_status) = remote::post( $url, array("version" => $version, - "client_token" => self::client_token(), + "client_token" => l10n_client::client_token(), "signature" => $signature, - "uid" => self::server_uid($api_key))); + "uid" => l10n_client::server_uid($api_key))); if (!remote::success($response_status)) { return false; } @@ -215,9 +215,9 @@ class l10n_client_Core { list ($response_data, $response_status) = remote::post( $url, array("data" => $request_data, - "client_token" => self::client_token(), + "client_token" => l10n_client::client_token(), "signature" => $signature, - "uid" => self::server_uid())); + "uid" => l10n_client::server_uid())); if (!remote::success($response_status)) { throw new Exception("@todo TRANSLATIONS_SUBMISSION_FAILED " . $response_status); diff --git a/modules/gallery/helpers/locales.php b/modules/gallery/helpers/locales.php index d1e72260..565e9da8 100644 --- a/modules/gallery/helpers/locales.php +++ b/modules/gallery/helpers/locales.php @@ -62,11 +62,14 @@ class locales_Core { } // @todo Might want to add a localizable language name as well. + // ref: http://cldr.unicode.org/ + // ref: http://cldr.unicode.org/index/cldr-spec/picking-the-right-language-code private static function _init_language_data() { $l["af_ZA"] = "Afrikaans"; // Afrikaans $l["ar_SA"] = "العربية"; // Arabic $l["be_BY"] = "Беларускі"; // Belarusian $l["bg_BG"] = "български"; // Bulgarian + $l["bn_BD"] = "বাংলা"; // Bengali $l["ca_ES"] = "Catalan"; // Catalan $l["cs_CZ"] = "čeština"; // Czech $l["da_DK"] = "Dansk"; // Danish @@ -92,6 +95,7 @@ class locales_Core { $l["ko_KR"] = "한국어"; // Korean $l["lt_LT"] = "Lietuvių"; // Lithuanian $l["lv_LV"] = "Latviešu"; // Latvian + $l["ms_MY"] = "Bahasa Melayu"; // Malay $l["mk_MK"] = "Македонски јазик"; // Macedonian $l["nl_NL"] = "Nederlands"; // Dutch $l["no_NO"] = "Norsk bokmål"; // Norwegian @@ -208,7 +212,7 @@ class locales_Core { } private static function _locale_match_score($requested_locale, $qvalue, $adjustment_factor) { - $installed = self::installed(); + $installed = locales::installed(); if (isset($installed[$requested_locale])) { return array($requested_locale, $qvalue); } @@ -223,14 +227,14 @@ class locales_Core { static function set_request_locale() { // 1. Check the session specific preference (cookie) - $locale = self::cookie_locale(); + $locale = locales::cookie_locale(); // 2. Check the user's preference if (!$locale) { $locale = identity::active_user()->locale; } // 3. Check the browser's / OS' preference if (!$locale) { - $locale = self::locale_from_http_request(); + $locale = locales::locale_from_http_request(); } // If we have any preference, override the site's default locale if ($locale) { diff --git a/modules/gallery/helpers/log.php b/modules/gallery/helpers/log.php index 26f70480..37154522 100644 --- a/modules/gallery/helpers/log.php +++ b/modules/gallery/helpers/log.php @@ -30,7 +30,7 @@ class log_Core { * @param string $html an html snippet presented alongside the log message to aid the admin */ static function success($category, $message, $html="") { - self::_add($category, $message, $html, self::SUCCESS); + self::_add($category, $message, $html, log::SUCCESS); } /** @@ -40,7 +40,7 @@ class log_Core { * @param string $html an html snippet presented alongside the log message to aid the admin */ static function info($category, $message, $html="") { - self::_add($category, $message, $html, self::INFO); + self::_add($category, $message, $html, log::INFO); } /** @@ -50,7 +50,7 @@ class log_Core { * @param string $html an html snippet presented alongside the log message to aid the admin */ static function warning($category, $message, $html="") { - self::_add($category, $message, $html, self::WARNING); + self::_add($category, $message, $html, log::WARNING); } /** @@ -60,7 +60,7 @@ class log_Core { * @param string $html an html snippet presented alongside the log message to aid the admin */ static function error($category, $message, $html="") { - self::_add($category, $message, $html, self::ERROR); + self::_add($category, $message, $html, log::ERROR); } /** @@ -92,16 +92,16 @@ class log_Core { */ static function severity_class($severity) { switch($severity) { - case self::SUCCESS: + case log::SUCCESS: return "g-success"; - case self::INFO: + case log::INFO: return "g-info"; - case self::WARNING: + case log::WARNING: return "g-warning"; - case self::ERROR: + case log::ERROR: return "g-error"; } } diff --git a/modules/gallery/helpers/message.php b/modules/gallery/helpers/message.php index 1f69e2a9..64dd703c 100644 --- a/modules/gallery/helpers/message.php +++ b/modules/gallery/helpers/message.php @@ -28,7 +28,7 @@ class message_Core { * @param string $msg a detailed message */ static function success($msg) { - self::_add($msg, self::SUCCESS); + self::_add($msg, message::SUCCESS); } /** @@ -36,7 +36,7 @@ class message_Core { * @param string $msg a detailed message */ static function info($msg) { - self::_add($msg, self::INFO); + self::_add($msg, message::INFO); } /** @@ -44,7 +44,7 @@ class message_Core { * @param string $msg a detailed message */ static function warning($msg) { - self::_add($msg, self::WARNING); + self::_add($msg, message::WARNING); } /** @@ -52,7 +52,7 @@ class message_Core { * @param string $msg a detailed message */ static function error($msg) { - self::_add($msg, self::ERROR); + self::_add($msg, message::ERROR); } /** @@ -79,7 +79,7 @@ class message_Core { $messages = Session::instance()->get_once("messages", array()); foreach ($messages as $msg) { $msg[0] = str_replace("__CSRF__", access::csrf_token(), $msg[0]); - $buf[] = "<li class=\"" . self::severity_class($msg[1]) . "\">$msg[0]</li>"; + $buf[] = "<li class=\"" . message::severity_class($msg[1]) . "\">$msg[0]</li>"; } if ($buf) { return "<ul id=\"g-action-status\" class=\"g-message-block\">" . implode("", $buf) . "</ul>"; @@ -93,16 +93,16 @@ class message_Core { */ static function severity_class($severity) { switch($severity) { - case self::SUCCESS: + case message::SUCCESS: return "g-success"; - case self::INFO: + case message::INFO: return "g-info"; - case self::WARNING: + case message::WARNING: return "g-warning"; - case self::ERROR: + case message::ERROR: return "g-error"; } } diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php index 7863520e..2b446daa 100644 --- a/modules/gallery/helpers/module.php +++ b/modules/gallery/helpers/module.php @@ -35,7 +35,7 @@ class module_Core { * @param integer $version */ static function set_version($module_name, $version) { - $module = self::get($module_name); + $module = module::get($module_name); if (!$module->loaded()) { $module->name = $module_name; $module->active = $module_name == "gallery"; // only gallery is active by default @@ -62,7 +62,7 @@ class module_Core { * not found */ static function info($module_name) { - $module_list = self::available(); + $module_list = module::available(); return isset($module_list->$module_name) ? $module_list->$module_name : false; } @@ -94,10 +94,10 @@ class module_Core { $modules->$module_name = new ArrayObject(parse_ini_file($file), ArrayObject::ARRAY_AS_PROPS); $m =& $modules->$module_name; - $m->installed = self::is_installed($module_name); - $m->active = self::is_active($module_name); + $m->installed = module::is_installed($module_name); + $m->active = module::is_active($module_name); $m->code_version = $m->version; - $m->version = self::get_version($module_name); + $m->version = module::get_version($module_name); $m->locked = false; if ($m->active && $m->version != $m->code_version) { @@ -107,7 +107,7 @@ class module_Core { // Lock certain modules $modules->gallery->locked = true; - $identity_module = self::get_var("gallery", "identity_provider", "user"); + $identity_module = module::get_var("gallery", "identity_provider", "user"); $modules->$identity_module->locked = true; $modules->ksort(); self::$available = $modules; @@ -258,7 +258,7 @@ class module_Core { call_user_func_array(array($installer_class, "activate"), array()); } - $module = self::get($module_name); + $module = module::get($module_name); if ($module->loaded()) { $module->active = true; $module->save(); @@ -285,7 +285,7 @@ class module_Core { call_user_func_array(array($installer_class, "deactivate"), array()); } - $module = self::get($module_name); + $module = module::get($module_name); if ($module->loaded()) { $module->active = false; $module->save(); @@ -312,7 +312,7 @@ class module_Core { } graphics::remove_rules($module_name); - $module = self::get($module_name); + $module = module::get($module_name); if ($module->loaded()) { $module->delete(); } @@ -425,48 +425,21 @@ class module_Core { * @return the value */ static function get_var($module_name, $name, $default_value=null) { - // We cache all vars in gallery._cache so that we can load all vars at once for - // performance. + // We cache vars so we can load them all at once for performance. if (empty(self::$var_cache)) { - $row = db::build() - ->select("value") - ->from("vars") - ->where("module_name", "=", "gallery") - ->where("name", "=", "_cache") - ->execute() - ->current(); - if ($row) { - self::$var_cache = unserialize($row->value); - } else { - // gallery._cache doesn't exist. Create it now. + self::$var_cache = Cache::instance()->get("var_cache"); + if (empty(self::$var_cache)) { + // Cache doesn't exist, create it now. foreach (db::build() ->select("module_name", "name", "value") ->from("vars") ->order_by("module_name") ->order_by("name") ->execute() as $row) { - if ($row->module_name == "gallery" && $row->name == "_cache") { - // This could happen if there's a race condition - continue; - } // Mute the "Creating default object from empty value" warning below @self::$var_cache->{$row->module_name}->{$row->name} = $row->value; } - $cache = ORM::factory("var"); - $cache->module_name = "gallery"; - $cache->name = "_cache"; - $cache->value = serialize(self::$var_cache); - try { - $cache->save(); - } catch (Database_Exception $e) { - // There's a potential race condition here. Don't fail if that happens because it's - // bound to be transient and not a huge deal, but at least put something in the logs. - if (stristr($e->getMessage(), "duplicate entry")) { - Kohana_Log::add("error", "Failed to cache vars"); - } else { - throw $e; - } - } + Cache::instance()->set("var_cache", self::$var_cache, array("vars")); } } @@ -495,11 +468,7 @@ class module_Core { $var->value = $value; $var->save(); - db::build() - ->delete("vars") - ->where("module_name", "=", "gallery") - ->where("name", "=", "_cache") - ->execute(); + Cache::instance()->delete("var_cache"); self::$var_cache = null; } @@ -524,11 +493,7 @@ class module_Core { ->where("name", "=", $name) ->execute(); - db::build() - ->delete("vars") - ->where("module_name", "=", "gallery") - ->where("name", "=", "_cache") - ->execute(); + Cache::instance()->delete("var_cache"); self::$var_cache = null; } @@ -538,19 +503,27 @@ class module_Core { * @param string $name */ static function clear_var($module_name, $name) { - $var = ORM::factory("var") + db::build() + ->delete("vars") ->where("module_name", "=", $module_name) ->where("name", "=", $name) - ->find(); - if ($var->loaded()) { - $var->delete(); - } + ->execute(); + + Cache::instance()->delete("var_cache"); + self::$var_cache = null; + } + /** + * Remove all variables for this module. + * @param string $module_name + */ + static function clear_all_vars($module_name) { db::build() ->delete("vars") - ->where("module_name", "=", "gallery") - ->where("name", "=", "_cache") + ->where("module_name", "=", $module_name) ->execute(); + + Cache::instance()->delete("var_cache"); self::$var_cache = null; } @@ -559,6 +532,6 @@ class module_Core { * @param string $module_name */ static function get_version($module_name) { - return self::get($module_name)->version; + return module::get($module_name)->version; } } diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php index 78358b6b..0895c5f4 100644 --- a/modules/gallery/helpers/movie.php +++ b/modules/gallery/helpers/movie.php @@ -58,7 +58,7 @@ class movie_Core { } static function extract_frame($input_file, $output_file) { - $ffmpeg = self::find_ffmpeg(); + $ffmpeg = movie::find_ffmpeg(); if (empty($ffmpeg)) { throw new Exception("@todo MISSING_FFMPEG"); } @@ -103,7 +103,7 @@ class movie_Core { * Return the width, height, mime_type and extension of the given movie file. */ static function get_file_metadata($file_path) { - $ffmpeg = self::find_ffmpeg(); + $ffmpeg = movie::find_ffmpeg(); if (empty($ffmpeg)) { throw new Exception("@todo MISSING_FFMPEG"); } diff --git a/modules/gallery/helpers/site_status.php b/modules/gallery/helpers/site_status.php index 13c42dda..85f30dba 100644 --- a/modules/gallery/helpers/site_status.php +++ b/modules/gallery/helpers/site_status.php @@ -101,7 +101,7 @@ class site_status_Core { $buf = array(); foreach (ORM::factory("message")->find_all() as $msg) { $value = str_replace("__CSRF__", access::csrf_token(), $msg->value); - $buf[] = "<li class=\"" . self::severity_class($msg->severity) . "\">$value</li>"; + $buf[] = "<li class=\"" . site_status::severity_class($msg->severity) . "\">$value</li>"; } if ($buf) { @@ -116,16 +116,16 @@ class site_status_Core { */ static function severity_class($severity) { switch($severity) { - case self::SUCCESS: + case site_status::SUCCESS: return "g-success"; - case self::INFO: + case site_status::INFO: return "g-info"; - case self::WARNING: + case site_status::WARNING: return "g-warning"; - case self::ERROR: + case site_status::ERROR: return "g-error"; } } diff --git a/modules/gallery/libraries/InPlaceEdit.php b/modules/gallery/libraries/InPlaceEdit.php index 7e631ab9..42eb2ffe 100644 --- a/modules/gallery/libraries/InPlaceEdit.php +++ b/modules/gallery/libraries/InPlaceEdit.php @@ -70,7 +70,7 @@ class InPlaceEdit_Core { public function render() { $v = new View("in_place_edit.html"); - $v->action = url::site($this->action); + $v->action = $this->action; $v->form = $this->form; $v->errors = $this->errors; foreach ($v->errors as $key => $error) { diff --git a/modules/gallery/libraries/ORM_MPTT.php b/modules/gallery/libraries/ORM_MPTT.php index d8d88e4e..f20fafa0 100644 --- a/modules/gallery/libraries/ORM_MPTT.php +++ b/modules/gallery/libraries/ORM_MPTT.php @@ -96,12 +96,16 @@ class ORM_MPTT_Core extends ORM { $item->reload()->delete(); } - // Deleting children has affected this item - $this->reload(); + // Deleting children has affected this item, but we'll reload it below. } $this->lock(); $this->reload(); // Assume that the prior lock holder may have changed this entry + if (!$this->loaded()) { + // Concurrent deletes may result in this item already being gone. Ignore it. + return; + } + try { db::build() ->update($this->table_name) diff --git a/modules/gallery/models/access_cache.php b/modules/gallery/models/access_cache.php index af1b5c6c..e730f25c 100644 --- a/modules/gallery/models/access_cache.php +++ b/modules/gallery/models/access_cache.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Access_Cache_Model extends ORM { +class Access_Cache_Model_Core extends ORM { } diff --git a/modules/gallery/models/access_intent.php b/modules/gallery/models/access_intent.php index e71f8c46..31711014 100644 --- a/modules/gallery/models/access_intent.php +++ b/modules/gallery/models/access_intent.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Access_Intent_Model extends ORM { +class Access_Intent_Model_Core extends ORM { } diff --git a/modules/gallery/models/cache.php b/modules/gallery/models/cache.php index 4a7e37f6..1c464d51 100644 --- a/modules/gallery/models/cache.php +++ b/modules/gallery/models/cache.php @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Cache_Model extends ORM {} +class Cache_Model_Core extends ORM {} diff --git a/modules/gallery/models/failed_auth.php b/modules/gallery/models/failed_auth.php index a541f435..649e4bc9 100644 --- a/modules/gallery/models/failed_auth.php +++ b/modules/gallery/models/failed_auth.php @@ -17,4 +17,4 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Failed_Auth_Model extends ORM {} +class Failed_Auth_Model_Core extends ORM {} diff --git a/modules/gallery/models/graphics_rule.php b/modules/gallery/models/graphics_rule.php index 49036b9c..09410af0 100644 --- a/modules/gallery/models/graphics_rule.php +++ b/modules/gallery/models/graphics_rule.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Graphics_Rule_Model extends ORM { +class Graphics_Rule_Model_Core extends ORM { } diff --git a/modules/gallery/models/incoming_translation.php b/modules/gallery/models/incoming_translation.php index 45340c30..ff6a7160 100644 --- a/modules/gallery/models/incoming_translation.php +++ b/modules/gallery/models/incoming_translation.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Incoming_Translation_Model extends ORM { +class Incoming_Translation_Model_Core extends ORM { } diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 07f781d1..9016a04a 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -20,7 +20,7 @@ class Item_Model_Core extends ORM_MPTT { protected $children = "items"; protected $sorting = array(); - protected $data_file = null; + public $data_file = null; public function __construct($id=null) { parent::__construct($id); @@ -71,6 +71,11 @@ class Item_Model_Core extends ORM_MPTT { } public function delete($ignored_id=null) { + if (!$this->loaded()) { + // Concurrent deletes may result in this item already being gone. Ignore it. + return; + } + if ($this->id == 1) { $v = new Validation(array("id")); $v->add_error("id", "cant_delete_root_album"); @@ -166,8 +171,9 @@ class Item_Model_Core extends ORM_MPTT { */ public function file_url($full_uri=false) { $relative_path = "var/albums/" . $this->relative_path(); + $cache_buster = $this->_cache_buster($this->file_path()); return ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)) - . "?m={$this->updated}"; + . $cache_buster; } /** @@ -198,7 +204,7 @@ class Item_Model_Core extends ORM_MPTT { * photo: http://example.com/gallery3/var/albums/album1/photo.thumb.jpg */ public function thumb_url($full_uri=false) { - $cache_buster = "?m={$this->updated}"; + $cache_buster = $this->_cache_buster($this->thumb_path()); $relative_path = "var/thumbs/" . $this->relative_path(); $base = ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)); if ($this->is_photo()) { @@ -227,9 +233,9 @@ class Item_Model_Core extends ORM_MPTT { */ public function resize_url($full_uri=false) { $relative_path = "var/resizes/" . $this->relative_path(); + $cache_buster = $this->_cache_buster($this->resize_path()); return ($full_uri ? url::abs_file($relative_path) : url::file($relative_path)) . - ($this->is_album() ? "/.album.jpg" : "") - . "?m={$this->updated}"; + ($this->is_album() ? "/.album.jpg" : "") . $cache_buster; } /** @@ -320,6 +326,7 @@ class Item_Model_Core extends ORM_MPTT { $this->updated = time(); if (!$this->loaded()) { // Create a new item. + module::event("item_before_create", $this); // Set a weight if it's missing. We don't do this in the constructor because it's not a // simple assignment. @@ -398,6 +405,7 @@ class Item_Model_Core extends ORM_MPTT { module::event("item_created", $this); } else { // Update an existing item + module::event("item_before_update", $item); // If any significant fields have changed, load up a copy of the original item and // keep it around. @@ -628,7 +636,7 @@ class Item_Model_Core extends ORM_MPTT { list ($height, $width) = $this->scale_dimensions($max); if ($center_vertically && $max) { // The constant is divide by 2 to calculate the file and 10 to convert to em - $margin_top = ($max - $height) / 20; + $margin_top = (int)(($max - $height) / 20); $extra_attrs["style"] = "margin-top: {$margin_top}em"; $extra_attrs["title"] = $this->title; } @@ -656,10 +664,10 @@ class Item_Model_Core extends ORM_MPTT { if ($height) { if (isset($max)) { if ($width > $height) { - $height = (int)($max * ($height / $width)); + $height = (int)($max * $height / $width); $width = $max; } else { - $width = (int)($max * ($width / $height)); + $width = (int)($max * $width / $height); $height = $max; } } @@ -700,10 +708,10 @@ class Item_Model_Core extends ORM_MPTT { $height = $this->height; if ($width > $max_size || $height > $max_size) { if ($width > $height) { - $height *= $max_size / $width; + $height = (int)($height * $max_size / $width); $width = $max_size; } else { - $width *= $max_size / $height; + $width = (int)($width * $max_size / $height); $height = $max_size; } } @@ -1022,4 +1030,8 @@ class Item_Model_Core extends ORM_MPTT { } return $data; } + + private function _cache_buster($path) { + return "?m=" . (string)(file_exists($path) ? filemtime($path) : 0); + } } diff --git a/modules/gallery/models/log.php b/modules/gallery/models/log.php index aa1a37ed..5d065313 100644 --- a/modules/gallery/models/log.php +++ b/modules/gallery/models/log.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Log_Model extends ORM { +class Log_Model_Core extends ORM { /** * @see ORM::__get() */ diff --git a/modules/gallery/models/message.php b/modules/gallery/models/message.php index 994d0cdb..3f84efd0 100644 --- a/modules/gallery/models/message.php +++ b/modules/gallery/models/message.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Message_Model extends ORM { +class Message_Model_Core extends ORM { } diff --git a/modules/gallery/models/module.php b/modules/gallery/models/module.php index dc181849..e54613d1 100644 --- a/modules/gallery/models/module.php +++ b/modules/gallery/models/module.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Module_Model extends ORM { +class Module_Model_Core extends ORM { } diff --git a/modules/gallery/models/outgoing_translation.php b/modules/gallery/models/outgoing_translation.php index 43f56dce..cd580bed 100644 --- a/modules/gallery/models/outgoing_translation.php +++ b/modules/gallery/models/outgoing_translation.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Outgoing_Translation_Model extends ORM { +class Outgoing_Translation_Model_Core extends ORM { } diff --git a/modules/gallery/models/permission.php b/modules/gallery/models/permission.php index b6b544d5..51bd95e7 100644 --- a/modules/gallery/models/permission.php +++ b/modules/gallery/models/permission.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Permission_Model extends ORM { +class Permission_Model_Core extends ORM { } diff --git a/modules/gallery/models/task.php b/modules/gallery/models/task.php index 4888a734..4d435101 100644 --- a/modules/gallery/models/task.php +++ b/modules/gallery/models/task.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Task_Model extends ORM { +class Task_Model_Core extends ORM { public function get($key, $default=null) { $context = unserialize($this->context); if (array_key_exists($key, $context)) { diff --git a/modules/gallery/models/theme.php b/modules/gallery/models/theme.php index 523542f9..50fd04fd 100644 --- a/modules/gallery/models/theme.php +++ b/modules/gallery/models/theme.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Theme_Model extends ORM { +class Theme_Model_Core extends ORM { }
\ No newline at end of file diff --git a/modules/gallery/models/var.php b/modules/gallery/models/var.php index a79d0048..f21486ee 100644 --- a/modules/gallery/models/var.php +++ b/modules/gallery/models/var.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Var_Model extends ORM { +class Var_Model_Core extends ORM { } diff --git a/modules/gallery/module.info b/modules/gallery/module.info index 1155ddf7..2b684e5e 100644 --- a/modules/gallery/module.info +++ b/modules/gallery/module.info @@ -1,3 +1,3 @@ name = "Gallery 3" description = "Gallery core application" -version = 40 +version = 41 diff --git a/modules/gallery/tests/Item_Model_Test.php b/modules/gallery/tests/Item_Model_Test.php index 90c54e3c..264a2128 100644 --- a/modules/gallery/tests/Item_Model_Test.php +++ b/modules/gallery/tests/Item_Model_Test.php @@ -406,6 +406,29 @@ class Item_Model_Test extends Gallery_Unit_Test_Case { return; // pass } $this->assert_true(false, "Shouldn't get here"); + } + + public function urls_test() { + $photo = test::random_photo(); + $this->assert_true( + preg_match("|http://./var/resizes/name_\d+\.jpg\?m=\d+|", $photo->resize_url()), + $photo->resize_url() . " is malformed"); + $this->assert_true( + preg_match("|http://./var/thumbs/name_\d+\.jpg\?m=\d+|", $photo->thumb_url()), + $photo->thumb_url() . " is malformed"); + $this->assert_true( + preg_match("|http://./var/albums/name_\d+\.jpg\?m=\d+|", $photo->file_url()), + $photo->file_url() . " is malformed"); + // Albums have special thumbnails. Empty album has cachebuster of 0 since it has no thumbnail + $album = test::random_album(); + $this->assert_true( + preg_match("|http://./var/thumbs/name_\d+/\.album\.jpg\?m=0|", $album->thumb_url()), + $album->thumb_url() . " is malformed"); + + $photo = test::random_photo($album); + $this->assert_true( + preg_match("|http://./var/thumbs/name_\d+/\.album\.jpg\?m=\d+|", $album->thumb_url()), + $album->thumb_url() . " is malformed"); } } diff --git a/modules/gallery/tests/Var_Test.php b/modules/gallery/tests/Var_Test.php index b3492c71..292fe2f1 100644 --- a/modules/gallery/tests/Var_Test.php +++ b/modules/gallery/tests/Var_Test.php @@ -19,31 +19,37 @@ */ class Var_Test extends Gallery_Unit_Test_Case { public function add_parameter_test() { - module::set_var("gallery", "Parameter", "original value"); - $this->assert_equal("original value", module::get_var("gallery", "Parameter")); + module::set_var("Var_Test", "Parameter", "original value"); + $this->assert_equal("original value", module::get_var("Var_Test", "Parameter")); - module::set_var("gallery", "Parameter", "updated value"); - $this->assert_equal("updated value", module::get_var("gallery", "Parameter")); + module::set_var("Var_Test", "Parameter", "updated value"); + $this->assert_equal("updated value", module::get_var("Var_Test", "Parameter")); } public function clear_parameter_test() { - module::set_var("gallery", "Parameter", "original value"); - $this->assert_equal("original value", module::get_var("gallery", "Parameter")); + module::set_var("Var_Test", "Parameter", "original value"); + module::clear_var("Var_Test", "Parameter"); + $this->assert_equal(null, module::get_var("Var_Test", "Parameter")); + } - module::clear_var("gallery", "Parameter"); - $this->assert_equal(null, module::get_var("gallery", "Parameter")); + public function clear_all_module_parameters_test() { + module::set_var("Var_Test", "Parameter1", "original value"); + module::set_var("Var_Test", "Parameter2", "original value"); + module::clear_all_vars("Var_Test"); + $this->assert_equal(null, module::get_var("Var_Test", "Parameter1")); + $this->assert_equal(null, module::get_var("Var_Test", "Parameter2")); } public function incr_parameter_test() { - module::set_var("gallery", "Parameter", "original value"); - module::incr_var("gallery", "Parameter"); - $this->assert_equal("1", module::get_var("gallery", "Parameter")); + module::set_var("Var_Test", "Parameter", "original value"); + module::incr_var("Var_Test", "Parameter"); + $this->assert_equal("1", module::get_var("Var_Test", "Parameter")); - module::set_var("gallery", "Parameter", "2"); - module::incr_var("gallery", "Parameter", "9"); - $this->assert_equal("11", module::get_var("gallery", "Parameter")); + module::set_var("Var_Test", "Parameter", "2"); + module::incr_var("Var_Test", "Parameter", "9"); + $this->assert_equal("11", module::get_var("Var_Test", "Parameter")); - module::incr_var("gallery", "NonExistent", "9"); - $this->assert_equal(null, module::get_var("gallery", "NonExistent")); + module::incr_var("Var_Test", "NonExistent", "9"); + $this->assert_equal(null, module::get_var("Var_Test", "NonExistent")); } }
\ No newline at end of file diff --git a/modules/gallery/tests/controller_auth_data.txt b/modules/gallery/tests/controller_auth_data.txt index 9ea6043a..24170092 100644 --- a/modules/gallery/tests/controller_auth_data.txt +++ b/modules/gallery/tests/controller_auth_data.txt @@ -1,7 +1,6 @@ modules/comment/controllers/admin_manage_comments.php queue DIRTY_CSRF modules/comment/helpers/comment_rss.php feed DIRTY_AUTH modules/digibug/controllers/digibug.php print_proxy DIRTY_CSRF|DIRTY_AUTH -modules/digibug/controllers/digibug.php close_window DIRTY_AUTH modules/g2_import/controllers/g2.php map DIRTY_CSRF modules/gallery/controllers/admin.php __call DIRTY_AUTH modules/gallery/controllers/albums.php index DIRTY_AUTH diff --git a/modules/gallery/tests/selenium/Add_Album.html b/modules/gallery/tests/selenium/Add_Album.html deleted file mode 100644 index ccd4d0b7..00000000 --- a/modules/gallery/tests/selenium/Add_Album.html +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>AddAlbum</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">AddAlbum</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/index.php/albums/1</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>link=Add album</td> - <td></td> -</tr> -<tr> - <td>type</td> - <td>name</td> - <td>seleniumtest</td> -</tr> -<tr> - <td>type</td> - <td>title</td> - <td>Selenium Test Album</td> -</tr> -<tr> - <td>type</td> - <td>description</td> - <td>Test</td> -</tr> -<tr> - <td>click</td> - <td>//button[@type='button']</td> - <td></td> -</tr> -<tr> - <td>assertTextPresent</td> - <td>Selenium Test Album</td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/modules/gallery/tests/selenium/Add_Comment.html b/modules/gallery/tests/selenium/Add_Comment.html deleted file mode 100644 index 054e7597..00000000 --- a/modules/gallery/tests/selenium/Add_Comment.html +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>Add comment</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">Add comment</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/index.php/albums/1</td> - <td></td> -</tr> -<tr> - <td>clickAndWait</td> - <td>g-photo-id-2</td> - <td></td> -</tr> -<tr> - <td>type</td> - <td>g-author</td> - <td>Test</td> -</tr> -<tr> - <td>type</td> - <td>g-email</td> - <td>test@gmail.com</td> -</tr> -<tr> - <td>type</td> - <td>g-text</td> - <td>This is a selenium test comment.</td> -</tr> -<tr> - <td>click</td> - <td>//button[@type='submit']</td> - <td></td> -</tr> -<tr> - <td>assertTextPresent</td> - <td>This is a selenium test comment.</td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/modules/gallery/tests/selenium/Add_Item.html b/modules/gallery/tests/selenium/Add_Item.html deleted file mode 100644 index 741dff65..00000000 --- a/modules/gallery/tests/selenium/Add_Item.html +++ /dev/null @@ -1,62 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>AddItem</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">AddItem</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/index.php/albums/1</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>link=Add an item</td> - <td></td> -</tr> -<tr> - <td>type</td> - <td>name</td> - <td>seleniumitem.jpg</td> -</tr> -<tr> - <td>type</td> - <td>title</td> - <td>Selenium Item</td> -</tr> -<tr> - <td>type</td> - <td>description</td> - <td>Test item</td> -</tr> -<tr> - <td>type</td> - <td>file</td> - <td>/Users/ckieffer/Sites/gallery3.0/core/tests/images/DSC_0003.jpg</td> -</tr> -<tr> - <td>click</td> - <td>//button[@type='button']</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>link=X</td> - <td></td> -</tr> -<tr> - <td>assertTextPresent</td> - <td>Selenium Item</td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/modules/gallery/tests/selenium/Login.html b/modules/gallery/tests/selenium/Login.html deleted file mode 100644 index d2e45c63..00000000 --- a/modules/gallery/tests/selenium/Login.html +++ /dev/null @@ -1,47 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> -<head profile="http://selenium-ide.openqa.org/profiles/test-case"> -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> -<link rel="selenium.base" href="" /> -<title>Login</title> -</head> -<body> -<table cellpadding="1" cellspacing="1" border="1"> -<thead> -<tr><td rowspan="1" colspan="3">Login</td></tr> -</thead><tbody> -<tr> - <td>open</td> - <td>/index.php/albums/1</td> - <td></td> -</tr> -<tr> - <td>click</td> - <td>g-login-link</td> - <td></td> -</tr> -<tr> - <td>type</td> - <td>g-name</td> - <td>admin</td> -</tr> -<tr> - <td>type</td> - <td>g-password</td> - <td>admin</td> -</tr> -<tr> - <td>clickAndWait</td> - <td>//button[@type='button']</td> - <td></td> -</tr> -<tr> - <td>clickAndWait</td> - <td>g-user-profile-link</td> - <td></td> -</tr> - -</tbody></table> -</body> -</html> diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index a714b3e5..0345df96 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -43,8 +43,8 @@ modules/digibug/views/digibug_form.html.php 6 DIRTY form:: modules/exif/views/exif_dialog.html.php 14 DIRTY $details[$i]["caption"] modules/exif/views/exif_dialog.html.php 21 DIRTY $details[$i]["caption"] modules/g2_import/views/admin_g2_import.html.php 9 DIRTY $form -modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY_ATTR text::alternate("g-odd","g-even") -modules/gallery/views/admin_advanced_settings.html.php 22 DIRTY $var->module_name +modules/gallery/views/admin_advanced_settings.html.php 20 DIRTY_ATTR text::alternate("g-odd","g-even") +modules/gallery/views/admin_advanced_settings.html.php 21 DIRTY $var->module_name modules/gallery/views/admin_block_log_entries.html.php 4 DIRTY_ATTR log::severity_class($entry->severity) modules/gallery/views/admin_block_log_entries.html.php 8 DIRTY_JS user_profile::url($entry->user->id) modules/gallery/views/admin_block_log_entries.html.php 10 DIRTY gallery::date_time($entry->timestamp) @@ -355,19 +355,19 @@ modules/user/views/admin_users_group.html.php 24 DIRTY_JS $group modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $width modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $height modules/watermark/views/admin_watermarks.html.php 20 DIRTY_ATTR $url -themes/admin_wind/views/admin.html.php 22 DIRTY_JS $theme->url() -themes/admin_wind/views/admin.html.php 39 DIRTY $theme->admin_head() -themes/admin_wind/views/admin.html.php 43 DIRTY $theme->admin_page_top() -themes/admin_wind/views/admin.html.php 51 DIRTY $theme->admin_header_top() -themes/admin_wind/views/admin.html.php 52 DIRTY_JS item::root()->url() -themes/admin_wind/views/admin.html.php 55 DIRTY $theme->user_menu() -themes/admin_wind/views/admin.html.php 58 DIRTY $theme->admin_menu() -themes/admin_wind/views/admin.html.php 61 DIRTY $theme->admin_header_bottom() -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 82 DIRTY $theme->admin_credits() -themes/admin_wind/views/admin.html.php 87 DIRTY $theme->admin_page_bottom() +themes/admin_wind/views/admin.html.php 21 DIRTY_JS $theme->url() +themes/admin_wind/views/admin.html.php 38 DIRTY $theme->admin_head() +themes/admin_wind/views/admin.html.php 42 DIRTY $theme->admin_page_top() +themes/admin_wind/views/admin.html.php 50 DIRTY $theme->admin_header_top() +themes/admin_wind/views/admin.html.php 51 DIRTY_JS item::root()->url() +themes/admin_wind/views/admin.html.php 54 DIRTY $theme->user_menu() +themes/admin_wind/views/admin.html.php 57 DIRTY $theme->admin_menu() +themes/admin_wind/views/admin.html.php 60 DIRTY $theme->admin_header_bottom() +themes/admin_wind/views/admin.html.php 67 DIRTY $content +themes/admin_wind/views/admin.html.php 73 DIRTY $sidebar +themes/admin_wind/views/admin.html.php 78 DIRTY $theme->admin_footer() +themes/admin_wind/views/admin.html.php 81 DIRTY $theme->admin_credits() +themes/admin_wind/views/admin.html.php 86 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 @@ -399,17 +399,17 @@ themes/wind/views/dynamic.html.php 29 DIRTY $theme themes/wind/views/movie.html.php 5 DIRTY $theme->paginator() themes/wind/views/movie.html.php 9 DIRTY $item->movie_img(array("class"=>"g-movie","id"=>"g-item-id-{$item->id}")) themes/wind/views/page.html.php 9 DIRTY $page_title -themes/wind/views/page.html.php 33 DIRTY_JS $theme->url() -themes/wind/views/page.html.php 42 DIRTY $new_width -themes/wind/views/page.html.php 43 DIRTY $new_height -themes/wind/views/page.html.php 44 DIRTY $thumb_proportion -themes/wind/views/page.html.php 81 DIRTY $header_text -themes/wind/views/page.html.php 83 DIRTY_JS item::root()->url() -themes/wind/views/page.html.php 87 DIRTY $theme->user_menu() -themes/wind/views/page.html.php 108 DIRTY_JS $parent->url($parent->id==$theme->item()->parent_id?"show={$theme->item()->id}":null) -themes/wind/views/page.html.php 129 DIRTY $content -themes/wind/views/page.html.php 135 DIRTY newView("sidebar.html") -themes/wind/views/page.html.php 142 DIRTY $footer_text +themes/wind/views/page.html.php 32 DIRTY_JS $theme->url() +themes/wind/views/page.html.php 41 DIRTY $new_width +themes/wind/views/page.html.php 42 DIRTY $new_height +themes/wind/views/page.html.php 43 DIRTY $thumb_proportion +themes/wind/views/page.html.php 80 DIRTY $header_text +themes/wind/views/page.html.php 82 DIRTY_JS item::root()->url() +themes/wind/views/page.html.php 86 DIRTY $theme->user_menu() +themes/wind/views/page.html.php 107 DIRTY_JS $parent->url($parent->id==$theme->item()->parent_id?"show={$theme->item()->id}":null) +themes/wind/views/page.html.php 128 DIRTY $content +themes/wind/views/page.html.php 134 DIRTY newView("sidebar.html") +themes/wind/views/page.html.php 141 DIRTY $footer_text themes/wind/views/paginator.html.php 33 DIRTY_JS $first_page_url themes/wind/views/paginator.html.php 42 DIRTY_JS $previous_page_url themes/wind/views/paginator.html.php 70 DIRTY_JS $next_page_url diff --git a/modules/gallery/views/admin_advanced_settings.html.php b/modules/gallery/views/admin_advanced_settings.html.php index 1f7d2f64..d4f646f8 100644 --- a/modules/gallery/views/admin_advanced_settings.html.php +++ b/modules/gallery/views/admin_advanced_settings.html.php @@ -9,6 +9,7 @@ <li class="g-warning"><?= t("Change these values at your own risk!") ?></li> </ul> + <?= t("Filter:") ?> <input id="g-admin-advanced-settings-filter" type="text"></input> <div class="g-block-content"> <table> <tr> @@ -17,8 +18,7 @@ <th> <?= t("Value") ?></th> </tr> <? foreach ($vars as $var): ?> - <? if ($var->module_name == "gallery" && $var->name == "_cache") continue ?> - <tr class="<?= text::alternate("g-odd", "g-even") ?>"> + <tr class="setting-row <?= text::alternate("g-odd", "g-even") ?>"> <td> <?= $var->module_name ?> </td> <td> <?= html::clean($var->name) ?> </td> <td> @@ -36,4 +36,22 @@ <? endforeach ?> </table> </div> + + <script> + $(document).ready(function() { + $("#g-admin-advanced-settings-filter").keyup(function() { + var filter = $(this).attr("value"); + if (filter) { + $("tr.setting-row").fadeOut("fast"); + $("tr.setting-row td:contains(" + filter + "), tr.setting-row td a:contains(" + filter + ")").each(function() { + if ($(this).children().length < 1) { + $(this).closest("tr").stop().show(); + } + }); + } else { + $("tr.setting-row").show(); + } + }); + }); + </script> </div> diff --git a/modules/gallery/views/admin_block_platform.html.php b/modules/gallery/views/admin_block_platform.html.php index 379ab0aa..9a594fa5 100644 --- a/modules/gallery/views/admin_block_platform.html.php +++ b/modules/gallery/views/admin_block_platform.html.php @@ -16,7 +16,7 @@ <?= t("MySQL: %mysql_version", array("mysql_version" => Database::instance()->query("SELECT version() as v")->current()->v)) ?> </li> <li> - <?= t("Server load: %load_average", array("load_average" => $load_average)) ?> + <?= t("Server load: %load_average", array("load_average" => join(" ", sys_getloadavg()))) ?> </li> <li> <?= t("Graphics toolkit: %toolkit", array("toolkit" => module::get_var("gallery", "graphics_toolkit"))) ?> diff --git a/modules/gallery/views/upgrader.html.php b/modules/gallery/views/upgrader.html.php index 1ec49c77..ad2e3421 100644 --- a/modules/gallery/views/upgrader.html.php +++ b/modules/gallery/views/upgrader.html.php @@ -17,7 +17,7 @@ <a id="dialog_close_link" style="display: none" onclick="$('#dialog').fadeOut(); return false;" href="#" class="close">[x]</a> <div id="busy" style="display: none"> <h1> - <img width="16" height="16" src="<?= url::file("lib/images/loading-small.gif") ?>"/> + <img width="16" height="16" src="<?= url::file("themes/wind/images/loading-small.gif") ?>"/> <?= t("Upgrade in progress!") ?> </h1> <p> diff --git a/modules/gallery_unit_test/controllers/gallery_unit_test.php b/modules/gallery_unit_test/controllers/gallery_unit_test.php index e241e1dd..c4a891ba 100644 --- a/modules/gallery_unit_test/controllers/gallery_unit_test.php +++ b/modules/gallery_unit_test/controllers/gallery_unit_test.php @@ -132,6 +132,7 @@ class Gallery_Unit_Test_Controller extends Controller { graphics::choose_default_toolkit(); $filter = count($_SERVER["argv"]) > 2 ? $_SERVER["argv"][2] : null; + set_time_limit(300); print new Unit_Test($modules, $filter); } catch (ORM_Validation_Exception $e) { print "Validation Exception: {$e->getMessage()}\n"; diff --git a/modules/image_block/helpers/image_block_block.php b/modules/image_block/helpers/image_block_block.php index da6e8782..0a53672c 100644 --- a/modules/image_block/helpers/image_block_block.php +++ b/modules/image_block/helpers/image_block_block.php @@ -29,16 +29,24 @@ class image_block_block_Core { // The random_query approach is flawed and doesn't always return a // result when there actually is one. Retry a *few* times. // @todo Consider another fallback if further optimizations are necessary. - $attempts = 0; - do { - $item = item::random_query()->where("type", "!=", "album")->find_all(1)->current(); - } while (!$item && $attempts++ < 3); - if ($item && $item->loaded()) { + $image_count = module::get_var("image_block", "image_count"); + $items = array(); + for ($i = 0; $i < $image_count; $i++) { + $attempts = 0; + $item = null; + do { + $item = item::random_query()->where("type", "!=", "album")->find_all(1)->current(); + } while (!$item && $attempts++ < 3); + if ($item) { + $items[] = $item; + } + } + if ($items) { $block = new Block(); $block->css_id = "g-image-block"; $block->title = t("Random image"); $block->content = new View("image_block_block.html"); - $block->content->item = $item; + $block->content->items = $items; } break; } diff --git a/modules/image_block/helpers/image_block_installer.php b/modules/image_block/helpers/image_block_installer.php new file mode 100644 index 00000000..62c38ba4 --- /dev/null +++ b/modules/image_block/helpers/image_block_installer.php @@ -0,0 +1,34 @@ +<?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 image_block_installer { + + static function install() { + module::set_var("image_block", "image_count", "1"); + module::set_version("image_block", $version = 2); + } + + static function upgrade($version) { + $db = Database::instance(); + if ($version == 1) { + module::set_var("image_block", "image_count", "1"); + module::set_version("image_block", $version = 2); + } + } +} diff --git a/modules/image_block/module.info b/modules/image_block/module.info index e6d85048..b92b83df 100644 --- a/modules/image_block/module.info +++ b/modules/image_block/module.info @@ -1,3 +1,3 @@ name = "Image Block" description = "Display a random image in the sidebar" -version = 1 +version = 2 diff --git a/modules/image_block/views/image_block_block.html.php b/modules/image_block/views/image_block_block.html.php index 68d5fa89..2a57c395 100644 --- a/modules/image_block/views/image_block_block.html.php +++ b/modules/image_block/views/image_block_block.html.php @@ -1,6 +1,8 @@ <?php defined("SYSPATH") or die("No direct script access.") ?> +<? foreach ($items as $item): ?> <div class="g-image-block"> <a href="<?= $item->url() ?>"> <?= $item->thumb_img(array("class" => "g-thumbnail")) ?> </a> </div> +<? endforeach ?> diff --git a/modules/notification/models/pending_notification.php b/modules/notification/models/pending_notification.php index c447620e..5857ce8c 100644 --- a/modules/notification/models/pending_notification.php +++ b/modules/notification/models/pending_notification.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Pending_Notification_Model extends ORM { +class Pending_Notification_Model_Core extends ORM { }
\ No newline at end of file diff --git a/modules/notification/models/subscription.php b/modules/notification/models/subscription.php index 043de45c..273b6ad9 100644 --- a/modules/notification/models/subscription.php +++ b/modules/notification/models/subscription.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Subscription_Model extends ORM { +class Subscription_Model_Core extends ORM { }
\ No newline at end of file diff --git a/modules/rest/controllers/rest.php b/modules/rest/controllers/rest.php index a721ff2b..c4e0fda4 100644 --- a/modules/rest/controllers/rest.php +++ b/modules/rest/controllers/rest.php @@ -86,6 +86,9 @@ class Rest_Controller extends Controller { } $request->url = url::abs_current(true); + if ($suffix = Kohana::config('core.url_suffix')) { + $request->url = substr($request->url, 0, strlen($request->url) - strlen($suffix)); + } rest::set_active_user($request->access_key); diff --git a/modules/rest/helpers/rest.php b/modules/rest/helpers/rest.php index d5ed0452..58943700 100644 --- a/modules/rest/helpers/rest.php +++ b/modules/rest/helpers/rest.php @@ -122,7 +122,12 @@ class rest_Core { * @return mixed the corresponding object (usually a model of some kind) */ static function resolve($url) { - $relative_url = substr($url, strlen(url::abs_site("rest"))); + if ($suffix = Kohana::config('core.url_suffix')) { + $relative_url = substr($url, strlen(url::abs_site("rest")) - strlen($suffix)); + } else { + $relative_url = substr($url, strlen(url::abs_site("rest"))); + } + $path = parse_url($relative_url, PHP_URL_PATH); $components = explode("/", $path, 3); diff --git a/modules/rest/models/user_access_key.php b/modules/rest/models/user_access_key.php index 1da0f5eb..93c3cf7f 100644 --- a/modules/rest/models/user_access_key.php +++ b/modules/rest/models/user_access_key.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class User_Access_Key_Model extends ORM { +class User_Access_Key_Model_Core extends ORM { } diff --git a/modules/search/models/search_record.php b/modules/search/models/search_record.php index fe9b758f..77290903 100644 --- a/modules/search/models/search_record.php +++ b/modules/search/models/search_record.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Search_Record_Model extends ORM { +class Search_Record_Model_Core extends ORM { function item() { return model_cache::get("item", $this->item_id); } diff --git a/modules/server_add/models/server_add_file.php b/modules/server_add/models/server_add_file.php index 83bde344..92b9f6de 100644 --- a/modules/server_add/models/server_add_file.php +++ b/modules/server_add/models/server_add_file.php @@ -17,5 +17,5 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Server_Add_File_Model extends ORM { +class Server_Add_File_Model_Core extends ORM { } diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php index 0c82579b..99743a8e 100644 --- a/modules/tag/controllers/admin_tags.php +++ b/modules/tag/controllers/admin_tags.php @@ -52,7 +52,6 @@ class Admin_Tags_Controller extends Admin_Controller { $form = tag::get_delete_form($tag); if ($form->validate()) { $name = $tag->name; - db::build()->delete("items_tags")->where("tag_id", "=", $tag->id)->execute(); $tag->delete(); message::success(t("Deleted tag %tag_name", array("tag_name" => $name))); log::success("tags", t("Deleted tag %tag_name", array("tag_name" => $name))); diff --git a/modules/tag/helpers/tag_event.php b/modules/tag/helpers/tag_event.php index 0cc2170c..829089c4 100644 --- a/modules/tag/helpers/tag_event.php +++ b/modules/tag/helpers/tag_event.php @@ -62,6 +62,12 @@ class tag_event_Core { static function item_deleted($item) { tag::clear_all($item); + if (!batch::in_progress()) { + tag::compact(); + } + } + + static function batch_complete() { tag::compact(); } @@ -88,6 +94,7 @@ class tag_event_Core { tag::add($item, trim($tag_name)); } } + module::event("item_related_update", $item); tag::compact(); } @@ -109,7 +116,7 @@ class tag_event_Core { if (!isset($group->uploadify)) { return; } - + $group = $form->add_photos; $group->input("tags") ->label(t("Add tags to all uploaded files")) @@ -132,7 +139,7 @@ class tag_event_Core { if (!isset($group->uploadify)) { return; } - + foreach (explode(",", $form->add_photos->tags->value) as $tag_name) { $tag_name = trim($tag_name); if ($tag_name) { diff --git a/modules/tag/helpers/tag_task.php b/modules/tag/helpers/tag_task.php new file mode 100644 index 00000000..7bf50546 --- /dev/null +++ b/modules/tag/helpers/tag_task.php @@ -0,0 +1,97 @@ +<?php defined("SYSPATH") or die("No direct script access."); +/** + * Gallery - a web based photo album viewer and editor + * Copyright (C) 2000-2010 Bharat Mediratta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ +class tag_task_Core { + + static function available_tasks() { + $tasks[] = Task_Definition::factory() + ->callback("tag_task::clean_up_tags") + ->name(t("Clean up tags")) + ->description(t("Correct tag counts and remove tags with no items")) + ->severity(log::SUCCESS); + return $tasks; + } + + /** + * Fix up tag counts and delete any tags that have no associated items. + * @param Task_Model the task + */ + static function clean_up_tags($task) { + $errors = array(); + try { + $start = microtime(true); + $last_tag_id = $task->get("last_tag_id", null); + $current = 0; + $total = 0; + + switch ($task->get("mode", "init")) { + case "init": + $task->set("total", ORM::factory("tag")->count_all()); + $task->set("mode", "clean_up_tags"); + $task->set("completed", 0); + $task->set("last_tag_id", 0); + + case "clean_up_tags": + $completed = $task->get("completed"); + $total = $task->get("total"); + $last_tag_id = $task->get("last_tag_id"); + $tags = ORM::factory("tag")->where("id", ">", $last_tag_id)->find_all(25); + Kohana_Log::add("error",print_r(Database::instance()->last_query(),1)); + while ($current < $total && microtime(true) - $start < 1 && $tag = $tags->current()) { + $last_tag_id = $tag->id; + $real_count = $tag->items_count(); + if ($tag->count != $real_count) { + $tag->count = $real_count; + if ($tag->count) { + $task->log( + "Fixing count for tag {$tag->name} (id: {$tag->id}, new count: {$tag->count})"); + $tag->save(); + } else { + $task->log("Deleting empty tag {$tag->name} ({$tag->id})"); + $tag->delete(); + } + } + + $completed++; + $tags->next(); + } + $task->percent_complete = $completed / $total * 100; + $task->set("completed", $completed); + $task->set("last_tag_id", $last_tag_id); + } + + $task->status = t2("Examined %count tag", "Examined %count tags", $completed); + + if ($completed == $total) { + $task->done = true; + $task->state = "success"; + $task->percent_complete = 100; + } + } catch (Exception $e) { + Kohana_Log::add("error",(string)$e); + $task->done = true; + $task->state = "error"; + $task->status = $e->getMessage(); + $errors[] = (string)$e; + } + if ($errors) { + $task->log($errors); + } + } +}
\ No newline at end of file diff --git a/modules/tag/models/tag.php b/modules/tag/models/tag.php index 269a0f39..c038f6d1 100644 --- a/modules/tag/models/tag.php +++ b/modules/tag/models/tag.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Tag_Model extends ORM { +class Tag_Model_Core extends ORM { protected $has_and_belongs_to_many = array("items"); /** @@ -57,8 +57,7 @@ class Tag_Model extends ORM { /** * Overload ORM::save() to trigger an item_related_update event for all items that are related - * to this tag. Since items can be added or removed as part of the save, we need to trigger an - * event for the union of all related items before and after the save. + * to this tag. */ public function save() { $related_item_ids = array(); @@ -70,20 +69,16 @@ class Tag_Model extends ORM { $related_item_ids[$row->item_id] = 1; } - $result = parent::save(); - - foreach (db::build() - ->select("item_id") - ->from("items_tags") - ->where("tag_id", "=", $this->id) - ->execute() as $row) { - $related_item_ids[$row->item_id] = 1; + if (isset($this->changed_relations["items"])) { + $changed = array_merge( + array_diff($this->changed_relations["items"], $this->object_relations["items"]), + array_diff($this->object_relations["items"], $this->changed_relations["items"])); } - if ($related_item_ids) { - foreach (ORM::factory("item") - ->where("id", "IN", array_keys($related_item_ids)) - ->find_all() as $item) { + $result = parent::save(); + + if (!empty($changed)) { + foreach (ORM::factory("item")->where("id", "IN", $changed)->find_all() as $item) { module::event("item_related_update", $item); } } @@ -93,7 +88,7 @@ class Tag_Model extends ORM { /** * Overload ORM::delete() to trigger an item_related_update event for all items that are - * related to this tag. + * related to this tag, and delete all items_tags relationships. */ public function delete($ignored_id=null) { $related_item_ids = array(); @@ -105,6 +100,7 @@ class Tag_Model extends ORM { $related_item_ids[$row->item_id] = 1; } + db::build()->delete("items_tags")->where("tag_id", "=", $this->id)->execute(); $result = parent::delete(); if ($related_item_ids) { diff --git a/modules/user/models/group.php b/modules/user/models/group.php index b27c7250..17d9320b 100644 --- a/modules/user/models/group.php +++ b/modules/user/models/group.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class Group_Model extends ORM implements Group_Definition { +class Group_Model_Core extends ORM implements Group_Definition { protected $has_and_belongs_to_many = array("users"); /** diff --git a/modules/user/models/user.php b/modules/user/models/user.php index b28288be..55bb3d6a 100644 --- a/modules/user/models/user.php +++ b/modules/user/models/user.php @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ -class User_Model extends ORM implements User_Definition { +class User_Model_Core extends ORM implements User_Definition { protected $has_and_belongs_to_many = array("groups"); protected $password_length = null; diff --git a/system/helpers/request.php b/system/helpers/request.php index 2cc59b20..c04a2fa2 100644 --- a/system/helpers/request.php +++ b/system/helpers/request.php @@ -123,6 +123,7 @@ class request_Core { if ( ! is_array(request::$user_agent)) { + request::$user_agent = array(); request::$user_agent['agent'] = isset($_SERVER['HTTP_USER_AGENT']) ? trim($_SERVER['HTTP_USER_AGENT']) : ''; // Parse the user agent and extract basic information diff --git a/system/libraries/ORM.php b/system/libraries/ORM.php index 4dd2eaf0..eb34221c 100644 --- a/system/libraries/ORM.php +++ b/system/libraries/ORM.php @@ -1002,7 +1002,11 @@ class ORM_Core { */ public function reload() { - return $this->find($this->object[$this->primary_key]); + if ($this->_loaded) { + return $this->find($this->object[$this->primary_key]); + } else { + return $this->clear(); + } } /** diff --git a/system/libraries/drivers/Image/ImageMagick.php b/system/libraries/drivers/Image/ImageMagick.php index 31862f75..55c0ba24 100644 --- a/system/libraries/drivers/Image/ImageMagick.php +++ b/system/libraries/drivers/Image/ImageMagick.php @@ -133,7 +133,7 @@ class Image_ImageMagick_Driver extends Image_Driver { // Set the IM geometry based on the properties $geometry = escapeshellarg($prop['width'].'x'.$prop['height'].'+'.$prop['left'].'+'.$prop['top']); - if ($error = exec(escapeshellcmd($this->dir.'convert'.$this->ext).' -background '.$this->background.' -flatten -crop '.$geometry.' '.$this->cmd_image.' '.$this->cmd_image)) + if ($error = exec(escapeshellcmd($this->dir.'convert'.$this->ext).' -background '.$this->background.' -flatten -crop '.$geometry.'! '.$this->cmd_image.' '.$this->cmd_image)) { $this->errors[] = $error; return FALSE; |