summaryrefslogtreecommitdiff
path: root/modules/gallery/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gallery/helpers')
-rw-r--r--modules/gallery/helpers/MY_html.php91
-rw-r--r--modules/gallery/helpers/MY_url.php31
-rw-r--r--modules/gallery/helpers/access.php108
-rw-r--r--modules/gallery/helpers/album.php66
-rw-r--r--modules/gallery/helpers/gallery.php230
-rw-r--r--modules/gallery/helpers/gallery_event.php14
-rw-r--r--modules/gallery/helpers/gallery_installer.php97
-rw-r--r--modules/gallery/helpers/gallery_menu.php167
-rw-r--r--modules/gallery/helpers/gallery_quick.php144
-rw-r--r--modules/gallery/helpers/gallery_rss.php11
-rw-r--r--modules/gallery/helpers/gallery_search.php24
-rw-r--r--modules/gallery/helpers/gallery_task.php41
-rw-r--r--modules/gallery/helpers/gallery_theme.php62
-rw-r--r--modules/gallery/helpers/graphics.php155
-rw-r--r--modules/gallery/helpers/item.php96
-rw-r--r--modules/gallery/helpers/l10n_client.php7
-rw-r--r--modules/gallery/helpers/locales.php (renamed from modules/gallery/helpers/locale.php)92
-rw-r--r--modules/gallery/helpers/model_cache.php6
-rw-r--r--modules/gallery/helpers/module.php17
-rw-r--r--modules/gallery/helpers/movie.php21
-rw-r--r--modules/gallery/helpers/p.php39
-rw-r--r--modules/gallery/helpers/photo.php52
-rw-r--r--modules/gallery/helpers/task.php3
23 files changed, 966 insertions, 608 deletions
diff --git a/modules/gallery/helpers/MY_html.php b/modules/gallery/helpers/MY_html.php
new file mode 100644
index 00000000..b29f287f
--- /dev/null
+++ b/modules/gallery/helpers/MY_html.php
@@ -0,0 +1,91 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2009 Bharat Mediratta
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+class html extends html_Core {
+ /**
+ * Returns a string that is safe to be used in HTML (XSS protection).
+ *
+ * If $html is a string, the returned string will be HTML escaped.
+ * If $html is a SafeString instance, the returned string may contain
+ * unescaped HTML which is assumed to be safe.
+ *
+ * Example:<pre>
+ * <div><?= html::clean($php_var) ?>
+ * </pre>
+ */
+ static function clean($html) {
+ return new SafeString($html);
+ }
+
+ /**
+ * Returns a string that is safe to be used in HTML (XSS protection),
+ * purifying (filtering) the given HTML to ensure that the result contains
+ * only non-malicious HTML.
+ *
+ * Example:<pre>
+ * <div><?= html::purify($item->title) ?>
+ * </pre>
+ */
+ static function purify($html) {
+ return SafeString::purify($html);
+ }
+
+ /**
+ * Flags the given string as safe to be used in HTML (free of malicious HTML/JS).
+ *
+ * Example:<pre>
+ * // Parameters to t() are automatically escaped by default.
+ * // If the parameter is marked as clean, it won't get escaped.
+ * t('Go <a href="%url">there</a>',
+ * array("url" => html::mark_clean(url::current())))
+ * </pre>
+ */
+ static function mark_clean($html) {
+ return SafeString::of_safe_html($html);
+ }
+
+ /**
+ * Escapes the given string for use in JavaScript.
+ *
+ * Example:<pre>
+ * <script type="text/javascript>"
+ * var some_js_string = <?= html::js_string($php_string) ?>;
+ * </script>
+ * </pre>
+ */
+ static function js_string($string) {
+ return SafeString::of($string)->for_js();
+ }
+
+ /**
+ * Returns a string safe for use in HTML element attributes.
+ *
+ * Assumes that the HTML element attribute is already
+ * delimited by single or double quotes
+ *
+ * Example:<pre>
+ * <a title="<?= html::clean_for_attribute($php_var) ?>">;
+ * </script>
+ * </pre>
+ * @return the string escaped for use in HTML attributes.
+ */
+ static function clean_attribute($string) {
+ return self::clean($string)->for_html_attr();
+ }
+}
diff --git a/modules/gallery/helpers/MY_url.php b/modules/gallery/helpers/MY_url.php
index c4967c52..368c947e 100644
--- a/modules/gallery/helpers/MY_url.php
+++ b/modules/gallery/helpers/MY_url.php
@@ -18,21 +18,6 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class url extends url_Core {
- static function site($uri, $protocol=false) {
- if (($pos = strpos($uri, "?")) !== false) {
- list ($uri, $query) = explode("?", $uri, 2);
- $query = "?$query";
- } else {
- $query = "";
- }
-
- $parts = explode("/", $uri, 3);
- if ($parts[0] == "albums" || $parts[0] == "photos") {
- $uri = model_cache::get("item", $parts[1])->relative_path();
- }
- return parent::site($uri . $query, $protocol);
- }
-
static function parse_url() {
if (Router::$controller) {
return;
@@ -55,20 +40,24 @@ class url extends url_Core {
}
/**
- * Return the item that the uri is referencing
+ * Locate an item using the URI. We assume that the uri is in the form /a/b/c where each
+ * component matches up with an item slug.
+ * @param string $uri the uri fragment
+ * @return Item_Model
*/
static function get_item_from_uri($uri) {
$current_uri = html_entity_decode($uri, ENT_QUOTES);
- $item = ORM::factory("item")->where("relative_path_cache", $current_uri)->find();
+ // In most cases, we'll have an exact match in the relative_url_cache item field.
+ // but failing that, walk down the tree until we find it. The fallback code will fix caches
+ // as it goes, so it'll never be run frequently.
+ $item = ORM::factory("item")->where("relative_url_cache", $current_uri)->find();
if (!$item->loaded) {
- // It's possible that the relative path cache for the item we're looking for is out of date,
- // so find it the hard way.
$count = count(Router::$segments);
foreach (ORM::factory("item")
- ->where("name", html_entity_decode(Router::$segments[$count - 1], ENT_QUOTES))
+ ->where("slug", html_entity_decode(Router::$segments[$count - 1], ENT_QUOTES))
->where("level", $count + 1)
->find_all() as $match) {
- if ($match->relative_path() == $current_uri) {
+ if ($match->relative_url() == $current_uri) {
$item = $match;
}
}
diff --git a/modules/gallery/helpers/access.php b/modules/gallery/helpers/access.php
index c48f0b79..949aea84 100644
--- a/modules/gallery/helpers/access.php
+++ b/modules/gallery/helpers/access.php
@@ -66,9 +66,10 @@
* the Access_Intent_Model
*/
class access_Core {
- const DENY = 0;
- const ALLOW = 1;
- const UNKNOWN = 2;
+ const DENY = false;
+ const ALLOW = true;
+ const INHERIT = null; // access_intent
+ const UNKNOWN = null; // cache (access_cache, items)
/**
* Does the active user have this permission on this item?
@@ -78,18 +79,30 @@ class access_Core {
* @return boolean
*/
static function can($perm_name, $item) {
+ return self::user_can(user::active(), $perm_name, $item);
+ }
+
+ /**
+ * Does the user have this permission on this item?
+ *
+ * @param User_Model $user
+ * @param string $perm_name
+ * @param Item_Model $item
+ * @return boolean
+ */
+ static function user_can($user, $perm_name, $item) {
if (!$item->loaded) {
return false;
}
- if (user::active()->admin) {
+ if ($user->admin) {
return true;
}
$resource = $perm_name == "view" ?
$item : model_cache::get("access_cache", $item->id, "item_id");
- foreach (user::group_ids() as $id) {
- if ($resource->__get("{$perm_name}_$id") === self::ALLOW) {
+ foreach ($user->groups as $group) {
+ if ($resource->__get("{$perm_name}_{$group->id}") === self::ALLOW) {
return true;
}
}
@@ -129,7 +142,7 @@ class access_Core {
* @param Group_Model $group
* @param string $perm_name
* @param Item_Model $item
- * @return integer access::ALLOW, access::DENY or null for no intent
+ * @return boolean access::ALLOW, access::DENY or access::INHERIT (null) for no intent
*/
static function group_intent($group, $perm_name, $item) {
$intent = model_cache::get("access_intent", $item->id, "item_id");
@@ -153,11 +166,11 @@ class access_Core {
// For view permissions, if any parent is self::DENY, then those parents lock this one.
// Return
$lock = ORM::factory("item")
- ->where("`left` <= $item->left")
- ->where("`right` >= $item->right")
+ ->where("`left_ptr` <= $item->left_ptr")
+ ->where("`right_ptr` >= $item->right_ptr")
->where("items.id <> $item->id")
->join("access_intents", "items.id", "access_intents.item_id")
- ->where("access_intents.view_$group->id", 0)
+ ->where("access_intents.view_$group->id", self::DENY)
->orderby("level", "DESC")
->limit(1)
->find();
@@ -205,6 +218,7 @@ class access_Core {
}
self::_update_htaccess_files($album, $group, $perm_name, $value);
+ model_cache::clear();
}
/**
@@ -240,7 +254,23 @@ class access_Core {
if ($item->id == 1) {
throw new Exception("@todo CANT_RESET_ROOT_PERMISSION");
}
- self::_set($group, $perm_name, $item, null);
+ self::_set($group, $perm_name, $item, self::INHERIT);
+ }
+
+ /**
+ * Recalculate the permissions for a given item and its hierarchy. $item must be an album.
+ */
+ static function recalculate_permissions($item) {
+ foreach (self::_get_all_groups() as $group) {
+ foreach (ORM::factory("permission")->find_all() as $perm) {
+ if ($perm->name == "view") {
+ self::_update_access_view_cache($group, $item);
+ } else {
+ self::_update_access_non_view_cache($group, $perm->name, $item);
+ }
+ }
+ }
+ model_cache::clear();
}
/**
@@ -411,6 +441,7 @@ class access_Core {
$cache_table = $perm_name == "view" ? "items" : "access_caches";
$db->query("ALTER TABLE {{$cache_table}} DROP `$field`");
$db->query("ALTER TABLE {access_intents} DROP `$field`");
+ model_cache::clear();
ORM::factory("access_intent")->clear_cache();
}
@@ -425,9 +456,11 @@ class access_Core {
$db = Database::instance();
$field = "{$perm_name}_{$group->id}";
$cache_table = $perm_name == "view" ? "items" : "access_caches";
- $db->query("ALTER TABLE {{$cache_table}} ADD `$field` SMALLINT NOT NULL DEFAULT 0");
- $db->query("ALTER TABLE {access_intents} ADD `$field` BOOLEAN DEFAULT NULL");
- $db->update("access_intents", array($field => 0), array("item_id" => 1));
+ $not_null = $cache_table == "items" ? "" : "NOT NULL";
+ $db->query("ALTER TABLE {{$cache_table}} ADD `$field` BINARY $not_null DEFAULT FALSE");
+ $db->query("ALTER TABLE {access_intents} ADD `$field` BINARY DEFAULT NULL");
+ $db->update("access_intents", array($field => self::DENY), array("item_id" => 1));
+ model_cache::clear();
ORM::factory("access_intent")->clear_cache();
}
@@ -457,11 +490,11 @@ class access_Core {
// item, then its safe to propagate from here.
if ($access->$field !== self::DENY) {
$tmp_item = ORM::factory("item")
- ->where("left <", $item->left)
- ->where("right >", $item->right)
+ ->where("left_ptr <", $item->left_ptr)
+ ->where("right_ptr >", $item->right_ptr)
->join("access_intents", "access_intents.item_id", "items.id")
->where("access_intents.$field", self::DENY)
- ->orderby("left", "DESC")
+ ->orderby("left_ptr", "DESC")
->limit(1)
->find();
if ($tmp_item->loaded) {
@@ -474,26 +507,26 @@ class access_Core {
// them according the rule above. So mark every permission below this level as UNKNOWN so
// that we can tell which permissions have been changed, and which ones need to be updated.
$db->update("items", array($field => self::UNKNOWN),
- array("left >=" => $item->left, "right <=" => $item->right));
+ array("left_ptr >=" => $item->left_ptr, "right_ptr <=" => $item->right_ptr));
$query = ORM::factory("access_intent")
- ->select(array("access_intents.$field", "items.left", "items.right", "items.id"))
+ ->select(array("access_intents.$field", "items.left_ptr", "items.right_ptr", "items.id"))
->join("items", "items.id", "access_intents.item_id")
- ->where("left >=", $item->left)
- ->where("right <=", $item->right)
+ ->where("left_ptr >=", $item->left_ptr)
+ ->where("right_ptr <=", $item->right_ptr)
->where("type", "album")
- ->where("access_intents.$field IS NOT", null)
+ ->where("access_intents.$field IS NOT", self::INHERIT)
->orderby("level", "DESC")
->find_all();
foreach ($query as $row) {
if ($row->$field == self::ALLOW) {
// Propagate ALLOW for any row that is still UNKNOWN.
$db->update("items", array($field => $row->$field),
- array($field => self::UNKNOWN, "left >=" => $row->left, "right <=" => $row->right));
+ array($field => self::UNKNOWN, "left_ptr >=" => $row->left_ptr, "right_ptr <=" => $row->right_ptr));
} else if ($row->$field == self::DENY) {
// DENY overwrites everything below it
$db->update("items", array($field => $row->$field),
- array("left >=" => $row->left, "right <=" => $row->right));
+ array("left_ptr >=" => $row->left_ptr, "right_ptr <=" => $row->right_ptr));
}
}
@@ -501,7 +534,7 @@ class access_Core {
// DENY parent in the hierarchy to propagate from. So we'll still have a UNKNOWN values in
// the hierarchy, and all of those are safe to change to ALLOW.
$db->update("items", array($field => self::ALLOW),
- array($field => self::UNKNOWN, "left >=" => $item->left, "right <=" => $item->right));
+ array($field => self::UNKNOWN, "left_ptr >=" => $item->left_ptr, "right_ptr <=" => $item->right_ptr));
}
/**
@@ -526,13 +559,13 @@ class access_Core {
//
// @todo To optimize this, we wouldn't need to propagate from the parent, we could just
// propagate from here with the parent's intent.
- if ($access->$field === null) {
+ if ($access->$field === self::INHERIT) {
$tmp_item = ORM::factory("item")
->join("access_intents", "items.id", "access_intents.item_id")
- ->where("left <", $item->left)
- ->where("right >", $item->right)
- ->where("$field IS NOT", null)
- ->orderby("left", "DESC")
+ ->where("left_ptr <", $item->left_ptr)
+ ->where("right_ptr >", $item->right_ptr)
+ ->where("$field IS NOT", self::UNKNOWN)
+ ->orderby("left_ptr", "DESC")
->limit(1)
->find();
if ($tmp_item->loaded) {
@@ -543,20 +576,21 @@ class access_Core {
// With non-view permissions, each level can override any permissions that came above it
// so start at the top and work downwards, overlaying permissions as we go.
$query = ORM::factory("access_intent")
- ->select(array("access_intents.$field", "items.left", "items.right"))
+ ->select(array("access_intents.$field", "items.left_ptr", "items.right_ptr"))
->join("items", "items.id", "access_intents.item_id")
- ->where("left >=", $item->left)
- ->where("right <=", $item->right)
- ->where("$field IS NOT", null)
+ ->where("left_ptr >=", $item->left_ptr)
+ ->where("right_ptr <=", $item->right_ptr)
+ ->where("$field IS NOT", self::INHERIT)
->orderby("level", "ASC")
->find_all();
foreach ($query as $row) {
+ $value = ($row->$field === self::ALLOW) ? "TRUE" : "FALSE";
$db->query(
- "UPDATE {access_caches} SET `$field` = {$row->$field} " .
+ "UPDATE {access_caches} SET `$field` = $value " .
"WHERE `item_id` IN " .
" (SELECT `id` FROM {items} " .
- " WHERE `left` >= $row->left " .
- " AND `right` <= $row->right)");
+ " WHERE `left_ptr` >= $row->left_ptr " .
+ " AND `right_ptr` <= $row->right_ptr)");
}
}
diff --git a/modules/gallery/helpers/album.php b/modules/gallery/helpers/album.php
index 1197f243..dfb1e66d 100644
--- a/modules/gallery/helpers/album.php
+++ b/modules/gallery/helpers/album.php
@@ -30,9 +30,10 @@ class album_Core {
* @param string $name the name of this new album (it will become the directory name on disk)
* @param integer $title the title of the new album
* @param string $description (optional) the longer description of this album
+ * @param string $slug (optional) the url component for this photo
* @return Item_Model
*/
- static function create($parent, $name, $title, $description=null, $owner_id=null) {
+ static function create($parent, $name, $title, $description=null, $owner_id=null, $slug=null) {
if (!$parent->loaded || !$parent->is_album()) {
throw new Exception("@todo INVALID_PARENT");
}
@@ -47,6 +48,10 @@ class album_Core {
throw new Exception("@todo NAME_CANNOT_END_IN_PERIOD");
}
+ if (empty($slug)) {
+ $slug = item::convert_filename_to_slug($name);
+ }
+
$album = ORM::factory("item");
$album->type = "album";
$album->title = $title;
@@ -55,15 +60,23 @@ class album_Core {
$album->owner_id = $owner_id;
$album->thumb_dirty = 1;
$album->resize_dirty = 1;
+ $album->slug = $slug;
$album->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
- $album->sort_column = "weight";
+ $album->sort_column = "created";
$album->sort_order = "ASC";
+ // Randomize the name or slug if there's a conflict
+ // @todo Improve this. Random numbers are not user friendly
while (ORM::factory("item")
->where("parent_id", $parent->id)
+ ->open_paren()
->where("name", $album->name)
+ ->orwhere("slug", $album->slug)
+ ->close_paren()
->find()->id) {
- $album->name = "{$name}-" . rand();
+ $rand = rand();
+ $album->name = "{$name}-$rand";
+ $album->slug = "{$slug}-$rand";
}
$album = $album->add_to_parent($parent);
@@ -71,6 +84,8 @@ class album_Core {
mkdir(dirname($album->thumb_path()));
mkdir(dirname($album->resize_path()));
+ // @todo: publish this from inside Item_Model::save() when we refactor to the point where
+ // there's only one save() happening here.
module::event("item_created", $album);
return $album;
@@ -82,28 +97,44 @@ class album_Core {
->label(t("Add an album to %album_title", array("album_title" => $parent->title)));
$group->input("title")->label(t("Title"));
$group->textarea("description")->label(t("Description"));
- $group->input("name")->label(t("Directory Name"))
+ $group->input("name")->label(t("Directory name"))
->callback("item::validate_no_slashes")
->error_messages("no_slashes", t("The directory name can't contain the \"/\" character"));
+ $group->input("slug")->label(t("Internet Address"))
+ ->callback("item::validate_url_safe")
+ ->error_messages(
+ "not_url_safe",
+ t("The internet address should contain only letters, numbers, hyphens and underscores"));
$group->hidden("type")->value("album");
$group->submit("")->value(t("Create"));
$form->add_rules_from(ORM::factory("item"));
+ $form->script("")
+ ->url(url::abs_file("modules/gallery/js/albums_form_add.js"));
return $form;
}
static function get_edit_form($parent) {
$form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gEditAlbumForm"));
$form->hidden("_method")->value("put");
- $group = $form->group("edit_album")->label(t("Edit Album"));
+ $group = $form->group("edit_item")->label(t("Edit Album"));
$group->input("title")->label(t("Title"))->value($parent->title);
$group->textarea("description")->label(t("Description"))->value($parent->description);
if ($parent->id != 1) {
$group->input("dirname")->label(t("Directory Name"))->value($parent->name)
+ ->rules("required")
+ ->error_messages("name_conflict", t("There is already a photo or album with this name"))
->callback("item::validate_no_slashes")
->error_messages("no_slashes", t("The directory name can't contain a \"/\""))
->callback("item::validate_no_trailing_period")
->error_messages("no_trailing_period", t("The directory name can't end in \".\""));
+ $group->input("slug")->label(t("Internet Address"))->value($parent->slug)
+ ->error_messages(
+ "slug_conflict", t("There is already a photo or album with this internet address"))
+ ->callback("item::validate_url_safe")
+ ->error_messages(
+ "not_url_safe",
+ t("The internet address should contain only letters, numbers, hyphens and underscores"));
}
$sort_order = $group->group("sort_order", array("id" => "gAlbumSortOrder"))
@@ -111,22 +142,33 @@ class album_Core {
$sort_order->dropdown("column", array("id" => "gAlbumSortColumn"))
->label(t("Sort by"))
- ->options(array("weight" => t("Order Added"),
- "captured" => t("Capture Date"),
- "created" => t("Creation Date"),
- "title" => t("Title"),
- "updated" => t("Updated Date"),
- "view_count" => t("Number of views"),
- "rand_key" => t("Random")))
+ ->options(album::get_sort_order_options())
->selected($parent->sort_column);
$sort_order->dropdown("direction", array("id" => "gAlbumSortDirection"))
->label(t("Order"))
->options(array("ASC" => t("Ascending"),
"DESC" => t("Descending")))
->selected($parent->sort_order);
+
+ module::event("item_edit_form", $parent, $form);
+
+ $group = $form->group("buttons")->label("");
$group->hidden("type")->value("album");
$group->submit("")->value(t("Modify"));
$form->add_rules_from(ORM::factory("item"));
return $form;
}
+
+ /**
+ * Return a structured set of all the possible sort orders.
+ */
+ static function get_sort_order_options() {
+ return array("weight" => t("Manual"),
+ "captured" => t("Date captured"),
+ "created" => t("Date uploaded"),
+ "title" => t("Title"),
+ "updated" => t("Date modified"),
+ "view_count" => t("Number of views"),
+ "rand_key" => t("Random"));
+ }
}
diff --git a/modules/gallery/helpers/gallery.php b/modules/gallery/helpers/gallery.php
index a32ac484..813134eb 100644
--- a/modules/gallery/helpers/gallery.php
+++ b/modules/gallery/helpers/gallery.php
@@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
class gallery_Core {
- const VERSION = "3.0 beta 2";
+ const VERSION = "3.0 git (pre-beta3)";
/**
* If Gallery is in maintenance mode, then force all non-admins to get routed to a "This site is
@@ -78,4 +78,232 @@ class gallery_Core {
static function time($timestamp) {
return date(module::get_var("gallery", "time_format", "H:i:s"), $timestamp);
}
+
+ static function site_menu($menu, $theme) {
+ if ($theme->page_type != "login") {
+ $menu->append(Menu::factory("link")
+ ->id("home")
+ ->label(t("Home"))
+ ->url(item::root()->url()));
+
+ $item = $theme->item();
+
+ $can_edit = $item && access::can("edit", $item);
+ $can_add = $item && access::can("add", $item);
+
+ if ($can_add) {
+ $menu->append($add_menu = Menu::factory("submenu")
+ ->id("add_menu")
+ ->label(t("Add")));
+ $add_menu->append(Menu::factory("dialog")
+ ->id("add_photos_item")
+ ->label(t("Add photos"))
+ ->url(url::site("simple_uploader/app/$item->id")));
+ if ($item->is_album()) {
+ $add_menu->append(Menu::factory("dialog")
+ ->id("add_album_item")
+ ->label(t("Add an album"))
+ ->url(url::site("form/add/albums/$item->id?type=album")));
+ }
+ }
+
+ $menu->append($options_menu = Menu::factory("submenu")
+ ->id("options_menu")
+ ->label(t("Photo options")));
+ if ($item && ($can_edit || $can_add)) {
+ if ($can_edit) {
+ $options_menu->append(Menu::factory("dialog")
+ ->id("edit_item")
+ ->label($item->is_album() ? t("Edit album") : t("Edit photo"))
+ ->url(url::site("form/edit/{$item->type}s/$item->id")));
+ }
+
+ if ($item->is_album()) {
+ $options_menu->label(t("Album options"));
+ if ($can_edit) {
+ $options_menu->append(Menu::factory("dialog")
+ ->id("edit_permissions")
+ ->label(t("Edit permissions"))
+ ->url(url::site("permissions/browse/$item->id")));
+ }
+ }
+ }
+
+ if (user::active()->admin) {
+ $menu->append($admin_menu = Menu::factory("submenu")
+ ->id("admin_menu")
+ ->label(t("Admin")));
+ gallery::admin_menu($admin_menu, $theme);
+ module::event("admin_menu", $admin_menu, $theme);
+ }
+
+ module::event("site_menu", $menu, $theme);
+ }
+ }
+
+ static function admin_menu($menu, $theme) {
+ $menu
+ ->append(Menu::factory("link")
+ ->id("dashboard")
+ ->label(t("Dashboard"))
+ ->url(url::site("admin")))
+ ->append(Menu::factory("submenu")
+ ->id("settings_menu")
+ ->label(t("Settings"))
+ ->append(Menu::factory("link")
+ ->id("graphics_toolkits")
+ ->label(t("Graphics"))
+ ->url(url::site("admin/graphics")))
+ ->append(Menu::factory("link")
+ ->id("languages")
+ ->label(t("Languages"))
+ ->url(url::site("admin/languages")))
+ ->append(Menu::factory("link")
+ ->id("advanced")
+ ->label(t("Advanced"))
+ ->url(url::site("admin/advanced_settings"))))
+ ->append(Menu::factory("link")
+ ->id("modules")
+ ->label(t("Modules"))
+ ->url(url::site("admin/modules")))
+ ->append(Menu::factory("submenu")
+ ->id("content_menu")
+ ->label(t("Content")))
+ ->append(Menu::factory("submenu")
+ ->id("appearance_menu")
+ ->label(t("Appearance"))
+ ->append(Menu::factory("link")
+ ->id("themes")
+ ->label(t("Theme Choice"))
+ ->url(url::site("admin/themes")))
+ ->append(Menu::factory("link")
+ ->id("theme_options")
+ ->label(t("Theme Options"))
+ ->url(url::site("admin/theme_options"))))
+ ->append(Menu::factory("submenu")
+ ->id("statistics_menu")
+ ->label(t("Statistics")))
+ ->append(Menu::factory("link")
+ ->id("maintenance")
+ ->label(t("Maintenance"))
+ ->url(url::site("admin/maintenance")));
+ return $menu;
+ }
+
+ static function context_menu($menu, $theme, $item, $thumb_css_selector) {
+ $menu->append($options_menu = Menu::factory("submenu")
+ ->id("options_menu")
+ ->label(t("Options"))
+ ->css_class("ui-icon-carat-1-n"));
+
+ if (access::can("edit", $item)) {
+ $page_type = $theme->page_type();
+ switch ($item->type) {
+ case "movie":
+ $edit_title = t("Edit this movie");
+ $delete_title = t("Delete this movie");
+ break;
+
+ case "album":
+ $edit_title = t("Edit this album");
+ $delete_title = t("Delete this album");
+ break;
+
+ default:
+ $edit_title = t("Edit this photo");
+ $delete_title = t("Delete this photo");
+ break;
+ }
+ $cover_title = t("Choose as the album cover");
+ $move_title = t("Move to another album");
+
+ $csrf = access::csrf_token();
+
+ $options_menu->append(Menu::factory("dialog")
+ ->id("edit")
+ ->label($edit_title)
+ ->css_class("ui-icon-pencil")
+ ->url(url::site("quick/form_edit/$item->id?page_type=$page_type")));
+
+
+ if ($item->is_photo() && graphics::can("rotate")) {
+ $options_menu
+ ->append(
+ Menu::factory("ajax_link")
+ ->id("rotate_ccw")
+ ->label(t("Rotate 90&deg; counter clockwise"))
+ ->css_class("ui-icon-rotate-ccw")
+ ->ajax_handler("function(data) { " .
+ "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }")
+ ->url(url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type")))
+ ->append(
+ Menu::factory("ajax_link")
+ ->id("rotate_cw")
+ ->label(t("Rotate 90&deg; clockwise"))
+ ->css_class("ui-icon-rotate-cw")
+ ->ajax_handler("function(data) { " .
+ "\$.gallery_replace_image(data, \$('$thumb_css_selector')) }")
+ ->url(url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type")));
+ }
+
+ // Don't move photos from the photo page; we don't yet have a good way of redirecting after
+ // move
+ if ($page_type == "album") {
+ $options_menu
+ ->append(Menu::factory("dialog")
+ ->id("move")
+ ->label($move_title)
+ ->css_class("ui-icon-folder-open")
+ ->url(url::site("move/browse/$item->id")));
+ }
+
+ $parent = $item->parent();
+ if (access::can("edit", $parent)) {
+ // We can't make this item the highlight if it's an album with no album cover, or if it's
+ // already the album cover.
+ if (($item->type == "album" && empty($item->album_cover_item_id)) ||
+ ($item->type == "album" && $parent->album_cover_item_id == $item->album_cover_item_id) ||
+ $parent->album_cover_item_id == $item->id) {
+ $disabledState = " ui-state-disabled";
+ } else {
+ $disabledState = " ";
+ }
+ if ($item->parent()->id != 1) {
+ $options_menu
+ ->append(Menu::factory("ajax_link")
+ ->id("make_album_cover")
+ ->label($cover_title)
+ ->css_class("ui-icon-star")
+ ->ajax_handler("function(data) { window.location.reload() }")
+ ->url(url::site("quick/make_album_cover/$item->id?csrf=$csrf")));
+ }
+ $options_menu
+ ->append(Menu::factory("dialog")
+ ->id("delete")
+ ->label($delete_title)
+ ->css_class("ui-icon-trash")
+ ->css_id("gQuickDelete")
+ ->url(url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type")));
+ }
+
+ if ($item->is_album()) {
+ $options_menu
+ ->append(Menu::factory("dialog")
+ ->id("add_item")
+ ->label(t("Add a photo"))
+ ->css_class("ui-icon-plus")
+ ->url(url::site("simple_uploader/app/$item->id")))
+ ->append(Menu::factory("dialog")
+ ->id("add_album")
+ ->label(t("Add an album"))
+ ->css_class("ui-icon-note")
+ ->url(url::site("form/add/albums/$item->id?type=album")))
+ ->append(Menu::factory("dialog")
+ ->id("edit_permissions")
+ ->label(t("Edit permissions"))
+ ->css_class("ui-icon-key")
+ ->url(url::site("permissions/browse/$item->id")));
+ }
+ }
+ }
} \ No newline at end of file
diff --git a/modules/gallery/helpers/gallery_event.php b/modules/gallery/helpers/gallery_event.php
index aa11b7c0..64f2a9ff 100644
--- a/modules/gallery/helpers/gallery_event.php
+++ b/modules/gallery/helpers/gallery_event.php
@@ -23,7 +23,7 @@ class gallery_event_Core {
access::add_group($group);
}
- static function group_before_delete($group) {
+ static function group_deleted($group) {
access::delete_group($group);
}
@@ -31,10 +31,14 @@ class gallery_event_Core {
access::add_item($item);
}
- static function item_before_delete($item) {
+ static function item_deleted($item) {
access::delete_item($item);
}
+ static function item_moved($item, $old_parent) {
+ access::recalculate_permissions($item->parent());
+ }
+
static function user_login($user) {
// If this user is an admin, check to see if there are any post-install tasks that we need
// to run and take care of those now.
@@ -43,4 +47,10 @@ class gallery_event_Core {
module::clear_var("gallery", "choose_default_tookit");
}
}
+
+ static function item_index_data($item, $data) {
+ $data[] = $item->description;
+ $data[] = $item->name;
+ $data[] = $item->title;
+ }
}
diff --git a/modules/gallery/helpers/gallery_installer.php b/modules/gallery/helpers/gallery_installer.php
index 28c1990f..a1856424 100644
--- a/modules/gallery/helpers/gallery_installer.php
+++ b/modules/gallery/helpers/gallery_installer.php
@@ -24,13 +24,13 @@ class gallery_installer {
`id` int(9) NOT NULL auto_increment,
`item_id` int(9),
PRIMARY KEY (`id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {access_intents} (
`id` int(9) NOT NULL auto_increment,
`item_id` int(9),
PRIMARY KEY (`id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {caches} (
`id` int(9) NOT NULL auto_increment,
@@ -40,7 +40,7 @@ class gallery_installer {
`cache` longblob,
PRIMARY KEY (`id`),
KEY (`tags`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {graphics_rules} (
`id` int(9) NOT NULL auto_increment,
@@ -51,7 +51,7 @@ class gallery_installer {
`priority` int(9) NOT NULL,
`target` varchar(32) NOT NULL,
PRIMARY KEY (`id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {incoming_translations} (
`id` int(9) NOT NULL auto_increment,
@@ -63,7 +63,7 @@ class gallery_installer {
PRIMARY KEY (`id`),
UNIQUE KEY(`key`, `locale`),
KEY `locale_key` (`locale`, `key`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {items} (
`id` int(9) NOT NULL auto_increment,
@@ -72,7 +72,7 @@ class gallery_installer {
`created` int(9) default NULL,
`description` varchar(2048) default NULL,
`height` int(9) default NULL,
- `left` int(9) NOT NULL,
+ `left_ptr` int(9) NOT NULL,
`level` int(9) NOT NULL,
`mime_type` varchar(64) default NULL,
`name` varchar(255) default NULL,
@@ -80,10 +80,12 @@ class gallery_installer {
`parent_id` int(9) NOT NULL,
`rand_key` float default NULL,
`relative_path_cache` varchar(255) default NULL,
+ `relative_url_cache` varchar(255) default NULL,
`resize_dirty` boolean default 1,
`resize_height` int(9) default NULL,
`resize_width` int(9) default NULL,
- `right` int(9) NOT NULL,
+ `right_ptr` int(9) NOT NULL,
+ `slug` varchar(255) default NULL,
`sort_column` varchar(64) default NULL,
`sort_order` char(4) default 'ASC',
`thumb_dirty` boolean default 1,
@@ -98,8 +100,9 @@ class gallery_installer {
PRIMARY KEY (`id`),
KEY `parent_id` (`parent_id`),
KEY `type` (`type`),
- KEY `random` (`rand_key`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ KEY `random` (`rand_key`),
+ KEY `weight` (`weight` DESC))
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {logs} (
`id` int(9) NOT NULL auto_increment,
@@ -112,7 +115,7 @@ class gallery_installer {
`url` varchar(255) default NULL,
`user_id` int(9) default 0,
PRIMARY KEY (`id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {messages} (
`id` int(9) NOT NULL auto_increment,
@@ -121,7 +124,7 @@ class gallery_installer {
`value` varchar(255) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY(`key`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {modules} (
`id` int(9) NOT NULL auto_increment,
@@ -130,7 +133,7 @@ class gallery_installer {
`version` int(9) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY(`name`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {outgoing_translations} (
`id` int(9) NOT NULL auto_increment,
@@ -142,7 +145,7 @@ class gallery_installer {
PRIMARY KEY (`id`),
UNIQUE KEY(`key`, `locale`),
KEY `locale_key` (`locale`, `key`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {permissions} (
`id` int(9) NOT NULL auto_increment,
@@ -150,14 +153,14 @@ class gallery_installer {
`name` varchar(64) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY(`name`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {sessions} (
`session_id` varchar(127) NOT NULL,
`data` text NOT NULL,
`last_activity` int(10) UNSIGNED NOT NULL,
PRIMARY KEY (`session_id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {tasks} (
`id` int(9) NOT NULL auto_increment,
@@ -172,7 +175,7 @@ class gallery_installer {
`updated` int(9) default NULL,
PRIMARY KEY (`id`),
KEY (`owner_id`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {themes} (
`id` int(9) NOT NULL auto_increment,
@@ -180,7 +183,7 @@ class gallery_installer {
`version` int(9) default NULL,
PRIMARY KEY (`id`),
UNIQUE KEY(`name`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
$db->query("CREATE TABLE {vars} (
`id` int(9) NOT NULL auto_increment,
@@ -189,7 +192,7 @@ class gallery_installer {
`value` text,
PRIMARY KEY (`id`),
UNIQUE KEY(`module_name`, `name`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
foreach (array("albums", "logs", "modules", "resizes", "thumbs", "tmp", "uploads") as $dir) {
@mkdir(VARPATH . $dir);
@@ -204,8 +207,8 @@ class gallery_installer {
$root->type = "album";
$root->title = "Gallery";
$root->description = "";
- $root->left = 1;
- $root->right = 2;
+ $root->left_ptr = 1;
+ $root->right_ptr = 2;
$root->parent_id = 0;
$root->level = 1;
$root->thumb_dirty = 1;
@@ -222,6 +225,7 @@ class gallery_installer {
module::set_var("gallery", "resize_size", 640);
module::set_var("gallery", "default_locale", "en_US");
module::set_var("gallery", "image_quality", 75);
+ module::set_var("gallery", "image_sharpen", 15);
// Add rules for generating our thumbnails and resizes
graphics::add_rule(
@@ -258,7 +262,7 @@ class gallery_installer {
module::set_var("gallery", "show_credits", 1);
// @todo this string needs to be picked up by l10n_scanner
module::set_var("gallery", "credits", "Powered by <a href=\"%url\">Gallery %version</a>");
- module::set_version("gallery", 7);
+ module::set_version("gallery", 12);
}
static function upgrade($version) {
@@ -283,7 +287,7 @@ class gallery_installer {
`cache` text,
PRIMARY KEY (`id`),
KEY (`tags`))
- ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ DEFAULT CHARSET=utf8;");
module::set_version("gallery", $version = 4);
}
@@ -305,6 +309,55 @@ class gallery_installer {
module::clear_var("gallery", "version");
module::set_version("gallery", $version = 7);
}
+
+ if ($version == 7) {
+ $groups = ORM::factory("group")->find_all();
+ $permissions = ORM::factory("permission")->find_all();
+ foreach($groups as $group) {
+ foreach($permissions as $permission) {
+ // Update access intents
+ $db->query("ALTER TABLE {access_intents} MODIFY COLUMN {$permission->name}_{$group->id} BINARY(1) DEFAULT NULL");
+ // Update access cache
+ if ($permission->name === "view") {
+ $db->query("ALTER TABLE {items} MODIFY COLUMN {$permission->name}_{$group->id} BINARY(1) DEFAULT FALSE");
+ } else {
+ $db->query("ALTER TABLE {access_caches} MODIFY COLUMN {$permission->name}_{$group->id} BINARY(1) NOT NULL DEFAULT FALSE");
+ }
+ }
+ }
+ module::set_version("gallery", $version = 8);
+ }
+
+ if ($version == 8) {
+ $db->query("ALTER TABLE {items} CHANGE COLUMN `left` `left_ptr` INT(9) NOT NULL;");
+ $db->query("ALTER TABLE {items} CHANGE COLUMN `right` `right_ptr` INT(9) NOT NULL;");
+ module::set_version("gallery", $version = 9);
+ }
+
+ if ($version == 9) {
+ $db->query("ALTER TABLE {items} ADD KEY `weight` (`weight` DESC);");
+
+ module::set_version("gallery", $version = 10);
+ }
+
+ if ($version == 10) {
+ module::set_var("gallery", "image_sharpen", 15);
+
+ module::set_version("gallery", $version = 11);
+ }
+
+ if ($version == 11) {
+ $db->query("ALTER TABLE {items} ADD COLUMN `relative_url_cache` varchar(255) DEFAULT NULL");
+ $db->query("ALTER TABLE {items} ADD COLUMN `slug` varchar(255) DEFAULT NULL");
+
+ // This is imperfect since some of the slugs may contain invalid characters, but it'll do
+ // for now because we don't want a lengthy operation here.
+ $db->query("UPDATE {items} SET `slug` = `name`");
+
+ // Flush all path caches becuase we're going to start urlencoding them.
+ $db->query("UPDATE {items} SET `relative_url_cache` = NULL, `relative_path_cache` = NULL");
+ module::set_version("gallery", $version = 12);
+ }
}
static function uninstall() {
diff --git a/modules/gallery/helpers/gallery_menu.php b/modules/gallery/helpers/gallery_menu.php
deleted file mode 100644
index b6f763b8..00000000
--- a/modules/gallery/helpers/gallery_menu.php
+++ /dev/null
@@ -1,167 +0,0 @@
-<?php defined("SYSPATH") or die("No direct script access.");
-/**
- * Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2009 Bharat Mediratta
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-class gallery_menu_Core {
- static function site($menu, $theme) {
- $is_admin = user::active()->admin;
-
- $menu->append(Menu::factory("link")
- ->id("home")
- ->label(t("Home"))
- ->url(url::site("albums/1")));
-
- $item = $theme->item();
-
- $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")
- ->label(t("Options")));
-
- if ($can_edit) {
- $options_menu
- ->append(Menu::factory("dialog")
- ->id("edit_item")
- ->label($item->is_album() ? t("Edit album") : t("Edit photo"))
- ->url(url::site("form/edit/{$item->type}s/$item->id")));
- }
-
- // @todo Move album options menu to the album quick edit pane
- if ($item->is_album()) {
- if ($can_add) {
- $options_menu
- ->append(Menu::factory("dialog")
- ->id("add_album")
- ->label(t("Add an album"))
- ->url(url::site("form/add/albums/$item->id?type=album")));
- }
-
- if ($can_edit) {
- $options_menu
- ->append(Menu::factory("dialog")
- ->id("edit_permissions")
- ->label(t("Edit permissions"))
- ->url(url::site("permissions/browse/$item->id")));
- }
- }
- }
-
- if ($is_admin) {
- $menu->append($admin_menu = Menu::factory("submenu")
- ->id("admin_menu")
- ->label(t("Admin")));
- self::admin($admin_menu, $theme);
- foreach (module::active() as $module) {
- if ($module->name == "gallery") {
- continue;
- }
- $class = "{$module->name}_menu";
- if (method_exists($class, "admin")) {
- call_user_func_array(array($class, "admin"), array(&$admin_menu, $theme));
- }
- }
- }
- }
-
- static function album($menu, $theme) {
- }
-
- static function tag($menu, $theme) {
- }
-
- static function thumb($menu, $theme, $item) {
- $menu->append(Menu::factory("submenu")
- ->id("options_menu")
- ->label(t("Options"))
- ->css_class("gThumbMenu"));
- }
-
- static function photo($menu, $theme) {
- if (access::can("view_full", $theme->item())) {
- $menu->append(Menu::factory("link")
- ->id("fullsize")
- ->label(t("View full size"))
- ->url($theme->item()->file_url())
- ->css_class("gFullSizeLink"));
- }
- }
-
- static function admin($menu, $theme) {
- $menu
- ->append(Menu::factory("link")
- ->id("dashboard")
- ->label(t("Dashboard"))
- ->url(url::site("admin")))
- ->append(Menu::factory("submenu")
- ->id("settings_menu")
- ->label(t("Settings"))
- ->append(Menu::factory("link")
- ->id("graphics_toolkits")
- ->label(t("Graphics"))
- ->url(url::site("admin/graphics")))
- ->append(Menu::factory("link")
- ->id("languages")
- ->label(t("Languages"))
- ->url(url::site("admin/languages")))
- ->append(Menu::factory("link")
- ->id("l10n_mode")
- ->label(Session::instance()->get("l10n_mode", false)
- ? t("Stop translating") : t("Start translating"))
- ->url(url::site("l10n_client/toggle_l10n_mode?csrf=" .
- access::csrf_token())))
- ->append(Menu::factory("link")
- ->id("advanced")
- ->label(t("Advanced"))
- ->url(url::site("admin/advanced_settings"))))
- ->append(Menu::factory("link")
- ->id("modules")
- ->label(t("Modules"))
- ->url(url::site("admin/modules")))
- ->append(Menu::factory("submenu")
- ->id("content_menu")
- ->label(t("Content")))
- ->append(Menu::factory("submenu")
- ->id("appearance_menu")
- ->label(t("Appearance"))
- ->append(Menu::factory("link")
- ->id("themes")
- ->label(t("Theme Choice"))
- ->url(url::site("admin/themes")))
- ->append(Menu::factory("link")
- ->id("theme_options")
- ->label(t("Theme Options"))
- ->url(url::site("admin/theme_options"))))
- ->append(Menu::factory("submenu")
- ->id("statistics_menu")
- ->label(t("Statistics")))
- ->append(Menu::factory("link")
- ->id("maintenance")
- ->label(t("Maintenance"))
- ->url(url::site("admin/maintenance")));
- }
-}
diff --git a/modules/gallery/helpers/gallery_quick.php b/modules/gallery/helpers/gallery_quick.php
deleted file mode 100644
index d0ffc584..00000000
--- a/modules/gallery/helpers/gallery_quick.php
+++ /dev/null
@@ -1,144 +0,0 @@
-<?php defined("SYSPATH") or die("No direct script access.");
-/**
- * Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2009 Bharat Mediratta
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-class gallery_quick_Core {
- static function get_quick_buttons($item, $page_type) {
- $buttons = self::buttons($item, $page_type);
- foreach (module::active() as $module) {
- if ($module->name == "gallery") {
- continue;
- }
- $class_name = "{$module->name}_quick";
- if (method_exists($class_name, "buttons")) {
- $module_buttons = call_user_func(array($class_name, "buttons"), $item, $page_type);
- foreach (array("left", "center", "right", "additional") as $position) {
- if (!empty($module_buttons[$position])) {
- $buttons[$position] = array_merge($buttons[$position], $module_buttons[$position]);
- }
- }
- }
- }
-
- $sorted_buttons->main = array();
- foreach (array("left", "center", "right") as $position) {
- $sorted_buttons->main = array_merge($sorted_buttons->main, $buttons[$position]);
- }
-
- $sorted_buttons->additional = $buttons["additional"];
- $max_display = empty($sorted_buttons->additional) ? 6 : 5;
- if (count($sorted_buttons->main) >= $max_display) {
- $to_move = array_slice($sorted_buttons->main, 5);
- $sorted_buttons->additional = array_merge($to_move, $sorted_buttons->additional);
- for ($i = count($sorted_buttons->main); $i >= 5; $i--) {
- unset($sorted_buttons->main[$i]);
- }
- }
-
- return $sorted_buttons;
- }
-
- static function buttons($item, $page_type) {
- $elements = array("left" => array(), "center" => array(), "right" => array(),
- "additional" => array());
- switch ($item->type) {
- case "movie":
- $edit_title = t("Edit this movie");
- $move_title = t("Move this movie to another album");
- $cover_title = t("Choose this movie as the album cover");
- $delete_title = t("Delete this movie");
- break;
- case "album":
- $edit_title = t("Edit this album");
- $move_title = t("Move this album to another album");
- $cover_title = t("Choose this album as the album cover");
- $delete_title = t("Delete this album");
- break;
- default:
- $edit_title = t("Edit this photo");
- $move_title = t("Move this photo to another album");
- $cover_title = t("Choose this photo as the album cover");
- $delete_title = t("Delete this photo");
- break;
- }
-
- $csrf = access::csrf_token();
- $elements["left"][] = (object)array(
- "title" => $edit_title,
- "class" => "gDialogLink gButtonLink",
- "icon" => "ui-icon-pencil",
- "href" => url::site("quick/form_edit/$item->id?page_type=$page_type"));
-
- if ($item->is_photo() && graphics::can("rotate")) {
- $elements["left"][] =
- (object)array(
- "title" => t("Rotate 90 degrees counter clockwise"),
- "class" => "gButtonLink",
- "icon" => "ui-icon-rotate-ccw",
- "href" => url::site("quick/rotate/$item->id/ccw?csrf=$csrf&page_type=$page_type"));
- $elements["left"][] =
- (object)array(
- "title" => t("Rotate 90 degrees clockwise"),
- "class" => "gButtonLink",
- "icon" => "ui-icon-rotate-cw",
- "href" => url::site("quick/rotate/$item->id/cw?csrf=$csrf&page_type=$page_type"));
- }
-
- // Don't move photos from the photo page; we don't yet have a good way of redirecting after move
- if ($page_type == "album") {
- $elements["left"][] = (object)array(
- "title" => $move_title,
- "class" => "gDialogLink gButtonLink",
- "icon" => "ui-icon-folder-open",
- "href" => url::site("move/browse/$item->id"));
- }
-
- if (access::can("edit", $item->parent())) {
- $disabledState =
- $item->type == "album" && empty($item->album_cover_item_id) ? " ui-state-disabled" : "";
- $elements["right"][] = (object)array(
- "title" => $cover_title,
- "class" => "gButtonLink{$disabledState}",
- "icon" => "ui-icon-star",
- "href" => url::site("quick/make_album_cover/$item->id?csrf=$csrf&page_type=$page_type"));
-
- $elements["right"][] = (object)array(
- "title" => $delete_title,
- "class" => "gDialogLink gButtonLink",
- "icon" => "ui-icon-trash",
- "id" => "gQuickDelete",
- "href" => url::site("quick/form_delete/$item->id?csrf=$csrf&page_type=$page_type"));
- }
-
- if ($item->is_album()) {
- $elements["additional"][] = (object)array(
- "title" => t("Add a photo"),
- "class" => "add_item gDialogLink",
- "href" => url::site("simple_uploader/app/$item->id"));
- $elements["additional"][] = (object)array(
- "title" => t("Add an album"),
- "class" => "add_album gDialogLink",
- "href" => url::site("form/add/albums/$item->id?type=album"));
- $elements["additional"][] = (object)array(
- "title" => t("Edit permissions"),
- "class" => "permissions gDialogLink",
- "href" => url::site("permissions/browse/$item->id"));
- }
- return $elements;
- }
-}
diff --git a/modules/gallery/helpers/gallery_rss.php b/modules/gallery/helpers/gallery_rss.php
index 7daf6170..feeab88a 100644
--- a/modules/gallery/helpers/gallery_rss.php
+++ b/modules/gallery/helpers/gallery_rss.php
@@ -40,7 +40,6 @@ class gallery_rss_Core {
$feed->max_pages = ceil($all_children->find_all()->count() / $limit);
$feed->title = t("Recent Updates");
- $feed->link = url::abs_site("albums/1");
$feed->description = t("Recent Updates");
return $feed;
@@ -50,11 +49,11 @@ class gallery_rss_Core {
$feed->children = $item
->viewable()
- ->descendants($limit, $offset, "photo");
- $feed->max_pages = ceil($item->viewable()->descendants_count("photo") / $limit);
- $feed->title = p::purify($item->title);
- $feed->link = url::abs_site("albums/{$item->id}");
- $feed->description = nl2br(p::purify($item->description));
+ ->descendants($limit, $offset, array("type" => "photo"));
+ $feed->max_pages = ceil(
+ $item->viewable()->descendants_count(array("type" => "photo")) / $limit);
+ $feed->title = html::purify($item->title);
+ $feed->description = nl2br(html::purify($item->description));
return $feed;
}
diff --git a/modules/gallery/helpers/gallery_search.php b/modules/gallery/helpers/gallery_search.php
deleted file mode 100644
index 2a4029d3..00000000
--- a/modules/gallery/helpers/gallery_search.php
+++ /dev/null
@@ -1,24 +0,0 @@
-<?php defined("SYSPATH") or die("No direct script access.");
-/**
- * Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2009 Bharat Mediratta
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-class gallery_search_Core {
- static function item_index_data($item) {
- return join(" ", array($item->description, $item->name, $item->title));
- }
-}
diff --git a/modules/gallery/helpers/gallery_task.php b/modules/gallery/helpers/gallery_task.php
index 9ce2c4a0..1b56ab97 100644
--- a/modules/gallery/helpers/gallery_task.php
+++ b/modules/gallery/helpers/gallery_task.php
@@ -45,7 +45,7 @@ class gallery_task_Core {
* @param Task_Model the task
*/
static function rebuild_dirty_images($task) {
- $message = array();
+ $errors = array();
try {
$result = graphics::find_dirty_images_query();
$completed = $task->get("completed", 0);
@@ -60,14 +60,15 @@ class gallery_task_Core {
$item = ORM::factory("item", $row->id);
if ($item->loaded) {
- $success = graphics::generate($item);
- if (!$success) {
+ try {
+ graphics::generate($item);
$ignored[$item->id] = 1;
- $message[] = t("Unable to rebuild images for '%title'",
- array("title" => p::purify($item->title)));
- } else {
- $message[] = t("Successfully rebuilt images for '%title'",
- array("title" => p::purify($item->title)));
+ $errors[] = t("Successfully rebuilt images for '%title'",
+ array("title" => html::purify($item->title)));
+ } catch (Exception $e) {
+ $errors[] = t("Unable to rebuild images for '%title'",
+ array("title" => html::purify($item->title)));
+ $errors[] = $e->__toString();
}
}
@@ -101,13 +102,15 @@ class gallery_task_Core {
$task->done = true;
$task->state = "error";
$task->status = $e->getMessage();
- $message[] = $e->__toString();
+ $errors[] = $e->__toString();
+ }
+ if ($errors) {
+ $task->log($errors);
}
- $task->log($message);
}
static function update_l10n(&$task) {
- $message = array();
+ $errors = array();
try {
$start = microtime(true);
$dirs = $task->get("dirs");
@@ -139,8 +142,8 @@ class gallery_task_Core {
}
}
- $message[] = $task->status = t2("Finding files: found 1 file",
- "Finding files: found %count files", count($files));
+ $task->status = t2("Finding files: found 1 file",
+ "Finding files: found %count files", count($files));
if (!$dirs) {
$task->set("mode", "scan_files");
@@ -165,8 +168,8 @@ class gallery_task_Core {
}
$total_files = $task->get("total_files");
- $message[] = $task->status = t2("Scanning files: scanned 1 file",
- "Scanning files: scanned %count files", $total_files - count($files));
+ $task->status = t2("Scanning files: scanned 1 file",
+ "Scanning files: scanned %count files", $total_files - count($files));
$task->percent_complete = 10 + 80 * ($total_files - count($files)) / $total_files;
if (empty($files)) {
@@ -177,7 +180,7 @@ class gallery_task_Core {
break;
case "fetch_updates": // 90% - 100%
- $message = array_merge($message, l10n_client::fetch_updates());
+ l10n_client::fetch_updates();
$task->done = true;
$task->state = "success";
$task->status = t("Translations installed/updated");
@@ -191,8 +194,10 @@ class gallery_task_Core {
$task->done = true;
$task->state = "error";
$task->status = $e->getMessage();
- $message[] = $e->__toString();
+ $errors[] = $e->__toString();
+ }
+ if ($errors) {
+ $task->log($errors);
}
- $task->log($message);
}
} \ No newline at end of file
diff --git a/modules/gallery/helpers/gallery_theme.php b/modules/gallery/helpers/gallery_theme.php
index 226b8a42..20dfeb04 100644
--- a/modules/gallery/helpers/gallery_theme.php
+++ b/modules/gallery/helpers/gallery_theme.php
@@ -22,67 +22,41 @@ class gallery_theme_Core {
$session = Session::instance();
$buf = "";
if ($session->get("debug")) {
- $theme->css("modules/gallery/css/debug.css");
- }
- if (($theme->page_type == "album" || $theme->page_type == "photo")
- && access::can("edit", $theme->item())) {
- $theme->css("modules/gallery/css/quick.css");
- $theme->script("modules/gallery/js/quick.js");
+ $theme->css("debug.css");
}
if (module::is_active("rss")) {
if ($item = $theme->item()) {
- $buf .= rss::feed_link("gallery/album/{$item->id}");
+ if ($item->is_album()) {
+ $buf .= rss::feed_link("gallery/album/{$item->id}");
+ } else {
+ $buf .= rss::feed_link("gallery/album/{$item->parent()->id}");
+ }
} else if ($tag = $theme->tag()) {
$buf .= rss::feed_link("tag/tag/{$tag->id}");
}
}
if ($session->get("l10n_mode", false)) {
- $theme->css("modules/gallery/css/l10n_client.css");
- $theme->script("lib/jquery.cookie.js");
- $theme->script("modules/gallery/js/l10n_client.js");
+ $theme->css("l10n_client.css");
+ $theme->script("jquery.cookie.js");
+ $theme->script("l10n_client.js");
}
return $buf;
}
- static function resize_top($theme, $item) {
- if (access::can("edit", $item)) {
- $edit_link = url::site("quick/pane/$item->id?page_type=photo");
- return "<div class=\"gQuick\" href=\"$edit_link\">";
- }
- }
-
- static function resize_bottom($theme, $item) {
- if (access::can("edit", $item)) {
- return "</div>";
- }
- }
-
- static function thumb_top($theme, $child) {
- if (access::can("edit", $child)) {
- $edit_link = url::site("quick/pane/$child->id?page_type=album");
- return "<div class=\"gQuick\" href=\"$edit_link\">";
- }
- }
-
- static function thumb_bottom($theme, $child) {
- if (access::can("edit", $child)) {
- return "</div>";
- }
- }
-
static function admin_head($theme) {
+ $theme->script("gallery.panel.js");
$session = Session::instance();
if ($session->get("debug")) {
- $theme->css("modules/gallery/css/debug.css");
+ $theme->css("debug.css");
}
if ($session->get("l10n_mode", false)) {
- $theme->css("modules/gallery/css/l10n_client.css");
- $theme->script("lib/jquery.cookie.js");
- $theme->script("modules/gallery/js/l10n_client.js");
+ $theme->css("l10n_client.css");
+ $theme->script("jquery.cookie.js");
+ $theme->script("l10n_client.js");
}
}
@@ -98,7 +72,7 @@ class gallery_theme_Core {
if ($session->get("after_install")) {
$session->delete("after_install");
- return new View("after_install_loader.html");
+ return new View("welcome_message_loader.html");
}
}
@@ -123,4 +97,10 @@ class gallery_theme_Core {
static function admin_credits() {
return gallery_theme::credits();
}
+
+ static function body_attributes() {
+ if (locales::is_rtl()) {
+ return 'class="rtl"';
+ }
+ }
} \ No newline at end of file
diff --git a/modules/gallery/helpers/graphics.php b/modules/gallery/helpers/graphics.php
index db9b2ef5..78812794 100644
--- a/modules/gallery/helpers/graphics.php
+++ b/modules/gallery/helpers/graphics.php
@@ -102,12 +102,12 @@ class graphics_Core {
/**
* Rebuild the thumb and resize for the given item.
* @param Item_Model $item
- * @return true on successful generation
*/
static function generate($item) {
if ($item->is_album()) {
if (!$cover = $item->album_cover()) {
- return false;
+ // This album has no cover; there's nothing to generate.
+ return;
}
$input_file = $cover->file_path();
$input_item = $cover;
@@ -127,7 +127,7 @@ class graphics_Core {
$item->thumb_dirty = 0;
$item->resize_dirty = 0;
$item->save();
- return true;
+ return;
}
try {
@@ -176,10 +176,8 @@ class graphics_Core {
// @todo we should handle this better.
Kohana::log("error", "Caught exception rebuilding image: {$item->title}\n" .
$e->getMessage() . "\n" . $e->getTraceAsString());
- return false;
+ throw $e;
}
-
- return true;
}
/**
@@ -195,6 +193,8 @@ class graphics_Core {
self::init_toolkit();
}
+ module::event("graphics_resize", $input_file, $output_file, $options);
+
if (@filesize($input_file) == 0) {
throw new Exception("@todo EMPTY_INPUT_FILE");
}
@@ -204,11 +204,16 @@ class graphics_Core {
// Image would get upscaled; do nothing
copy($input_file, $output_file);
} else {
- Image::factory($input_file)
+ $image = Image::factory($input_file)
->resize($options["width"], $options["height"], $options["master"])
- ->quality(module::get_var("gallery", "image_quality"))
- ->save($output_file);
+ ->quality(module::get_var("gallery", "image_quality"));
+ if (graphics::can("sharpen")) {
+ $image->sharpen(module::get_var("gallery", "image_sharpen"));
+ }
+ $image->save($output_file);
}
+
+ module::event("graphics_resize_completed", $input_file, $output_file, $options);
}
/**
@@ -223,10 +228,14 @@ class graphics_Core {
self::init_toolkit();
}
+ module::event("graphics_rotate", $input_file, $output_file, $options);
+
Image::factory($input_file)
->quality(module::get_var("gallery", "image_quality"))
->rotate($options["degrees"])
->save($output_file);
+
+ module::event("graphics_rotate_completed", $input_file, $output_file, $options);
}
/**
@@ -249,6 +258,8 @@ class graphics_Core {
self::init_toolkit();
}
+ module::event("graphics_composite", $input_file, $output_file, $options);
+
list ($width, $height) = getimagesize($input_file);
list ($w_width, $w_height) = getimagesize($options["file"]);
@@ -276,6 +287,9 @@ class graphics_Core {
->composite($options["file"], $x, $y, $options["transparency"])
->quality(module::get_var("gallery", "image_quality"))
->save($output_file);
+
+
+ module::event("graphics_composite_completed", $input_file, $output_file, $options);
}
/**
@@ -312,9 +326,9 @@ class graphics_Core {
t2("One of your photos is out of date. <a %attrs>Click here to fix it</a>",
"%count of your photos are out of date. <a %attrs>Click here to fix them</a>",
$count,
- array("attrs" => sprintf(
+ array("attrs" => html::mark_clean(sprintf(
'href="%s" class="gDialogLink"',
- url::site("admin/maintenance/start/gallery_task::rebuild_dirty_images?csrf=__CSRF__")))),
+ url::site("admin/maintenance/start/gallery_task::rebuild_dirty_images?csrf=__CSRF__"))))),
"graphics_dirty");
}
}
@@ -326,15 +340,101 @@ class graphics_Core {
* GraphicsMagick we return the path to the directory containing the appropriate binaries.
*/
static function detect_toolkits() {
+ $toolkits = new stdClass();
+
+ // GD is special, it doesn't use exec()
$gd = function_exists("gd_info") ? gd_info() : array();
- $exec = function_exists("exec");
+ $toolkits->gd->name = "GD";
if (!isset($gd["GD Version"])) {
- $gd["GD Version"] = false;
+ $toolkits->gd->installed = false;
+ $toolkits->gd->error = t("GD is not installed");
+ } else {
+ $toolkits->gd->installed = true;
+ $toolkits->gd->version = $gd["GD Version"];
+ $toolkits->gd->rotate = function_exists("imagerotate");
+ $toolkits->gd->sharpen = function_exists("imageconvolution");
+ $toolkits->gd->binary = "";
+ $toolkits->gd->dir = "";
+
+ if (!$toolkits->gd->rotate && !$toolkits->gd->sharpen) {
+ $toolkits->gd->error =
+ t("You have GD version %version, but it lacks image rotation and sharpening.",
+ array("version" => $gd["GD Version"]));
+ } else if (!$toolkits->gd->rotate) {
+ $toolkits->gd->error =
+ t("You have GD version %version, but it lacks image rotation.",
+ array("version" => $gd["GD Version"]));
+ } else if (!$toolkits->gd->sharpen) {
+ $toolkits->gd->error =
+ t("You have GD version %version, but it lacks image sharpening.",
+ array("version" => $gd["GD Version"]));
+ }
+ }
+
+ if (!function_exists("exec")) {
+ $toolkits->imagemagick->installed = false;
+ $toolkits->imagemagick->error = t("ImageMagick requires the <b>exec</b> function");
+
+ $toolkits->graphicsmagick->installed = false;
+ $toolkits->graphicsmagick->error = t("GraphicsMagick requires the <b>exec</b> function");
+ } else {
+ putenv("PATH=" . getenv("PATH") . ":/usr/local/bin:/opt/local/bin:/opt/bin");
+
+ // @todo: consider refactoring the two segments below into a loop since they are so
+ // similar.
+
+ // ImageMagick
+ $path = exec("which convert");
+ $toolkits->imagemagick->name = "ImageMagick";
+ if ($path) {
+ if (@is_file($path)) {
+ preg_match('/Version: \S+ (\S+)/', `convert -v`, $matches);
+ $version = $matches[1];
+
+ $toolkits->imagemagick->installed = true;
+ $toolkits->imagemagick->version = $version;
+ $toolkits->imagemagick->binary = $path;
+ $toolkits->imagemagick->dir = dirname($path);
+ $toolkits->imagemagick->rotate = true;
+ $toolkits->imagemagick->sharpen = true;
+ } else {
+ $toolkits->imagemagick->installed = false;
+ $toolkits->imagemagick->error =
+ t("ImageMagick is installed, but PHP's open_basedir restriction " .
+ "prevents Gallery from using it.");
+ }
+ } else {
+ $toolkits->imagemagick->installed = false;
+ $toolkits->imagemagick->error = t("We could not locate ImageMagick on your system.");
+ }
+
+ // GraphicsMagick
+ $path = exec("which gm");
+ $toolkits->graphicsmagick->name = "GraphicsMagick";
+ if ($path) {
+ if (@is_file($path)) {
+ preg_match('/\S+ (\S+)/', `gm version`, $matches);
+ $version = $matches[1];
+
+ $toolkits->graphicsmagick->installed = true;
+ $toolkits->graphicsmagick->version = $version;
+ $toolkits->graphicsmagick->binary = $path;
+ $toolkits->graphicsmagick->dir = dirname($path);
+ $toolkits->graphicsmagick->rotate = true;
+ $toolkits->graphicsmagick->sharpen = true;
+ } else {
+ $toolkits->graphicsmagick->installed = false;
+ $toolkits->graphicsmagick->error =
+ t("GraphicsMagick is installed, but PHP's open_basedir restriction " .
+ "prevents Gallery from using it.");
+ }
+ } else {
+ $toolkits->graphicsmagick->installed = false;
+ $toolkits->graphicsmagick->error = t("We could not locate GraphicsMagick on your system.");
+ }
}
- putenv("PATH=" . getenv("PATH") . ":/usr/local/bin:/opt/local/bin:/opt/bin");
- return array("gd" => $gd,
- "imagemagick" => $exec ? dirname(exec("which convert")) : false,
- "graphicsmagick" => $exec ? dirname(exec("which gm")) : false);
+
+ return $toolkits;
}
/**
@@ -344,16 +444,17 @@ class graphics_Core {
// Detect a graphics toolkit
$toolkits = graphics::detect_toolkits();
foreach (array("imagemagick", "graphicsmagick", "gd") as $tk) {
- if ($toolkits[$tk]) {
+ if ($toolkits->$tk->installed) {
module::set_var("gallery", "graphics_toolkit", $tk);
- module::set_var("gallery", "graphics_toolkit_path", $tk == "gd" ? "" : $toolkits[$tk]);
+ module::set_var("gallery", "graphics_toolkit_path", $toolkits->$tk->dir);
break;
}
}
+
if (!module::get_var("gallery", "graphics_toolkit")) {
site_status::warning(
t("Graphics toolkit missing! Please <a href=\"%url\">choose a toolkit</a>",
- array("url" => url::site("admin/graphics"))),
+ array("url" => html::mark_clean(url::site("admin/graphics")))),
"missing_graphics_toolkit");
}
}
@@ -385,14 +486,18 @@ class graphics_Core {
/**
* Verify that a specific graphics function is available with the active toolkit.
- * @param string $func (eg rotate, resize)
+ * @param string $func (eg rotate, sharpen)
* @return boolean
*/
static function can($func) {
- if (module::get_var("gallery", "graphics_toolkit") == "gd" &&
- $func == "rotate" &&
- !function_exists("imagerotate")) {
- return false;
+ if (module::get_var("gallery", "graphics_toolkit") == "gd") {
+ switch ($func) {
+ case "rotate":
+ return function_exists("imagerotate");
+
+ case "sharpen":
+ return function_exists("imageconvolution");
+ }
}
return true;
diff --git a/modules/gallery/helpers/item.php b/modules/gallery/helpers/item.php
index f40b5c97..588c08d4 100644
--- a/modules/gallery/helpers/item.php
+++ b/modules/gallery/helpers/item.php
@@ -53,7 +53,7 @@ class item_Core {
access::required("view", $parent);
access::required("edit", $parent);
- model_cache::clear("item", $parent->album_cover_item_id);
+ model_cache::clear();
$parent->album_cover_item_id = $item->is_album() ? $item->album_cover_item_id : $item->id;
$parent->thumb_dirty = 1;
$parent->save();
@@ -69,7 +69,7 @@ class item_Core {
access::required("edit", $album);
@unlink($album->thumb_path());
- model_cache::clear("item", $album->album_cover_item_id) ;
+ model_cache::clear();
$album->album_cover_item_id = null;
$album->thumb_width = 0;
$album->thumb_height = 0;
@@ -90,21 +90,9 @@ class item_Core {
}
}
- static function validate_no_name_conflict($input) {
- $itemid = Input::instance()->post("item");
- if (is_array($itemid)) {
- $itemid = $itemid[0];
- }
- $item = ORM::factory("item")
- ->in("id", $itemid)
- ->find();
- if (Database::instance()
- ->from("items")
- ->where("parent_id", $item->parent_id)
- ->where("id <>", $item->id)
- ->where("name", $input->value)
- ->count_records()) {
- $input->add_error("conflict", 1);
+ static function validate_url_safe($input) {
+ if (preg_match("/[^A-Za-z0-9-_]/", $input->value)) {
+ $input->add_error("not_url_safe", 1);
}
}
@@ -121,6 +109,16 @@ class item_Core {
}
/**
+ * Convert a filename into something we can use as a url component.
+ * @param string $filename
+ */
+ static function convert_filename_to_slug($filename) {
+ $result = pathinfo($filename, PATHINFO_FILENAME);
+ $result = preg_replace("/[^A-Za-z0-9-_]+/", "-", $result);
+ return trim($result, "-");
+ }
+
+ /**
* Display delete confirmation message and form
* @param object $item
* @return string form
@@ -129,12 +127,72 @@ class item_Core {
if (Input::instance()->get("page_type") == "album") {
$page_type = "album";
} else {
- $page_type = "item";
+ $page_type = "photo";
}
- $form = new Forge("quick/delete/$item->id?page_type=$page_type", "", "post", array("id" => "gConfirmDelete"));
+ $form = new Forge(
+ "quick/delete/$item->id?page_type=$page_type", "", "post", array("id" => "gConfirmDelete"));
$form->hidden("_method")->value("put");
$group = $form->group("confirm_delete")->label(t("Confirm Deletion"));
$group->submit("")->value(t("Delete"));
return $form;
}
+
+ /**
+ * Get the next weight value
+ */
+ static function get_max_weight() {
+ // Guard against an empty result when we create the first item. It's unfortunate that we
+ // have to check this every time.
+ // @todo: figure out a better way to bootstrap the weight.
+ $result = Database::instance()
+ ->select("weight")->from("items")
+ ->orderby("weight", "desc")->limit(1)
+ ->get()->current();
+ return ($result ? $result->weight : 0) + 1;
+ }
+
+ /**
+ * Add a set of restrictions to any following queries to restrict access only to items
+ * viewable by the active user.
+ * @chainable
+ */
+ static function viewable($model) {
+ $view_restrictions = array();
+ if (!user::active()->admin) {
+ foreach (user::group_ids() as $id) {
+ // Separate the first restriction from the rest to make it easier for us to formulate
+ // our where clause below
+ if (empty($view_restrictions)) {
+ $view_restrictions[0] = "items.view_$id";
+ } else {
+ $view_restrictions[1]["items.view_$id"] = access::ALLOW;
+ }
+ }
+ }
+ switch (count($view_restrictions)) {
+ case 0:
+ break;
+
+ case 1:
+ $model->where($view_restrictions[0], access::ALLOW);
+ break;
+
+ default:
+ $model->open_paren();
+ $model->where($view_restrictions[0], access::ALLOW);
+ $model->orwhere($view_restrictions[1]);
+ $model->close_paren();
+ break;
+ }
+
+ return $model;
+ }
+
+ /**
+ * Return the root Item_Model
+ * @return Item_Model
+ */
+ static function root() {
+ return model_cache::get("item", 1);
+ }
} \ No newline at end of file
diff --git a/modules/gallery/helpers/l10n_client.php b/modules/gallery/helpers/l10n_client.php
index 6d4da0eb..3460cc65 100644
--- a/modules/gallery/helpers/l10n_client.php
+++ b/modules/gallery/helpers/l10n_client.php
@@ -74,7 +74,7 @@ class l10n_client_Core {
$request->locales = array();
$request->messages = new stdClass();
- $locales = locale::installed();
+ $locales = locales::installed();
foreach ($locales as $locale => $locale_data) {
$request->locales[] = $locale;
}
@@ -113,10 +113,6 @@ class l10n_client_Core {
// [{key:<key_1>, translation: <JSON encoded translation>, rev:<rev>, locale:<locale>},
// {key:<key_2>, ...}
// ]
- $count = count($response);
- $message[] = t2("Installed 1 new / updated translation message",
- "Installed %count new / updated translation messages", $count);
-
foreach ($response as $message_data) {
// @todo Better input validation
if (empty($message_data->key) || empty($message_data->translation) ||
@@ -153,7 +149,6 @@ class l10n_client_Core {
$entry->translation = $translation;
$entry->save();
}
- return $message;
}
static function submit_translations() {
diff --git a/modules/gallery/helpers/locale.php b/modules/gallery/helpers/locales.php
index 41b78834..16dda2d7 100644
--- a/modules/gallery/helpers/locale.php
+++ b/modules/gallery/helpers/locales.php
@@ -21,8 +21,9 @@
/**
* This is the API for handling locales.
*/
-class locale_Core {
+class locales_Core {
private static $locales;
+ private static $language_subtag_to_locale;
/**
* Return the list of available locales.
@@ -55,6 +56,9 @@ class locale_Core {
: array_merge($locales, array($default));
module::set_var("gallery", "installed_locales", join("|", $locales));
+
+ // Clear the cache
+ self::$locales = null;
}
// @todo Might want to add a localizable language name as well.
@@ -105,6 +109,16 @@ class locale_Core {
$l["zh_TW"] = "&#32321;&#39636;&#20013;&#25991;"; // Chinese (TW)
asort($l, SORT_LOCALE_STRING);
self::$locales = $l;
+
+ // Language subtag to (default) locale mapping
+ foreach ($l as $locale => $name) {
+ list ($language) = explode("_", $locale . "_");
+ // The first one mentioned is the default
+ if (!isset($d[$language])) {
+ $d[$language] = $locale;
+ }
+ }
+ self::$language_subtag_to_locale = $d;
}
static function display_name($locale=null) {
@@ -121,4 +135,80 @@ class locale_Core {
list ($language, $territory) = explode('_', $locale . "_");
return in_array($language, array("he", "fa", "ar"));
}
+
+ /**
+ * Returns the best match comparing the HTTP accept-language header
+ * with the installed locales.
+ * @todo replace this with request::accepts_language() when we upgrade to Kohana 2.4
+ */
+ static function locale_from_http_request() {
+ $http_accept_language = Input::instance()->server("HTTP_ACCEPT_LANGUAGE");
+ if ($http_accept_language) {
+ // Parse the HTTP header and build a preference list
+ // Example value: "de,en-us;q=0.7,en-uk,fr-fr;q=0.2"
+ $locale_preferences = array();
+ foreach (explode(",", $http_accept_language) as $code) {
+ list ($requested_locale, $qvalue) = explode(";", $code . ";");
+ $requested_locale = trim($requested_locale);
+ $qvalue = trim($qvalue);
+ if (preg_match("/^([a-z]{2,3})(?:[_-]([a-zA-Z]{2}))?/", $requested_locale, $matches)) {
+ $requested_locale = strtolower($matches[1]);
+ if (!empty($matches[2])) {
+ $requested_locale .= "_" . strtoupper($matches[2]);
+ }
+ $requested_locale = trim(str_replace("-", "_", $requested_locale));
+ if (!strlen($qvalue)) {
+ // If not specified, default to 1.
+ $qvalue = 1;
+ } else {
+ // qvalue is expected to be something like "q=0.7"
+ list ($ignored, $qvalue) = explode("=", $qvalue . "==");
+ $qvalue = floatval($qvalue);
+ }
+ $locale_preferences[] = array($requested_locale, $qvalue);
+ }
+ }
+
+ // Compare and score requested locales with installed ones
+ $scored_locales = array();
+ foreach ($locale_preferences as $requested_value) {
+ $scored_locale_match = self::_locale_match_score($requested_value);
+ if ($scored_locale_match) {
+ $scored_locales[] = $scored_locale_match;
+ }
+ }
+
+ usort($scored_locales, array("locales", "_compare_locale_by_qvalue"));
+
+ $best_match = array_shift($scored_locales);
+ if ($best_match) {
+ return $best_match[0];
+ }
+ }
+
+ return null;
+ }
+
+ static function _compare_locale_by_qvalue($a, $b) {
+ $a = $a[1];
+ $b = $b[1];
+ if ($a == $b) {
+ return 0;
+ }
+ return $a < $b ? 1 : -1;
+ }
+
+ private static function _locale_match_score($requested_locale_and_qvalue) {
+ list ($requested_locale, $qvalue) = $requested_locale_and_qvalue;
+ $installed = self::installed();
+ if (isset($installed[$requested_locale])) {
+ return $requested_locale_and_qvalue;
+ }
+ list ($language) = explode("_", $requested_locale . "_");
+ if (isset(self::$language_subtag_to_locale[$language]) &&
+ isset($installed[self::$language_subtag_to_locale[$language]])) {
+ return array(self::$language_subtag_to_locale[$language], $qvalue * 0.66);
+ }
+ return null;
+ }
} \ No newline at end of file
diff --git a/modules/gallery/helpers/model_cache.php b/modules/gallery/helpers/model_cache.php
index 2649fdbd..a3e09862 100644
--- a/modules/gallery/helpers/model_cache.php
+++ b/modules/gallery/helpers/model_cache.php
@@ -32,10 +32,8 @@ class model_cache_Core {
return self::$cache->$model_name->$field_name->$id;
}
- static function clear($model_name, $id, $field_name="id") {
- if (!empty(self::$cache->$model_name->$field_name->$id)) {
- unset(self::$cache->$model_name->$field_name->$id);
- }
+ static function clear() {
+ self::$cache = new stdClass();
}
static function set($model) {
diff --git a/modules/gallery/helpers/module.php b/modules/gallery/helpers/module.php
index 0d483206..a3088c38 100644
--- a/modules/gallery/helpers/module.php
+++ b/modules/gallery/helpers/module.php
@@ -119,6 +119,8 @@ class module_Core {
$installer_class = "{$module_name}_installer";
if (method_exists($installer_class, "install")) {
call_user_func_array(array($installer_class, "install"), array());
+ } else {
+ module::set_version($module_name, 1);
}
module::load_modules();
@@ -145,6 +147,13 @@ class module_Core {
$installer_class = "{$module_name}_installer";
if (method_exists($installer_class, "upgrade")) {
call_user_func_array(array($installer_class, "upgrade"), array($version_before));
+ } else {
+ $available = module::available();
+ if (isset($available->$module_name->code_version)) {
+ module::set_version($module_name, $available->$module_name->code_version);
+ } else {
+ throw new Exception("@todo UNKNOWN_MODULE");
+ }
}
module::load_modules();
@@ -274,11 +283,9 @@ class module_Core {
array_shift($args);
$function = str_replace(".", "_", $name);
- foreach (self::$modules as $module) {
- if (!$module->active) {
- continue;
- }
-
+ // @todo: consider calling gallery_event first, since for things menus we need it to do some
+ // setup
+ foreach (self::$active as $module) {
$class = "{$module->name}_event";
if (method_exists($class, $function)) {
call_user_func_array(array($class, $function), $args);
diff --git a/modules/gallery/helpers/movie.php b/modules/gallery/helpers/movie.php
index d62ead76..59bf5c19 100644
--- a/modules/gallery/helpers/movie.php
+++ b/modules/gallery/helpers/movie.php
@@ -31,10 +31,11 @@ class movie_Core {
* @param string $name the filename to use for this photo in the album
* @param integer $title the title of the new photo
* @param string $description (optional) the longer description of this photo
+ * @param string $slug (optional) the url component for this photo
* @return Item_Model
*/
static function create($parent, $filename, $name, $title,
- $description=null, $owner_id=null) {
+ $description=null, $owner_id=null, $slug=null) {
if (!$parent->loaded || !$parent->is_album()) {
throw new Exception("@todo INVALID_PARENT");
}
@@ -67,6 +68,10 @@ class movie_Core {
$name .= "." . $pi["extension"];
}
+ if (empty($slug)) {
+ $slug = item::convert_filename_to_slug($name);
+ }
+
$movie = ORM::factory("item");
$movie->type = "movie";
$movie->title = $title;
@@ -79,15 +84,21 @@ class movie_Core {
$movie->thumb_dirty = 1;
$movie->resize_dirty = 1;
$movie->sort_column = "weight";
+ $movie->slug = $slug;
$movie->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
// Randomize the name if there's a conflict
+ // @todo Improve this. Random numbers are not user friendly
while (ORM::factory("item")
->where("parent_id", $parent->id)
+ ->open_paren()
->where("name", $movie->name)
+ ->orwhere("slug", $movie->slug)
+ ->close_paren()
->find()->id) {
- // @todo Improve this. Random numbers are not user friendly
- $movie->name = rand() . "." . $pi["extension"];
+ $rand = rand();
+ $movie->name = "{$name}.$rand.{$pi['extension']}";
+ $movie->slug = "{$slug}-$rand";
}
// This saves the photo
@@ -102,6 +113,8 @@ class movie_Core {
copy($filename, $movie->file_path());
+ // @todo: publish this from inside Item_Model::save() when we refactor to the point where
+ // there's only one save() happening here.
module::event("item_created", $movie);
// Build our thumbnail
@@ -139,7 +152,7 @@ class movie_Core {
$cmd = escapeshellcmd($ffmpeg) . " -i " . escapeshellarg($input_file) .
" -an -ss 00:00:03 -an -r 1 -vframes 1" .
- " -y -f mjpeg " . escapeshellarg($output_file);
+ " -y -f mjpeg " . escapeshellarg($output_file) . " 2>&1";
exec($cmd);
}
diff --git a/modules/gallery/helpers/p.php b/modules/gallery/helpers/p.php
deleted file mode 100644
index 862c769b..00000000
--- a/modules/gallery/helpers/p.php
+++ /dev/null
@@ -1,39 +0,0 @@
-<?php defined("SYSPATH") or die("No direct script access.");
-/**
- * Gallery - a web based photo album viewer and editor
- * Copyright (C) 2000-2009 Bharat Mediratta
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
- */
-class p_Core {
- private static $_purifier = null;
- static function clean($dirty_html) {
- return html::specialchars($dirty_html);
- }
-
- static function purify($dirty_html) {
- if (empty(self::$_purifier)) {
- require_once(dirname(__file__) . "/../lib/HTMLPurifier/HTMLPurifier.auto.php");
- $config = HTMLPurifier_Config::createDefault();
- foreach (Kohana::config('purifier') as $category => $key_value) {
- foreach ($key_value as $key => $value) {
- $config->set("$category.$key", $value);
- }
- }
- self::$_purifier = new HTMLPurifier($config);
- }
- return self::$_purifier->purify($dirty_html);
- }
-}
diff --git a/modules/gallery/helpers/photo.php b/modules/gallery/helpers/photo.php
index e8a4f357..3d9fbe69 100644
--- a/modules/gallery/helpers/photo.php
+++ b/modules/gallery/helpers/photo.php
@@ -31,10 +31,11 @@ class photo_Core {
* @param string $name the filename to use for this photo in the album
* @param integer $title the title of the new photo
* @param string $description (optional) the longer description of this photo
+ * @param string $slug (optional) the url component for this photo
* @return Item_Model
*/
static function create($parent, $filename, $name, $title,
- $description=null, $owner_id=null) {
+ $description=null, $owner_id=null, $slug=null) {
if (!$parent->loaded || !$parent->is_album()) {
throw new Exception("@todo INVALID_PARENT");
}
@@ -66,6 +67,10 @@ class photo_Core {
$name .= "." . $pi["extension"];
}
+ if (empty($slug)) {
+ $slug = item::convert_filename_to_slug($name);
+ }
+
$photo = ORM::factory("item");
$photo->type = "photo";
$photo->title = $title;
@@ -78,15 +83,21 @@ class photo_Core {
$photo->thumb_dirty = 1;
$photo->resize_dirty = 1;
$photo->sort_column = "weight";
+ $photo->slug = $slug;
$photo->rand_key = ((float)mt_rand()) / (float)mt_getrandmax();
- // Randomize the name if there's a conflict
+ // Randomize the name or slug if there's a conflict
+ // @todo Improve this. Random numbers are not user friendly
while (ORM::factory("item")
->where("parent_id", $parent->id)
+ ->open_paren()
->where("name", $photo->name)
+ ->orwhere("slug", $photo->slug)
+ ->close_paren()
->find()->id) {
- // @todo Improve this. Random numbers are not user friendly
- $photo->name = rand() . "." . $pi["extension"];
+ $rand = rand();
+ $photo->name = "{$name}.$rand.{$pi['extension']}";
+ $photo->slug = "{$slug}-$rand";
}
// This saves the photo
@@ -105,10 +116,18 @@ class photo_Core {
copy($filename, $photo->file_path());
+ // @todo: publish this from inside Item_Model::save() when we refactor to the point where
+ // there's only one save() happening here.
module::event("item_created", $photo);
- // Build our thumbnail/resizes
- graphics::generate($photo);
+ // Build our thumbnail/resizes. If we fail to build thumbnail/resize we assume that the image
+ // is bad in some way and discard it.
+ try {
+ graphics::generate($photo);
+ } catch (Exception $e) {
+ $photo->delete();
+ throw $e;
+ }
// If the parent has no cover item, make this it.
if (access::can("edit", $parent) && $parent->album_cover_item_id == null) {
@@ -121,10 +140,15 @@ class photo_Core {
static function get_add_form($parent) {
$form = new Forge("albums/{$parent->id}", "", "post", array("id" => "gAddPhotoForm"));
$group = $form->group("add_photo")->label(
- t("Add Photo to %album_title", array("album_title" =>$parent->title)));
+ t("Add Photo to %album_title", array("album_title" => $parent->title)));
$group->input("title")->label(t("Title"));
$group->textarea("description")->label(t("Description"));
$group->input("name")->label(t("Filename"));
+ $group->input("slug")->label(t("Internet Address"))->value($photo->slug)
+ ->callback("item::validate_url_safe")
+ ->error_messages(
+ "not_url_safe",
+ t("The internet address should contain only letters, numbers, hyphens and underscores"));
$group->upload("file")->label(t("File"))->rules("required|allow[jpg,png,gif,flv,mp4]");
$group->hidden("type")->value("photo");
$group->submit("")->value(t("Upload"));
@@ -135,16 +159,26 @@ class photo_Core {
static function get_edit_form($photo) {
$form = new Forge("photos/$photo->id", "", "post", array("id" => "gEditPhotoForm"));
$form->hidden("_method")->value("put");
- $group = $form->group("edit_photo")->label(t("Edit Photo"));
+ $group = $form->group("edit_item")->label(t("Edit Photo"));
$group->input("title")->label(t("Title"))->value($photo->title);
$group->textarea("description")->label(t("Description"))->value($photo->description);
$group->input("filename")->label(t("Filename"))->value($photo->name)
- ->error_messages("conflict", t("There is already a file with this name"))
+ ->error_messages("name_conflict", t("There is already a photo or album with this name"))
->callback("item::validate_no_slashes")
->error_messages("no_slashes", t("The photo name can't contain a \"/\""))
->callback("item::validate_no_trailing_period")
->error_messages("no_trailing_period", t("The photo name can't end in \".\""));
+ $group->input("slug")->label(t("Internet Address"))->value($photo->slug)
+ ->callback("item::validate_url_safe")
+ ->error_messages(
+ "slug_conflict", t("There is already a photo or album with this internet address"))
+ ->error_messages(
+ "not_url_safe",
+ t("The internet address should contain only letters, numbers, hyphens and underscores"));
+
+ module::event("item_edit_form", $photo, $form);
+ $group = $form->group("buttons")->label("");
$group->submit("")->value(t("Modify"));
$form->add_rules_from(ORM::factory("item"));
return $form;
diff --git a/modules/gallery/helpers/task.php b/modules/gallery/helpers/task.php
index 6a9f63c2..9fa04305 100644
--- a/modules/gallery/helpers/task.php
+++ b/modules/gallery/helpers/task.php
@@ -84,10 +84,11 @@ class task_Core {
}
$task->save();
} catch (Exception $e) {
+ Kohana::log("error", $e->__toString());
$task->log($e->__toString());
$task->state = "error";
$task->done = true;
- $task->status = $e->getMessage();
+ $task->status = substr($e->getMessage(), 0, 255);
$task->save();
}