diff options
Diffstat (limited to 'classes')
-rw-r--r-- | classes/Channel.php | 238 | ||||
-rw-r--r-- | classes/Command.php | 419 | ||||
-rw-r--r-- | classes/CommandInterpreter.php | 198 | ||||
-rw-r--r-- | classes/Notice.php | 140 | ||||
-rw-r--r-- | classes/Notice_tag.php | 15 | ||||
-rw-r--r-- | classes/Profile_tag.php | 43 | ||||
-rw-r--r-- | classes/User.php | 29 | ||||
-rwxr-xr-x | classes/laconica.ini | 5 |
8 files changed, 146 insertions, 941 deletions
diff --git a/classes/Channel.php b/classes/Channel.php deleted file mode 100644 index fdeff21fc..000000000 --- a/classes/Channel.php +++ /dev/null @@ -1,238 +0,0 @@ -<?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); } - -class Channel -{ - - function on($user) - { - return false; - } - - function off($user) - { - return false; - } - - function output($user, $text) - { - return false; - } - - function error($user, $text) - { - return false; - } - - function source() - { - return null; - } -} - -class XMPPChannel extends Channel -{ - - var $conn = null; - - function source() - { - return 'xmpp'; - } - - function __construct($conn) - { - $this->conn = $conn; - } - - function on($user) - { - return $this->set_notify($user, 1); - } - - function off($user) - { - return $this->set_notify($user, 0); - } - - function output($user, $text) - { - $text = '['.common_config('site', 'name') . '] ' . $text; - jabber_send_message($user->jabber, $text); - } - - function error($user, $text) - { - $text = '['.common_config('site', 'name') . '] ' . $text; - jabber_send_message($user->jabber, $text); - } - - function set_notify(&$user, $notify) - { - $orig = clone($user); - $user->jabbernotify = $notify; - $result = $user->update($orig); - if (!$result) { - $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, - 'Could not set notify flag to ' . $notify . - ' for user ' . common_log_objstring($user) . - ': ' . $last_error->message); - return false; - } else { - common_log(LOG_INFO, - 'User ' . $user->nickname . ' set notify flag to ' . $notify); - return true; - } - } -} - -class WebChannel extends Channel -{ - var $out = null; - - function __construct($out=null) - { - $this->out = $out; - } - - function source() - { - return 'web'; - } - - function on($user) - { - return false; - } - - function off($user) - { - return false; - } - - function output($user, $text) - { - # XXX: buffer all output and send it at the end - # XXX: even better, redirect to appropriate page - # depending on what command was run - $this->out->startHTML(); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Command results')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'command_result'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } - - function error($user, $text) - { - common_user_error($text); - } -} - -class AjaxWebChannel extends WebChannel -{ - function output($user, $text) - { - $this->out->startHTML('text/xml;charset=utf-8'); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Command results')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'command_result'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } - - function error($user, $text) - { - $this->out->startHTML('text/xml;charset=utf-8'); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Ajax Error')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'error'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } -} - -class MailChannel extends Channel -{ - - var $addr = null; - - function source() - { - return 'mail'; - } - - function __construct($addr=null) - { - $this->addr = $addr; - } - - function on($user) - { - return $this->set_notify($user, 1); - } - - function off($user) - { - return $this->set_notify($user, 0); - } - - function output($user, $text) - { - - $headers['From'] = $user->incomingemail; - $headers['To'] = $this->addr; - - $headers['Subject'] = _('Command complete'); - - return mail_send(array($this->addr), $headers, $text); - } - - function error($user, $text) - { - - $headers['From'] = $user->incomingemail; - $headers['To'] = $this->addr; - - $headers['Subject'] = _('Command failed'); - - return mail_send(array($this->addr), $headers, $text); - } - - function set_notify($user, $value) - { - $orig = clone($user); - $user->smsnotify = $value; - $result = $user->update($orig); - if (!$result) { - common_log_db_error($user, 'UPDATE', __FILE__); - return false; - } - return true; - } -} diff --git a/classes/Command.php b/classes/Command.php deleted file mode 100644 index eacbdacb3..000000000 --- a/classes/Command.php +++ /dev/null @@ -1,419 +0,0 @@ -<?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); } - -require_once(INSTALLDIR.'/classes/Channel.php'); - -class Command -{ - - var $user = null; - - function __construct($user=null) - { - $this->user = $user; - } - - function execute($channel) - { - return false; - } -} - -class UnimplementedCommand extends Command -{ - function execute($channel) - { - $channel->error($this->user, _("Sorry, this command is not yet implemented.")); - } -} - -class TrackingCommand extends UnimplementedCommand -{ -} - -class TrackOffCommand extends UnimplementedCommand -{ -} - -class TrackCommand extends UnimplementedCommand -{ - var $word = null; - function __construct($user, $word) - { - parent::__construct($user); - $this->word = $word; - } -} - -class UntrackCommand extends UnimplementedCommand -{ - var $word = null; - function __construct($user, $word) - { - parent::__construct($user); - $this->word = $word; - } -} - -class NudgeCommand extends UnimplementedCommand -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } -} - -class InviteCommand extends UnimplementedCommand -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } -} - -class StatsCommand extends Command -{ - function execute($channel) - { - - $subs = new Subscription(); - $subs->subscriber = $this->user->id; - $subs_count = (int) $subs->count() - 1; - - $subbed = new Subscription(); - $subbed->subscribed = $this->user->id; - $subbed_count = (int) $subbed->count() - 1; - - $notices = new Notice(); - $notices->profile_id = $this->user->id; - $notice_count = (int) $notices->count(); - - $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n". - "Subscribers: %2\$s\n". - "Notices: %3\$s"), - $subs_count, - $subbed_count, - $notice_count)); - } -} - -class FavCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - - $recipient = - common_relative_profile($this->user, common_canonical_nickname($this->other)); - - if (!$recipient) { - $channel->error($this->user, _('No such user.')); - return; - } - $notice = $recipient->getCurrentNotice(); - if (!$notice) { - $channel->error($this->user, _('User has no last notice')); - return; - } - - $fave = Fave::addNew($this->user, $notice); - - if (!$fave) { - $channel->error($this->user, _('Could not create favorite.')); - return; - } - - $other = User::staticGet('id', $recipient->id); - - if ($other && $other->id != $user->id) { - if ($other->email && $other->emailnotifyfav) { - mail_notify_fave($other, $this->user, $notice); - } - } - - $this->user->blowFavesCache(); - - $channel->output($this->user, _('Notice marked as fave.')); - } -} - -class WhoisCommand extends Command -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - $recipient = - common_relative_profile($this->user, common_canonical_nickname($this->other)); - - if (!$recipient) { - $channel->error($this->user, _('No such user.')); - return; - } - - $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname, - $recipient->profileurl); - if ($recipient->fullname) { - $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname); - } - if ($recipient->location) { - $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location); - } - if ($recipient->homepage) { - $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage); - } - if ($recipient->bio) { - $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio); - } - $channel->output($this->user, $whois); - } -} - -class MessageCommand extends Command -{ - var $other = null; - var $text = null; - function __construct($user, $other, $text) - { - parent::__construct($user); - $this->other = $other; - $this->text = $text; - } - - function execute($channel) - { - $other = User::staticGet('nickname', common_canonical_nickname($this->other)); - $len = mb_strlen($this->text); - if ($len == 0) { - $channel->error($this->user, _('No content!')); - return; - } else if ($len > 140) { - $content = common_shorten_links($content); - if (mb_strlen($content) > 140) { - $channel->error($this->user, sprintf(_('Message too long - maximum is 140 characters, you sent %d'), $len)); - return; - } - } - - if (!$other) { - $channel->error($this->user, _('No such user.')); - return; - } else if (!$this->user->mutuallySubscribed($other)) { - $channel->error($this->user, _('You can\'t send a message to this user.')); - return; - } else if ($this->user->id == $other->id) { - $channel->error($this->user, _('Don\'t send a message to yourself; just say it to yourself quietly instead.')); - return; - } - $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source()); - if ($message) { - $channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other)); - } else { - $channel->error($this->user, _('Error sending direct message.')); - } - } -} - -class GetCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - $target_nickname = common_canonical_nickname($this->other); - - $target = - common_relative_profile($this->user, $target_nickname); - - if (!$target) { - $channel->error($this->user, _('No such user.')); - return; - } - $notice = $target->getCurrentNotice(); - if (!$notice) { - $channel->error($this->user, _('User has no last notice')); - return; - } - $notice_content = $notice->content; - - $channel->output($this->user, $target_nickname . ": " . $notice_content); - } -} - -class SubCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - - if (!$this->other) { - $channel->error($this->user, _('Specify the name of the user to subscribe to')); - return; - } - - $result = subs_subscribe_user($this->user, $this->other); - - if ($result == 'true') { - $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); - } else { - $channel->error($this->user, $result); - } - } -} - -class UnsubCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - if(!$this->other) { - $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); - return; - } - - $result=subs_unsubscribe_user($this->user, $this->other); - - if ($result) { - $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); - } else { - $channel->error($this->user, $result); - } - } -} - -class OffCommand extends Command -{ - var $other = null; - function __construct($user, $other=null) - { - parent::__construct($user); - $this->other = $other; - } - function execute($channel) - { - if ($other) { - $channel->error($this->user, _("Command not yet implemented.")); - } else { - if ($channel->off($this->user)) { - $channel->output($this->user, _('Notification off.')); - } else { - $channel->error($this->user, _('Can\'t turn off notification.')); - } - } - } -} - -class OnCommand extends Command -{ - var $other = null; - function __construct($user, $other=null) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - if ($other) { - $channel->error($this->user, _("Command not yet implemented.")); - } else { - if ($channel->on($this->user)) { - $channel->output($this->user, _('Notification on.')); - } else { - $channel->error($this->user, _('Can\'t turn on notification.')); - } - } - } -} - -class HelpCommand extends Command -{ - function execute($channel) - { - $channel->output($this->user, - _("Commands:\n". - "on - turn on notifications\n". - "off - turn off notifications\n". - "help - show this help\n". - "follow <nickname> - subscribe to user\n". - "leave <nickname> - unsubscribe from user\n". - "d <nickname> <text> - direct message to user\n". - "get <nickname> - get last notice from user\n". - "whois <nickname> - get profile info on user\n". - "fav <nickname> - add user's last notice as a 'fave'\n". - "stats - get your stats\n". - "stop - same as 'off'\n". - "quit - same as 'off'\n". - "sub <nickname> - same as 'follow'\n". - "unsub <nickname> - same as 'leave'\n". - "last <nickname> - same as 'get'\n". - "on <nickname> - not yet implemented.\n". - "off <nickname> - not yet implemented.\n". - "nudge <nickname> - not yet implemented.\n". - "invite <phone number> - not yet implemented.\n". - "track <word> - not yet implemented.\n". - "untrack <word> - not yet implemented.\n". - "track off - not yet implemented.\n". - "untrack all - not yet implemented.\n". - "tracks - not yet implemented.\n". - "tracking - not yet implemented.\n")); - } -} diff --git a/classes/CommandInterpreter.php b/classes/CommandInterpreter.php deleted file mode 100644 index 0679f5462..000000000 --- a/classes/CommandInterpreter.php +++ /dev/null @@ -1,198 +0,0 @@ -<?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); } - -require_once(INSTALLDIR.'/classes/Command.php'); - -class CommandInterpreter -{ - - function handle_command($user, $text) - { - # XXX: localise - - $text = preg_replace('/\s+/', ' ', trim($text)); - list($cmd, $arg) = explode(' ', $text, 2); - - # We try to support all the same commands as Twitter, see - # http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands - # There are a few compatibility commands from earlier versions of - # Laconica - - switch(strtolower($cmd)) { - case 'help': - if ($arg) { - return null; - } - return new HelpCommand($user); - case 'on': - if ($arg) { - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new OnCommand($user, $other); - } - } else { - return new OnCommand($user); - } - case 'off': - if ($arg) { - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new OffCommand($user, $other); - } - } else { - return new OffCommand($user); - } - case 'stop': - case 'quit': - if ($arg) { - return null; - } else { - return new OffCommand($user); - } - case 'follow': - case 'sub': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new SubCommand($user, $other); - } - case 'leave': - case 'unsub': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new UnsubCommand($user, $other); - } - case 'get': - case 'last': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new GetCommand($user, $other); - } - case 'd': - case 'dm': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if (!$extra) { - return null; - } else { - return new MessageCommand($user, $other, $extra); - } - case 'whois': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new WhoisCommand($user, $other); - } - case 'fav': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new FavCommand($user, $other); - } - case 'nudge': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new NudgeCommand($user, $other); - } - case 'stats': - if ($arg) { - return null; - } - return new StatsCommand($user); - case 'invite': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new InviteCommand($user, $other); - } - case 'track': - if (!$arg) { - return null; - } - list($word, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else if ($word == 'off') { - return new TrackOffCommand($user); - } else { - return new TrackCommand($user, $word); - } - case 'untrack': - if (!$arg) { - return null; - } - list($word, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else if ($word == 'all') { - return new TrackOffCommand($user); - } else { - return new UntrackCommand($user, $word); - } - case 'tracks': - case 'tracking': - if ($arg) { - return null; - } - return new TrackingCommand($user); - default: - return false; - } - } -} - diff --git a/classes/Notice.php b/classes/Notice.php index 329988368..9b5194a5c 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -34,22 +34,24 @@ class Notice extends Memcached_DataObject ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ - public $__table = 'notice'; // table name - public $id; // int(4) primary_key not_null - public $profile_id; // int(4) not_null + public $__table = 'notice'; // table name + public $id; // int(4) primary_key not_null + public $profile_id; // int(4) not_null public $uri; // varchar(255) unique_key public $content; // varchar(140) - public $rendered; // text() + public $rendered; // text() public $url; // varchar(255) - public $created; // datetime() not_null - public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP - public $reply_to; // int(4) - public $is_local; // tinyint(1) - public $source; // varchar(32) + public $created; // datetime() not_null + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + public $reply_to; // int(4) + public $is_local; // tinyint(1) + public $source; // varchar(32) + public $conversation; // int(4) /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Notice',$k,$v); } + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Notice',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE @@ -94,23 +96,28 @@ class Notice extends Memcached_DataObject /* Add them to the database */ foreach(array_unique($match[1]) as $hashtag) { /* elide characters we don't want in the tag */ - $hashtag = common_canonical_tag($hashtag); - - $tag = DB_DataObject::factory('Notice_tag'); - $tag->notice_id = $this->id; - $tag->tag = $hashtag; - $tag->created = $this->created; - $id = $tag->insert(); - if (!$id) { - $last_error = PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, 'DB error inserting hashtag: ' . $last_error->message); - common_server_error(sprintf(_('DB error inserting hashtag: %s'), $last_error->message)); - return; - } + $this->saveTag($hashtag); } return true; } + function saveTag($hashtag) + { + $hashtag = common_canonical_tag($hashtag); + + $tag = new Notice_tag(); + $tag->notice_id = $this->id; + $tag->tag = $hashtag; + $tag->created = $this->created; + $id = $tag->insert(); + + if (!$id) { + throw new ServerException(sprintf(_('DB error inserting hashtag: %s'), + $last_error->message)); + return; + } + } + static function saveNew($profile_id, $content, $source=null, $is_local=1, $reply_to=null, $uri=null) { $profile = Profile::staticGet($profile_id); @@ -136,10 +143,12 @@ class Notice extends Memcached_DataObject $notice->profile_id = $profile_id; $blacklist = common_config('public', 'blacklist'); + $autosource = common_config('public', 'autosource'); # Blacklisted are non-false, but not 1, either - if ($blacklist && in_array($profile_id, $blacklist)) { + if (($blacklist && in_array($profile_id, $blacklist)) || + ($source && $autosource && in_array($source, $autosource))) { $notice->is_local = -1; } else { $notice->is_local = $is_local; @@ -147,39 +156,51 @@ class Notice extends Memcached_DataObject $notice->query('BEGIN'); - $notice->reply_to = $reply_to; $notice->created = common_sql_now(); $notice->content = common_shorten_links($content); $notice->rendered = common_render_content($notice->content, $notice); $notice->source = $source; $notice->uri = $uri; - $id = $notice->insert(); - - if (!$id) { - common_log_db_error($notice, 'INSERT', __FILE__); - return _('Problem saving notice.'); + if (!empty($reply_to)) { + $reply_notice = Notice::staticGet('id', $reply_to); + if (!empty($reply_notice)) { + $notice->reply_to = $reply_to; + $notice->conversation = $reply_notice->conversation; + } } - # Update the URI after the notice is in the database - if (!$uri) { - $orig = clone($notice); - $notice->uri = common_notice_uri($notice); + if (Event::handle('StartNoticeSave', array(&$notice))) { + + $id = $notice->insert(); - if (!$notice->update($orig)) { - common_log_db_error($notice, 'UPDATE', __FILE__); + if (!$id) { + common_log_db_error($notice, 'INSERT', __FILE__); return _('Problem saving notice.'); } - } - # XXX: do we need to change this for remote users? + # Update the URI after the notice is in the database + if (!$uri) { + $orig = clone($notice); + $notice->uri = common_notice_uri($notice); + + if (!$notice->update($orig)) { + common_log_db_error($notice, 'UPDATE', __FILE__); + return _('Problem saving notice.'); + } + } - $notice->saveReplies(); - $notice->saveTags(); - $notice->saveGroups(); + # XXX: do we need to change this for remote users? - $notice->addToInboxes(); - $notice->query('COMMIT'); + $notice->saveReplies(); + $notice->saveTags(); + $notice->saveGroups(); + + $notice->addToInboxes(); + $notice->query('COMMIT'); + + Event::handle('EndNoticeSave', array($notice)); + } # Clear the cache for subscribed users, so they'll update at next request # XXX: someone clever could prepend instead of clearing the cache @@ -572,7 +593,7 @@ class Notice extends Memcached_DataObject $inbox = new Notice_inbox(); $UT = common_config('db','type')=='pgsql'?'"user"':'user'; $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created) ' . - "SELECT $UT.id, " . $this->id . ', "' . $this->created . '" ' . + "SELECT $UT.id, " . $this->id . ", '" . $this->created . "' " . "FROM $UT JOIN subscription ON $UT.id = subscription.subscriber " . 'WHERE subscription.subscribed = ' . $this->profile_id . ' ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . @@ -614,6 +635,15 @@ class Notice extends Memcached_DataObject continue; } + // we automatically add a tag for every group name, too + + $tag = Notice_tag::pkeyGet(array('tag' => common_canonical_tag($nickname), + 'notice_id' => $this->id)); + + if (is_null($tag)) { + $this->saveTag($nickname); + } + if ($profile->isMember($group)) { $gi = new Group_inbox(); @@ -633,7 +663,7 @@ class Notice extends Memcached_DataObject $inbox = new Notice_inbox(); $UT = common_config('db','type')=='pgsql'?'"user"':'user'; $qry = 'INSERT INTO notice_inbox (user_id, notice_id, created, source) ' . - "SELECT $UT.id, " . $this->id . ', "' . $this->created . '", 2 ' . + "SELECT $UT.id, " . $this->id . ", '" . $this->created . "', 2 " . "FROM $UT JOIN group_member ON $UT.id = group_member.profile_id " . 'WHERE group_member.group_id = ' . $group->id . ' ' . 'AND NOT EXISTS (SELECT user_id, notice_id ' . @@ -684,6 +714,7 @@ class Notice extends Memcached_DataObject if ($recipient_notice) { $orig = clone($this); $this->reply_to = $recipient_notice->id; + $this->conversation = $recipient_notice->conversation; $this->update($orig); } } @@ -725,10 +756,27 @@ class Notice extends Memcached_DataObject if (!$id) { common_log_db_error($reply, 'INSERT', __FILE__); return; + } else { + $replied[$recipient->id] = 1; } } } } } + + // If it's not a reply, make it the root of a new conversation + + if (empty($this->conversation)) { + $orig = clone($this); + $this->conversation = $this->id; + $this->update($orig); + } + + foreach (array_keys($replied) as $recipient) { + $user = User::staticGet('id', $recipient); + if ($user) { + mail_notify_attn($user, $this); + } + } } } diff --git a/classes/Notice_tag.php b/classes/Notice_tag.php index 94f9296d6..f2247299a 100644 --- a/classes/Notice_tag.php +++ b/classes/Notice_tag.php @@ -19,7 +19,7 @@ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Notice_tag extends Memcached_DataObject +class Notice_tag extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -35,18 +35,18 @@ class Notice_tag extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - + static function getStream($tag, $offset=0, $limit=20) { - $qry = + $qry = 'SELECT notice.* ' . 'FROM notice JOIN notice_tag ON notice.id = notice_tag.notice_id ' . - 'WHERE notice_tag.tag = "%s" '; + "WHERE notice_tag.tag = '%s' "; return Notice::getStream(sprintf($qry, $tag), 'notice_tag:notice_stream:' . common_keyize($tag), $offset, $limit); } - + function blowCache() { $cache = common_memcache(); @@ -54,4 +54,9 @@ class Notice_tag extends Memcached_DataObject $cache->delete(common_cache_key('notice_tag:notice_stream:' . $this->tag)); } } + + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Notice_tag', $kv); + } } diff --git a/classes/Profile_tag.php b/classes/Profile_tag.php index cb60cbaec..0a1ad9cd6 100644 --- a/classes/Profile_tag.php +++ b/classes/Profile_tag.php @@ -4,7 +4,7 @@ */ require_once INSTALLDIR.'/classes/Memcached_DataObject.php'; -class Profile_tag extends Memcached_DataObject +class Profile_tag extends Memcached_DataObject { ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ @@ -23,45 +23,46 @@ class Profile_tag extends Memcached_DataObject ###END_AUTOCODE static function getTags($tagger, $tagged) { - + $tags = array(); # XXX: store this in memcached - + $profile_tag = new Profile_tag(); $profile_tag->tagger = $tagger; $profile_tag->tagged = $tagged; - + $profile_tag->find(); - + while ($profile_tag->fetch()) { $tags[] = $profile_tag->tag; } - + $profile_tag->free(); - + return $tags; } - + static function setTags($tagger, $tagged, $newtags) { - + + $newtags = array_unique($newtags); $oldtags = Profile_tag::getTags($tagger, $tagged); - + # Delete stuff that's old that not in new - + $to_delete = array_diff($oldtags, $newtags); - + # Insert stuff that's in new and not in old - + $to_insert = array_diff($newtags, $oldtags); - + $profile_tag = new Profile_tag(); - + $profile_tag->tagger = $tagger; $profile_tag->tagged = $tagged; - + $profile_tag->query('BEGIN'); - + foreach ($to_delete as $deltag) { $profile_tag->tag = $deltag; $result = $profile_tag->delete(); @@ -70,7 +71,7 @@ class Profile_tag extends Memcached_DataObject return false; } } - + foreach ($to_insert as $instag) { $profile_tag->tag = $instag; $result = $profile_tag->insert(); @@ -79,12 +80,12 @@ class Profile_tag extends Memcached_DataObject return false; } } - + $profile_tag->query('COMMIT'); - + return true; } - + # Return profiles with a given tag static function getTagged($tagger, $tag) { $profile = new Profile(); diff --git a/classes/User.php b/classes/User.php index a6a1b11b9..8b0b9acd5 100644 --- a/classes/User.php +++ b/classes/User.php @@ -40,6 +40,7 @@ class User extends Memcached_DataObject public $emailnotifyfav; // tinyint(1) default_1 public $emailnotifynudge; // tinyint(1) default_1 public $emailnotifymsg; // tinyint(1) default_1 + public $emailnotifyattn; // tinyint(1) default_1 public $emailmicroid; // tinyint(1) default_1 public $language; // varchar(50) public $timezone; // varchar(50) @@ -62,8 +63,10 @@ class User extends Memcached_DataObject public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('User',$k,$v); } + 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 @@ -180,16 +183,16 @@ class User extends Memcached_DataObject $profile->nickname = $nickname; $profile->profileurl = common_profile_url($nickname); - if ($fullname) { + if (!empty($fullname)) { $profile->fullname = $fullname; } - if ($homepage) { + if (!empty($homepage)) { $profile->homepage = $homepage; } - if ($bio) { + if (!empty($bio)) { $profile->bio = $bio; } - if ($location) { + if (!empty($location)) { $profile->location = $location; } @@ -197,7 +200,7 @@ class User extends Memcached_DataObject $id = $profile->insert(); - if (!$id) { + if (empty($id)) { common_log_db_error($profile, 'INSERT', __FILE__); return false; } @@ -207,13 +210,13 @@ class User extends Memcached_DataObject $user->id = $id; $user->nickname = $nickname; - if ($password) { # may not have a password for OpenID users + if (!empty($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) { + if (!empty($code)) { $invite = Invitation::staticGet($code); if ($invite && $invite->address && $invite->address_type == 'email' && $invite->address == $email) { $user->email = $invite->address; @@ -250,7 +253,7 @@ class User extends Memcached_DataObject return false; } - if ($email && !$user->email) { + if (!empty($email) && !$user->email) { $confirm = new Confirm_address(); $confirm->code = common_confirmation_code(128); @@ -265,7 +268,7 @@ class User extends Memcached_DataObject } } - if ($code && $user->email) { + if (!empty($code) && $user->email) { $user->emailChanged(); } @@ -586,7 +589,7 @@ class User extends Memcached_DataObject 'JOIN profile_tag ON (profile_tag.tagged = subscription.subscriber ' . 'AND profile_tag.tagger = subscription.subscribed) ' . 'WHERE subscription.subscribed = %d ' . - 'AND profile_tag.tag = "%s" ' . + "AND profile_tag.tag = '%s' " . 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; @@ -614,7 +617,7 @@ class User extends Memcached_DataObject 'JOIN profile_tag on (profile_tag.tagged = subscription.subscribed ' . 'AND profile_tag.tagger = subscription.subscriber) ' . 'WHERE subscription.subscriber = %d ' . - 'AND profile_tag.tag = "%s" ' . + "AND profile_tag.tag = '%s' " . 'AND subscription.subscribed != subscription.subscriber ' . 'ORDER BY subscription.created DESC '; diff --git a/classes/laconica.ini b/classes/laconica.ini index 255122a97..aaa7035a4 100755 --- a/classes/laconica.ini +++ b/classes/laconica.ini @@ -168,6 +168,7 @@ modified = 384 reply_to = 1 is_local = 17 source = 2 +conversation = 1 [notice__keys] id = N @@ -292,7 +293,8 @@ created = 142 modified = 384 [sms_carrier__keys] -id = N +id = K +name = U [subscription] subscriber = 129 @@ -331,6 +333,7 @@ emailnotifysub = 17 emailnotifyfav = 17 emailnotifynudge = 17 emailnotifymsg = 17 +emailnotifyattn = 17 emailmicroid = 17 language = 2 timezone = 2 |