diff options
author | Evan Prodromou <evan@status.net> | 2009-11-17 08:04:14 -0500 |
---|---|---|
committer | Evan Prodromou <evan@status.net> | 2009-11-17 08:04:14 -0500 |
commit | bac2d80c919a78d5cafd57f712872a90cda04847 (patch) | |
tree | d2df10a582edc0bf9e043f1c764953a290927678 /classes | |
parent | 9a1a83e8ebe5ad39838e6363f1537a1a5232b9cb (diff) | |
parent | 6a1afda259c5223449f679a64f932e36df5ebe39 (diff) |
Merge branch '0.9.x' into adminpanel
Conflicts:
classes/User.php
Diffstat (limited to 'classes')
-rw-r--r-- | classes/Message.php | 6 | ||||
-rw-r--r-- | classes/Notice.php | 11 | ||||
-rw-r--r-- | classes/Plugin_DataObject.php | 195 | ||||
-rw-r--r-- | classes/Profile.php | 142 | ||||
-rw-r--r-- | classes/Profile_role.php (renamed from classes/User_role.php) | 26 | ||||
-rw-r--r-- | classes/User.php | 132 | ||||
-rw-r--r-- | classes/statusnet.ini | 61 |
7 files changed, 426 insertions, 147 deletions
diff --git a/classes/Message.php b/classes/Message.php index 979e6e87c..718a9d922 100644 --- a/classes/Message.php +++ b/classes/Message.php @@ -39,6 +39,12 @@ class Message extends Memcached_DataObject static function saveNew($from, $to, $content, $source) { + $sender = Profile::staticGet('id', $from); + + if (!$sender->hasRight(Right::NEWMESSAGE)) { + throw new ClientException(_('You are banned from sending direct messages.')); + } + $msg = new Message(); $msg->from_profile = $from; diff --git a/classes/Notice.php b/classes/Notice.php index 291e6202b..1db431f2a 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -195,22 +195,19 @@ class Notice extends Memcached_DataObject ' take a breather and post again in a few minutes.')); } - $banned = common_config('profile', 'banned'); - - if ( in_array($profile_id, $banned) || in_array($profile->nickname, $banned)) { - common_log(LOG_WARNING, "Attempted post from banned user: $profile->nickname (user id = $profile_id)."); + if (!$profile->hasRight(Right::NEWNOTICE)) { + common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $profile->nickname); throw new ClientException(_('You are banned from posting notices on this site.')); } $notice = new Notice(); $notice->profile_id = $profile_id; - $blacklist = common_config('public', 'blacklist'); $autosource = common_config('public', 'autosource'); - # Blacklisted are non-false, but not 1, either + # Sandboxed are non-false, but not 1, either - if (($blacklist && in_array($profile_id, $blacklist)) || + if (!$user->hasRight(Right::PUBLICNOTICE) || ($source && $autosource && in_array($source, $autosource))) { $notice->is_local = Notice::LOCAL_NONPUBLIC; } else { diff --git a/classes/Plugin_DataObject.php b/classes/Plugin_DataObject.php new file mode 100644 index 000000000..d5cecf0f7 --- /dev/null +++ b/classes/Plugin_DataObject.php @@ -0,0 +1,195 @@ +<?php +/* + * StatusNet - the distributed open-source microblogging tool + * Copyright (C) 2008, 2009, StatusNet, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 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 Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } + +require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; + +abstract class Plugin_DataObject extends Memcached_DataObject +{ + function table() { + static $table = null; + if($table == null) { + $table = array(); + $DB = $this->getDatabaseConnection(); + $dbtype = $DB->phptype; + $tableDef = $this->tableDef(); + foreach($tableDef->columns as $columnDef){ + switch(strtoupper($columnDef->type)) { + /*shamelessly copied from DB_DataObject_Generator*/ + case 'INT': + case 'INT2': // postgres + case 'INT4': // postgres + case 'INT8': // postgres + case 'SERIAL4': // postgres + case 'SERIAL8': // postgres + case 'INTEGER': + case 'TINYINT': + case 'SMALLINT': + case 'MEDIUMINT': + case 'BIGINT': + $type = DB_DATAOBJECT_INT; + if ($columnDef->size == 1) { + $type += DB_DATAOBJECT_BOOL; + } + break; + + case 'REAL': + case 'DOUBLE': + case 'DOUBLE PRECISION': // double precision (firebird) + case 'FLOAT': + case 'FLOAT4': // real (postgres) + case 'FLOAT8': // double precision (postgres) + case 'DECIMAL': + case 'MONEY': // mssql and maybe others + case 'NUMERIC': + case 'NUMBER': // oci8 + $type = DB_DATAOBJECT_INT; // should really by FLOAT!!! / MONEY... + break; + + case 'YEAR': + $type = DB_DATAOBJECT_INT; + break; + + case 'BIT': + case 'BOOL': + case 'BOOLEAN': + + $type = DB_DATAOBJECT_BOOL; + // postgres needs to quote '0' + if ($dbtype == 'pgsql') { + $type += DB_DATAOBJECT_STR; + } + break; + + case 'STRING': + case 'CHAR': + case 'VARCHAR': + case 'VARCHAR2': + case 'TINYTEXT': + + case 'ENUM': + case 'SET': // not really but oh well + + case 'POINT': // mysql geometry stuff - not really string - but will do.. + + case 'TIMESTAMPTZ': // postgres + case 'BPCHAR': // postgres + case 'INTERVAL': // postgres (eg. '12 days') + + case 'CIDR': // postgres IP net spec + case 'INET': // postgres IP + case 'MACADDR': // postgress network Mac address. + + case 'INTEGER[]': // postgres type + case 'BOOLEAN[]': // postgres type + + $type = DB_DATAOBJECT_STR; + break; + + case 'TEXT': + case 'MEDIUMTEXT': + case 'LONGTEXT': + + $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TXT; + break; + + + case 'DATE': + $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE; + break; + + case 'TIME': + $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_TIME; + break; + + + case 'DATETIME': + + $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; + break; + + case 'TIMESTAMP': // do other databases use this??? + + $type = ($dbtype == 'mysql') ? + DB_DATAOBJECT_MYSQLTIMESTAMP : + DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE + DB_DATAOBJECT_TIME; + break; + + + case 'BLOB': /// these should really be ignored!!!??? + case 'TINYBLOB': + case 'MEDIUMBLOB': + case 'LONGBLOB': + + case 'CLOB': // oracle character lob support + + case 'BYTEA': // postgres blob support.. + $type = DB_DATAOBJECT_STR + DB_DATAOBJECT_BLOB; + break; + + default: + throw new Exception("Cannot handle datatype: $columnDef->type"); + } + if(! $columnDef->nullable) { + $type+=DB_DATAOBJECT_NOTNULL; + } + $table[$columnDef->name]=$type; + } + } + return $table; + } + + function keys() { + static $keys = null; + if($keys == null) { + $keys = array(); + $tableDef = $this->tableDef(); + foreach($tableDef->columns as $columnDef){ + if($columnDef->key != null){ + $keys[] = $columnDef->name; + } + } + } + return $keys; + } + + function sequenceKey() { + static $sequenceKey = null; + if($sequenceKey == null) { + $sequenceKey = array(false,false); + $tableDef = $this->tableDef(); + foreach($tableDef->columns as $columnDef){ + if($columnDef->key == 'PRI' && $columnDef->auto_increment){ + $sequenceKey=array($columnDef->name,true); + } + } + } + return $sequenceKey; + } + + /** + * Get the TableDef object that represents the table backing this class + * Ideally, this function would a static function, but PHP doesn't allow + * abstract static functions + * @return TableDef TableDef instance + */ + abstract function tableDef(); +} + diff --git a/classes/Profile.php b/classes/Profile.php index 7c1e9db33..1b9cdb52f 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -310,10 +310,12 @@ class Profile extends Memcached_DataObject 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; + if ($offset>0 && !is_null($limit)){ + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } } $profile = new Profile(); @@ -333,11 +335,13 @@ class Profile extends Memcached_DataObject 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; - if ($offset) { - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; + if ($offset>0 && !is_null($limit)){ + if ($offset) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } } } @@ -587,4 +591,124 @@ class Profile extends Memcached_DataObject return $location; } + + function hasRole($name) + { + $role = Profile_role::pkeyGet(array('profile_id' => $this->id, + 'role' => $name)); + return (!empty($role)); + } + + function grantRole($name) + { + $role = new Profile_role(); + + $role->profile_id = $this->id; + $role->role = $name; + $role->created = common_sql_now(); + + $result = $role->insert(); + + if (!$result) { + common_log_db_error($role, 'INSERT', __FILE__); + return false; + } + + return true; + } + + function revokeRole($name) + { + $role = Profile_role::pkeyGet(array('profile_id' => $this->id, + 'role' => $name)); + + if (empty($role)) { + throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.'); + } + + $result = $role->delete(); + + if (!$result) { + common_log_db_error($role, 'DELETE', __FILE__); + throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.'); + } + + return true; + } + + function isSandboxed() + { + return $this->hasRole(Profile_role::SANDBOXED); + } + + function isSilenced() + { + return $this->hasRole(Profile_role::SILENCED); + } + + function sandbox() + { + $this->grantRole(Profile_role::SANDBOXED); + } + + function unsandbox() + { + $this->revokeRole(Profile_role::SANDBOXED); + } + + function silence() + { + $this->grantRole(Profile_role::SILENCED); + } + + function unsilence() + { + $this->revokeRole(Profile_role::SILENCED); + } + + /** + * Does this user have the right to do X? + * + * With our role-based authorization, this is merely a lookup for whether the user + * has a particular role. The implementation currently uses a switch statement + * to determine if the user has the pre-defined role to exercise the right. Future + * implementations may allow per-site roles, and different mappings of roles to rights. + * + * @param $right string Name of the right, usually a constant in class Right + * @return boolean whether the user has the right in question + */ + + function hasRight($right) + { + $result = false; + if (Event::handle('UserRightsCheck', array($this, $right, &$result))) { + switch ($right) + { + case Right::DELETEOTHERSNOTICE: + case Right::SANDBOXUSER: + case Right::SILENCEUSER: + case Right::DELETEUSER: + $result = $this->hasRole(Profile_role::MODERATOR); + break; + case Right::CONFIGURESITE: + $result = $this->hasRole(Profile_role::ADMINISTRATOR); + break; + case Right::NEWNOTICE: + case Right::NEWMESSAGE: + case Right::SUBSCRIBE: + $result = !$this->isSilenced(); + break; + case Right::PUBLICNOTICE: + case Right::EMAILONREPLY: + case Right::EMAILONSUBSCRIBE: + case Right::EMAILONFAVE: + $result = !$this->isSandboxed(); + break; + default: + $result = false; + break; + } + } + return $result; + } } diff --git a/classes/User_role.php b/classes/Profile_role.php index fc3806897..afa7fb74e 100644 --- a/classes/User_role.php +++ b/classes/Profile_role.php @@ -1,7 +1,7 @@ <?php /* * StatusNet - the distributed open-source microblogging tool - * Copyright (C) 2008, 2009, StatusNet, Inc. + * Copyright (C) 2009, StatusNet, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -10,42 +10,46 @@ * * 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 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -if (!defined('STATUSNET') && !defined('LACONICA')) { exit(1); } +if (!defined('STATUSNET')) { + exit(1); +} /** - * Table Definition for user_role + * Table Definition for profile_role */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class User_role extends Memcached_DataObject +class Profile_role extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ - public $__table = 'user_role'; // table name - public $user_id; // int(4) primary_key not_null + public $__table = 'profile_role'; // table name + public $profile_id; // int(4) primary_key not_null public $role; // varchar(32) primary_key not_null - public $created; // datetime() not_null + public $created; // datetime not_null default_0000-00-00%2000%3A00%3A00 /* Static get */ - function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User_role',$k,$v); } + function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('Profile_role',$k,$v); } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE function &pkeyGet($kv) { - return Memcached_DataObject::pkeyGet('User_role', $kv); + return Memcached_DataObject::pkeyGet('Profile_role', $kv); } const MODERATOR = 'moderator'; const ADMINISTRATOR = 'administrator'; + const SANDBOXED = 'sandboxed'; + const SILENCED = 'silenced'; } diff --git a/classes/User.php b/classes/User.php index 447a34141..f905ea2b7 100644 --- a/classes/User.php +++ b/classes/User.php @@ -114,7 +114,7 @@ class User extends Memcached_DataObject return $result; } - function allowed_nickname($nickname) + static function allowed_nickname($nickname) { // XXX: should already be validated for size, content, etc. $blacklist = common_config('nickname', 'blacklist'); @@ -190,7 +190,17 @@ class User extends Memcached_DataObject $profile->query('BEGIN'); + if(!empty($email)) + { + $email = common_canonical_email($email); + } + + $nickname = common_canonical_nickname($nickname); $profile->nickname = $nickname; + if(! User::allowed_nickname($nickname)){ + common_log(LOG_WARNING, sprintf("Attempted to register a nickname that is not allowed: %s", $profile->nickname), + __FILE__); + } $profile->profileurl = common_profile_url($nickname); if (!empty($fullname)) { @@ -242,6 +252,10 @@ class User extends Memcached_DataObject } } + if(isset($email_confirmed) && $email_confirmed) { + $user->email = $email; + } + // This flag is ignored but still set to 1 $user->inboxed = 1; @@ -563,11 +577,13 @@ class User extends Memcached_DataObject 'WHERE group_member.profile_id = %d ' . 'ORDER BY group_member.created DESC '; - if ($offset) { - if (common_config('db','type') == 'pgsql') { - $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; - } else { - $qry .= ' LIMIT ' . $offset . ', ' . $limit; + if ($offset>0 && !is_null($limit)) { + if ($offset) { + if (common_config('db','type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } } } @@ -643,80 +659,10 @@ class User extends Memcached_DataObject return Design::staticGet('id', $this->design_id); } - function hasRole($name) - { - $role = User_role::pkeyGet(array('user_id' => $this->id, - 'role' => $name)); - return (!empty($role)); - } - - function grantRole($name) - { - $role = new User_role(); - - $role->user_id = $this->id; - $role->role = $name; - $role->created = common_sql_now(); - - $result = $role->insert(); - - if (!$result) { - common_log_db_error($role, 'INSERT', __FILE__); - return false; - } - - return true; - } - - function revokeRole($name) - { - $role = User_role::pkeyGet(array('user_id' => $this->id, - 'role' => $name)); - - if (empty($role)) { - throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; does not exist.'); - } - - $result = $role->delete(); - - if (!$result) { - common_log_db_error($role, 'DELETE', __FILE__); - throw new Exception('Cannot revoke role "'.$name.'" for user #'.$this->id.'; database error.'); - } - - return true; - } - - /** - * Does this user have the right to do X? - * - * With our role-based authorization, this is merely a lookup for whether the user - * has a particular role. The implementation currently uses a switch statement - * to determine if the user has the pre-defined role to exercise the right. Future - * implementations may allow per-site roles, and different mappings of roles to rights. - * - * @param $right string Name of the right, usually a constant in class Right - * @return boolean whether the user has the right in question - */ - function hasRight($right) { - $result = false; - if (Event::handle('UserRightsCheck', array($this, $right, &$result))) { - switch ($right) - { - case Right::DELETEOTHERSNOTICE: - $result = $this->hasRole(User_role::MODERATOR); - break; - case Right::CONFIGURESITE: - $result = $this->hasRole(User_role::ADMINISTRATOR); - break; - default: - $result = false; - break; - } - } - return $result; + $profile = $this->getProfile(); + return $profile->hasRight($right); } function delete() @@ -761,4 +707,34 @@ class User extends Memcached_DataObject $block->delete(); // XXX delete group block? Reset blocker? } + + function hasRole($name) + { + $profile = $this->getProfile(); + return $profile->hasRole($name); + } + + function grantRole($name) + { + $profile = $this->getProfile(); + return $profile->grantRole($name); + } + + function revokeRole($name) + { + $profile = $this->getProfile(); + return $profile->revokeRole($name); + } + + function isSandboxed() + { + $profile = $this->getProfile(); + return $profile->isSandboxed(); + } + + function isSilenced() + { + $profile = $this->getProfile(); + return $profile->isSilenced(); + } } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index 912d05cdf..b2509dac5 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -253,6 +253,15 @@ modified = 384 [location_namespace__keys] id = K +[login_token] +user_id = 129 +token = 130 +created = 142 +modified = 384 + +[login_token__keys] +user_id = K + [message] id = 129 uri = 2 @@ -358,6 +367,15 @@ modified = 384 blocker = K blocked = K +[profile_role] +profile_id = 129 +role = 130 +created = 142 + +[profile_role__keys] +profile_id = K +role = K + [profile_tag] tagger = 129 tagged = 129 @@ -524,45 +542,4 @@ created = 142 modified = 384 [user_group__keys] -id = N - -[user_openid] -canonical = 130 -display = 130 -user_id = 129 -created = 142 -modified = 384 - -[user_openid__keys] -canonical = K -display = U - -[user_openid_trustroot] -trustroot = 130 -user_id = 129 -created = 142 -modified = 384 - -[user_openid__keys] -trustroot = K -user_id = K - -[user_role] -user_id = 129 -role = 130 -created = 142 - -[user_role__keys] -user_id = K -role = K - -[login_token] -user_id = 129 -token = 130 -created = 142 -modified = 384 - -[login_token__keys] -user_id = K -token = K - +id = N
\ No newline at end of file |