From 54ae9fac88512f1bac05a5952fca9ade2eab0898 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 31 May 2009 22:12:14 -0700 Subject: Remove extra blank line --- modules/gallery/controllers/file_proxy.php | 1 - 1 file changed, 1 deletion(-) (limited to 'modules/gallery') diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php index 1901bd9f..dfdb4f34 100644 --- a/modules/gallery/controllers/file_proxy.php +++ b/modules/gallery/controllers/file_proxy.php @@ -38,7 +38,6 @@ class File_Proxy_Controller extends Controller { // var_uri: http://example.com/gallery3/var/ $var_uri = url::file("var/"); - // Make sure that the request is for a file inside var $offset = strpos($request_uri, $var_uri); if ($offset === false) { -- cgit v1.2.3 From 33df7de391eebdab2cb09ca97207cb81f4274cd1 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 31 May 2009 22:25:53 -0700 Subject: Accidentally broke the AllowOverride info url in the migration from core -> modules/gallery. Fixed, and incidentally make the link appear in a new tab/window. --- modules/gallery/views/permissions_browse.html.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery') diff --git a/modules/gallery/views/permissions_browse.html.php b/modules/gallery/views/permissions_browse.html.php index 5cd9cf82..8bb2e830 100644 --- a/modules/gallery/views/permissions_browse.html.php +++ b/modules/gallery/views/permissions_browse.html.php @@ -27,7 +27,7 @@ -- cgit v1.2.3 From 9a7e642cd6cc3d250d9d413c3ce0414e92e9d769 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Sun, 31 May 2009 22:30:48 -0700 Subject: Don't let relative_path() try to update the database if the Item_Model is not loaded, else you get weird errors. --- modules/gallery/models/item.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'modules/gallery') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 4b8cac8e..9406f5d9 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -287,6 +287,10 @@ class Item_Model extends ORM_MPTT { * @return string */ public function relative_path() { + if (!$this->loaded) { + return; + } + if (!isset($this->relative_path_cache)) { $paths = array(); foreach (Database::instance() -- cgit v1.2.3 From 463b3454ae7633815e24cdf86e81c57409dd15a9 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Sun, 31 May 2009 23:28:27 -0700 Subject: Move the sql packaging code from installer into the gallery module. It must be run from the command line and will throw a 404 if it is run as a web request. --- index.php | 15 +- installer/package.php | 239 -------------------------------- modules/gallery/controllers/package.php | 163 ++++++++++++++++++++++ 3 files changed, 173 insertions(+), 244 deletions(-) delete mode 100755 installer/package.php create mode 100644 modules/gallery/controllers/package.php (limited to 'modules/gallery') diff --git a/index.php b/index.php index a70053a8..fc6309b7 100644 --- a/index.php +++ b/index.php @@ -48,11 +48,16 @@ define('SYSPATH', strtr(realpath('system') . '/', DIRECTORY_SEPARATOR, '/')); // Force a test run if we're in command line mode. if (PHP_SAPI == 'cli') { - array_splice($_SERVER['argv'], 1, 0, 'gallery_unit_test'); - define('TEST_MODE', 1); - @mkdir('test/var/logs', 0777, true); - define('VARPATH', strtr(realpath('test/var') . '/', DIRECTORY_SEPARATOR, '/')); - @copy("var/database.php", VARPATH . "database.php"); + if ($_SERVER['argv'][1] != "package") { + array_splice($_SERVER['argv'], 1, 0, 'gallery_unit_test'); + define('TEST_MODE', 1); + @mkdir('test/var/logs', 0777, true); + define('VARPATH', strtr(realpath('test/var') . '/', DIRECTORY_SEPARATOR, '/')); + @copy("var/database.php", VARPATH . "database.php"); + } else { + define('TEST_MODE', 0); + define('VARPATH', strtr(realpath('var') . '/', DIRECTORY_SEPARATOR, '/')); + } } else { define('TEST_MODE', 0); define('VARPATH', strtr(realpath('var') . '/', DIRECTORY_SEPARATOR, '/')); diff --git a/installer/package.php b/installer/package.php deleted file mode 100755 index 591f12d0..00000000 --- a/installer/package.php +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/php -f - tmp/dump.sql"); - - $db = Database::instance(); - // Drop all tables - foreach ($db->list_tables() as $table) { - $db->query("DROP TABLE IF EXISTS `$table`"); - } - - // Now the var directory - rename (VARPATH, realpath("tmp/var")); - mkdir(VARPATH); - copy(realpath("tmp/var/database.php"), VARPATH . "database.php"); - - $db->clear_cache(); - $modules_list = module::$modules; - $active_modules = module::$active; - - module::$modules = array(); - module::$active = array(); - - // Use a known random seed so that subsequent packaging runs will reuse the same random - // numbers, keeping our install.sql file more stable. - srand(0); -} - -function reset_install($config) { - // Reset the var path - system("rm -rf " . VARPATH); - rename (realpath("tmp/var"), VARPATH); - - $db = Database::instance(); - // Drop all tables - foreach ($db->list_tables() as $table) { - $db->query("DROP TABLE IF EXISTS `$table`"); - } - - // Lets restorep the database - $conn = $config["connection"]; - do_system("mysql -u{$conn['user']} -p{$conn['pass']} {$conn['database']} " . - " < tmp/dump.sql"); - - // Clear any database caching - $db->clear_cache(); - - module::$modules = $modules_list; - module::$active = $active_modules; -} - -function do_system($command) { - exec($command, $output, $status); - if ($status) { - throw new Exception("$command\nFailed to dump database\n" . implode("\n", $output)); - } -} - -function kohana_bootstrap() { - define('KOHANA_VERSION', '2.3.3'); - define('KOHANA_CODENAME', 'aegolius'); - - // Test of Kohana is running in Windows - define('KOHANA_IS_WIN', DIRECTORY_SEPARATOR === '\\'); - - // Kohana benchmarks are prefixed to prevent collisions - define('SYSTEM_BENCHMARK', 'system_benchmark'); - - // Load benchmarking support - require SYSPATH.'core/Benchmark'.EXT; - - // Start total_execution - Benchmark::start(SYSTEM_BENCHMARK.'_total_execution'); - - // Start kohana_loading - Benchmark::start(SYSTEM_BENCHMARK.'_kohana_loading'); - - // Load core files - require SYSPATH.'core/utf8'.EXT; - require SYSPATH.'core/Event'.EXT; - require SYSPATH.'core/Kohana'.EXT; - - // Prepare the environment - Kohana::setup(); - // End kohana_loading - Benchmark::stop(SYSTEM_BENCHMARK.'_kohana_loading'); - - // Prepare the system - Event::run('system.ready'); - - // Clean up and exit (this basically shuts down output buffering - Event::run('system.shutdown'); -} - -function install() { - gallery_installer::install(true); - module::load_modules(); - - foreach (array("user", "comment", "organize", "info", "rss", - "search", "slideshow", "tag") as $module_name) { - module::install($module_name); - module::activate($module_name); - } -} - -function dump_database() { - // We now have a clean install with just the packages that we want. Make sure that the - // database is clean too. - $db = Database::instance(); - $db->query("TRUNCATE {sessions}"); - $db->query("TRUNCATE {logs}"); - $db->query("DELETE FROM {vars} WHERE `module_name` = 'gallery' AND `name` = '_cache'"); - $db->update("users", array("password" => ""), array("id" => 1)); - $db->update("users", array("password" => ""), array("id" => 2)); - - $dbconfig = Kohana::config('database.default'); - $conn = $dbconfig["connection"]; - $pass = $conn["pass"] ? "-p{$conn['pass']}" : ""; - $sql_file = DOCROOT . "installer/install.sql"; - if (!is_writable($sql_file)) { - throw new Exception("$sql_file is not writeable"); - return; - } - do_system("mysqldump --compact --add-drop-table -h{$conn['host']} " . - "-u{$conn['user']} $pass {$conn['database']} > $sql_file"); - - // Post-process the sql file - $buf = ""; - $root = ORM::factory("item", 1); - $root_created_timestamp = $root->created; - $root_updated_timestamp = $root->updated; - foreach (file($sql_file) as $line) { - // Prefix tables - $line = preg_replace( - "/(CREATE TABLE|IF EXISTS|INSERT INTO) `{$dbconfig['table_prefix']}(\w+)`/", "\\1 {\\2}", - $line); - - // Normalize dates - $line = preg_replace("/,$root_created_timestamp,/", ",UNIX_TIMESTAMP(),", $line); - $line = preg_replace("/,$root_updated_timestamp,/", ",UNIX_TIMESTAMP(),", $line); - $buf .= $line; - } - $fd = fopen($sql_file, "wb"); - fwrite($fd, $buf); - fclose($fd); -} - -function dump_var() { - $objects = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator(VARPATH), - RecursiveIteratorIterator::SELF_FIRST); - - $var_file = DOCROOT . "installer/init_var.php"; - if (!is_writable($var_file)) { - throw new Exception("$var_file is not writeable"); - return; - } - - $paths = array(); - foreach($objects as $name => $file) { - if ($file->getBasename() == "database.php") { - continue; - } else if (basename($file->getPath()) == "logs") { - continue; - } - - if ($file->isDir()) { - $paths[] = "VARPATH . \"" . substr($name, strlen(VARPATH)) . "\""; - } else { - // @todo: serialize non-directories - throw new Exception("Unknown file: $name"); - } - } - // Sort the paths so that the var file is stable - sort($paths); - - $fd = fopen($var_file, "w"); - fwrite($fd, "\n"); - fwrite($fd, "getTrace(); - return; -} - -try { - // Install the standard modules - install(); - - // Dump the empty gallery3 database and format it for the installer - dump_database(); - - // Dump the var directory - dump_var(); -} catch (Exception $e) { - print $e->getTrace(); -} - -try { - // Reset the Gallery3 installation - reset_install($config); -} catch (Exception $e) { - print $e->getTrace(); -} - -system("rm -rf tmp"); -?> \ No newline at end of file diff --git a/modules/gallery/controllers/package.php b/modules/gallery/controllers/package.php new file mode 100644 index 00000000..7b702498 --- /dev/null +++ b/modules/gallery/controllers/package.php @@ -0,0 +1,163 @@ +auto_render = false; + + $this->_reset(); // empty and reinstall the standard modules + + $this->_dump_database(); // Dump the database + + $this->_dump_var(); // Dump the var directory + print t("Successfully wrote install.sql and init_var.php\n"); + } + + private function _reset() { + $db = Database::instance(); + + // Drop all tables + foreach ($db->list_tables() as $table) { + $db->query("DROP TABLE IF EXISTS `$table`"); + } + + // Clean out data + dir::unlink(VARPATH . "uploads"); + dir::unlink(VARPATH . "albums"); + dir::unlink(VARPATH . "resizes"); + dir::unlink(VARPATH . "thumbs"); + dir::unlink(VARPATH . "modules"); + dir::unlink(VARPATH . "tmp"); + + $db->clear_cache(); + module::$modules = array(); + module::$active = array(); + + // Use a known random seed so that subsequent packaging runs will reuse the same random + // numbers, keeping our install.sql file more stable. + srand(0); + + try { + gallery_installer::install(true); + module::load_modules(); + + foreach (array("user", "comment", "organize", "info", "rss", + "search", "slideshow", "tag") as $module_name) { + module::install($module_name); + module::activate($module_name); + } + } catch (Exception $e) { + Kohana::log("error", $e->getTraceAsString()); + print $e->getTrace(); + throw $e; + } + } + + private function _dump_database() { + // We now have a clean install with just the packages that we want. Make sure that the + // database is clean too. + $db = Database::instance(); + $db->query("TRUNCATE {sessions}"); + $db->query("TRUNCATE {logs}"); + $db->query("DELETE FROM {vars} WHERE `module_name` = 'core' AND `name` = '_cache'"); + $db->update("users", array("password" => ""), array("id" => 1)); + $db->update("users", array("password" => ""), array("id" => 2)); + + $dbconfig = Kohana::config('database.default'); + $conn = $dbconfig["connection"]; + $pass = $conn["pass"] ? "-p{$conn['pass']}" : ""; + $sql_file = DOCROOT . "installer/install.sql"; + if (!is_writable($sql_file)) { + print "$sql_file is not writeable"; + return; + } + $command = "mysqldump --compact --add-drop-table -h{$conn['host']} " . + "-u{$conn['user']} $pass {$conn['database']} > $sql_file"; + exec($command, $output, $status); + if ($status) { + print "
";
+      print "$command\n";
+      print "Failed to dump database\n";
+      print implode("\n", $output);
+      return;
+    }
+
+    // Post-process the sql file
+    $buf = "";
+    $root_timestamp = ORM::factory("item", 1)->created;
+    foreach (file($sql_file) as $line) {
+      // Prefix tables
+      $line = preg_replace(
+        "/(CREATE TABLE|IF EXISTS|INSERT INTO) `{$dbconfig['table_prefix']}(\w+)`/", "\\1 {\\2}",
+        $line);
+
+      // Normalize dates
+      $line = preg_replace("/,$root_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
+      $buf .= $line;
+    }
+    $fd = fopen($sql_file, "wb");
+    fwrite($fd, $buf);
+    fclose($fd);
+  }
+
+  private function _dump_var() {
+    $this->auto_render = false;
+
+    $objects = new RecursiveIteratorIterator(
+      new RecursiveDirectoryIterator(VARPATH),
+      RecursiveIteratorIterator::SELF_FIRST);
+
+    $var_file = DOCROOT . "installer/init_var.php";
+    if (!is_writable($var_file)) {
+      print "$var_file is not writeable";
+      return;
+    }
+
+    $paths = array();
+    foreach($objects as $name => $file){
+      if ($file->getBasename() == "database.php") {
+        continue;
+      } else if (basename($file->getPath()) == "logs") {
+        continue;
+      }
+
+      if ($file->isDir()) {
+        $paths[] = "VARPATH . \"" . substr($name, strlen(VARPATH)) . "\"";
+      } else {
+        // @todo: serialize non-directories
+        print "Unknown file: $name";
+        return;
+      }
+    }
+    // Sort the paths so that the var file is stable
+    sort($paths);
+
+    $fd = fopen($var_file, "w");
+    fwrite($fd, "\n");
+    fwrite($fd, "
Date: Mon, 1 Jun 2009 00:11:09 -0700
Subject: Do a little cleanup and get rid of code left-over from when this
 controller rendered HTML.  Also, catch all exceptions at the root level and
 restore the change in 84ce0cdefda162917c7b01722a7259ac52c4e30d which appears
 to have gotten lost in the shuffle.

---
 modules/gallery/controllers/package.php | 43 +++++++++++++++------------------
 1 file changed, 20 insertions(+), 23 deletions(-)

(limited to 'modules/gallery')

diff --git a/modules/gallery/controllers/package.php b/modules/gallery/controllers/package.php
index 7b702498..1b096cb5 100644
--- a/modules/gallery/controllers/package.php
+++ b/modules/gallery/controllers/package.php
@@ -23,14 +23,16 @@ class Package_Controller extends Controller {
       Kohana::show_404();
     }
 
-    $this->auto_render = false;
-
-    $this->_reset();                // empty and reinstall the standard modules
-
-    $this->_dump_database();        // Dump the database
+    try {
+      $this->_reset();                // empty and reinstall the standard modules
+      $this->_dump_database();        // Dump the database
+      $this->_dump_var();             // Dump the var directory
+    } catch (Exception $e) {
+      print $e->getTraceAsString();
+      return;
+    }
 
-    $this->_dump_var();             // Dump the var directory
-    print t("Successfully wrote install.sql and init_var.php\n");
+    print "Successfully wrote install.sql and init_var.php\n";
   }
 
   private function _reset() {
@@ -57,19 +59,13 @@ class Package_Controller extends Controller {
     // numbers, keeping our install.sql file more stable.
     srand(0);
 
-    try {
-      gallery_installer::install(true);
-      module::load_modules();
+    gallery_installer::install(true);
+    module::load_modules();
 
-      foreach (array("user", "comment", "organize", "info", "rss",
-                     "search", "slideshow", "tag") as $module_name) {
-        module::install($module_name);
-        module::activate($module_name);
-      }
-    } catch (Exception $e) {
-      Kohana::log("error", $e->getTraceAsString());
-      print $e->getTrace();
-      throw $e;
+    foreach (array("user", "comment", "organize", "info", "rss",
+                   "search", "slideshow", "tag") as $module_name) {
+      module::install($module_name);
+      module::activate($module_name);
     }
   }
 
@@ -104,7 +100,9 @@ class Package_Controller extends Controller {
 
     // Post-process the sql file
     $buf = "";
-    $root_timestamp = ORM::factory("item", 1)->created;
+    $root = ORM::factory("item", 1);
+    $root_created_timestamp = $root->created;
+    $root_updated_timestamp = $root->updated;
     foreach (file($sql_file) as $line) {
       // Prefix tables
       $line = preg_replace(
@@ -112,7 +110,8 @@ class Package_Controller extends Controller {
         $line);
 
       // Normalize dates
-      $line = preg_replace("/,$root_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
+      $line = preg_replace("/,$root_created_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
+      $line = preg_replace("/,$root_updated_timestamp,/", ",UNIX_TIMESTAMP(),", $line);
       $buf .= $line;
     }
     $fd = fopen($sql_file, "wb");
@@ -121,8 +120,6 @@ class Package_Controller extends Controller {
   }
 
   private function _dump_var() {
-    $this->auto_render = false;
-
     $objects = new RecursiveIteratorIterator(
       new RecursiveDirectoryIterator(VARPATH),
       RecursiveIteratorIterator::SELF_FIRST);
-- 
cgit v1.2.3


From c94c11eb3e4f48d2dbcc73ea6ca9358170733392 Mon Sep 17 00:00:00 2001
From: Bharat Mediratta 
Date: Mon, 1 Jun 2009 00:22:30 -0700
Subject: Normalize the random values used in the blocks_dashboard_xxx vars so
 that install.sql is more stable.

---
 installer/install.sql                   | 4 ++--
 modules/gallery/controllers/package.php | 9 +++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)

(limited to 'modules/gallery')

diff --git a/installer/install.sql b/installer/install.sql
index 7109236f..0aaf8e79 100755
--- a/installer/install.sql
+++ b/installer/install.sql
@@ -333,6 +333,6 @@ CREATE TABLE {vars} (
   `value` text,
   PRIMARY KEY  (`id`),
   UNIQUE KEY `module_name` (`module_name`,`name`)
-) ENGINE=InnoDB AUTO_INCREMENT=22 DEFAULT CHARSET=utf8;
+) ENGINE=InnoDB AUTO_INCREMENT=24 DEFAULT CHARSET=utf8;
 SET character_set_client = @saved_cs_client;
-INSERT INTO {vars} VALUES (1,'gallery','active_site_theme','default'),(2,'gallery','active_admin_theme','admin_default'),(3,'gallery','page_size','9'),(4,'gallery','thumb_size','200'),(5,'gallery','resize_size','640'),(6,'gallery','default_locale','en_US'),(7,'gallery','image_quality','75'),(9,'gallery','blocks_dashboard_sidebar','a:4:{i:1804289383;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"block_adder\";}i:846930886;a:2:{i:0;s:7:\"gallery\";i:1;s:5:\"stats\";}i:1681692777;a:2:{i:0;s:7:\"gallery\";i:1;s:13:\"platform_info\";}i:1714636915;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"project_news\";}}'),(14,'gallery','blocks_dashboard_center','a:4:{i:1957747793;a:2:{i:0;s:7:\"gallery\";i:1;s:7:\"welcome\";}i:424238335;a:2:{i:0;s:7:\"gallery\";i:1;s:12:\"photo_stream\";}i:719885386;a:2:{i:0;s:7:\"gallery\";i:1;s:11:\"log_entries\";}i:1649760492;a:2:{i:0;s:7:\"comment\";i:1;s:15:\"recent_comments\";}}'),(17,'gallery','version','3.0 pre-beta git'),(18,'gallery','choose_default_tookit','1'),(19,'gallery','credits','Powered by Gallery %version'),(21,'comment','spam_caught','0');
+INSERT INTO {vars} VALUES (1,'gallery','active_site_theme','default'),(2,'gallery','active_admin_theme','admin_default'),(3,'gallery','page_size','9'),(4,'gallery','thumb_size','200'),(5,'gallery','resize_size','640'),(6,'gallery','default_locale','en_US'),(7,'gallery','image_quality','75'),(9,'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\";}}'),(14,'gallery','blocks_dashboard_center','a:4:{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\";}i:9;a:2:{i:0;s:7:\"comment\";i:1;s:15:\"recent_comments\";}}'),(17,'gallery','version','3.0 pre-beta git'),(18,'gallery','choose_default_tookit','1'),(19,'gallery','credits','Powered by Gallery %version'),(21,'comment','spam_caught','0');
diff --git a/modules/gallery/controllers/package.php b/modules/gallery/controllers/package.php
index 1b096cb5..f5146fc8 100644
--- a/modules/gallery/controllers/package.php
+++ b/modules/gallery/controllers/package.php
@@ -72,6 +72,15 @@ class Package_Controller extends Controller {
   private function _dump_database() {
     // We now have a clean install with just the packages that we want.  Make sure that the
     // database is clean too.
+    $i = 1;
+    foreach (array("blocks_dashboard_sidebar", "blocks_dashboard_center") as $key) {
+      $blocks = array();
+      foreach (unserialize(module::get_var("gallery", $key)) as $rnd => $value) {
+        $blocks[++$i] = $value;
+      }
+      module::set_var("gallery", $key, serialize($blocks));
+    }
+
     $db = Database::instance();
     $db->query("TRUNCATE {sessions}");
     $db->query("TRUNCATE {logs}");
-- 
cgit v1.2.3


From 1145b846ba3ad354579a95bf1c70498472553b54 Mon Sep 17 00:00:00 2001
From: Bharat Mediratta 
Date: Mon, 1 Jun 2009 21:07:24 -0700
Subject: Fix a place where I shouldn't have renamed "core" to "gallery",
 breaking maintenance mode.

---
 modules/gallery/helpers/gallery.php | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'modules/gallery')

diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php
index 34671f1f..1686571c 100644
--- a/modules/gallery/helpers/gallery.php
+++ b/modules/gallery/helpers/gallery.php
@@ -23,7 +23,7 @@ class gallery_Core {
    * down for maintenance" page.
    */
   static function maintenance_mode() {
-    $maintenance_mode = Kohana::config("gallery.maintenance_mode", false, false);
+    $maintenance_mode = Kohana::config("core.maintenance_mode", false, false);
 
     if (Router::$controller != "login" && !empty($maintenance_mode) && !user::active()->admin) {
       Router::$controller = "maintenance";
-- 
cgit v1.2.3


From 43abcd93867996e32890fa101ae09255ccc24847 Mon Sep 17 00:00:00 2001
From: Bharat Mediratta 
Date: Mon, 1 Jun 2009 22:40:22 -0700
Subject: Security pass over all controller code.  Mostly adding CSRF checking
 and verifying user permissions, but there are several above-the-bar changes:

1) Server add is now only available to admins.  This is a hard
   requirement because we have to limit server access (eg:
   server_add::children) to a user subset and the current permission
   model doesn't include that.  Easiest fix is to restrict to admins.
   Got rid of the server_add permission.

2) We now know check permissions at every level, which means in
   controllers AND in helpers.  This "belt and suspenders" approach will
   give us defense in depth in case we overlook it in one area.

3) We now do CSRF checking in every controller method that changes the
   code, in addition to the Forge auto-check.  Again, defense in depth
   and it makes scanning the code for security much simpler.

4) Moved Simple_Uploader_Controller::convert_filename_to_title to
   item:convert_filename_to_title

5) Fixed a bug in sending notification emails.

6) Fixed the Organize code to verify that you only have access to your
   own tasks.  In general, added permission checks to organize which had
   pretty much no validation code.

I did my best to verify every feature that I touched.
---
 modules/akismet/controllers/admin_akismet.php      |  3 +
 modules/comment/controllers/admin_comments.php     |  2 +
 modules/comment/controllers/comments.php           |  5 ++
 modules/g2_import/controllers/admin_g2_import.php  |  2 +
 modules/gallery/controllers/admin.php              |  3 +-
 modules/gallery/controllers/admin_dashboard.php    |  4 +
 modules/gallery/controllers/admin_graphics.php     |  1 +
 modules/gallery/controllers/admin_languages.php    |  4 +
 .../gallery/controllers/admin_theme_details.php    |  2 +
 modules/gallery/controllers/albums.php             | 14 +++-
 modules/gallery/controllers/l10n_client.php        | 11 ++-
 modules/gallery/controllers/move.php               |  9 +++
 modules/gallery/controllers/movies.php             |  3 +
 modules/gallery/controllers/permissions.php        |  4 +
 modules/gallery/controllers/photos.php             |  5 ++
 modules/gallery/controllers/quick.php              | 26 ++++---
 modules/gallery/controllers/rest.php               | 10 +--
 modules/gallery/controllers/simple_uploader.php    | 18 ++---
 modules/gallery/helpers/item.php                   | 17 +++++
 modules/gallery/libraries/MY_Forge.php             |  1 +
 modules/gallery/views/simple_uploader.html.php     |  2 +-
 modules/notification/helpers/notification.php      |  2 +-
 modules/organize/controllers/organize.php          | 85 ++++++++++++++++++----
 modules/organize/helpers/organize.php              |  8 ++
 modules/organize/helpers/organize_task.php         | 29 +++++++-
 modules/recaptcha/controllers/admin_recaptcha.php  |  8 +-
 modules/server_add/controllers/server_add.php      | 38 ++++++++--
 .../server_add/helpers/server_add_installer.php    |  5 --
 modules/server_add/helpers/server_add_menu.php     |  4 +-
 modules/server_add/helpers/server_add_task.php     |  1 -
 modules/tag/controllers/admin_tags.php             |  1 +
 modules/tag/controllers/tags.php                   |  2 +
 modules/user/controllers/admin_users.php           |  6 ++
 modules/user/controllers/login.php                 |  4 +
 modules/user/controllers/logout.php                |  2 +
 modules/user/controllers/password.php              |  4 +
 modules/user/views/login.html.php                  |  2 +-
 modules/watermark/controllers/admin_watermarks.php |  6 ++
 38 files changed, 281 insertions(+), 72 deletions(-)

(limited to 'modules/gallery')

diff --git a/modules/akismet/controllers/admin_akismet.php b/modules/akismet/controllers/admin_akismet.php
index 7485f283..9ba89bd4 100644
--- a/modules/akismet/controllers/admin_akismet.php
+++ b/modules/akismet/controllers/admin_akismet.php
@@ -22,6 +22,9 @@ class Admin_Akismet_Controller extends Admin_Controller {
     $form = akismet::get_configure_form();
 
     if (request::method() == "post") {
+      // @todo move the "post" handler part of this code into a separate function
+      access::verify_csrf();
+
       $valid = $form->validate();
 
       if ($valid) {
diff --git a/modules/comment/controllers/admin_comments.php b/modules/comment/controllers/admin_comments.php
index 50e35d23..3e8d3c46 100644
--- a/modules/comment/controllers/admin_comments.php
+++ b/modules/comment/controllers/admin_comments.php
@@ -107,6 +107,7 @@ class Admin_Comments_Controller extends Admin_Controller {
 
   public function set_state($id, $state) {
     access::verify_csrf();
+
     $comment = ORM::factory("comment", $id);
     $orig = clone $comment;
     if ($comment->loaded) {
@@ -121,6 +122,7 @@ class Admin_Comments_Controller extends Admin_Controller {
 
   public function delete_all_spam() {
     access::verify_csrf();
+
     ORM::factory("comment")
       ->where("state", "spam")
       ->delete_all();
diff --git a/modules/comment/controllers/comments.php b/modules/comment/controllers/comments.php
index 930579ac..c48bd380 100644
--- a/modules/comment/controllers/comments.php
+++ b/modules/comment/controllers/comments.php
@@ -134,6 +134,7 @@ class Comments_Controller extends REST_Controller {
    */
   public function _update($comment) {
     $item = ORM::factory("item", $comment->item_id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     $form = comment::get_edit_form($comment);
@@ -161,6 +162,7 @@ class Comments_Controller extends REST_Controller {
    */
   public function _delete($comment) {
     $item = ORM::factory("item", $comment->item_id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     $comment->delete();
@@ -183,6 +185,9 @@ class Comments_Controller extends REST_Controller {
    *  @see REST_Controller::form_edit($resource)
    */
   public function _form_edit($comment) {
+    if (!user::active()->admin) {
+      access::forbidden();
+    }
     print comment::get_edit_form($comment);
   }
 }
diff --git a/modules/g2_import/controllers/admin_g2_import.php b/modules/g2_import/controllers/admin_g2_import.php
index 25894291..f2969f49 100644
--- a/modules/g2_import/controllers/admin_g2_import.php
+++ b/modules/g2_import/controllers/admin_g2_import.php
@@ -39,6 +39,8 @@ class Admin_g2_import_Controller extends Admin_Controller {
   }
 
   public function save() {
+    access::verify_csrf();
+
     $form = $this->_get_import_form();
     if ($form->validate()) {
       $embed_path = $form->configure_g2_import->embed_path->value;
diff --git a/modules/gallery/controllers/admin.php b/modules/gallery/controllers/admin.php
index af0f387a..b92a32cd 100644
--- a/modules/gallery/controllers/admin.php
+++ b/modules/gallery/controllers/admin.php
@@ -22,8 +22,9 @@ class Admin_Controller extends Controller {
 
   public function __construct($theme=null) {
     if (!(user::active()->admin)) {
-      throw new Exception("@todo UNAUTHORIZED", 401);
+      access::forbidden();
     }
+
     parent::__construct();
   }
 
diff --git a/modules/gallery/controllers/admin_dashboard.php b/modules/gallery/controllers/admin_dashboard.php
index a1090a6d..3cb97b14 100644
--- a/modules/gallery/controllers/admin_dashboard.php
+++ b/modules/gallery/controllers/admin_dashboard.php
@@ -29,6 +29,8 @@ class Admin_Dashboard_Controller extends Admin_Controller {
   }
 
   public function add_block() {
+    access::verify_csrf();
+
     $form = gallery_block::get_add_block_form();
     if ($form->validate()) {
       list ($module_name, $id) = explode(":", $form->add_block->id->value);
@@ -51,6 +53,7 @@ class Admin_Dashboard_Controller extends Admin_Controller {
 
   public function remove_block($id) {
     access::verify_csrf();
+
     $blocks_center = block_manager::get_active("dashboard_center");
     $blocks_sidebar = block_manager::get_active("dashboard_sidebar");
 
@@ -73,6 +76,7 @@ class Admin_Dashboard_Controller extends Admin_Controller {
 
   public function reorder() {
     access::verify_csrf();
+
     $active_set = array();
     foreach (array("dashboard_sidebar", "dashboard_center") as $location) {
       foreach (block_manager::get_active($location) as $id => $info) {
diff --git a/modules/gallery/controllers/admin_graphics.php b/modules/gallery/controllers/admin_graphics.php
index 7e8ef47c..72f8d8e1 100644
--- a/modules/gallery/controllers/admin_graphics.php
+++ b/modules/gallery/controllers/admin_graphics.php
@@ -43,6 +43,7 @@ class Admin_Graphics_Controller extends Admin_Controller {
 
   public function choose($toolkit) {
     access::verify_csrf();
+
     if ($toolkit != module::get_var("gallery", "graphics_toolkit")) {
       module::set_var("gallery", "graphics_toolkit", $toolkit);
 
diff --git a/modules/gallery/controllers/admin_languages.php b/modules/gallery/controllers/admin_languages.php
index 1dea733c..4639de89 100644
--- a/modules/gallery/controllers/admin_languages.php
+++ b/modules/gallery/controllers/admin_languages.php
@@ -31,6 +31,8 @@ class Admin_Languages_Controller extends Admin_Controller {
   }
 
   public function save() {
+    access::verify_csrf();
+
     $form = $this->_languages_form();
     if ($form->validate()) {
       module::set_var("gallery", "default_locale", $form->choose_language->locale->value);
@@ -41,6 +43,8 @@ class Admin_Languages_Controller extends Admin_Controller {
   }
 
   public function share() {
+    access::verify_csrf();
+
     $form = $this->_share_translations_form();
     if (!$form->validate()) {
       // Show the page with form errors
diff --git a/modules/gallery/controllers/admin_theme_details.php b/modules/gallery/controllers/admin_theme_details.php
index fec1311b..97696df5 100644
--- a/modules/gallery/controllers/admin_theme_details.php
+++ b/modules/gallery/controllers/admin_theme_details.php
@@ -26,6 +26,8 @@ class Admin_Theme_Details_Controller extends Admin_Controller {
   }
 
   public function save() {
+    access::verify_csrf();
+
     $form = theme::get_edit_form_admin();
     if ($form->validate()) {
       module::set_var("gallery", "page_size", $form->edit_theme->page_size->value);
diff --git a/modules/gallery/controllers/albums.php b/modules/gallery/controllers/albums.php
index 5ccadb37..efde4f09 100644
--- a/modules/gallery/controllers/albums.php
+++ b/modules/gallery/controllers/albums.php
@@ -24,11 +24,11 @@ class Albums_Controller extends Items_Controller {
    */
   public function _show($album) {
     if (!access::can("view", $album)) {
-      if ($album->id != 1) {
-        access::forbidden();
-      } else {
+      if ($album->id == 1) {
         print new Theme_View("login_page.html", "album");
         return;
+      } else {
+        access::forbidden();
       }
     }
 
@@ -77,6 +77,8 @@ class Albums_Controller extends Items_Controller {
    * @see REST_Controller::_create($resource)
    */
   public function _create($album) {
+    access::verify_csrf();
+    access::required("view", $album);
     access::required("add", $album);
 
     switch ($this->input->post("type")) {
@@ -92,6 +94,7 @@ class Albums_Controller extends Items_Controller {
   }
 
   private function _create_album($album) {
+    access::required("view", $album);
     access::required("add", $album);
 
     $form = album::get_add_form($album);
@@ -120,6 +123,7 @@ class Albums_Controller extends Items_Controller {
   }
 
   private function _create_photo($album) {
+    access::required("view", $album);
     access::required("add", $album);
 
     // If we set the content type as JSON, it triggers saving the result as
@@ -153,6 +157,8 @@ class Albums_Controller extends Items_Controller {
    * @see REST_Controller::_update($resource)
    */
   public function _update($album) {
+    access::verify_csrf();
+    access::required("view", $album);
     access::required("edit", $album);
 
     $form = album::get_edit_form($album);
@@ -202,6 +208,7 @@ class Albums_Controller extends Items_Controller {
    */
   public function _form_add($album_id) {
     $album = ORM::factory("item", $album_id);
+    access::required("view", $album);
     access::required("add", $album);
 
     switch ($this->input->get("type")) {
@@ -223,6 +230,7 @@ class Albums_Controller extends Items_Controller {
    *  @see REST_Controller::_form_add($parameters)
    */
   public function _form_edit($album) {
+    access::required("view", $album);
     access::required("edit", $album);
 
     print album::get_edit_form($album);
diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php
index 17520051..c3a76659 100644
--- a/modules/gallery/controllers/l10n_client.php
+++ b/modules/gallery/controllers/l10n_client.php
@@ -20,7 +20,9 @@
 class L10n_Client_Controller extends Controller {
   public function save() {
     access::verify_csrf();
-    user::active()->admin or access::forbidden();
+    if (!user::active()->admin) {
+      access::forbidden();
+    }
 
     $input = Input::instance();
     $message = $input->post("l10n-message-source");
@@ -58,6 +60,9 @@ class L10n_Client_Controller extends Controller {
 
   public function toggle_l10n_mode() {
     access::verify_csrf();
+    if (!user::active()->admin) {
+      access::forbidden();
+    }
 
     $session = Session::instance();
     $session->set("l10n_mode",
@@ -89,6 +94,10 @@ class L10n_Client_Controller extends Controller {
   }
 
   public static function l10n_form() {
+    if (!user::active()->admin) {
+      access::forbidden();
+    }
+
     $calls = I18n::instance()->call_log();
 
     if ($calls) {
diff --git a/modules/gallery/controllers/move.php b/modules/gallery/controllers/move.php
index 130c247f..93ef05a6 100644
--- a/modules/gallery/controllers/move.php
+++ b/modules/gallery/controllers/move.php
@@ -20,6 +20,7 @@
 class Move_Controller extends Controller {
   public function browse($source_id) {
     $source = ORM::factory("item", $source_id);
+    access::required("view", $source);
     access::required("edit", $source);
 
     $view = new View("move_browse.html");
@@ -33,6 +34,11 @@ class Move_Controller extends Controller {
     $source = ORM::factory("item", $source_id);
     $target = ORM::factory("item", $this->input->post("target_id"));
 
+    access::required("view", $source);
+    access::required("edit", $source);
+    access::required("view", $target);
+    access::required("edit", $target);
+
     item::move($source, $target);
 
     print json_encode(
@@ -43,8 +49,11 @@ class Move_Controller extends Controller {
   public function show_sub_tree($source_id, $target_id) {
     $source = ORM::factory("item", $source_id);
     $target = ORM::factory("item", $target_id);
+    access::required("view", $source);
     access::required("edit", $source);
     access::required("view", $target);
+    // show targets even if they're not editable because they may contain children which *are*
+    // editable
 
     print $this->_get_tree_html($source, $target);
   }
diff --git a/modules/gallery/controllers/movies.php b/modules/gallery/controllers/movies.php
index 55bbb0e5..86b0f177 100644
--- a/modules/gallery/controllers/movies.php
+++ b/modules/gallery/controllers/movies.php
@@ -66,6 +66,8 @@ class Movies_Controller extends Items_Controller {
    * @see REST_Controller::_update($resource)
    */
   public function _update($photo) {
+    access::verify_csrf();
+    access::required("view", $photo);
     access::required("edit", $photo);
 
     $form = photo::get_edit_form($photo);
@@ -108,6 +110,7 @@ class Movies_Controller extends Items_Controller {
    *  @see REST_Controller::_form_edit($resource)
    */
   public function _form_edit($photo) {
+    access::required("view", $photo);
     access::required("edit", $photo);
     print photo::get_edit_form($photo);
   }
diff --git a/modules/gallery/controllers/permissions.php b/modules/gallery/controllers/permissions.php
index b0cee303..c776a0fd 100644
--- a/modules/gallery/controllers/permissions.php
+++ b/modules/gallery/controllers/permissions.php
@@ -20,6 +20,7 @@
 class Permissions_Controller extends Controller {
   function browse($id) {
     $item = ORM::factory("item", $id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     if (!$item->is_album()) {
@@ -37,6 +38,7 @@ class Permissions_Controller extends Controller {
 
   function form($id) {
     $item = ORM::factory("item", $id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     if (!$item->is_album()) {
@@ -48,9 +50,11 @@ class Permissions_Controller extends Controller {
 
   function change($command, $group_id, $perm_id, $item_id) {
     access::verify_csrf();
+
     $group = ORM::factory("group", $group_id);
     $perm = ORM::factory("permission", $perm_id);
     $item = ORM::factory("item", $item_id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     if ($group->loaded && $perm->loaded && $item->loaded) {
diff --git a/modules/gallery/controllers/photos.php b/modules/gallery/controllers/photos.php
index 5d4040cf..2de51bc7 100644
--- a/modules/gallery/controllers/photos.php
+++ b/modules/gallery/controllers/photos.php
@@ -62,10 +62,13 @@ class Photos_Controller extends Items_Controller {
     print $template;
   }
 
+
   /**
    * @see REST_Controller::_update($resource)
    */
   public function _update($photo) {
+    access::verify_csrf();
+    access::required("view", $photo);
     access::required("edit", $photo);
 
     $form = photo::get_edit_form($photo);
@@ -110,7 +113,9 @@ class Photos_Controller extends Items_Controller {
    *  @see REST_Controller::_form_edit($resource)
    */
   public function _form_edit($photo) {
+    access::required("view", $photo);
     access::required("edit", $photo);
+
     print photo::get_edit_form($photo);
   }
 }
diff --git a/modules/gallery/controllers/quick.php b/modules/gallery/controllers/quick.php
index 643dce30..6efcb9de 100644
--- a/modules/gallery/controllers/quick.php
+++ b/modules/gallery/controllers/quick.php
@@ -19,8 +19,8 @@
  */
 class Quick_Controller extends Controller {
   public function pane($id) {
-    $item = ORM::factory("item", $id);
-    if (!$item->loaded) {
+    $item = model_cache::get("item", $id);
+    if (!access::can("view", $item) || !access::can("edit", $item)) {
       return "";
     }
 
@@ -32,10 +32,9 @@ class Quick_Controller extends Controller {
 
   public function rotate($id, $dir) {
     access::verify_csrf();
-    $item = ORM::factory("item", $id);
-    if (!$item->loaded) {
-      return "";
-    }
+    $item = model_cache::get("item", $id);
+    access::required("view", $item);
+    access::required("edit", $item);
 
     $degrees = 0;
     switch($dir) {
@@ -82,14 +81,21 @@ class Quick_Controller extends Controller {
 
   public function make_album_cover($id) {
     access::verify_csrf();
-    item::make_album_cover(ORM::factory("item", $id));
+
+    $item = model_cache::get("item", $id);
+    access::required("view", $item);
+    access::required("view", $item->parent());
+    access::required("edit", $item->parent());
+
+    item::make_album_cover($item);
 
     print json_encode(array("result" => "success"));
   }
 
   public function delete($id) {
     access::verify_csrf();
-    $item = ORM::factory("item", $id);
+    $item = model_cache::get("item", $id);
+    access::required("view", $item);
     access::required("edit", $item);
 
     if ($item->is_album()) {
@@ -110,8 +116,10 @@ class Quick_Controller extends Controller {
   }
 
   public function form_edit($id) {
-    $item = ORM::factory("item", $id);
+    $item = model_cache::get("item", $id);
+    access::required("view", $item);
     access::required("edit", $item);
+
     if ($item->is_album()) {
       $form = album::get_edit_form($item);
     } else {
diff --git a/modules/gallery/controllers/rest.php b/modules/gallery/controllers/rest.php
index 11a6bbac..2edf079f 100644
--- a/modules/gallery/controllers/rest.php
+++ b/modules/gallery/controllers/rest.php
@@ -86,21 +86,20 @@ class REST_Controller extends Controller {
       return Kohana::show_404();
     }
 
-    if ($request_method != "get") {
-      access::verify_csrf();
-    }
-
     switch ($request_method) {
     case "get":
       return $this->_show($resource);
 
     case "put":
+      access::verify_csrf();
       return $this->_update($resource);
 
     case "delete":
+      access::verify_csrf();
       return $this->_delete($resource);
 
     case "post":
+      access::verify_csrf();
       return $this->_create($resource);
     }
   }
@@ -111,17 +110,18 @@ class REST_Controller extends Controller {
       throw new Exception("@todo ERROR_MISSING_RESOURCE_TYPE");
     }
 
-    // @todo this needs security checks
     $resource = ORM::factory($this->resource_type, $resource_id);
     if (!$resource->loaded) {
       return Kohana::show_404();
     }
 
+    // Security checks must be performed in _form_edit
     return $this->_form_edit($resource);
   }
 
   /* We're adding a new item, pass along any additional parameters. */
   public function form_add($parameters) {
+    // Security checks must be performed in _form_add
     return $this->_form_add($parameters);
   }
 
diff --git a/modules/gallery/controllers/simple_uploader.php b/modules/gallery/controllers/simple_uploader.php
index ec2a5ab9..dfbd4f17 100644
--- a/modules/gallery/controllers/simple_uploader.php
+++ b/modules/gallery/controllers/simple_uploader.php
@@ -20,6 +20,7 @@
 class Simple_Uploader_Controller extends Controller {
   public function app($id) {
     $item = ORM::factory("item", $id);
+    access::required("view", $item);
     access::required("add", $item);
 
     $v = new View("simple_uploader.html");
@@ -33,13 +34,13 @@ class Simple_Uploader_Controller extends Controller {
 
   public function add_photo($id) {
     $album = ORM::factory("item", $id);
+    access::required("view", $album);
     access::required("add", $album);
     access::verify_csrf();
 
     $file_validation = new Validation($_FILES);
     $file_validation->add_rules("Filedata", "upload::valid", "upload::type[gif,jpg,png,flv,mp4]");
     if ($file_validation->validate()) {
-
       // SimpleUploader.swf does not yet call /start directly, so simulate it here for now.
       if (!batch::in_progress()) {
         batch::start();
@@ -48,7 +49,7 @@ class Simple_Uploader_Controller extends Controller {
       $temp_filename = upload::save("Filedata");
       try {
         $name = substr(basename($temp_filename), 10);  // Skip unique identifier Kohana adds
-        $title = $this->convert_filename_to_title($name);
+        $title = item::convert_filename_to_title($name);
         $path_info = pathinfo($temp_filename);
         if (array_key_exists("extension", $path_info) &&
             in_array(strtolower($path_info["extension"]), array("flv", "mp4"))) {
@@ -69,18 +70,11 @@ class Simple_Uploader_Controller extends Controller {
     print "File Received";
   }
 
-  /**
-   * We should move this into a helper somewhere.. but where is appropriate?
-   */
-  private function convert_filename_to_title($filename) {
-    $title = strtr($filename, "_", " ");
-    $title = preg_replace("/\..*?$/", "", $title);
-    $title = preg_replace("/ +/", " ", $title);
-    return $title;
-  }
-
   public function finish() {
+    access::verify_csrf();
+
     batch::stop();
     print json_encode(array("result" => "success"));
   }
+
 }
diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php
index 7daaf1e1..09870b45 100644
--- a/modules/gallery/helpers/item.php
+++ b/modules/gallery/helpers/item.php
@@ -19,6 +19,8 @@
  */
 class item_Core {
   static function move($source, $target) {
+    access::required("view", $source);
+    access::required("view", $target);
     access::required("edit", $source);
     access::required("edit", $target);
 
@@ -47,6 +49,8 @@ class item_Core {
 
   static function make_album_cover($item) {
     $parent = $item->parent();
+    access::required("view", $item);
+    access::required("view", $parent);
     access::required("edit", $parent);
 
     model_cache::clear("item", $parent->album_cover_item_id);
@@ -61,6 +65,7 @@ class item_Core {
   }
 
   static function remove_album_cover($album) {
+    access::required("view", $album);
     access::required("edit", $album);
     @unlink($album->thumb_path());
 
@@ -102,4 +107,16 @@ class item_Core {
       $input->add_error("conflict", 1);
     }
   }
+
+  /**
+   * Sanitize a filename into something presentable as an item title
+   * @param string $filename
+   * @return string title
+   */
+  static function convert_filename_to_title($filename) {
+    $title = strtr($filename, "_", " ");
+    $title = preg_replace("/\..*?$/", "", $title);
+    $title = preg_replace("/ +/", " ", $title);
+    return $title;
+  }
 }
\ No newline at end of file
diff --git a/modules/gallery/libraries/MY_Forge.php b/modules/gallery/libraries/MY_Forge.php
index 17d0465b..b40d067d 100644
--- a/modules/gallery/libraries/MY_Forge.php
+++ b/modules/gallery/libraries/MY_Forge.php
@@ -26,6 +26,7 @@ class Forge extends Forge_Core {
     parent::__construct($action, $title, $method, $attr);
     $this->hidden("csrf")->value("");
   }
+
   /**
    * Use our own template
    */
diff --git a/modules/gallery/views/simple_uploader.html.php b/modules/gallery/views/simple_uploader.html.php
index abda6d26..7b90c5be 100644
--- a/modules/gallery/views/simple_uploader.html.php
+++ b/modules/gallery/views/simple_uploader.html.php
@@ -3,7 +3,7 @@
 
 
 
-
"> +">
p::clean($item->title))) ?>
diff --git a/modules/notification/helpers/notification.php b/modules/notification/helpers/notification.php index 32301fe0..8ee0c6ba 100644 --- a/modules/notification/helpers/notification.php +++ b/modules/notification/helpers/notification.php @@ -149,7 +149,7 @@ class notification { $result = ORM::factory("pending_notification") ->where("email", $email) ->find_all(); - if ($result->count == 1) { + if ($result->count() == 1) { $pending = $result->get(); Sendmail::factory() ->to($email) diff --git a/modules/organize/controllers/organize.php b/modules/organize/controllers/organize.php index 1c4792b2..43d41357 100644 --- a/modules/organize/controllers/organize.php +++ b/modules/organize/controllers/organize.php @@ -24,19 +24,22 @@ class Organize_Controller extends Controller { function index($item_id=1) { $item = ORM::factory("item", $item_id); $root = ($item->id == 1) ? $item : ORM::factory("item", 1); + access::required("view", $item); + access::required("edit", $item); $v = new View("organize.html"); $v->root = $root; $v->item = $item; $v->album_tree = $this->tree($item, $root); - $v->button_pane = new View("organize_button_pane.html"); - print $v; } function content($item_id) { $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + $width = $this->input->get("width"); $height = $this->input->get("height"); $offset = $this->input->get("offset", 0); @@ -55,12 +58,17 @@ class Organize_Controller extends Controller { function header($item_id) { $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); print json_encode(array("title" => $item->title, "description" => empty($item->description) ? "" : $item->description)); } function tree($item, $parent) { + access::required("view", $item); + access::required("edit", $item); + $albums = ORM::factory("item") ->where(array("parent_id" => $parent->id, "type" => "album")) ->orderby(array("title" => "ASC")) @@ -88,6 +96,8 @@ class Organize_Controller extends Controller { $items = $this->input->post("item"); $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); $definition = $this->_getOperationDefinition($item, $operation); @@ -101,22 +111,26 @@ class Organize_Controller extends Controller { // @todo If there is only one item then call task_run($task->id); Maybe even change js so // we can call finish as well. batch::start(); - print json_encode(array("result" => "started", - "runningMsg" => $definition["runningMsg"], - "pauseMsg" => "
{$definition['pauseMsg']}
", - "resumeMsg" => "
{$definition['resumeMsg']}
", - "task" => array("id" => $task->id, - "percent_complete" => $task->percent_complete, - "type" => $task->get("type"), - "status" => $task->status, - "state" => $task->state, - "done" => $task->done))); + print json_encode( + array("result" => "started", + "runningMsg" => $definition["runningMsg"], + "pauseMsg" => "
{$definition['pauseMsg']}
", + "resumeMsg" => "
{$definition['resumeMsg']}
", + "task" => array("id" => $task->id, + "percent_complete" => $task->percent_complete, + "type" => $task->get("type"), + "status" => $task->status, + "state" => $task->state, + "done" => $task->done))); } function runTask($task_id) { access::verify_csrf(); $task = task::run($task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } print json_encode(array("result" => $task->done ? $task->state : "in_progress", "task" => array("id" => $task->id, @@ -132,6 +146,9 @@ class Organize_Controller extends Controller { access::verify_csrf(); $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } if ($task->done) { $item = ORM::factory("item", (int)$task->get("target")); @@ -178,6 +195,9 @@ class Organize_Controller extends Controller { access::verify_csrf(); $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } if (!$task->done) { $task->done = 1; @@ -210,7 +230,7 @@ class Organize_Controller extends Controller { function editForm() { $event_parms = new stdClass(); $event_parms->panes = array(); - $event_parms->itemids = $this->input->get("item");; + $event_parms->itemids = $this->input->get("item"); // The following code should be done more dynamically i.e. use the event mechanism if (count($event_parms->itemids) == 1) { @@ -218,8 +238,12 @@ class Organize_Controller extends Controller { ->in("id", $event_parms->itemids[0]) ->find(); - $event_parms->panes[] = array("label" => $item->is_album() ? t("Edit Album") : t("Edit Photo"), - "content" => organize::get_general_edit_form($item)); + access::required("view", $item); + access::required("edit", $item); + + $event_parms->panes[] = array( + "label" => $item->is_album() ? t("Edit Album") : t("Edit Photo"), + "content" => organize::get_general_edit_form($item)); if ($item->is_album()) { $event_parms->panes[] = array("label" => t("Sort Order"), @@ -243,6 +267,7 @@ class Organize_Controller extends Controller { $item = ORM::factory("item") ->in("id", $itemids[0]) ->find(); + access::required("view", $item); access::required("edit", $item); $form = organize::get_general_edit_form($item); @@ -273,6 +298,7 @@ class Organize_Controller extends Controller { $item = ORM::factory("item") ->in("id", $itemids[0]) ->find(); + access::required("view", $item); access::required("edit", $item); print organize::get_general_edit_form($item); @@ -285,6 +311,7 @@ class Organize_Controller extends Controller { $item = ORM::factory("item") ->in("id", $itemids[0]) ->find(); + access::required("view", $item); access::required("edit", $item); $form = organize::get_sort_edit_form($item); @@ -309,6 +336,7 @@ class Organize_Controller extends Controller { $item = ORM::factory("item") ->in("id", $itemids[0]) ->find(); + access::required("view", $item); access::required("edit", $item); print organize::get_sort_edit_form($item); @@ -373,6 +401,13 @@ class Organize_Controller extends Controller { } private function _add_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + $tag = ORM::factory("tag") ->where("name", $new_tag) ->find(); @@ -391,6 +426,13 @@ class Organize_Controller extends Controller { } private function _delete_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + $tag = ORM::factory("tag") ->where("name", $new_tag) ->find(); @@ -407,6 +449,13 @@ class Organize_Controller extends Controller { } private function _update_tag($new_tag, $itemids) { + // Super lame security stopgap. This code is going to get rewritten anyway. + foreach ($itemids as $item_id) { + $item = ORM::factory("item", $item_id); + access::required("view", $item); + access::required("edit", $item); + } + $tag = ORM::factory("tag") ->where("name", $new_tag) ->find(); @@ -441,6 +490,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("The move operation was paused"), "resumeMsg" => t("The move operation was resumed")); break; + case "rearrange": return array("description" => t("Rearrange the order of albums and photos"), "name" => t("Rearrange: %name", array("name" => $item->title)), @@ -449,6 +499,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("The rearrange operation was paused"), "resumeMsg" => t("The rearrange operation was resumed")); break; + case "rotateCcw": return array("description" => t("Rotate the selected photos counter clockwise"), "name" => t("Rotate images in %name", array("name" => $item->title)), @@ -457,6 +508,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("The rotate operation was paused"), "resumeMsg" => t("The rotate operation was resumed")); break; + case "rotateCw": return array("description" => t("Rotate the selected photos clockwise"), "name" => t("Rotate images in %name", array("name" => $item->title)), @@ -465,6 +517,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("The rotate operation was paused"), "resumeMsg" => t("The rotate operation was resumed")); break; + case "delete": return array("description" => t("Delete selected photos and albums"), "name" => t("Delete images in %name", array("name" => $item->title)), @@ -473,6 +526,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("The delete operation was paused"), "resumeMsg" => t("The delete operation was resumed")); break; + case "albumCover": return array("description" => t("Reset Album Cover"), "name" => t("Reset Album cover for %name", array("name" => $item->title)), @@ -481,6 +535,7 @@ class Organize_Controller extends Controller { "pauseMsg" => t("Reset album cover was paused"), "resumeMsg" => t("Reset album cover was resumed")); break; + default: throw new Exception("Operation '$operation' is not implmented"); } diff --git a/modules/organize/helpers/organize.php b/modules/organize/helpers/organize.php index 3a207c95..9bf4e986 100644 --- a/modules/organize/helpers/organize.php +++ b/modules/organize/helpers/organize.php @@ -66,6 +66,14 @@ class organize_Core { $tagPane->hidden("item")->value(implode("|", $itemids)); $item_count = count($itemids); $ids = implode(", ", $itemids); + + // Lame stopgap security check. This code is going to get rewritten anyway. + foreach ($itemids as $id) { + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + } + $tags = Database::instance()->query( "SELECT t.name, COUNT(it.item_id) as count FROM {items_tags} it, {tags} t diff --git a/modules/organize/helpers/organize_task.php b/modules/organize/helpers/organize_task.php index 0f0e4792..dc474818 100644 --- a/modules/organize/helpers/organize_task.php +++ b/modules/organize/helpers/organize_task.php @@ -38,30 +38,55 @@ class organize_task_Core { switch ($taskType) { case "move": $source = ORM::factory("item", $id); + access::required("view", $source); + access::required("view", $target); + access::required("edit", $source); + access::required("edit", $target); + item::move($source, $target); break; + case "rearrange": + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + Database::instance() ->query("Update {items} set weight = {$context["position"]} where id=$id;"); break; + case "rotateCcw": case "rotateCw": $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + if ($item->is_photo()) { $context["post_process"]["reload"][] = self::_do_rotation($item, $taskType == "rotateCcw" ? -90 : 90); } break; + case "albumCover": - item::make_album_cover(ORM::factory("item", $id)); + $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("view", $item->parent()); + access::required("edit", $item->parent()); + + item::make_album_cover($item); break; + case "delete": $item = ORM::factory("item", $id); + access::required("view", $item); + access::required("edit", $item); + $item->delete(); $context["post_process"]["remove"][] = array("id" => $id); break; + default: - throw new Exception("Task '$taskType' is not implmented"); + throw new Exception("Task '$taskType' is not implemented"); } } $context["position"] += $stop; diff --git a/modules/recaptcha/controllers/admin_recaptcha.php b/modules/recaptcha/controllers/admin_recaptcha.php index a8f85ed9..5813df8b 100644 --- a/modules/recaptcha/controllers/admin_recaptcha.php +++ b/modules/recaptcha/controllers/admin_recaptcha.php @@ -21,6 +21,8 @@ class Admin_Recaptcha_Controller extends Admin_Controller { public function index() { $form = recaptcha::get_configure_form(); if (request::method() == "post") { + // @todo move the "save" part of this into a separate controller function + access::verify_csrf(); $old_public_key = module::get_var("recaptcha", "public_key"); $old_private_key = module::get_var("recaptcha", "private_key"); if ($form->validate()) { @@ -55,10 +57,4 @@ class Admin_Recaptcha_Controller extends Admin_Controller { $view->content->form = $form; print $view; } - - public function test() { - $view = new View("admin_recaptcha_test.html"); - $view->public_key = module::get_var("recaptcha", "public_key"); - print $view; - } } diff --git a/modules/server_add/controllers/server_add.php b/modules/server_add/controllers/server_add.php index d5278b3b..c37eab58 100644 --- a/modules/server_add/controllers/server_add.php +++ b/modules/server_add/controllers/server_add.php @@ -21,10 +21,11 @@ class Server_Add_Controller extends Controller { public function index($id) { $paths = unserialize(module::get_var("server_add", "authorized_paths")); - $item = ORM::factory("item", $id); - access::required("server_add", $item); - access::required("add", $item); + if (!user::active()->admin) { + access::forbidden(); + } + $item = ORM::factory("item", $id); $view = new View("server_add_tree_dialog.html"); $view->action = url::abs_site("__ARGS__/{$id}__TASK_ID__?csrf=" . access::csrf_token()); $view->parents = $item->parents(); @@ -41,8 +42,11 @@ class Server_Add_Controller extends Controller { } public function children() { - $paths = unserialize(module::get_var("server_add", "authorized_paths")); + if (!user::active()->admin) { + access::forbidden(); + } + $paths = unserialize(module::get_var("server_add", "authorized_paths")); $path_valid = false; $path = $this->input->post("path"); @@ -66,7 +70,12 @@ class Server_Add_Controller extends Controller { } function start($id) { + if (!user::active()->admin) { + access::forbidden(); + } access::verify_csrf(); + + $item = ORM::factory("item", $id); $paths = unserialize(module::get_var("server_add", "authorized_paths")); $input_files = $this->input->post("path"); $files = array(); @@ -114,9 +123,15 @@ class Server_Add_Controller extends Controller { } function add_photo($task_id) { + if (!user::active()->admin) { + access::forbidden(); + } access::verify_csrf(); $task = task::run($task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } if ($task->done) { switch ($task->state) { @@ -146,10 +161,16 @@ class Server_Add_Controller extends Controller { } public function finish($id, $task_id) { + if (!user::active()->admin) { + access::forbidden(); + } access::verify_csrf(); - $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } + if (!$task->done) { message::warning(t("Add from server was cancelled prior to completion")); } @@ -159,9 +180,14 @@ class Server_Add_Controller extends Controller { } public function pause($id, $task_id) { + if (!user::active()->admin) { + access::forbidden(); + } access::verify_csrf(); - $task = ORM::factory("task", $task_id); + if (!$task->loaded || $task->owner_id != user::active()->id) { + access::forbidden(); + } message::warning(t("Add from server was cancelled prior to completion")); batch::stop(); diff --git a/modules/server_add/helpers/server_add_installer.php b/modules/server_add/helpers/server_add_installer.php index b592b448..f8773a2e 100644 --- a/modules/server_add/helpers/server_add_installer.php +++ b/modules/server_add/helpers/server_add_installer.php @@ -22,7 +22,6 @@ class server_add_installer { $db = Database::instance(); $version = module::get_version("server_add"); if ($version == 0) { - access::register_permission("server_add", t("Add files from server")); module::set_version("server_add", 1); } server_add::check_config(); @@ -31,8 +30,4 @@ class server_add_installer { static function deactivate() { site_status::clear("server_add_configuration"); } - - static function uninstall() { - access::delete_permission("server_add"); - } } diff --git a/modules/server_add/helpers/server_add_menu.php b/modules/server_add/helpers/server_add_menu.php index 04c94493..7269d952 100644 --- a/modules/server_add/helpers/server_add_menu.php +++ b/modules/server_add/helpers/server_add_menu.php @@ -28,11 +28,9 @@ class server_add_menu_Core { static function site($menu, $theme) { $item = $theme->item(); - $paths = unserialize(module::get_var("server_add", "authorized_paths")); - if ($item && access::can("edit", $item) && access::can("server_add", $item) && - $item->is_album() && !empty($paths)) { + if (user::active()->admin && $item->is_album() && !empty($paths)) { $options_menu = $menu->get("options_menu") ->append(Menu::factory("dialog") ->id("server_add") diff --git a/modules/server_add/helpers/server_add_task.php b/modules/server_add/helpers/server_add_task.php index c5a7f067..98575915 100644 --- a/modules/server_add/helpers/server_add_task.php +++ b/modules/server_add/helpers/server_add_task.php @@ -31,7 +31,6 @@ class server_add_task_Core { if (!empty($context["files"][$path])) { $file = $context["files"][$path][$context["position"]]; $parent = ORM::factory("item", $file["parent_id"]); - access::required("server_add", $parent); access::required("add", $parent); if (!$parent->is_album()) { throw new Exception("@todo BAD_ALBUM"); diff --git a/modules/tag/controllers/admin_tags.php b/modules/tag/controllers/admin_tags.php index 1176b0ca..01884bb8 100644 --- a/modules/tag/controllers/admin_tags.php +++ b/modules/tag/controllers/admin_tags.php @@ -42,6 +42,7 @@ class Admin_Tags_Controller extends Admin_Controller { public function delete($id) { access::verify_csrf(); + $tag = ORM::factory("tag", $id); if (!$tag->loaded) { kohana::show_404(); diff --git a/modules/tag/controllers/tags.php b/modules/tag/controllers/tags.php index aecd1db7..930c1252 100644 --- a/modules/tag/controllers/tags.php +++ b/modules/tag/controllers/tags.php @@ -48,6 +48,7 @@ class Tags_Controller extends REST_Controller { public function _create($tag) { $item = ORM::factory("item", $this->input->post("item_id")); + access::required("view", $item); access::required("edit", $item); $form = tag::get_add_form($item); @@ -73,6 +74,7 @@ class Tags_Controller extends REST_Controller { public function _form_add($item_id) { $item = ORM::factory("item", $item_id); access::required("view", $item); + access::required("edit", $item); return tag::get_add_form($item); } diff --git a/modules/user/controllers/admin_users.php b/modules/user/controllers/admin_users.php index ac17c577..fe8061aa 100644 --- a/modules/user/controllers/admin_users.php +++ b/modules/user/controllers/admin_users.php @@ -28,6 +28,7 @@ class Admin_Users_Controller extends Controller { public function add_user() { access::verify_csrf(); + $form = user::get_add_form_admin(); $valid = $form->validate(); $name = $form->add_user->inputs["name"]->value; @@ -63,6 +64,7 @@ class Admin_Users_Controller extends Controller { public function delete_user($id) { access::verify_csrf(); + if ($id == user::active()->id || $id == user::guest()->id) { access::forbidden(); } @@ -97,6 +99,7 @@ class Admin_Users_Controller extends Controller { public function edit_user($id) { access::verify_csrf(); + $user = ORM::factory("user", $id); if (!$user->loaded) { kohana::show_404(); @@ -182,6 +185,7 @@ class Admin_Users_Controller extends Controller { public function add_group() { access::verify_csrf(); + $form = group::get_add_form_admin(); $valid = $form->validate(); if ($valid) { @@ -210,6 +214,7 @@ class Admin_Users_Controller extends Controller { public function delete_group($id) { access::verify_csrf(); + $group = ORM::factory("group", $id); if (!$group->loaded) { kohana::show_404(); @@ -240,6 +245,7 @@ class Admin_Users_Controller extends Controller { public function edit_group($id) { access::verify_csrf(); + $group = ORM::factory("group", $id); if (!$group->loaded) { kohana::show_404(); diff --git a/modules/user/controllers/login.php b/modules/user/controllers/login.php index 6ee2e69d..54a7905e 100644 --- a/modules/user/controllers/login.php +++ b/modules/user/controllers/login.php @@ -26,6 +26,8 @@ class Login_Controller extends Controller { } public function auth_ajax() { + access::verify_csrf(); + list ($valid, $form) = $this->_auth("login/auth_ajax"); if ($valid) { print json_encode( @@ -42,6 +44,8 @@ class Login_Controller extends Controller { } public function auth_html() { + access::verify_csrf(); + list ($valid, $form) = $this->_auth("login/auth_html"); if ($valid) { url::redirect("albums/1"); diff --git a/modules/user/controllers/logout.php b/modules/user/controllers/logout.php index b43680d5..6ceb7192 100644 --- a/modules/user/controllers/logout.php +++ b/modules/user/controllers/logout.php @@ -19,6 +19,8 @@ */ class Logout_Controller extends Controller { public function index() { + access::verify_csrf(); + $user = user::active(); user::logout(); log::info("user", t("User %name logged out", array("name" => $user->name)), diff --git a/modules/user/controllers/password.php b/modules/user/controllers/password.php index c3e66634..3b0eac66 100644 --- a/modules/user/controllers/password.php +++ b/modules/user/controllers/password.php @@ -19,6 +19,8 @@ */ class Password_Controller extends Controller { public function reset() { + access::verify_csrf(); + if (request::method() == "post") { $this->_send_reset(); } else { @@ -27,6 +29,8 @@ class Password_Controller extends Controller { } public function do_reset() { + access::verify_csrf(); + if (request::method() == "post") { $this->_change_password(); } else { diff --git a/modules/user/views/login.html.php b/modules/user/views/login.html.php index cce2fb54..3889f06e 100644 --- a/modules/user/views/login.html.php +++ b/modules/user/views/login.html.php @@ -12,7 +12,7 @@ '" title="' . t("Edit Your Profile") . '" id="gUserProfileLink" class="gDialogLink">' . p::clean(empty($user->full_name) ? $user->name : $user->full_name) . '')) ?> -
  • " id="gLogoutLink">
  • diff --git a/modules/watermark/controllers/admin_watermarks.php b/modules/watermark/controllers/admin_watermarks.php index d487edb8..423196ac 100644 --- a/modules/watermark/controllers/admin_watermarks.php +++ b/modules/watermark/controllers/admin_watermarks.php @@ -38,6 +38,8 @@ class Admin_Watermarks_Controller extends Admin_Controller { } public function edit() { + access::verify_csrf(); + $form = watermark::get_edit_form(); if ($form->validate()) { module::set_var("watermark", "position", $form->edit_watermark->position->value); @@ -61,6 +63,8 @@ class Admin_Watermarks_Controller extends Admin_Controller { } public function delete() { + access::verify_csrf(); + $form = watermark::get_delete_form(); if ($form->validate()) { if ($name = module::get_var("watermark", "name")) { @@ -91,6 +95,8 @@ class Admin_Watermarks_Controller extends Admin_Controller { } public function add() { + access::verify_csrf(); + $form = watermark::get_add_form(); if ($form->validate()) { $file = $_POST["file"]; -- cgit v1.2.3 From 3b6567f38c206f1302c7b22d94d5eae4b458311a Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Mon, 1 Jun 2009 23:20:36 -0700 Subject: Unescape %20 into " " also. --- modules/gallery/controllers/file_proxy.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/controllers/file_proxy.php b/modules/gallery/controllers/file_proxy.php index dfdb4f34..1f885e53 100644 --- a/modules/gallery/controllers/file_proxy.php +++ b/modules/gallery/controllers/file_proxy.php @@ -32,8 +32,8 @@ class File_Proxy_Controller extends Controller { $request_uri = $this->input->server("REQUEST_URI"); $request_uri = preg_replace("/\?.*/", "", $request_uri); - // Firefox converts ~ to %7E breaking our url comparison, below. Convert that back here. - $request_uri = str_replace("%7E", "~", $request_uri); + // Unescape %7E ("~") and %20 (" ") + $request_uri = str_replace(array("%7E", "%20"), array("~", " "), $request_uri); // var_uri: http://example.com/gallery3/var/ $var_uri = url::file("var/"); -- cgit v1.2.3 From 1cfed1fac1f2aa109e96c2aa5c9f66002610b0f8 Mon Sep 17 00:00:00 2001 From: Andy Staudacher Date: Tue, 2 Jun 2009 00:43:04 -0700 Subject: Extend L10n client to provide UI for plural translation. Ticket 148. --- modules/gallery/controllers/l10n_client.php | 102 ++++++++++++++++------------ modules/gallery/css/l10n_client.css | 14 ++-- modules/gallery/helpers/l10n_client.php | 76 +++++++++++++++++++++ modules/gallery/js/l10n_client.js | 100 +++++++++++++++++++++------ modules/gallery/libraries/I18n.php | 27 +++++--- modules/gallery/views/l10n_client.html.php | 41 ++++++++++- 6 files changed, 275 insertions(+), 85 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/controllers/l10n_client.php b/modules/gallery/controllers/l10n_client.php index c3a76659..aa93a758 100644 --- a/modules/gallery/controllers/l10n_client.php +++ b/modules/gallery/controllers/l10n_client.php @@ -24,11 +24,36 @@ class L10n_Client_Controller extends Controller { access::forbidden(); } - $input = Input::instance(); - $message = $input->post("l10n-message-source"); - $translation = $input->post("l10n-edit-target"); - $key = I18n::get_message_key($message); $locale = I18n::instance()->locale(); + $input = Input::instance(); + $key = $input->post("l10n-message-key"); + + $root_message = ORM::factory("incoming_translation") + ->where(array("key" => $key, + "locale" => "root")) + ->find(); + + if (!$root_message->loaded) { + throw new Exception("@todo bad request data / illegal state"); + } + $is_plural = I18n::is_plural_message(unserialize($root_message->message)); + + if ($is_plural) { + $plural_forms = l10n_client::plural_forms($locale); + $translation = array(); + foreach($plural_forms as $plural_form) { + $value = $input->post("l10n-edit-plural-translation-$plural_form"); + if (null === $value || !is_string($value)) { + throw new Exception("@todo bad request data"); + } + $translation[$plural_form] = $value; + } + } else { + $translation = $input->post("l10n-edit-translation"); + if (null === $translation || !is_string($translation)) { + throw new Exception("@todo bad request data"); + } + } $entry = ORM::factory("outgoing_translation") ->where(array("key" => $key, @@ -38,7 +63,7 @@ class L10n_Client_Controller extends Controller { if (!$entry->loaded) { $entry->key = $key; $entry->locale = $locale; - $entry->message = serialize($message); + $entry->message = $root_message->message; $entry->base_revision = null; } @@ -71,19 +96,6 @@ class L10n_Client_Controller extends Controller { url::redirect("albums/1"); } - private static function _l10n_client_form() { - $form = new Forge("l10n_client/save", "", "post", array("id" => "gL10nClientSaveForm")); - $group = $form->group("l10n_message"); - $group->hidden("l10n-message-source")->value(""); - $group->textarea("l10n-edit-target"); - $group->submit("l10n-edit-save")->value(t("Save translation")); - // TODO(andy_st): Avoiding multiple submit buttons for now (hassle with jQuery form plugin). - // $group->submit("l10n-edit-copy")->value(t("Copy source")); - // $group->submit("l10n-edit-clear")->value(t("Clear")); - - return $form; - } - private static function _l10n_client_search_form() { $form = new Forge("l10n_client/search", "", "post", array("id" => "gL10nSearchForm")); $group = $form->group("l10n_search"); @@ -94,41 +106,47 @@ class L10n_Client_Controller extends Controller { } public static function l10n_form() { - if (!user::active()->admin) { - access::forbidden(); - } - $calls = I18n::instance()->call_log(); + $locale = I18n::instance()->locale(); if ($calls) { + $translations = array(); + foreach (Database::instance() + ->select("key", "translation") + ->from("incoming_translations") + ->where(array("locale" => $locale)) + ->get() + ->as_array() as $row) { + $translations[$row->key] = unserialize($row->translation); + } + // Override incoming with outgoing... + foreach (Database::instance() + ->select("key", "translation") + ->from("outgoing_translations") + ->where(array("locale" => $locale)) + ->get() + ->as_array() as $row) { + $translations[$row->key] = unserialize($row->translation); + } + $string_list = array(); - foreach ($calls as $call) { + $cache = array(); + foreach ($calls as $key => $call) { list ($message, $options) = $call; - // Note: Don't interpolate placeholders for the actual translation input field. - // TODO: Use $options to generate a preview. - if (is_array($message)) { - // TODO: Handle plural forms. - // Translate each message. If it has a plural form, get - // the current locale's plural rules and all plural translations. - continue; - } - $source = $message; - $translation = ''; - $options_for_raw_translation = array(); - if (isset($options['count'])) { - $options_for_raw_translation['count'] = $options['count']; - } - if (I18n::instance()->has_translation($message, $options_for_raw_translation)) { - $translation = I18n::instance()->translate($message, $options_for_raw_translation); - } - $string_list[] = array('source' => $source, + // Ensure that the message is in the DB + l10n_scanner::process_message($message, $cache); + // Note: Not interpolating placeholders for the actual translation input field. + // TODO: Might show a preview w/ interpolations (using $options) + $translation = isset($translations[$key]) ? $translations[$key] : ''; + $string_list[] = array('source' => $message, + 'key' => $key, 'translation' => $translation); } $v = new View('l10n_client.html'); $v->string_list = $string_list; - $v->l10n_form = self::_l10n_client_form(); $v->l10n_search_form = self::_l10n_client_search_form(); + $v->plural_forms = l10n_client::plural_forms($locale); return $v; } diff --git a/modules/gallery/css/l10n_client.css b/modules/gallery/css/l10n_client.css index 8973715f..6616f511 100644 --- a/modules/gallery/css/l10n_client.css +++ b/modules/gallery/css/l10n_client.css @@ -145,7 +145,6 @@ how it wants to round. */ margin:0em; } - #l10n-client-string-editor { display:none; float:left; @@ -168,18 +167,13 @@ how it wants to round. */ #gL10nClientSaveForm { padding:0em;} - #gL10nClientSaveForm .form-textarea { - height:13em; - font-size:1em; line-height:1.25em; - width:95%;} - - #gL10nClientSaveForm .form-submit { - margin-top: 0em;} - - #l10n-client form ul, #l10n-client form li, #l10n-client form input[type=submit], #l10n-client form input[type=text] { display: inline ! important ; } + +#l10n-client form .hidden { + display: none; +} diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php index d26739f5..4e905c6c 100644 --- a/modules/gallery/helpers/l10n_client.php +++ b/modules/gallery/helpers/l10n_client.php @@ -200,4 +200,80 @@ class l10n_client_Core { // @todo Move messages out of outgoing into incoming, using new rev? // @todo show which messages have been rejected / are pending? } + + /** + * Plural forms. + */ + static function plural_forms($locale) { + $parts = explode('_', $locale); + $language = $parts[0]; + + // Data from CLDR 1.6 (http://unicode.org/cldr/data/common/supplemental/plurals.xml). + // Docs: http://www.unicode.org/cldr/data/charts/supplemental/language_plural_rules.html + switch ($language) { + case 'az': + case 'fa': + case 'hu': + case 'ja': + case 'ko': + case 'my': + case 'to': + case 'tr': + case 'vi': + case 'yo': + case 'zh': + case 'bo': + case 'dz': + case 'id': + case 'jv': + case 'ka': + case 'km': + case 'kn': + case 'ms': + case 'th': + return array('other'); + + case 'ar': + return array('zero', 'one', 'two', 'few', 'many', 'other'); + + case 'lv': + return array('zero', 'one', 'other'); + + case 'ga': + case 'se': + case 'sma': + case 'smi': + case 'smj': + case 'smn': + case 'sms': + return array('one', 'two', 'other'); + + case 'ro': + case 'mo': + case 'lt': + case 'cs': + case 'sk': + case 'pl': + return array('one', 'few', 'other'); + + case 'hr': + case 'ru': + case 'sr': + case 'uk': + case 'be': + case 'bs': + case 'sh': + case 'mt': + return array('one', 'few', 'many', 'other'); + + case 'sl': + return array('one', 'two', 'few', 'other'); + + case 'cy': + return array('one', 'two', 'many', 'other'); + + default: // en, de, etc. + return array('one', 'other'); + } + } } \ No newline at end of file diff --git a/modules/gallery/js/l10n_client.js b/modules/gallery/js/l10n_client.js index f43671f1..efd956e2 100644 --- a/modules/gallery/js/l10n_client.js +++ b/modules/gallery/js/l10n_client.js @@ -90,6 +90,40 @@ jQuery.extend(Gallery, { this.setString = function(index, data) { l10n_client_data[index]['translation'] = data; } + // Display the source message + this.showSourceMessage = function(source, is_plural) { + if (is_plural) { + var pretty_source = '[one] - ' + source['one'] + "\n"; + pretty_source += '[other] - ' + source['other']; + } else { + var pretty_source = source; + } + $('#l10n-client-string-editor .source-text').text(pretty_source); + } + this.isPluralMessage = function(message) { + return typeof(message) == 'object'; + } + this.updateTranslationForm = function(translation, is_plural) { + $('.translationField').addClass('hidden'); + if (is_plural) { + if (typeof(translation) != 'object') { + translation = {}; + } + var num_plural_forms = plural_forms.length; + for (var i = 0; i < num_plural_forms; i++) { + var form = plural_forms[i]; + if (translation[form] == undefined) { + translation[form] = ''; + } + $('#l10n-edit-plural-translation-' + form) + .attr('value', translation[form]); + $('#plural-' + form).removeClass('hidden'); + } + } else { + $('#l10n-edit-translation').attr('value', translation); + $('#l10n-edit-translation').removeClass('hidden'); + } + } // Filter the the string list by a search string this.filter = function(search) { if(search == false || search == '') { @@ -126,11 +160,12 @@ Gallery.behaviors.l10nClient = function(context) { $('#l10n-client-string-select li').removeClass('active'); $(this).addClass('active'); var index = $('#l10n-client-string-select li').index(this); - - $('#l10n-client-string-editor .source-text').text(Gallery.l10nClient.getString(index, 'source')); - $("#gL10nClientSaveForm input[name='l10n-message-source']").val(Gallery.l10nClient.getString(index, 'source')); - $('#gL10nClientSaveForm #l10n-edit-target').val(Gallery.l10nClient.getString(index, 'translation')); - + var source = Gallery.l10nClient.getString(index, 'source'); + var key = Gallery.l10nClient.getString(index, 'key'); + var is_plural = Gallery.l10nClient.isPluralMessage(source); + Gallery.l10nClient.showSourceMessage(source, is_plural); + Gallery.l10nClient.updateTranslationForm(Gallery.l10nClient.getString(index, 'translation'), is_plural); + $("#gL10nClientSaveForm input[name='l10n-message-key']").val(key); Gallery.l10nClient.selected = index; }); @@ -165,23 +200,46 @@ Gallery.behaviors.l10nClient = function(context) { $('#gL10nClientSaveForm').ajaxForm({ dataType: "json", success: function(data) { - // Store string in local js - Gallery.l10nClient.setString(Gallery.l10nClient.selected, $('#gL10nClientSaveForm #l10n-edit-target').val()); - - // Mark string as translated. - $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated').text($('#gL10nClientSaveForm #l10n-edit-target').val()); - - // Empty input fields. - $('#l10n-client-string-editor .source-text').html(''); - $('#gL10nClientSaveForm #l10n-edit-target').val(''); - $("#gL10nClientSaveForm input[name='l10n-message-source']").val(''); - }, - error: function(xmlhttp) { - // TODO: Localize this message - alert('An HTTP error @status occured (or empty response).'.replace('@status', xmlhttp.status)); - } - }); + var source = Gallery.l10nClient.getString(Gallery.l10nClient.selected, 'source'); + var is_plural = Gallery.l10nClient.isPluralMessage(source); + var num_plural_forms = plural_forms.length; + + // Store translation in local js + if (is_plural) { + var translation = {}; + for (var i = 0; i < num_plural_forms; i++) { + var form = plural_forms[i]; + translation[form] = $('#gL10nClientSaveForm #l10n-edit-plural-translation-' + form).attr('value'); + } + } else { + translation = $('#l10n-edit-translation').attr('value'); + } + Gallery.l10nClient.setString(Gallery.l10nClient.selected, translation); + + // Mark message as translated. + $('#l10n-client-string-select li').eq(Gallery.l10nClient.selected).removeClass('untranslated').removeClass('active').addClass('translated'); + + // Clear the translation form fields + Gallery.l10nClient.showSourceMessage('', false); + $('#gL10nClientSaveForm #l10n-edit-translation').val(''); + + for (var i = 0; i < num_plural_forms; i++) { + var form = plural_forms[i]; + $('#gL10nClientSaveForm #l10n-edit-plural-translation-' + form).val(''); + } + $("#gL10nClientSaveForm input[name='l10n-message-key']").val(''); + }, + error: function(xmlhttp) { + // TODO: Localize this message + alert('An HTTP error @status occured (or empty response).'.replace('@status', xmlhttp.status)); + } + }); + // TODO: Add copy/clear buttons (without ajax behavior) + /* "/> + "/> + */ + // TODO: Handle plurals in copy button // Copy source text to translation field on button click. $('#gL10nClientSaveForm #l10n-edit-copy').click(function() { diff --git a/modules/gallery/libraries/I18n.php b/modules/gallery/libraries/I18n.php index f2801169..03a6d8f6 100644 --- a/modules/gallery/libraries/I18n.php +++ b/modules/gallery/libraries/I18n.php @@ -148,30 +148,37 @@ class I18n_Core { public function has_translation($message, $options=null) { $locale = empty($options['locale']) ? $this->_config['default_locale'] : $options['locale']; - $count = empty($options['count']) ? null : $options['count']; - $values = $options; - unset($values['locale']); - $this->log($message, $options); $entry = $this->lookup($locale, $message); if (null === $entry) { return false; - } else if (!is_array($entry)) { + } else if (!is_array($message)) { return $entry !== ''; } else { - $plural_key = self::get_plural_key($locale, $count); - return isset($entry[$plural_key]) - && $entry[$plural_key] !== null - && $entry[$plural_key] !== ''; + if (!is_array($entry) || empty($entry)) { + return false; + } + // It would be better to verify that all the locale's plural forms have a non-empty + // translation, but this is fine for now. + foreach ($entry as $value) { + if ($value === '') { + return false; + } + } + return true; } } - public static function get_message_key($message) { + static function get_message_key($message) { $as_string = is_array($message) ? implode('|', $message) : $message; return md5($as_string); } + static function is_plural_message($message) { + return is_array($message); + } + private function interpolate($locale, $string, $values) { // TODO: Handle locale specific number formatting. diff --git a/modules/gallery/views/l10n_client.html.php b/modules/gallery/views/l10n_client.html.php index 8f4092c7..faa6e939 100644 --- a/modules/gallery/views/l10n_client.html.php +++ b/modules/gallery/views/l10n_client.html.php @@ -11,21 +11,58 @@
    • "> + + [one] -
      + [other] - + +
    +
    -
    +
    
         
    - + " id="gL10nClientSaveForm"> + + + + + + + + + + "/> +
    -- cgit v1.2.3 From 0f987880e67c667dc1e2c47455fc9ee0859fcba7 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Tue, 2 Jun 2009 12:08:47 -0700 Subject: Fix for ticket #320 --- modules/gallery/models/item.php | 6 +++--- modules/gallery/views/move_tree.html.php | 4 ++-- modules/image_block/views/image_block_block.html.php | 2 +- modules/organize/views/organize_thumb_grid.html.php | 2 +- modules/search/views/search.html.php | 2 +- themes/default/views/album.html.php | 2 +- themes/default/views/photo.html.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/models/item.php b/modules/gallery/models/item.php index 9406f5d9..10bad0b2 100644 --- a/modules/gallery/models/item.php +++ b/modules/gallery/models/item.php @@ -395,7 +395,7 @@ class Item_Model extends ORM_MPTT { * @param boolean (optional) $center_vertically Center vertically (default: false) * @return string */ - public function thumb_tag($extra_attrs=array(), $max=null, $center_vertically=false) { + public function thumb_img($extra_attrs=array(), $max=null, $center_vertically=false) { 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 @@ -448,7 +448,7 @@ class Item_Model extends ORM_MPTT { * @param array $extra_attrs Extra attributes to add to the img tag * @return string */ - public function resize_tag($extra_attrs) { + public function resize_img($extra_attrs) { $attrs = array_merge($extra_attrs, array("src" => $this->resize_url(), "alt" => $this->title, @@ -464,7 +464,7 @@ class Item_Model extends ORM_MPTT { * @param array $extra_attrs * @return string */ - public function movie_tag($extra_attrs) { + public function movie_img($extra_attrs) { $attrs = array_merge($extra_attrs, array("id" => "player", "style" => "display:block;width:400px;height:300px") diff --git a/modules/gallery/views/move_tree.html.php b/modules/gallery/views/move_tree.html.php index 91a2f9da..5f70cf67 100644 --- a/modules/gallery/views/move_tree.html.php +++ b/modules/gallery/views/move_tree.html.php @@ -1,5 +1,5 @@ -thumb_tag(array(), 25); ?> +thumb_img(array(), 25); ?> is_descendant($parent)): ?> title) ?> @@ -8,7 +8,7 @@
    • - thumb_tag(array(), 25); ?> + thumb_img(array(), 25); ?> is_descendant($child)): ?> title) ?> diff --git a/modules/image_block/views/image_block_block.html.php b/modules/image_block/views/image_block_block.html.php index 0ba9915e..48a3c912 100644 --- a/modules/image_block/views/image_block_block.html.php +++ b/modules/image_block/views/image_block_block.html.php @@ -1,6 +1,6 @@ diff --git a/modules/organize/views/organize_thumb_grid.html.php b/modules/organize/views/organize_thumb_grid.html.php index 64d8aaf3..c80696ad 100644 --- a/modules/organize/views/organize_thumb_grid.html.php +++ b/modules/organize/views/organize_thumb_grid.html.php @@ -6,7 +6,7 @@
    • - thumb_tag(array("class" => "gThumbnail"), $thumbsize, true) ?> + thumb_img(array("class" => "gThumbnail"), $thumbsize, true) ?>
    • diff --git a/modules/search/views/search.html.php b/modules/search/views/search.html.php index de4343ae..5db07bad 100644 --- a/modules/search/views/search.html.php +++ b/modules/search/views/search.html.php @@ -29,7 +29,7 @@
    • id") ?>"> - thumb_tag() ?> + thumb_img() ?>

      title) ?>

      diff --git a/themes/default/views/album.html.php b/themes/default/views/album.html.php index 6e17696d..7d4a6f54 100644 --- a/themes/default/views/album.html.php +++ b/themes/default/views/album.html.php @@ -15,7 +15,7 @@
    • thumb_top($child) ?> - thumb_tag(array("class" => "gThumbnail")) ?> + thumb_img(array("class" => "gThumbnail")) ?> thumb_bottom($child) ?>

      title) ?>

      diff --git a/themes/default/views/photo.html.php b/themes/default/views/photo.html.php index cc069158..85143da8 100644 --- a/themes/default/views/photo.html.php +++ b/themes/default/views/photo.html.php @@ -29,7 +29,7 @@ "> - resize_tag(array("id" => "gPhotoId-{$item->id}", "class" => "gResize")) ?> + resize_img(array("id" => "gPhotoId-{$item->id}", "class" => "gResize")) ?> -- cgit v1.2.3 From d8eca7682d36e66cffa86fd101998d72b4e413d1 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Tue, 2 Jun 2009 12:41:59 -0700 Subject: make cleanm static --- modules/gallery/helpers/p.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'modules/gallery') diff --git a/modules/gallery/helpers/p.php b/modules/gallery/helpers/p.php index c3074c23..0a6210dc 100644 --- a/modules/gallery/helpers/p.php +++ b/modules/gallery/helpers/p.php @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ class p_Core { - function clean($dirty_html) { + static function clean($dirty_html) { return html::specialchars($dirty_html); } } -- cgit v1.2.3 From 4f50357a3873bb612abf1e5fddebe9ee9cbadf40 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Tue, 2 Jun 2009 12:56:36 -0700 Subject: fix the xss_security_test in regards to the renaming of thumb_tag, resize_tag and move_tag. --- modules/gallery/tests/xss_data.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/tests/xss_data.txt b/modules/gallery/tests/xss_data.txt index 4aaa520d..67f293dd 100644 --- a/modules/gallery/tests/xss_data.txt +++ b/modules/gallery/tests/xss_data.txt @@ -195,14 +195,14 @@ modules/gallery/views/l10n_client.html.php 29 DIRTY $string_l modules/gallery/views/move_browse.html.php 4 DIRTY $source->id modules/gallery/views/move_browse.html.php 39 DIRTY $tree modules/gallery/views/move_browse.html.php 42 DIRTY $source->id -modules/gallery/views/move_tree.html.php 2 DIRTY $parent->thumb_tag(array(), 25) +modules/gallery/views/move_tree.html.php 2 DIRTY $parent->thumb_img(array(), 25) modules/gallery/views/move_tree.html.php 4 DIRTY $parent->id modules/gallery/views/move_tree.html.php 4 CLEAN $parent->title modules/gallery/views/move_tree.html.php 6 DIRTY $parent->id modules/gallery/views/move_tree.html.php 6 CLEAN $parent->title modules/gallery/views/move_tree.html.php 8 DIRTY $parent->id modules/gallery/views/move_tree.html.php 10 DIRTY $child->id -modules/gallery/views/move_tree.html.php 11 DIRTY $child->thumb_tag(array(), 25) +modules/gallery/views/move_tree.html.php 11 DIRTY $child->thumb_img(array(), 25) modules/gallery/views/move_tree.html.php 13 DIRTY $child->id modules/gallery/views/move_tree.html.php 13 CLEAN $child->title modules/gallery/views/move_tree.html.php 15 DIRTY $child->id @@ -335,7 +335,7 @@ modules/organize/views/organize_thumb_grid.html.php 7 DIRTY $child->i modules/organize/views/organize_thumb_grid.html.php 7 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 8 DIRTY $child->id modules/organize/views/organize_thumb_grid.html.php 8 DIRTY $item_class -modules/organize/views/organize_thumb_grid.html.php 9 DIRTY $child->thumb_tag(array("class" => "gThumbnail"), $thumbsize, true) +modules/organize/views/organize_thumb_grid.html.php 9 DIRTY $child->thumb_img(array("class" => "gThumbnail"), $thumbsize, true) modules/recaptcha/views/admin_recaptcha.html.php 5 DIRTY $form->get_key_url modules/recaptcha/views/admin_recaptcha.html.php 8 DIRTY $form modules/recaptcha/views/admin_recaptcha.html.php 21 DIRTY $public_key @@ -406,7 +406,7 @@ modules/rss/views/rss_block.html.php 8 DIRTY $title modules/search/views/search.html.php 11 CLEAN $q modules/search/views/search.html.php 30 DIRTY $item_class modules/search/views/search.html.php 31 DIRTY $item->id -modules/search/views/search.html.php 32 DIRTY $item->thumb_tag() +modules/search/views/search.html.php 32 DIRTY $item->thumb_img() modules/search/views/search.html.php 34 CLEAN $item->title modules/search/views/search.html.php 37 CLEAN $item->description modules/search/views/search.html.php 43 DIRTY $theme->pager() @@ -518,7 +518,7 @@ themes/default/views/album.html.php 15 DIRTY $child->i themes/default/views/album.html.php 15 DIRTY $item_class themes/default/views/album.html.php 16 DIRTY $theme->thumb_top($child) themes/default/views/album.html.php 17 DIRTY $child->url() -themes/default/views/album.html.php 18 DIRTY $child->thumb_tag(array("class" => "gThumbnail")) +themes/default/views/album.html.php 18 DIRTY $child->thumb_img(array("class" => "gThumbnail")) themes/default/views/album.html.php 20 DIRTY $theme->thumb_bottom($child) themes/default/views/album.html.php 21 DIRTY $child->url() themes/default/views/album.html.php 21 CLEAN $child->title @@ -607,7 +607,7 @@ themes/default/views/photo.html.php 15 DIRTY $position themes/default/views/photo.html.php 15 DIRTY $sibling_count themes/default/views/photo.html.php 18 DIRTY $next_item->url() themes/default/views/photo.html.php 28 DIRTY $theme->resize_top($item) -themes/default/views/photo.html.php 32 DIRTY $item->resize_tag(array("id" => "gPhotoId-{$item->id}", "class" => "gResize")) +themes/default/views/photo.html.php 32 DIRTY $item->resize_img(array("id" => "gPhotoId-{$item->id}", "class" => "gResize")) themes/default/views/photo.html.php 36 DIRTY $theme->resize_bottom($item) themes/default/views/photo.html.php 40 CLEAN $item->title themes/default/views/photo.html.php 41 CLEAN $item->description -- cgit v1.2.3 From ffb3abdcace93c8397e4660dc0e45d932903dd5a Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 2 Jun 2009 13:37:19 -0700 Subject: Restore "view" permissions on the root album in teardown. --- modules/gallery/tests/Access_Helper_Test.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'modules/gallery') diff --git a/modules/gallery/tests/Access_Helper_Test.php b/modules/gallery/tests/Access_Helper_Test.php index 7012a487..d71bf971 100644 --- a/modules/gallery/tests/Access_Helper_Test.php +++ b/modules/gallery/tests/Access_Helper_Test.php @@ -38,6 +38,10 @@ class Access_Helper_Test extends Unit_Test_Case { $user->delete(); } } catch (Exception $e) { } + + // Reset some permissions that we mangle below + $root = ORM::factory("item", 1); + access::allow(group::everybody(), "view", $root); } public function setup() { -- cgit v1.2.3 From dbeceb333b876cdfeab35e5b35c4292cda8819e8 Mon Sep 17 00:00:00 2001 From: Tim Almdal Date: Tue, 2 Jun 2009 14:19:03 -0700 Subject: Improve test isolation so that Albums_Controller_Test doesn't fail when run with Photos_Controller_Test --- modules/gallery/tests/Albums_Controller_Test.php | 20 ++++++++++++-------- modules/gallery/tests/Photos_Controller_Test.php | 21 +++++++++++++-------- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/tests/Albums_Controller_Test.php b/modules/gallery/tests/Albums_Controller_Test.php index ef1fac77..7674e85f 100644 --- a/modules/gallery/tests/Albums_Controller_Test.php +++ b/modules/gallery/tests/Albums_Controller_Test.php @@ -20,17 +20,21 @@ class Albums_Controller_Test extends Unit_Test_Case { public function setup() { $this->_post = $_POST; + $this->_album = null; } public function teardown() { $_POST = $this->_post; + if ($this->_album) { + $this->_album->delete(); + } } public function change_album_test() { $controller = new Albums_Controller(); $root = ORM::factory("item", 1); - $album = album::create($root, "test", "test", "test"); - $orig_name = $album->name; + $this->_album = album::create($root, "test", "test", "test"); + $orig_name = $this->_album->name; $_POST["dirname"] = "test"; $_POST["name"] = "new name"; @@ -43,31 +47,31 @@ class Albums_Controller_Test extends Unit_Test_Case { access::allow(group::everybody(), "edit", $root); ob_start(); - $controller->_update($album); + $controller->_update($this->_album); $results = ob_get_contents(); ob_end_clean(); $this->assert_equal( json_encode(array("result" => "success", "location" => "http://./index.php/test")), $results); - $this->assert_equal("new title", $album->title); - $this->assert_equal("new description", $album->description); + $this->assert_equal("new title", $this->_album->title); + $this->assert_equal("new description", $this->_album->description); // We don't change the name, yet. - $this->assert_equal($orig_name, $album->name); + $this->assert_equal($orig_name, $this->_album->name); } public function change_album_no_csrf_fails_test() { $controller = new Albums_Controller(); $root = ORM::factory("item", 1); - $album = album::create($root, "test", "test", "test"); + $this->_album = album::create($root, "test", "test", "test"); $_POST["name"] = "new name"; $_POST["title"] = "new title"; $_POST["description"] = "new description"; access::allow(group::everybody(), "edit", $root); try { - $controller->_update($album); + $controller->_update($this->_album); $this->assert_true(false, "This should fail"); } catch (Exception $e) { // pass diff --git a/modules/gallery/tests/Photos_Controller_Test.php b/modules/gallery/tests/Photos_Controller_Test.php index 771cc90d..f7d3f72f 100644 --- a/modules/gallery/tests/Photos_Controller_Test.php +++ b/modules/gallery/tests/Photos_Controller_Test.php @@ -20,17 +20,22 @@ class Photos_Controller_Test extends Unit_Test_Case { public function setup() { $this->_post = $_POST; + $this->_photo = null; } public function teardown() { $_POST = $this->_post; + if ($this->_photo) { + $this->_photo->delete(); + } } public function change_photo_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", "test"); - $orig_name = $photo->name; + $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test.jpeg", "test", + "test"); + $orig_name = $this->_photo->name; $_POST["filename"] = "test.jpeg"; $_POST["name"] = "new name"; @@ -40,7 +45,7 @@ class Photos_Controller_Test extends Unit_Test_Case { access::allow(group::everybody(), "edit", $root); ob_start(); - $controller->_update($photo); + $controller->_update($this->_photo); $results = ob_get_contents(); ob_end_clean(); @@ -48,24 +53,24 @@ class Photos_Controller_Test extends Unit_Test_Case { json_encode(array("result" => "success", "location" => "http://./index.php/test.jpeg")), $results); - $this->assert_equal("new title", $photo->title); - $this->assert_equal("new description", $photo->description); + $this->assert_equal("new title", $this->_photo->title); + $this->assert_equal("new description", $this->_photo->description); // We don't change the name, yet. - $this->assert_equal($orig_name, $photo->name); + $this->assert_equal($orig_name, $this->_photo->name); } public function change_photo_no_csrf_fails_test() { $controller = new Photos_Controller(); $root = ORM::factory("item", 1); - $photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test", "test", "test"); + $this->_photo = photo::create($root, MODPATH . "gallery/tests/test.jpg", "test", "test", "test"); $_POST["name"] = "new name"; $_POST["title"] = "new title"; $_POST["description"] = "new description"; access::allow(group::everybody(), "edit", $root); try { - $controller->_update($photo); + $controller->_update($this->_photo); $this->assert_true(false, "This should fail"); } catch (Exception $e) { // pass -- cgit v1.2.3 From e834c4ca2434ff687461e39ee02926f449f49287 Mon Sep 17 00:00:00 2001 From: Bharat Mediratta Date: Tue, 2 Jun 2009 15:46:05 -0700 Subject: Have server_add turn the "Add Photo" menu option into a dropdown and make "Add from Server" a 2nd option there. This requires adding the Menu::remove() API function. --- modules/gallery/libraries/Menu.php | 13 +++++++++- modules/server_add/helpers/server_add_menu.php | 34 ++++++++++++++++++++++---- 2 files changed, 41 insertions(+), 6 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/libraries/Menu.php b/modules/gallery/libraries/Menu.php index d19d8b1e..83bd1616 100644 --- a/modules/gallery/libraries/Menu.php +++ b/modules/gallery/libraries/Menu.php @@ -170,11 +170,22 @@ class Menu_Core extends Menu_Element { return $this; } + /** + * Remove an element from the menu + */ + public function remove($target_id) { + unset($this->elements[$target_id]); + } + /** * Retrieve a Menu_Element by id */ public function get($id) { - return $this->elements[$id]; + if (array_key_exists($id, $this->elements)) { + return $this->elements[$id]; + } + + return null; } public function __toString() { diff --git a/modules/server_add/helpers/server_add_menu.php b/modules/server_add/helpers/server_add_menu.php index 7269d952..a97a6cee 100644 --- a/modules/server_add/helpers/server_add_menu.php +++ b/modules/server_add/helpers/server_add_menu.php @@ -31,11 +31,35 @@ class server_add_menu_Core { $paths = unserialize(module::get_var("server_add", "authorized_paths")); if (user::active()->admin && $item->is_album() && !empty($paths)) { - $options_menu = $menu->get("options_menu") - ->append(Menu::factory("dialog") - ->id("server_add") - ->label(t("Add from server")) - ->url(url::site("server_add/index/$item->id"))); + // This is a little tricky. Normally there's an "Add Photo" menu option, but we want to + // turn that into a dropdown if there are two different ways to add things. Do that in a + // portable way for now. If we find ourselves duplicating this pattern, we should make an + // API method for this. + $server_add = Menu::factory("dialog") + ->id("server_add") + ->label(t("Add from server")) + ->url(url::site("server_add/index/$item->id")); + $options_menu = $menu->get("options_menu"); + $add_item = $options_menu->get("add_item"); + $add_menu = $options_menu->get("add_menu"); + + if ($add_item && !$add_menu) { + // Assuming that $add_menu is unset, create add_menu and add our item + $options_menu->add_after( + "add_item", + Menu::factory("submenu") + ->id("add_menu") + ->label(t("Add")) + ->append($add_item) + ->append($server_add)); + $options_menu->remove("add_item"); + } else if ($add_menu) { + // Append to the existing sub-menu + $add_menu->append($server_add); + } else { + // Else just add it in at the end of Options + $options_menu->append($server_add); + } } } } -- cgit v1.2.3 From dde5fb96ee9db5a67b286ea4ac4f35190453a6ef Mon Sep 17 00:00:00 2001 From: jhilden Date: Tue, 2 Jun 2009 19:31:11 -0400 Subject: made "Add photos" its own site menu item * open for suggestions on the submenu item labels * @bharat: not sure about the add photos menu item id in the dropdown case --- modules/gallery/helpers/gallery_menu.php | 13 ++++++++----- modules/server_add/helpers/server_add_menu.php | 25 ++++++++++++++----------- 2 files changed, 22 insertions(+), 16 deletions(-) (limited to 'modules/gallery') diff --git a/modules/gallery/helpers/gallery_menu.php b/modules/gallery/helpers/gallery_menu.php index 09c2d91a..d28e71c9 100644 --- a/modules/gallery/helpers/gallery_menu.php +++ b/modules/gallery/helpers/gallery_menu.php @@ -30,7 +30,14 @@ class gallery_menu_Core { $can_edit = $item && access::can("edit", $item) || $is_admin; $can_add = $item && (access::can("add", $item) || $is_admin); - + + if ($can_add) { + $menu->append(Menu::factory("dialog") + ->id("add_photos_item") + ->label(t("Add photos")) + ->url(url::site("simple_uploader/app/$item->id"))); + } + if ($item && $can_edit || $can_add) { $menu->append($options_menu = Menu::factory("submenu") ->id("options_menu") @@ -48,10 +55,6 @@ class gallery_menu_Core { if ($item->is_album()) { if ($can_add) { $options_menu - ->append(Menu::factory("dialog") - ->id("add_item") - ->label(t("Add a photo")) - ->url(url::site("simple_uploader/app/$item->id"))) ->append(Menu::factory("dialog") ->id("add_album") ->label(t("Add an album")) diff --git a/modules/server_add/helpers/server_add_menu.php b/modules/server_add/helpers/server_add_menu.php index a97a6cee..f02223f7 100644 --- a/modules/server_add/helpers/server_add_menu.php +++ b/modules/server_add/helpers/server_add_menu.php @@ -40,22 +40,25 @@ class server_add_menu_Core { ->label(t("Add from server")) ->url(url::site("server_add/index/$item->id")); $options_menu = $menu->get("options_menu"); - $add_item = $options_menu->get("add_item"); - $add_menu = $options_menu->get("add_menu"); + $add_photos_item = $menu->get("add_photos_item"); + $add_photos_menu = $menu->get("add_photos_menu"); - if ($add_item && !$add_menu) { + if ($add_photos_item && !$add_photos_menu) { // Assuming that $add_menu is unset, create add_menu and add our item - $options_menu->add_after( - "add_item", + $menu->add_after( + "home", Menu::factory("submenu") - ->id("add_menu") - ->label(t("Add")) - ->append($add_item) + ->id("add_photos_menu") + ->label(t("Add Photos")) + ->append(Menu::factory("dialog") + ->id("add_photos_submenu_item") + ->label(t("via Simple Uploader")) + ->url(url::site("simple_uploader/app/$item->id"))) ->append($server_add)); - $options_menu->remove("add_item"); - } else if ($add_menu) { + $menu->remove("add_photos_item"); + } else if ($add_photos_menu) { // Append to the existing sub-menu - $add_menu->append($server_add); + $add_photos_menu->append($server_add); } else { // Else just add it in at the end of Options $options_menu->append($server_add); -- cgit v1.2.3