+++ /dev/null
-<?php
-/**
- * StatusNet, the distributed open-source microblogging tool
- *
- * Data class for user location preferences
- *
- * PHP version 5
- *
- * LICENCE: 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/>.
- *
- * @category Data
- * @package StatusNet
- * @author Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet Inc.
- * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
- * @link http://status.net/
- */
-
-class Inbox extends Managed_DataObject {
- const BOXCAR = 128;
- const MAX_NOTICES = 1024;
-
- ###START_AUTOCODE
- /* the code below is auto generated do not remove the above tag */
-
- public $__table = 'inbox'; // table name
- public $user_id; // int(4) primary_key not_null
- public $notice_ids; // blob
-
- /* the code above is auto generated do not remove the tag below */
- ###END_AUTOCODE
-
- public static function schemaDef()
- {
- return array(
- 'fields' => array(
- 'user_id' => array('type' => 'int', 'not null' => true, 'description' => 'user receiving the notice'),
- 'notice_ids' => array('type' => 'blob', 'description' => 'packed list of notice ids'),
- ),
- 'primary key' => array('user_id'),
- 'foreign keys' => array(
- 'inbox_user_id_fkey' => array('user', array('user_id' => 'id')),
- ),
- );
- }
-
- /**
- * Append the given notice to the given user's inbox.
- * Caching updates are managed for the inbox itself.
- *
- * If the notice is already in this inbox, the second
- * add will be silently dropped.
- *
- * @param int @user_id
- * @param int $notice_id
- * @return boolean success
- */
- static function insertNotice(Notice $notice, $user_id)
- {
- // Going straight to the DB rather than trusting our caching
- // during an update. Note: not using DB_DataObject::staticGet,
- // which is unsafe to use directly (in-process caching causes
- // memory leaks, which accumulate in queue processes).
- $inbox = new Inbox();
- $inbox->get('user_id', $user_id);
-
- if (empty($inbox)) {
- return false;
- }
-
- $ids = $inbox->unpack();
- if (in_array(intval($notice->id), $ids)) {
- // Already in there, we probably re-ran some inbox adds
- // due to an error. Skip the dupe silently.
- return true;
- }
-
- $result = $inbox->query(sprintf('UPDATE inbox '.
- 'SET notice_ids = concat(cast(0x%08x as binary(4)), '.
- 'SUBSTR(notice_ids, 1, %d)) '.
- 'WHERE user_id = %d',
- $notice->id,
- 4 * (self::MAX_NOTICES - 1),
- $user_id));
-
- if ($result !== false) {
- self::blow('inbox:user_id:%d', $user_id);
- }
-
- return $result;
- }
-
- static function bulkInsert(Notice $notice, array $user_ids)
- {
- foreach ($user_ids as $user_id)
- {
- self::insertNotice($notice, $user_id);
- }
- }
-
- /**
- * Saves a list of integer notice_ids into a packed blob in this object.
- * @param array $ids list of integer notice_ids
- */
- function pack(array $ids)
- {
- $this->notice_ids = call_user_func_array('pack', array_merge(array('N*'), $ids));
- }
-
- /**
- * @return array of integer notice_ids
- */
- function unpack()
- {
- return unpack('N*', $this->notice_ids);
- }
-}
return $ni;
}
- /**
- * Adds this notice to the inboxes of each local user who should receive
- * it, based on author subscriptions, group memberships, and @-replies.
- *
- * Warning: running a second time currently will make items appear
- * multiple times in users' inboxes.
- *
- * @fixme make more robust against errors
- * @fixme break up massive deliveries to smaller background tasks
- *
- * @param array $groups optional list of Group objects;
- * if left empty, will be loaded from group_inbox records
- * @param array $recipient optional list of reply profile ids
- * if left empty, will be loaded from reply records
- */
- function addToInboxes(array $groups=null, array $recipients=null)
- {
- $ni = $this->whoGets($groups, $recipients);
-
- $ids = array_keys($ni);
-
- // Bulk insert
- Inbox::bulkInsert($this, $ids);
-
- return;
- }
-
function getSubscribedUsers()
{
$user = new User();
return false;
}
- // Everyone gets an inbox
-
- $inbox = new Inbox();
-
- $inbox->user_id = $user->id;
- $inbox->notice_ids = '';
-
- $result = $inbox->insert();
-
- if (!$result) {
- common_log_db_error($inbox, 'INSERT', __FILE__);
- return false;
- }
-
// Everyone is subscribed to themself
$subscription = new Subscription();
'Location_namespace',
'Login_token',
'User_location_prefs',
- 'Inbox',
'User_im_prefs',
'Conversation',
'Local_group',
* If this function indicates failure, a warning will be logged
* and the item is placed back in the queue to be re-run.
*
- * @fixme addToInboxes is known to fail sometimes with large recipient sets
- *
* @param Notice $notice
* @return boolean true on success, false on failure
*/
function handle($notice)
{
- try {
- $notice->addToInboxes();
- } catch (Exception $e) {
- $this->logit($notice, $e);
- }
-
try {
$notice->sendReplyNotifications();
} catch (Exception $e) {
if ($scoped === null) {
$scoped = Profile::current();
}
- // Note: we don't use CachingNoticeStream since RawInboxNoticeStream
- // uses Inbox::getKV(), which is cached.
+ // FIXME: we don't use CachingNoticeStream - but maybe we should?
parent::__construct(new RawInboxNoticeStream($target), $scoped);
}
}
*/
class InboxTagCloudSection extends TagCloudSection
{
+ const MAX_NOTICES = 1024; // legacy value for "Inbox" table size when that existed
+
protected $target = null;
function __construct($out=null, Profile $target)
{
$profile = Profile::current();
- $keypart = sprintf('Inbox:notice_tag:%d:%d', $this->target,
- $profile instanceof Profile ? $profile->id : 0);
+ $stream = new InboxNoticeStream($this->target, $profile);
- $tag = Memcached_DataObject::cacheGet($keypart);
+ $ids = $stream->getNoticeIds(0, self::MAX_NOTICES, null, null);
- if ($tag === false) {
+ if (empty($ids)) {
+ $tag = array();
+ } else {
+ $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
+ // @fixme should we use the cutoff too? Doesn't help with indexing per-user.
- $stream = new InboxNoticeStream($this->target, $profile);
+ $qry = 'SELECT notice_tag.tag, '.
+ $weightexpr . ' as weight ' .
+ 'FROM notice_tag JOIN notice ' .
+ 'ON notice_tag.notice_id = notice.id ' .
+ 'WHERE notice.id in (' . implode(',', $ids) . ')'.
+ 'GROUP BY notice_tag.tag ' .
+ 'ORDER BY weight DESC ';
- $ids = $stream->getNoticeIds(0, Inbox::MAX_NOTICES, null, null);
+ $limit = TAGS_PER_SECTION;
+ $offset = 0;
- if (empty($ids)) {
- $tag = array();
+ if (common_config('db','type') == 'pgsql') {
+ $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
} else {
- $weightexpr = common_sql_weight('notice_tag.created', common_config('tag', 'dropoff'));
- // @fixme should we use the cutoff too? Doesn't help with indexing per-user.
-
- $qry = 'SELECT notice_tag.tag, '.
- $weightexpr . ' as weight ' .
- 'FROM notice_tag JOIN notice ' .
- 'ON notice_tag.notice_id = notice.id ' .
- 'WHERE notice.id in (' . implode(',', $ids) . ')'.
- 'GROUP BY notice_tag.tag ' .
- 'ORDER BY weight DESC ';
-
- $limit = TAGS_PER_SECTION;
- $offset = 0;
-
- if (common_config('db','type') == 'pgsql') {
- $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset;
- } else {
- $qry .= ' LIMIT ' . $offset . ', ' . $limit;
- }
+ $qry .= ' LIMIT ' . $offset . ', ' . $limit;
+ }
- $t = new Notice_tag();
+ $t = new Notice_tag();
- $t->query($qry);
+ $t->query($qry);
- $tag = array();
+ $tag = array();
- while ($t->fetch()) {
- $tag[] = clone($t);
- }
+ while ($t->fetch()) {
+ $tag[] = clone($t);
}
-
- Memcached_DataObject::cacheSet($keypart, $tag, 3600);
}
return new ArrayWrapper($tag);
if ($flink instanceof Foreign_link) {
common_log(LOG_DEBUG, "TweetInQueueHandler - Got flink so add notice ".
$notice->id." to inbox ".$flink->user_id);
- // @fixme this should go through more regular channels?
- Inbox::insertNotice($notice, $flink->user_id);
- }else {
+ // FIXME: How should a Twitter user get their Inbox filled with foreign tweets?
+ } else {
common_log(LOG_DEBUG, "TweetInQueueHandler - No flink found for foreign user ".$receiver);
}
}
$importer = new TwitterImport();
printf("\timporting...");
$notice = $importer->importStatus($data);
- if ($notice instanceof Notice) {
- global $myuser;
- Inbox::insertNotice($notice, $myuser->id);
- printf(" %s\n", $notice->id);
- } else {
+ if (!$notice instanceof Notice) {
printf(" FAIL\n");
}
}
fixupNoticeRendered();
fixupNoticeConversation();
initConversation();
- initInbox();
fixupGroupURI();
initGroupProfileId();
printfnq("DONE.\n");
}
-function initInbox()
-{
- printfnq("Ensuring all users have an inbox...");
-
- $user = new User();
- $user->whereAdd('not exists (select user_id from inbox where user_id = user.id)');
- $user->orderBy('id');
-
- if ($user->find()) {
-
- while ($user->fetch()) {
-
- try {
- $notice = new Notice();
-
- $notice->selectAdd();
- $notice->selectAdd('id');
- $notice->joinAdd(array('profile_id', 'subscription:subscribed'));
- $notice->whereAdd('subscription.subscriber = ' . $user->id);
- $notice->whereAdd('notice.created >= subscription.created');
-
- $ids = array();
-
- if ($notice->find()) {
- while ($notice->fetch()) {
- $ids[] = $notice->id;
- }
- }
-
- $notice = null;
-
- $inbox = new Inbox();
- $inbox->user_id = $user->id;
- $inbox->pack($ids);
- $inbox->insert();
- } catch (Exception $e) {
- printv("Error initializing inbox: " . $e->getMessage());
- }
- }
- }
-
- printfnq("DONE.\n");
-}
-
function initGroupProfileId()
{
printfnq("Ensuring all User_group entries have a Profile and profile_id...");