gnu-social/classes/User.php
Evan Prodromou 02a3f24b92 single function for important streams, with memcached support
I moved the 4 streams for a user (with friends, faves, replies,
personal) into functions on the User object. Added a helper function
in Notice for making notice streams. Also, will fetch notice streams
out of the memcached server, if possible. Made the API, RSS, and HTML
output all use the same streams (hopefully cached).

Added some code to Notice to blow the cache when a notice is posted.
Also, added code to favor and disfavor actions to blow the faves
cache, too.

darcs-hash:20080928120119-5ed1f-ead542348bcd3cf315be6f42934353154402eb16.gz
2008-09-28 08:01:19 -04:00

373 lines
10 KiB
PHP

<?php
/*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, Controlez-Vous, 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('LACONICA')) { exit(1); }
/**
* Table Definition for user
*/
require_once INSTALLDIR.'/classes/Memcached_DataObject.php';
require_once 'Validate.php';
require_once(INSTALLDIR.'/lib/noticewrapper.php');
class User extends Memcached_DataObject
{
###START_AUTOCODE
/* the code below is auto generated do not remove the above tag */
public $__table = 'user'; // table name
public $id; // int(4) primary_key not_null
public $nickname; // varchar(64) unique_key
public $password; // varchar(255)
public $email; // varchar(255) unique_key
public $incomingemail; // varchar(255) unique_key
public $emailnotifysub; // tinyint(1) default_1
public $emailnotifyfav; // tinyint(1) default_1
public $emailnotifymsg; // tinyint(1) default_1
public $emailmicroid; // tinyint(1) default_1
public $language; // varchar(50)
public $timezone; // varchar(50)
public $emailpost; // tinyint(1) default_1
public $jabber; // varchar(255) unique_key
public $jabbernotify; // tinyint(1)
public $jabberreplies; // tinyint(1)
public $jabbermicroid; // tinyint(1) default_1
public $updatefrompresence; // tinyint(1)
public $sms; // varchar(64) unique_key
public $carrier; // int(4)
public $smsnotify; // tinyint(1)
public $smsreplies; // tinyint(1)
public $smsemail; // varchar(255)
public $uri; // varchar(255) unique_key
public $autosubscribe; // tinyint(1)
public $created; // datetime() not_null
public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP
/* Static get */
function staticGet($k,$v=NULL) { return Memcached_DataObject::staticGet('User',$k,$v); }
/* the code above is auto generated do not remove the tag below */
###END_AUTOCODE
function getProfile() {
$profile = DB_DataObject::factory('profile');
$profile->id = $this->id;
if ($profile->find()) {
$profile->fetch();
return $profile;
}
return NULL;
}
function isSubscribed($other) {
assert(!is_null($other));
$sub = DB_DataObject::factory('subscription');
$sub->subscriber = $this->id;
$sub->subscribed = $other->id;
return $sub->find();
}
# 'update' won't write key columns, so we have to do it ourselves.
function updateKeys(&$orig) {
$parts = array();
foreach (array('nickname', 'email', 'jabber', 'incomingemail', 'sms', 'carrier', 'smsemail', 'language', 'timezone') as $k) {
if (strcmp($this->$k, $orig->$k) != 0) {
$parts[] = $k . ' = ' . $this->_quote($this->$k);
}
}
if (count($parts) == 0) {
# No changes
return true;
}
$toupdate = implode(', ', $parts);
$table = $this->tableName();
if(common_config('db','quote_identifiers')) {
$table = '"' . $table . '"';
}
$qry = 'UPDATE ' . $table . ' SET ' . $toupdate .
' WHERE id = ' . $this->id;
$orig->decache();
$result = $this->query($qry);
if ($result) {
$this->encache();
}
return $result;
}
function allowed_nickname($nickname) {
# XXX: should already be validated for size, content, etc.
static $blacklist = array('rss', 'xrds', 'doc', 'main',
'settings', 'notice', 'user',
'search', 'avatar', 'tag', 'tags',
'api', 'message');
$merged = array_merge($blacklist, common_config('nickname', 'blacklist'));
return !in_array($nickname, $merged);
}
function getCurrentNotice($dt=NULL) {
$profile = $this->getProfile();
if (!$profile) {
return NULL;
}
return $profile->getCurrentNotice($dt);
}
function getCarrier() {
return Sms_carrier::staticGet($this->carrier);
}
function subscribeTo($other) {
$sub = new Subscription();
$sub->subscriber = $this->id;
$sub->subscribed = $other->id;
$sub->created = common_sql_now(); # current time
if (!$sub->insert()) {
return false;
}
return true;
}
function noticesWithFriendsWindow() {
$notice = new Notice();
$notice->query('SELECT notice.* ' .
'FROM notice JOIN subscription on notice.profile_id = subscription.subscribed ' .
'WHERE subscription.subscriber = ' . $this->id . ' ' .
'ORDER BY created DESC, notice.id DESC ' .
'LIMIT 0, ' . WITHFRIENDS_CACHE_WINDOW);
}
static function register($fields) {
# MAGICALLY put fields into current scope
extract($fields);
$profile = new Profile();
$profile->query('BEGIN');
$profile->nickname = $nickname;
$profile->profileurl = common_profile_url($nickname);
if ($fullname) {
$profile->fullname = $fullname;
}
if ($homepage) {
$profile->homepage = $homepage;
}
if ($bio) {
$profile->bio = $bio;
}
if ($location) {
$profile->location = $location;
}
$profile->created = common_sql_now();
$id = $profile->insert();
if (!$id) {
common_log_db_error($profile, 'INSERT', __FILE__);
return FALSE;
}
$user = new User();
$user->id = $id;
$user->nickname = $nickname;
if ($password) { # may not have a password for OpenID users
$user->password = common_munge_password($password, $id);
}
# Users who respond to invite email have proven their ownership of that address
if ($code) {
$invite = Invitation::staticGet($code);
if ($invite && $invite->address && $invite->address_type == 'email' && $invite->address == $email) {
$user->email = $invite->address;
}
}
$user->created = common_sql_now();
$user->uri = common_user_uri($user);
$result = $user->insert();
if (!$result) {
common_log_db_error($user, 'INSERT', __FILE__);
return FALSE;
}
# Everyone is subscribed to themself
$subscription = new Subscription();
$subscription->subscriber = $user->id;
$subscription->subscribed = $user->id;
$subscription->created = $user->created;
$result = $subscription->insert();
if (!$result) {
common_log_db_error($subscription, 'INSERT', __FILE__);
return FALSE;
}
if ($email && !$user->email) {
$confirm = new Confirm_address();
$confirm->code = common_confirmation_code(128);
$confirm->user_id = $user->id;
$confirm->address = $email;
$confirm->address_type = 'email';
$result = $confirm->insert();
if (!$result) {
common_log_db_error($confirm, 'INSERT', __FILE__);
return FALSE;
}
}
if ($code && $user->email) {
$user->emailChanged();
}
$profile->query('COMMIT');
if ($email && !$user->email) {
mail_confirm_address($confirm->code,
$profile->nickname,
$email);
}
return $user;
}
# Things we do when the email changes
function emailChanged() {
$invites = new Invitation();
$invites->address = $this->email;
$invites->address_type = 'email';
if ($invites->find()) {
while ($invites->fetch()) {
$other = User::staticGet($invites->user_id);
subs_subscribe_to($other, $this);
}
}
}
function hasFave($notice) {
$fave = new Fave();
$fave->user_id = $this->id;
$fave->notice_id = $notice->id;
if ($fave->find()) {
$result = true;
} else {
$result = false;
}
$fave->free();
unset($fave);
return $result;
}
function mutuallySubscribed($other) {
return $this->isSubscribed($other) &&
$other->isSubscribed($this);
}
function mutuallySubscribedUsers() {
# 3-way join; probably should get cached
$qry = 'SELECT user.* ' .
'FROM subscription sub1 JOIN user ON sub1.subscribed = user.id ' .
'JOIN subscription sub2 ON user.id = sub2.subscriber ' .
'WHERE sub1.subscriber = %d and sub2.subscribed = %d ' .
'ORDER BY user.nickname';
$user = new User();
$user->query(sprintf($qry, $this->id, $this->id));
return $user;
}
function getReplies($offset=0, $limit=NOTICES_PER_PAGE) {
$qry =
'SELECT notice.* ' .
'FROM notice JOIN reply ON notice.id = reply.notice_id ' .
'WHERE reply.profile_id = %d ';
return Notice::getStream(sprintf($qry, $this->id),
'user:replies:'.$this->id,
$offset, $limit);
}
function getNotices($offset=0, $limit=NOTICES_PER_PAGE) {
$qry =
'SELECT * ' .
'FROM notice ' .
'WHERE profile_id = %d ';
return Notice::getStream(sprintf($qry, $this->id),
'user:notices:'.$this->id,
$offset, $limit);
}
function favoriteNotices($offset=0, $limit=NOTICES_PER_PAGE) {
$qry =
'SELECT notice.* ' .
'FROM notice JOIN fave ON notice.id = fave.notice_id ' .
'WHERE fave.profile_id = %d ';
return Notice::getStream(sprintf($qry, $this->id),
'user:faves:'.$this->id,
$offset, $limit);
}
function noticesWithFriends($offset=0, $limit=NOTICES_PER_PAGE) {
$qry =
'SELECT notice.* ' .
'FROM notice JOIN subscription ON notice.profile_id = subscription.subscribed ' .
'WHERE subscription.subscriber = %d';
return Notice::getStream(sprintf($qry, $this->id),
'user:notices_with_friends:' . $this->id,
$offset, $limit);
}
function blowFavesCache() {
$cache = common_memcache();
if ($cache) {
$cache->delete(common_cache_key('user:faves:'.$this->id));
}
}
}