From: Mikael Nordfeldth Date: Fri, 7 Nov 2014 14:47:10 +0000 (+0100) Subject: DirectMessage moved into a plugin, not done yet X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=68143ff916b07e8188d1a8ff6cba3ad31c34a2ad;p=quix0rs-gnu-social.git DirectMessage moved into a plugin, not done yet We still have to move some API calls into the new plugin. --- diff --git a/actions/apidirectmessage.php b/actions/apidirectmessage.php deleted file mode 100644 index e971a7d4ee..0000000000 --- a/actions/apidirectmessage.php +++ /dev/null @@ -1,361 +0,0 @@ -. - * - * @category API - * @package StatusNet - * @author Adrian Lang - * @author Evan Prodromou - * @author Robin Millette - * @author Zach Copley - * @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/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * Show a list of direct messages from or to the authenticating user - * - * @category API - * @package StatusNet - * @author Adrian Lang - * @author Evan Prodromou - * @author Robin Millette - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ -class ApiDirectMessageAction extends ApiAuthAction -{ - var $messages = null; - var $title = null; - var $subtitle = null; - var $link = null; - var $selfuri_base = null; - var $id = null; - - /** - * Take arguments for running - * - * @param array $args $_REQUEST args - * - * @return boolean success flag - */ - function prepare($args) - { - parent::prepare($args); - - $this->user = $this->auth_user; - - if (empty($this->user)) { - // TRANS: Client error given when a user was not found (404). - $this->clientError(_('No such user.'), 404); - } - - $server = common_root_url(); - $taguribase = TagURI::base(); - - if ($this->arg('sent')) { - - // Action was called by /api/direct_messages/sent.format - - $this->title = sprintf( - // TRANS: Title. %s is a user nickname. - _("Direct messages from %s"), - $this->user->nickname - ); - $this->subtitle = sprintf( - // TRANS: Subtitle. %s is a user nickname. - _("All the direct messages sent from %s"), - $this->user->nickname - ); - $this->link = $server . $this->user->nickname . '/outbox'; - $this->selfuri_base = common_root_url() . 'api/direct_messages/sent'; - $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id; - } else { - $this->title = sprintf( - // TRANS: Title. %s is a user nickname. - _("Direct messages to %s"), - $this->user->nickname - ); - $this->subtitle = sprintf( - // TRANS: Subtitle. %s is a user nickname. - _("All the direct messages sent to %s"), - $this->user->nickname - ); - $this->link = $server . $this->user->nickname . '/inbox'; - $this->selfuri_base = common_root_url() . 'api/direct_messages'; - $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id; - } - - $this->messages = $this->getMessages(); - - return true; - } - - /** - * Handle the request - * - * Show the messages - * - * @param array $args $_REQUEST data (unused) - * - * @return void - */ - function handle($args) - { - parent::handle($args); - $this->showMessages(); - } - - /** - * Show the messages - * - * @return void - */ - function showMessages() - { - switch($this->format) { - case 'xml': - $this->showXmlDirectMessages(); - break; - case 'rss': - $this->showRssDirectMessages(); - break; - case 'atom': - $this->showAtomDirectMessages(); - break; - case 'json': - $this->showJsonDirectMessages(); - break; - default: - // TRANS: Client error displayed when coming across a non-supported API method. - $this->clientError(_('API method not found.'), $code = 404); - break; - } - } - - /** - * Get notices - * - * @return array notices - */ - function getMessages() - { - $message = new Message(); - - if ($this->arg('sent')) { - $message->from_profile = $this->user->id; - } else { - $message->to_profile = $this->user->id; - } - - if (!empty($this->max_id)) { - $message->whereAdd('id <= ' . $this->max_id); - } - - if (!empty($this->since_id)) { - $message->whereAdd('id > ' . $this->since_id); - } - - $message->orderBy('created DESC, id DESC'); - $message->limit((($this->page - 1) * $this->count), $this->count); - $message->find(); - - $messages = array(); - - while ($message->fetch()) { - $messages[] = clone($message); - } - - return $messages; - } - - /** - * Is this action read only? - * - * @param array $args other arguments - * - * @return boolean true - */ - function isReadOnly($args) - { - return true; - } - - /** - * When was this notice last modified? - * - * @return string datestamp of the latest notice in the stream - */ - function lastModified() - { - if (!empty($this->messages)) { - return strtotime($this->messages[0]->created); - } - - return null; - } - - /** - * Shows a list of direct messages as Twitter-style XML array - * - * @return void - */ - function showXmlDirectMessages() - { - $this->initDocument('xml'); - $this->elementStart('direct-messages', array('type' => 'array', - 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); - - foreach ($this->messages as $m) { - $dm_array = $this->directMessageArray($m); - $this->showXmlDirectMessage($dm_array); - } - - $this->elementEnd('direct-messages'); - $this->endDocument('xml'); - } - - /** - * Shows a list of direct messages as a JSON encoded array - * - * @return void - */ - function showJsonDirectMessages() - { - $this->initDocument('json'); - - $dmsgs = array(); - - foreach ($this->messages as $m) { - $dm_array = $this->directMessageArray($m); - array_push($dmsgs, $dm_array); - } - - $this->showJsonObjects($dmsgs); - $this->endDocument('json'); - } - - /** - * Shows a list of direct messages as RSS items - * - * @return void - */ - function showRssDirectMessages() - { - $this->initDocument('rss'); - - $this->element('title', null, $this->title); - - $this->element('link', null, $this->link); - $this->element('description', null, $this->subtitle); - $this->element('language', null, 'en-us'); - - $this->element( - 'atom:link', - array( - 'type' => 'application/rss+xml', - 'href' => $this->selfuri_base . '.rss', - 'rel' => self - ), - null - ); - $this->element('ttl', null, '40'); - - foreach ($this->messages as $m) { - $entry = $this->rssDirectMessageArray($m); - $this->showTwitterRssItem($entry); - } - - $this->endTwitterRss(); - } - - /** - * Shows a list of direct messages as Atom entries - * - * @return void - */ - function showAtomDirectMessages() - { - $this->initDocument('atom'); - - $this->element('title', null, $this->title); - $this->element('id', null, $this->id); - - $selfuri = common_root_url() . 'api/direct_messages.atom'; - - $this->element( - 'link', array( - 'href' => $this->link, - 'rel' => 'alternate', - 'type' => 'text/html'), - null - ); - $this->element( - 'link', array( - 'href' => $this->selfuri_base . '.atom', 'rel' => 'self', - 'type' => 'application/atom+xml'), - null - ); - $this->element('updated', null, common_date_iso8601('now')); - $this->element('subtitle', null, $this->subtitle); - - foreach ($this->messages as $m) { - $entry = $this->rssDirectMessageArray($m); - $this->showTwitterAtomEntry($entry); - } - - $this->endDocument('atom'); - } - - /** - * An entity tag for this notice - * - * Returns an Etag based on the action name, language, and - * timestamps of the notice - * - * @return string etag - */ - function etag() - { - if (!empty($this->messages)) { - - $last = count($this->messages) - 1; - - return '"' . implode( - ':', - array($this->arg('action'), - common_user_cache_hash($this->auth_user), - common_language(), - strtotime($this->messages[0]->created), - strtotime($this->messages[$last]->created) - ) - ) - . '"'; - } - - return null; - } -} diff --git a/actions/apidirectmessagenew.php b/actions/apidirectmessagenew.php deleted file mode 100644 index 653fa3a9ed..0000000000 --- a/actions/apidirectmessagenew.php +++ /dev/null @@ -1,140 +0,0 @@ -. - * - * @category API - * @package StatusNet - * @author Adrian Lang - * @author Evan Prodromou - * @author Robin Millette - * @author Zach Copley - * @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/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * Creates a new direct message from the authenticating user to - * the user specified by id. - * - * @category API - * @package StatusNet - * @author Adrian Lang - * @author Evan Prodromou - * @author Robin Millette - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ -class ApiDirectMessageNewAction extends ApiAuthAction -{ - protected $needPost = true; - - var $other = null; // Profile we're sending to - var $content = null; - - /** - * Take arguments for running - * - * @param array $args $_REQUEST args - * - * @return boolean success flag - */ - protected function prepare(array $args=array()) - { - parent::prepare($args); - - if (empty($this->user)) { - // TRANS: Client error when user not found for an API direct message action. - $this->clientError(_('No such user.'), 404); - } - - $this->content = $this->trimmed('text'); - - $user_param = $this->trimmed('user'); - $user_id = $this->arg('user_id'); - $screen_name = $this->trimmed('screen_name'); - - if (isset($user_param) || isset($user_id) || isset($screen_name)) { - $this->other = $this->getTargetProfile($user_param); - } - - return true; - } - - /** - * Handle the request - * - * Save the new message - * - * @return void - */ - protected function handle() - { - parent::handle(); - - if (empty($this->content)) { - // TRANS: Client error displayed when no message text was submitted (406). - $this->clientError(_('No message text!'), 406); - } else { - $content_shortened = $this->auth_user->shortenLinks($this->content); - if (Message::contentTooLong($content_shortened)) { - // TRANS: Client error displayed when message content is too long. - // TRANS: %d is the maximum number of characters for a message. - $this->clientError( - sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent()), - 406); - } - } - - if (!$this->other instanceof Profile) { - // TRANS: Client error displayed if a recipient user could not be found (403). - $this->clientError(_('Recipient user not found.'), 403); - } else if (!$this->user->mutuallySubscribed($this->other)) { - // TRANS: Client error displayed trying to direct message another user who's not a friend (403). - $this->clientError(_('Cannot send direct messages to users who aren\'t your friend.'), 403); - } else if ($this->user->id == $this->other->id) { - - // Note: sending msgs to yourself is allowed by Twitter - - // TRANS: Client error displayed trying to direct message self (403). - $this->clientError(_('Do not send a message to yourself; just say it to yourself quietly instead.'), 403); - } - - $message = Message::saveNew( - $this->user->id, - $this->other->id, - html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'), - $this->source - ); - - $message->notify(); - - if ($this->format == 'xml') { - $this->showSingleXmlDirectMessage($message); - } elseif ($this->format == 'json') { - $this->showSingleJsondirectMessage($message); - } - } -} diff --git a/actions/inbox.php b/actions/inbox.php deleted file mode 100644 index e9aa34317d..0000000000 --- a/actions/inbox.php +++ /dev/null @@ -1,129 +0,0 @@ -. - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008 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/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/mailbox.php'; - -/** - * action handler for message inbox - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see MailboxAction - */ -class InboxAction extends MailboxAction -{ - - /** - * Title of the page - * - * @return string page title - */ - function title() - { - if ($this->page > 1) { - // TRANS: Title for all but the first page of the inbox page. - // TRANS: %1$s is the user's nickname, %2$s is the page number. - return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname, - $this->page); - } else { - // TRANS: Title for the first page of the inbox page. - // TRANS: %s is the user's nickname. - return sprintf(_('Inbox for %s'), $this->user->nickname); - } - } - - /** - * Retrieve the messages for this user and this page - * - * Does a query for the right messages - * - * @return Message data object with stream for messages - * - * @see MailboxAction::getMessages() - */ - function getMessages() - { - $message = new Message(); - - $message->to_profile = $this->user->id; - $message->orderBy('created DESC, id DESC'); - $message->limit((($this->page - 1) * MESSAGES_PER_PAGE), - MESSAGES_PER_PAGE + 1); - - if ($message->find()) { - return $message; - } else { - return null; - } - } - - function getMessageList($message) - { - return new InboxMessageList($this, $message); - } - - /** - * Instructions for using this page - * - * @return string localised instructions for using the page - */ - function getInstructions() - { - // TRANS: Instructions for user inbox page. - return _('This is your inbox, which lists your incoming private messages.'); - } -} - -class InboxMessageList extends MessageList -{ - function newItem($message) - { - return new InboxMessageListItem($this->out, $message); - } -} - -class InboxMessageListItem extends MessageListItem -{ - /** - * Returns the profile we want to show with the message - * - * @return Profile The profile that matches the message - */ - function getMessageProfile() - { - return $this->message->getFrom(); - } -} diff --git a/actions/newmessage.php b/actions/newmessage.php deleted file mode 100644 index 428a55762c..0000000000 --- a/actions/newmessage.php +++ /dev/null @@ -1,228 +0,0 @@ -. - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @author Zach Copley - * @author Sarven Capadisli - * @copyright 2008-2009 StatusNet, Inc. - * @copyright 2013 Free Software Foundation, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -if (!defined('STATUSNET')) { - exit(1); -} - -/** - * Action for posting new direct messages - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @author Zach Copley - * @author Sarven Capadisli - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -class NewmessageAction extends FormAction -{ - var $content = null; - var $to = null; - var $other = null; - - /** - * Title of the page - * - * Note that this usually doesn't get called unless something went wrong - * - * @return string page title - */ - - function title() - { - // TRANS: Page title for new direct message page. - return _('New message'); - } - - /** - * Handle input, produce output - * - * @param array $args $_REQUEST contents - * - * @return void - */ - - protected function prepare(array $args=array()) - { - parent::prepare($args); - - $this->content = $this->trimmed('content'); - $this->to = $this->trimmed('to'); - - if ($this->to) { - - $this->other = Profile::getKV('id', $this->to); - - if (!$this->other instanceof Profile) { - // TRANS: Client error displayed trying to send a direct message to a non-existing user. - $this->clientError(_('No such user.'), 404); - } - - if (!$this->other->isLocal()) { - // TRANS: Explains that current federation does not support direct, private messages yet. - $this->clientError(_('You cannot send direct messages to federated users yet.')); - } - - if (!$this->scoped->mutuallySubscribed($this->other)) { - // TRANS: Client error displayed trying to send a direct message to a user while sender and - // TRANS: receiver are not subscribed to each other. - $this->clientError(_('You cannot send a message to this user.'), 404); - } - } - - return true; - } - - protected function handlePost() - { - parent::handlePost(); - - assert($this->scoped instanceof Profile); // XXX: maybe an error instead... - - if (!$this->content) { - // TRANS: Form validator error displayed trying to send a direct message without content. - $this->clientError(_('No content!')); - } else { - $content_shortened = $this->scoped->shortenLinks($this->content); - - if (Message::contentTooLong($content_shortened)) { - // TRANS: Form validation error displayed when message content is too long. - // TRANS: %d is the maximum number of characters for a message. - $this->clientError(sprintf(_m('That\'s too long. Maximum message size is %d character.', - 'That\'s too long. Maximum message size is %d characters.', - Message::maxContent()), - Message::maxContent())); - } - } - - if (!$this->other) { - // TRANS: Form validation error displayed trying to send a direct message without specifying a recipient. - $this->clientError(_('No recipient specified.')); - } else if (!$this->scoped->mutuallySubscribed($this->other)) { - // TRANS: Client error displayed trying to send a direct message to a user while sender and - // TRANS: receiver are not subscribed to each other. - $this->clientError(_('You cannot send a message to this user.'), 404); - } else if ($this->scoped->id == $this->other->id) { - // TRANS: Client error displayed trying to send a direct message to self. - $this->clientError(_('Do not send a message to yourself; ' . - 'just say it to yourself quietly instead.'), 403); - } - - $message = Message::saveNew($this->scoped->id, $this->other->id, $this->content, 'web'); - $message->notify(); - - if ($this->boolean('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Page title after sending a direct message. - $this->element('title', null, _('Message sent')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->element('p', array('id' => 'command_result'), - // TRANS: Confirmation text after sending a direct message. - // TRANS: %s is the direct message recipient. - sprintf(_('Direct message to %s sent.'), - $this->other->nickname)); - $this->elementEnd('body'); - $this->endHTML(); - } else { - $url = common_local_url('outbox', - array('nickname' => $this->scoped->nickname)); - common_redirect($url, 303); - } - } - - /** - * Show an Ajax-y error message - * - * Goes back to the browser, where it's shown in a popup. - * - * @param string $msg Message to show - * - * @return void - */ - - function ajaxErrorMsg($msg) - { - $this->startHTML('text/xml;charset=utf-8', true); - $this->elementStart('head'); - // TRANS: Page title after an AJAX error occurred on the "send direct message" page. - $this->element('title', null, _('Ajax Error')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->element('p', array('id' => 'error'), $msg); - $this->elementEnd('body'); - $this->endHTML(); - } - - function showForm($msg = null) - { - if ($msg && $this->boolean('ajax')) { - $this->ajaxErrorMsg($msg); - return; - } - - $this->msg = $msg; - if ($this->trimmed('ajax')) { - $this->startHTML('text/xml;charset=utf-8'); - $this->elementStart('head'); - // TRANS: Page title on page for sending a direct message. - $this->element('title', null, _('New message')); - $this->elementEnd('head'); - $this->elementStart('body'); - $this->showNoticeForm(); - $this->elementEnd('body'); - $this->endHTML(); - } - else { - $this->showPage(); - } - } - - function showPageNotice() - { - if ($this->msg) { - $this->element('p', 'error', $this->msg); - } - } - - // Do nothing (override) - - function showNoticeForm() - { - $message_form = new MessageForm($this, $this->other, $this->content); - $message_form->show(); - } -} diff --git a/actions/outbox.php b/actions/outbox.php deleted file mode 100644 index 6d10c8119f..0000000000 --- a/actions/outbox.php +++ /dev/null @@ -1,126 +0,0 @@ -. - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008 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/ - */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/mailbox.php'; - -/** - * action handler for message outbox - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see MailboxAction - */ -class OutboxAction extends MailboxAction -{ - /** - * Title of the page - * - * @return string page title - */ - function title() - { - if ($this->page > 1) { - // TRANS: Title for outbox for any but the fist page. - // TRANS: %1$s is the user nickname, %2$d is the page number. - return sprintf(_('Outbox for %1$s - page %2$d'), - $this->user->nickname, $page); - } else { - // TRANS: Title for first page of outbox. - return sprintf(_('Outbox for %s'), $this->user->nickname); - } - } - - /** - * retrieve the messages for this user and this page - * - * Does a query for the right messages - * - * @return Message data object with stream for messages - * - * @see MailboxAction::getMessages() - */ - function getMessages() - { - $message = new Message(); - - $message->from_profile = $this->user->id; - $message->orderBy('created DESC, id DESC'); - $message->limit((($this->page - 1) * MESSAGES_PER_PAGE), - MESSAGES_PER_PAGE + 1); - - if ($message->find()) { - return $message; - } else { - return null; - } - } - - function getMessageList($message) - { - return new OutboxMessageList($this, $message); - } - - /** - * instructions for using this page - * - * @return string localised instructions for using the page - */ - function getInstructions() - { - // TRANS: Instructions for outbox. - return _('This is your outbox, which lists private messages you have sent.'); - } -} - -class OutboxMessageList extends MessageList -{ - function newItem($message) - { - return new OutboxMessageListItem($this->out, $message); - } -} - -class OutboxMessageListItem extends MessageListItem -{ - /** - * Returns the profile we want to show with the message - * - * @return Profile The profile that matches the message - */ - function getMessageProfile() - { - return $this->message->getTo(); - } -} diff --git a/actions/showmessage.php b/actions/showmessage.php deleted file mode 100644 index 86fbee8b73..0000000000 --- a/actions/showmessage.php +++ /dev/null @@ -1,163 +0,0 @@ -. - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008-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/ - */ -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * Show a single message - * - * @category Personal - * @package StatusNet - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - */ - -class ShowmessageAction extends Action -{ - /** - * Message object to show - */ - var $message = null; - - /** - * The current user - */ - - var $user = null; - - /** - * Load attributes based on database arguments - * - * Loads all the DB stuff - * - * @param array $args $_REQUEST array - * - * @return success flag - */ - function prepare($args) - { - parent::prepare($args); - - $this->page = 1; - - $id = $this->trimmed('message'); - $this->message = Message::getKV('id', $id); - - if (!$this->message) { - // TRANS: Client error displayed requesting a single message that does not exist. - $this->clientError(_('No such message.'), 404); - } - - $this->user = common_current_user(); - - if (empty($this->user) || - ($this->user->id != $this->message->from_profile && - $this->user->id != $this->message->to_profile)) { - // TRANS: Client error displayed requesting a single direct message the requesting user was not a party in. - throw new ClientException(_('Only the sender and recipient ' . - 'may read this message.'), 403); - } - - return true; - } - - function handle($args) - { - $this->showPage(); - } - - function title() - { - if ($this->user->id == $this->message->from_profile) { - $to = $this->message->getTo(); - // @todo FIXME: Might be nice if the timestamp could be localised. - // TRANS: Page title for single direct message display when viewing user is the sender. - // TRANS: %1$s is the addressed user's nickname, $2$s is a timestamp. - return sprintf(_('Message to %1$s on %2$s'), - $to->nickname, - common_exact_date($this->message->created)); - } else if ($this->user->id == $this->message->to_profile) { - $from = $this->message->getFrom(); - // @todo FIXME: Might be nice if the timestamp could be localised. - // TRANS: Page title for single message display. - // TRANS: %1$s is the sending user's nickname, $2$s is a timestamp. - return sprintf(_('Message from %1$s on %2$s'), - $from->nickname, - common_exact_date($this->message->created)); - } - } - - - function showContent() - { - $this->elementStart('ul', 'notices messages'); - $ml = new ShowMessageListItem($this, $this->message, $this->user); - $ml->show(); - $this->elementEnd('ul'); - } - - function isReadOnly($args) - { - return true; - } - - /** - * Don't show aside - * - * @return void - */ - - function showAside() { - } -} - -class ShowMessageListItem extends MessageListItem -{ - var $user; - - function __construct($out, $message, $user) - { - parent::__construct($out, $message); - $this->user = $user; - } - - function getMessageProfile() - { - if ($this->user->id == $this->message->from_profile) { - return $this->message->getTo(); - } else if ($this->user->id == $this->message->to_profile) { - return $this->message->getFrom(); - } else { - // This shouldn't happen - return null; - } - } -} diff --git a/classes/Message.php b/classes/Message.php deleted file mode 100644 index 9c79862e5c..0000000000 --- a/classes/Message.php +++ /dev/null @@ -1,218 +0,0 @@ - array( - 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'), - 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'), - 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'), - 'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'), - 'content' => array('type' => 'text', 'description' => 'message content'), - 'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'), - 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'), - 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), - 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), - 'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'), - ), - 'primary key' => array('id'), - 'unique keys' => array( - 'message_uri_key' => array('uri'), - ), - 'foreign keys' => array( - 'message_from_profile_fkey' => array('profile', array('from_profile' => 'id')), - 'message_to_profile_fkey' => array('profile', array('to_profile' => 'id')), - ), - 'indexes' => array( - // @fixme these are really terrible indexes, since you can only sort on one of them at a time. - // looks like we really need a (to_profile, created) for inbox and a (from_profile, created) for outbox - 'message_from_idx' => array('from_profile'), - 'message_to_idx' => array('to_profile'), - 'message_created_idx' => array('created'), - ), - ); - } - - function getFrom() - { - return Profile::getKV('id', $this->from_profile); - } - - function getTo() - { - return Profile::getKV('id', $this->to_profile); - } - - static function saveNew($from, $to, $content, $source) { - $sender = Profile::getKV('id', $from); - - if (!$sender->hasRight(Right::NEWMESSAGE)) { - // TRANS: Client exception thrown when a user tries to send a direct message while being banned from sending them. - throw new ClientException(_('You are banned from sending direct messages.')); - } - - $user = User::getKV('id', $sender->id); - - $msg = new Message(); - - $msg->from_profile = $from; - $msg->to_profile = $to; - if ($user) { - // Use the sender's URL shortening options. - $msg->content = $user->shortenLinks($content); - } else { - $msg->content = common_shorten_links($content); - } - $msg->rendered = common_render_text($msg->content); - $msg->created = common_sql_now(); - $msg->source = $source; - - $result = $msg->insert(); - - if (!$result) { - common_log_db_error($msg, 'INSERT', __FILE__); - // TRANS: Message given when a message could not be stored on the server. - throw new ServerException(_('Could not insert message.')); - } - - $orig = clone($msg); - $msg->uri = common_local_url('showmessage', array('message' => $msg->id)); - - $result = $msg->update($orig); - - if (!$result) { - common_log_db_error($msg, 'UPDATE', __FILE__); - // TRANS: Message given when a message could not be updated on the server. - throw new ServerException(_('Could not update message with new URI.')); - } - - return $msg; - } - - static function maxContent() - { - $desclimit = common_config('message', 'contentlimit'); - // null => use global limit (distinct from 0!) - if (is_null($desclimit)) { - $desclimit = common_config('site', 'textlimit'); - } - return $desclimit; - } - - static function contentTooLong($content) - { - $contentlimit = self::maxContent(); - return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit)); - } - - function notify() - { - $from = User::getKV('id', $this->from_profile); - $to = User::getKV('id', $this->to_profile); - - mail_notify_message($this, $from, $to); - } - - function getSource() - { - if (empty($this->source)) { - return false; - } - - $ns = new Notice_source(); - switch ($this->source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'system': - case 'api': - $ns->code = $this->source; - break; - default: - $ns = Notice_source::getKV($this->source); - if (!$ns instanceof Notice_source) { - $ns = new Notice_source(); - $ns->code = $this->source; - $app = Oauth_application::getKV('name', $this->source); - if ($app) { - $ns->name = $app->name; - $ns->url = $app->source_url; - } - } - break; - } - return $ns; - } - - function asActivity() - { - $act = new Activity(); - - if (Event::handle('StartMessageAsActivity', array($this, &$act))) { - - $act->id = TagURI::mint(sprintf('activity:message:%d', $this->id)); - $act->time = strtotime($this->created); - $act->link = $this->url; - - $profile = Profile::getKV('id', $this->from_profile); - - if (empty($profile)) { - throw new Exception(sprintf("Sender profile not found: %d", $this->from_profile)); - } - - $act->actor = $profile->asActivityObject(); - $act->actor->extra[] = $profile->profileInfo(); - - $act->verb = ActivityVerb::POST; - - $act->objects[] = ActivityObject::fromMessage($this); - - $ctx = new ActivityContext(); - - $rprofile = Profile::getKV('id', $this->to_profile); - - if (empty($rprofile)) { - throw new Exception(sprintf("Receiver profile not found: %d", $this->to_profile)); - } - - $ctx->attention[$rprofile->getUri()] = ActivityObject::PERSON; - - $act->context = $ctx; - - $source = $this->getSource(); - - if ($source instanceof Notice_source) { - $act->generator = ActivityObject::fromNoticeSource($source); - } - - Event::handle('EndMessageAsActivity', array($this, &$act)); - } - - return $act; - } -} diff --git a/classes/Profile.php b/classes/Profile.php index a03f53cc7d..00a457a5c9 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -861,7 +861,6 @@ class Profile extends Managed_DataObject { $this->_deleteNotices(); $this->_deleteSubscriptions(); - $this->_deleteMessages(); $this->_deleteTags(); $this->_deleteBlocks(); $this->_deleteAttentions(); @@ -937,17 +936,6 @@ class Profile extends Managed_DataObject $self->delete(); } - function _deleteMessages() - { - $msg = new Message(); - $msg->from_profile = $this->id; - $msg->delete(); - - $msg = new Message(); - $msg->to_profile = $this->id; - $msg->delete(); - } - function _deleteTags() { $tag = new Profile_tag(); diff --git a/db/core.php b/db/core.php index c0aed1d3db..ec3fe7f736 100644 --- a/db/core.php +++ b/db/core.php @@ -55,7 +55,6 @@ $classes = array('Schema_version', 'Foreign_link', 'Foreign_subscription', 'Invitation', - 'Message', 'Profile_prefs', 'Profile_tag', 'Profile_list', diff --git a/lib/accountprofileblock.php b/lib/accountprofileblock.php index 76e2edb7ce..fe11a0fc15 100644 --- a/lib/accountprofileblock.php +++ b/lib/accountprofileblock.php @@ -171,17 +171,6 @@ class AccountProfileBlock extends ProfileBlock $this->out->elementEnd('li'); if ($this->profile->isLocal() && $cur->mutuallySubscribed($this->profile)) { - - // message - - $this->out->elementStart('li', 'entity_send-a-message'); - $this->out->element('a', array('href' => common_local_url('newmessage', array('to' => $this->user->id)), - // TRANS: Link title for link on user profile. - 'title' => _('Send a direct message to this user.')), - // TRANS: Link text for link on user profile. - _m('BUTTON','Message')); - $this->out->elementEnd('li'); - // nudge if ($this->user->email && $this->user->emailnotifynudge) { diff --git a/lib/mailbox.php b/lib/mailbox.php deleted file mode 100644 index 3c7281e985..0000000000 --- a/lib/mailbox.php +++ /dev/null @@ -1,167 +0,0 @@ -. - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @copyright 2008 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/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -/** - * common superclass for direct messages inbox and outbox - * - * @category Message - * @package StatusNet - * @author Evan Prodromou - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * @see InboxAction - * @see OutboxAction - */ -class MailboxAction extends Action -{ - var $page = null; - - function prepare($args) - { - parent::prepare($args); - - $nickname = common_canonical_nickname($this->arg('nickname')); - $this->user = User::getKV('nickname', $nickname); - $this->page = $this->trimmed('page'); - - if (!$this->page) { - $this->page = 1; - } - - common_set_returnto($this->selfUrl()); - - return true; - } - - /** - * output page based on arguments - * - * @param array $args HTTP arguments (from $_REQUEST) - * - * @return void - */ - function handle($args) - { - parent::handle($args); - - if (!$this->user) { - // TRANS: Client error displayed when trying to access a mailbox without providing a user. - $this->clientError(_('No such user.'), 404); - } - - $cur = common_current_user(); - - if (!$cur || $cur->id != $this->user->id) { - // TRANS: Client error displayed when trying to access a mailbox that is not of the logged in user. - $this->clientError(_('Only the user can read their own mailboxes.'), 403); - } - - $this->showPage(); - } - - function showNoticeForm() - { - $message_form = new MessageForm($this); - $message_form->show(); - } - - function showContent() - { - $message = $this->getMessages(); - - if ($message) { - - $ml = $this->getMessageList($message); - - $cnt = $ml->show(); - - $this->pagination($this->page > 1, - $cnt > MESSAGES_PER_PAGE, - $this->page, - $this->trimmed('action'), - array('nickname' => $this->user->nickname)); - } else { - $this->element('p', - 'guide', - // TRANS: Message displayed when there are no private messages in the inbox of a user. - _('You have no private messages. '. - 'You can send private message to engage other users in conversation. '. - 'People can send you messages for your eyes only.')); - } - } - - function getMessages() - { - return null; - } - - function getMessageList($message) - { - return null; - } - - /** - * Show the page notice - * - * Shows instructions for the page - * - * @return void - */ - function showPageNotice() - { - $instr = $this->getInstructions(); - $output = common_markup_to_html($instr); - - $this->elementStart('div', 'instructions'); - $this->raw($output); - $this->elementEnd('div'); - } - - /** - * Mailbox actions are read only - * - * @param array $args other arguments - * - * @return boolean - */ - function isReadOnly($args) - { - return true; - } - - function showObjectNav() - { - $mm = new MailboxMenu($this); - $mm->show(); - } -} diff --git a/lib/mailboxmenu.php b/lib/mailboxmenu.php deleted file mode 100644 index 49e7dce21a..0000000000 --- a/lib/mailboxmenu.php +++ /dev/null @@ -1,72 +0,0 @@ -. - * - * @category Cache - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 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); -} - -/** - * Menu of existing mailboxes - * - * @category General - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ -class MailboxMenu extends Menu -{ - function show() - { - $cur = common_current_user(); - $nickname = $cur->nickname; - - $this->out->elementStart('ul', array('class' => 'nav')); - - $this->item('inbox', - array('nickname' => $nickname), - // TRANS: Menu item in mailbox menu. Leads to incoming private messages. - _m('MENU','Inbox'), - // TRANS: Menu item title in mailbox menu. Leads to incoming private messages. - _('Your incoming messages.')); - - $this->item('outbox', - array('nickname' => $nickname), - // TRANS: Menu item in mailbox menu. Leads to outgoing private messages. - _m('MENU','Outbox'), - // TRANS: Menu item title in mailbox menu. Leads to outgoing private messages. - _('Your sent messages.')); - - $this->out->elementEnd('ul'); - } -} diff --git a/lib/messageform.php b/lib/messageform.php deleted file mode 100644 index acd30e3b38..0000000000 --- a/lib/messageform.php +++ /dev/null @@ -1,209 +0,0 @@ -. - * - * @category Form - * @package StatusNet - * @author Evan Prodromou - * @author Sarven Capadisli - * @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/ - */ - -if (!defined('STATUSNET') && !defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/form.php'; - -/** - * Form for posting a direct message - * - * @category Form - * @package StatusNet - * @author Evan Prodromou - * @author Sarven Capadisli - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://status.net/ - * - * @see HTMLOutputter - */ -class MessageForm extends Form -{ - /** - * User to send a direct message to - */ - var $to = null; - - /** - * Pre-filled content of the form - */ - var $content = null; - - /** - * Constructor - * - * @param HTMLOutputter $out output channel - * @param User $to user to send a message to - * @param string $content content to pre-fill - */ - function __construct($out=null, $to=null, $content=null) - { - parent::__construct($out); - - $this->to = $to; - $this->content = $content; - } - - /** - * ID of the form - * - * @return string ID of the form - */ - function id() - { - return 'form_notice-direct'; - } - - /** - * Class of the form - * - * @return string class of the form - */ - function formClass() - { - return 'form_notice ajax-notice'; - } - - /** - * Action of the form - * - * @return string URL of the action - */ - function action() - { - return common_local_url('newmessage'); - } - - /** - * Legend of the Form - * - * @return void - */ - function formLegend() - { - // TRANS: Form legend for direct notice. - $this->out->element('legend', null, _('Send a direct notice')); - } - - /** - * Data elements - * - * @return void - */ - function formData() - { - $user = common_current_user(); - - $mutual_users = $user->mutuallySubscribedUsers(); - - $mutual = array(); - // TRANS: Label entry in drop-down selection box in direct-message inbox/outbox. - // TRANS: This is the default entry in the drop-down box, doubling as instructions - // TRANS: and a brake against accidental submissions with the first user in the list. - $mutual[0] = _('Select recipient:'); - - while ($mutual_users->fetch()) { - if ($mutual_users->id != $user->id) { - $mutual[$mutual_users->id] = $mutual_users->nickname; - } - } - - $mutual_users->free(); - unset($mutual_users); - - if (count($mutual) == 1) { - // TRANS: Entry in drop-down selection box in direct-message inbox/outbox when no one is available to message. - $mutual[0] = _('No mutual subscribers.'); - } - - // TRANS: Dropdown label in direct notice form. - $this->out->dropdown('to', _('To'), $mutual, null, false, - ($this->to) ? $this->to->id : null); - - $this->out->element('textarea', array('class' => 'notice_data-text', - 'cols' => 35, - 'rows' => 4, - 'name' => 'content'), - ($this->content) ? $this->content : ''); - - $contentLimit = Message::maxContent(); - - if ($contentLimit > 0) { - $this->out->element('span', - array('class' => 'count'), - $contentLimit); - } - } - - /** - * Action elements - * - * @return void - */ - function formActions() - { - $this->out->element('input', array('id' => 'notice_action-submit', - 'class' => 'submit', - 'name' => 'message_send', - 'type' => 'submit', - // TRANS: Button text for sending a direct notice. - 'value' => _m('Send button for sending notice', 'Send'))); - } - - - /** - * Show the form - * - * Uses a recipe to output the form. - * - * @return void - * @see Widget::show() - */ - - function show() - { - $this->elementStart('div', 'input_forms'); - $this->elementStart( - 'div', - array( - 'id' => 'input_form_direct', - 'class' => 'input_form current nonav' - ) - ); - - parent::show(); - - $this->elementEnd('div'); - $this->elementEnd('div'); - - } -} diff --git a/lib/messagelist.php b/lib/messagelist.php deleted file mode 100644 index 0185977285..0000000000 --- a/lib/messagelist.php +++ /dev/null @@ -1,107 +0,0 @@ -. - * - * @category Widget - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 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); -} - -/** - * Message list widget - * - * @category Widget - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ -abstract class MessageList extends Widget -{ - var $message; - - /** - * Constructor - * - * @param HTMLOutputter $out Output context - * @param Message $message Stream of messages to show - */ - function __construct($out, $message) - { - parent::__construct($out); - $this->message = $message; - } - - /** - * Show the widget - * - * Uses newItem() to create each new item. - * - * @return integer count of messages seen. - */ - function show() - { - $cnt = 0; - - $this->out->elementStart('div', array('id' =>'notices_primary')); - - // TRANS: Header in message list. - $this->out->element('h2', null, _('Messages')); - - $this->out->elementStart('ul', 'notices messages'); - - while ($this->message->fetch() && $cnt <= MESSAGES_PER_PAGE) { - - $cnt++; - - if ($cnt > MESSAGES_PER_PAGE) { - break; - } - - $mli = $this->newItem($this->message); - - $mli->show(); - } - - $this->out->elementEnd('ul'); - - $this->out->elementEnd('div'); - } - - /** - * Create a new message item for a message - * - * @param Message $message The message to show - * - * @return MessageListItem an item to show - */ - abstract function newItem($message); -} diff --git a/lib/messagelistitem.php b/lib/messagelistitem.php deleted file mode 100644 index c9f4c6042b..0000000000 --- a/lib/messagelistitem.php +++ /dev/null @@ -1,194 +0,0 @@ -. - * - * @category Widget - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 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); -} - -/** - * A single item in a message list - * - * @category Widget - * @package StatusNet - * @author Evan Prodromou - * @copyright 2011 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ -abstract class MessageListItem extends Widget -{ - var $message; - - /** - * Constructor - * - * @param HTMLOutputter $out Output context - * @param Message $message Message to show - */ - function __construct($out, $message) - { - parent::__construct($out); - $this->message = $message; - } - - /** - * Show the widget - * - * @return void - */ - function show() - { - $this->out->elementStart('li', array('class' => 'h-entry notice', - 'id' => 'message-' . $this->message->id)); - - $profile = $this->getMessageProfile(); - - $this->out->elementStart('a', array('href' => $profile->profileurl, - 'class' => 'p-author')); - $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE); - $this->out->element('img', array('src' => $avatarUrl, - 'class' => 'avatar u-photo', - 'width' => AVATAR_STREAM_SIZE, - 'height' => AVATAR_STREAM_SIZE, - 'alt' => $profile->getBestName())); - $this->out->element('span', array('class' => 'nickname fn'), $profile->getNickname()); - $this->out->elementEnd('a'); - - // FIXME: URL, image, video, audio - $this->out->elementStart('div', array('class' => 'e-content')); - $this->out->raw($this->message->rendered); - $this->out->elementEnd('div'); - - $messageurl = common_local_url('showmessage', - array('message' => $this->message->id)); - - // XXX: we need to figure this out better. Is this right? - if (strcmp($this->message->uri, $messageurl) != 0 && - preg_match('/^http/', $this->message->uri)) { - $messageurl = $this->message->uri; - } - - $this->out->elementStart('div', 'entry-metadata'); - $this->out->elementStart('a', array('rel' => 'bookmark', - 'class' => 'timestamp', - 'href' => $messageurl)); - $dt = common_date_iso8601($this->message->created); - $this->out->element('time', array('class' => 'dt-published', - 'datetime' => common_date_iso8601($this->message->created), - // TRANS: Timestamp title (tooltip text) for NoticeListItem - 'title' => common_exact_date($this->message->created)), - common_date_string($this->message->created)); - $this->out->elementEnd('a'); - - if ($this->message->source) { - $this->out->elementStart('span', 'source'); - // FIXME: bad i18n. Device should be a parameter (from %s). - // TRANS: Followed by notice source (usually the client used to send the notice). - $this->out->text(_('from')); - $this->showSource($this->message->source); - $this->out->elementEnd('span'); - } - $this->out->elementEnd('div'); - - $this->out->elementEnd('li'); - } - - /** - * Dummy method. Serves no other purpose than to make strings available used - * in self::showSource() through xgettext. - * - * @return void - */ - function messageListItemDummyMessages() - { - // A dummy array with messages. These will get extracted by xgettext and - // are used in self::showSource(). - $dummy_messages = array( - // TRANS: A possible notice source (web interface). - _m('SOURCE','web'), - // TRANS: A possible notice source (XMPP). - _m('SOURCE','xmpp'), - // TRANS: A possible notice source (e-mail). - _m('SOURCE','mail'), - // TRANS: A possible notice source (OpenMicroBlogging). - _m('SOURCE','omb'), - // TRANS: A possible notice source (Application Programming Interface). - _m('SOURCE','api'), - ); - } - - /** - * Show the source of the message - * - * Returns either the name (and link) of the API client that posted the notice, - * or one of other other channels. - * - * @param string $source the source of the message - * - * @return void - */ - function showSource($source) - { - $source_name = _m('SOURCE',$source); - switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': - $this->out->element('span', 'device', $source_name); - break; - default: - $ns = Notice_source::getKV($source); - if ($ns) { - $this->out->elementStart('span', 'device'); - $this->out->element('a', array('href' => $ns->url, - 'rel' => 'external'), - $ns->name); - $this->out->elementEnd('span'); - } else { - $this->out->element('span', 'device', $source_name); - } - break; - } - return; - } - - /** - * Return the profile to show in the message item - * - * Overridden in sub-classes to show sender, receiver, or whatever - * - * @return Profile profile to show avatar and name of - */ - abstract function getMessageProfile(); -} diff --git a/lib/personalgroupnav.php b/lib/personalgroupnav.php index 8c413c6ab9..06bd2474bb 100644 --- a/lib/personalgroupnav.php +++ b/lib/personalgroupnav.php @@ -96,19 +96,6 @@ class PersonalGroupNav extends Menu sprintf(_('Replies to %s'), $name), $mine && $action =='replies', 'nav_timeline_replies'); - - if ($scoped instanceof Profile && $scoped->id == $target->id && - !common_config('singleuser', 'enabled')) { - - $this->out->menuItem(common_local_url('inbox', array('nickname' => - $nickname)), - // TRANS: Menu item in personal group navigation menu. - _m('MENU','Messages'), - // TRANS: Menu item title in personal group navigation menu. - _('Your incoming messages'), - $mine && $action =='inbox'); - } - Event::handle('EndPersonalGroupNav', array($this, $target, $scoped)); } $this->out->elementEnd('ul'); diff --git a/lib/router.php b/lib/router.php index 54683e986e..8260cb3e2e 100644 --- a/lib/router.php +++ b/lib/router.php @@ -249,12 +249,6 @@ class Router array('action' => 'conversation'), array('id' => '[0-9]+')); - $m->connect('message/new', array('action' => 'newmessage')); - $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT)); - $m->connect('message/:message', - array('action' => 'showmessage'), - array('message' => '[0-9]+')); - $m->connect('user/:id', array('action' => 'userbyid'), array('id' => '[0-9]+')); @@ -507,21 +501,6 @@ class Router 'screen_name' => Nickname::DISPLAY_FMT, 'format' => '(xml|json)')); - // direct messages - - $m->connect('api/direct_messages.:format', - array('action' => 'ApiDirectMessage', - 'format' => '(xml|json|rss|atom)')); - - $m->connect('api/direct_messages/sent.:format', - array('action' => 'ApiDirectMessage', - 'format' => '(xml|json|rss|atom)', - 'sent' => true)); - - $m->connect('api/direct_messages/new.:format', - array('action' => 'ApiDirectMessageNew', - 'format' => '(xml|json)')); - // friendships $m->connect('api/friendships/show.:format', diff --git a/plugins/DirectMessage/DirectMessagePlugin.php b/plugins/DirectMessage/DirectMessagePlugin.php new file mode 100644 index 0000000000..1e717833ad --- /dev/null +++ b/plugins/DirectMessage/DirectMessagePlugin.php @@ -0,0 +1,116 @@ +. + */ + +if (!defined('GNUSOCIAL')) { exit(1); } + +/** + * @maintainer Mikael Nordfeldth + */ +class DirectMessagePlugin extends Plugin +{ + public function onCheckSchema() + { + $schema = Schema::get(); + $schema->ensureTable('message', Message::schemaDef()); + return true; + } + + public function onRouterInitialized(URLMapper $m) + { + // web front-end actions + $m->connect('message/new', array('action' => 'newmessage')); + $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => Nickname::DISPLAY_FMT)); + $m->connect('message/:message', + array('action' => 'showmessage'), + array('message' => '[0-9]+')); + + // direct messages + $m->connect('api/direct_messages.:format', + array('action' => 'ApiDirectMessage', + 'format' => '(xml|json|rss|atom)')); + $m->connect('api/direct_messages/sent.:format', + array('action' => 'ApiDirectMessage', + 'format' => '(xml|json|rss|atom)', + 'sent' => true)); + $m->connect('api/direct_messages/new.:format', + array('action' => 'ApiDirectMessageNew', + 'format' => '(xml|json)')); + + return true; + } + + public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped=null) + { + if ($scoped instanceof Profile && $scoped->id == $target->id + && !common_config('singleuser', 'enabled')) { + + $menu->out->menuItem(common_local_url('inbox', array('nickname' => + $target->getNickname())), + // TRANS: Menu item in personal group navigation menu. + _m('MENU','Messages'), + // TRANS: Menu item title in personal group navigation menu. + _('Your incoming messages'), + $scoped->id === $target->id && $menu->actionName =='inbox'); + } + } + + public function onEndProfilePageActionsElements(HTMLOutputter $out, Profile $profile) + { + $scoped = Profile::current(); + if (!$scoped instanceof Profile) { + return true; + } + + if ($profile->isLocal() && $scoped->mutuallySubscribed($profile)) { + $out->elementStart('li', 'entity_send-a-message'); + $out->element('a', array('href' => common_local_url('newmessage', array('to' => $profile->id)), + // TRANS: Link title for link on user profile. + 'title' => _('Send a direct message to this user.')), + // TRANS: Link text for link on user profile. + _m('BUTTON','Message')); + $out->elementEnd('li'); + } + return true; + } + + public function onProfileDeleteRelated(Profile $profile, &$related) + { + $msg = new Message(); + $msg->from_profile = $profile->id; + $msg->delete(); + + $msg = new Message(); + $msg->to_profile = $profile->id; + $msg->delete(); + return true; + } + + public function onPluginVersion(array &$versions) + { + $versions[] = array('name' => 'Direct Message', + 'version' => GNUSOCIAL_VERSION, + 'author' => 'Mikael Nordfeldth', + 'homepage' => 'http://gnu.io/', + 'rawdescription' => + // TRANS: Plugin description. + _m('Direct Message to other local users (broken out of core).')); + + return true; + } +} diff --git a/plugins/DirectMessage/actions/apidirectmessage.php b/plugins/DirectMessage/actions/apidirectmessage.php new file mode 100644 index 0000000000..e971a7d4ee --- /dev/null +++ b/plugins/DirectMessage/actions/apidirectmessage.php @@ -0,0 +1,361 @@ +. + * + * @category API + * @package StatusNet + * @author Adrian Lang + * @author Evan Prodromou + * @author Robin Millette + * @author Zach Copley + * @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/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Show a list of direct messages from or to the authenticating user + * + * @category API + * @package StatusNet + * @author Adrian Lang + * @author Evan Prodromou + * @author Robin Millette + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ +class ApiDirectMessageAction extends ApiAuthAction +{ + var $messages = null; + var $title = null; + var $subtitle = null; + var $link = null; + var $selfuri_base = null; + var $id = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + function prepare($args) + { + parent::prepare($args); + + $this->user = $this->auth_user; + + if (empty($this->user)) { + // TRANS: Client error given when a user was not found (404). + $this->clientError(_('No such user.'), 404); + } + + $server = common_root_url(); + $taguribase = TagURI::base(); + + if ($this->arg('sent')) { + + // Action was called by /api/direct_messages/sent.format + + $this->title = sprintf( + // TRANS: Title. %s is a user nickname. + _("Direct messages from %s"), + $this->user->nickname + ); + $this->subtitle = sprintf( + // TRANS: Subtitle. %s is a user nickname. + _("All the direct messages sent from %s"), + $this->user->nickname + ); + $this->link = $server . $this->user->nickname . '/outbox'; + $this->selfuri_base = common_root_url() . 'api/direct_messages/sent'; + $this->id = "tag:$taguribase:SentDirectMessages:" . $this->user->id; + } else { + $this->title = sprintf( + // TRANS: Title. %s is a user nickname. + _("Direct messages to %s"), + $this->user->nickname + ); + $this->subtitle = sprintf( + // TRANS: Subtitle. %s is a user nickname. + _("All the direct messages sent to %s"), + $this->user->nickname + ); + $this->link = $server . $this->user->nickname . '/inbox'; + $this->selfuri_base = common_root_url() . 'api/direct_messages'; + $this->id = "tag:$taguribase:DirectMessages:" . $this->user->id; + } + + $this->messages = $this->getMessages(); + + return true; + } + + /** + * Handle the request + * + * Show the messages + * + * @param array $args $_REQUEST data (unused) + * + * @return void + */ + function handle($args) + { + parent::handle($args); + $this->showMessages(); + } + + /** + * Show the messages + * + * @return void + */ + function showMessages() + { + switch($this->format) { + case 'xml': + $this->showXmlDirectMessages(); + break; + case 'rss': + $this->showRssDirectMessages(); + break; + case 'atom': + $this->showAtomDirectMessages(); + break; + case 'json': + $this->showJsonDirectMessages(); + break; + default: + // TRANS: Client error displayed when coming across a non-supported API method. + $this->clientError(_('API method not found.'), $code = 404); + break; + } + } + + /** + * Get notices + * + * @return array notices + */ + function getMessages() + { + $message = new Message(); + + if ($this->arg('sent')) { + $message->from_profile = $this->user->id; + } else { + $message->to_profile = $this->user->id; + } + + if (!empty($this->max_id)) { + $message->whereAdd('id <= ' . $this->max_id); + } + + if (!empty($this->since_id)) { + $message->whereAdd('id > ' . $this->since_id); + } + + $message->orderBy('created DESC, id DESC'); + $message->limit((($this->page - 1) * $this->count), $this->count); + $message->find(); + + $messages = array(); + + while ($message->fetch()) { + $messages[] = clone($message); + } + + return $messages; + } + + /** + * Is this action read only? + * + * @param array $args other arguments + * + * @return boolean true + */ + function isReadOnly($args) + { + return true; + } + + /** + * When was this notice last modified? + * + * @return string datestamp of the latest notice in the stream + */ + function lastModified() + { + if (!empty($this->messages)) { + return strtotime($this->messages[0]->created); + } + + return null; + } + + /** + * Shows a list of direct messages as Twitter-style XML array + * + * @return void + */ + function showXmlDirectMessages() + { + $this->initDocument('xml'); + $this->elementStart('direct-messages', array('type' => 'array', + 'xmlns:statusnet' => 'http://status.net/schema/api/1/')); + + foreach ($this->messages as $m) { + $dm_array = $this->directMessageArray($m); + $this->showXmlDirectMessage($dm_array); + } + + $this->elementEnd('direct-messages'); + $this->endDocument('xml'); + } + + /** + * Shows a list of direct messages as a JSON encoded array + * + * @return void + */ + function showJsonDirectMessages() + { + $this->initDocument('json'); + + $dmsgs = array(); + + foreach ($this->messages as $m) { + $dm_array = $this->directMessageArray($m); + array_push($dmsgs, $dm_array); + } + + $this->showJsonObjects($dmsgs); + $this->endDocument('json'); + } + + /** + * Shows a list of direct messages as RSS items + * + * @return void + */ + function showRssDirectMessages() + { + $this->initDocument('rss'); + + $this->element('title', null, $this->title); + + $this->element('link', null, $this->link); + $this->element('description', null, $this->subtitle); + $this->element('language', null, 'en-us'); + + $this->element( + 'atom:link', + array( + 'type' => 'application/rss+xml', + 'href' => $this->selfuri_base . '.rss', + 'rel' => self + ), + null + ); + $this->element('ttl', null, '40'); + + foreach ($this->messages as $m) { + $entry = $this->rssDirectMessageArray($m); + $this->showTwitterRssItem($entry); + } + + $this->endTwitterRss(); + } + + /** + * Shows a list of direct messages as Atom entries + * + * @return void + */ + function showAtomDirectMessages() + { + $this->initDocument('atom'); + + $this->element('title', null, $this->title); + $this->element('id', null, $this->id); + + $selfuri = common_root_url() . 'api/direct_messages.atom'; + + $this->element( + 'link', array( + 'href' => $this->link, + 'rel' => 'alternate', + 'type' => 'text/html'), + null + ); + $this->element( + 'link', array( + 'href' => $this->selfuri_base . '.atom', 'rel' => 'self', + 'type' => 'application/atom+xml'), + null + ); + $this->element('updated', null, common_date_iso8601('now')); + $this->element('subtitle', null, $this->subtitle); + + foreach ($this->messages as $m) { + $entry = $this->rssDirectMessageArray($m); + $this->showTwitterAtomEntry($entry); + } + + $this->endDocument('atom'); + } + + /** + * An entity tag for this notice + * + * Returns an Etag based on the action name, language, and + * timestamps of the notice + * + * @return string etag + */ + function etag() + { + if (!empty($this->messages)) { + + $last = count($this->messages) - 1; + + return '"' . implode( + ':', + array($this->arg('action'), + common_user_cache_hash($this->auth_user), + common_language(), + strtotime($this->messages[0]->created), + strtotime($this->messages[$last]->created) + ) + ) + . '"'; + } + + return null; + } +} diff --git a/plugins/DirectMessage/actions/apidirectmessagenew.php b/plugins/DirectMessage/actions/apidirectmessagenew.php new file mode 100644 index 0000000000..653fa3a9ed --- /dev/null +++ b/plugins/DirectMessage/actions/apidirectmessagenew.php @@ -0,0 +1,140 @@ +. + * + * @category API + * @package StatusNet + * @author Adrian Lang + * @author Evan Prodromou + * @author Robin Millette + * @author Zach Copley + * @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/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Creates a new direct message from the authenticating user to + * the user specified by id. + * + * @category API + * @package StatusNet + * @author Adrian Lang + * @author Evan Prodromou + * @author Robin Millette + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ +class ApiDirectMessageNewAction extends ApiAuthAction +{ + protected $needPost = true; + + var $other = null; // Profile we're sending to + var $content = null; + + /** + * Take arguments for running + * + * @param array $args $_REQUEST args + * + * @return boolean success flag + */ + protected function prepare(array $args=array()) + { + parent::prepare($args); + + if (empty($this->user)) { + // TRANS: Client error when user not found for an API direct message action. + $this->clientError(_('No such user.'), 404); + } + + $this->content = $this->trimmed('text'); + + $user_param = $this->trimmed('user'); + $user_id = $this->arg('user_id'); + $screen_name = $this->trimmed('screen_name'); + + if (isset($user_param) || isset($user_id) || isset($screen_name)) { + $this->other = $this->getTargetProfile($user_param); + } + + return true; + } + + /** + * Handle the request + * + * Save the new message + * + * @return void + */ + protected function handle() + { + parent::handle(); + + if (empty($this->content)) { + // TRANS: Client error displayed when no message text was submitted (406). + $this->clientError(_('No message text!'), 406); + } else { + $content_shortened = $this->auth_user->shortenLinks($this->content); + if (Message::contentTooLong($content_shortened)) { + // TRANS: Client error displayed when message content is too long. + // TRANS: %d is the maximum number of characters for a message. + $this->clientError( + sprintf(_m('That\'s too long. Maximum message size is %d character.', 'That\'s too long. Maximum message size is %d characters.', Message::maxContent()), Message::maxContent()), + 406); + } + } + + if (!$this->other instanceof Profile) { + // TRANS: Client error displayed if a recipient user could not be found (403). + $this->clientError(_('Recipient user not found.'), 403); + } else if (!$this->user->mutuallySubscribed($this->other)) { + // TRANS: Client error displayed trying to direct message another user who's not a friend (403). + $this->clientError(_('Cannot send direct messages to users who aren\'t your friend.'), 403); + } else if ($this->user->id == $this->other->id) { + + // Note: sending msgs to yourself is allowed by Twitter + + // TRANS: Client error displayed trying to direct message self (403). + $this->clientError(_('Do not send a message to yourself; just say it to yourself quietly instead.'), 403); + } + + $message = Message::saveNew( + $this->user->id, + $this->other->id, + html_entity_decode($this->content, ENT_NOQUOTES, 'UTF-8'), + $this->source + ); + + $message->notify(); + + if ($this->format == 'xml') { + $this->showSingleXmlDirectMessage($message); + } elseif ($this->format == 'json') { + $this->showSingleJsondirectMessage($message); + } + } +} diff --git a/plugins/DirectMessage/actions/inbox.php b/plugins/DirectMessage/actions/inbox.php new file mode 100644 index 0000000000..e9aa34317d --- /dev/null +++ b/plugins/DirectMessage/actions/inbox.php @@ -0,0 +1,129 @@ +. + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008 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/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/mailbox.php'; + +/** + * action handler for message inbox + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * @see MailboxAction + */ +class InboxAction extends MailboxAction +{ + + /** + * Title of the page + * + * @return string page title + */ + function title() + { + if ($this->page > 1) { + // TRANS: Title for all but the first page of the inbox page. + // TRANS: %1$s is the user's nickname, %2$s is the page number. + return sprintf(_('Inbox for %1$s - page %2$d'), $this->user->nickname, + $this->page); + } else { + // TRANS: Title for the first page of the inbox page. + // TRANS: %s is the user's nickname. + return sprintf(_('Inbox for %s'), $this->user->nickname); + } + } + + /** + * Retrieve the messages for this user and this page + * + * Does a query for the right messages + * + * @return Message data object with stream for messages + * + * @see MailboxAction::getMessages() + */ + function getMessages() + { + $message = new Message(); + + $message->to_profile = $this->user->id; + $message->orderBy('created DESC, id DESC'); + $message->limit((($this->page - 1) * MESSAGES_PER_PAGE), + MESSAGES_PER_PAGE + 1); + + if ($message->find()) { + return $message; + } else { + return null; + } + } + + function getMessageList($message) + { + return new InboxMessageList($this, $message); + } + + /** + * Instructions for using this page + * + * @return string localised instructions for using the page + */ + function getInstructions() + { + // TRANS: Instructions for user inbox page. + return _('This is your inbox, which lists your incoming private messages.'); + } +} + +class InboxMessageList extends MessageList +{ + function newItem($message) + { + return new InboxMessageListItem($this->out, $message); + } +} + +class InboxMessageListItem extends MessageListItem +{ + /** + * Returns the profile we want to show with the message + * + * @return Profile The profile that matches the message + */ + function getMessageProfile() + { + return $this->message->getFrom(); + } +} diff --git a/plugins/DirectMessage/actions/newmessage.php b/plugins/DirectMessage/actions/newmessage.php new file mode 100644 index 0000000000..428a55762c --- /dev/null +++ b/plugins/DirectMessage/actions/newmessage.php @@ -0,0 +1,228 @@ +. + * + * @category Personal + * @package StatusNet + * @author Evan Prodromou + * @author Zach Copley + * @author Sarven Capadisli + * @copyright 2008-2009 StatusNet, Inc. + * @copyright 2013 Free Software Foundation, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +if (!defined('STATUSNET')) { + exit(1); +} + +/** + * Action for posting new direct messages + * + * @category Personal + * @package StatusNet + * @author Evan Prodromou + * @author Zach Copley + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class NewmessageAction extends FormAction +{ + var $content = null; + var $to = null; + var $other = null; + + /** + * Title of the page + * + * Note that this usually doesn't get called unless something went wrong + * + * @return string page title + */ + + function title() + { + // TRANS: Page title for new direct message page. + return _('New message'); + } + + /** + * Handle input, produce output + * + * @param array $args $_REQUEST contents + * + * @return void + */ + + protected function prepare(array $args=array()) + { + parent::prepare($args); + + $this->content = $this->trimmed('content'); + $this->to = $this->trimmed('to'); + + if ($this->to) { + + $this->other = Profile::getKV('id', $this->to); + + if (!$this->other instanceof Profile) { + // TRANS: Client error displayed trying to send a direct message to a non-existing user. + $this->clientError(_('No such user.'), 404); + } + + if (!$this->other->isLocal()) { + // TRANS: Explains that current federation does not support direct, private messages yet. + $this->clientError(_('You cannot send direct messages to federated users yet.')); + } + + if (!$this->scoped->mutuallySubscribed($this->other)) { + // TRANS: Client error displayed trying to send a direct message to a user while sender and + // TRANS: receiver are not subscribed to each other. + $this->clientError(_('You cannot send a message to this user.'), 404); + } + } + + return true; + } + + protected function handlePost() + { + parent::handlePost(); + + assert($this->scoped instanceof Profile); // XXX: maybe an error instead... + + if (!$this->content) { + // TRANS: Form validator error displayed trying to send a direct message without content. + $this->clientError(_('No content!')); + } else { + $content_shortened = $this->scoped->shortenLinks($this->content); + + if (Message::contentTooLong($content_shortened)) { + // TRANS: Form validation error displayed when message content is too long. + // TRANS: %d is the maximum number of characters for a message. + $this->clientError(sprintf(_m('That\'s too long. Maximum message size is %d character.', + 'That\'s too long. Maximum message size is %d characters.', + Message::maxContent()), + Message::maxContent())); + } + } + + if (!$this->other) { + // TRANS: Form validation error displayed trying to send a direct message without specifying a recipient. + $this->clientError(_('No recipient specified.')); + } else if (!$this->scoped->mutuallySubscribed($this->other)) { + // TRANS: Client error displayed trying to send a direct message to a user while sender and + // TRANS: receiver are not subscribed to each other. + $this->clientError(_('You cannot send a message to this user.'), 404); + } else if ($this->scoped->id == $this->other->id) { + // TRANS: Client error displayed trying to send a direct message to self. + $this->clientError(_('Do not send a message to yourself; ' . + 'just say it to yourself quietly instead.'), 403); + } + + $message = Message::saveNew($this->scoped->id, $this->other->id, $this->content, 'web'); + $message->notify(); + + if ($this->boolean('ajax')) { + $this->startHTML('text/xml;charset=utf-8'); + $this->elementStart('head'); + // TRANS: Page title after sending a direct message. + $this->element('title', null, _('Message sent')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->element('p', array('id' => 'command_result'), + // TRANS: Confirmation text after sending a direct message. + // TRANS: %s is the direct message recipient. + sprintf(_('Direct message to %s sent.'), + $this->other->nickname)); + $this->elementEnd('body'); + $this->endHTML(); + } else { + $url = common_local_url('outbox', + array('nickname' => $this->scoped->nickname)); + common_redirect($url, 303); + } + } + + /** + * Show an Ajax-y error message + * + * Goes back to the browser, where it's shown in a popup. + * + * @param string $msg Message to show + * + * @return void + */ + + function ajaxErrorMsg($msg) + { + $this->startHTML('text/xml;charset=utf-8', true); + $this->elementStart('head'); + // TRANS: Page title after an AJAX error occurred on the "send direct message" page. + $this->element('title', null, _('Ajax Error')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->element('p', array('id' => 'error'), $msg); + $this->elementEnd('body'); + $this->endHTML(); + } + + function showForm($msg = null) + { + if ($msg && $this->boolean('ajax')) { + $this->ajaxErrorMsg($msg); + return; + } + + $this->msg = $msg; + if ($this->trimmed('ajax')) { + $this->startHTML('text/xml;charset=utf-8'); + $this->elementStart('head'); + // TRANS: Page title on page for sending a direct message. + $this->element('title', null, _('New message')); + $this->elementEnd('head'); + $this->elementStart('body'); + $this->showNoticeForm(); + $this->elementEnd('body'); + $this->endHTML(); + } + else { + $this->showPage(); + } + } + + function showPageNotice() + { + if ($this->msg) { + $this->element('p', 'error', $this->msg); + } + } + + // Do nothing (override) + + function showNoticeForm() + { + $message_form = new MessageForm($this, $this->other, $this->content); + $message_form->show(); + } +} diff --git a/plugins/DirectMessage/actions/outbox.php b/plugins/DirectMessage/actions/outbox.php new file mode 100644 index 0000000000..6d10c8119f --- /dev/null +++ b/plugins/DirectMessage/actions/outbox.php @@ -0,0 +1,126 @@ +. + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008 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/ + */ +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/mailbox.php'; + +/** + * action handler for message outbox + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * @see MailboxAction + */ +class OutboxAction extends MailboxAction +{ + /** + * Title of the page + * + * @return string page title + */ + function title() + { + if ($this->page > 1) { + // TRANS: Title for outbox for any but the fist page. + // TRANS: %1$s is the user nickname, %2$d is the page number. + return sprintf(_('Outbox for %1$s - page %2$d'), + $this->user->nickname, $page); + } else { + // TRANS: Title for first page of outbox. + return sprintf(_('Outbox for %s'), $this->user->nickname); + } + } + + /** + * retrieve the messages for this user and this page + * + * Does a query for the right messages + * + * @return Message data object with stream for messages + * + * @see MailboxAction::getMessages() + */ + function getMessages() + { + $message = new Message(); + + $message->from_profile = $this->user->id; + $message->orderBy('created DESC, id DESC'); + $message->limit((($this->page - 1) * MESSAGES_PER_PAGE), + MESSAGES_PER_PAGE + 1); + + if ($message->find()) { + return $message; + } else { + return null; + } + } + + function getMessageList($message) + { + return new OutboxMessageList($this, $message); + } + + /** + * instructions for using this page + * + * @return string localised instructions for using the page + */ + function getInstructions() + { + // TRANS: Instructions for outbox. + return _('This is your outbox, which lists private messages you have sent.'); + } +} + +class OutboxMessageList extends MessageList +{ + function newItem($message) + { + return new OutboxMessageListItem($this->out, $message); + } +} + +class OutboxMessageListItem extends MessageListItem +{ + /** + * Returns the profile we want to show with the message + * + * @return Profile The profile that matches the message + */ + function getMessageProfile() + { + return $this->message->getTo(); + } +} diff --git a/plugins/DirectMessage/actions/showmessage.php b/plugins/DirectMessage/actions/showmessage.php new file mode 100644 index 0000000000..86fbee8b73 --- /dev/null +++ b/plugins/DirectMessage/actions/showmessage.php @@ -0,0 +1,163 @@ +. + * + * @category Personal + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008-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/ + */ +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * Show a single message + * + * @category Personal + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + */ + +class ShowmessageAction extends Action +{ + /** + * Message object to show + */ + var $message = null; + + /** + * The current user + */ + + var $user = null; + + /** + * Load attributes based on database arguments + * + * Loads all the DB stuff + * + * @param array $args $_REQUEST array + * + * @return success flag + */ + function prepare($args) + { + parent::prepare($args); + + $this->page = 1; + + $id = $this->trimmed('message'); + $this->message = Message::getKV('id', $id); + + if (!$this->message) { + // TRANS: Client error displayed requesting a single message that does not exist. + $this->clientError(_('No such message.'), 404); + } + + $this->user = common_current_user(); + + if (empty($this->user) || + ($this->user->id != $this->message->from_profile && + $this->user->id != $this->message->to_profile)) { + // TRANS: Client error displayed requesting a single direct message the requesting user was not a party in. + throw new ClientException(_('Only the sender and recipient ' . + 'may read this message.'), 403); + } + + return true; + } + + function handle($args) + { + $this->showPage(); + } + + function title() + { + if ($this->user->id == $this->message->from_profile) { + $to = $this->message->getTo(); + // @todo FIXME: Might be nice if the timestamp could be localised. + // TRANS: Page title for single direct message display when viewing user is the sender. + // TRANS: %1$s is the addressed user's nickname, $2$s is a timestamp. + return sprintf(_('Message to %1$s on %2$s'), + $to->nickname, + common_exact_date($this->message->created)); + } else if ($this->user->id == $this->message->to_profile) { + $from = $this->message->getFrom(); + // @todo FIXME: Might be nice if the timestamp could be localised. + // TRANS: Page title for single message display. + // TRANS: %1$s is the sending user's nickname, $2$s is a timestamp. + return sprintf(_('Message from %1$s on %2$s'), + $from->nickname, + common_exact_date($this->message->created)); + } + } + + + function showContent() + { + $this->elementStart('ul', 'notices messages'); + $ml = new ShowMessageListItem($this, $this->message, $this->user); + $ml->show(); + $this->elementEnd('ul'); + } + + function isReadOnly($args) + { + return true; + } + + /** + * Don't show aside + * + * @return void + */ + + function showAside() { + } +} + +class ShowMessageListItem extends MessageListItem +{ + var $user; + + function __construct($out, $message, $user) + { + parent::__construct($out, $message); + $this->user = $user; + } + + function getMessageProfile() + { + if ($this->user->id == $this->message->from_profile) { + return $this->message->getTo(); + } else if ($this->user->id == $this->message->to_profile) { + return $this->message->getFrom(); + } else { + // This shouldn't happen + return null; + } + } +} diff --git a/plugins/DirectMessage/classes/Message.php b/plugins/DirectMessage/classes/Message.php new file mode 100644 index 0000000000..9c79862e5c --- /dev/null +++ b/plugins/DirectMessage/classes/Message.php @@ -0,0 +1,218 @@ + array( + 'id' => array('type' => 'serial', 'not null' => true, 'description' => 'unique identifier'), + 'uri' => array('type' => 'varchar', 'length' => 255, 'description' => 'universally unique identifier'), + 'from_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is from'), + 'to_profile' => array('type' => 'int', 'not null' => true, 'description' => 'who the message is to'), + 'content' => array('type' => 'text', 'description' => 'message content'), + 'rendered' => array('type' => 'text', 'description' => 'HTML version of the content'), + 'url' => array('type' => 'varchar', 'length' => 255, 'description' => 'URL of any attachment (image, video, bookmark, whatever)'), + 'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'), + 'modified' => array('type' => 'timestamp', 'not null' => true, 'description' => 'date this record was modified'), + 'source' => array('type' => 'varchar', 'length' => 32, 'description' => 'source of comment, like "web", "im", or "clientname"'), + ), + 'primary key' => array('id'), + 'unique keys' => array( + 'message_uri_key' => array('uri'), + ), + 'foreign keys' => array( + 'message_from_profile_fkey' => array('profile', array('from_profile' => 'id')), + 'message_to_profile_fkey' => array('profile', array('to_profile' => 'id')), + ), + 'indexes' => array( + // @fixme these are really terrible indexes, since you can only sort on one of them at a time. + // looks like we really need a (to_profile, created) for inbox and a (from_profile, created) for outbox + 'message_from_idx' => array('from_profile'), + 'message_to_idx' => array('to_profile'), + 'message_created_idx' => array('created'), + ), + ); + } + + function getFrom() + { + return Profile::getKV('id', $this->from_profile); + } + + function getTo() + { + return Profile::getKV('id', $this->to_profile); + } + + static function saveNew($from, $to, $content, $source) { + $sender = Profile::getKV('id', $from); + + if (!$sender->hasRight(Right::NEWMESSAGE)) { + // TRANS: Client exception thrown when a user tries to send a direct message while being banned from sending them. + throw new ClientException(_('You are banned from sending direct messages.')); + } + + $user = User::getKV('id', $sender->id); + + $msg = new Message(); + + $msg->from_profile = $from; + $msg->to_profile = $to; + if ($user) { + // Use the sender's URL shortening options. + $msg->content = $user->shortenLinks($content); + } else { + $msg->content = common_shorten_links($content); + } + $msg->rendered = common_render_text($msg->content); + $msg->created = common_sql_now(); + $msg->source = $source; + + $result = $msg->insert(); + + if (!$result) { + common_log_db_error($msg, 'INSERT', __FILE__); + // TRANS: Message given when a message could not be stored on the server. + throw new ServerException(_('Could not insert message.')); + } + + $orig = clone($msg); + $msg->uri = common_local_url('showmessage', array('message' => $msg->id)); + + $result = $msg->update($orig); + + if (!$result) { + common_log_db_error($msg, 'UPDATE', __FILE__); + // TRANS: Message given when a message could not be updated on the server. + throw new ServerException(_('Could not update message with new URI.')); + } + + return $msg; + } + + static function maxContent() + { + $desclimit = common_config('message', 'contentlimit'); + // null => use global limit (distinct from 0!) + if (is_null($desclimit)) { + $desclimit = common_config('site', 'textlimit'); + } + return $desclimit; + } + + static function contentTooLong($content) + { + $contentlimit = self::maxContent(); + return ($contentlimit > 0 && !empty($content) && (mb_strlen($content) > $contentlimit)); + } + + function notify() + { + $from = User::getKV('id', $this->from_profile); + $to = User::getKV('id', $this->to_profile); + + mail_notify_message($this, $from, $to); + } + + function getSource() + { + if (empty($this->source)) { + return false; + } + + $ns = new Notice_source(); + switch ($this->source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'system': + case 'api': + $ns->code = $this->source; + break; + default: + $ns = Notice_source::getKV($this->source); + if (!$ns instanceof Notice_source) { + $ns = new Notice_source(); + $ns->code = $this->source; + $app = Oauth_application::getKV('name', $this->source); + if ($app) { + $ns->name = $app->name; + $ns->url = $app->source_url; + } + } + break; + } + return $ns; + } + + function asActivity() + { + $act = new Activity(); + + if (Event::handle('StartMessageAsActivity', array($this, &$act))) { + + $act->id = TagURI::mint(sprintf('activity:message:%d', $this->id)); + $act->time = strtotime($this->created); + $act->link = $this->url; + + $profile = Profile::getKV('id', $this->from_profile); + + if (empty($profile)) { + throw new Exception(sprintf("Sender profile not found: %d", $this->from_profile)); + } + + $act->actor = $profile->asActivityObject(); + $act->actor->extra[] = $profile->profileInfo(); + + $act->verb = ActivityVerb::POST; + + $act->objects[] = ActivityObject::fromMessage($this); + + $ctx = new ActivityContext(); + + $rprofile = Profile::getKV('id', $this->to_profile); + + if (empty($rprofile)) { + throw new Exception(sprintf("Receiver profile not found: %d", $this->to_profile)); + } + + $ctx->attention[$rprofile->getUri()] = ActivityObject::PERSON; + + $act->context = $ctx; + + $source = $this->getSource(); + + if ($source instanceof Notice_source) { + $act->generator = ActivityObject::fromNoticeSource($source); + } + + Event::handle('EndMessageAsActivity', array($this, &$act)); + } + + return $act; + } +} diff --git a/plugins/DirectMessage/lib/mailbox.php b/plugins/DirectMessage/lib/mailbox.php new file mode 100644 index 0000000000..3c7281e985 --- /dev/null +++ b/plugins/DirectMessage/lib/mailbox.php @@ -0,0 +1,167 @@ +. + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @copyright 2008 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/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +/** + * common superclass for direct messages inbox and outbox + * + * @category Message + * @package StatusNet + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * @see InboxAction + * @see OutboxAction + */ +class MailboxAction extends Action +{ + var $page = null; + + function prepare($args) + { + parent::prepare($args); + + $nickname = common_canonical_nickname($this->arg('nickname')); + $this->user = User::getKV('nickname', $nickname); + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + common_set_returnto($this->selfUrl()); + + return true; + } + + /** + * output page based on arguments + * + * @param array $args HTTP arguments (from $_REQUEST) + * + * @return void + */ + function handle($args) + { + parent::handle($args); + + if (!$this->user) { + // TRANS: Client error displayed when trying to access a mailbox without providing a user. + $this->clientError(_('No such user.'), 404); + } + + $cur = common_current_user(); + + if (!$cur || $cur->id != $this->user->id) { + // TRANS: Client error displayed when trying to access a mailbox that is not of the logged in user. + $this->clientError(_('Only the user can read their own mailboxes.'), 403); + } + + $this->showPage(); + } + + function showNoticeForm() + { + $message_form = new MessageForm($this); + $message_form->show(); + } + + function showContent() + { + $message = $this->getMessages(); + + if ($message) { + + $ml = $this->getMessageList($message); + + $cnt = $ml->show(); + + $this->pagination($this->page > 1, + $cnt > MESSAGES_PER_PAGE, + $this->page, + $this->trimmed('action'), + array('nickname' => $this->user->nickname)); + } else { + $this->element('p', + 'guide', + // TRANS: Message displayed when there are no private messages in the inbox of a user. + _('You have no private messages. '. + 'You can send private message to engage other users in conversation. '. + 'People can send you messages for your eyes only.')); + } + } + + function getMessages() + { + return null; + } + + function getMessageList($message) + { + return null; + } + + /** + * Show the page notice + * + * Shows instructions for the page + * + * @return void + */ + function showPageNotice() + { + $instr = $this->getInstructions(); + $output = common_markup_to_html($instr); + + $this->elementStart('div', 'instructions'); + $this->raw($output); + $this->elementEnd('div'); + } + + /** + * Mailbox actions are read only + * + * @param array $args other arguments + * + * @return boolean + */ + function isReadOnly($args) + { + return true; + } + + function showObjectNav() + { + $mm = new MailboxMenu($this); + $mm->show(); + } +} diff --git a/plugins/DirectMessage/lib/mailboxmenu.php b/plugins/DirectMessage/lib/mailboxmenu.php new file mode 100644 index 0000000000..49e7dce21a --- /dev/null +++ b/plugins/DirectMessage/lib/mailboxmenu.php @@ -0,0 +1,72 @@ +. + * + * @category Cache + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 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); +} + +/** + * Menu of existing mailboxes + * + * @category General + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ +class MailboxMenu extends Menu +{ + function show() + { + $cur = common_current_user(); + $nickname = $cur->nickname; + + $this->out->elementStart('ul', array('class' => 'nav')); + + $this->item('inbox', + array('nickname' => $nickname), + // TRANS: Menu item in mailbox menu. Leads to incoming private messages. + _m('MENU','Inbox'), + // TRANS: Menu item title in mailbox menu. Leads to incoming private messages. + _('Your incoming messages.')); + + $this->item('outbox', + array('nickname' => $nickname), + // TRANS: Menu item in mailbox menu. Leads to outgoing private messages. + _m('MENU','Outbox'), + // TRANS: Menu item title in mailbox menu. Leads to outgoing private messages. + _('Your sent messages.')); + + $this->out->elementEnd('ul'); + } +} diff --git a/plugins/DirectMessage/lib/messageform.php b/plugins/DirectMessage/lib/messageform.php new file mode 100644 index 0000000000..acd30e3b38 --- /dev/null +++ b/plugins/DirectMessage/lib/messageform.php @@ -0,0 +1,209 @@ +. + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @author Sarven Capadisli + * @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/ + */ + +if (!defined('STATUSNET') && !defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/form.php'; + +/** + * Form for posting a direct message + * + * @category Form + * @package StatusNet + * @author Evan Prodromou + * @author Sarven Capadisli + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://status.net/ + * + * @see HTMLOutputter + */ +class MessageForm extends Form +{ + /** + * User to send a direct message to + */ + var $to = null; + + /** + * Pre-filled content of the form + */ + var $content = null; + + /** + * Constructor + * + * @param HTMLOutputter $out output channel + * @param User $to user to send a message to + * @param string $content content to pre-fill + */ + function __construct($out=null, $to=null, $content=null) + { + parent::__construct($out); + + $this->to = $to; + $this->content = $content; + } + + /** + * ID of the form + * + * @return string ID of the form + */ + function id() + { + return 'form_notice-direct'; + } + + /** + * Class of the form + * + * @return string class of the form + */ + function formClass() + { + return 'form_notice ajax-notice'; + } + + /** + * Action of the form + * + * @return string URL of the action + */ + function action() + { + return common_local_url('newmessage'); + } + + /** + * Legend of the Form + * + * @return void + */ + function formLegend() + { + // TRANS: Form legend for direct notice. + $this->out->element('legend', null, _('Send a direct notice')); + } + + /** + * Data elements + * + * @return void + */ + function formData() + { + $user = common_current_user(); + + $mutual_users = $user->mutuallySubscribedUsers(); + + $mutual = array(); + // TRANS: Label entry in drop-down selection box in direct-message inbox/outbox. + // TRANS: This is the default entry in the drop-down box, doubling as instructions + // TRANS: and a brake against accidental submissions with the first user in the list. + $mutual[0] = _('Select recipient:'); + + while ($mutual_users->fetch()) { + if ($mutual_users->id != $user->id) { + $mutual[$mutual_users->id] = $mutual_users->nickname; + } + } + + $mutual_users->free(); + unset($mutual_users); + + if (count($mutual) == 1) { + // TRANS: Entry in drop-down selection box in direct-message inbox/outbox when no one is available to message. + $mutual[0] = _('No mutual subscribers.'); + } + + // TRANS: Dropdown label in direct notice form. + $this->out->dropdown('to', _('To'), $mutual, null, false, + ($this->to) ? $this->to->id : null); + + $this->out->element('textarea', array('class' => 'notice_data-text', + 'cols' => 35, + 'rows' => 4, + 'name' => 'content'), + ($this->content) ? $this->content : ''); + + $contentLimit = Message::maxContent(); + + if ($contentLimit > 0) { + $this->out->element('span', + array('class' => 'count'), + $contentLimit); + } + } + + /** + * Action elements + * + * @return void + */ + function formActions() + { + $this->out->element('input', array('id' => 'notice_action-submit', + 'class' => 'submit', + 'name' => 'message_send', + 'type' => 'submit', + // TRANS: Button text for sending a direct notice. + 'value' => _m('Send button for sending notice', 'Send'))); + } + + + /** + * Show the form + * + * Uses a recipe to output the form. + * + * @return void + * @see Widget::show() + */ + + function show() + { + $this->elementStart('div', 'input_forms'); + $this->elementStart( + 'div', + array( + 'id' => 'input_form_direct', + 'class' => 'input_form current nonav' + ) + ); + + parent::show(); + + $this->elementEnd('div'); + $this->elementEnd('div'); + + } +} diff --git a/plugins/DirectMessage/lib/messagelist.php b/plugins/DirectMessage/lib/messagelist.php new file mode 100644 index 0000000000..0185977285 --- /dev/null +++ b/plugins/DirectMessage/lib/messagelist.php @@ -0,0 +1,107 @@ +. + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 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); +} + +/** + * Message list widget + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ +abstract class MessageList extends Widget +{ + var $message; + + /** + * Constructor + * + * @param HTMLOutputter $out Output context + * @param Message $message Stream of messages to show + */ + function __construct($out, $message) + { + parent::__construct($out); + $this->message = $message; + } + + /** + * Show the widget + * + * Uses newItem() to create each new item. + * + * @return integer count of messages seen. + */ + function show() + { + $cnt = 0; + + $this->out->elementStart('div', array('id' =>'notices_primary')); + + // TRANS: Header in message list. + $this->out->element('h2', null, _('Messages')); + + $this->out->elementStart('ul', 'notices messages'); + + while ($this->message->fetch() && $cnt <= MESSAGES_PER_PAGE) { + + $cnt++; + + if ($cnt > MESSAGES_PER_PAGE) { + break; + } + + $mli = $this->newItem($this->message); + + $mli->show(); + } + + $this->out->elementEnd('ul'); + + $this->out->elementEnd('div'); + } + + /** + * Create a new message item for a message + * + * @param Message $message The message to show + * + * @return MessageListItem an item to show + */ + abstract function newItem($message); +} diff --git a/plugins/DirectMessage/lib/messagelistitem.php b/plugins/DirectMessage/lib/messagelistitem.php new file mode 100644 index 0000000000..c9f4c6042b --- /dev/null +++ b/plugins/DirectMessage/lib/messagelistitem.php @@ -0,0 +1,194 @@ +. + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 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); +} + +/** + * A single item in a message list + * + * @category Widget + * @package StatusNet + * @author Evan Prodromou + * @copyright 2011 StatusNet, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 + * @link http://status.net/ + */ +abstract class MessageListItem extends Widget +{ + var $message; + + /** + * Constructor + * + * @param HTMLOutputter $out Output context + * @param Message $message Message to show + */ + function __construct($out, $message) + { + parent::__construct($out); + $this->message = $message; + } + + /** + * Show the widget + * + * @return void + */ + function show() + { + $this->out->elementStart('li', array('class' => 'h-entry notice', + 'id' => 'message-' . $this->message->id)); + + $profile = $this->getMessageProfile(); + + $this->out->elementStart('a', array('href' => $profile->profileurl, + 'class' => 'p-author')); + $avatarUrl = $profile->avatarUrl(AVATAR_STREAM_SIZE); + $this->out->element('img', array('src' => $avatarUrl, + 'class' => 'avatar u-photo', + 'width' => AVATAR_STREAM_SIZE, + 'height' => AVATAR_STREAM_SIZE, + 'alt' => $profile->getBestName())); + $this->out->element('span', array('class' => 'nickname fn'), $profile->getNickname()); + $this->out->elementEnd('a'); + + // FIXME: URL, image, video, audio + $this->out->elementStart('div', array('class' => 'e-content')); + $this->out->raw($this->message->rendered); + $this->out->elementEnd('div'); + + $messageurl = common_local_url('showmessage', + array('message' => $this->message->id)); + + // XXX: we need to figure this out better. Is this right? + if (strcmp($this->message->uri, $messageurl) != 0 && + preg_match('/^http/', $this->message->uri)) { + $messageurl = $this->message->uri; + } + + $this->out->elementStart('div', 'entry-metadata'); + $this->out->elementStart('a', array('rel' => 'bookmark', + 'class' => 'timestamp', + 'href' => $messageurl)); + $dt = common_date_iso8601($this->message->created); + $this->out->element('time', array('class' => 'dt-published', + 'datetime' => common_date_iso8601($this->message->created), + // TRANS: Timestamp title (tooltip text) for NoticeListItem + 'title' => common_exact_date($this->message->created)), + common_date_string($this->message->created)); + $this->out->elementEnd('a'); + + if ($this->message->source) { + $this->out->elementStart('span', 'source'); + // FIXME: bad i18n. Device should be a parameter (from %s). + // TRANS: Followed by notice source (usually the client used to send the notice). + $this->out->text(_('from')); + $this->showSource($this->message->source); + $this->out->elementEnd('span'); + } + $this->out->elementEnd('div'); + + $this->out->elementEnd('li'); + } + + /** + * Dummy method. Serves no other purpose than to make strings available used + * in self::showSource() through xgettext. + * + * @return void + */ + function messageListItemDummyMessages() + { + // A dummy array with messages. These will get extracted by xgettext and + // are used in self::showSource(). + $dummy_messages = array( + // TRANS: A possible notice source (web interface). + _m('SOURCE','web'), + // TRANS: A possible notice source (XMPP). + _m('SOURCE','xmpp'), + // TRANS: A possible notice source (e-mail). + _m('SOURCE','mail'), + // TRANS: A possible notice source (OpenMicroBlogging). + _m('SOURCE','omb'), + // TRANS: A possible notice source (Application Programming Interface). + _m('SOURCE','api'), + ); + } + + /** + * Show the source of the message + * + * Returns either the name (and link) of the API client that posted the notice, + * or one of other other channels. + * + * @param string $source the source of the message + * + * @return void + */ + function showSource($source) + { + $source_name = _m('SOURCE',$source); + switch ($source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'api': + $this->out->element('span', 'device', $source_name); + break; + default: + $ns = Notice_source::getKV($source); + if ($ns) { + $this->out->elementStart('span', 'device'); + $this->out->element('a', array('href' => $ns->url, + 'rel' => 'external'), + $ns->name); + $this->out->elementEnd('span'); + } else { + $this->out->element('span', 'device', $source_name); + } + break; + } + return; + } + + /** + * Return the profile to show in the message item + * + * Overridden in sub-classes to show sender, receiver, or whatever + * + * @return Profile profile to show avatar and name of + */ + abstract function getMessageProfile(); +}