diff --git a/actions/all.php b/actions/all.php index a53bbea07b..03179a2468 100644 --- a/actions/all.php +++ b/actions/all.php @@ -69,17 +69,6 @@ class AllAction extends ProfileAction sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'all', array('nickname' => $this->user->nickname)); - } - function showLocalNav() { $nav = new PersonalGroupNav($this); diff --git a/actions/conversation.php b/actions/conversation.php index 0d7cb9a874..20c68986cb 100644 --- a/actions/conversation.php +++ b/actions/conversation.php @@ -207,7 +207,7 @@ class ConversationTree extends NoticeList // We take responsibility for doing the li $this->out->elementStart('li', array('class' => 'hentry notice', - 'id' => 'notice-' . $this->notice->id)); + 'id' => 'notice-' . $id)); $item = $this->newListItem($notice); $item->show(); diff --git a/actions/favorited.php b/actions/favorited.php index 7e31303e3b..c902d80f53 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -221,15 +221,4 @@ class FavoritedAction extends Action $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, $this->page, 'favorited'); } - - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'favorited'); - } } diff --git a/actions/foaf.php b/actions/foaf.php index 2d5b78d123..fb0172eb90 100644 --- a/actions/foaf.php +++ b/actions/foaf.php @@ -82,14 +82,18 @@ class FoafAction extends Action 'http://www.w3.org/2000/01/rdf-schema#', 'xmlns:geo' => 'http://www.w3.org/2003/01/geo/wgs84_pos#', + 'xmlns:bio' => + 'http://purl.org/vocab/bio/0.1/', + 'xmlns:sioc' => + 'http://rdfs.org/sioc/ns#', 'xmlns' => 'http://xmlns.com/foaf/0.1/')); // This is the document about the user $this->showPpd('', $this->user->uri); - // XXX: might not be a person - $this->elementStart('Person', array('rdf:about' => + // Would be nice to tell if they were a Person or not (e.g. a #person usertag?) + $this->elementStart('Agent', array('rdf:about' => $this->user->uri)); $this->element('mbox_sha1sum', null, sha1('mailto:' . $this->user->email)); if ($this->profile->fullname) { @@ -98,8 +102,11 @@ class FoafAction extends Action if ($this->profile->homepage) { $this->element('homepage', array('rdf:resource' => $this->profile->homepage)); } + if ($this->profile->profileurl) { + $this->element('weblog', array('rdf:resource' => $this->profile->profileurl)); + } if ($this->profile->bio) { - $this->element('rdfs:comment', null, $this->profile->bio); + $this->element('bio:olb', null, $this->profile->bio); } // XXX: more structured location data if ($this->profile->location) { @@ -110,10 +117,7 @@ class FoafAction extends Action $this->elementEnd('based_near'); } - $this->showMicrobloggingAccount($this->profile, common_root_url()); - $avatar = $this->profile->getOriginalAvatar(); - if ($avatar) { $this->elementStart('img'); $this->elementStart('Image', array('rdf:about' => $avatar->url)); @@ -129,39 +133,8 @@ class FoafAction extends Action $this->elementEnd('img'); } - // Get people user is subscribed to - - $person = array(); - - $sub = new Subscription(); - $sub->subscriber = $this->profile->id; - $sub->whereAdd('subscriber != subscribed'); - - if ($sub->find()) { - while ($sub->fetch()) { - if (!empty($sub->token)) { - $other = Remote_profile::staticGet('id', $sub->subscribed); - } else { - $other = User::staticGet('id', $sub->subscribed); - } - if (empty($other)) { - common_debug('Got a bad subscription: '.print_r($sub,true)); - continue; - } - $this->element('knows', array('rdf:resource' => $other->uri)); - $person[$other->uri] = array(LISTENEE, - $other->id, - $other->nickname, - (empty($sub->token)) ? 'User' : 'Remote_profile'); - $other->free(); - $other = null; - unset($other); - } - } - - $sub->free(); - $sub = null; - unset($sub); + $person = $this->showMicrobloggingAccount($this->profile, + common_root_url(), $this->user->uri, false); // Get people who subscribe to user @@ -198,7 +171,15 @@ class FoafAction extends Action $sub = null; unset($sub); - $this->elementEnd('Person'); + foreach ($person as $uri => $p) { + list($type, $id, $nickname, $cls) = $p; + if ($type == BOTH) { + $this->element('knows', array('rdf:resource' => $uri)); + } + } + + $this->elementEnd('Agent'); + foreach ($person as $uri => $p) { $foaf_url = null; @@ -207,16 +188,18 @@ class FoafAction extends Action $foaf_url = common_local_url('foaf', array('nickname' => $nickname)); } $profile = Profile::staticGet($id); - $this->elementStart('Person', array('rdf:about' => $uri)); - if ($type == LISTENER || $type == BOTH) { + $this->elementStart('Agent', array('rdf:about' => $uri)); + if ($type == BOTH) { $this->element('knows', array('rdf:resource' => $this->user->uri)); } - $this->showMicrobloggingAccount($profile, ($cls == 'User') ? - common_root_url() : null); + $this->showMicrobloggingAccount($profile, + ($cls == 'User') ? common_root_url() : null, + $uri, + true); if ($foaf_url) { $this->element('rdfs:seeAlso', array('rdf:resource' => $foaf_url)); } - $this->elementEnd('Person'); + $this->elementEnd('Agent'); if ($foaf_url) { $this->showPpd($foaf_url, $uri); } @@ -237,18 +220,66 @@ class FoafAction extends Action $this->elementEnd('PersonalProfileDocument'); } - function showMicrobloggingAccount($profile, $service=null) + function showMicrobloggingAccount($profile, $service=null, $useruri=null, $isSubscriber=false) { + $attr = array(); + if ($useruri) { + $attr['rdf:about'] = $useruri . '#acct'; + } + // Their account $this->elementStart('holdsAccount'); - $this->elementStart('OnlineAccount'); + $this->elementStart('OnlineAccount', $attr); if ($service) { $this->element('accountServiceHomepage', array('rdf:resource' => $service)); } $this->element('accountName', null, $profile->nickname); - $this->element('homepage', array('rdf:resource' => $profile->profileurl)); + $this->element('accountProfilePage', array('rdf:resource' => $profile->profileurl)); + if ($useruri) { + $this->element('sioc:account_of', array('rdf:resource'=>$useruri)); + } + + $person = array(); + + if ($isSubscriber) { + $this->element('sioc:follows', array('rdf:resource'=>$this->user->uri . '#acct')); + } else { + // Get people user is subscribed to + $sub = new Subscription(); + $sub->subscriber = $profile->id; + $sub->whereAdd('subscriber != subscribed'); + + if ($sub->find()) { + while ($sub->fetch()) { + if (!empty($sub->token)) { + $other = Remote_profile::staticGet('id', $sub->subscribed); + } else { + $other = User::staticGet('id', $sub->subscribed); + } + if (empty($other)) { + common_debug('Got a bad subscription: '.print_r($sub,true)); + continue; + } + $this->element('sioc:follows', array('rdf:resource' => $other->uri.'#acct')); + $person[$other->uri] = array(LISTENEE, + $other->id, + $other->nickname, + (empty($sub->token)) ? 'User' : 'Remote_profile'); + $other->free(); + $other = null; + unset($other); + } + } + + $sub->free(); + $sub = null; + unset($sub); + } + $this->elementEnd('OnlineAccount'); $this->elementEnd('holdsAccount'); + + return $person; } } diff --git a/actions/groupmembers.php b/actions/groupmembers.php index 909935bec8..21e5ebbaa1 100644 --- a/actions/groupmembers.php +++ b/actions/groupmembers.php @@ -137,15 +137,4 @@ class GroupmembersAction extends Action $this->page, 'groupmembers', array('nickname' => $this->group->nickname)); } - - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'groupmembers', array('nickname' => $this->group->nickname)); - } } diff --git a/actions/groups.php b/actions/groups.php index e20acce706..26b52a5fcd 100644 --- a/actions/groups.php +++ b/actions/groups.php @@ -129,15 +129,4 @@ class GroupsAction extends Action $gbm = new GroupsByMembersSection($this); $gbm->show(); } - - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'groups', array('nickname' => $this->group->nickname)); - } } diff --git a/actions/inbox.php b/actions/inbox.php index 7b5cf2d203..f14ba631fd 100644 --- a/actions/inbox.php +++ b/actions/inbox.php @@ -46,15 +46,15 @@ require_once INSTALLDIR.'/lib/mailbox.php'; class InboxAction extends MailboxAction { - + /** * Title of the page * * @return string page title */ - + function title() - { + { if ($this->page > 1) { return sprintf(_("Inbox for %s - page %d"), $this->user->nickname, $this->page); @@ -63,22 +63,11 @@ class InboxAction extends MailboxAction } } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'inbox', array('nickname' => $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() @@ -95,7 +84,7 @@ class InboxAction extends MailboxAction if ($message->find()) { return $message; - } else { + } else { return null; } } diff --git a/actions/outbox.php b/actions/outbox.php index deef1cc870..a875e9ad95 100644 --- a/actions/outbox.php +++ b/actions/outbox.php @@ -62,22 +62,11 @@ class OutboxAction extends MailboxAction } } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'outbox', array('nickname' => $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() diff --git a/actions/public.php b/actions/public.php index d2f9da6460..27153f1315 100644 --- a/actions/public.php +++ b/actions/public.php @@ -135,17 +135,6 @@ class PublicAction extends Action _('Public Stream Feed (Atom)'))); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'public'); - } - /** * Extra head elements * diff --git a/actions/replies.php b/actions/replies.php index 5d84f6428c..d7ed440e92 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -137,17 +137,6 @@ class RepliesAction extends OwnerDesignAction return array(new Feed(Feed::RSS1, $rssurl, $rsstitle)); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'replies', array('nickname' => $this->user->nickname)); - } - /** * show the personal group nav * diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 839f083dd4..865045337a 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -45,8 +45,10 @@ require_once INSTALLDIR.'/lib/feedlist.php'; * @link http://laconi.ca/ */ -class ShowfavoritesAction extends OwnerDesignAction +class ShowfavoritesAction extends Action { + /** User we're getting the faves of */ + var $user = null; /** Page of the faves we're on */ var $page = null; @@ -148,17 +150,6 @@ class ShowfavoritesAction extends OwnerDesignAction return array(new Feed(Feed::RSS1, $feedurl, $feedtitle)); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'showfavorites', array('nickname' => $this->user->nickname)); - } - /** * show the personal group nav * diff --git a/actions/showgroup.php b/actions/showgroup.php index a7df397273..29b6fa1e61 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -311,17 +311,6 @@ class ShowgroupAction extends Action $this->group->nickname))); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'showgroup', array('nickname' => $this->group->nickname)); - } - /** * Fill in the sidebar. * diff --git a/actions/showstream.php b/actions/showstream.php index 678a3174c1..e2f4e24d43 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -147,17 +147,6 @@ class ShowstreamAction extends ProfileAction sprintf(_('FOAF for %s'), $this->user->nickname))); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'showstream', array('nickname' => $this->user->nickname)); - } - function extraHead() { // for remote subscriptions etc. diff --git a/actions/tag.php b/actions/tag.php index e9351d2419..d0ad797ebc 100644 --- a/actions/tag.php +++ b/actions/tag.php @@ -76,22 +76,6 @@ class TagAction extends Action sprintf(_('Feed for tag %s'), $this->tag))); } - /** - * Output document relationship links - * - * @return void - */ - function showRelationshipLinks() - { - $this->sequenceRelationships($this->page > 1, $this->count > NOTICES_PER_PAGE, // FIXME - $this->page, 'tag', array('tag' => $this->tag)); - } - - function showPageNotice() - { - return sprintf(_('Messages tagged "%s", most recent first'), $this->tag); - } - function showContent() { $notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1); diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php index 8b956f897a..b5e7b91da7 100644 --- a/actions/twitapiaccount.php +++ b/actions/twitapiaccount.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -51,7 +53,8 @@ class TwitapiaccountAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } @@ -60,24 +63,20 @@ class TwitapiaccountAction extends TwitterapiAction if (!is_null($location) && mb_strlen($location) > 255) { // XXX: But Twitter just truncates and runs with it. -- Zach - $this->clientError(_('That\'s too long. Max notice size is 255 chars.'), 406, $apidate['content-type']); + $this->clientError(_('That\'s too long. Max notice size is 255 chars.'), + 406, $apidate['content-type']); return; } - $user = $apidata['user']; + $user = $apidata['user']; // Always the auth user $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - $orig_profile = clone($profile); $profile->location = $location; $result = $profile->update($orig_profile); - if (!$result) { + if (empty($result)) { common_log_db_error($profile, 'UPDATE', __FILE__); $this->serverError(_('Couldn\'t save profile.')); return; diff --git a/actions/twitapiblocks.php b/actions/twitapiblocks.php index 8135adef3c..0e35091622 100644 --- a/actions/twitapiblocks.php +++ b/actions/twitapiblocks.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -31,12 +33,12 @@ class TwitapiblocksAction extends TwitterapiAction $blockee = $this->get_user($apidata['api_arg'], $apidata); - if (!$blockee) { + if (empty($blockee)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } - $user = $apidata['user']; + $user = $apidata['user']; // Always the auth user if ($user->hasBlocked($blockee) || $user->block($blockee)) { $type = $apidata['content-type']; @@ -53,7 +55,7 @@ class TwitapiblocksAction extends TwitterapiAction parent::handle($args); $blockee = $this->get_user($apidata['api_arg'], $apidata); - if (!$blockee) { + if (empty($blockee)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index d2dbdb619b..85c788d6a6 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -38,42 +40,34 @@ class Twitapidirect_messagesAction extends TwitterapiAction function show_messages($args, $apidata, $type) { - $user = $apidata['user']; + $user = $apidata['user']; // Always the auth user - $count = $this->arg('count'); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); - - $page = $this->arg('page'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - $message = new Message(); - - $title = null; + $message = new Message(); + $title = null; $subtitle = null; - $link = null; - $server = common_root_url(); + $link = null; + $server = common_root_url(); if ($type == 'received') { $message->to_profile = $user->id; $title = sprintf(_("Direct messages to %s"), $user->nickname); - $subtitle = sprintf(_("All the direct messages sent to %s"), $user->nickname); + $subtitle = sprintf(_("All the direct messages sent to %s"), + $user->nickname); $link = $server . $user->nickname . '/inbox'; } else { $message->from_profile = $user->id; $title = _('Direct Messages You\'ve Sent'); - $subtitle = sprintf(_("All the direct messages sent from %s"), $user->nickname); + $subtitle = sprintf(_("All the direct messages sent from %s"), + $user->nickname); $link = $server . $user->nickname . '/outbox'; } + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); + if ($max_id) { $message->whereAdd("id <= $max_id"); } @@ -82,25 +76,23 @@ class Twitapidirect_messagesAction extends TwitterapiAction $message->whereAdd("id > $since_id"); } - $since = strtotime($this->arg('since')); - if ($since) { $d = date('Y-m-d H:i:s', $since); $message->whereAdd("created > '$d'"); } $message->orderBy('created DESC, id DESC'); - $message->limit((($page-1)*20), $count); + $message->limit((($page-1)*$count), $count); $message->find(); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_dmsgs($message); break; - case 'rss': + case 'rss': $this->show_rss_dmsgs($message, $title, $link, $subtitle); break; - case 'atom': + case 'atom': $selfuri = common_root_url() . 'api/direct_messages'; $selfuri .= ($type == 'received') ? '.atom' : '/sent.atom'; $taguribase = common_config('integration', 'taguri'); @@ -111,12 +103,13 @@ class Twitapidirect_messagesAction extends TwitterapiAction $id = "tag:$taguribase:DirectMessages:" . $user->id; } - $this->show_atom_dmsgs($message, $title, $link, $subtitle, $selfuri, $id); + $this->show_atom_dmsgs($message, $title, $link, $subtitle, + $selfuri, $id); break; - case 'json': + case 'json': $this->show_json_dmsgs($message); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -128,22 +121,24 @@ class Twitapidirect_messagesAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } $user = $apidata['user']; - $source = $this->trimmed('source'); // Not supported by Twitter. + $source = $this->trimmed('source'); // Not supported by Twitter. $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (!$source || in_array($source, $reserved_sources)) { + if (empty($source) || in_array($source, $reserved_sources)) { $source = 'api'; } $content = $this->trimmed('text'); - if (!$content) { - $this->clientError(_('No message text!'), $code = 406, $apidata['content-type']); + if (empty($content)) { + $this->clientError(_('No message text!'), + $code = 406, $apidata['content-type']); } else { $content_shortened = common_shorten_links($content); if (mb_strlen($content_shortened) > 140) { @@ -155,8 +150,9 @@ class Twitapidirect_messagesAction extends TwitterapiAction $other = $this->get_user($this->trimmed('user')); - if (!$other) { - $this->clientError(_('Recipient user not found.'), $code = 403, $apidata['content-type']); + if (empty($other)) { + $this->clientError(_('Recipient user not found.'), + $code = 403, $apidata['content-type']); return; } else if (!$user->mutuallySubscribed($other)) { $this->clientError(_('Can\'t send direct messages to users who aren\'t your friend.'), diff --git a/actions/twitapifavorites.php b/actions/twitapifavorites.php index 31dce341b7..8656adbe86 100644 --- a/actions/twitapifavorites.php +++ b/actions/twitapifavorites.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -31,50 +33,39 @@ class TwitapifavoritesAction extends TwitterapiAction $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - - $page = $this->arg('page'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - $notice = $user->favoriteNotices((($page-1)*20), $count); - - if (!$notice) { - $this->serverError(_('Could not retrieve favorite notices.')); - return; - } - - $sitename = common_config('site', 'name'); - $title = sprintf(_('%s / Favorites from %s'), $sitename, $user->nickname); + $sitename = common_config('site', 'name'); + $title = sprintf(_('%s / Favorites from %s'), $sitename, + $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:Favorites:".$user->id; - $link = common_local_url('favorites', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, $profile->getBestName(), $user->nickname); + $id = "tag:$taguribase:Favorites:".$user->id; + $link = common_local_url('favorites', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('%s updates favorited by %s / %s.'), $sitename, + $profile->getBestName(), $user->nickname); + + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); + + $notice = $user->favoriteNotices(($page-1)*$count, $count); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_timeline($notice); break; - case 'rss': + case 'rss': $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': if (isset($apidata['api_arg'])) { $selfuri = $selfuri = common_root_url() . 'api/favorites/' . $apidata['api_arg'] . '.atom'; @@ -82,12 +73,13 @@ class TwitapifavoritesAction extends TwitterapiAction $selfuri = $selfuri = common_root_url() . 'api/favorites.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); break; - case 'json': + case 'json': $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -100,7 +92,8 @@ class TwitapifavoritesAction extends TwitterapiAction // Check for RESTfulness if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { // XXX: Twitter just prints the err msg, no XML / JSON. - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } @@ -109,25 +102,27 @@ class TwitapifavoritesAction extends TwitterapiAction return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user + $notice_id = $apidata['api_arg']; $notice = Notice::staticGet($notice_id); - if (!$notice) { - $this->clientError(_('No status found with that ID.'), 404, $apidata['content-type']); + if (empty($notice)) { + $this->clientError(_('No status found with that ID.'), + 404, $apidata['content-type']); return; } // XXX: Twitter lets you fave things repeatedly via api. if ($user->hasFave($notice)) { - $this->clientError(_('This notice is already a favorite!'), 403, $apidata['content-type']); + $this->clientError(_('This notice is already a favorite!'), + 403, $apidata['content-type']); return; } $fave = Fave::addNew($user, $notice); - if (!$fave) { + if (empty($fave)) { $this->serverError(_('Could not create favorite.')); return; } @@ -149,7 +144,8 @@ class TwitapifavoritesAction extends TwitterapiAction $this->serverError(_('API method under construction.'), $code=501); } - // XXX: these two funcs swiped from faves. Maybe put in util.php, or some common base class? + // XXX: these two funcs swiped from faves. + // Maybe put in util.php, or some common base class? function notify($fave, $notice, $user) { diff --git a/actions/twitapifriendships.php b/actions/twitapifriendships.php index 2f8250e0dc..b1c277748a 100644 --- a/actions/twitapifriendships.php +++ b/actions/twitapifriendships.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -29,23 +31,25 @@ class TwitapifriendshipsAction extends TwitterapiAction parent::handle($args); if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } - $id = $apidata['api_arg']; - + $id = $apidata['api_arg']; $other = $this->get_user($id); - if (!$other) { - $this->clientError(_('Could not follow user: User not found.'), 403, $apidata['content-type']); + if (empty($other)) { + $this->clientError(_('Could not follow user: User not found.'), + 403, $apidata['content-type']); return; } $user = $apidata['user']; if ($user->isSubscribed($other)) { - $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), $other->nickname); + $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), + $other->nickname); $this->clientError($errmsg, 403, $apidata['content-type']); return; } @@ -60,8 +64,9 @@ class TwitapifriendshipsAction extends TwitterapiAction $result = $sub->insert(); - if (!$result) { - $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), $other->nickname); + if (empty($result)) { + $errmsg = sprintf(_('Could not follow user: %s is already on your list.'), + $other->nickname); $this->clientError($errmsg, 400, $apidata['content-type']); return; } @@ -82,7 +87,8 @@ class TwitapifriendshipsAction extends TwitterapiAction parent::handle($args); if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } @@ -91,7 +97,7 @@ class TwitapifriendshipsAction extends TwitterapiAction # We can't subscribe to a remote person, but we can unsub $other = $this->get_profile($id); - $user = $apidata['user']; + $user = $apidata['user']; // Alwyas the auth user $sub = new Subscription(); $sub->subscriber = $user->id; @@ -102,7 +108,8 @@ class TwitapifriendshipsAction extends TwitterapiAction $sub->delete(); $sub->query('COMMIT'); } else { - $this->clientError(_('You are not friends with the specified user.'), 403, $apidata['content-type']); + $this->clientError(_('You are not friends with the specified user.'), + 403, $apidata['content-type']); return; } @@ -128,8 +135,9 @@ class TwitapifriendshipsAction extends TwitterapiAction $user_a = $this->get_user($user_a_id); $user_b = $this->get_user($user_b_id); - if (!$user_a || !$user_b) { - $this->clientError(_('Two user ids or screen_names must be supplied.'), 400, $apidata['content-type']); + if (empty($user_a) || empty($user_b)) { + $this->clientError(_('Two user ids or screen_names must be supplied.'), + 400, $apidata['content-type']); return; } diff --git a/actions/twitapihelp.php b/actions/twitapihelp.php index db5892baf2..bdef1314af 100644 --- a/actions/twitapihelp.php +++ b/actions/twitapihelp.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 1fbde6639f..94f624afb9 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -26,64 +28,45 @@ class TwitapistatusesAction extends TwitterapiAction function public_timeline($args, $apidata) { - parent::handle($args); - - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s public timeline"), $sitename); - - $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:PublicTimeline"; - $link = common_root_url(); - - $subtitle = sprintf(_("%s updates from everyone!"), $sitename); - - // Number of public statuses to return by default -- Twitter sends 20 - $MAX_PUBSTATUSES = 20; - - // FIXME: To really live up to the spec we need to build a list + // XXX: To really live up to the spec we need to build a list // of notices by users who have custom avatars, so fix this SQL -- Zach - $page = $this->arg('page'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); + parent::handle($args); - if (!$page) { - $page = 1; - } - if (!$since_id) { - $since_id = 0; - } - if (!$max_id) { - $max_id = 0; - } + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s public timeline"), $sitename); + $taguribase = common_config('integration', 'taguri'); + $id = "tag:$taguribase:PublicTimeline"; + $link = common_root_url(); + $subtitle = sprintf(_("%s updates from everyone!"), $sitename); - $since = strtotime($this->arg('since')); + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $max_id, $since); + $notice = Notice::publicStream(($page-1)*$count, $count, $since_id, + $max_id, $since); - if ($notice) { - - switch($apidata['content-type']) { - case 'xml': - $this->show_xml_timeline($notice); - break; - case 'rss': - $this->show_rss_timeline($notice, $title, $link, $subtitle); - break; - case 'atom': - $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); - break; - case 'json': - $this->show_json_timeline($notice); - break; - default: - $this->clientError(_('API method not found!'), $code = 404); - break; - } - - } else { - $this->serverError(_('Couldn\'t find any statuses.'), $code = 503); + switch($apidata['content-type']) { + case 'xml': + $this->show_xml_timeline($notice); + break; + case 'rss': + $this->show_rss_timeline($notice, $title, $link, $subtitle); + break; + case 'atom': + $selfuri = common_root_url() . 'api/statuses/public_timeline.atom'; + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); + break; + case 'json': + $this->show_json_timeline($notice); + break; + default: + $this->clientError(_('API method not found!'), $code = 404); + break; } } @@ -92,68 +75,57 @@ class TwitapistatusesAction extends TwitterapiAction { parent::handle($args); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $count = $this->arg('count'); - $page = $this->arg('page'); - $max_id = $this->arg('max_id'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $user; if (empty($user)) { - $this->clientError(_('No such user!'), 404, $apidata['content-type']); + $this->clientError(_('No such user!'), 404, + $apidata['content-type']); return; } - $profile = $user->getProfile(); - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s and friends"), $user->nickname); + $profile = $user->getProfile(); + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s and friends"), $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:FriendsTimeline:" . $user->id; - $link = common_local_url('all', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename); + $id = "tag:$taguribase:FriendsTimeline:" . $user->id; + $link = common_local_url('all', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), + $user->nickname, $sitename); - $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $max_id, $since); + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); + + $notice = $user->noticesWithFriends(($page-1)*$count, + $count, $since_id, $max_id,$since); switch($apidata['content-type']) { - case 'xml': + case 'xml': $this->show_xml_timeline($notice); break; - case 'rss': + case 'rss': $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': if (isset($apidata['api_arg'])) { $selfuri = common_root_url() . - 'api/statuses/friends_timeline/' . $apidata['api_arg'] . '.atom'; + 'api/statuses/friends_timeline/' . + $apidata['api_arg'] . '.atom'; } else { $selfuri = common_root_url() . 'api/statuses/friends_timeline.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, null, $selfuri); break; - case 'json': + case 'json': $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -166,48 +138,21 @@ class TwitapistatusesAction extends TwitterapiAction $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - - $count = $this->arg('count'); - $since = $this->arg('since'); - $since_id = $this->arg('since_id'); - $page = $this->arg('page'); - $max_id = $this->arg('max_id'); - - if (!$page) { - $page = 1; - } - - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); - - $sitename = common_config('site', 'name'); - $title = sprintf(_("%s timeline"), $user->nickname); + $sitename = common_config('site', 'name'); + $title = sprintf(_("%s timeline"), $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:UserTimeline:".$user->id; - $link = common_local_url('showstream', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('Updates from %1$s on %2$s!'), $user->nickname, $sitename); + $id = "tag:$taguribase:UserTimeline:".$user->id; + $link = common_local_url('showstream', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('Updates from %1$s on %2$s!'), + $user->nickname, $sitename); # FriendFeed's SUP protocol # Also added RSS and Atom feeds @@ -215,26 +160,34 @@ class TwitapistatusesAction extends TwitterapiAction $suplink = common_local_url('sup', null, null, $user->id); header('X-SUP-ID: '.$suplink); - # XXX: since + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - $notice = $user->getNotices((($page-1)*20), $count, $since_id, $max_id, $since); + $notice = $user->getNotices(($page-1)*$count, + $count, $since_id, $max_id, $since); switch($apidata['content-type']) { case 'xml': $this->show_xml_timeline($notice); break; case 'rss': - $this->show_rss_timeline($notice, $title, $link, $subtitle, $suplink); + $this->show_rss_timeline($notice, $title, $link, + $subtitle, $suplink); break; case 'atom': if (isset($apidata['api_arg'])) { $selfuri = common_root_url() . - 'api/statuses/user_timeline/' . $apidata['api_arg'] . '.atom'; + 'api/statuses/user_timeline/' . + $apidata['api_arg'] . '.atom'; } else { $selfuri = common_root_url() . 'api/statuses/user_timeline.atom'; } - $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, $suplink, $selfuri); + $this->show_atom_timeline($notice, $title, $id, $link, + $subtitle, $suplink, $selfuri); break; case 'json': $this->show_json_timeline($notice); @@ -247,7 +200,6 @@ class TwitapistatusesAction extends TwitterapiAction function update($args, $apidata) { - parent::handle($args); if (!in_array($apidata['content-type'], array('xml', 'json'))) { @@ -256,21 +208,24 @@ class TwitapistatusesAction extends TwitterapiAction } if ($_SERVER['REQUEST_METHOD'] != 'POST') { - $this->clientError(_('This method requires a POST.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST.'), + 400, $apidata['content-type']); return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user + $status = $this->trimmed('status'); $source = $this->trimmed('source'); - $in_reply_to_status_id = intval($this->trimmed('in_reply_to_status_id')); + $in_reply_to_status_id = + intval($this->trimmed('in_reply_to_status_id')); $reserved_sources = array('web', 'omb', 'mail', 'xmpp', 'api'); - if (!$source || in_array($source, $reserved_sources)) { + + if (empty($source) || in_array($source, $reserved_sources)) { $source = 'api'; } - if (!$status) { + if (empty($status)) { // XXX: Note: In this case, Twitter simply returns '200 OK' // No error is given, but the status is not posted to the @@ -288,9 +243,9 @@ class TwitapistatusesAction extends TwitterapiAction // as "truncated." Sending this error may screw up some clients // that assume Twitter will truncate for them. Should we just // truncate too? -- Zach - $this->clientError(_('That\'s too long. Max notice size is 140 chars.'), $code = 406, $apidata['content-type']); + $this->clientError(_('That\'s too long. Max notice size is 140 chars.'), + $code = 406, $apidata['content-type']); return; - } } @@ -321,13 +276,15 @@ class TwitapistatusesAction extends TwitterapiAction if ($reply) { $reply_to = $in_reply_to_status_id; } else { - $this->clientError(_('Not found'), $code = 404, $apidata['content-type']); + $this->clientError(_('Not found'), $code = 404, + $apidata['content-type']); return; } } - $notice = Notice::saveNew($user->id, html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), - $source, 1, $reply_to); + $notice = Notice::saveNew($user->id, + html_entity_decode($status, ENT_NOQUOTES, 'UTF-8'), + $source, 1, $reply_to); if (is_string($notice)) { $this->serverError($notice); @@ -343,71 +300,55 @@ class TwitapistatusesAction extends TwitterapiAction function mentions($args, $apidata) { - parent::handle($args); - $since = $this->arg('since'); - $count = $this->arg('count'); - $page = $this->arg('page'); - $since_id = $this->arg('since_id'); - $max_id = $this->arg('max_id'); - $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $apidata['user']; + + if (empty($user)) { + $this->clientError(_('No such user!'), 404, + $apidata['content-type']); + return; + } + $profile = $user->getProfile(); - $sitename = common_config('site', 'name'); - $title = sprintf(_('%1$s / Updates mentioning %2$s'), + $sitename = common_config('site', 'name'); + $title = sprintf(_('%1$s / Updates mentioning %2$s'), $sitename, $user->nickname); $taguribase = common_config('integration', 'taguri'); - $id = "tag:$taguribase:Mentions:".$user->id; - $link = common_local_url('replies', array('nickname' => $user->nickname)); - $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), + $id = "tag:$taguribase:Mentions:".$user->id; + $link = common_local_url('replies', + array('nickname' => $user->nickname)); + $subtitle = sprintf(_('%1$s updates that reply to updates from %2$s / %3$s.'), $sitename, $user->nickname, $profile->getBestName()); - if (!$page) { - $page = 1; - } + $page = (int)$this->arg('page', 1); + $count = (int)$this->arg('count', 20); + $max_id = (int)$this->arg('max_id', 0); + $since_id = (int)$this->arg('since_id', 0); + $since = $this->arg('since'); - if (!$count) { - $count = 20; - } - - if (!$since_id) { - $since_id = 0; - } - - if (!$max_id) { - $max_id = 0; - } - - $since = strtotime($this->arg('since')); - - $notice = $user->getReplies((($page-1)*20), + $notice = $user->getReplies(($page-1)*$count, $count, $since_id, $max_id, $since); - $notices = array(); - - while ($notice->fetch()) { - $notices[] = clone($notice); - } switch($apidata['content-type']) { - case 'xml': - $this->show_xml_timeline($notices); + case 'xml': + $this->show_xml_timeline($notice); break; - case 'rss': - $this->show_rss_timeline($notices, $title, $link, $subtitle); + case 'rss': + $this->show_rss_timeline($notice, $title, $link, $subtitle); break; - case 'atom': + case 'atom': $selfuri = common_root_url() . ltrim($_SERVER['QUERY_STRING'], 'p='); - $this->show_atom_timeline($notices, $title, $id, $link, $subtitle, + $this->show_atom_timeline($notice, $title, $id, $link, $subtitle, null, $selfuri); break; - case 'json': - $this->show_json_timeline($notices); + case 'json': + $this->show_json_timeline($notice); break; - default: + default: $this->clientError(_('API method not found!'), $code = 404); } @@ -428,8 +369,8 @@ class TwitapistatusesAction extends TwitterapiAction } $this->auth_user = $apidata['user']; - $notice_id = $apidata['api_arg']; - $notice = Notice::staticGet($notice_id); + $notice_id = $apidata['api_arg']; + $notice = Notice::staticGet($notice_id); if ($notice) { if ($apidata['content-type'] == 'xml') { @@ -438,15 +379,16 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_single_json_status($notice); } } else { - // XXX: Twitter just sets a 404 header and doens't bother to return an err msg - $this->clientError(_('No status with that ID found.'), 404, $apidata['content-type']); + // XXX: Twitter just sets a 404 header and doens't bother + // to return an err msg + $this->clientError(_('No status with that ID found.'), + 404, $apidata['content-type']); } } function destroy($args, $apidata) { - parent::handle($args); if (!in_array($apidata['content-type'], array('xml', 'json'))) { @@ -457,17 +399,18 @@ class TwitapistatusesAction extends TwitterapiAction // Check for RESTfulness if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'DELETE'))) { // XXX: Twitter just prints the err msg, no XML / JSON. - $this->clientError(_('This method requires a POST or DELETE.'), 400, $apidata['content-type']); + $this->clientError(_('This method requires a POST or DELETE.'), + 400, $apidata['content-type']); return; } - $this->auth_user = $apidata['user']; - $user = $this->auth_user; + $user = $apidata['user']; // Always the auth user $notice_id = $apidata['api_arg']; - $notice = Notice::staticGet($notice_id); + $notice = Notice::staticGet($notice_id); - if (!$notice) { - $this->clientError(_('No status found with that ID.'), 404, $apidata['content-type']); + if (empty($notice)) { + $this->clientError(_('No status found with that ID.'), + 404, $apidata['content-type']); return; } @@ -483,7 +426,8 @@ class TwitapistatusesAction extends TwitterapiAction $this->show_single_json_status($notice); } } else { - $this->clientError(_('You may not delete another user\'s status.'), 403, $apidata['content-type']); + $this->clientError(_('You may not delete another user\'s status.'), + 403, $apidata['content-type']); } } @@ -514,42 +458,41 @@ class TwitapistatusesAction extends TwitterapiAction function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false) { - $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); - if (!$user) { + if (empty($user)) { $this->clientError('Not Found', 404, $apidata['content-type']); return; } - $page = $this->trimmed('page'); - - if (!$page || !is_numeric($page)) { - $page = 1; - } - $profile = $user->getProfile(); - if (!$profile) { - $this->serverError(_('User has no profile.')); - return; - } - $sub = new Subscription(); $sub->$user_attr = $profile->id; - $since = strtotime($this->trimmed('since')); - - if ($since) { - $d = date('Y-m-d H:i:s', $since); - $sub->whereAdd("created > '$d'"); - } - $sub->orderBy('created DESC'); + // Normally, page 100 friends at a time + if (!$onlyIDs) { - $sub->limit(($page-1)*100, 100); + $page = $this->arg('page', 1); + $count = $this->arg('count', 100); + $sub->limit(($page-1)*$count, $count); + } else { + + // If we're just looking at IDs, return + // ALL of them, unless the user specifies a page, + // in which case, return 500 per page. + + $page = $this->arg('page'); + if (!empty($page)) { + if ($page < 1) { + $page = 1; + } + $count = 500; + $sub->limit(($page-1)*$count, $count); + } } $others = array(); @@ -578,21 +521,21 @@ class TwitapistatusesAction extends TwitterapiAction function show_profiles($profiles, $type) { switch ($type) { - case 'xml': + case 'xml': $this->elementStart('users', array('type' => 'array')); foreach ($profiles as $profile) { $this->show_profile($profile); } $this->elementEnd('users'); break; - case 'json': + case 'json': $arrays = array(); foreach ($profiles as $profile) { $arrays[] = $this->twitter_user_array($profile, true); } print json_encode($arrays); break; - default: + default: $this->clientError(_('unsupported file type')); } } @@ -600,21 +543,21 @@ class TwitapistatusesAction extends TwitterapiAction function showIDs($profiles, $type) { switch ($type) { - case 'xml': + case 'xml': $this->elementStart('ids'); foreach ($profiles as $profile) { $this->element('id', null, $profile->id); } $this->elementEnd('ids'); break; - case 'json': + case 'json': $ids = array(); foreach ($profiles as $profile) { $ids[] = (int)$profile->id; } print json_encode($ids); break; - default: + default: $this->clientError(_('unsupported file type')); } } @@ -627,8 +570,8 @@ class TwitapistatusesAction extends TwitterapiAction function supported($cmd) { - - $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', 'FavCommand', 'OnCommand', 'OffCommand'); + $cmdlist = array('MessageCommand', 'SubCommand', 'UnsubCommand', + 'FavCommand', 'OnCommand', 'OffCommand'); if (in_array(get_class($cmd), $cmdlist)) { return true; diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index b90bbfa985..13a8746cd0 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/twitterapi.php'); @@ -51,18 +53,11 @@ class TwitapiusersAction extends TwitterapiAction $user = $apidata['user']; } - if (!$user) { + if (empty($user)) { $this->client_error(_('Not found.'), 404, $apidata['content-type']); return; } - $profile = $user->getProfile(); - - if (!$profile) { - common_server_error(_('User has no profile.')); - return; - } - $twitter_user = $this->twitter_user_array($profile, true); if ($apidata['content-type'] == 'xml') { diff --git a/classes/Notice.php b/classes/Notice.php index 895b5d2c71..1c48581492 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -120,7 +120,8 @@ class Notice extends Memcached_DataObject } } - static function saveNew($profile_id, $content, $source=null, $is_local=1, $reply_to=null, $uri=null) { + static function saveNew($profile_id, $content, $source=null, + $is_local=1, $reply_to=null, $uri=null, $created=null) { $profile = Profile::staticGet($profile_id); @@ -166,7 +167,11 @@ class Notice extends Memcached_DataObject $notice->query('BEGIN'); $notice->reply_to = $reply_to; - $notice->created = common_sql_now(); + if (!empty($created)) { + $notice->created = $created; + } else { + $notice->created = common_sql_now(); + } $notice->content = $final; $notice->rendered = common_render_content($final, $notice); $notice->source = $source; @@ -271,13 +276,15 @@ class Notice extends Memcached_DataObject function getUploadedAttachment() { $post = clone $this; - $query = 'select file.url as uploaded from file join file_to_post on file.id = file_id where post_id=' . $post->escape($post->id) . ' and url like "%/notice/%/file"'; + $query = 'select file.url as up, file.id as i from file join file_to_post on file.id = file_id where post_id=' . $post->escape($post->id) . ' and url like "%/notice/%/file"'; $post->query($query); $post->fetch(); - $ret = $post->uploaded; -// var_dump($post); + if (empty($post->up) || empty($post->i)) { + $ret = false; + } else { + $ret = array($post->up, $post->i); + } $post->free(); -// die(); return $ret; } diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index 8a27e17478..673e187c72 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -85,4 +85,9 @@ class Notice_inbox extends Memcached_DataObject return $ids; } + + function &pkeyGet($kv) + { + return Memcached_DataObject::pkeyGet('Notice_inbox', $kv); + } } diff --git a/js/util.js b/js/util.js index b712ba8e2b..fd2500d447 100644 --- a/js/util.js +++ b/js/util.js @@ -178,7 +178,14 @@ $(document).ready(function(){ $('#form_notice').append(document._importNode($(".error", xhr.responseXML).get(0), true)); } else { - alert("Sorry! We had trouble sending your notice ("+xhr.status+" "+xhr.statusText+"). Please report the problem to the site administrator if this happens again."); + var HTTP20x30x = [200, 201, 202, 203, 204, 205, 206, 300, 301, 302, 303, 304, 305, 306, 307]; + if(jQuery.inArray(parseInt(xhr.status), HTTP20x30x) < 0) { + alert("Sorry! We had trouble sending your notice ("+xhr.status+" "+xhr.statusText+"). Please report the problem to the site administrator if this happens again."); + } + else { + $("#notice_data-text").val(""); + counter(); + } } } }, @@ -196,10 +203,20 @@ $(document).ready(function(){ else { li = $("li", xml).get(0); if ($("#"+li.id).length == 0) { - $("#notices_primary .notices").prepend(document._importNode(li, true)); - $("#notices_primary .notice:first").css({display:"none"}); - $("#notices_primary .notice:first").fadeIn(2500); - NoticeReply(); + var notice_irt_value = $('#notice_in-reply-to').val(); + var notice_irt = '#notices_primary #notice-'+notice_irt_value; + if($('body')[0].id == 'conversation') { + if(notice_irt_value.length > 0 && $(notice_irt+' .notices').length < 1) { + $(notice_irt).append('
    '); + } + $($(notice_irt+' .notices')[0]).append(document._importNode(li, true)); + } + else { + $("#notices_primary .notices").prepend(document._importNode(li, true)); + } + $('#'+li.id).css({display:'none'}); + $('#'+li.id).fadeIn(2500); + NoticeReply(); } } $("#notice_data-text").val(""); @@ -303,4 +320,3 @@ function NoticeAttachments() { } ); } - diff --git a/lib/action.php b/lib/action.php index 55fb7c0896..89a8c8f4d3 100644 --- a/lib/action.php +++ b/lib/action.php @@ -124,7 +124,6 @@ class Action extends HTMLOutputter // lawsuit $this->showShortcutIcon(); $this->showStylesheets(); $this->showScripts(); - $this->showRelationshipLinks(); $this->showOpenSearch(); $this->showFeeds(); $this->showDescription(); @@ -224,16 +223,6 @@ class Action extends HTMLOutputter // lawsuit 'href="'.theme_path('css/ie.css', null).'?version='.LACONICA_VERSION.'" />getDesign(); - if (!empty($design)) { - $cur = common_current_user(); - if (empty($cur) || $cur->viewdesigns) { - $design->showCSS($this); - } - } - Event::handle('EndShowDesign', array($this, $design)); - } Event::handle('EndShowStyles', array($this)); } } @@ -258,6 +247,7 @@ class Action extends HTMLOutputter // lawsuit 'src' => common_path('js/jquery.joverlay.min.js')), ' '); + Event::handle('EndShowJQueryScripts', array($this)); } if (Event::handle('StartShowLaconicaScripts', array($this))) { @@ -276,19 +266,6 @@ class Action extends HTMLOutputter // lawsuit } } - /** - * Show document relationship links - * - * SHOULD overload - * - * @return nothing - */ - function showRelationshipLinks() - { - // output elements with appropriate HTML4.01 link types: - // http://www.w3.org/TR/html401/types.html#type-links - } - /** * Show OpenSearch headers * @@ -598,20 +575,32 @@ class Action extends HTMLOutputter // lawsuit /** * Show page notice block. * + * Only show the block if a subclassed action has overrided + * Action::showPageNotice(), or an event handler is registered for + * the StartShowPageNotice event, in which case we assume the + * 'page_notice' definition list is desired. This is to prevent + * empty 'page_notice' definition lists from being output everywhere. + * * @return nothing */ function showPageNoticeBlock() { - $this->elementStart('dl', array('id' => 'page_notice', - 'class' => 'system_notice')); - $this->element('dt', null, _('Page notice')); - $this->elementStart('dd'); - if (Event::handle('StartShowPageNotice', array($this))) { - $this->showPageNotice(); - Event::handle('EndShowPageNotice', array($this)); + $rmethod = new ReflectionMethod($this, 'showPageNotice'); + $dclass = $rmethod->getDeclaringClass()->getName(); + + if ($dclass != 'Action' || Event::hasHandler('StartShowPageNotice')) { + + $this->elementStart('dl', array('id' => 'page_notice', + 'class' => 'system_notice')); + $this->element('dt', null, _('Page notice')); + $this->elementStart('dd'); + if (Event::handle('StartShowPageNotice', array($this))) { + $this->showPageNotice(); + Event::handle('EndShowPageNotice', array($this)); + } + $this->elementEnd('dd'); + $this->elementEnd('dl'); } - $this->elementEnd('dd'); - $this->elementEnd('dl'); } /** @@ -1072,51 +1061,4 @@ class Action extends HTMLOutputter // lawsuit { return null; } - - /** - * Generate document metadata for sequential navigation - * - * @param boolean $have_before is there something before? - * @param boolean $have_after is there something after? - * @param integer $page current page - * @param string $action current action - * @param array $args rest of query arguments - * - * @return nothing - */ - function sequenceRelationships($have_next, $have_previous, $page, $action, $args=null) - { - // Outputs machine-readable pagination in elements. - // Pattern taken from $this->pagination() method. - - // "next" is equivalent to "after" - if ($have_next) { - $pargs = array('page' => $page-1); - $this->element('link', array('rel' => 'next', - 'href' => common_local_url($action, $args, $pargs), - 'title' => _('Next'))); - } - // "previous" is equivalent to "before" - if ($have_previous=true) { // FIXME - $pargs = array('page' => $page+1); - $this->element('link', array('rel' => 'prev', - 'href' => common_local_url($action, $args, $pargs), - 'title' => _('Previous'))); - } - } - - /** - * A design for this action - * - * A design (colors and background) for the current page. May be - * the user's design, or a group's design, or a site design. - * - * @return Design a design object to use - */ - - function getDesign() - { - // XXX: return site design by default - return null; - } } diff --git a/lib/event.php b/lib/event.php index d815ae54ba..4ccee17e66 100644 --- a/lib/event.php +++ b/lib/event.php @@ -110,4 +110,32 @@ class Event { } return ($result !== false); } + + /** + * Check to see if an event handler exists + * + * Look to see if there's any handler for a given event, or narrow + * by providing the name of a specific plugin class. + * + * @param string $name Name of the event to look for + * @param string $plugin Optional name of the plugin class to look for + * + * @return boolean flag saying whether such a handler exists + * + */ + + public static function hasHandler($name, $plugin=null) { + if (array_key_exists($name, Event::$_handlers)) { + if (isset($plugin)) { + foreach (Event::$_handlers[$name] as $handler) { + if (get_class($handler[0]) == $plugin) { + return true; + } + } + } else { + return true; + } + } + return false; + } } diff --git a/lib/noticeform.php b/lib/noticeform.php index 5d7cf194ee..3212f382ad 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -148,6 +148,7 @@ class NoticeForm extends Form $this->out->element('dd', array('id' => 'notice_text-count'), '140'); $this->out->elementEnd('dl'); + $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); $this->out->element('label', array('for' => 'notice_data-attach'), _('Attach')); $this->out->element('input', array('id' => 'notice_data-attach', 'type' => 'file', @@ -157,7 +158,6 @@ class NoticeForm extends Form $this->out->hidden('notice_return-to', $this->action, 'returnto'); } $this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto'); - $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); } /** diff --git a/lib/noticelist.php b/lib/noticelist.php index c00942af49..e449970045 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -365,7 +365,7 @@ class NoticeListItem extends Widget } $uploaded = $this->notice->getUploadedAttachment(); if ($uploaded) { - $this->out->element('a', array('href' => $uploaded, 'class' => 'attachment'), $uploaded); + $this->out->element('a', array('href' => $uploaded[0], 'class' => 'attachment', 'id' => 'attachment-' . $uploaded[1]), $uploaded[0]); } $this->out->elementEnd('p'); } diff --git a/lib/rssaction.php b/lib/rssaction.php index 2f25ed7e47..eafdbf131d 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -170,7 +170,7 @@ class Rss10Action extends Action $this->elementStart('rdf:Seq'); foreach ($this->notices as $notice) { - $this->element('sioct:MicroblogPost', array('rdf:resource' => $notice->uri)); + $this->element('rdf:li', array('rdf:resource' => $notice->uri)); } $this->elementEnd('rdf:Seq'); @@ -197,14 +197,19 @@ class Rss10Action extends Action $profile = Profile::staticGet($notice->profile_id); $nurl = common_local_url('shownotice', array('notice' => $notice->id)); $creator_uri = common_profile_uri($profile); - $this->elementStart('item', array('rdf:about' => $notice->uri)); + $this->elementStart('item', array('rdf:about' => $notice->uri, + 'rdf:type' => 'http://rdfs.org/sioc/types#MicroblogPost')); $title = $profile->nickname . ': ' . common_xml_safe_str(trim($notice->content)); $this->element('title', null, $title); $this->element('link', null, $nurl); $this->element('description', null, $profile->nickname."'s status on ".common_exact_date($notice->created)); + if ($notice->rendered) { + $this->element('content:encoded', null, common_xml_safe_str($notice->rendered)); + } $this->element('dc:date', null, common_date_w3dtf($notice->created)); $this->element('dc:creator', null, ($profile->fullname) ? $profile->fullname : $profile->nickname); - $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri)); + $this->element('foaf:maker', array('rdf:resource' => $creator_uri)); + $this->element('sioc:has_creator', array('rdf:resource' => $creator_uri.'#acct')); $this->element('laconica:postIcon', array('rdf:resource' => $profile->avatarUrl())); $this->element('cc:licence', array('rdf:resource' => common_config('license', 'url'))); $this->elementEnd('item'); @@ -216,15 +221,15 @@ class Rss10Action extends Action foreach ($this->creators as $uri => $profile) { $id = $profile->id; $nickname = $profile->nickname; - $this->elementStart('sioc:User', array('rdf:about' => $uri)); + $this->elementStart('foaf:Agent', array('rdf:about' => $uri)); $this->element('foaf:nick', null, $nickname); if ($profile->fullname) { $this->element('foaf:name', null, $profile->fullname); } - $this->element('sioc:id', null, $id); + $this->element('foaf:holdsAccount', array('rdf:resource' => $uri.'#acct')); $avatar = $profile->avatarUrl(); - $this->element('sioc:avatar', array('rdf:resource' => $avatar)); - $this->elementEnd('sioc:User'); + $this->element('foaf:depiction', array('rdf:resource' => $avatar)); + $this->elementEnd('foaf:Agent'); } } @@ -239,7 +244,7 @@ class Rss10Action extends Action 'xmlns:dc' => 'http://purl.org/dc/elements/1.1/', 'xmlns:cc' => - 'http://web.resource.org/cc/', + 'http://creativecommons.org/ns#', 'xmlns:content' => 'http://purl.org/rss/1.0/modules/content/', 'xmlns:foaf' => @@ -253,10 +258,10 @@ class Rss10Action extends Action 'xmlns' => 'http://purl.org/rss/1.0/')); $this->elementStart('sioc:Site', array('rdf:about' => common_root_url())); $this->element('sioc:name', null, common_config('site', 'name')); - $this->elementStart('sioc:container_of'); + $this->elementStart('sioc:space_of'); $this->element('sioc:Container', array('rdf:about' => $channel['url'])); - $this->elementEnd('sioc:container_of'); + $this->elementEnd('sioc:space_of'); $this->elementEnd('sioc:Site'); } diff --git a/lib/twitterapi.php b/lib/twitterapi.php index ca8b03cdcd..569bc6d7a2 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} class TwitterapiAction extends Action { @@ -521,11 +523,11 @@ class TwitterapiAction extends Action function init_document($type='xml') { switch ($type) { - case 'xml': + case 'xml': header('Content-Type: application/xml; charset=utf-8'); $this->startXML(); break; - case 'json': + case 'json': header('Content-Type: application/json; charset=utf-8'); // Check for JSONP callback @@ -534,15 +536,15 @@ class TwitterapiAction extends Action print $callback . '('; } break; - case 'rss': + case 'rss': header("Content-Type: application/rss+xml; charset=utf-8"); $this->init_twitter_rss(); break; - case 'atom': + case 'atom': header('Content-Type: application/atom+xml; charset=utf-8'); $this->init_twitter_atom(); break; - default: + default: $this->client_error(_('Not a supported data format.')); break; } @@ -553,10 +555,10 @@ class TwitterapiAction extends Action function end_document($type='xml') { switch ($type) { - case 'xml': + case 'xml': $this->endXML(); break; - case 'json': + case 'json': // Check for JSONP callback $callback = $this->arg('callback'); @@ -564,13 +566,13 @@ class TwitterapiAction extends Action print ')'; } break; - case 'rss': + case 'rss': $this->end_twitter_rss(); break; - case 'atom': + case 'atom': $this->end_twitter_rss(); break; - default: + default: $this->client_error(_('Not a supported data format.')); break; } @@ -657,13 +659,13 @@ class TwitterapiAction extends Action { $profile_array = $this->twitter_user_array($profile, true); switch ($content_type) { - case 'xml': + case 'xml': $this->show_twitter_xml_user($profile_array); break; - case 'json': + case 'json': $this->show_json_objects($profile_array); break; - default: + default: $this->client_error(_('Not a supported data format.')); return; } @@ -672,8 +674,8 @@ class TwitterapiAction extends Action function get_user($id, $apidata=null) { - if (!$id) { - + if (empty($id)) { + // Twitter supports these other ways of passing the user ID if (is_numeric($this->arg('id'))) { return User::staticGet($this->arg('id')); @@ -681,7 +683,7 @@ class TwitterapiAction extends Action $nickname = common_canonical_nickname($this->arg('id')); return User::staticGet('nickname', $nickname); } else if ($this->arg('user_id')) { - // This is to ensure that a non-numeric user_id still + // This is to ensure that a non-numeric user_id still // overrides screen_name even if it doesn't get used if (is_numeric($this->arg('user_id'))) { return User::staticGet('id', $this->arg('user_id')); @@ -693,7 +695,7 @@ class TwitterapiAction extends Action // Fall back to trying the currently authenticated user return $apidata['user']; } - + } else if (is_numeric($id)) { return User::staticGet($id); } else { @@ -720,13 +722,13 @@ class TwitterapiAction extends Action { $source_name = _($source); switch ($source) { - case 'web': - case 'xmpp': - case 'mail': - case 'omb': - case 'api': + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'api': break; - default: + default: $ns = Notice_source::staticGet($source); if ($ns) { $source_name = '' . $ns->name . ''; @@ -736,4 +738,49 @@ class TwitterapiAction extends Action return $source_name; } + /** + * Returns query argument or default value if not found. Certain + * parameters used throughout the API are lightly scrubbed and + * bounds checked. This overrides Action::arg(). + * + * @param string $key requested argument + * @param string $def default value to return if $key is not provided + * + * @return var $var + */ + function arg($key, $def=null) + { + + // XXX: Do even more input validation/scrubbing? + + if (array_key_exists($key, $this->args)) { + switch($key) { + case 'page': + $page = (int)$this->args['page']; + return ($page < 1) ? 1 : $page; + case 'count': + $count = (int)$this->args['count']; + if ($count < 1) { + return 20; + } elseif ($count > 200) { + return 200; + } else { + return $count; + } + case 'since_id': + $since_id = (int)$this->args['since_id']; + return ($since_id < 1) ? 0 : $since_id; + case 'max_id': + $max_id = (int)$this->args['max_id']; + return ($max_id < 1) ? 0 : $max_id; + case 'since': + return strtotime($this->args['since']); + default: + return parent::arg($key, $def); + } + } else { + return $def; + } + } + } diff --git a/lib/util.php b/lib/util.php index 9872d97c48..b3a94a5a01 100644 --- a/lib/util.php +++ b/lib/util.php @@ -922,7 +922,6 @@ function common_enqueue_notice_transport($notice, $transport) $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); common_log(LOG_ERR, 'DB error inserting queue item: ' . $last_error->message); throw new ServerException('DB error inserting queue item: ' . $last_error->message); ->>>>>>> 0.7.x:lib/util.php } common_log(LOG_DEBUG, 'complete queueing notice ID = ' . $notice->id . ' for ' . $transport); return true; diff --git a/scripts/twitterstatusfetcher.php b/scripts/twitterstatusfetcher.php index a61ce1b0d1..9287b6d733 100755 --- a/scripts/twitterstatusfetcher.php +++ b/scripts/twitterstatusfetcher.php @@ -255,42 +255,11 @@ class TwitterStatusFetcher extends Daemon // check to see if we've already imported the status if (!$notice) { - $notice = new Notice(); - $notice->profile_id = $id; + $created = strftime('%Y-%m-%d %H:%M:%S', + strtotime($status->created_at));; - $notice->query('BEGIN'); - - // XXX: figure out reply_to - $notice->reply_to = null; - - // XXX: Should this be common_sql_now() instead of status create date? - - $notice->created = strftime('%Y-%m-%d %H:%M:%S', - strtotime($status->created_at)); - $notice->content = $status->text; - $notice->rendered = common_render_content($status->text, $notice); - $notice->source = 'twitter'; - $notice->is_local = 0; - $notice->uri = $uri; - - $notice_id = $notice->insert(); - - if (!$notice_id) { - common_log_db_error($notice, 'INSERT', __FILE__); - if (defined('SCRIPT_DEBUG')) { - common_debug('Could not save notice!'); - } - } - - // XXX: Figure out a better way to link Twitter replies? - $notice->saveReplies(); - - // XXX: Do we want to pollute our tag cloud with - // hashtags from Twitter? - $notice->saveTags(); - $notice->saveGroups(); - - $notice->query('COMMIT'); + $notice = Notice::saveNew($id, $status->text, 'twitter', + -2, null, $uri, $created); if (defined('SCRIPT_DEBUG')) { common_debug("Saved status $status->id" . @@ -298,13 +267,13 @@ class TwitterStatusFetcher extends Daemon } } - if (!Notice_inbox::staticGet('notice_id', $notice->id)) { - + if (!Notice_inbox::pkeyGet(array('notice_id' => $notice->id, + 'user_id' => $flink->user_id))) { // Add to inbox $inbox = new Notice_inbox(); $inbox->user_id = $flink->user_id; $inbox->notice_id = $notice->id; - $inbox->created = common_sql_now(); + $inbox->created = $notice->created; $inbox->insert(); } diff --git a/theme/base/images/icons/clip-big.png b/theme/base/images/icons/clip-big.png deleted file mode 100644 index 3945f56cc0..0000000000 Binary files a/theme/base/images/icons/clip-big.png and /dev/null differ diff --git a/theme/base/images/icons/clip-inline.png b/theme/base/images/icons/clip-inline.png deleted file mode 100644 index 870f8b2e8f..0000000000 Binary files a/theme/base/images/icons/clip-inline.png and /dev/null differ diff --git a/theme/base/images/icons/clip.png b/theme/base/images/icons/clip.png deleted file mode 100644 index 3c5a17d18b..0000000000 Binary files a/theme/base/images/icons/clip.png and /dev/null differ