From deffcc1442ab452c3cadba1d2158d24209831656 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 18 Jan 2011 16:55:51 -0500 Subject: [PATCH] non-working version of private groups --- .../PrivateGroup/Group_privacy_settings.php | 184 ++++++++++++++++++ plugins/PrivateGroup/Group_private_inbox.php | 184 ++++++++++++++++++ plugins/PrivateGroup/PrivateGroupPlugin.php | 177 +++++++++++++++++ plugins/PrivateGroup/groupinbox.php | 164 ++++++++++++++++ 4 files changed, 709 insertions(+) create mode 100644 plugins/PrivateGroup/Group_privacy_settings.php create mode 100644 plugins/PrivateGroup/Group_private_inbox.php create mode 100644 plugins/PrivateGroup/PrivateGroupPlugin.php create mode 100644 plugins/PrivateGroup/groupinbox.php diff --git a/plugins/PrivateGroup/Group_privacy_settings.php b/plugins/PrivateGroup/Group_privacy_settings.php new file mode 100644 index 0000000000..38d68c91ed --- /dev/null +++ b/plugins/PrivateGroup/Group_privacy_settings.php @@ -0,0 +1,184 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * 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 + * 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 . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +/** + * Data class for counting greetings + * + * We use the DB_DataObject framework for data classes in StatusNet. Each + * table maps to a particular data class, making it easier to manipulate + * data. + * + * Data classes should extend Memcached_DataObject, the (slightly misnamed) + * extension of DB_DataObject that provides caching, internationalization, + * and other bits of good functionality to StatusNet-specific data classes. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * @see DB_DataObject + */ + +class User_greeting_count extends Memcached_DataObject +{ + public $__table = 'user_greeting_count'; // table name + public $user_id; // int(4) primary_key not_null + public $greeting_count; // int(4) + + /** + * Get an instance by key + * + * This is a utility method to get a single instance with a given key value. + * + * @param string $k Key to use to lookup (usually 'user_id' for this class) + * @param mixed $v Value to lookup + * + * @return User_greeting_count object found, or null for no hits + * + */ + function staticGet($k, $v=null) + { + return Memcached_DataObject::staticGet('User_greeting_count', $k, $v); + } + + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + function table() + { + return array('user_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'greeting_count' => DB_DATAOBJECT_INT); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has, since it + * won't appear in StatusNet's own keys list. In most cases, this will + * simply reference your keyTypes() function. + * + * @return array list of key field names + */ + function keys() + { + return array_keys($this->keyTypes()); + } + + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. This key information is used to store and clear + * cached data, so be sure to list any key that will be used for static + * lookups. + * + * @return array associative array of key definitions, field name to type: + * 'K' for primary key: for compound keys, add an entry for each component; + * 'U' for unique keys: compound keys are not well supported here. + */ + function keyTypes() + { + return array('user_id' => 'K'); + } + + /** + * Magic formula for non-autoincrementing integer primary keys + * + * If a table has a single integer column as its primary key, DB_DataObject + * assumes that the column is auto-incrementing and makes a sequence table + * to do this incrementation. Since we don't need this for our class, we + * overload this method and return the magic formula that DB_DataObject needs. + * + * @return array magic three-false array that stops auto-incrementing. + */ + function sequenceKey() + { + return array(false, false, false); + } + + /** + * Increment a user's greeting count and return instance + * + * This method handles the ins and outs of creating a new greeting_count for a + * user or fetching the existing greeting count and incrementing its value. + * + * @param integer $user_id ID of the user to get a count for + * + * @return User_greeting_count instance for this user, with count already incremented. + */ + static function inc($user_id) + { + $gc = User_greeting_count::staticGet('user_id', $user_id); + + if (empty($gc)) { + + $gc = new User_greeting_count(); + + $gc->user_id = $user_id; + $gc->greeting_count = 1; + + $result = $gc->insert(); + + if (!$result) { + // TRANS: Exception thrown when the user greeting count could not be saved in the database. + // TRANS: %d is a user ID (number). + throw Exception(sprintf(_m("Could not save new greeting count for %d."), + $user_id)); + } + } else { + $orig = clone($gc); + + $gc->greeting_count++; + + $result = $gc->update($orig); + + if (!$result) { + // TRANS: Exception thrown when the user greeting count could not be saved in the database. + // TRANS: %d is a user ID (number). + throw Exception(sprintf(_m("Could not increment greeting count for %d."), + $user_id)); + } + } + + return $gc; + } +} diff --git a/plugins/PrivateGroup/Group_private_inbox.php b/plugins/PrivateGroup/Group_private_inbox.php new file mode 100644 index 0000000000..38d68c91ed --- /dev/null +++ b/plugins/PrivateGroup/Group_private_inbox.php @@ -0,0 +1,184 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * 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 + * 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 . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +require_once INSTALLDIR . '/classes/Memcached_DataObject.php'; + +/** + * Data class for counting greetings + * + * We use the DB_DataObject framework for data classes in StatusNet. Each + * table maps to a particular data class, making it easier to manipulate + * data. + * + * Data classes should extend Memcached_DataObject, the (slightly misnamed) + * extension of DB_DataObject that provides caching, internationalization, + * and other bits of good functionality to StatusNet-specific data classes. + * + * @category Action + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * @see DB_DataObject + */ + +class User_greeting_count extends Memcached_DataObject +{ + public $__table = 'user_greeting_count'; // table name + public $user_id; // int(4) primary_key not_null + public $greeting_count; // int(4) + + /** + * Get an instance by key + * + * This is a utility method to get a single instance with a given key value. + * + * @param string $k Key to use to lookup (usually 'user_id' for this class) + * @param mixed $v Value to lookup + * + * @return User_greeting_count object found, or null for no hits + * + */ + function staticGet($k, $v=null) + { + return Memcached_DataObject::staticGet('User_greeting_count', $k, $v); + } + + /** + * return table definition for DB_DataObject + * + * DB_DataObject needs to know something about the table to manipulate + * instances. This method provides all the DB_DataObject needs to know. + * + * @return array array of column definitions + */ + function table() + { + return array('user_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL, + 'greeting_count' => DB_DATAOBJECT_INT); + } + + /** + * return key definitions for DB_DataObject + * + * DB_DataObject needs to know about keys that the table has, since it + * won't appear in StatusNet's own keys list. In most cases, this will + * simply reference your keyTypes() function. + * + * @return array list of key field names + */ + function keys() + { + return array_keys($this->keyTypes()); + } + + /** + * return key definitions for Memcached_DataObject + * + * Our caching system uses the same key definitions, but uses a different + * method to get them. This key information is used to store and clear + * cached data, so be sure to list any key that will be used for static + * lookups. + * + * @return array associative array of key definitions, field name to type: + * 'K' for primary key: for compound keys, add an entry for each component; + * 'U' for unique keys: compound keys are not well supported here. + */ + function keyTypes() + { + return array('user_id' => 'K'); + } + + /** + * Magic formula for non-autoincrementing integer primary keys + * + * If a table has a single integer column as its primary key, DB_DataObject + * assumes that the column is auto-incrementing and makes a sequence table + * to do this incrementation. Since we don't need this for our class, we + * overload this method and return the magic formula that DB_DataObject needs. + * + * @return array magic three-false array that stops auto-incrementing. + */ + function sequenceKey() + { + return array(false, false, false); + } + + /** + * Increment a user's greeting count and return instance + * + * This method handles the ins and outs of creating a new greeting_count for a + * user or fetching the existing greeting count and incrementing its value. + * + * @param integer $user_id ID of the user to get a count for + * + * @return User_greeting_count instance for this user, with count already incremented. + */ + static function inc($user_id) + { + $gc = User_greeting_count::staticGet('user_id', $user_id); + + if (empty($gc)) { + + $gc = new User_greeting_count(); + + $gc->user_id = $user_id; + $gc->greeting_count = 1; + + $result = $gc->insert(); + + if (!$result) { + // TRANS: Exception thrown when the user greeting count could not be saved in the database. + // TRANS: %d is a user ID (number). + throw Exception(sprintf(_m("Could not save new greeting count for %d."), + $user_id)); + } + } else { + $orig = clone($gc); + + $gc->greeting_count++; + + $result = $gc->update($orig); + + if (!$result) { + // TRANS: Exception thrown when the user greeting count could not be saved in the database. + // TRANS: %d is a user ID (number). + throw Exception(sprintf(_m("Could not increment greeting count for %d."), + $user_id)); + } + } + + return $gc; + } +} diff --git a/plugins/PrivateGroup/PrivateGroupPlugin.php b/plugins/PrivateGroup/PrivateGroupPlugin.php new file mode 100644 index 0000000000..9aded1d960 --- /dev/null +++ b/plugins/PrivateGroup/PrivateGroupPlugin.php @@ -0,0 +1,177 @@ +. + * + * @category Privacy + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + // This check helps protect against security problems; + // your code file can't be executed directly from the web. + exit(1); +} + +/** + * Private groups + * + * This plugin allows users to send private messages to a group. + * + * @category Privacy + * @package StatusNet + * @author Evan Prodromou + * @copyright 2010 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ +class PrivateGroupPlugin extends Plugin +{ + /** + * Database schema setup + * + * @see Schema + * @see ColumnDef + * + * @return boolean hook value + */ + + function onCheckSchema() + { + $schema = Schema::get(); + + // For storing user-submitted flags on profiles + + $schema->ensureTable('group_privacy_settings', + array(new ColumnDef('group_id', + 'integer', + null, + false, + 'PRI'), + new ColumnDef('allow_privacy', + 'integer'), + new ColumnDef('allow_sender', + 'integer'), + new ColumnDef('created', + 'datetime'), + new ColumnDef('modified', + 'timestamp')); + + $schema->ensureTable('group_private_inbox', + array(new ColumnDef('group_id', + 'integer', + null, + false, + 'PRI'), + new ColumnDef('allow_privacy', + 'integer'), + new ColumnDef('allow_sender', + 'integer'), + new ColumnDef('created', + 'datetime'), + new ColumnDef('modified', + 'timestamp')); + + return true; + } + + /** + * Load related modules when needed + * + * @param string $cls Name of the class to be loaded + * + * @return boolean hook value + */ + + function onAutoload($cls) + { + $dir = dirname(__FILE__); + + switch ($cls) + { + case 'GroupinboxAction': + include_once $dir . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php'; + return false; + case 'Group_privacy_settings': + case 'Group_private_inbox': + include_once $dir . '/'.$cls.'.php'; + return false; + default: + return true; + } + } + + /** + * Map URLs to actions + * + * @param Net_URL_Mapper $m path-to-action mapper + * + * @return boolean hook value + */ + + function onRouterInitialized($m) + { + $m->connect('group/:nickname/inbox', + array('action' => 'groupinbox'), + array('nickname' => Nickname::DISPLAY_FMT)); + + return true; + } + + /** + * Add group inbox to the menu + * + * @param Action $action The current action handler. Use this to + * do any output. + * + * @return boolean hook value; true means continue processing, false means stop. + * + * @see Action + */ + + function onEndGroupGroupNav($groupnav) + { + $action = $groupnav->action; + $group = $groupnav->group; + + $action->menuItem(common_local_url('groupinbox', + array('nickname' => $group->nickname)), + _m('Inbox'), + _m('Private messages for this group'), + $action->trimmed('action') == 'groupinbox', + 'nav_group_inbox'); + return true; + } + + function onPluginVersion(&$versions) + { + $versions[] = array('name' => 'PrivateGroup', + 'version' => STATUSNET_VERSION, + 'author' => 'Evan Prodromou', + 'homepage' => 'http://status.net/wiki/Plugin:PrivateGroup', + 'rawdescription' => + _m('Allow posting DMs to a group.')); + return true; + } +} diff --git a/plugins/PrivateGroup/groupinbox.php b/plugins/PrivateGroup/groupinbox.php new file mode 100644 index 0000000000..a793ac6de2 --- /dev/null +++ b/plugins/PrivateGroup/groupinbox.php @@ -0,0 +1,164 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + * + * StatusNet - the distributed open-source microblogging tool + * 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 + * 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 . + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Give a warm greeting to our friendly user + * + * This sample action shows some basic ways of doing output in an action + * class. + * + * Action classes have several output methods that they override from + * the parent class. + * + * @category Sample + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://status.net/ + */ +class HelloAction extends Action +{ + var $user = null; + var $gc = null; + + /** + * Take arguments for running + * + * This method is called first, and it lets the action class get + * all its arguments and validate them. It's also the time + * to fetch any relevant data from the database. + * + * Action classes should run parent::prepare($args) as the first + * line of this method to make sure the default argument-processing + * happens. + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + function prepare($args) + { + parent::prepare($args); + + $this->user = common_current_user(); + + if (!empty($this->user)) { + $this->gc = User_greeting_count::inc($this->user->id); + } + + return true; + } + + /** + * Handle request + * + * This is the main method for handling a request. Note that + * most preparation should be done in the prepare() method; + * by the time handle() is called the action should be + * more or less ready to go. + * + * @param array $args $_REQUEST args; handled in prepare() + * + * @return void + */ + function handle($args) + { + parent::handle($args); + + $this->showPage(); + } + + /** + * Title of this page + * + * Override this method to show a custom title. + * + * @return string Title of the page + */ + function title() + { + if (empty($this->user)) { + return _m('Hello'); + } else { + return sprintf(_m('Hello, %s!'), $this->user->nickname); + } + } + + /** + * Show content in the content area + * + * The default StatusNet page has a lot of decorations: menus, + * logos, tabs, all that jazz. This method is used to show + * content in the content area of the page; it's the main + * thing you want to overload. + * + * This method also demonstrates use of a plural localized string. + * + * @return void + */ + function showContent() + { + if (empty($this->user)) { + $this->element('p', array('class' => 'greeting'), + _m('Hello, stranger!')); + } else { + $this->element('p', array('class' => 'greeting'), + sprintf(_m('Hello, %s'), $this->user->nickname)); + $this->element('p', array('class' => 'greeting_count'), + sprintf(_m('I have greeted you %d time.', + 'I have greeted you %d times.', + $this->gc->greeting_count), + $this->gc->greeting_count)); + } + } + + /** + * Return true if read only. + * + * Some actions only read from the database; others read and write. + * The simple database load-balancer built into StatusNet will + * direct read-only actions to database mirrors (if they are configured), + * and read-write actions to the master database. + * + * This defaults to false to avoid data integrity issues, but you + * should make sure to overload it for performance gains. + * + * @param array $args other arguments, if RO/RW status depends on them. + * + * @return boolean is read only action? + */ + function isReadOnly($args) + { + return false; + } +} -- 2.39.5