summaryrefslogtreecommitdiff
path: root/classes
diff options
context:
space:
mode:
authorEvan Prodromou <evan@status.net>2009-11-17 08:04:14 -0500
committerEvan Prodromou <evan@status.net>2009-11-17 08:04:14 -0500
commitbac2d80c919a78d5cafd57f712872a90cda04847 (patch)
treed2df10a582edc0bf9e043f1c764953a290927678 /classes
parent9a1a83e8ebe5ad39838e6363f1537a1a5232b9cb (diff)
parent6a1afda259c5223449f679a64f932e36df5ebe39 (diff)
Merge branch '0.9.x' into adminpanel
Conflicts: classes/User.php
Diffstat (limited to 'classes')
-rw-r--r--classes/Message.php6
-rw-r--r--classes/Notice.php11
-rw-r--r--classes/Plugin_DataObject.php195
-rw-r--r--classes/Profile.php142
-rw-r--r--classes/Profile_role.php (renamed from classes/User_role.php)26
-rw-r--r--classes/User.php132
-rw-r--r--classes/statusnet.ini61
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