summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBharat Mediratta <bharat@menalto.com>2008-12-01 08:50:00 +0000
committerBharat Mediratta <bharat@menalto.com>2008-12-01 08:50:00 +0000
commit91c4bda1ec6640abb8b1a585e1fd1f8955d53fd1 (patch)
tree42f8f79c6d356a04d0e8365a0921d7257f12c64d
parentab0fcb7453db7d93c9dc1dfd38e6d6f84a5b16b5 (diff)
Prototype access control model. There's much left to do, but it's a
working implementation.
-rw-r--r--core/controllers/items.php3
-rw-r--r--core/controllers/welcome.php38
-rw-r--r--core/helpers/access.php384
-rw-r--r--core/helpers/core_event.php45
-rw-r--r--core/helpers/core_installer.php29
-rw-r--r--core/models/access_cache.php21
-rw-r--r--core/models/access_intent.php21
-rw-r--r--core/models/permission.php (renamed from core/models/access.php)2
-rw-r--r--core/views/welcome.html.php18
-rw-r--r--modules/user/helpers/group.php8
-rw-r--r--modules/user/helpers/user_installer.php13
11 files changed, 550 insertions, 32 deletions
diff --git a/core/controllers/items.php b/core/controllers/items.php
index 26b55492..6cf27fbf 100644
--- a/core/controllers/items.php
+++ b/core/controllers/items.php
@@ -99,11 +99,10 @@ class Items_Controller extends REST_Controller {
// 1) Add security checks
$parent = $item->parent();
if ($parent->id) {
+ module::event("{$item->type}_before_delete", $item);
$item->delete();
}
- module::event("{$item->type}_deleted", $item);
-
url::redirect("{$parent->type}s/{$parent->id}");
}
diff --git a/core/controllers/welcome.php b/core/controllers/welcome.php
index c29a5aaf..cabaf0a9 100644
--- a/core/controllers/welcome.php
+++ b/core/controllers/welcome.php
@@ -71,16 +71,33 @@ class Welcome_Controller extends Template_Controller {
}
function uninstall($module_name) {
+ $clean = true;
if ($module_name == "core") {
// We have to uninstall all other modules first, else their tables, etc don't
// get cleaned up.
- foreach (ORM::factory("module")->find_all() as $module) {
- if ($module->name != "core" && $module->version) {
- call_user_func(array("{$module->name}_installer", "uninstall"));
+ try {
+ foreach (ORM::factory("module")->find_all() as $module) {
+ if ($module->name != "core" && $module->version) {
+ try {
+ call_user_func(array("{$module->name}_installer", "uninstall"));
+ } catch (Exception $e) {
+ $clean = false;
+ }
+ }
}
- }
+ } catch (Exception $e) { }
}
call_user_func(array("{$module_name}_installer", "uninstall"));
+
+ $clean = false;
+ if (!$clean) {
+ // Since we're in a state of flux, it's possible that other stuff went wrong with the
+ // uninstall, so back off and nuke things from orbit.
+ $db = Database::instance();
+ foreach ($db->list_tables() as $table) {
+ $db->query("DROP TABLE `$table`");
+ }
+ }
url::redirect("welcome");
}
@@ -442,7 +459,7 @@ class Welcome_Controller extends Template_Controller {
url::redirect("welcome");
}
- public function _load_album_tree() {
+ private function _load_album_tree() {
$tree = array();
foreach (ORM::factory("item")->where("type", "album")->find_all() as $album) {
if ($album->parent_id) {
@@ -451,7 +468,16 @@ class Welcome_Controller extends Template_Controller {
$tree[$album->id]->album = $album;
$tree[$album->id]->children = array();
}
-
return $tree;
}
+
+ public function add_perm($group_id, $perm, $item_id) {
+ access::allow($group_id, $perm, $item_id);
+ url::redirect("welcome");
+ }
+
+ public function deny_perm($group_id, $perm, $item_id) {
+ access::deny($group_id, $perm, $item_id);
+ url::redirect("welcome");
+ }
}
diff --git a/core/helpers/access.php b/core/helpers/access.php
new file mode 100644
index 00000000..9ca54779
--- /dev/null
+++ b/core/helpers/access.php
@@ -0,0 +1,384 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2008 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.
+ */
+/**
+ * API for Gallery Access control.
+ *
+ * Permissions are hierarchical, and apply only to groups and albums. They cascade down from the
+ * top of the Gallery to the bottom, so if you set a permission in the root album, that permission
+ * applies for any sub-album unless the sub-album overrides it. Likewise, any permission applied
+ * to an album applies to any photos inside the album. Overrides can be applied at any level of
+ * the hierarchy for any permission other than View permissions.
+ *
+ * View permissions are an exceptional case. In the case of viewability, we want to ensure that
+ * if an album's parent is inaccessible, then this album must be inaccessible also. So while view
+ * permissions cascade downwards and you're free to set the ALLOW permission on any album, that
+ * ALLOW permission will be ignored unless all that album's parents are marked ALLOW also.
+ *
+ * Implementatation Notes:
+ *
+ * Notes refer to this example album hierarchy:
+ * A1
+ * / \
+ * A2 A3
+ * / \
+ * A4 A5
+ *
+ * o We have the concept of "intents". A user can specify that he intends for A3 to be
+ * inaccessible (ie: a DENY on the "view" permission to the EVERYBODY group). Once A3 is
+ * inaccessible, A5 can never be displayed to that group. If A1 is made inaccessible, then the
+ * entire tree is hidden. If subsequently A1 is made accessible, then the whole tree is
+ * available again *except* A3 and below since the user's preference for A3 is maintained.
+ *
+ * o Intents are specified as <group_id, perm, item_id> tuples. It would be inefficient to check
+ * these tuples every time we want to do a lookup, so we use these intents to create an entire
+ * table of permissions for easy lookup in the Access_Cache_Model. There's a 1:1 mapping
+ * between Item_Model and Access_Cache_Model entries.
+ *
+ * o For efficiency, we create columns in Access_Intent_Model and Access_Cache_Model for each of
+ * the possible Group_Model and Permission_Model combinations. This may lead to performance
+ * issues for very large Gallery installs, but for small to medium sized ones (5-10 groups, 5-10
+ * permissions) it's especially efficient because there's a single field value for each
+ * group/permission/item combination.
+ *
+ * o If at any time the Access_Cache_Model becomes invalid, we can rebuild the entire table from
+ * the Access_Intent_Model
+ *
+ * TODO
+ * o In the near future, we'll be moving the "view" columns out of Access_Intent_Model and
+ * directly into Item_Model. By doing this, we'll be able to find viewable items (the most
+ * common permission access) without doing table joins.
+ */
+class access_Core {
+ const DENY = 0;
+ const ALLOW = 1;
+ const UNKNOWN = 2;
+
+ /**
+ * Can this group have this permission on this item?
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @param integer $item_id
+ * @return boolean
+ */
+ public static function can($group_id, $perm_name, $item_id) {
+ $access = ORM::factory("access_cache")->where("item_id", $item_id)->find();
+ if (!$access) {
+ throw new Exception("@todo MISSING_ACCESS for $item_id");
+ }
+
+ return $access->__get("{$perm_name}_{$group_id}") == self::ALLOW;
+ }
+
+ /**
+ * Internal method to set a permission
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @param integer $item_id
+ * @param boolean $value
+ * @return boolean
+ */
+ private static function _set($group_id, $perm_name, $item_id, $value) {
+ $access = ORM::factory("access_intent")->where("item_id", $item_id)->find();
+ if (!$access->loaded) {
+ throw new Exception("@todo MISSING_ACCESS for $item_id");
+ }
+
+ $access->__set("{$perm_name}_{$group_id}", $value);
+ $access->save();
+
+ self::_update_access_cache($group_id, $perm_name, $item_id);
+ }
+
+ /**
+ * Allow a group to have a permission on an item.
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @param integer $item_id
+ * @return boolean
+ */
+ public static function allow($group_id, $perm_name, $item_id) {
+ self::_set($group_id, $perm_name, $item_id, self::ALLOW);
+ }
+
+ /**
+ * Deny a group the given permission on an item.
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @param integer $item_id
+ * @return boolean
+ */
+ public static function deny($group_id, $perm_name, $item_id) {
+ self::_set($group_id, $perm_name, $item_id, self::DENY);
+ }
+
+ /**
+ * Register a permission so that modules can use it.
+ *
+ * @param string $perm_name
+ * @return void
+ */
+ public static function register_permission($perm_name) {
+ $permission = ORM::factory("permission", $perm_name);
+ if ($permission->loaded) {
+ throw new Exception("@todo PERMISSION_ALREADY_EXISTS $name");
+ }
+ $permission->name = $perm_name;
+ $permission->save();
+
+ foreach (self::_get_all_groups() as $group) {
+ self::_add_columns($perm_name, $group->id);
+ }
+ self::_add_columns($perm_name, group::EVERYBODY);
+ }
+
+ /**
+ * Delete a permission.
+ *
+ * @param string $perm_name
+ * @return void
+ */
+ public static function delete_permission($name) {
+ foreach (self::_get_all_groups() as $group) {
+ self::_drop_columns($name, $group->id);
+ }
+ self::_drop_columns($name, group::EVERYBODY);
+ ORM::factory("permission", $name)->delete();
+ }
+
+ /**
+ * Add the appropriate columns for a new group
+ *
+ * @param Group_Model $group
+ * @return void
+ */
+ public static function add_group($group) {
+ foreach (ORM::factory("permission")->find_all() as $perm) {
+ self::_add_columns($perm->name, $group->id);
+ }
+ }
+
+ /**
+ * Remove a group's permission columns (usually when it's deleted)
+ *
+ * @param Group_Model $group
+ * @return void
+ */
+ public static function remove_group($group) {
+ foreach (ORM::factory("permission")->find_all() as $perm) {
+ self::_drop_columns($perm->name, $group->id);
+ }
+ }
+
+ /**
+ * Add new access rows when a new item is added.
+ *
+ * @param Item_Model $item
+ * @return void
+ */
+ public static function add_item($item) {
+ $access_intent = ORM::factory("access_intent");
+ $access_intent->item_id = $item->id;
+ $access_intent->save();
+
+ // Create a new access cache entry and copy the parents values.
+ $parent_access_cache =
+ ORM::factory("access_cache")->where("item_id", $item->parent()->id)->find();
+ $access_cache = ORM::factory("access_cache");
+ $access_cache->item_id = $item->id;
+ foreach (ORM::factory("permission")->find_all() as $perm) {
+ foreach (self::_get_all_groups() as $group) {
+ $field = "{$perm->name}_{$group->id}";
+ $access_cache->$field = $parent_access_cache->$field;
+ }
+ $field = "{$perm->name}_0";
+ $access_cache->$field = $parent_access_cache->$field;
+ }
+ $access_cache->save();
+ }
+
+ /**
+ * Delete appropriate access rows when an item is deleted.
+ *
+ * @param Item_Model $item
+ * @return void
+ */
+ public static function remove_item($item) {
+ ORM::factory("access_intent")->where("item_id", $item->id)->delete();
+ ORM::factory("access_cache")->where("item_id", $item->id)->delete();
+ }
+
+ /**
+ * Internal method to get all available groups.
+ *
+ * @return ORM_Iterator
+ */
+ private static function _get_all_groups() {
+ try {
+ return ORM::factory("group")->find_all();
+ } catch (Kohana_Database_Exception $e) {
+ return array();
+ }
+ }
+
+ /**
+ * Internal method to remove Permission/Group columns
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @return void
+ */
+ private static function _drop_columns($perm_name, $group_id) {
+ $db = Database::instance();
+ $field = "{$perm_name}_{$group_id}";
+ $db->query("ALTER TABLE `access_caches` DROP `$field`");
+ $db->query("ALTER TABLE `access_intents` DROP `$field`");
+ }
+
+ /**
+ * Internal method to add Permission/Group columns
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @return void
+ */
+ private static function _add_columns($perm_name, $group_id) {
+ $db = Database::instance();
+ $field = "{$perm_name}_{$group_id}";
+ $db->query("ALTER TABLE `access_caches` ADD `$field` TINYINT(2) NOT NULL DEFAULT 0");
+ $db->query("ALTER TABLE `access_intents` ADD `$field` BOOLEAN DEFAULT NULL");
+ }
+
+ /**
+ * Update the Access_Cache model based on information from the Access_Intent model. This
+ * creates a fast-lookup table for permissions based on the rules that the user has specified in
+ * the intent model.
+ *
+ * @todo: use database locking
+ *
+ * @param integer $group_id
+ * @param string $perm_name
+ * @param integer $item_id
+ * @return void
+ */
+ public static function _update_access_cache($group_id, $perm_name, $item_id) {
+ $item = ORM::factory("item", $item_id);
+ if (!$item->loaded) {
+ throw new Exception("@todo MISSING_ITEM for $item_id");
+ }
+ $access = ORM::factory("access_intent")->where("item_id", $item_id)->find();
+
+ $db = Database::instance();
+ $field = "{$perm_name}_{$group_id}";
+
+ if ($perm_name == "view") {
+ // With view permissions, deny values in the parent can override allow values in the child,
+ // so start from the bottom of the tree and work upwards overlaying negative on top of
+ // positive.
+ //
+ // If the item's intent is ALLOW or DEFAULT, it's possible that some ancestor has specified
+ // DENY and this ALLOW cannot be obeyed. So in that case, back up the tree and find any
+ // non-DEFAULT and non-ALLOW parent and propagate from there. If we can't find a matching
+ // item, then its safe to propagate from here.
+ if ($access->$field != self::DENY) {
+ $tmp_item = ORM::factory("item")
+ ->join("access_intents", "items.id", "access_intents.item_id")
+ ->where("left <", $item->left)
+ ->where("right >", $item->right)
+ ->where($field, self::DENY)
+ ->orderby("left", "DESC")
+ ->limit(1)
+ ->find();
+ if ($tmp_item->loaded) {
+ $item = $tmp_item;
+ }
+ }
+
+ // We will have a problem if we're trying to change a DENY to an ALLOW because the
+ // access_caches table will already contain DENY values and we won't be able to overwrite
+ // 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.
+ //
+ // Potential problem: if $item_id's intent is unspecified then we have to back up the tree to
+ // find the nearest non-default parent and update the map starting from there. That can't
+ // happen currently, but if it does, then the symptom will be that we have a branch of
+ // access_caches in the UNKNOWN state.
+ $db->query("UPDATE `access_caches` SET `$field` = ? " .
+ "WHERE `item_id` IN " .
+ " (SELECT `id` FROM `items` " .
+ " WHERE `left` >= $item->left " .
+ " AND `right` <= $item->right)",
+ array(self::UNKNOWN));
+
+ $query = $db->query(
+ "SELECT `access_intents`.`$field`, `items`.`left`, `items`.`right`, `items`.`id` " .
+ "FROM `access_intents` JOIN (`items`) ON (`access_intents`.`item_id` = `items`.`id`) " .
+ "WHERE `left` >= $item->left " .
+ "AND `right` <= $item->right " .
+ "AND `type` = 'album' " .
+ "AND `$field` IS NOT NULL " .
+ "ORDER BY `level` DESC ");
+ foreach ($query as $row) {
+ if ($row->$field == self::ALLOW) {
+ // Propagate ALLOW for any row that is still UNKNOWN.
+ $db->query(
+ "UPDATE `access_caches` SET `$field` = {$row->$field} " .
+ "WHERE `$field` = ? " .
+ "AND `item_id` IN " .
+ " (SELECT `id` FROM `items` " .
+ " WHERE `left` >= $row->left " .
+ " AND `right` <= $row->right)",
+ array(self::UNKNOWN));
+ } else if ($row->$field == self::DENY) {
+ // DENY overwrites everything below it
+ $db->query(
+ "UPDATE `access_caches` SET `$field` = {$row->$field} " .
+ "WHERE `item_id` IN " .
+ " (SELECT `id` FROM `items` " .
+ " WHERE `left` >= $row->left " .
+ " AND `right` <= $row->right)");
+ }
+ }
+ } else {
+ // 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 = $db->query(
+ "SELECT `access_intents`.`$field`, `items`.`left`, `items`.`right` " .
+ "FROM `access_intents` JOIN (`items`) ON (`access_intents`.`item_id` = `items`.`id`) " .
+ "WHERE `left` >= ? " .
+ "AND `right` <= ? " .
+ "AND `type` = 'album' " .
+ "AND `$field` IS NOT NULL " .
+ "ORDER BY `level` ASC ",
+ array($item->left, $item->right));
+ foreach ($query as $row) {
+ $db->query(
+ "UPDATE `access_caches` SET `$field` = {$row->$field} " .
+ "WHERE `item_id` IN " .
+ " (SELECT `id` FROM `items` " .
+ " WHERE `left` >= $row->left " .
+ " AND `right` <= $row->right)");
+ }
+ }
+ }
+}
diff --git a/core/helpers/core_event.php b/core/helpers/core_event.php
new file mode 100644
index 00000000..3cf9f12f
--- /dev/null
+++ b/core/helpers/core_event.php
@@ -0,0 +1,45 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2008 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 core_event_Core {
+ public static function group_created($group) {
+ access::add_group($group);
+ }
+
+ public static function group_before_delete($group) {
+ access::remove_group($group);
+ }
+
+ public static function photo_created($photo) {
+ access::add_item($photo);
+ }
+
+ public static function photo_before_delete($photo) {
+ access::remove_item($photo);
+ }
+
+ public static function album_created($album) {
+ access::add_item($album);
+ }
+
+ public static function album_before_delete($album) {
+ access::remove_item($album);
+ }
+}
diff --git a/core/helpers/core_installer.php b/core/helpers/core_installer.php
index 792798ea..d1e359c7 100644
--- a/core/helpers/core_installer.php
+++ b/core/helpers/core_installer.php
@@ -31,11 +31,15 @@ class core_installer {
}
if ($version == 0) {
- $db->query("CREATE TABLE `access` (
+ $db->query("CREATE TABLE `access_caches` (
+ `id` int(9) NOT NULL auto_increment,
+ `item_id` int(9),
+ PRIMARY KEY (`id`))
+ ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+
+ $db->query("CREATE TABLE `access_intents` (
`id` int(9) NOT NULL auto_increment,
`item_id` int(9),
- `group_id` int(9) NOT NULL,
- `perm` char(255) default NULL,
PRIMARY KEY (`id`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
@@ -70,10 +74,21 @@ class core_installer {
UNIQUE KEY(`name`))
ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+ $db->query("CREATE TABLE `permissions` (
+ `id` int(9) NOT NULL auto_increment,
+ `name` char(255) default NULL,
+ `version` int(9) default NULL,
+ PRIMARY KEY (`id`),
+ UNIQUE KEY(`name`))
+ ENGINE=InnoDB DEFAULT CHARSET=utf8;");
+
foreach (array("albums", "resizes") as $dir) {
@mkdir(VARPATH . $dir);
}
+ access::register_permission("view");
+ access::register_permission("edit");
+
$root = ORM::factory("item");
$root->type = 'album';
$root->title = "Gallery";
@@ -85,13 +100,19 @@ class core_installer {
$root->set_thumbnail(DOCROOT . "core/tests/test.jpg", 200, 150)
->save();
+ access::add_item($root);
+ access::allow(0, "view", $root->id);
+ access::deny(0, "edit", $root->id);
+
module::set_version("core", 1);
}
}
public static function uninstall() {
$db = Database::instance();
- $db->query("DROP TABLE IF EXISTS `access`;");
+ $db->query("DROP TABLE IF EXISTS `access_cache`;");
+ $db->query("DROP TABLE IF EXISTS `access_intent`;");
+ $db->query("DROP TABLE IF EXISTS `permissions`;");
$db->query("DROP TABLE IF EXISTS `items`;");
$db->query("DROP TABLE IF EXISTS `modules`;");
system("/bin/rm -rf " . VARPATH . "albums");
diff --git a/core/models/access_cache.php b/core/models/access_cache.php
new file mode 100644
index 00000000..aa530993
--- /dev/null
+++ b/core/models/access_cache.php
@@ -0,0 +1,21 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2008 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 Access_Cache_Model extends ORM {
+}
diff --git a/core/models/access_intent.php b/core/models/access_intent.php
new file mode 100644
index 00000000..b7d68508
--- /dev/null
+++ b/core/models/access_intent.php
@@ -0,0 +1,21 @@
+<?php defined("SYSPATH") or die("No direct script access.");
+/**
+ * Gallery - a web based photo album viewer and editor
+ * Copyright (C) 2000-2008 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 Access_Intent_Model extends ORM {
+}
diff --git a/core/models/access.php b/core/models/permission.php
index f85e152d..e2080828 100644
--- a/core/models/access.php
+++ b/core/models/permission.php
@@ -17,5 +17,5 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
-class Access_Model extends ORM {
+class Permission_Model extends ORM {
}
diff --git a/core/views/welcome.html.php b/core/views/welcome.html.php
index e2390e9e..1cfd6d7c 100644
--- a/core/views/welcome.html.php
+++ b/core/views/welcome.html.php
@@ -128,6 +128,11 @@
a:hover {
text-decoration: underline;
}
+
+ span.understate {
+ font-size: 70%;
+ font-style: italic;
+ }
</style>
<?= html::script("lib/jquery.js") ?>
<?= html::script("lib/jquery.cookie.js") ?>
@@ -334,15 +339,14 @@
<? $current = $album_tree[$current]; ?>
<ul>
<li>
+ <span class="understate">(<?= $current->album->id ?>)</span>
<?= html::anchor("albums/{$current->album->id}", $current->album->title) ?>
- <? foreach (ORM::factory("item")->list_fields("items") as $field => $info): ?>
- <? if (!strncmp($field, "view_", 5)): ?>
- [<?= $field ?>=<?= $current->album->$field ?>]
+ access:
+ <? if (access::can(group::EVERYBODY, "view", $current->album->id)): ?>
+ access: <?= html::anchor("welcome/deny_perm/0/view/{$current->album->id}", "yes") ?>
+ <? else: ?>
+ access: <?= html::anchor("welcome/add_perm/0/view/{$current->album->id}", "no") ?>
<? endif ?>
- <? endforeach ?>
- <? foreach (ORM::factory("access")->where("item_id", $current->album->id)->find() as $access): ?>
- [ <?= $access->id ?> ]
- <? endforeach ?>
<? $stack[] = "CLOSE"; ?>
<? if ($current->children): ?>
<? $stack = array_merge($stack, $current->children) ?>
diff --git a/modules/user/helpers/group.php b/modules/user/helpers/group.php
index 2e6a3962..12118432 100644
--- a/modules/user/helpers/group.php
+++ b/modules/user/helpers/group.php
@@ -24,6 +24,7 @@
* Note: by design, this class does not do any permission checking.
*/
class group_Core {
+ const EVERYBODY = 0;
const REGISTERED_USERS = 1;
/**
@@ -41,9 +42,7 @@ class group_Core {
$group->name = $name;
$group->save();
- // Create the view column for this group in the items table.
- Database::instance()->query("ALTER TABLE `items` ADD `view_{$group->id}` BOOLEAN DEFAULT 0");
-
+ module::event("group_created", $group);
return $group;
}
@@ -56,8 +55,7 @@ class group_Core {
$group = ORM::factory("group", $id);
if ($group->loaded) {
- // Drop the view column for this group in the items table.
- Database::instance()->query("ALTER TABLE `items` DROP `view_{$group->id}`");
+ module::event("group_before_delete", $group);
$group->delete();
}
}
diff --git a/modules/user/helpers/user_installer.php b/modules/user/helpers/user_installer.php
index 0f030d0e..58066acd 100644
--- a/modules/user/helpers/user_installer.php
+++ b/modules/user/helpers/user_installer.php
@@ -66,14 +66,13 @@ class user_installer {
}
public static function uninstall() {
- // Remove all our groups so that we clean up the items table
+ // Delete all users and groups so that we give other modules an opportunity to clean up
+ foreach (ORM::factory("user")->find_all() as $user) {
+ user::delete($user->id);
+ }
+
foreach (ORM::factory("group")->find_all() as $group) {
- try {
- group::delete($group->id);
- } catch (Kohana_Database_Exception $e) {
- // We may get errors when we try to remove the view columns from the items table.
- // Ignore those for now.
- }
+ group::delete($group->id);
}
try {