From 32f81b3c0e7be3da35d5813e5409fa3b65dc220e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 24 Jan 2009 18:38:12 +0100 Subject: Initial support for ping service It makes sense to use the weblogs.com ping service to alert people to changes on the site. So, we do. Includes an extra ping queue handler. --- lib/common.php | 2 ++ lib/ping.php | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/util.php | 2 +- 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 lib/ping.php (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index a2f9b9bfe..cc82f8bd7 100644 --- a/lib/common.php +++ b/lib/common.php @@ -128,6 +128,8 @@ $config = array('enabled' => false, 'server' => 'localhost', 'port' => 11211), + 'ping' => + array('notify' => array()), 'inboxes' => array('enabled' => true), # on by default for new sites ); diff --git a/lib/ping.php b/lib/ping.php new file mode 100644 index 000000000..32c0b9806 --- /dev/null +++ b/lib/ping.php @@ -0,0 +1,79 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +function ping_broadcast_notice($notice) { + if (!$notice->is_local) { + return; + } + + # Array of servers, URL => type + $notify = common_config('ping', 'notify'); + $profile = $notice->getProfile(); + $tags = ping_notice_tags($notice); + + foreach ($notify as $notify_url => $type) { + switch ($type) { + case 'xmlrpc': + case 'extended': + $req = xmlrpc_encode_request('weblogUpdates.ping', + array($profile->nickname, # site name + common_local_url('showstream', + array('nickname' => $profile->nickname)), + common_local_url('shownotice', + array('notice' => $notice->id)), + common_local_url('userrss', + array('nickname' => $profile->nickname)), + $tags)); + + # We re-use this tool's fetcher, since it's pretty good + + $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); + + if (!$fetcher) { + common_log(LOG_WARNING, 'Failed to initialize Yadis fetcher.', __FILE__); + return false; + } + + $result = $fetcher->post($notify_url, + $req); + + case 'get': + case 'post': + default: + common_log(LOG_WARNING, 'Unknown notify type for ' . $notify_url . ': ' . $type); + } + } +} + +function ping_notice_tags($notice) { + $tag = new Notice_tag(); + $tag->notice_id = $notice->id; + $tags = array(); + if ($tag->find()) { + while ($tag->fetch()) { + $tags[] = $tag->tag; + } + $tag->free(); + unset($tag); + return implode('|', $tags); + } + return NULL; +} \ No newline at end of file diff --git a/lib/util.php b/lib/util.php index b5b194519..419e21e82 100644 --- a/lib/util.php +++ b/lib/util.php @@ -1124,7 +1124,7 @@ function common_twitter_broadcast($notice, $flink) function common_enqueue_notice($notice) { - foreach (array('jabber', 'omb', 'sms', 'public') as $transport) { + foreach (array('jabber', 'omb', 'sms', 'public', 'ping') as $transport) { $qi = new Queue_item(); $qi->notice_id = $notice->id; $qi->transport = $transport; -- cgit v1.2.3-54-g00ecf From d90089314944ed1696f66cabbb6935ea61e4b2e6 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Sat, 7 Feb 2009 10:01:08 -0500 Subject: Fixed #1152: Needless image scaling and poor JPG quality --- lib/imagefile.php | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/imagefile.php b/lib/imagefile.php index 74c3d14f0..faec7f0ff 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -112,6 +112,23 @@ class ImageFile throw new Exception(_('Lost our file.')); return; } + + // Don't crop/scale if it isn't necessary + if ($size === $this->width + && $size === $this->height + && $x === 0 + && $y === 0 + && $w === $this->width + && $h === $this->height) { + + $outname = common_avatar_filename($this->id, + image_type_to_extension($this->type), + $size, + common_timestamp()); + $outpath = common_avatar_path($outname); + @copy($this->filepath, $outpath); + return $outname; + } switch ($this->type) { case IMAGETYPE_GIF: @@ -165,7 +182,7 @@ class ImageFile imagegif($image_dest, $outpath); break; case IMAGETYPE_JPEG: - imagejpeg($image_dest, $outpath); + imagejpeg($image_dest, $outpath, 100); break; case IMAGETYPE_PNG: imagepng($image_dest, $outpath); @@ -174,6 +191,9 @@ class ImageFile throw new Exception(_('Unknown file type')); return; } + + imagedestroy($image_src); + imagedestroy($image_dest); return $outname; } -- cgit v1.2.3-54-g00ecf From 805560677bc66a58c270551fa54b613642b3af97 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Sat, 7 Feb 2009 11:10:46 -0500 Subject: Fixed references to common_avatar_*. --- lib/imagefile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/imagefile.php b/lib/imagefile.php index a8e963370..ea24029a3 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -121,11 +121,11 @@ class ImageFile && $w === $this->width && $h === $this->height) { - $outname = common_avatar_filename($this->id, + $outname = Avatar::filename($this->id, image_type_to_extension($this->type), $size, common_timestamp()); - $outpath = common_avatar_path($outname); + $outpath = Avatar::path($outname); @copy($this->filepath, $outpath); return $outname; } -- cgit v1.2.3-54-g00ecf From 43888b523919f816e45a956a2e9f7d10416067df Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 9 Feb 2009 15:35:38 +0000 Subject: trac #1160 fix dropdown xmloutput function for the selected attribute and fix newmessage auto-selected dropdown. --- actions/newmessage.php | 2 +- lib/htmloutputter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/actions/newmessage.php b/actions/newmessage.php index f83015a37..82276ff34 100644 --- a/actions/newmessage.php +++ b/actions/newmessage.php @@ -201,7 +201,7 @@ class NewmessageAction extends Action function showNoticeForm() { - $message_form = new MessageForm($this, $this->to, $this->content); + $message_form = new MessageForm($this, $this->other, $this->content); $message_form->show(); } } diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 7780b1c19..e2319b1fd 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -255,7 +255,7 @@ class HTMLOutputter extends XMLOutputter foreach ($content as $value => $option) { if ($value == $selected) { $this->element('option', array('value' => $value, - 'selected' => $value), + 'selected' => 'selected'), $option); } else { $this->element('option', array('value' => $value), $option); -- cgit v1.2.3-54-g00ecf From 9e23b5c5d706f4573261d6530688a44a8b80bcf4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 9 Feb 2009 11:46:26 -0500 Subject: Change action autoloading to allow actions in plugins Since plugins may define custom actions, we shouldn't require that there be a file in our actions/ subdir for every action. So, I changed the (admittedly hackish) auto-loading code in index.php so it instead checks whether a class exists with the expected name. This, in turn, uses the increasingly hacking __autoload() function, which I changed to auto-load stuff named "BlahblahAction" from the actions subdir if available. --- index.php | 13 ++++++------- lib/common.php | 3 +++ 2 files changed, 9 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/index.php b/index.php index 0a79b9731..e62d9469a 100644 --- a/index.php +++ b/index.php @@ -22,6 +22,8 @@ define('LACONICA', true); require_once INSTALLDIR . '/lib/common.php'; +// XXX: we need a little more structure in this script + // get and cache current user $user = common_current_user(); @@ -45,19 +47,16 @@ if (!$user && common_config('site', 'private') && common_redirect(common_local_url('login')); } -$actionfile = INSTALLDIR."/actions/$action.php"; +$action_class = ucfirst($action).'Action'; -if (!file_exists($actionfile)) { +if (!class_exists($action_class)) { $cac = new ClientErrorAction(_('Unknown action'), 404); $cac->showPage(); } else { - - include_once $actionfile; - - $action_class = ucfirst($action).'Action'; - $action_obj = new $action_class(); + // XXX: find somewhere for this little block to live + if ($config['db']['mirror'] && $action_obj->isReadOnly()) { if (is_array($config['db']['mirror'])) { // "load balancing", ha ha diff --git a/lib/common.php b/lib/common.php index 041459cf3..7bfd14c42 100644 --- a/lib/common.php +++ b/lib/common.php @@ -211,6 +211,9 @@ function __autoload($class) require_once(INSTALLDIR.'/classes/' . $class . '.php'); } else if (file_exists(INSTALLDIR.'/lib/' . strtolower($class) . '.php')) { require_once(INSTALLDIR.'/lib/' . strtolower($class) . '.php'); + } else if (mb_substr($class, -6) == 'Action' && + file_exists(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php')) { + require_once(INSTALLDIR.'/actions/' . strtolower(mb_substr($class, 0, -6)) . '.php'); } } -- cgit v1.2.3-54-g00ecf From c1bc77efd968aecd465fb6173d20bd386016eae2 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 9 Feb 2009 12:06:06 -0500 Subject: whitespace and formatting --- lib/imagefile.php | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/lib/imagefile.php b/lib/imagefile.php index ea24029a3..0c93b257e 100644 --- a/lib/imagefile.php +++ b/lib/imagefile.php @@ -68,17 +68,17 @@ class ImageFile static function fromUpload($param='upload') { switch ($_FILES[$param]['error']) { - case UPLOAD_ERR_OK: // success, jump out + case UPLOAD_ERR_OK: // success, jump out break; - case UPLOAD_ERR_INI_SIZE: - case UPLOAD_ERR_FORM_SIZE: + case UPLOAD_ERR_INI_SIZE: + case UPLOAD_ERR_FORM_SIZE: throw new Exception(sprintf(_('That file is too big. The maximum file size is %d.'), $this->maxFileSize())); return; - case UPLOAD_ERR_PARTIAL: + case UPLOAD_ERR_PARTIAL: @unlink($_FILES[$param]['tmp_name']); throw new Exception(_('Partial upload.')); return; - default: + default: throw new Exception(_('System error uploading file.')); return; } @@ -112,19 +112,19 @@ class ImageFile throw new Exception(_('Lost our file.')); return; } - + // Don't crop/scale if it isn't necessary - if ($size === $this->width - && $size === $this->height - && $x === 0 - && $y === 0 + if ($size === $this->width + && $size === $this->height + && $x === 0 + && $y === 0 && $w === $this->width && $h === $this->height) { - + $outname = Avatar::filename($this->id, - image_type_to_extension($this->type), - $size, - common_timestamp()); + image_type_to_extension($this->type), + $size, + common_timestamp()); $outpath = Avatar::path($outname); @copy($this->filepath, $outpath); return $outname; @@ -171,9 +171,9 @@ class ImageFile imagecopyresampled($image_dest, $image_src, 0, 0, $x, $y, $size, $size, $w, $h); $outname = Avatar::filename($this->id, - image_type_to_extension($this->type), - $size, - common_timestamp()); + image_type_to_extension($this->type), + $size, + common_timestamp()); $outpath = Avatar::path($outname); @@ -191,7 +191,7 @@ class ImageFile throw new Exception(_('Unknown file type')); return; } - + imagedestroy($image_src); imagedestroy($image_dest); @@ -229,12 +229,12 @@ class ImageFile $num = substr($str, 0, -1); switch(strtoupper($unit)){ - case 'G': - $num *= 1024; - case 'M': - $num *= 1024; - case 'K': - $num *= 1024; + case 'G': + $num *= 1024; + case 'M': + $num *= 1024; + case 'K': + $num *= 1024; } return $num; -- cgit v1.2.3-54-g00ecf From 3e005f2d1bf01c295c132b6ca52e1139ef60b733 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 6 Feb 2009 21:17:45 -0800 Subject: "Change your email address..." msg was printing out \n instead of a newline --- lib/mail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/mail.php b/lib/mail.php index b424d579f..a1faefc80 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -246,7 +246,7 @@ function mail_subscribe_notify_profile($listenee, $other) "\n".'Faithfully yours,'."\n".'%7$s.'."\n\n". "----\n". "Change your email address or ". - "notification options at ".'%8$s\n'), + "notification options at ".'%8$s' ."\n"), $long_name, common_config('site', 'name'), $other->profileurl, -- cgit v1.2.3-54-g00ecf From 32744124bcb8aa0683490a56defd4a79f072d278 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 9 Feb 2009 16:56:38 -0500 Subject: Add a hook for showing sidebar sections --- EVENTS.txt | 5 +++++ lib/action.php | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index 4b8260b3c..d9634325d 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -34,3 +34,8 @@ StartShowLaconicaScripts: Showing Laconica script links (use this to link to a C EndShowLaconicaScripts: End showing Laconica script links - $action: the current action +StartShowSections: Start the list of sections in the sidebar +- $action: the current action + +EndShowSections: End the list of sections in the sidebar +- $action: the current action diff --git a/lib/action.php b/lib/action.php index 0628dc70d..ce92addf5 100644 --- a/lib/action.php +++ b/lib/action.php @@ -524,12 +524,16 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ + function showAside() { $this->elementStart('div', array('id' => 'aside_primary', 'class' => 'aside')); $this->showExportData(); - $this->showSections(); + if (Event::handle('StartShowSections', array($this))) { + $this->showSections(); + Event::handle('EndShowSections', array($this)); + } $this->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From f6705f06c0a8251c0f3eb0fe88532e75645f7705 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Mon, 9 Feb 2009 17:29:27 -0500 Subject: Fixed #1170: Auto-linking bug when URL cotains special chars. --- lib/util.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 7ce4e229e..5204693bc 100644 --- a/lib/util.php +++ b/lib/util.php @@ -412,8 +412,8 @@ function common_replace_urls_callback($text, $callback) { // Then clean up what the regex left behind $offset = 0; - foreach($matches[0] as $url) { - $url = htmlspecialchars_decode($url); + foreach($matches[0] as $orig_url) { + $url = htmlspecialchars_decode($orig_url); // Make sure we didn't pick up an email address if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue; @@ -456,6 +456,9 @@ function common_replace_urls_callback($text, $callback) { if (!in_array($url_parts[2], $tlds)) continue; + // Put the url back the way we found it. + $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); + // Call user specified func $modified_url = $callback($url); -- cgit v1.2.3-54-g00ecf From 0d586524874560c51277b90f33bcbed164748f6d Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 9 Feb 2009 15:35:38 +0000 Subject: trac #1160 fix dropdown xmloutput function for the selected attribute and fix newmessage auto-selected dropdown. --- actions/newmessage.php | 2 +- lib/htmloutputter.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/actions/newmessage.php b/actions/newmessage.php index f83015a37..82276ff34 100644 --- a/actions/newmessage.php +++ b/actions/newmessage.php @@ -201,7 +201,7 @@ class NewmessageAction extends Action function showNoticeForm() { - $message_form = new MessageForm($this, $this->to, $this->content); + $message_form = new MessageForm($this, $this->other, $this->content); $message_form->show(); } } diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 7780b1c19..e2319b1fd 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -255,7 +255,7 @@ class HTMLOutputter extends XMLOutputter foreach ($content as $value => $option) { if ($value == $selected) { $this->element('option', array('value' => $value, - 'selected' => $value), + 'selected' => 'selected'), $option); } else { $this->element('option', array('value' => $value), $option); -- cgit v1.2.3-54-g00ecf From cf29ef2bc484c1d9719e852d1d3b6eeaff74e094 Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Mon, 9 Feb 2009 19:15:30 -0500 Subject: Fixed remaining substr_replace with multibyte equivalent. --- lib/util.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index be92f422f..75d1e21a4 100644 --- a/lib/util.php +++ b/lib/util.php @@ -446,7 +446,7 @@ function common_replace_urls_callback($text, $callback) { // If the first part wasn't cap'd but the last part was, we captured too much if ((!$prev_part && $last_part)) { - $url = substr_replace($url, '', mb_strpos($url, '.'.$url_parts[2], 0)); + $url = mb_substr($url, 0 , mb_strpos($url, '.'.$url_parts['2'], 0)); } // Capture the new TLD -- cgit v1.2.3-54-g00ecf From c9e8b1e5c380904e479927e2f24754d8709f590e Mon Sep 17 00:00:00 2001 From: Meitar Moscovitz Date: Wed, 11 Feb 2009 03:03:16 +1100 Subject: Add streamlined mobile device-friendly styles when enabled in config. A new mobile-specific style sheet is added and loaded only if the `$config['site']['mobile']` configuration variable is set to true. --- config.php.sample | 2 ++ lib/action.php | 7 +++++++ theme/base/css/mobile.css | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 theme/base/css/mobile.css (limited to 'lib') diff --git a/config.php.sample b/config.php.sample index a2c5801f4..d1191ea01 100644 --- a/config.php.sample +++ b/config.php.sample @@ -18,6 +18,8 @@ $config['site']['server'] = 'localhost'; $config['site']['path'] = 'laconica'; #$config['site']['fancy'] = false; #$config['site']['theme'] = 'default'; +#To enable the built-in mobile style sheet, defaults to false. +#$config['site']['mobile'] = true; #For contact email, defaults to $_SERVER["SERVER_ADMIN"] #$config['site']['email'] = 'admin@example.net'; #Brought by... diff --git a/lib/action.php b/lib/action.php index ce92addf5..ce37f4760 100644 --- a/lib/action.php +++ b/lib/action.php @@ -170,6 +170,13 @@ class Action extends HTMLOutputter // lawsuit } $this->comment('[if IE]>element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION, + // TODO: "handheld" CSS for other mobile devices + 'media' => 'screen and (max-device-width: 480px)')); // Mobile WebKit + } } /** diff --git a/theme/base/css/mobile.css b/theme/base/css/mobile.css new file mode 100644 index 000000000..6cd717a4d --- /dev/null +++ b/theme/base/css/mobile.css @@ -0,0 +1,48 @@ +/** theme: base + * + * @package Laconica + * @author Meitar Moscovitz + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +/* Go linear. */ +#header, +#header address, +#site_nav_global_primary, +#anon_notice, +#site_nav_local_views .nav, +#core, +#content_inner, +#notices_primary, +.notice, +.notice .entry-title, +.notice div.entry-content, +.pagination, +.pagination .nav, +.aside .section { float: none; } + +/* And liquid. */ +#wrap { width: 95%; } + +body { font-size: 2em; } /* Make things bigger on smaller screens. */ + +#site_nav_global_primary, #site_nav_global_secondary { text-align: center; } + +.notice div.entry-content { margin-left: 0; } +address { margin: 0; } + +#anon_notice, #footer { clear: left; width: auto; font-size: .5em; } + +#content { padding: 18px 0; width: 100%; } +#content h1, #page_notice, #content_inner { padding: 0 18px; } +#content_inner { width: auto; } +.pagination .nav { overflow: auto; } + +#aside_primary { margin: 10px 0 0 0; border: none; padding: 0; width: 100%; } +#popular_notices { float: none; width: auto; } +/* Columns for supplemental info. */ +.aside .section { clear: none; padding: 9px; width: 45%; } +#top_groups_by_post { float: left; } +#featured_users { float: right; } +#export_data { display: none; } -- cgit v1.2.3-54-g00ecf From beddf906634054b115d41046ac112cd0264dbfe1 Mon Sep 17 00:00:00 2001 From: Meitar Moscovitz Date: Wed, 11 Feb 2009 03:12:14 +1100 Subject: Trigger only on handheld device screens, not on browser screens, d'oh! --- lib/action.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index ce37f4760..3e236d714 100644 --- a/lib/action.php +++ b/lib/action.php @@ -175,7 +175,7 @@ class Action extends HTMLOutputter // lawsuit 'type' => 'text/css', 'href' => theme_path('css/mobile.css', 'base') . '?version=' . LACONICA_VERSION, // TODO: "handheld" CSS for other mobile devices - 'media' => 'screen and (max-device-width: 480px)')); // Mobile WebKit + 'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit } } -- cgit v1.2.3-54-g00ecf From 7763f804cafa6f41316e30512c4ceab9b78f2c08 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Tue, 10 Feb 2009 22:04:47 +0000 Subject: trac #233 Explicitely show we have an rss feed for notice searches. --- actions/noticesearch.php | 76 +++++++++++++++++++++++++++++++++++------------- lib/feedlist.php | 7 +++++ 2 files changed, 63 insertions(+), 20 deletions(-) (limited to 'lib') diff --git a/actions/noticesearch.php b/actions/noticesearch.php index a5f01350c..2d94a7906 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -78,6 +78,62 @@ class NoticesearchAction extends SearchAction return _('Text search'); } + + function showExportData() + { + $q = $this->trimmed('q'); + if (!$q) { + return; + } + $fl = new FeedList($this); + $fl->show(array(0 => array('href' => common_local_url('noticesearchrss', array('q' => $q)), + 'type' => 'rss', + 'version' => 'RSS 1.0', + 'item' => 'noticesearchrss'))); + } + + + + function showFeeds() + { + $q = $this->trimmed('q'); + if (!$q) { + return; + } + + $this->element('link', array('rel' => 'alternate', + 'href' => common_local_url('noticesearchrss', + array('q' => $q)), + 'type' => 'application/rss+xml', + 'title' => _('Search Stream Feed'))); + } + + + /** + * Show header + * + * @param array $arr array containing the query + * + * @return void + */ + + function extraHead2() + { + $q = $this->trimmed('q'); + if ($q) { + $this->element('link', array('rel' => 'alternate', + 'href' => common_local_url('noticesearchrss', + array('q' => $q)), + 'type' => 'application/rss+xml', + 'title' => _('Search Stream Feed'))); + } + } + + + + + + /** * Show results * @@ -119,26 +175,6 @@ class NoticesearchAction extends SearchAction $page, 'noticesearch', array('q' => $q)); } - /** - * Show header - * - * @param array $arr array containing the query - * - * @return void - */ - - function extraHead() - { - $q = $this->trimmed('q'); - if ($q) { - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('noticesearchrss', - array('q' => $q)), - 'type' => 'application/rss+xml', - 'title' => _('Search Stream Feed'))); - } - } - /** * Show notice * diff --git a/lib/feedlist.php b/lib/feedlist.php index 47d909e96..8bfcb9c5a 100644 --- a/lib/feedlist.php +++ b/lib/feedlist.php @@ -112,6 +112,13 @@ class FeedList extends Widget $feed['textContent'] = "Atom"; break; + case 'noticesearchrss': + $feed_classname = $feed['type']; + $feed_mimetype = "application/".$feed['type']."+xml"; + $feed_title = $feed['version']." feed for this notice search"; + $feed['textContent'] = "RSS"; + break; + case 'tagrss': $feed_classname = $feed['type']; $feed_mimetype = "application/".$feed['type']."+xml"; -- cgit v1.2.3-54-g00ecf From 646fdea1bf8a93bbfb60212982a218994ffa8bbe Mon Sep 17 00:00:00 2001 From: Sean Murphy Date: Tue, 10 Feb 2009 17:42:58 -0500 Subject: Fixed 1174: schemeless URL auto-linking bug --- lib/util.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 75d1e21a4..a130c7d49 100644 --- a/lib/util.php +++ b/lib/util.php @@ -418,8 +418,8 @@ function common_replace_urls_callback($text, $callback) { // Make sure we didn't pick up an email address if (preg_match('#^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$#i', $url)) continue; - // Remove trailing punctuation - $url = rtrim($url, '.?!,;:\'"`'); + // Remove surrounding punctuation + $url = trim($url, '.?!,;:\'"`([<'); // Remove surrounding parens and the like preg_match('/[)\]>]+$/', $url, $trailing); -- cgit v1.2.3-54-g00ecf From 7b9e69eb8923ef3018f0ce3e6042d9901ed16abd Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 10 Feb 2009 22:32:38 -0500 Subject: integrate URL routing into core code --- htaccess.sample | 162 +-------------------------- index.php | 124 +++++++++++++-------- lib/router.php | 340 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 423 insertions(+), 203 deletions(-) create mode 100644 lib/router.php (limited to 'lib') diff --git a/htaccess.sample b/htaccess.sample index 5f9827f96..634900dbf 100644 --- a/htaccess.sample +++ b/htaccess.sample @@ -4,165 +4,9 @@ RewriteEngine On RewriteBase /mublog/ -RewriteRule ^$ index.php?action=public [L,QSA] -RewriteRule ^rss$ index.php?action=publicrss [L,QSA] -RewriteRule ^xrds$ index.php?action=publicxrds [L,QSA] -RewriteRule ^featuredrss$ index.php?action=featuredrss [L,QSA] -RewriteRule ^favoritedrss$ index.php?action=favoritedrss [L,QSA] -RewriteRule ^opensearch/people$ index.php?action=opensearch&type=people [L,QSA] -RewriteRule ^opensearch/notice$ index.php?action=opensearch&type=notice [L,QSA] - -RewriteRule ^doc/about$ index.php?action=doc&title=about [L,QSA] -RewriteRule ^doc/contact$ index.php?action=doc&title=contact [L,QSA] -RewriteRule ^doc/faq$ index.php?action=doc&title=faq [L,QSA] -RewriteRule ^doc/help$ index.php?action=doc&title=help [L,QSA] -RewriteRule ^doc/im$ index.php?action=doc&title=im [L,QSA] -RewriteRule ^doc/openid$ index.php?action=doc&title=openid [L,QSA] -RewriteRule ^doc/openmublog$ index.php?action=doc&title=openmublog [L,QSA] -RewriteRule ^doc/privacy$ index.php?action=doc&title=privacy [L,QSA] -RewriteRule ^doc/source$ index.php?action=doc&title=source [L,QSA] -RewriteRule ^doc/tags$ index.php?action=doc&title=tags [L,QSA] -RewriteRule ^doc/groups$ index.php?action=doc&title=groups [L,QSA] -RewriteRule ^doc/sms$ index.php?action=doc&title=sms [L,QSA] - -RewriteRule ^facebook/$ index.php?action=facebookhome [L,QSA] -RewriteRule ^facebook/index.php$ index.php?action=facebookhome [L,QSA] -RewriteRule ^facebook/settings.php$ index.php?action=facebooksettings [L,QSA] -RewriteRule ^facebook/invite.php$ index.php?action=facebookinvite [L,QSA] -RewriteRule ^facebook/remove$ index.php?action=facebookremove [L,QSA] - -RewriteRule ^main/login$ index.php?action=login [L,QSA] -RewriteRule ^main/logout$ index.php?action=logout [L,QSA] -RewriteRule ^main/register/(.*)$ index.php?action=register&code=$1 [L,QSA] -RewriteRule ^main/register$ index.php?action=register [L,QSA] -RewriteRule ^main/openid$ index.php?action=openidlogin [L,QSA] -RewriteRule ^main/remote$ index.php?action=remotesubscribe [L,QSA] - -RewriteRule ^main/subscribe$ index.php?action=subscribe [L,QSA] -RewriteRule ^main/unsubscribe$ index.php?action=unsubscribe [L,QSA] -RewriteRule ^main/confirmaddress$ index.php?action=confirmaddress [L,QSA] -RewriteRule ^main/confirmaddress/(.*)$ index.php?action=confirmaddress&code=$1 [L,QSA] -RewriteRule ^main/recoverpassword$ index.php?action=recoverpassword [L,QSA] -RewriteRule ^main/recoverpassword/(.*)$ index.php?action=recoverpassword&code=$1 [L,QSA] -RewriteRule ^main/invite$ index.php?action=invite [L,QSA] - -RewriteRule ^main/favor$ index.php?action=favor [L,QSA] -RewriteRule ^main/disfavor$ index.php?action=disfavor [L,QSA] - -RewriteRule ^main/sup$ index.php?action=sup [L,QSA] - -RewriteRule ^main/tagother$ index.php?action=tagother [L,QSA] - -RewriteRule ^main/block$ index.php?action=block [L,QSA] - -RewriteRule ^settings/profile$ index.php?action=profilesettings [L,QSA] -RewriteRule ^settings/avatar$ index.php?action=avatarsettings [L,QSA] -RewriteRule ^settings/password$ index.php?action=passwordsettings [L,QSA] -RewriteRule ^settings/openid$ index.php?action=openidsettings [L,QSA] -RewriteRule ^settings/im$ index.php?action=imsettings [L,QSA] -RewriteRule ^settings/email$ index.php?action=emailsettings [L,QSA] -RewriteRule ^settings/sms$ index.php?action=smssettings [L,QSA] -RewriteRule ^settings/twitter$ index.php?action=twittersettings [L,QSA] -RewriteRule ^settings/other$ index.php?action=othersettings [L,QSA] - -RewriteRule ^search/group$ index.php?action=groupsearch [L,QSA] -RewriteRule ^search/people$ index.php?action=peoplesearch [L,QSA] -RewriteRule ^search/notice$ index.php?action=noticesearch [L,QSA] -RewriteRule ^search/notice/rss$ index.php?action=noticesearchrss [L,QSA] - -RewriteRule ^notice/new$ index.php?action=newnotice [L,QSA] -RewriteRule ^notice/(\d+)$ index.php?action=shownotice¬ice=$1 [L,QSA] -RewriteRule ^notice/delete/((\d+))?$ index.php?action=deletenotice¬ice=$2 [L,QSA] -RewriteRule ^notice/delete$ index.php?action=deletenotice [L,QSA] - -RewriteRule ^message/new$ index.php?action=newmessage [L,QSA] -RewriteRule ^message/(\d+)$ index.php?action=showmessage&message=$1 [L,QSA] - -RewriteRule ^user/(\d+)$ index.php?action=userbyid&id=$1 [L,QSA] - -RewriteRule ^tags/?$ index.php?action=publictagcloud [L,QSA] -RewriteRule ^tag/([a-zA-Z0-9]+)/rss$ index.php?action=tagrss&tag=$1 [L,QSA] -RewriteRule ^tag(/(.*))?$ index.php?action=tag&tag=$2 [L,QSA] - -RewriteRule ^peopletag/([a-zA-Z0-9]+)$ index.php?action=peopletag&tag=$1 [L,QSA] - -RewriteRule ^featured/?$ index.php?action=featured [L,QSA] -RewriteRule ^favorited/?$ index.php?action=favorited [L,QSA] - -RewriteRule ^group/new$ index.php?action=newgroup [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/edit$ index.php?action=editgroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/join$ index.php?action=joingroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/leave$ index.php?action=leavegroup&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/members$ index.php?action=groupmembers&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/logo$ index.php?action=grouplogo&nickname=$1 [L,QSA] -RewriteRule ^group/([0-9]+)/id$ index.php?action=groupbyid&id=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)/rss$ index.php?action=grouprss&nickname=$1 [L,QSA] -RewriteRule ^group/([a-zA-Z0-9]+)$ index.php?action=showgroup&nickname=$1 [L,QSA] -RewriteRule ^group$ index.php?action=groups [L,QSA] - -# Twitter-compatible API rewrites -# XXX: Surely these can be refactored a little -- Zach -RewriteRule ^api/statuses/public_timeline(.*)$ index.php?action=api&apiaction=statuses&method=public_timeline$1 [L,QSA] -RewriteRule ^api/statuses/friends_timeline(.*)$ index.php?action=api&apiaction=statuses&method=friends_timeline$1 [L,QSA] -RewriteRule ^api/statuses/user_timeline/(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline&argument=$1 [L,QSA] -RewriteRule ^api/statuses/user_timeline(.*)$ index.php?action=api&apiaction=statuses&method=user_timeline$1 [L,QSA] -RewriteRule ^api/statuses/show/(.*)$ index.php?action=api&apiaction=statuses&method=show&argument=$1 [L,QSA] -RewriteRule ^api/statuses/update(.*)$ index.php?action=api&apiaction=statuses&method=update$1 [L,QSA] -RewriteRule ^api/statuses/replies(.*)$ index.php?action=api&apiaction=statuses&method=replies&argument=$1 [L,QSA] -RewriteRule ^api/statuses/destroy/(.*)$ index.php?action=api&apiaction=statuses&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/statuses/friends/(.*)$ index.php?action=api&apiaction=statuses&method=friends&argument=$1 [L,QSA] -RewriteRule ^api/statuses/friends(.*)$ index.php?action=api&apiaction=statuses&method=friends$1 [L,QSA] -RewriteRule ^api/statuses/followers/(.*)$ index.php?action=api&apiaction=statuses&method=followers&argument=$1 [L,QSA] -RewriteRule ^api/statuses/followers(.*)$ index.php?action=api&apiaction=statuses&method=followers$1 [L,QSA] -RewriteRule ^api/statuses/featured(.*)$ index.php?action=api&apiaction=statuses&method=featured$1 [L,QSA] -RewriteRule ^api/users/show/(.*)$ index.php?action=api&apiaction=users&method=show&argument=$1 [L,QSA] -RewriteRule ^api/users/show(.*)$ index.php?action=api&apiaction=users&method=show$1 [L,QSA] -RewriteRule ^api/direct_messages/sent(.*)$ index.php?action=api&apiaction=direct_messages&method=sent$1 [L,QSA] -RewriteRule ^api/direct_messages/destroy/(.*)$ index.php?action=api&apiaction=direct_messages&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/direct_messages/new(.*)$ index.php?action=api&apiaction=direct_messages&method=create$1 [L,QSA] -RewriteRule ^api/direct_messages(.*)$ index.php?action=api&apiaction=direct_messages&method=direct_messages$1 [L,QSA] -RewriteRule ^api/friendships/create/(.*)$ index.php?action=api&apiaction=friendships&method=create&argument=$1 [L,QSA] -RewriteRule ^api/friendships/destroy/(.*)$ index.php?action=api&apiaction=friendships&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/friendships/exists(.*)$ index.php?action=api&apiaction=friendships&method=exists$1 [L,QSA] -RewriteRule ^api/account/verify_credentials(.*)$ index.php?action=api&apiaction=account&method=verify_credentials$1 [L,QSA] -RewriteRule ^api/account/end_session$ index.php?action=api&apiaction=account&method=end_session$1 [L,QSA] -RewriteRule ^api/account/update_location(.*)$ index.php?action=api&apiaction=account&method=update_location$1 [L,QSA] -RewriteRule ^api/account/update_delivery_device(.*)$ index.php?action=api&apiaction=account&method=update_delivery_device$1 [L,QSA] -RewriteRule ^api/account/rate_limit_status(.*)$ index.php?action=api&apiaction=account&method=rate_limit_status$1 [L,QSA] -RewriteRule ^api/favorites/create/(.*)$ index.php?action=api&apiaction=favorites&method=create&argument=$1 [L,QSA] -RewriteRule ^api/favorites/destroy/(.*)$ index.php?action=api&apiaction=favorites&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/favorites/(.*)$ index.php?action=api&apiaction=favorites&method=favorites&argument=$1 [L,QSA] -RewriteRule ^api/favorites(.*)$ index.php?action=api&apiaction=favorites&method=favorites$1 [L,QSA] -RewriteRule ^api/notifications/follow/(.*)$ index.php?action=api&apiaction=notifications&method=follow&argument=$1 [L,QSA] -RewriteRule ^api/notifications/leave/(.*)$ index.php?action=api&apiaction=notifications&method=leave&argument=$1 [L,QSA] -RewriteRule ^api/blocks/create/(.*)$ index.php?action=api&apiaction=blocks&method=create&argument=$1 [L,QSA] -RewriteRule ^api/blocks/destroy/(.*)$ index.php?action=api&apiaction=blocks&method=destroy&argument=$1 [L,QSA] -RewriteRule ^api/help/(.*)$ index.php?action=api&apiaction=help&method=$1 [L,QSA] -RewriteRule ^api/laconica/version(.*)$ index.php?action=api&apiaction=laconica&method=version$1 [L,QSA] -RewriteRule ^api/laconica/config(.*)$ index.php?action=api&apiaction=laconica&method=config$1 [L,QSA] -RewriteRule ^api/laconica/wadl\.xml$ index.php?action=api&apiaction=laconica&method=wadl.xml [L,QSA] - -RewriteRule ^(\w+)/subscriptions$ index.php?action=subscriptions&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/subscriptions/([a-zA-Z0-9]+)$ index.php?action=subscriptions&nickname=$1&tag=$2 [L,QSA] -RewriteRule ^(\w+)/subscribers/([a-zA-Z0-9]+)$ index.php?action=subscribers&nickname=$1&tag=$2 [L,QSA] -RewriteRule ^(\w+)/subscribers$ index.php?action=subscribers&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/nudge$ index.php?action=nudge&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/xrds$ index.php?action=xrds&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/rss$ index.php?action=userrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/all$ index.php?action=all&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/all/rss$ index.php?action=allrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/foaf$ index.php?action=foaf&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/replies$ index.php?action=replies&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/replies/rss$ index.php?action=repliesrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/avatar/(original|96|48|24)$ index.php?action=avatarbynickname&nickname=$1&size=$2 [L,QSA] -RewriteRule ^(\w+)/favorites$ index.php?action=showfavorites&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/favorites/rss$ index.php?action=favoritesrss&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/inbox$ index.php?action=inbox&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/outbox$ index.php?action=outbox&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/microsummary$ index.php?action=microsummary&nickname=$1 [L,QSA] -RewriteRule ^(\w+)/groups$ index.php?action=usergroups&nickname=$1 [L,QSA] - -RewriteRule ^(\w+)$ index.php?action=showstream&nickname=$1 [L,QSA] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule (.*) index.php?p=$1 [L,QSA] Order allow,deny diff --git a/index.php b/index.php index e62d9469a..f334e2c34 100644 --- a/index.php +++ b/index.php @@ -22,69 +22,105 @@ define('LACONICA', true); require_once INSTALLDIR . '/lib/common.php'; -// XXX: we need a little more structure in this script +$user = null; +$action = null; + +function getPath($req) { + if (common_config('site', 'fancy')) { + return $req['p']; + } else if ($_SERVER['PATH_INFO']) { + return $_SERVER['PATH_INFO']; + } else { + return $req['p']; + } +} -// get and cache current user +function main() { -$user = common_current_user(); + global $user, $action; -// initialize language env + // XXX: we need a little more structure in this script -common_init_language(); + // get and cache current user -$action = $_REQUEST['action']; + $user = common_current_user(); -if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) { - common_redirect(common_local_url('public')); -} + // initialize language env -// If the site is private, and they're not on one of the "public" -// parts of the site, redirect to login + common_init_language(); -if (!$user && common_config('site', 'private') && - !in_array($action, array('login', 'openidlogin', 'finishopenidlogin', - 'recoverpassword', 'api', 'doc', 'register'))) { - common_redirect(common_local_url('login')); -} + $path = getPath($_REQUEST); + + $r = new Router(); -$action_class = ucfirst($action).'Action'; + $args = $r->map($path); -if (!class_exists($action_class)) { - $cac = new ClientErrorAction(_('Unknown action'), 404); - $cac->showPage(); -} else { - $action_obj = new $action_class(); + if (!$args) { + $cac = new ClientErrorAction(_('Unknown page'), 404); + $cac->showPage(); + return; + } - // XXX: find somewhere for this little block to live + $args = array_merge($args, $_REQUEST); - if ($config['db']['mirror'] && $action_obj->isReadOnly()) { - if (is_array($config['db']['mirror'])) { - // "load balancing", ha ha - $k = array_rand($config['db']['mirror']); + $action = $args['action']; - $mirror = $config['db']['mirror'][$k]; - } else { - $mirror = $config['db']['mirror']; - } - $config['db']['database'] = $mirror; + if (!$action || !preg_match('/^[a-zA-Z0-9_-]*$/', $action)) { + common_redirect(common_local_url('public')); + return; } - try { - if ($action_obj->prepare($_REQUEST)) { - $action_obj->handle($_REQUEST); - } - } catch (ClientException $cex) { - $cac = new ClientErrorAction($cex->getMessage(), $cex->getCode()); + // If the site is private, and they're not on one of the "public" + // parts of the site, redirect to login + + if (!$user && common_config('site', 'private') && + !in_array($action, array('login', 'openidlogin', 'finishopenidlogin', + 'recoverpassword', 'api', 'doc', 'register'))) { + common_redirect(common_local_url('login')); + return; + } + + $action_class = ucfirst($action).'Action'; + + if (!class_exists($action_class)) { + $cac = new ClientErrorAction(_('Unknown action'), 404); $cac->showPage(); - } catch (ServerException $sex) { // snort snort guffaw - $sac = new ServerErrorAction($sex->getMessage(), $sex->getCode()); - $sac->showPage(); - } catch (Exception $ex) { - $sac = new ServerErrorAction($ex->getMessage()); - $sac->showPage(); + } else { + $action_obj = new $action_class(); + + // XXX: find somewhere for this little block to live + + if ($config['db']['mirror'] && $action_obj->isReadOnly()) { + if (is_array($config['db']['mirror'])) { + // "load balancing", ha ha + $k = array_rand($config['db']['mirror']); + + $mirror = $config['db']['mirror'][$k]; + } else { + $mirror = $config['db']['mirror']; + } + $config['db']['database'] = $mirror; + } + + try { + if ($action_obj->prepare($args)) { + $action_obj->handle($args); + } + } catch (ClientException $cex) { + $cac = new ClientErrorAction($cex->getMessage(), $cex->getCode()); + $cac->showPage(); + } catch (ServerException $sex) { // snort snort guffaw + $sac = new ServerErrorAction($sex->getMessage(), $sex->getCode()); + $sac->showPage(); + } catch (Exception $ex) { + $sac = new ServerErrorAction($ex->getMessage()); + $sac->showPage(); + } } } +main(); + // XXX: cleanup exit() calls or add an exit handler so // this always gets called diff --git a/lib/router.php b/lib/router.php new file mode 100644 index 000000000..6781322a2 --- /dev/null +++ b/lib/router.php @@ -0,0 +1,340 @@ +. + * + * @category URL + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once 'Net/URL/Mapper.php'; + +/** + * URL Router + * + * Cheap wrapper around Net_URL_Mapper + * + * @category URL + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +class Router +{ + var $m = null; + + function __construct() + { + $m = Net_URL_Mapper::getInstance(); + + // In the "root" + + $m->connect('', array('action' => 'public')); + $m->connect('rss', array('action' => 'publicrss')); + $m->connect('xrds', array('action' => 'publicxrds')); + $m->connect('featuredrss', array('action' => 'featuredrss')); + $m->connect('favoritedrss', array('action' => 'favoritedrss')); + $m->connect('opensearch/people', array('action' => 'opensearch', + 'type' => 'people')); + $m->connect('opensearch/notice', array('action' => 'opensearch', + 'type' => 'notice')); + + // docs + + $m->connect('doc/:title', array('action' => 'doc')); + + // facebook + + $m->connect('facebook', array('action' => 'facebookhome')); + $m->connect('facebook/index.php', array('action' => 'facebookhome')); + $m->connect('facebook/settings.php', array('action' => 'facebooksettings')); + $m->connect('facebook/invite.php', array('action' => 'facebookinvite')); + $m->connect('facebook/remove', array('action' => 'facebookremove')); + + // main stuff is repetitive + + $main = array('login', 'logout', 'register', 'subscribe', + 'unsubscribe', 'confirmaddress', 'recoverpassword', + 'invite', 'favor', 'disfavor', 'sup', + 'tagother', 'block'); + + foreach ($main as $a) { + $m->connect('main/'.$a, array('action' => $a)); + } + + // these take a code + + foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { + $m->connect('main/'.$c.'/:code', array('action' => $c)); + } + + // exceptional + + $m->connect('main/openid', array('action' => 'openidlogin')); + $m->connect('main/remote', array('action' => 'remotesubscribe')); + + // settings + + foreach (array('profile', 'avatar', 'password', 'openid', 'im', + 'email', 'sms', 'twitter', 'other') as $s) { + $m->connect('settings/'.$s, array('action' => $s.'settings')); + } + + // search + + foreach (array('group', 'people', 'notice') as $s) { + $m->connect('search/'.$s, array('action' => $s.'search')); + } + + $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); + + // notice + + $m->connect('notice/new', array('action' => 'newnotice')); + $m->connect('notice/:notice', + array('action' => 'shownotice'), + array('notice' => '[0-9]+')); + $m->connect('notice/delete', array('action' => 'deletenotice')); + $m->connect('notice/delete/:notice', + array('action' => 'deletenotice'), + array('notice' => '[0-9]+')); + + $m->connect('message/new', array('action' => 'newmessage')); + $m->connect('message/:message', + array('action' => 'showmessage'), + array('message' => '[0-9]+')); + + $m->connect('user/:id', + array('action' => 'userbyid'), + array('id' => '[0-9]+')); + + $m->connect('tags/?', array('action' => 'publictagcloud')); + $m->connect('tag/?', array('action' => 'publictagcloud')); + $m->connect('tag/:tag/rss', + array('action' => 'tagrss'), + array('tag' => '[a-zA-Z0-9]+')); + $m->connect('tag/:tag', + array('action' => 'tag'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect('peopletag/:tag', + array('action' => 'peopletag'), + array('tag' => '[a-zA-Z0-9]+')); + + $m->connect('featured/?', array('action' => 'featured')); + $m->connect('favorited/?', array('action' => 'favorited')); + + // groups + + $m->connect('group/new', array('action' => 'newgroup')); + + foreach (array('edit', 'join', 'leave') as $v) { + $m->connect('group/:nickname/'.$v, + array('action' => $v.'group'), + array('nickname' => '[a-zA-Z0-9]+')); + } + + foreach (array('members', 'logo', 'rss') as $n) { + $m->connect('group/:nickname/'.$n, + array('action' => 'group'.$n), + array('nickname' => '[a-zA-Z0-9]+')); + } + + $m->connect('group/:id/id', + array('action' => 'groupbyid'), + array('id' => '[0-9]+')); + + $m->connect('group/:nickname', + array('action' => 'showgroup'), + array('nickname' => '[a-zA-Z0-9]+')); + + $m->connect('group/?', array('action' => 'groups')); + + // Twitter-compatible API + + // statuses API + + $m->connect('api/statuses/:method', + array('action' => 'api', + 'apiaction' => 'statuses'), + array('method' => '(public_timeline|friends_timeline|user_timeline|update|replies|friends|followers|featured)(\.(atom|rss|xml|json))?')); + + $m->connect('api/statuses/:method/:argument', + array('action' => 'api', + 'apiaction' => 'statuses'), + array('method' => '(user_timeline|show|destroy|friends|followers)')); + + // users + + $m->connect('api/users/show/:argument', + array('action' => 'api', + 'apiaction' => 'users')); + + $m->connect('api/users/:method', + array('action' => 'api', + 'apiaction' => 'users'), + array('method' => 'show(\.(xml|json|atom|rss))?')); + + // direct messages + + $m->connect('api/direct_messages/:method', + array('action' => 'api', + 'apiaction' => 'direct_messages'), + array('method' => '(sent|new)(\.(xml|json|atom|rss))?')); + + $m->connect('api/direct_messages/destroy/:argument', + array('action' => 'api', + 'apiaction' => 'direct_messages')); + + $m->connect('api/:method', + array('action' => 'api', + 'apiaction' => 'direct_messages'), + array('method' => 'direct_messages(\.(xml|json|atom|rss))?')); + + // friendships + + $m->connect('api/friendships/:method/:argument', + array('action' => 'api', + 'apiaction' => 'friendships'), + array('method' => '(create|destroy)')); + + $m->connect('api/friendships/:method', + array('action' => 'api', + 'apiaction' => 'friendships'), + array('method' => 'exists(\.(xml|json|rss|atom))')); + + // account + + $m->connect('api/account/:method', + array('action' => 'api', + 'apiaction' => 'account')); + + // favorites + + $m->connect('api/favorites/:method/:argument', + array('action' => 'api', + 'apiaction' => 'favorites')); + + $m->connect('api/favorites/:argument', + array('action' => 'api', + 'apiaction' => 'favorites', + 'method' => 'favorites')); + + $m->connect('api/:method', + array('action' => 'api', + 'apiaction' => 'favorites'), + array('method' => 'favorites(\.(xml|json|rss|atom))?')); + + // notifications + + $m->connect('api/notifications/:method/:argument', + array('action' => 'api', + 'apiaction' => 'favorites')); + + // blocks + + $m->connect('api/blocks/:method/:argument', + array('action' => 'api', + 'apiaction' => 'blocks')); + + // help + + $m->connect('api/help/:method', + array('action' => 'api', + 'apiaction' => 'help')); + + // laconica + + $m->connect('api/laconica/:method', + array('action' => 'api', + 'apiaction' => 'laconica')); + + // user stuff + + foreach (array('subscriptions', 'subscribers', + 'nudge', 'xrds', 'all', 'foaf', + 'replies', 'inbox', 'outbox', 'microsummary') as $a) { + $m->connect(':nickname/'.$a, + array('action' => $a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('subscriptions', 'subscribers') as $a) { + $m->connect(':nickname/'.$a.'/:tag', + array('action' => $a), + array('tag' => '[a-zA-Z0-9]+', + 'nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('rss', 'groups') as $a) { + $m->connect(':nickname/'.$a, + array('action' => 'user'.$a), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + foreach (array('all', 'replies', 'favorites') as $a) { + $m->connect(':nickname/'.$a.'/rss', + array('action' => $a.'rss'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + } + + $m->connect(':nickname/favorites', + array('action' => 'showfavorites'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + + $m->connect(':nickname/avatar/:size', + array('action' => 'avatarbynickname'), + array('size' => '(original|96|48|24)', + 'nickname' => '[a-zA-Z0-9]{1,64}')); + + $m->connect(':nickname', + array('action' => 'showstream'), + array('nickname' => '[a-zA-Z0-9]{1,64}')); + + $this->m = $m; + } + + function map($path) + { + return $this->m->match($path); + } + + function build($action, $args=null, $fragment=null) + { + $action_arg = array('action' => $action); + + if ($args) { + $args = array_merge($args, $action_arg); + } else { + $args = $action_arg; + } + + return $this->m->generate($args, null, $fragment); + } +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From fbecbcb693e9d8fc810cf316e8739a22ac501043 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Tue, 10 Feb 2009 22:49:25 -0500 Subject: Build urls using Net_URL_Mapper, too --- lib/router.php | 28 ++++-- lib/util.php | 269 ++------------------------------------------------------- 2 files changed, 27 insertions(+), 270 deletions(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index 6781322a2..6443bf354 100644 --- a/lib/router.php +++ b/lib/router.php @@ -47,10 +47,17 @@ require_once 'Net/URL/Mapper.php'; class Router { - var $m = null; + static $m = null; function __construct() { + if (!$this->m) { + $this->m = $this->initialize(); + } + } + + function initialize() { + $m = Net_URL_Mapper::getInstance(); // In the "root" @@ -134,8 +141,10 @@ class Router array('action' => 'userbyid'), array('id' => '[0-9]+')); - $m->connect('tags/?', array('action' => 'publictagcloud')); - $m->connect('tag/?', array('action' => 'publictagcloud')); + $m->connect('tags/', array('action' => 'publictagcloud')); + $m->connect('tag/', array('action' => 'publictagcloud')); + $m->connect('tags', array('action' => 'publictagcloud')); + $m->connect('tag', array('action' => 'publictagcloud')); $m->connect('tag/:tag/rss', array('action' => 'tagrss'), array('tag' => '[a-zA-Z0-9]+')); @@ -147,8 +156,10 @@ class Router array('action' => 'peopletag'), array('tag' => '[a-zA-Z0-9]+')); - $m->connect('featured/?', array('action' => 'featured')); - $m->connect('favorited/?', array('action' => 'favorited')); + $m->connect('featured/', array('action' => 'featured')); + $m->connect('featured', array('action' => 'featured')); + $m->connect('favorited/', array('action' => 'favorited')); + $m->connect('favorited', array('action' => 'favorited')); // groups @@ -174,7 +185,10 @@ class Router array('action' => 'showgroup'), array('nickname' => '[a-zA-Z0-9]+')); - $m->connect('group/?', array('action' => 'groups')); + $m->connect('group/', array('action' => 'groups')); + $m->connect('group', array('action' => 'groups')); + $m->connect('groups/', array('action' => 'groups')); + $m->connect('groups', array('action' => 'groups')); // Twitter-compatible API @@ -317,7 +331,7 @@ class Router array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}')); - $this->m = $m; + return $m; } function map($path) diff --git a/lib/util.php b/lib/util.php index c5a092f63..a78af8be9 100644 --- a/lib/util.php +++ b/lib/util.php @@ -669,275 +669,18 @@ function common_relative_profile($sender, $nickname, $dt=null) function common_local_url($action, $args=null, $fragment=null) { - $url = null; + $r = new Router(); + $path = $r->build($action, $args, $fragment); + if ($path) { + } if (common_config('site','fancy')) { - $url = common_fancy_url($action, $args); + $url = common_path(mb_substr($path, 1)); } else { - $url = common_simple_url($action, $args); - } - if (!is_null($fragment)) { - $url .= '#'.$fragment; + $url = common_path('index.php'.$path); } return $url; } -function common_fancy_url($action, $args=null) -{ - switch (strtolower($action)) { - case 'public': - if ($args && isset($args['page'])) { - return common_path('?page=' . $args['page']); - } else { - return common_path(''); - } - case 'featured': - if ($args && isset($args['page'])) { - return common_path('featured?page=' . $args['page']); - } else { - return common_path('featured'); - } - case 'favorited': - if ($args && isset($args['page'])) { - return common_path('favorited?page=' . $args['page']); - } else { - return common_path('favorited'); - } - case 'publicrss': - return common_path('rss'); - case 'publicatom': - return common_path("api/statuses/public_timeline.atom"); - case 'publicxrds': - return common_path('xrds'); - case 'tagrss': - return common_path('tag/' . $args['tag'] . '/rss'); - case 'featuredrss': - return common_path('featuredrss'); - case 'favoritedrss': - return common_path('favoritedrss'); - case 'opensearch': - if ($args && $args['type']) { - return common_path('opensearch/'.$args['type']); - } else { - return common_path('opensearch/people'); - } - case 'doc': - return common_path('doc/'.$args['title']); - case 'block': - case 'login': - case 'logout': - case 'subscribe': - case 'unsubscribe': - case 'invite': - return common_path('main/'.$action); - case 'tagother': - return common_path('main/tagother?id='.$args['id']); - case 'register': - if ($args && $args['code']) { - return common_path('main/register/'.$args['code']); - } else { - return common_path('main/register'); - } - case 'remotesubscribe': - if ($args && $args['nickname']) { - return common_path('main/remote?nickname=' . $args['nickname']); - } else { - return common_path('main/remote'); - } - case 'nudge': - return common_path($args['nickname'].'/nudge'); - case 'openidlogin': - return common_path('main/openid'); - case 'profilesettings': - return common_path('settings/profile'); - case 'passwordsettings': - return common_path('settings/password'); - case 'emailsettings': - return common_path('settings/email'); - case 'openidsettings': - return common_path('settings/openid'); - case 'smssettings': - return common_path('settings/sms'); - case 'twittersettings': - return common_path('settings/twitter'); - case 'othersettings': - return common_path('settings/other'); - case 'deleteprofile': - return common_path('settings/delete'); - case 'newnotice': - if ($args && $args['replyto']) { - return common_path('notice/new?replyto='.$args['replyto']); - } else { - return common_path('notice/new'); - } - case 'shownotice': - return common_path('notice/'.$args['notice']); - case 'deletenotice': - if ($args && $args['notice']) { - return common_path('notice/delete/'.$args['notice']); - } else { - return common_path('notice/delete'); - } - case 'microsummary': - case 'xrds': - case 'foaf': - return common_path($args['nickname'].'/'.$action); - case 'all': - case 'replies': - case 'inbox': - case 'outbox': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'/'.$action.'?page=' . $args['page']); - } else { - return common_path($args['nickname'].'/'.$action); - } - case 'subscriptions': - case 'subscribers': - $nickname = $args['nickname']; - unset($args['nickname']); - if (isset($args['tag'])) { - $tag = $args['tag']; - unset($args['tag']); - } - $params = http_build_query($args); - if ($params) { - return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '') . '?' . $params); - } else { - return common_path($nickname.'/'.$action . (($tag) ? '/' . $tag : '')); - } - case 'allrss': - return common_path($args['nickname'].'/all/rss'); - case 'repliesrss': - return common_path($args['nickname'].'/replies/rss'); - case 'userrss': - if (isset($args['limit'])) - return common_path($args['nickname'].'/rss?limit=' . $args['limit']); - return common_path($args['nickname'].'/rss'); - case 'showstream': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'?page=' . $args['page']); - } else { - return common_path($args['nickname']); - } - - case 'usertimeline': - return common_path("api/statuses/user_timeline/".$args['nickname'].".atom"); - case 'confirmaddress': - return common_path('main/confirmaddress/'.$args['code']); - case 'userbyid': - return common_path('user/'.$args['id']); - case 'recoverpassword': - $path = 'main/recoverpassword'; - if ($args['code']) { - $path .= '/' . $args['code']; - } - return common_path($path); - case 'imsettings': - return common_path('settings/im'); - case 'avatarsettings': - return common_path('settings/avatar'); - case 'groupsearch': - return common_path('search/group' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'peoplesearch': - return common_path('search/people' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'noticesearch': - return common_path('search/notice' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'noticesearchrss': - return common_path('search/notice/rss' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'avatarbynickname': - return common_path($args['nickname'].'/avatar/'.$args['size']); - case 'tag': - $path = 'tag/' . $args['tag']; - unset($args['tag']); - return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); - case 'publictagcloud': - return common_path('tags'); - case 'peopletag': - $path = 'peopletag/' . $args['tag']; - unset($args['tag']); - return common_path($path . (($args) ? ('?' . http_build_query($args)) : '')); - case 'tags': - return common_path('tags' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'favor': - return common_path('main/favor'); - case 'disfavor': - return common_path('main/disfavor'); - case 'showfavorites': - if ($args && isset($args['page'])) { - return common_path($args['nickname'].'/favorites?page=' . $args['page']); - } else { - return common_path($args['nickname'].'/favorites'); - } - case 'favoritesrss': - return common_path($args['nickname'].'/favorites/rss'); - case 'showmessage': - return common_path('message/' . $args['message']); - case 'newmessage': - return common_path('message/new' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'api': - // XXX: do fancy URLs for all the API methods - switch (strtolower($args['apiaction'])) { - case 'statuses': - switch (strtolower($args['method'])) { - case 'user_timeline.rss': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.rss'); - case 'user_timeline.atom': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.atom'); - case 'user_timeline.json': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.json'); - case 'user_timeline.xml': - return common_path('api/statuses/user_timeline/'.$args['argument'].'.xml'); - default: return common_simple_url($action, $args); - } - default: return common_simple_url($action, $args); - } - case 'sup': - if ($args && isset($args['seconds'])) { - return common_path('main/sup?seconds='.$args['seconds']); - } else { - return common_path('main/sup'); - } - case 'newgroup': - return common_path('group/new'); - case 'showgroup': - return common_path('group/'.$args['nickname'] . (($args['page']) ? ('?page=' . $args['page']) : '')); - case 'editgroup': - return common_path('group/'.$args['nickname'].'/edit'); - case 'joingroup': - return common_path('group/'.$args['nickname'].'/join'); - case 'leavegroup': - return common_path('group/'.$args['nickname'].'/leave'); - case 'groupbyid': - return common_path('group/'.$args['id'].'/id'); - case 'grouprss': - return common_path('group/'.$args['nickname'].'/rss'); - case 'groupmembers': - return common_path('group/'.$args['nickname'].'/members' . (($args['page']) ? ('?page=' . $args['page']) : '')); - case 'grouplogo': - return common_path('group/'.$args['nickname'].'/logo'); - case 'usergroups': - $nickname = $args['nickname']; - unset($args['nickname']); - return common_path($nickname.'/groups' . (($args) ? ('?' . http_build_query($args)) : '')); - case 'groups': - return common_path('group' . (($args) ? ('?' . http_build_query($args)) : '')); - default: - return common_simple_url($action, $args); - } -} - -function common_simple_url($action, $args=null) -{ - global $config; - /* XXX: pretty URLs */ - $extra = ''; - if ($args) { - foreach ($args as $key => $value) { - $extra .= "&${key}=${value}"; - } - } - return common_path("index.php?action=${action}${extra}"); -} - function common_path($relative) { global $config; -- cgit v1.2.3-54-g00ecf From bba1dbdb403aac067ae97c44531f6886f90fec35 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 00:45:11 -0500 Subject: Use a router singleton --- index.php | 2 +- lib/router.php | 11 ++++++++++- lib/util.php | 6 +++++- 3 files changed, 16 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/index.php b/index.php index f334e2c34..717b17361 100644 --- a/index.php +++ b/index.php @@ -51,7 +51,7 @@ function main() { $path = getPath($_REQUEST); - $r = new Router(); + $r = Router::get(); $args = $r->map($path); diff --git a/lib/router.php b/lib/router.php index 6443bf354..d47ad7118 100644 --- a/lib/router.php +++ b/lib/router.php @@ -48,6 +48,15 @@ require_once 'Net/URL/Mapper.php'; class Router { static $m = null; + static $inst = null; + + static function get() + { + if (!Router::$inst) { + Router::$inst = new Router(); + } + return Router::$inst; + } function __construct() { @@ -344,7 +353,7 @@ class Router $action_arg = array('action' => $action); if ($args) { - $args = array_merge($args, $action_arg); + $args = array_merge($action_arg, $args); } else { $args = $action_arg; } diff --git a/lib/util.php b/lib/util.php index a78af8be9..9b38b5596 100644 --- a/lib/util.php +++ b/lib/util.php @@ -669,8 +669,12 @@ function common_relative_profile($sender, $nickname, $dt=null) function common_local_url($action, $args=null, $fragment=null) { - $r = new Router(); + common_debug("Action = $action, args = " . (($args) ? '(' . implode($args, ',') . ')' : $args) . ", fragment = $fragment"); + $r = Router::get(); + $start = microtime(); $path = $r->build($action, $args, $fragment); + $end = microtime(); + common_debug("Pathbuilding took " . ($end - $start)); if ($path) { } if (common_config('site','fancy')) { -- cgit v1.2.3-54-g00ecf From d345c746b9021266a2ed100329affe49c5ae8fc3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 08:34:21 -0500 Subject: add related link to Atom for feeds for some downstream users --- lib/jabber.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/jabber.php b/lib/jabber.php index f41d984d6..b385d3c5c 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -186,6 +186,11 @@ function jabber_format_entry($profile, $notice) $entry .= "". $notice->uri . "\n"; $entry .= "".common_date_w3dtf($notice->created)."\n"; $entry .= "".common_date_w3dtf($notice->modified)."\n"; + if ($notice->reply_to) { + $replyurl = common_local_url('shownotice', + array('notice' => $notice->reply_to)); + $entry .= "\n"; + } $entry .= "\n"; $html = "\n\n"; -- cgit v1.2.3-54-g00ecf From c640b747f7e682ac632397cf32e41ef4c2dca96f Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 08:34:21 -0500 Subject: add related link to Atom for feeds for some downstream users --- lib/jabber.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/jabber.php b/lib/jabber.php index f41d984d6..b385d3c5c 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -186,6 +186,11 @@ function jabber_format_entry($profile, $notice) $entry .= "". $notice->uri . "\n"; $entry .= "".common_date_w3dtf($notice->created)."\n"; $entry .= "".common_date_w3dtf($notice->modified)."\n"; + if ($notice->reply_to) { + $replyurl = common_local_url('shownotice', + array('notice' => $notice->reply_to)); + $entry .= "\n"; + } $entry .= "\n"; $html = "\n\n"; -- cgit v1.2.3-54-g00ecf From 22b10399aaa97061ed940f92f5b15f6aacfb1093 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 11:37:50 -0500 Subject: Unify feeds definition in actions I got a little sick of trying to keep the export data and links synched in actions, so I made a common method, getFeeds(), which gets the feeds for both. It returns an array of Feed objects, which know about what their mime type is, title, location, all that jazz. I changed the FeedList class so it handles the new Feed objects instead of the old array of data. I changed all the actions that show feeds (I think...) so that they now use getFeeds() for all their feed needs. --- actions/all.php | 36 +++++++-------- actions/noticesearch.php | 62 +++++--------------------- actions/public.php | 53 ++++++---------------- actions/replies.php | 28 ++---------- actions/showfavorites.php | 33 ++------------ actions/showgroup.php | 25 ++--------- actions/showstream.php | 67 ++++++++++------------------ actions/tag.php | 22 +++------- lib/action.php | 38 +++++++++++++--- lib/feed.php | 110 ++++++++++++++++++++++++++++++++++++++++++++++ lib/feedlist.php | 101 ++++++++---------------------------------- 11 files changed, 240 insertions(+), 335 deletions(-) create mode 100644 lib/feed.php (limited to 'lib') diff --git a/actions/all.php b/actions/all.php index d75d1b946..08dcccbdd 100644 --- a/actions/all.php +++ b/actions/all.php @@ -42,9 +42,9 @@ class AllAction extends Action if (!$this->page) { $this->page = 1; } - + common_set_returnto($this->selfUrl()); - + return true; } @@ -69,13 +69,22 @@ class AllAction extends Action } } - function showFeeds() + function getFeeds() { - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('allrss', array('nickname' => - $this->user->nickname)), - 'type' => 'application/rss+xml', - 'title' => sprintf(_('Feed for friends of %s'), $this->user->nickname))); + return array(new Feed(Feed::RSS1, + common_local_url('allrss', array('nickname' => + $this->user->nickname)), + sprintf(_('Feed for friends of %s (RSS 1.0)'), $this->user->nickname)), + new Feed(Feed::RSS2, + common_local_url('api', array('apiaction' => 'statuses', + 'method' => 'friends', + 'argument' => $this->user->nickname.'.rss')), + sprintf(_('Feed for friends of %s (RSS 2.0)'), $this->user->nickname)), + new Feed(Feed::ATOM, + common_local_url('api', array('apiaction' => 'statuses', + 'method' => 'friends', + 'argument' => $this->user->nickname.'.atom')), + sprintf(_('Feed for friends of %s (Atom)'), $this->user->nickname))); } function showLocalNav() @@ -84,15 +93,6 @@ class AllAction extends Action $nav->show(); } - function showExportData() - { - $fl = new FeedList($this); - $fl->show(array(0=>array('href'=>common_local_url('allrss', array('nickname' => $this->user->nickname)), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'allrss'))); - } - function showContent() { $notice = $this->user->noticesWithFriends(($this->page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1); @@ -110,7 +110,7 @@ class AllAction extends Action $user =& common_current_user(); if ($user && ($user->id == $this->user->id)) { $this->element('h1', NULL, _("You and friends")); - } else { + } else { $this->element('h1', NULL, sprintf(_('%s and friends'), $this->user->nickname)); } } diff --git a/actions/noticesearch.php b/actions/noticesearch.php index 2d94a7906..dc58d7528 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -57,11 +57,11 @@ class NoticesearchAction extends SearchAction return true; } - + /** * Get instructions - * - * @return string instruction text + * + * @return string instruction text */ function getInstructions() { @@ -70,7 +70,7 @@ class NoticesearchAction extends SearchAction /** * Get title - * + * * @return string title */ function title() @@ -78,62 +78,20 @@ class NoticesearchAction extends SearchAction return _('Text search'); } - - function showExportData() + function getFeeds() { $q = $this->trimmed('q'); - if (!$q) { - return; - } - $fl = new FeedList($this); - $fl->show(array(0 => array('href' => common_local_url('noticesearchrss', array('q' => $q)), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'noticesearchrss'))); - } - - - function showFeeds() - { - $q = $this->trimmed('q'); if (!$q) { - return; + return null; } - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('noticesearchrss', - array('q' => $q)), - 'type' => 'application/rss+xml', - 'title' => _('Search Stream Feed'))); + return array(new Feed(Feed::RSS1, common_local_url('noticesearchrss', + array('q' => $q)), + sprintf(_('Search results for "%s" on %s'), + $q, common_config('site', 'name')))); } - - /** - * Show header - * - * @param array $arr array containing the query - * - * @return void - */ - - function extraHead2() - { - $q = $this->trimmed('q'); - if ($q) { - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('noticesearchrss', - array('q' => $q)), - 'type' => 'application/rss+xml', - 'title' => _('Search Stream Feed'))); - } - } - - - - - - /** * Show results * diff --git a/actions/public.php b/actions/public.php index 1137bd876..a20ae4032 100644 --- a/actions/public.php +++ b/actions/public.php @@ -119,24 +119,20 @@ class PublicAction extends Action * @return void */ - function showFeeds() + function getFeeds() { - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('publicrss'), - 'type' => 'application/rdf+xml', - 'title' => _('Public Stream Feed (RSS 1.0)'))); - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'public_timeline.rss')), - 'type' => 'application/rss+xml', - 'title' => _('Public Stream Feed (RSS 2.0)'))); - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'public_timeline.atom')), - 'type' => 'application/atom+xml', - 'title' => _('Public Stream Feed (Atom)'))); + return array(new Feed(Feed::RSS1, common_local_url('publicrss'), + _('Public Stream Feed (RSS 1.0)')), + new Feed(Feed::RSS2, + common_local_url('api', + array('apiaction' => 'statuses', + 'method' => 'public_timeline.rss')), + _('Public Stream Feed (RSS 2.0)')), + new Feed(Feed::ATOM, + common_local_url('api', + array('apiaction' => 'statuses', + 'method' => 'public_timeline.atom')), + _('Public Stream Feed (Atom)'))); } /** @@ -197,29 +193,6 @@ class PublicAction extends Action $this->page, 'public'); } - /** - * Makes a list of exported feeds for this page - * - * @return void - * - * @todo I18N - */ - - function showExportData() - { - $fl = new FeedList($this); - $fl->show(array(0 => array('href' => common_local_url('publicrss'), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'publicrss'), - 1 => array('href' => common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'public_timeline.atom')), - 'type' => 'atom', - 'version' => 'Atom 1.0', - 'item' => 'publicatom'))); - } - function showSections() { // $top = new TopPostersSection($this); diff --git a/actions/replies.php b/actions/replies.php index 7eff74a66..4ab9b14ed 100644 --- a/actions/replies.php +++ b/actions/replies.php @@ -84,7 +84,7 @@ class RepliesAction extends Action $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; common_set_returnto($this->selfUrl()); - + return true; } @@ -129,16 +129,13 @@ class RepliesAction extends Action * @return void */ - function showFeeds() + function getFeeds() { $rssurl = common_local_url('repliesrss', array('nickname' => $this->user->nickname)); $rsstitle = sprintf(_('Feed for replies to %s'), $this->user->nickname); - $this->element('link', array('rel' => 'alternate', - 'href' => $rssurl, - 'type' => 'application/rss+xml', - 'title' => $rsstitle)); + return array(new Feed(Feed::RSS1, $rssurl, $rsstitle)); } /** @@ -153,25 +150,6 @@ class RepliesAction extends Action $nav->show(); } - /** - * Show the replies feed links - * - * @return void - */ - - function showExportData() - { - $fl = new FeedList($this); - - $rssurl = common_local_url('repliesrss', - array('nickname' => $this->user->nickname)); - - $fl->show(array(0=>array('href'=> $rssurl, - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'repliesrss'))); - } - /** * Show the content * diff --git a/actions/showfavorites.php b/actions/showfavorites.php index 31479e1a7..d1c9283f0 100644 --- a/actions/showfavorites.php +++ b/actions/showfavorites.php @@ -113,7 +113,7 @@ class ShowfavoritesAction extends Action } common_set_returnto($this->selfUrl()); - + return true; } @@ -136,10 +136,10 @@ class ShowfavoritesAction extends Action /** * Feeds for the section * - * @return void + * @return array Feed objects to show */ - function showFeeds() + function getFeeds() { $feedurl = common_local_url('favoritesrss', array('nickname' => @@ -147,10 +147,7 @@ class ShowfavoritesAction extends Action $feedtitle = sprintf(_('Feed for favorites of %s'), $this->user->nickname); - $this->element('link', array('rel' => 'alternate', - 'href' => $feedurl, - 'type' => 'application/rss+xml', - 'title' => $feedtitle)); + return array(new Feed(Feed::RSS1, $feedurl, $feedtitle)); } /** @@ -165,28 +162,6 @@ class ShowfavoritesAction extends Action $nav->show(); } - /** - * Show the replies feed links - * - * @return void - */ - - function showExportData() - { - $feedurl = common_local_url('favoritesrss', - array('nickname' => - $this->user->nickname)); - - $fl = new FeedList($this); - - // XXX: I18N - - $fl->show(array(0=>array('href'=> $feedurl, - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'Favorites'))); - } - /** * Show the content * diff --git a/actions/showgroup.php b/actions/showgroup.php index 7bc68fbc6..340e18333 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -292,37 +292,18 @@ class ShowgroupAction extends Action } /** - * Show a list of links to feeds this page produces + * Get a list of the feeds for this page * * @return void */ - function showExportData() - { - $fl = new FeedList($this); - $fl->show(array(0=>array('href'=>common_local_url('grouprss', - array('nickname' => $this->group->nickname)), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'notices'))); - } - - /** - * Show a list of links to feeds this page produces - * - * @return void - */ - - function showFeeds() + function getFeeds() { $url = common_local_url('grouprss', array('nickname' => $this->group->nickname)); - $this->element('link', array('rel' => 'alternate', - 'href' => $url, - 'type' => 'application/rss+xml', - 'title' => sprintf(_('Notice feed for %s group'), + return array(new Feed(Feed::RSS1, $url, sprintf(_('Notice feed for %s group'), $this->group->nickname))); } diff --git a/actions/showstream.php b/actions/showstream.php index 962f4b452..0ee5d769e 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -155,54 +155,35 @@ class ShowstreamAction extends Action return; } - function showExportData() + function getFeeds() { - $fl = new FeedList($this); - $fl->show(array(0=>array('href'=>common_local_url('userrss', - array('nickname' => $this->user->nickname)), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'notices'), - 1=>array('href'=>common_local_url('usertimeline', - array('nickname' => $this->user->nickname)), - 'type' => 'atom', - 'version' => 'Atom 1.0', - 'item' => 'usertimeline'), - 2=>array('href'=>common_local_url('foaf', - array('nickname' => $this->user->nickname)), - 'type' => 'rdf', - 'version' => 'FOAF', - 'item' => 'foaf'))); - } - - function showFeeds() - { - $this->element('link', array('rel' => 'alternate', - 'type' => 'application/rss+xml', - 'href' => common_local_url('userrss', - array('nickname' => $this->user->nickname)), - 'title' => sprintf(_('Notice feed for %s (RSS)'), - $this->user->nickname))); - - $this->element('link', - array('rel' => 'alternate', - 'href' => common_local_url('api', - array('apiaction' => 'statuses', - 'method' => 'user_timeline.atom', - 'argument' => $this->user->nickname)), - 'type' => 'application/atom+xml', - 'title' => sprintf(_('Notice feed for %s (Atom)'), - $this->user->nickname))); + return array(new Feed(Feed::RSS1, + common_local_url('userrss', + array('nickname' => $this->user->nickname)), + sprintf(_('Notice feed for %s (RSS 1.0)'), + $this->user->nickname)), + new Feed(Feed::RSS2, + common_local_url('api', + array('apiaction' => 'statuses', + 'method' => 'user_timeline', + 'argument' => $this->user->nickname.'.rss')), + sprintf(_('Notice feed for %s (RSS 2.0)'), + $this->user->nickname)), + new Feed(Feed::ATOM, + common_local_url('api', + array('apiaction' => 'statuses', + 'method' => 'user_timeline', + 'argument' => $this->user->nickname.'.atom')), + sprintf(_('Notice feed for %s (Atom)'), + $this->user->nickname)), + new Feed(Feed::FOAF, + common_local_url('foaf', array('nickname' => + $this->user->nickname)), + sprintf(_('FOAF for %s'), $this->user->nickname))); } function extraHead() { - // FOAF - $this->element('link', array('rel' => 'meta', - 'href' => common_local_url('foaf', array('nickname' => - $this->user->nickname)), - 'type' => 'application/rdf+xml', - 'title' => 'FOAF')); // for remote subscriptions etc. $this->element('meta', array('http-equiv' => 'X-XRDS-Location', 'content' => common_local_url('xrds', array('nickname' => diff --git a/actions/tag.php b/actions/tag.php index 4401f892a..231f2c299 100644 --- a/actions/tag.php +++ b/actions/tag.php @@ -37,9 +37,9 @@ class TagAction extends Action } $this->page = ($this->arg('page')) ? ($this->arg('page')+0) : 1; - + common_set_returnto($this->selfUrl()); - + return true; } @@ -61,12 +61,11 @@ class TagAction extends Action $this->showPage(); } - function showFeeds() + function getFeeds() { - $this->element('link', array('rel' => 'alternate', - 'href' => common_local_url('tagrss', array('tag' => $this->tag)), - 'type' => 'application/rss+xml', - 'title' => sprintf(_('Feed for tag %s'), $this->tag))); + return array(new Feed(Feed::RSS1, + common_local_url('tagrss', array('tag' => $this->tag)), + sprintf(_('Feed for tag %s'), $this->tag))); } function showPageNotice() @@ -74,15 +73,6 @@ class TagAction extends Action return sprintf(_('Messages tagged "%s", most recent first'), $this->tag); } - function showExportData() - { - $fl = new FeedList($this); - $fl->show(array(0=>array('href'=>common_local_url('tagrss', array('tag' => $this->tag)), - 'type' => 'rss', - 'version' => 'RSS 1.0', - 'item' => 'tagrss'))); - } - function showContent() { $notice = Notice_tag::getStream($this->tag, (($this->page-1)*NOTICES_PER_PAGE), NOTICES_PER_PAGE + 1); diff --git a/lib/action.php b/lib/action.php index ce92addf5..bd38bf79c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -225,9 +225,19 @@ class Action extends HTMLOutputter // lawsuit * * @return nothing */ + function showFeeds() { - // does nothing by default + $feeds = $this->getFeeds(); + + if ($feeds) { + foreach ($feeds as $feed) { + $this->element('link', array('rel' => $feed->rel(), + 'href' => $feed->url, + 'type' => $feed->mimeType(), + 'title' => $feed->title)); + } + } } /** @@ -540,15 +550,16 @@ class Action extends HTMLOutputter // lawsuit /** * Show export data feeds. * - * MAY overload if there are feeds - * - * @return nothing + * @return void */ + function showExportData() { - // is there structure to this? - // list of (visible!) feed links - // can we reuse list of feeds from showFeeds() ? + $feeds = $this->getFeeds(); + if ($feeds) { + $fl = new FeedList($this); + $fl->show($feeds); + } } /** @@ -924,4 +935,17 @@ class Action extends HTMLOutputter // lawsuit $this->elementEnd('div'); } } + + /** + * An array of feeds for this action. + * + * Returns an array of potential feeds for this action. + * + * @return array Feed object to show in head and links + */ + + function getFeeds() + { + return null; + } } diff --git a/lib/feed.php b/lib/feed.php new file mode 100644 index 000000000..466926844 --- /dev/null +++ b/lib/feed.php @@ -0,0 +1,110 @@ +. + * + * @category Feed + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Data structure for feeds + * + * This structure is a helpful container for shipping around information about syndication feeds. + * + * @category Feed + * @package Laconica + * @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://laconi.ca/ + */ + +class Feed +{ + const RSS1 = 1; + const RSS2 = 2; + const ATOM = 3; + const FOAF = 4; + + var $type = null; + var $url = null; + var $title = null; + + function __construct($type, $url, $title) + { + $this->type = $type; + $this->url = $url; + $this->title = $title; + } + + function mimeType() + { + switch ($this->type) { + case Feed::RSS1: + return 'application/rdf+xml'; + case Feed::RSS2: + return 'application/rss+xml'; + case Feed::ATOM: + return 'application/atom+xml'; + case Feed::FOAF: + return 'application/rdf+xml'; + default: + return null; + } + } + + function typeName() + { + switch ($this->type) { + case Feed::RSS1: + return _('RSS 1.0'); + case Feed::RSS2: + return _('RSS 2.0'); + case Feed::ATOM: + return _('Atom'); + case Feed::FOAF: + return _('FOAF'); + default: + return null; + } + } + + function rel() + { + switch ($this->type) { + case Feed::RSS1: + case Feed::RSS2: + case Feed::ATOM: + return 'alternate'; + case Feed::FOAF: + return 'meta'; + default: + return null; + } + } +} diff --git a/lib/feedlist.php b/lib/feedlist.php index 8bfcb9c5a..927e43c33 100644 --- a/lib/feedlist.php +++ b/lib/feedlist.php @@ -50,7 +50,7 @@ if (!defined('LACONICA')) { class FeedList extends Widget { var $action = null; - + function __construct($action=null) { parent::__construct($action); @@ -64,8 +64,8 @@ class FeedList extends Widget $this->out->element('h2', null, _('Export data')); $this->out->elementStart('ul', array('class' => 'xoxo')); - foreach ($feeds as $key => $value) { - $this->feedItem($feeds[$key]); + foreach ($feeds as $feed) { + $this->feedItem($feed); } $this->out->elementEnd('ul'); @@ -74,92 +74,27 @@ class FeedList extends Widget function feedItem($feed) { - $nickname = $this->action->trimmed('nickname'); - - switch($feed['item']) { - case 'notices': default: - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "$nickname's ".$feed['version']." notice feed"; - $feed['textContent'] = "RSS"; - break; - - case 'allrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = $feed['version']." feed for $nickname and friends"; - $feed['textContent'] = "RSS"; - break; - - case 'repliesrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = $feed['version']." feed for replies to $nickname"; - $feed['textContent'] = "RSS"; - break; - - case 'publicrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "Public timeline ".$feed['version']." feed"; - $feed['textContent'] = "RSS"; - break; - - case 'publicatom': - $feed_classname = "atom"; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "Public timeline ".$feed['version']." feed"; - $feed['textContent'] = "Atom"; - break; - - case 'noticesearchrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = $feed['version']." feed for this notice search"; - $feed['textContent'] = "RSS"; - break; - - case 'tagrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = $feed['version']." feed for this tag"; - $feed['textContent'] = "RSS"; - break; + $classname = null; - case 'favoritedrss': - $feed_classname = $feed['type']; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "Favorited ".$feed['version']." feed"; - $feed['textContent'] = "RSS"; + switch ($feed->type) { + case Feed::RSS1: + case Feed::RSS2: + $classname = 'rss'; break; - - case 'foaf': - $feed_classname = "foaf"; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "$nickname's FOAF file"; - $feed['textContent'] = "FOAF"; + case Feed::ATOM: + $classname = 'atom'; break; - - case 'favoritesrss': - $feed_classname = "favorites"; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "Feed for favorites of $nickname"; - $feed['textContent'] = "RSS"; - break; - - case 'usertimeline': - $feed_classname = "atom"; - $feed_mimetype = "application/".$feed['type']."+xml"; - $feed_title = "$nickname's ".$feed['version']." notice feed"; - $feed['textContent'] = "Atom"; + case Feed::FOAF: + $classname = 'foaf'; break; } + $this->out->elementStart('li'); - $this->out->element('a', array('href' => $feed['href'], - 'class' => $feed_classname, - 'type' => $feed_mimetype, - 'title' => $feed_title), - $feed['textContent']); + $this->out->element('a', array('href' => $feed->url, + 'class' => $classname, + 'type' => $feed->mimeType(), + 'title' => $feed->title), + $feed->typeName()); $this->out->elementEnd('li'); } } -- cgit v1.2.3-54-g00ecf From fc293545be13473d992b512141be233c2963f6da Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 11 Feb 2009 16:50:07 +0000 Subject: Minor. Changed from @class location to label --- actions/showgroup.php | 2 +- actions/showstream.php | 2 +- actions/tagother.php | 2 +- lib/grouplist.php | 2 +- lib/profilelist.php | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/actions/showgroup.php b/actions/showgroup.php index 7bc68fbc6..6df8dd306 100644 --- a/actions/showgroup.php +++ b/actions/showgroup.php @@ -244,7 +244,7 @@ class ShowgroupAction extends Action if ($this->group->location) { $this->elementStart('dl', 'entity_location'); $this->element('dt', null, _('Location')); - $this->element('dd', 'location', $this->group->location); + $this->element('dd', 'label', $this->group->location); $this->elementEnd('dl'); } diff --git a/actions/showstream.php b/actions/showstream.php index 962f4b452..bd6f4153b 100644 --- a/actions/showstream.php +++ b/actions/showstream.php @@ -281,7 +281,7 @@ class ShowstreamAction extends Action if ($this->profile->location) { $this->elementStart('dl', 'entity_location'); $this->element('dt', null, _('Location')); - $this->element('dd', 'location', $this->profile->location); + $this->element('dd', 'label', $this->profile->location); $this->elementEnd('dl'); } diff --git a/actions/tagother.php b/actions/tagother.php index 3e8a12fd6..79151c911 100644 --- a/actions/tagother.php +++ b/actions/tagother.php @@ -110,7 +110,7 @@ class TagotherAction extends Action if ($this->profile->location) { $this->elementStart('dl', 'entity_location'); $this->element('dt', null, _('Location')); - $this->element('dd', 'location', $this->profile->location); + $this->element('dd', 'label', $this->profile->location); $this->elementEnd('dl'); } if ($this->profile->homepage) { diff --git a/lib/grouplist.php b/lib/grouplist.php index 4c448e250..6801ab426 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -124,7 +124,7 @@ class GroupList extends Widget if ($this->group->location) { $this->out->elementStart('dl', 'entity_location'); $this->out->element('dt', null, _('Location')); - $this->out->elementStart('dd', 'location'); + $this->out->elementStart('dd', 'label'); $this->out->raw($this->highlight($this->group->location)); $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); diff --git a/lib/profilelist.php b/lib/profilelist.php index 4d924b039..8bef49dce 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -123,7 +123,7 @@ class ProfileList extends Widget if ($this->profile->location) { $this->out->elementStart('dl', 'entity_location'); $this->out->element('dt', null, _('Location')); - $this->out->elementStart('dd', 'location'); + $this->out->elementStart('dd', 'label'); $this->out->raw($this->highlight($this->profile->location)); $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); -- cgit v1.2.3-54-g00ecf From b5cc7e4aabeddd08a27e02b2249ce86f92f96fac Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 14:45:06 -0500 Subject: Handle DB_DataObject errors better We try to handle DB_DataObject errors a little bit better. Previously, they just spit out a cryptic string to the browser with a suggestion to turn on debugging (not a good idea!). So, we catch the error, write the full error message to the log, and then tell users that the can contact the admins if they need to. --- index.php | 25 ++++++++++++++++-- lib/dberroraction.php | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/htmloutputter.php | 14 ++++++---- 3 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 lib/dberroraction.php (limited to 'lib') diff --git a/index.php b/index.php index 717b17361..4db0e7555 100644 --- a/index.php +++ b/index.php @@ -25,7 +25,8 @@ require_once INSTALLDIR . '/lib/common.php'; $user = null; $action = null; -function getPath($req) { +function getPath($req) +{ if (common_config('site', 'fancy')) { return $req['p']; } else if ($_SERVER['PATH_INFO']) { @@ -35,10 +36,30 @@ function getPath($req) { } } -function main() { +function handleError($error) +{ + common_log(LOG_ERR, "PEAR error: " . $error->getMessage()); + $msg = sprintf(_('The database for %s isn\'t responding correctly, '. + 'so the site won\'t work properly. '. + 'The site admins probably know about the problem, '. + 'but you can contact them at %s to make sure. '. + 'Otherwise, wait a few minutes and try again.'), + common_config('site', 'name'), + common_config('site', 'email')); + + $dac = new DBErrorAction($msg, 500); + $dac->showPage(); + exit(-1); +} +function main() +{ global $user, $action; + // For database errors + + PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError'); + // XXX: we need a little more structure in this script // get and cache current user diff --git a/lib/dberroraction.php b/lib/dberroraction.php new file mode 100644 index 000000000..0dc92490c --- /dev/null +++ b/lib/dberroraction.php @@ -0,0 +1,73 @@ + + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/servererroraction.php'; + +/** + * Class for displaying DB Errors + * + * This only occurs if there's been a DB_DataObject_Error that's + * reported through PEAR, so we try to avoid doing anything that connects + * to the DB, so we don't trigger it again. + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ + +class DBErrorAction extends ServerErrorAction +{ + function __construct($message='Error', $code=500) + { + parent::__construct($message, $code); + } + + function title() + { + return _('Database error'); + } + + function getLanguage() + { + // Don't try to figure out user's language; just show the page + return common_config('site', 'language'); + } + + function showPrimaryNav() + { + // don't show primary nav + } +} diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index e2319b1fd..45e61d2fc 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -108,22 +108,26 @@ class HTMLOutputter extends XMLOutputter } header('Content-Type: '.$type); - + $this->extraHeaders(); $this->startXML('html', '-//W3C//DTD XHTML 1.0 Strict//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd'); - // FIXME: correct language for interface - - $language = common_language(); + $language = $this->getLanguage(); $this->elementStart('html', array('xmlns' => 'http://www.w3.org/1999/xhtml', 'xml:lang' => $language, 'lang' => $language)); } + function getLanguage() + { + // FIXME: correct language for interface + return common_language(); + } + /** * Ends an HTML document * @@ -134,7 +138,7 @@ class HTMLOutputter extends XMLOutputter $this->elementEnd('html'); $this->endXML(); } - + /** * To specify additional HTTP headers for the action * -- cgit v1.2.3-54-g00ecf From 1d5296e596168f6ee8b18e9917e8d8aa62ac254c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 15:39:49 -0500 Subject: change htmloutputter to use exception instead of common_user_error --- lib/htmloutputter.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/htmloutputter.php b/lib/htmloutputter.php index 45e61d2fc..06603ac05 100644 --- a/lib/htmloutputter.php +++ b/lib/htmloutputter.php @@ -101,9 +101,8 @@ class HTMLOutputter extends XMLOutputter $type = common_negotiate_type($cp, $sp); if (!$type) { - common_user_error(_('This page is not available in a '. - 'media type you accept'), 406); - exit(0); + throw new ClientException(_('This page is not available in a '. + 'media type you accept'), 406); } } -- cgit v1.2.3-54-g00ecf From 5127396325a29d6c7b8f0e1e0ae3e0580ab30dda Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 15:46:29 -0500 Subject: Move Commands stuff out of classes The classes/ subdir is primarily for the DB_DataObject classes. Stuff in there can get stomped by various generation scripts. I've moved the lurkers there -- related to command-handling -- to lib/. Since auto-loading works fine with lib/, there shouldn't be much of a visible change here. --- classes/Channel.php | 238 ----------------------- classes/Command.php | 419 ----------------------------------------- classes/CommandInterpreter.php | 198 ------------------- lib/channel.php | 238 +++++++++++++++++++++++ lib/command.php | 419 +++++++++++++++++++++++++++++++++++++++++ lib/commandinterpreter.php | 198 +++++++++++++++++++ 6 files changed, 855 insertions(+), 855 deletions(-) delete mode 100644 classes/Channel.php delete mode 100644 classes/Command.php delete mode 100644 classes/CommandInterpreter.php create mode 100644 lib/channel.php create mode 100644 lib/command.php create mode 100644 lib/commandinterpreter.php (limited to 'lib') diff --git a/classes/Channel.php b/classes/Channel.php deleted file mode 100644 index fdeff21fc..000000000 --- a/classes/Channel.php +++ /dev/null @@ -1,238 +0,0 @@ -. - */ - -if (!defined('LACONICA')) { exit(1); } - -class Channel -{ - - function on($user) - { - return false; - } - - function off($user) - { - return false; - } - - function output($user, $text) - { - return false; - } - - function error($user, $text) - { - return false; - } - - function source() - { - return null; - } -} - -class XMPPChannel extends Channel -{ - - var $conn = null; - - function source() - { - return 'xmpp'; - } - - function __construct($conn) - { - $this->conn = $conn; - } - - function on($user) - { - return $this->set_notify($user, 1); - } - - function off($user) - { - return $this->set_notify($user, 0); - } - - function output($user, $text) - { - $text = '['.common_config('site', 'name') . '] ' . $text; - jabber_send_message($user->jabber, $text); - } - - function error($user, $text) - { - $text = '['.common_config('site', 'name') . '] ' . $text; - jabber_send_message($user->jabber, $text); - } - - function set_notify(&$user, $notify) - { - $orig = clone($user); - $user->jabbernotify = $notify; - $result = $user->update($orig); - if (!$result) { - $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); - common_log(LOG_ERR, - 'Could not set notify flag to ' . $notify . - ' for user ' . common_log_objstring($user) . - ': ' . $last_error->message); - return false; - } else { - common_log(LOG_INFO, - 'User ' . $user->nickname . ' set notify flag to ' . $notify); - return true; - } - } -} - -class WebChannel extends Channel -{ - var $out = null; - - function __construct($out=null) - { - $this->out = $out; - } - - function source() - { - return 'web'; - } - - function on($user) - { - return false; - } - - function off($user) - { - return false; - } - - function output($user, $text) - { - # XXX: buffer all output and send it at the end - # XXX: even better, redirect to appropriate page - # depending on what command was run - $this->out->startHTML(); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Command results')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'command_result'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } - - function error($user, $text) - { - common_user_error($text); - } -} - -class AjaxWebChannel extends WebChannel -{ - function output($user, $text) - { - $this->out->startHTML('text/xml;charset=utf-8'); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Command results')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'command_result'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } - - function error($user, $text) - { - $this->out->startHTML('text/xml;charset=utf-8'); - $this->out->elementStart('head'); - $this->out->element('title', null, _('Ajax Error')); - $this->out->elementEnd('head'); - $this->out->elementStart('body'); - $this->out->element('p', array('id' => 'error'), $text); - $this->out->elementEnd('body'); - $this->out->endHTML(); - } -} - -class MailChannel extends Channel -{ - - var $addr = null; - - function source() - { - return 'mail'; - } - - function __construct($addr=null) - { - $this->addr = $addr; - } - - function on($user) - { - return $this->set_notify($user, 1); - } - - function off($user) - { - return $this->set_notify($user, 0); - } - - function output($user, $text) - { - - $headers['From'] = $user->incomingemail; - $headers['To'] = $this->addr; - - $headers['Subject'] = _('Command complete'); - - return mail_send(array($this->addr), $headers, $text); - } - - function error($user, $text) - { - - $headers['From'] = $user->incomingemail; - $headers['To'] = $this->addr; - - $headers['Subject'] = _('Command failed'); - - return mail_send(array($this->addr), $headers, $text); - } - - function set_notify($user, $value) - { - $orig = clone($user); - $user->smsnotify = $value; - $result = $user->update($orig); - if (!$result) { - common_log_db_error($user, 'UPDATE', __FILE__); - return false; - } - return true; - } -} diff --git a/classes/Command.php b/classes/Command.php deleted file mode 100644 index eacbdacb3..000000000 --- a/classes/Command.php +++ /dev/null @@ -1,419 +0,0 @@ -. - */ - -if (!defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/classes/Channel.php'); - -class Command -{ - - var $user = null; - - function __construct($user=null) - { - $this->user = $user; - } - - function execute($channel) - { - return false; - } -} - -class UnimplementedCommand extends Command -{ - function execute($channel) - { - $channel->error($this->user, _("Sorry, this command is not yet implemented.")); - } -} - -class TrackingCommand extends UnimplementedCommand -{ -} - -class TrackOffCommand extends UnimplementedCommand -{ -} - -class TrackCommand extends UnimplementedCommand -{ - var $word = null; - function __construct($user, $word) - { - parent::__construct($user); - $this->word = $word; - } -} - -class UntrackCommand extends UnimplementedCommand -{ - var $word = null; - function __construct($user, $word) - { - parent::__construct($user); - $this->word = $word; - } -} - -class NudgeCommand extends UnimplementedCommand -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } -} - -class InviteCommand extends UnimplementedCommand -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } -} - -class StatsCommand extends Command -{ - function execute($channel) - { - - $subs = new Subscription(); - $subs->subscriber = $this->user->id; - $subs_count = (int) $subs->count() - 1; - - $subbed = new Subscription(); - $subbed->subscribed = $this->user->id; - $subbed_count = (int) $subbed->count() - 1; - - $notices = new Notice(); - $notices->profile_id = $this->user->id; - $notice_count = (int) $notices->count(); - - $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n". - "Subscribers: %2\$s\n". - "Notices: %3\$s"), - $subs_count, - $subbed_count, - $notice_count)); - } -} - -class FavCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - - $recipient = - common_relative_profile($this->user, common_canonical_nickname($this->other)); - - if (!$recipient) { - $channel->error($this->user, _('No such user.')); - return; - } - $notice = $recipient->getCurrentNotice(); - if (!$notice) { - $channel->error($this->user, _('User has no last notice')); - return; - } - - $fave = Fave::addNew($this->user, $notice); - - if (!$fave) { - $channel->error($this->user, _('Could not create favorite.')); - return; - } - - $other = User::staticGet('id', $recipient->id); - - if ($other && $other->id != $user->id) { - if ($other->email && $other->emailnotifyfav) { - mail_notify_fave($other, $this->user, $notice); - } - } - - $this->user->blowFavesCache(); - - $channel->output($this->user, _('Notice marked as fave.')); - } -} - -class WhoisCommand extends Command -{ - var $other = null; - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - $recipient = - common_relative_profile($this->user, common_canonical_nickname($this->other)); - - if (!$recipient) { - $channel->error($this->user, _('No such user.')); - return; - } - - $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname, - $recipient->profileurl); - if ($recipient->fullname) { - $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname); - } - if ($recipient->location) { - $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location); - } - if ($recipient->homepage) { - $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage); - } - if ($recipient->bio) { - $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio); - } - $channel->output($this->user, $whois); - } -} - -class MessageCommand extends Command -{ - var $other = null; - var $text = null; - function __construct($user, $other, $text) - { - parent::__construct($user); - $this->other = $other; - $this->text = $text; - } - - function execute($channel) - { - $other = User::staticGet('nickname', common_canonical_nickname($this->other)); - $len = mb_strlen($this->text); - if ($len == 0) { - $channel->error($this->user, _('No content!')); - return; - } else if ($len > 140) { - $content = common_shorten_links($content); - if (mb_strlen($content) > 140) { - $channel->error($this->user, sprintf(_('Message too long - maximum is 140 characters, you sent %d'), $len)); - return; - } - } - - if (!$other) { - $channel->error($this->user, _('No such user.')); - return; - } else if (!$this->user->mutuallySubscribed($other)) { - $channel->error($this->user, _('You can\'t send a message to this user.')); - return; - } else if ($this->user->id == $other->id) { - $channel->error($this->user, _('Don\'t send a message to yourself; just say it to yourself quietly instead.')); - return; - } - $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source()); - if ($message) { - $channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other)); - } else { - $channel->error($this->user, _('Error sending direct message.')); - } - } -} - -class GetCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - $target_nickname = common_canonical_nickname($this->other); - - $target = - common_relative_profile($this->user, $target_nickname); - - if (!$target) { - $channel->error($this->user, _('No such user.')); - return; - } - $notice = $target->getCurrentNotice(); - if (!$notice) { - $channel->error($this->user, _('User has no last notice')); - return; - } - $notice_content = $notice->content; - - $channel->output($this->user, $target_nickname . ": " . $notice_content); - } -} - -class SubCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - - if (!$this->other) { - $channel->error($this->user, _('Specify the name of the user to subscribe to')); - return; - } - - $result = subs_subscribe_user($this->user, $this->other); - - if ($result == 'true') { - $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); - } else { - $channel->error($this->user, $result); - } - } -} - -class UnsubCommand extends Command -{ - - var $other = null; - - function __construct($user, $other) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - if(!$this->other) { - $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); - return; - } - - $result=subs_unsubscribe_user($this->user, $this->other); - - if ($result) { - $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); - } else { - $channel->error($this->user, $result); - } - } -} - -class OffCommand extends Command -{ - var $other = null; - function __construct($user, $other=null) - { - parent::__construct($user); - $this->other = $other; - } - function execute($channel) - { - if ($other) { - $channel->error($this->user, _("Command not yet implemented.")); - } else { - if ($channel->off($this->user)) { - $channel->output($this->user, _('Notification off.')); - } else { - $channel->error($this->user, _('Can\'t turn off notification.')); - } - } - } -} - -class OnCommand extends Command -{ - var $other = null; - function __construct($user, $other=null) - { - parent::__construct($user); - $this->other = $other; - } - - function execute($channel) - { - if ($other) { - $channel->error($this->user, _("Command not yet implemented.")); - } else { - if ($channel->on($this->user)) { - $channel->output($this->user, _('Notification on.')); - } else { - $channel->error($this->user, _('Can\'t turn on notification.')); - } - } - } -} - -class HelpCommand extends Command -{ - function execute($channel) - { - $channel->output($this->user, - _("Commands:\n". - "on - turn on notifications\n". - "off - turn off notifications\n". - "help - show this help\n". - "follow - subscribe to user\n". - "leave - unsubscribe from user\n". - "d - direct message to user\n". - "get - get last notice from user\n". - "whois - get profile info on user\n". - "fav - add user's last notice as a 'fave'\n". - "stats - get your stats\n". - "stop - same as 'off'\n". - "quit - same as 'off'\n". - "sub - same as 'follow'\n". - "unsub - same as 'leave'\n". - "last - same as 'get'\n". - "on - not yet implemented.\n". - "off - not yet implemented.\n". - "nudge - not yet implemented.\n". - "invite - not yet implemented.\n". - "track - not yet implemented.\n". - "untrack - not yet implemented.\n". - "track off - not yet implemented.\n". - "untrack all - not yet implemented.\n". - "tracks - not yet implemented.\n". - "tracking - not yet implemented.\n")); - } -} diff --git a/classes/CommandInterpreter.php b/classes/CommandInterpreter.php deleted file mode 100644 index 0679f5462..000000000 --- a/classes/CommandInterpreter.php +++ /dev/null @@ -1,198 +0,0 @@ -. - */ - -if (!defined('LACONICA')) { exit(1); } - -require_once(INSTALLDIR.'/classes/Command.php'); - -class CommandInterpreter -{ - - function handle_command($user, $text) - { - # XXX: localise - - $text = preg_replace('/\s+/', ' ', trim($text)); - list($cmd, $arg) = explode(' ', $text, 2); - - # We try to support all the same commands as Twitter, see - # http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands - # There are a few compatibility commands from earlier versions of - # Laconica - - switch(strtolower($cmd)) { - case 'help': - if ($arg) { - return null; - } - return new HelpCommand($user); - case 'on': - if ($arg) { - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new OnCommand($user, $other); - } - } else { - return new OnCommand($user); - } - case 'off': - if ($arg) { - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new OffCommand($user, $other); - } - } else { - return new OffCommand($user); - } - case 'stop': - case 'quit': - if ($arg) { - return null; - } else { - return new OffCommand($user); - } - case 'follow': - case 'sub': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new SubCommand($user, $other); - } - case 'leave': - case 'unsub': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new UnsubCommand($user, $other); - } - case 'get': - case 'last': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new GetCommand($user, $other); - } - case 'd': - case 'dm': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if (!$extra) { - return null; - } else { - return new MessageCommand($user, $other, $extra); - } - case 'whois': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new WhoisCommand($user, $other); - } - case 'fav': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new FavCommand($user, $other); - } - case 'nudge': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new NudgeCommand($user, $other); - } - case 'stats': - if ($arg) { - return null; - } - return new StatsCommand($user); - case 'invite': - if (!$arg) { - return null; - } - list($other, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else { - return new InviteCommand($user, $other); - } - case 'track': - if (!$arg) { - return null; - } - list($word, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else if ($word == 'off') { - return new TrackOffCommand($user); - } else { - return new TrackCommand($user, $word); - } - case 'untrack': - if (!$arg) { - return null; - } - list($word, $extra) = explode(' ', $arg, 2); - if ($extra) { - return null; - } else if ($word == 'all') { - return new TrackOffCommand($user); - } else { - return new UntrackCommand($user, $word); - } - case 'tracks': - case 'tracking': - if ($arg) { - return null; - } - return new TrackingCommand($user); - default: - return false; - } - } -} - diff --git a/lib/channel.php b/lib/channel.php new file mode 100644 index 000000000..fdeff21fc --- /dev/null +++ b/lib/channel.php @@ -0,0 +1,238 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +class Channel +{ + + function on($user) + { + return false; + } + + function off($user) + { + return false; + } + + function output($user, $text) + { + return false; + } + + function error($user, $text) + { + return false; + } + + function source() + { + return null; + } +} + +class XMPPChannel extends Channel +{ + + var $conn = null; + + function source() + { + return 'xmpp'; + } + + function __construct($conn) + { + $this->conn = $conn; + } + + function on($user) + { + return $this->set_notify($user, 1); + } + + function off($user) + { + return $this->set_notify($user, 0); + } + + function output($user, $text) + { + $text = '['.common_config('site', 'name') . '] ' . $text; + jabber_send_message($user->jabber, $text); + } + + function error($user, $text) + { + $text = '['.common_config('site', 'name') . '] ' . $text; + jabber_send_message($user->jabber, $text); + } + + function set_notify(&$user, $notify) + { + $orig = clone($user); + $user->jabbernotify = $notify; + $result = $user->update($orig); + if (!$result) { + $last_error = &PEAR::getStaticProperty('DB_DataObject','lastError'); + common_log(LOG_ERR, + 'Could not set notify flag to ' . $notify . + ' for user ' . common_log_objstring($user) . + ': ' . $last_error->message); + return false; + } else { + common_log(LOG_INFO, + 'User ' . $user->nickname . ' set notify flag to ' . $notify); + return true; + } + } +} + +class WebChannel extends Channel +{ + var $out = null; + + function __construct($out=null) + { + $this->out = $out; + } + + function source() + { + return 'web'; + } + + function on($user) + { + return false; + } + + function off($user) + { + return false; + } + + function output($user, $text) + { + # XXX: buffer all output and send it at the end + # XXX: even better, redirect to appropriate page + # depending on what command was run + $this->out->startHTML(); + $this->out->elementStart('head'); + $this->out->element('title', null, _('Command results')); + $this->out->elementEnd('head'); + $this->out->elementStart('body'); + $this->out->element('p', array('id' => 'command_result'), $text); + $this->out->elementEnd('body'); + $this->out->endHTML(); + } + + function error($user, $text) + { + common_user_error($text); + } +} + +class AjaxWebChannel extends WebChannel +{ + function output($user, $text) + { + $this->out->startHTML('text/xml;charset=utf-8'); + $this->out->elementStart('head'); + $this->out->element('title', null, _('Command results')); + $this->out->elementEnd('head'); + $this->out->elementStart('body'); + $this->out->element('p', array('id' => 'command_result'), $text); + $this->out->elementEnd('body'); + $this->out->endHTML(); + } + + function error($user, $text) + { + $this->out->startHTML('text/xml;charset=utf-8'); + $this->out->elementStart('head'); + $this->out->element('title', null, _('Ajax Error')); + $this->out->elementEnd('head'); + $this->out->elementStart('body'); + $this->out->element('p', array('id' => 'error'), $text); + $this->out->elementEnd('body'); + $this->out->endHTML(); + } +} + +class MailChannel extends Channel +{ + + var $addr = null; + + function source() + { + return 'mail'; + } + + function __construct($addr=null) + { + $this->addr = $addr; + } + + function on($user) + { + return $this->set_notify($user, 1); + } + + function off($user) + { + return $this->set_notify($user, 0); + } + + function output($user, $text) + { + + $headers['From'] = $user->incomingemail; + $headers['To'] = $this->addr; + + $headers['Subject'] = _('Command complete'); + + return mail_send(array($this->addr), $headers, $text); + } + + function error($user, $text) + { + + $headers['From'] = $user->incomingemail; + $headers['To'] = $this->addr; + + $headers['Subject'] = _('Command failed'); + + return mail_send(array($this->addr), $headers, $text); + } + + function set_notify($user, $value) + { + $orig = clone($user); + $user->smsnotify = $value; + $result = $user->update($orig); + if (!$result) { + common_log_db_error($user, 'UPDATE', __FILE__); + return false; + } + return true; + } +} diff --git a/lib/command.php b/lib/command.php new file mode 100644 index 000000000..eacbdacb3 --- /dev/null +++ b/lib/command.php @@ -0,0 +1,419 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +require_once(INSTALLDIR.'/classes/Channel.php'); + +class Command +{ + + var $user = null; + + function __construct($user=null) + { + $this->user = $user; + } + + function execute($channel) + { + return false; + } +} + +class UnimplementedCommand extends Command +{ + function execute($channel) + { + $channel->error($this->user, _("Sorry, this command is not yet implemented.")); + } +} + +class TrackingCommand extends UnimplementedCommand +{ +} + +class TrackOffCommand extends UnimplementedCommand +{ +} + +class TrackCommand extends UnimplementedCommand +{ + var $word = null; + function __construct($user, $word) + { + parent::__construct($user); + $this->word = $word; + } +} + +class UntrackCommand extends UnimplementedCommand +{ + var $word = null; + function __construct($user, $word) + { + parent::__construct($user); + $this->word = $word; + } +} + +class NudgeCommand extends UnimplementedCommand +{ + var $other = null; + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } +} + +class InviteCommand extends UnimplementedCommand +{ + var $other = null; + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } +} + +class StatsCommand extends Command +{ + function execute($channel) + { + + $subs = new Subscription(); + $subs->subscriber = $this->user->id; + $subs_count = (int) $subs->count() - 1; + + $subbed = new Subscription(); + $subbed->subscribed = $this->user->id; + $subbed_count = (int) $subbed->count() - 1; + + $notices = new Notice(); + $notices->profile_id = $this->user->id; + $notice_count = (int) $notices->count(); + + $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n". + "Subscribers: %2\$s\n". + "Notices: %3\$s"), + $subs_count, + $subbed_count, + $notice_count)); + } +} + +class FavCommand extends Command +{ + + var $other = null; + + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + + $recipient = + common_relative_profile($this->user, common_canonical_nickname($this->other)); + + if (!$recipient) { + $channel->error($this->user, _('No such user.')); + return; + } + $notice = $recipient->getCurrentNotice(); + if (!$notice) { + $channel->error($this->user, _('User has no last notice')); + return; + } + + $fave = Fave::addNew($this->user, $notice); + + if (!$fave) { + $channel->error($this->user, _('Could not create favorite.')); + return; + } + + $other = User::staticGet('id', $recipient->id); + + if ($other && $other->id != $user->id) { + if ($other->email && $other->emailnotifyfav) { + mail_notify_fave($other, $this->user, $notice); + } + } + + $this->user->blowFavesCache(); + + $channel->output($this->user, _('Notice marked as fave.')); + } +} + +class WhoisCommand extends Command +{ + var $other = null; + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + $recipient = + common_relative_profile($this->user, common_canonical_nickname($this->other)); + + if (!$recipient) { + $channel->error($this->user, _('No such user.')); + return; + } + + $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname, + $recipient->profileurl); + if ($recipient->fullname) { + $whois .= "\n" . sprintf(_('Fullname: %s'), $recipient->fullname); + } + if ($recipient->location) { + $whois .= "\n" . sprintf(_('Location: %s'), $recipient->location); + } + if ($recipient->homepage) { + $whois .= "\n" . sprintf(_('Homepage: %s'), $recipient->homepage); + } + if ($recipient->bio) { + $whois .= "\n" . sprintf(_('About: %s'), $recipient->bio); + } + $channel->output($this->user, $whois); + } +} + +class MessageCommand extends Command +{ + var $other = null; + var $text = null; + function __construct($user, $other, $text) + { + parent::__construct($user); + $this->other = $other; + $this->text = $text; + } + + function execute($channel) + { + $other = User::staticGet('nickname', common_canonical_nickname($this->other)); + $len = mb_strlen($this->text); + if ($len == 0) { + $channel->error($this->user, _('No content!')); + return; + } else if ($len > 140) { + $content = common_shorten_links($content); + if (mb_strlen($content) > 140) { + $channel->error($this->user, sprintf(_('Message too long - maximum is 140 characters, you sent %d'), $len)); + return; + } + } + + if (!$other) { + $channel->error($this->user, _('No such user.')); + return; + } else if (!$this->user->mutuallySubscribed($other)) { + $channel->error($this->user, _('You can\'t send a message to this user.')); + return; + } else if ($this->user->id == $other->id) { + $channel->error($this->user, _('Don\'t send a message to yourself; just say it to yourself quietly instead.')); + return; + } + $message = Message::saveNew($this->user->id, $other->id, $this->text, $channel->source()); + if ($message) { + $channel->output($this->user, sprintf(_('Direct message to %s sent'), $this->other)); + } else { + $channel->error($this->user, _('Error sending direct message.')); + } + } +} + +class GetCommand extends Command +{ + + var $other = null; + + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + $target_nickname = common_canonical_nickname($this->other); + + $target = + common_relative_profile($this->user, $target_nickname); + + if (!$target) { + $channel->error($this->user, _('No such user.')); + return; + } + $notice = $target->getCurrentNotice(); + if (!$notice) { + $channel->error($this->user, _('User has no last notice')); + return; + } + $notice_content = $notice->content; + + $channel->output($this->user, $target_nickname . ": " . $notice_content); + } +} + +class SubCommand extends Command +{ + + var $other = null; + + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + + if (!$this->other) { + $channel->error($this->user, _('Specify the name of the user to subscribe to')); + return; + } + + $result = subs_subscribe_user($this->user, $this->other); + + if ($result == 'true') { + $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); + } else { + $channel->error($this->user, $result); + } + } +} + +class UnsubCommand extends Command +{ + + var $other = null; + + function __construct($user, $other) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + if(!$this->other) { + $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); + return; + } + + $result=subs_unsubscribe_user($this->user, $this->other); + + if ($result) { + $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); + } else { + $channel->error($this->user, $result); + } + } +} + +class OffCommand extends Command +{ + var $other = null; + function __construct($user, $other=null) + { + parent::__construct($user); + $this->other = $other; + } + function execute($channel) + { + if ($other) { + $channel->error($this->user, _("Command not yet implemented.")); + } else { + if ($channel->off($this->user)) { + $channel->output($this->user, _('Notification off.')); + } else { + $channel->error($this->user, _('Can\'t turn off notification.')); + } + } + } +} + +class OnCommand extends Command +{ + var $other = null; + function __construct($user, $other=null) + { + parent::__construct($user); + $this->other = $other; + } + + function execute($channel) + { + if ($other) { + $channel->error($this->user, _("Command not yet implemented.")); + } else { + if ($channel->on($this->user)) { + $channel->output($this->user, _('Notification on.')); + } else { + $channel->error($this->user, _('Can\'t turn on notification.')); + } + } + } +} + +class HelpCommand extends Command +{ + function execute($channel) + { + $channel->output($this->user, + _("Commands:\n". + "on - turn on notifications\n". + "off - turn off notifications\n". + "help - show this help\n". + "follow - subscribe to user\n". + "leave - unsubscribe from user\n". + "d - direct message to user\n". + "get - get last notice from user\n". + "whois - get profile info on user\n". + "fav - add user's last notice as a 'fave'\n". + "stats - get your stats\n". + "stop - same as 'off'\n". + "quit - same as 'off'\n". + "sub - same as 'follow'\n". + "unsub - same as 'leave'\n". + "last - same as 'get'\n". + "on - not yet implemented.\n". + "off - not yet implemented.\n". + "nudge - not yet implemented.\n". + "invite - not yet implemented.\n". + "track - not yet implemented.\n". + "untrack - not yet implemented.\n". + "track off - not yet implemented.\n". + "untrack all - not yet implemented.\n". + "tracks - not yet implemented.\n". + "tracking - not yet implemented.\n")); + } +} diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php new file mode 100644 index 000000000..0679f5462 --- /dev/null +++ b/lib/commandinterpreter.php @@ -0,0 +1,198 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +require_once(INSTALLDIR.'/classes/Command.php'); + +class CommandInterpreter +{ + + function handle_command($user, $text) + { + # XXX: localise + + $text = preg_replace('/\s+/', ' ', trim($text)); + list($cmd, $arg) = explode(' ', $text, 2); + + # We try to support all the same commands as Twitter, see + # http://getsatisfaction.com/twitter/topics/what_are_the_twitter_commands + # There are a few compatibility commands from earlier versions of + # Laconica + + switch(strtolower($cmd)) { + case 'help': + if ($arg) { + return null; + } + return new HelpCommand($user); + case 'on': + if ($arg) { + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new OnCommand($user, $other); + } + } else { + return new OnCommand($user); + } + case 'off': + if ($arg) { + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new OffCommand($user, $other); + } + } else { + return new OffCommand($user); + } + case 'stop': + case 'quit': + if ($arg) { + return null; + } else { + return new OffCommand($user); + } + case 'follow': + case 'sub': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new SubCommand($user, $other); + } + case 'leave': + case 'unsub': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new UnsubCommand($user, $other); + } + case 'get': + case 'last': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new GetCommand($user, $other); + } + case 'd': + case 'dm': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if (!$extra) { + return null; + } else { + return new MessageCommand($user, $other, $extra); + } + case 'whois': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new WhoisCommand($user, $other); + } + case 'fav': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new FavCommand($user, $other); + } + case 'nudge': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new NudgeCommand($user, $other); + } + case 'stats': + if ($arg) { + return null; + } + return new StatsCommand($user); + case 'invite': + if (!$arg) { + return null; + } + list($other, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else { + return new InviteCommand($user, $other); + } + case 'track': + if (!$arg) { + return null; + } + list($word, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else if ($word == 'off') { + return new TrackOffCommand($user); + } else { + return new TrackCommand($user, $word); + } + case 'untrack': + if (!$arg) { + return null; + } + list($word, $extra) = explode(' ', $arg, 2); + if ($extra) { + return null; + } else if ($word == 'all') { + return new TrackOffCommand($user); + } else { + return new UntrackCommand($user, $word); + } + case 'tracks': + case 'tracking': + if ($arg) { + return null; + } + return new TrackingCommand($user); + default: + return false; + } + } +} + -- cgit v1.2.3-54-g00ecf From 9d07032334043625a5aa3243d911bdc1c77a7a9c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 11 Feb 2009 15:48:30 -0500 Subject: fix command classes --- lib/channel.php | 1 - lib/command.php | 74 +++++++++++++++++++++++----------------------- lib/commandinterpreter.php | 3 +- 3 files changed, 38 insertions(+), 40 deletions(-) (limited to 'lib') diff --git a/lib/channel.php b/lib/channel.php index fdeff21fc..f1e205546 100644 --- a/lib/channel.php +++ b/lib/channel.php @@ -21,7 +21,6 @@ if (!defined('LACONICA')) { exit(1); } class Channel { - function on($user) { return false; diff --git a/lib/command.php b/lib/command.php index eacbdacb3..507990a0b 100644 --- a/lib/command.php +++ b/lib/command.php @@ -19,18 +19,18 @@ if (!defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/classes/Channel.php'); +require_once(INSTALLDIR.'/lib/channel.php'); class Command { - + var $user = null; - + function __construct($user=null) { $this->user = $user; } - + function execute($channel) { return false; @@ -109,7 +109,7 @@ class StatsCommand extends Command $notices = new Notice(); $notices->profile_id = $this->user->id; $notice_count = (int) $notices->count(); - + $channel->output($this->user, sprintf(_("Subscriptions: %1\$s\n". "Subscribers: %2\$s\n". "Notices: %3\$s"), @@ -121,21 +121,21 @@ class StatsCommand extends Command class FavCommand extends Command { - + var $other = null; - + function __construct($user, $other) { parent::__construct($user); $this->other = $other; } - + function execute($channel) { - - $recipient = + + $recipient = common_relative_profile($this->user, common_canonical_nickname($this->other)); - + if (!$recipient) { $channel->error($this->user, _('No such user.')); return; @@ -145,7 +145,7 @@ class FavCommand extends Command $channel->error($this->user, _('User has no last notice')); return; } - + $fave = Fave::addNew($this->user, $notice); if (!$fave) { @@ -154,15 +154,15 @@ class FavCommand extends Command } $other = User::staticGet('id', $recipient->id); - + if ($other && $other->id != $user->id) { if ($other->email && $other->emailnotifyfav) { mail_notify_fave($other, $this->user, $notice); } } - + $this->user->blowFavesCache(); - + $channel->output($this->user, _('Notice marked as fave.')); } } @@ -175,17 +175,17 @@ class WhoisCommand extends Command parent::__construct($user); $this->other = $other; } - + function execute($channel) { - $recipient = + $recipient = common_relative_profile($this->user, common_canonical_nickname($this->other)); - + if (!$recipient) { $channel->error($this->user, _('No such user.')); return; } - + $whois = sprintf(_("%1\$s (%2\$s)"), $recipient->nickname, $recipient->profileurl); if ($recipient->fullname) { @@ -214,7 +214,7 @@ class MessageCommand extends Command $this->other = $other; $this->text = $text; } - + function execute($channel) { $other = User::staticGet('nickname', common_canonical_nickname($this->other)); @@ -229,7 +229,7 @@ class MessageCommand extends Command return; } } - + if (!$other) { $channel->error($this->user, _('No such user.')); return; @@ -251,19 +251,19 @@ class MessageCommand extends Command class GetCommand extends Command { - + var $other = null; - + function __construct($user, $other) { parent::__construct($user); $this->other = $other; } - + function execute($channel) { $target_nickname = common_canonical_nickname($this->other); - + $target = common_relative_profile($this->user, $target_nickname); @@ -277,32 +277,32 @@ class GetCommand extends Command return; } $notice_content = $notice->content; - + $channel->output($this->user, $target_nickname . ": " . $notice_content); } } class SubCommand extends Command { - + var $other = null; - + function __construct($user, $other) { parent::__construct($user); $this->other = $other; } - + function execute($channel) { - + if (!$this->other) { $channel->error($this->user, _('Specify the name of the user to subscribe to')); return; } - + $result = subs_subscribe_user($this->user, $this->other); - + if ($result == 'true') { $channel->output($this->user, sprintf(_('Subscribed to %s'), $this->other)); } else { @@ -315,7 +315,7 @@ class UnsubCommand extends Command { var $other = null; - + function __construct($user, $other) { parent::__construct($user); @@ -328,9 +328,9 @@ class UnsubCommand extends Command $channel->error($this->user, _('Specify the name of the user to unsubscribe from')); return; } - + $result=subs_unsubscribe_user($this->user, $this->other); - + if ($result) { $channel->output($this->user, sprintf(_('Unsubscribed from %s'), $this->other)); } else { @@ -369,7 +369,7 @@ class OnCommand extends Command parent::__construct($user); $this->other = $other; } - + function execute($channel) { if ($other) { @@ -406,7 +406,7 @@ class HelpCommand extends Command "unsub - same as 'leave'\n". "last - same as 'get'\n". "on - not yet implemented.\n". - "off - not yet implemented.\n". + "off - not yet implemented.\n". "nudge - not yet implemented.\n". "invite - not yet implemented.\n". "track - not yet implemented.\n". diff --git a/lib/commandinterpreter.php b/lib/commandinterpreter.php index 0679f5462..49c733c03 100644 --- a/lib/commandinterpreter.php +++ b/lib/commandinterpreter.php @@ -19,11 +19,10 @@ if (!defined('LACONICA')) { exit(1); } -require_once(INSTALLDIR.'/classes/Command.php'); +require_once INSTALLDIR.'/lib/command.php'; class CommandInterpreter { - function handle_command($user, $text) { # XXX: localise -- cgit v1.2.3-54-g00ecf From 7155cf813de1502e796c0eac1e680289f3552c29 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 11 Feb 2009 17:46:53 -0800 Subject: Move/reorg Twitter broadcast code to lib/twitter.php in prep for making a twitterqueuehandler. --- actions/twittersettings.php | 5 ++- lib/twitter.php | 97 +++++++++++++++++++++++++++++++++++++++++++-- lib/util.php | 87 ++++------------------------------------ 3 files changed, 104 insertions(+), 85 deletions(-) (limited to 'lib') diff --git a/actions/twittersettings.php b/actions/twittersettings.php index 2d41469bb..a79859bbf 100644 --- a/actions/twittersettings.php +++ b/actions/twittersettings.php @@ -32,6 +32,7 @@ if (!defined('LACONICA')) { } require_once INSTALLDIR.'/lib/connectsettingsaction.php'; +require_once INSTALLDIR.'/lib/twitter.php'; define('SUBSCRIPTIONS', 80); @@ -90,7 +91,7 @@ class TwittersettingsAction extends ConnectSettingsAction $fuser = null; - $flink = Foreign_link::getByUserID($user->id, 1); // 1 == Twitter + $flink = Foreign_link::getByUserID($user->id, TWITTER_SERVICE); if ($flink) { $fuser = $flink->getForeignUser(); @@ -358,7 +359,7 @@ class TwittersettingsAction extends ConnectSettingsAction $flink->user_id = $user->id; $flink->foreign_id = $twit_user->id; - $flink->service = 1; // Twitter + $flink->service = TWITTER_SERVICE; $flink->credentials = $password; $flink->created = common_sql_now(); diff --git a/lib/twitter.php b/lib/twitter.php index 197298549..72212c185 100644 --- a/lib/twitter.php +++ b/lib/twitter.php @@ -19,6 +19,8 @@ if (!defined('LACONICA')) { exit(1); } +define("TWITTER_SERVICE", 1); // Twitter is foreign_service ID 1 + function get_twitter_data($uri, $screen_name, $password) { @@ -28,14 +30,13 @@ function get_twitter_data($uri, $screen_name, $password) CURLOPT_FAILONERROR => true, CURLOPT_HEADER => false, CURLOPT_FOLLOWLOCATION => true, - # CURLOPT_USERAGENT => "identi.ca", + CURLOPT_USERAGENT => "Laconica", CURLOPT_CONNECTTIMEOUT => 120, CURLOPT_TIMEOUT => 120, # Twitter is strict about accepting invalid "Expect" headers CURLOPT_HTTPHEADER => array('Expect:') ); - $ch = curl_init($uri); curl_setopt_array($ch, $options); $data = curl_exec($ch); @@ -95,7 +96,7 @@ function add_twitter_user($twitter_id, $screen_name) $fuser->nickname = $screen_name; $fuser->uri = 'http://twitter.com/' . $screen_name; $fuser->id = $twitter_id; - $fuser->service = 1; // Twitter + $fuser->service = TWITTER_SERVICE; // Twitter $fuser->created = common_sql_now(); $result = $fuser->insert(); @@ -206,3 +207,93 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password) return true; } +function is_twitter_bound($notice, $flink) { + + // Check to see if notice should go to Twitter + if (($flink->noticesync & FOREIGN_NOTICE_SEND)) { + + // If it's not a Twitter-style reply, or if the user WANTS to send replies. + if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || + ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) { + return true; + } + } + + return false; +} + +function broadcast_twitter($notice) +{ + global $config; + $success = true; + + $flink = Foreign_link::getByUserID($notice->profile_id, + TWITTER_SERVICE); + + // XXX: Not sure WHERE to check whether a notice should go to + // Twitter. Should we even put in the queue if it's not? --Zach + if (is_twitter_bound($notice, $flink)) { + + $fuser = $flink->getForeignUser(); + $twitter_user = $fuser->nickname; + $twitter_password = $flink->credentials; + $uri = 'http://www.twitter.com/statuses/update.json'; + + // XXX: Hack to get around PHP cURL's use of @ being a a meta character + $statustxt = preg_replace('/^@/', ' @', $notice->content); + + $options = array( + CURLOPT_USERPWD => "$twitter_user:$twitter_password", + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => + array( + 'status' => $statustxt, + 'source' => $config['integration']['source'] + ), + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FAILONERROR => true, + CURLOPT_HEADER => false, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_USERAGENT => "Laconica", + CURLOPT_CONNECTTIMEOUT => 120, // XXX: How long should this be? + CURLOPT_TIMEOUT => 120, + + # Twitter is strict about accepting invalid "Expect" headers + CURLOPT_HTTPHEADER => array('Expect:') + ); + + $ch = curl_init($uri); + curl_setopt_array($ch, $options); + $data = curl_exec($ch); + $errmsg = curl_error($ch); + + if ($errmsg) { + common_debug("cURL error: $errmsg - " . + "trying to send notice for $twitter_user.", + __FILE__); + $success = false; + } + + curl_close($ch); + + if (!$data) { + common_debug("No data returned by Twitter's " . + "API trying to send update for $twitter_user", + __FILE__); + $success = false; + } + + // Twitter should return a status + $status = json_decode($data); + + if (!$status->id) { + common_debug("Unexpected data returned by Twitter " . + " API trying to send update for $twitter_user", + __FILE__); + $success = false; + } + } + + return $success; +} + diff --git a/lib/util.php b/lib/util.php index c0c980111..3f4fae3a5 100644 --- a/lib/util.php +++ b/lib/util.php @@ -796,24 +796,6 @@ function common_redirect($url, $code=307) function common_broadcast_notice($notice, $remote=false) { - - // Check to see if notice should go to Twitter - $flink = Foreign_link::getByUserID($notice->profile_id, 1); // 1 == Twitter - if (($flink->noticesync & FOREIGN_NOTICE_SEND) == FOREIGN_NOTICE_SEND) { - - // If it's not a Twitter-style reply, or if the user WANTS to send replies... - - if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || - (($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) == FOREIGN_NOTICE_SEND_REPLY)) { - - $result = common_twitter_broadcast($notice, $flink); - - if (!$result) { - common_debug('Unable to send notice: ' . $notice->id . ' to Twitter.', __FILE__); - } - } - } - if (common_config('queue', 'enabled')) { // Do it later! return common_enqueue_notice($notice); @@ -822,68 +804,6 @@ function common_broadcast_notice($notice, $remote=false) } } -function common_twitter_broadcast($notice, $flink) -{ - global $config; - $success = true; - $fuser = $flink->getForeignUser(); - $twitter_user = $fuser->nickname; - $twitter_password = $flink->credentials; - $uri = 'http://www.twitter.com/statuses/update.json'; - - // XXX: Hack to get around PHP cURL's use of @ being a a meta character - $statustxt = preg_replace('/^@/', ' @', $notice->content); - - $options = array( - CURLOPT_USERPWD => "$twitter_user:$twitter_password", - CURLOPT_POST => true, - CURLOPT_POSTFIELDS => array( - 'status' => $statustxt, - 'source' => $config['integration']['source'] - ), - CURLOPT_RETURNTRANSFER => true, - CURLOPT_FAILONERROR => true, - CURLOPT_HEADER => false, - CURLOPT_FOLLOWLOCATION => true, - CURLOPT_USERAGENT => "Laconica", - CURLOPT_CONNECTTIMEOUT => 120, // XXX: Scary!!!! How long should this be? - CURLOPT_TIMEOUT => 120, - - # Twitter is strict about accepting invalid "Expect" headers - CURLOPT_HTTPHEADER => array('Expect:') - ); - - $ch = curl_init($uri); - curl_setopt_array($ch, $options); - $data = curl_exec($ch); - $errmsg = curl_error($ch); - - if ($errmsg) { - common_debug("cURL error: $errmsg - trying to send notice for $twitter_user.", - __FILE__); - $success = false; - } - - curl_close($ch); - - if (!$data) { - common_debug("No data returned by Twitter's API trying to send update for $twitter_user", - __FILE__); - $success = false; - } - - // Twitter should return a status - $status = json_decode($data); - - if (!$status->id) { - common_debug("Unexpected data returned by Twitter API trying to send update for $twitter_user", - __FILE__); - $success = false; - } - - return $success; -} - // Stick the notice on the queue function common_enqueue_notice($notice) @@ -935,6 +855,13 @@ function common_real_broadcast($notice, $remote=false) common_log(LOG_ERR, 'Error in public broadcast for notice ' . $notice->id); } } + if ($success) { + $success = broadcast_twitter($notice); + if (!$success) { + common_log(LOG_ERR, 'Error in Twitter broadcast for notice ' . $notice->id); + } + } + // XXX: broadcast notices to other IM return $success; } -- cgit v1.2.3-54-g00ecf From 9f035e2847e0d119ca3d70e02df6f4fa73ca64c3 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 11 Feb 2009 21:41:56 -0800 Subject: Code to handle PEAR_Errors raised by DB_DataObject that are bubbling up, but are actually expected and can safely be ignored. --- actions/emailsettings.php | 22 ++++++++++++++++++++++ actions/register.php | 23 ++++++++++++++++++++++- lib/action.php | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/actions/emailsettings.php b/actions/emailsettings.php index b84acb214..c6c983453 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -487,4 +487,26 @@ class EmailsettingsAction extends AccountSettingsAction return $other->id != $user->id; } } + + /** + * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * + * In this case email don't exist in the DB yet, so DB_DataObject + * throws an error. Overrided from Action. + * + * @param PEAR_Error + * + * @return nothing + */ + + function checkDB_DataObjectError($error) { + if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { + + // Do nothing. + + } else { + parent::checkDB_DataObjectError($error); + } + } + } diff --git a/actions/register.php b/actions/register.php index 5d7a8ce69..853bd0cf6 100644 --- a/actions/register.php +++ b/actions/register.php @@ -223,10 +223,31 @@ class RegisterAction extends Action */ function nicknameExists($nickname) - { + { $user = User::staticGet('nickname', $nickname); return ($user !== false); } + + /** + * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * + * In this case nickname and email don't exist in the DB yet, + * so DB_DataObject throws an error. Overrided from Action. + * + * @param PEAR_Error + * + * @return nothing + */ + + function checkDB_DataObjectError($error) { + if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { + + // Do nothing. + + } else { + parent::checkDB_DataObjectError($error); + } + } /** * Does the given email address already exist? diff --git a/lib/action.php b/lib/action.php index bd38bf79c..e3a8ef62c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -82,6 +82,17 @@ class Action extends HTMLOutputter // lawsuit */ function prepare($argarray) { + // This is for checking PEAR_Errors raised by DB_DataObject. + // Setting this to PEAR_ERROR_CALLBACK because setting + // to PEAR_ERROR_EXCEPTION does't work to allow PEAR_Errors + // to be handled as PHP5 exceptions, and PEAR_ERROR_RETURN + // does not cause DB_DataObject to actually return PEAR_Errors + // that can be checked with PEAR::isError() -- instead + // they just disappear into the ether, and can only be checked for + // after the fact. -- Zach + PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, + array($this, "checkDB_DataObjectError")); + $this->args =& common_copy_args($argarray); return true; } @@ -844,6 +855,21 @@ class Action extends HTMLOutputter // lawsuit throw new ClientException($msg, $code); } + /** + * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * + * Logs the DB_DataObject error. Override to do something else. + * + * @param PEAR_Error + * + * @return nothing + */ + + function checkDB_DataObjectError($error) { + common_log(LOG_ERR, $error->getMessage()); + // XXX: throw an exception here? --Zach + } + /** * Returns the current URL * -- cgit v1.2.3-54-g00ecf From 616bdd43a921b2554d21b80af28ddb0fb6cb3c16 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 11 Feb 2009 22:08:20 -0800 Subject: Just discovered the PEAR_Error handling function in index.php. Duh. Renamed the Action functions to throw an exception like it. I still think it probably makes sense to have the callback defined in both places for finer control. --- actions/emailsettings.php | 6 +++--- actions/register.php | 6 +++--- lib/action.php | 31 ++++++++++++++++++------------- 3 files changed, 24 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/actions/emailsettings.php b/actions/emailsettings.php index c6c983453..0a86aa66d 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -489,7 +489,7 @@ class EmailsettingsAction extends AccountSettingsAction } /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * Handle old fashioned PEAR_Error msgs coming from DB_DataObject * * In this case email don't exist in the DB yet, so DB_DataObject * throws an error. Overrided from Action. @@ -499,13 +499,13 @@ class EmailsettingsAction extends AccountSettingsAction * @return nothing */ - function checkDB_DataObjectError($error) { + function handleError($error) { if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { // Do nothing. } else { - parent::checkDB_DataObjectError($error); + parent::handleError($error); } } diff --git a/actions/register.php b/actions/register.php index 853bd0cf6..aafb54ebb 100644 --- a/actions/register.php +++ b/actions/register.php @@ -229,7 +229,7 @@ class RegisterAction extends Action } /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * Handle old fashioned PEAR_Error msgs coming from DB_DataObject * * In this case nickname and email don't exist in the DB yet, * so DB_DataObject throws an error. Overrided from Action. @@ -239,13 +239,13 @@ class RegisterAction extends Action * @return nothing */ - function checkDB_DataObjectError($error) { + function handleError($error) { if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { // Do nothing. } else { - parent::checkDB_DataObjectError($error); + parent::handleError($error); } } diff --git a/lib/action.php b/lib/action.php index e3a8ef62c..926fe93fb 100644 --- a/lib/action.php +++ b/lib/action.php @@ -82,16 +82,10 @@ class Action extends HTMLOutputter // lawsuit */ function prepare($argarray) { - // This is for checking PEAR_Errors raised by DB_DataObject. - // Setting this to PEAR_ERROR_CALLBACK because setting - // to PEAR_ERROR_EXCEPTION does't work to allow PEAR_Errors - // to be handled as PHP5 exceptions, and PEAR_ERROR_RETURN - // does not cause DB_DataObject to actually return PEAR_Errors - // that can be checked with PEAR::isError() -- instead - // they just disappear into the ether, and can only be checked for - // after the fact. -- Zach + + // For PEAR_Errors comming from DB_DataObject PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, - array($this, "checkDB_DataObjectError")); + array($this, "handleError")); $this->args =& common_copy_args($argarray); return true; @@ -856,7 +850,7 @@ class Action extends HTMLOutputter // lawsuit } /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject + * Handle old fashioned PEAR_Error msgs coming from DB_DataObject * * Logs the DB_DataObject error. Override to do something else. * @@ -865,9 +859,20 @@ class Action extends HTMLOutputter // lawsuit * @return nothing */ - function checkDB_DataObjectError($error) { - common_log(LOG_ERR, $error->getMessage()); - // XXX: throw an exception here? --Zach + function handleError($error) { + + common_log(LOG_ERR, "PEAR error: " . $error->getMessage()); + $msg = sprintf(_('The database for %s isn\'t responding correctly, '. + 'so the site won\'t work properly. '. + 'The site admins probably know about the problem, '. + 'but you can contact them at %s to make sure. '. + 'Otherwise, wait a few minutes and try again.'), + common_config('site', 'name'), + common_config('site', 'email')); + + $dac = new DBErrorAction($msg, 500); + $dac->showPage(); + exit(-1); } /** -- cgit v1.2.3-54-g00ecf From 99773e3b5ef0fa395bccb9a9656afe7552d42594 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Feb 2009 07:58:36 -0500 Subject: wrap multiline regexp in quotes so it doesn't mess up my editor's indenting --- lib/util.php | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index c0c980111..03e3618db 100644 --- a/lib/util.php +++ b/lib/util.php @@ -394,20 +394,20 @@ function common_render_text($text) function common_replace_urls_callback($text, $callback) { // Start off with a regex - $regex = '# - (?: - (?: - (?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc):// - | - (?:mailto|aim|tel): - ) - [^.\s]+\.[^\s]+ - | - (?:[^.\s/:]+\.)+ - (?:museum|travel|[a-z]{2,4}) - (?:[:/][^\s]*)? - ) - #ix'; + $regex = '#'. + '(?:'. + '(?:'. + '(?:https?|ftps?|mms|rtsp|gopher|news|nntp|telnet|wais|file|prospero|webcal|xmpp|irc)://'. + '|'. + '(?:mailto|aim|tel):'. + ')'. + '[^.\s]+\.[^\s]+'. + '|'. + '(?:[^.\s/:]+\.)+'. + '(?:museum|travel|[a-z]{2,4})'. + '(?:[:/][^\s]*)?'. + ')'. + '#ix'; preg_match_all($regex, $text, $matches); // Then clean up what the regex left behind -- cgit v1.2.3-54-g00ecf From eaae4562228bcbf780329d7bbb5f35437b31ebe3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Feb 2009 08:38:43 -0500 Subject: Add XMLStringer for building XML strings We had a bunch of --- lib/util.php | 41 ++++++++++++++++++++++++++------ lib/xmlstringer.php | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 lib/xmlstringer.php (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 03e3618db..a6f6a9351 100644 --- a/lib/util.php +++ b/lib/util.php @@ -475,13 +475,14 @@ function common_linkify($url) { $display = $url; $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url:$url; + $attrs = array('href' => $url, 'rel' => 'external'); + if ($longurl = common_longurl($url)) { $longurl = htmlentities($longurl, ENT_QUOTES, 'UTF-8'); - $title = "title=\"$longurl\""; + $attrs['title'] = $longurl; } - else $title = ''; - return "$display"; + return XMLStringer::estring('a', $attrs, $display); } function common_longurl($short_url) @@ -582,7 +583,13 @@ function common_tag_link($tag) { $canonical = common_canonical_tag($tag); $url = common_local_url('tag', array('tag' => $canonical)); - return ''; + $xs = new XMLStringer(); + $xs->elementStart('span', 'tag'); + $xs->element('a', array('href' => $url, + 'rel' => 'tag'), + $tag); + $xs->elementEnd(); + return $xs->getString(); } function common_canonical_tag($tag) @@ -600,7 +607,14 @@ function common_at_link($sender_id, $nickname) $sender = Profile::staticGet($sender_id); $recipient = common_relative_profile($sender, common_canonical_nickname($nickname)); if ($recipient) { - return ''.$nickname.''; + $xs = new XMLStringer(false); + $xs->elementStart('span', 'vcard'); + $xs->elementStart('a', array('href' => $recipient->profileurl, + 'class' => 'url')); + $xs->element('span', 'fn nickname', $nickname); + $xs->elementEnd('a'); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $nickname; } @@ -611,7 +625,14 @@ function common_group_link($sender_id, $nickname) $sender = Profile::staticGet($sender_id); $group = User_group::staticGet('nickname', common_canonical_nickname($nickname)); if ($group && $sender->isMember($group)) { - return ''.$nickname.''; + $xs = new XMLStringer(); + $xs->elementStart('span', 'vcard'); + $xs->elementStart('a', array('href' => $group->permalink(), + 'class' => 'url')); + $xs->element('span', 'fn nickname', $nickname); + $xs->elementEnd('a'); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $nickname; } @@ -628,7 +649,13 @@ function common_at_hash_link($sender_id, $tag) $url = common_local_url('subscriptions', array('nickname' => $user->nickname, 'tag' => $tag)); - return ''; + $xs = new XMLStringer(); + $xs->elementStart('span', 'tag'); + $xs->element('a', array('href' => $url, + 'rel' => $tag), + $tag); + $xs->elementEnd('span'); + return $xs->getString(); } else { return $tag; } diff --git a/lib/xmlstringer.php b/lib/xmlstringer.php new file mode 100644 index 000000000..951b13b67 --- /dev/null +++ b/lib/xmlstringer.php @@ -0,0 +1,68 @@ +. + * + * @category Output + * @package Laconica + * @author Evan Prodromou + * @copyright 2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Create in-memory XML + * + * @category Output + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see Action + * @see HTMLOutputter + */ + +class XMLStringer extends XMLOutputter +{ + function __construct($indent=false) + { + $this->xw = new XMLWriter(); + $this->xw->openMemory(); + $this->xw->setIndent($indent); + } + + function getString() + { + return $this->xw->outputMemory(); + } + + // utility for quickly creating XML-strings + + static function estring($tag, $attrs=null, $content=null) + { + $xs = new XMLStringer(); + $xs->element($tag, $attrs, $content); + return $xs->getString(); + } +} \ No newline at end of file -- cgit v1.2.3-54-g00ecf From ab8d27b8d1e25bd1058b904d03fedf97148f4b89 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Feb 2009 09:22:45 -0500 Subject: don't over specialize URLs --- lib/util.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index a6f6a9351..37c941cdb 100644 --- a/lib/util.php +++ b/lib/util.php @@ -472,13 +472,15 @@ function common_replace_urls_callback($text, $callback) { } function common_linkify($url) { + // It comes in special'd, so we unspecial it before passing to the stringifying + // functions + $url = htmlspecialchars_decode($url); $display = $url; - $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url:$url; + $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url; $attrs = array('href' => $url, 'rel' => 'external'); if ($longurl = common_longurl($url)) { - $longurl = htmlentities($longurl, ENT_QUOTES, 'UTF-8'); $attrs['title'] = $longurl; } -- cgit v1.2.3-54-g00ecf From b09eb06dae77be27e56d1573de0de7d393950ce5 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Feb 2009 16:04:43 -0500 Subject: Revert "Just discovered the PEAR_Error handling function in index.php. Duh." This reverts commit 616bdd43a921b2554d21b80af28ddb0fb6cb3c16. Kind of a long hard way to deal with a simple situation, so I'd prefer to just use the global handler. --- actions/emailsettings.php | 6 +++--- actions/register.php | 6 +++--- lib/action.php | 31 +++++++++++++------------------ 3 files changed, 19 insertions(+), 24 deletions(-) (limited to 'lib') diff --git a/actions/emailsettings.php b/actions/emailsettings.php index 0a86aa66d..c6c983453 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -489,7 +489,7 @@ class EmailsettingsAction extends AccountSettingsAction } /** - * Handle old fashioned PEAR_Error msgs coming from DB_DataObject + * Check old fashioned PEAR_Error msgs coming from DB_DataObject * * In this case email don't exist in the DB yet, so DB_DataObject * throws an error. Overrided from Action. @@ -499,13 +499,13 @@ class EmailsettingsAction extends AccountSettingsAction * @return nothing */ - function handleError($error) { + function checkDB_DataObjectError($error) { if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { // Do nothing. } else { - parent::handleError($error); + parent::checkDB_DataObjectError($error); } } diff --git a/actions/register.php b/actions/register.php index aafb54ebb..853bd0cf6 100644 --- a/actions/register.php +++ b/actions/register.php @@ -229,7 +229,7 @@ class RegisterAction extends Action } /** - * Handle old fashioned PEAR_Error msgs coming from DB_DataObject + * Check old fashioned PEAR_Error msgs coming from DB_DataObject * * In this case nickname and email don't exist in the DB yet, * so DB_DataObject throws an error. Overrided from Action. @@ -239,13 +239,13 @@ class RegisterAction extends Action * @return nothing */ - function handleError($error) { + function checkDB_DataObjectError($error) { if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { // Do nothing. } else { - parent::handleError($error); + parent::checkDB_DataObjectError($error); } } diff --git a/lib/action.php b/lib/action.php index 926fe93fb..e3a8ef62c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -82,10 +82,16 @@ class Action extends HTMLOutputter // lawsuit */ function prepare($argarray) { - - // For PEAR_Errors comming from DB_DataObject + // This is for checking PEAR_Errors raised by DB_DataObject. + // Setting this to PEAR_ERROR_CALLBACK because setting + // to PEAR_ERROR_EXCEPTION does't work to allow PEAR_Errors + // to be handled as PHP5 exceptions, and PEAR_ERROR_RETURN + // does not cause DB_DataObject to actually return PEAR_Errors + // that can be checked with PEAR::isError() -- instead + // they just disappear into the ether, and can only be checked for + // after the fact. -- Zach PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, - array($this, "handleError")); + array($this, "checkDB_DataObjectError")); $this->args =& common_copy_args($argarray); return true; @@ -850,7 +856,7 @@ class Action extends HTMLOutputter // lawsuit } /** - * Handle old fashioned PEAR_Error msgs coming from DB_DataObject + * Check old fashioned PEAR_Error msgs coming from DB_DataObject * * Logs the DB_DataObject error. Override to do something else. * @@ -859,20 +865,9 @@ class Action extends HTMLOutputter // lawsuit * @return nothing */ - function handleError($error) { - - common_log(LOG_ERR, "PEAR error: " . $error->getMessage()); - $msg = sprintf(_('The database for %s isn\'t responding correctly, '. - 'so the site won\'t work properly. '. - 'The site admins probably know about the problem, '. - 'but you can contact them at %s to make sure. '. - 'Otherwise, wait a few minutes and try again.'), - common_config('site', 'name'), - common_config('site', 'email')); - - $dac = new DBErrorAction($msg, 500); - $dac->showPage(); - exit(-1); + function checkDB_DataObjectError($error) { + common_log(LOG_ERR, $error->getMessage()); + // XXX: throw an exception here? --Zach } /** -- cgit v1.2.3-54-g00ecf From 3b5fd8fb6bbfa95efe3294ea77ae809dab071f99 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 12 Feb 2009 16:05:37 -0500 Subject: Revert "Code to handle PEAR_Errors raised by DB_DataObject that are bubbling" This reverts commit 9f035e2847e0d119ca3d70e02df6f4fa73ca64c3. It's a lot of complicated stuff, and the global handler probably does fine. --- actions/emailsettings.php | 22 ---------------------- actions/register.php | 23 +---------------------- lib/action.php | 26 -------------------------- 3 files changed, 1 insertion(+), 70 deletions(-) (limited to 'lib') diff --git a/actions/emailsettings.php b/actions/emailsettings.php index c6c983453..b84acb214 100644 --- a/actions/emailsettings.php +++ b/actions/emailsettings.php @@ -487,26 +487,4 @@ class EmailsettingsAction extends AccountSettingsAction return $other->id != $user->id; } } - - /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject - * - * In this case email don't exist in the DB yet, so DB_DataObject - * throws an error. Overrided from Action. - * - * @param PEAR_Error - * - * @return nothing - */ - - function checkDB_DataObjectError($error) { - if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { - - // Do nothing. - - } else { - parent::checkDB_DataObjectError($error); - } - } - } diff --git a/actions/register.php b/actions/register.php index 853bd0cf6..5d7a8ce69 100644 --- a/actions/register.php +++ b/actions/register.php @@ -223,31 +223,10 @@ class RegisterAction extends Action */ function nicknameExists($nickname) - { + { $user = User::staticGet('nickname', $nickname); return ($user !== false); } - - /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject - * - * In this case nickname and email don't exist in the DB yet, - * so DB_DataObject throws an error. Overrided from Action. - * - * @param PEAR_Error - * - * @return nothing - */ - - function checkDB_DataObjectError($error) { - if ($error->getCode() == DB_DATAOBJECT_ERROR_NODATA) { - - // Do nothing. - - } else { - parent::checkDB_DataObjectError($error); - } - } /** * Does the given email address already exist? diff --git a/lib/action.php b/lib/action.php index e3a8ef62c..bd38bf79c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -82,17 +82,6 @@ class Action extends HTMLOutputter // lawsuit */ function prepare($argarray) { - // This is for checking PEAR_Errors raised by DB_DataObject. - // Setting this to PEAR_ERROR_CALLBACK because setting - // to PEAR_ERROR_EXCEPTION does't work to allow PEAR_Errors - // to be handled as PHP5 exceptions, and PEAR_ERROR_RETURN - // does not cause DB_DataObject to actually return PEAR_Errors - // that can be checked with PEAR::isError() -- instead - // they just disappear into the ether, and can only be checked for - // after the fact. -- Zach - PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, - array($this, "checkDB_DataObjectError")); - $this->args =& common_copy_args($argarray); return true; } @@ -855,21 +844,6 @@ class Action extends HTMLOutputter // lawsuit throw new ClientException($msg, $code); } - /** - * Check old fashioned PEAR_Error msgs coming from DB_DataObject - * - * Logs the DB_DataObject error. Override to do something else. - * - * @param PEAR_Error - * - * @return nothing - */ - - function checkDB_DataObjectError($error) { - common_log(LOG_ERR, $error->getMessage()); - // XXX: throw an exception here? --Zach - } - /** * Returns the current URL * -- cgit v1.2.3-54-g00ecf From dac8d103e69deb63c7eafe16286f23a66034d967 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 12 Feb 2009 22:16:48 +0000 Subject: Hooks for: header, contentblock, footer --- EVENTS.txt | 19 +++++++++++++++++++ lib/action.php | 15 ++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index d9634325d..aed3dd9c5 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -39,3 +39,22 @@ StartShowSections: Start the list of sections in the sidebar EndShowSections: End the list of sections in the sidebar - $action: the current action + +StartShowHeader: Showing before the header container +- $action: the current action + +EndShowHeader: Showing after the header container +- $action: the current action + +StartShowFooter: Showing before the footer container +- $action: the current action + +EndShowFooter: Showing after the footer container +- $action: the current action + +StartShowContentBlock: Showing before the content container +- $action: the current action + +EndShowContentBlock: Showing after the content container +- $action: the current action + diff --git a/lib/action.php b/lib/action.php index bd38bf79c..602118cdf 100644 --- a/lib/action.php +++ b/lib/action.php @@ -275,9 +275,15 @@ class Action extends HTMLOutputter // lawsuit { $this->elementStart('body', array('id' => $this->trimmed('action'))); $this->elementStart('div', array('id' => 'wrap')); - $this->showHeader(); + if (Event::handle('StartShowHeader', array($this))) { + $this->showHeader(); + Event::handle('EndShowHeader', array($this)); + } $this->showCore(); - $this->showFooter(); + if (Event::handle('StartShowFooter', array($this))) { + $this->showFooter(); + Event::handle('EndShowFooter', array($this)); + } $this->elementEnd('div'); $this->elementEnd('body'); } @@ -432,7 +438,10 @@ class Action extends HTMLOutputter // lawsuit { $this->elementStart('div', array('id' => 'core')); $this->showLocalNavBlock(); - $this->showContentBlock(); + if (Event::handle('StartShowContentBlock', array($this))) { + $this->showContentBlock(); + Event::handle('EndShowContentBlock', array($this)); + } $this->showAside(); $this->elementEnd('div'); } -- cgit v1.2.3-54-g00ecf From f8e2ad0677d6eede93e3008452e36985ea999d74 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 12 Feb 2009 14:39:21 -0800 Subject: The fabled twitterqueuehandler --- lib/twitter.php | 2 +- lib/util.php | 2 +- scripts/startdaemons.sh | 3 +- scripts/stopdaemons.sh | 2 +- scripts/twitterqueuehandler.php | 71 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 4 deletions(-) create mode 100755 scripts/twitterqueuehandler.php (limited to 'lib') diff --git a/lib/twitter.php b/lib/twitter.php index 72212c185..deb6fd276 100644 --- a/lib/twitter.php +++ b/lib/twitter.php @@ -231,7 +231,7 @@ function broadcast_twitter($notice) TWITTER_SERVICE); // XXX: Not sure WHERE to check whether a notice should go to - // Twitter. Should we even put in the queue if it's not? --Zach + // Twitter. Should we even put in the queue if it shouldn't? --Zach if (is_twitter_bound($notice, $flink)) { $fuser = $flink->getForeignUser(); diff --git a/lib/util.php b/lib/util.php index 3f4fae3a5..7923fe28a 100644 --- a/lib/util.php +++ b/lib/util.php @@ -808,7 +808,7 @@ function common_broadcast_notice($notice, $remote=false) function common_enqueue_notice($notice) { - foreach (array('jabber', 'omb', 'sms', 'public') as $transport) { + foreach (array('jabber', 'omb', 'sms', 'public', 'twitter') as $transport) { $qi = new Queue_item(); $qi->notice_id = $notice->id; $qi->transport = $transport; diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 685bd938f..269036393 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -23,7 +23,8 @@ DIR=`dirname $0` for f in xmppdaemon.php jabberqueuehandler.php publicqueuehandler.php \ - xmppconfirmhandler.php smsqueuehandler.php ombqueuehandler.php; do + xmppconfirmhandler.php smsqueuehandler.php ombqueuehandler.php \ + twitterqueuehandler.php; do echo -n "Starting $f..."; php $DIR/$f diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh index 08e1d4714..b69d296d3 100755 --- a/scripts/stopdaemons.sh +++ b/scripts/stopdaemons.sh @@ -24,7 +24,7 @@ SDIR=`dirname $0` DIR=`php $SDIR/getpiddir.php` for f in jabberhandler ombhandler publichandler smshandler \ - xmppconfirmhandler xmppdaemon; do + xmppconfirmhandler xmppdaemon twitterhandler ; do FILES="$DIR/$f.*.pid" for ff in "$FILES" ; do diff --git a/scripts/twitterqueuehandler.php b/scripts/twitterqueuehandler.php new file mode 100755 index 000000000..7da4f1e20 --- /dev/null +++ b/scripts/twitterqueuehandler.php @@ -0,0 +1,71 @@ +#!/usr/bin/env php +. + */ + +# Abort if called from a web server +if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { + print "This script must be run from the command line\n"; + exit(); +} + +define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); +define('LACONICA', true); + +require_once(INSTALLDIR . '/lib/common.php'); +require_once(INSTALLDIR . '/lib/twitter.php'); +require_once(INSTALLDIR . '/lib/queuehandler.php'); + +set_error_handler('common_error_handler'); + +class TwitterQueueHandler extends QueueHandler +{ + + function transport() + { + return 'twitter'; + } + + function start() + { + $this->log(LOG_INFO, "INITIALIZE"); + return true; + } + + function handle_notice($notice) + { + return broadcast_twitter($notice); + } + + function finish() + { + } + +} + +ini_set("max_execution_time", "0"); +ini_set("max_input_time", "0"); +set_time_limit(0); + +mb_internal_encoding('UTF-8'); + +$id = ($argc > 1) ? $argv[1] : null; + +$handler = new TwitterQueueHandler($id); + +$handler->runOnce(); -- cgit v1.2.3-54-g00ecf From 070d1a3f247dd20e855bda1486121545ec667e9a Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 13 Feb 2009 04:33:43 +0000 Subject: Hooks for: custom, laconica, UA specific stylesheets --- EVENTS.txt | 18 ++++++++++++++++++ lib/action.php | 43 ++++++++++++++++++++++++++----------------- 2 files changed, 44 insertions(+), 17 deletions(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index aed3dd9c5..16ca9ea06 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -15,6 +15,24 @@ StartSecondaryNav: Showing the secondary nav menu EndSecondaryNav: At the end of the secondary nav menu - $action: the current action +StartShowStyles: Showing Style links; good place to add UA style resets +- $action: the current action + +EndShowStyles: End showing Style links; good place to add custom styles +- $action: the current action + +StartShowLaconicaStyles: Showing Laconica Style links +- $action: the current action + +EndShowLaconicaStyles: End showing Laconica Style links; good place to add handheld or JavaScript dependant styles +- $action: the current action + +StartShowUAStyles: Showing custom UA Style links +- $action: the current action + +EndShowUAStyles: End showing custom UA Style links; good place to add user-agent (e.g., filter, -webkit, -moz) specific styles +- $action: the current action + StartShowScripts: Showing JavaScript links - $action: the current action diff --git a/lib/action.php b/lib/action.php index 602118cdf..cd0db5399 100644 --- a/lib/action.php +++ b/lib/action.php @@ -151,25 +151,34 @@ class Action extends HTMLOutputter // lawsuit */ function showStylesheets() { - $this->element('link', array('rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION, - 'media' => 'screen, projection, tv')); - $this->element('link', array('rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION, - 'media' => 'screen, projection, tv')); - $this->comment('[if IE]>comment('[if lte IE '.$ver.']>element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION, + 'media' => 'screen, projection, tv')); + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION, + 'media' => 'screen, projection, tv')); + Event::handle('EndShowLaconicaStyles', array($this)); } + if (Event::handle('StartShowUAStyles', array($this))) { + $this->comment('[if IE]>comment('[if lte IE '.$ver.']>comment('[if IE]>comment('[if IE]> Date: Fri, 13 Feb 2009 05:42:00 +0000 Subject: We have a FacebookQueueHandler now. The update_facebook.php cron script is totally deprecated. --- lib/facebookutil.php | 96 +++++++++++++++++++++++++++++- lib/util.php | 4 +- scripts/startdaemons.sh | 2 +- scripts/stopdaemons.sh | 2 +- scripts/update_facebook.php | 141 -------------------------------------------- 5 files changed, 100 insertions(+), 145 deletions(-) delete mode 100755 scripts/update_facebook.php (limited to 'lib') diff --git a/lib/facebookutil.php b/lib/facebookutil.php index beab51366..e2ad20d19 100644 --- a/lib/facebookutil.php +++ b/lib/facebookutil.php @@ -36,7 +36,7 @@ function getFacebookNotices($since) // XXX: What should the limit be? //static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) { - + return Notice::getStreamDirect($qry, 0, 1000, 0, 0, null, $since); } @@ -52,3 +52,97 @@ function updateProfileBox($facebook, $flink, $notice) { $fbaction->updateProfileBox($notice); } +function isFacebookBound($notice, $flink) { + + // If the user does not want to broadcast to Facebook, move along + if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) { + common_log(LOG_INFO, "Skipping notice $notice->id " . + 'because user has FOREIGN_NOTICE_SEND bit off.'); + return false; + } + + $success = false; + + // If it's not a reply, or if the user WANTS to send @-replies... + if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || + ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) { + + $success = true; + + // The two condition below are deal breakers: + + // Avoid a loop + if ($notice->source == 'Facebook') { + common_log(LOG_INFO, "Skipping notice $notice->id because its " . + 'source is Facebook.'); + $success = false; + } + + $facebook = getFacebook(); + $fbuid = $flink->foreign_id; + + try { + + // Check to see if the user has given the FB app status update perms + $result = $facebook->api_client-> + users_hasAppPermission('status_update', $fbuid); + + if ($result != 1) { + $user = $flink->getUser(); + $msg = "Can't send notice $notice->id to Facebook " . + "because user $user->nickname hasn't given the " . + 'Facebook app \'status_update\' permission.'; + common_log(LOG_INFO, $msg); + $success = false; + } + + } catch(FacebookRestClientException $e){ + common_log(LOG_ERROR, $e->getMessage()); + $success = false; + } + + } + + return $success; + +} + + +function facebookBroadcastNotice($notice) +{ + $facebook = getFacebook(); + $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); + $fbuid = $flink->foreign_id; + + if (isFacebookBound($notice, $flink)) { + + $status = null; + + // Get the status 'verb' (prefix) the user has set + try { + $prefix = $facebook->api_client-> + data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid); + + $status = "$prefix $notice->content"; + + } catch(FacebookRestClientException $e) { + common_log(LOG_ERROR, $e->getMessage()); + return false; + } + + // Okay, we're good to go! + + try { + $facebook->api_client->users_setStatus($status, $fbuid, false, true); + updateProfileBox($facebook, $flink, $notice); + } catch(FacebookRestClientException $e) { + common_log(LOG_ERROR, $e->getMessage()); + return false; + + // Should we remove flink if this fails? + } + + } + + return true; +} diff --git a/lib/util.php b/lib/util.php index 031fd0da0..3eeb9fde3 100644 --- a/lib/util.php +++ b/lib/util.php @@ -837,7 +837,7 @@ function common_broadcast_notice($notice, $remote=false) function common_enqueue_notice($notice) { - foreach (array('jabber', 'omb', 'sms', 'public', 'twitter') as $transport) { + foreach (array('jabber', 'omb', 'sms', 'public', 'twitter', 'facebook') as $transport) { $qi = new Queue_item(); $qi->notice_id = $notice->id; $qi->transport = $transport; @@ -891,6 +891,8 @@ function common_real_broadcast($notice, $remote=false) } } + // XXX: Do a real-time FB broadcast here? + // XXX: broadcast notices to other IM return $success; } diff --git a/scripts/startdaemons.sh b/scripts/startdaemons.sh index 269036393..a3256966d 100755 --- a/scripts/startdaemons.sh +++ b/scripts/startdaemons.sh @@ -24,7 +24,7 @@ DIR=`dirname $0` for f in xmppdaemon.php jabberqueuehandler.php publicqueuehandler.php \ xmppconfirmhandler.php smsqueuehandler.php ombqueuehandler.php \ - twitterqueuehandler.php; do + twitterqueuehandler.php facebookqueuehandler.php; do echo -n "Starting $f..."; php $DIR/$f diff --git a/scripts/stopdaemons.sh b/scripts/stopdaemons.sh index b69d296d3..fd4406d41 100755 --- a/scripts/stopdaemons.sh +++ b/scripts/stopdaemons.sh @@ -24,7 +24,7 @@ SDIR=`dirname $0` DIR=`php $SDIR/getpiddir.php` for f in jabberhandler ombhandler publichandler smshandler \ - xmppconfirmhandler xmppdaemon twitterhandler ; do + xmppconfirmhandler xmppdaemon twitterhandler facebookhandler ; do FILES="$DIR/$f.*.pid" for ff in "$FILES" ; do diff --git a/scripts/update_facebook.php b/scripts/update_facebook.php deleted file mode 100755 index 60e10417f..000000000 --- a/scripts/update_facebook.php +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env php -. - */ - -# Abort if called from a web server -if (isset($_SERVER) && array_key_exists('REQUEST_METHOD', $_SERVER)) { - print "This script must be run from the command line\n"; - exit(); -} - -define('INSTALLDIR', realpath(dirname(__FILE__) . '/..')); -define('LACONICA', true); - -require_once INSTALLDIR . '/lib/common.php'; -require_once INSTALLDIR . '/lib/facebookutil.php'; - -// For storing the last run date-time -$last_updated_file = INSTALLDIR . '/scripts/facebook_last_updated'; - -// Lock file name -$lock_file = INSTALLDIR . '/scripts/update_facebook.lock'; - -// Make sure only one copy of the script is running at a time -$lock_file = @fopen($lock_file, "w+"); -if (!flock( $lock_file, LOCK_EX | LOCK_NB, &$wouldblock) || $wouldblock) { - die("Can't open lock file. Script already running?\n"); -} - -$facebook = getFacebook(); -$current_time = time(); -$since = getLastUpdated(); -updateLastUpdated($current_time); -$notice = getFacebookNotices($since); -$cnt = 0; - -while($notice->fetch()) { - - $flink = Foreign_link::getByUserID($notice->profile_id, FACEBOOK_SERVICE); - $user = $flink->getUser(); - $fbuid = $flink->foreign_id; - - if (!userCanUpdate($fbuid)) { - continue; - } - - $prefix = $facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid); - $content = "$prefix $notice->content"; - - if (($flink->noticesync & FOREIGN_NOTICE_SEND) == FOREIGN_NOTICE_SEND) { - - // If it's not a reply, or if the user WANTS to send replies... - if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $content) || - (($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) == FOREIGN_NOTICE_SEND_REPLY)) { - - // Avoid a Loop - if ($notice->source != 'Facebook') { - - try { - $facebook->api_client->users_setStatus($content, - $fbuid, false, true); - updateProfileBox($facebook, $flink, $notice); - $cnt++; - } catch(FacebookRestClientException $e) { - print "Couldn't sent notice $notice->id!\n"; - print $e->getMessage(); - - // Remove flink? - } - } - } - } -} - -if ($cnt > 0) { - print date('r', $current_time) . - ": Found $cnt new notices for Facebook since last run at " . - date('r', $since) . "\n"; -} - -fclose($lock_file); -exit(0); - - -function userCanUpdate($fbuid) { - - global $facebook; - - $result = false; - - try { - $result = $facebook->api_client->users_hasAppPermission('status_update', $fbuid); - } catch(FacebookRestClientException $e){ - print_r($e); - } - - return $result; -} - -function getLastUpdated(){ - global $last_updated_file, $current_time; - $last = $current_time; - - if (file_exists($last_updated_file) && - ($file = fopen($last_updated_file, 'r'))) { - $last = fgets($file); - } else { - print "$last_updated_file doesn't exit. Trying to create it...\n"; - $file = fopen($last_updated_file, 'w+') or - die("Can't open $last_updated_file for writing!\n"); - print 'Success. Using current time (' . date('r', $last) . - ") to look for new notices.\n"; - } - - fclose($file); - return $last; -} - -function updateLastUpdated($time){ - global $last_updated_file; - $file = fopen($last_updated_file, 'w') or - die("Can't open $last_updated_file for writing!"); - fwrite($file, $time); - fclose($file); -} - -- cgit v1.2.3-54-g00ecf From 47c5d508b36d4351f2bd94e7b36738fdf040b0aa Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 13 Feb 2009 10:47:22 -0500 Subject: remove debugging info from local_url --- lib/util.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 3eeb9fde3..b065c2d74 100644 --- a/lib/util.php +++ b/lib/util.php @@ -701,12 +701,8 @@ function common_relative_profile($sender, $nickname, $dt=null) function common_local_url($action, $args=null, $fragment=null) { - common_debug("Action = $action, args = " . (($args) ? '(' . implode($args, ',') . ')' : $args) . ", fragment = $fragment"); $r = Router::get(); - $start = microtime(); $path = $r->build($action, $args, $fragment); - $end = microtime(); - common_debug("Pathbuilding took " . ($end - $start)); if ($path) { } if (common_config('site','fancy')) { @@ -890,9 +886,9 @@ function common_real_broadcast($notice, $remote=false) common_log(LOG_ERR, 'Error in Twitter broadcast for notice ' . $notice->id); } } - - // XXX: Do a real-time FB broadcast here? - + + // XXX: Do a real-time FB broadcast here? + // XXX: broadcast notices to other IM return $success; } -- cgit v1.2.3-54-g00ecf From 02184df7c8fd40ee9d1b134fd318e0c6f444ae01 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 13 Feb 2009 10:08:11 -0800 Subject: Fixed arguments to syslog (LOG_ERR, not LOG_ERROR) and removed unused function --- lib/facebookutil.php | 21 +++------------------ lib/jabber.php | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) (limited to 'lib') diff --git a/lib/facebookutil.php b/lib/facebookutil.php index e2ad20d19..ec3987273 100644 --- a/lib/facebookutil.php +++ b/lib/facebookutil.php @@ -25,21 +25,6 @@ define("FACEBOOK_SERVICE", 2); // Facebook is foreign_service ID 2 define("FACEBOOK_NOTICE_PREFIX", 1); define("FACEBOOK_PROMPTED_UPDATE_PREF", 2); -// Gets all the notices from users with a Facebook link since a given ID -function getFacebookNotices($since) -{ - $qry = 'SELECT notice.* ' . - 'FROM notice ' . - 'JOIN foreign_link ' . - 'WHERE notice.profile_id = foreign_link.user_id ' . - 'AND foreign_link.service = 2'; - - // XXX: What should the limit be? - //static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) { - - return Notice::getStreamDirect($qry, 0, 1000, 0, 0, null, $since); -} - function getFacebook() { $apikey = common_config('facebook', 'apikey'); @@ -97,7 +82,7 @@ function isFacebookBound($notice, $flink) { } } catch(FacebookRestClientException $e){ - common_log(LOG_ERROR, $e->getMessage()); + common_log(LOG_ERR, $e->getMessage()); $success = false; } @@ -126,7 +111,7 @@ function facebookBroadcastNotice($notice) $status = "$prefix $notice->content"; } catch(FacebookRestClientException $e) { - common_log(LOG_ERROR, $e->getMessage()); + common_log(LOG_ERR, $e->getMessage()); return false; } @@ -136,7 +121,7 @@ function facebookBroadcastNotice($notice) $facebook->api_client->users_setStatus($status, $fbuid, false, true); updateProfileBox($facebook, $flink, $notice); } catch(FacebookRestClientException $e) { - common_log(LOG_ERROR, $e->getMessage()); + common_log(LOG_ERR, $e->getMessage()); return false; // Should we remove flink if this fails? diff --git a/lib/jabber.php b/lib/jabber.php index b385d3c5c..3fbb3e1ab 100644 --- a/lib/jabber.php +++ b/lib/jabber.php @@ -114,7 +114,7 @@ function jabber_connect($resource=null) try { $conn->connect(true); // true = persistent connection } catch (XMPPHP_Exception $e) { - common_log(LOG_ERROR, $e->getMessage()); + common_log(LOG_ERR, $e->getMessage()); return false; } -- cgit v1.2.3-54-g00ecf From b9fc7334a8ecfbe1c0ec6c3d5451aa82827b50a1 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 14 Feb 2009 17:48:08 -0500 Subject: Fix the More... link for popular notices section --- lib/popularnoticesection.php | 5 +++++ lib/section.php | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index 5734d8001..5380563b9 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -80,4 +80,9 @@ class PopularNoticeSection extends NoticeSection { return 'popular_notices'; } + + function moreUrl() + { + return common_local_url('favorited'); + } } diff --git a/lib/section.php b/lib/section.php index 0c32ddcf8..d14575086 100644 --- a/lib/section.php +++ b/lib/section.php @@ -103,6 +103,6 @@ class Section extends Widget function moreTitle() { - return null; + return _('More...'); } } -- cgit v1.2.3-54-g00ecf From 3db9c134a052b906c8c9cff946e63ee28457ce1b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 14 Feb 2009 17:53:11 -0500 Subject: Fix More... URL for featured user section --- lib/featureduserssection.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/featureduserssection.php b/lib/featureduserssection.php index 2935d8363..aed94b1a5 100644 --- a/lib/featureduserssection.php +++ b/lib/featureduserssection.php @@ -86,4 +86,9 @@ class FeaturedUsersSection extends ProfileSection { return 'featured_users'; } + + function moreUrl() + { + return common_local_url('featured'); + } } -- cgit v1.2.3-54-g00ecf From da2348fbbe27facf4cfbf3fad800b3ccf98b4136 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 14 Feb 2009 21:55:25 -0500 Subject: Optionally ignore some notice sources for public page We optionally ignore some notice sources from the public page. Typically these are automatic notice sources like twitterfeed that don't usually represent the community on the site very well. --- classes/Notice.php | 4 +++- config.php.sample | 8 ++++++++ lib/common.php | 3 ++- 3 files changed, 13 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index 6db59c96e..b8cd2bd7f 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -136,10 +136,12 @@ class Notice extends Memcached_DataObject $notice->profile_id = $profile_id; $blacklist = common_config('public', 'blacklist'); + $autosource = common_config('public', 'autosource'); # Blacklisted are non-false, but not 1, either - if ($blacklist && in_array($profile_id, $blacklist)) { + if (($blacklist && in_array($profile_id, $blacklist)) || + ($source && $autosource && in_array($source, $autosource))) { $notice->is_local = -1; } else { $notice->is_local = $is_local; diff --git a/config.php.sample b/config.php.sample index a2c5801f4..3fa898e1b 100644 --- a/config.php.sample +++ b/config.php.sample @@ -107,6 +107,14 @@ $config['sphinx']['port'] = 3312; #$config['public']['blacklist'][] = 123; #$config['public']['blacklist'][] = 2307; +#Mark certain notice sources as automatic and thus not +#appropriate for public feed +#$config['public]['autosource'][] = 'twitterfeed'; +#$config['public]['autosource'][] = 'rssdent'; +#$config['public]['autosource'][] = 'Ping.Fm'; +#$config['public]['autosource'][] = 'HelloTxt'; +#$config['public]['autosource'][] = 'Updating.Me'; + #Do notice broadcasts offline #If you use this, you must run the six offline daemons in the #background. See the README for details. diff --git a/lib/common.php b/lib/common.php index 7bfd14c42..4fc749ca0 100644 --- a/lib/common.php +++ b/lib/common.php @@ -106,7 +106,8 @@ $config = array('server' => null), 'public' => array('localonly' => true, - 'blacklist' => array()), + 'blacklist' => array(), + 'autosource' => array()), 'theme' => array('server' => null), 'throttle' => -- cgit v1.2.3-54-g00ecf From 9d81cef5cc2a0a197a0223206ba3d9a687065886 Mon Sep 17 00:00:00 2001 From: Meitar Moscovitz Date: Mon, 16 Feb 2009 15:45:18 +1100 Subject: Add framebusting JavaScript to help avoid clickjacking attacks. --- lib/action.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index cd0db5399..48d5821a1 100644 --- a/lib/action.php +++ b/lib/action.php @@ -205,6 +205,9 @@ class Action extends HTMLOutputter // lawsuit $this->element('script', array('type' => 'text/javascript', 'src' => common_path('js/util.js?version='.LACONICA_VERSION)), ' '); + // Frame-busting code to avoid clickjacking attacks. + $this->element('script', array('type' => 'text/javascript'), + 'if (window.top !== window.self) { window.top.location.href = window.self.location.href; }'); Event::handle('EndShowLaconicaScripts', array($this)); } Event::handle('EndShowScripts', array($this)); -- cgit v1.2.3-54-g00ecf From 9c9b6790ce78296c0b182f03b5f6f2c035e43a7c Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 16 Feb 2009 17:46:24 +0000 Subject: trac #201 Add flowplayer to enable multimedia playback capability. --- bin/flowplayer-3.0.5.swf | Bin 0 -> 92317 bytes bin/flowplayer.audio-3.0.3.swf | Bin 0 -> 2756 bytes bin/flowplayer.controls-3.0.3.swf | Bin 0 -> 15977 bytes js/flowplayer-3.0.5.min.js | 24 ++++++++++++++++++++++++ js/jquery.simplemodal-1.2.2.pack.js | 8 ++++++++ js/video.js | 9 +++++++++ lib/action.php | 26 ++++++++++++++++++++++++++ lib/util.php | 6 ++++++ theme/base/css/modal.css | 22 ++++++++++++++++++++++ theme/base/css/modal_ie.css | 16 ++++++++++++++++ theme/base/images/x.png | Bin 0 -> 1066 bytes 11 files changed, 111 insertions(+) create mode 100644 bin/flowplayer-3.0.5.swf create mode 100644 bin/flowplayer.audio-3.0.3.swf create mode 100644 bin/flowplayer.controls-3.0.3.swf create mode 100644 js/flowplayer-3.0.5.min.js create mode 100644 js/jquery.simplemodal-1.2.2.pack.js create mode 100644 js/video.js create mode 100644 theme/base/css/modal.css create mode 100644 theme/base/css/modal_ie.css create mode 100644 theme/base/images/x.png (limited to 'lib') diff --git a/bin/flowplayer-3.0.5.swf b/bin/flowplayer-3.0.5.swf new file mode 100644 index 000000000..05b64a032 Binary files /dev/null and b/bin/flowplayer-3.0.5.swf differ diff --git a/bin/flowplayer.audio-3.0.3.swf b/bin/flowplayer.audio-3.0.3.swf new file mode 100644 index 000000000..ef85f1bff Binary files /dev/null and b/bin/flowplayer.audio-3.0.3.swf differ diff --git a/bin/flowplayer.controls-3.0.3.swf b/bin/flowplayer.controls-3.0.3.swf new file mode 100644 index 000000000..09a27e8a9 Binary files /dev/null and b/bin/flowplayer.controls-3.0.3.swf differ diff --git a/js/flowplayer-3.0.5.min.js b/js/flowplayer-3.0.5.min.js new file mode 100644 index 000000000..b1c33150a --- /dev/null +++ b/js/flowplayer-3.0.5.min.js @@ -0,0 +1,24 @@ +/** + * flowplayer.js 3.0.5. The Flowplayer API + * + * Copyright 2009 Flowplayer Oy + * + * This file is part of Flowplayer. + * + * Flowplayer is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Flowplayer is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Flowplayer. If not, see . + * + * Version: 3.0.5 - Tue Feb 03 2009 13:14:17 GMT-0000 (GMT+00:00) + */ +(function(){function log(args){console.log("$f.fireEvent",[].slice.call(args));}function clone(obj){if(!obj||typeof obj!='object'){return obj;}var temp=new obj.constructor();for(var key in obj){if(obj.hasOwnProperty(key)){temp[key]=clone(obj[key]);}}return temp;}function each(obj,fn){if(!obj){return;}var name,i=0,length=obj.length;if(length===undefined){for(name in obj){if(fn.call(obj[name],name,obj[name])===false){break;}}}else{for(var value=obj[0];i1){var swf=arguments[1];var conf=(arguments.length==3)?arguments[2]:{};if(typeof arg=='string'){if(arg.indexOf(".")!=-1){var instances=[];each(select(arg),function(){instances.push(new Player(this,clone(swf),clone(conf)));});return new Iterator(instances);}else{var node=el(arg);return new Player(node!==null?node:arg,swf,conf);}}else if(arg){return new Player(arg,swf,conf);}}return null;};extend(window.$f,{fireEvent:function(id,evt,a0,a1,a2){var p=$f(id);return p?p._fireEvent(evt,a0,a1,a2):null;},addPlugin:function(name,fn){Player.prototype[name]=fn;return $f;},each:each,extend:extend});if(document.all){window.onbeforeunload=function(){$f("*").each(function(){if(this.isLoaded()){this.close();}});};}if(typeof jQuery=='function'){jQuery.prototype.flowplayer=function(params,conf){if(!arguments.length||typeof arguments[0]=='number'){var arr=[];this.each(function(){var p=$f(this);if(p){arr.push(p);}});return arguments.length?arr[arguments[0]]:new Iterator(arr);}return this.each(function(){$f(this,clone(params),conf?clone(conf):{});});};}})();(function(){var jQ=typeof jQuery=='function';function isDomReady(){if(domReady.done){return false;}var d=document;if(d&&d.getElementsByTagName&&d.getElementById&&d.body){clearInterval(domReady.timer);domReady.timer=null;for(var i=0;i';}var e=extend({},p);e.width=e.height=e.id=e.w3c=e.src=null;for(var k in e){if(e[k]!==null){html+='';}}var vars="";if(c){for(var key in c){if(c[key]!==null){vars+=key+'='+(typeof c[key]=='object'?asString(c[key]):c[key])+'&';}}vars=vars.substring(0,vars.length-1);html+='';}html+="";return html;}function Flash(root,opts,flashvars){var version=flashembed.getVersion();extend(this,{getContainer:function(){return root;},getConf:function(){return conf;},getVersion:function(){return version;},getFlashvars:function(){return flashvars;},getApi:function(){return root.firstChild;},getHTML:function(){return getHTML(opts,flashvars);}});var required=opts.version;var express=opts.expressInstall;var ok=!required||flashembed.isSupported(required);if(ok){opts.onFail=opts.version=opts.expressInstall=null;root.innerHTML=getHTML(opts,flashvars);}else if(required&&express&&flashembed.isSupported([6,65])){extend(opts,{src:express});flashvars={MMredirectURL:location.href,MMplayerType:'PlugIn',MMdoctitle:document.title};root.innerHTML=getHTML(opts,flashvars);}else{if(root.innerHTML.replace(/\s/g,'')!==''){}else{root.innerHTML="

Flash version "+required+" or greater is required

"+"

"+(version[0]>0?"Your version is "+version:"You have no flash plugin installed")+"

"+"

Download latest version from here

";}}if(!ok&&opts.onFail){var ret=opts.onFail.call(this);if(typeof ret=='string'){root.innerHTML=ret;}}}window.flashembed=function(root,conf,flashvars){if(typeof root=='string'){var el=document.getElementById(root);if(el){root=el;}else{domReady(function(){flashembed(root,conf,flashvars);});return;}}if(!root){return;}var opts={width:'100%',height:'100%',allowfullscreen:true,allowscriptaccess:'always',quality:'high',version:null,onFail:null,expressInstall:null,w3c:false};if(typeof conf=='string'){conf={src:conf};}extend(opts,conf);return new Flash(root,opts,flashvars);};extend(window.flashembed,{getVersion:function(){var version=[0,0];if(navigator.plugins&&typeof navigator.plugins["Shockwave Flash"]=="object"){var _d=navigator.plugins["Shockwave Flash"].description;if(typeof _d!="undefined"){_d=_d.replace(/^.*\s+(\S+\s+\S+$)/,"$1");var _m=parseInt(_d.replace(/^(.*)\..*$/,"$1"),10);var _r=/r/.test(_d)?parseInt(_d.replace(/^.*r(.*)$/,"$1"),10):0;version=[_m,_r];}}else if(window.ActiveXObject){try{var _a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.7");}catch(e){try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash.6");version=[6,0];_a.AllowScriptAccess="always";}catch(ee){if(version[0]==6){return;}}try{_a=new ActiveXObject("ShockwaveFlash.ShockwaveFlash");}catch(eee){}}if(typeof _a=="object"){_d=_a.GetVariable("$version");if(typeof _d!="undefined"){_d=_d.replace(/^\S+\s+(.*)$/,"$1").split(",");version=[parseInt(_d[0],10),parseInt(_d[2],10)];}}}return version;},isSupported:function(version){var now=flashembed.getVersion();var ret=(now[0]>version[0])||(now[0]==version[0]&&now[1]>=version[1]);return ret;},domReady:domReady,asString:asString,getHTML:getHTML});if(jQ){jQuery.prototype.flashembed=function(conf,flashvars){return this.each(function(){flashembed(this,conf,flashvars);});};}})(); \ No newline at end of file diff --git a/js/jquery.simplemodal-1.2.2.pack.js b/js/jquery.simplemodal-1.2.2.pack.js new file mode 100644 index 000000000..b5ad5c23a --- /dev/null +++ b/js/jquery.simplemodal-1.2.2.pack.js @@ -0,0 +1,8 @@ +/* + * SimpleModal 1.2.2 - jQuery Plugin + * http://www.ericmmartin.com/projects/simplemodal/ + * Copyright (c) 2008 Eric Martin + * Dual licensed under the MIT and GPL licenses + * Revision: $Id: jquery.simplemodal.js 181 2008-12-16 16:51:44Z emartin24 $ + */ +eval(function(p,a,c,k,e,r){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(g($){m f=$.Q.1Q&&1a($.Q.1D)==6&&!10[\'2g\'],1f=$.Q.1Q&&!$.2a,w=[];$.y=g(a,b){I $.y.12.1n(a,b)};$.y.D=g(){$.y.12.D()};$.1P.y=g(a){I $.y.12.1n(3,a)};$.y.1O={V:29,1J:\'r-H\',1B:{},1z:\'r-n\',20:{},1Z:{},v:2t,D:1o,1T:\'\',X:\'r-D\',l:F,1g:K,1e:F,1d:F,1c:F};$.y.12={7:F,4:{},1n:g(a,b){8(3.4.j){I K}3.7=$.U({},$.y.1O,b);3.v=3.7.v;3.1w=K;8(J a==\'27\'){a=a 25 1A?a:$(a);8(a.1v().1v().23()>0){3.4.T=a.1v();8(!3.7.1g){3.4.21=a.2x(1o)}}}q 8(J a==\'2w\'||J a==\'1r\'){a=$(\'<1q/>\').2s(a)}q{2r(\'2q 2p: 2o j 2l: \'+J a);I K}3.4.j=a.11(\'r-j\').E(3.7.1Z);a=F;3.1S();3.1R();8($.1m(3.7.1d)){3.7.1d.1l(3,[3.4])}I 3},1S:g(){w=3.1k();8(f){3.4.x=$(\'\').E($.U(3.7.2b,{1j:\'1i\',V:0,l:\'1h\',A:w[0],z:w[1],v:3.7.v,L:0,B:0})).O(\'u\')}3.4.H=$(\'<1q/>\').1N(\'1M\',3.7.1J).11(\'r-H\').E($.U(3.7.1B,{1j:\'1i\',V:3.7.V/1b,A:w[0],z:w[1],l:\'1h\',B:0,L:0,v:3.7.v+1})).O(\'u\');3.4.n=$(\'<1q/>\').1N(\'1M\',3.7.1z).11(\'r-n\').E($.U(3.7.20,{1j:\'1i\',l:\'1h\',v:3.7.v+2})).1K(3.7.D?$(3.7.1T).11(3.7.X):\'\').O(\'u\');3.19();8(f||1f){3.18()}3.4.n.1K(3.4.j.1I())},1H:g(){m a=3;$(\'.\'+3.7.X).1G(\'1L.r\',g(e){e.28();a.D()});$(10).1G(\'1F.r\',g(){w=a.1k();a.19();8(f||1f){a.18()}q{a.4.x&&a.4.x.E({A:w[0],z:w[1]});a.4.H.E({A:w[0],z:w[1]})}})},1E:g(){$(\'.\'+3.7.X).1C(\'1L.r\');$(10).1C(\'1F.r\')},18:g(){m p=3.7.l;$.26([3.4.x||F,3.4.H,3.4.n],g(i,e){8(e){m a=\'k.u.17\',N=\'k.u.1W\',16=\'k.u.24\',S=\'k.u.1y\',R=\'k.u.1x\',15=\'k.u.22\',1t=\'k.P.17\',1s=\'k.P.1W\',C=\'k.P.1y\',G=\'k.P.1x\',s=e[0].2v;s.l=\'2u\';8(i<2){s.14(\'A\');s.14(\'z\');s.Z(\'A\',\'\'+16+\' > \'+a+\' ? \'+16+\' : \'+a+\' + "o"\');s.Z(\'z\',\'\'+15+\' > \'+N+\' ? \'+15+\' : \'+N+\' + "o"\')}q{m b,W;8(p&&p.1Y==1X){8(p[0]){m c=J p[0]==\'1r\'?p[0].1V():p[0].13(/o/,\'\');b=c.1U(\'%\')==-1?c+\' + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\':1a(c.13(/%/,\'\'))+\' * ((\'+1t+\' || \'+a+\') / 1b) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\'}8(p[1]){m d=J p[1]==\'1r\'?p[1].1V():p[1].13(/o/,\'\');W=d.1U(\'%\')==-1?d+\' + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\':1a(d.13(/%/,\'\'))+\' * ((\'+1s+\' || \'+N+\') / 1b) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}}q{b=\'(\'+1t+\' || \'+a+\') / 2 - (3.2n / 2) + (t = \'+G+\' ? \'+G+\' : \'+R+\') + "o"\';W=\'(\'+1s+\' || \'+N+\') / 2 - (3.2m / 2) + (t = \'+C+\' ? \'+C+\' : \'+S+\') + "o"\'}s.14(\'L\');s.14(\'B\');s.Z(\'L\',b);s.Z(\'B\',W)}}})},1k:g(){m a=$(10);m h=$.Q.2k&&$.Q.1D>\'9.5\'&&$.1P.2i<=\'1.2.6\'?k.P[\'17\']:a.A();I[h,a.z()]},19:g(){m a,B,1u=(w[0]/2)-((3.4.n.A()||3.4.j.A())/2),1p=(w[1]/2)-((3.4.n.z()||3.4.j.z())/2);8(3.7.l&&3.7.l.1Y==1X){a=3.7.l[0]||1u;B=3.7.l[1]||1p}q{a=1u;B=1p}3.4.n.E({B:B,L:a})},1R:g(){3.4.x&&3.4.x.Y();8($.1m(3.7.1e)){3.7.1e.1l(3,[3.4])}q{3.4.H.Y();3.4.n.Y();3.4.j.Y()}3.1H()},D:g(){8(!3.4.j){I K}8($.1m(3.7.1c)&&!3.1w){3.1w=1o;3.7.1c.1l(3,[3.4])}q{8(3.4.T){8(3.7.1g){3.4.j.1I().O(3.4.T)}q{3.4.j.M();3.4.21.O(3.4.T)}}q{3.4.j.M()}3.4.n.M();3.4.H.M();3.4.x&&3.4.x.M();3.4={}}3.1E()}}})(1A);',62,158,'|||this|dialog|||opts|if||||||||function|||data|document|position|var|container|px||else|simplemodal|||body|zIndex||iframe|modal|width|height|left|sl|close|css|null|st|overlay|return|typeof|false|top|remove|bcw|appendTo|documentElement|browser|bst|bsl|parentNode|extend|opacity|le|closeClass|show|setExpression|window|addClass|impl|replace|removeExpression|bsw|bsh|clientHeight|fixIE|setPosition|parseInt|100|onClose|onShow|onOpen|ieQuirks|persist|fixed|none|display|getDimensions|apply|isFunction|init|true|vCenter|div|number|cw|ch|hCenter|parent|occb|scrollTop|scrollLeft|containerId|jQuery|overlayCss|unbind|version|unbindEvents|resize|bind|bindEvents|hide|overlayId|append|click|id|attr|defaults|fn|msie|open|create|closeHTML|indexOf|toString|clientWidth|Array|constructor|dataCss|containerCss|orig|scrollWidth|size|scrollHeight|instanceof|each|object|preventDefault|50|boxModel|iframeCss|javascript|src|Close|title|XMLHttpRequest|modalCloseImg|jquery|class|opera|type|offsetWidth|offsetHeight|Unsupported|Error|SimpleModal|alert|html|1000|absolute|style|string|clone'.split('|'),0,{})) \ No newline at end of file diff --git a/js/video.js b/js/video.js new file mode 100644 index 000000000..936a6312e --- /dev/null +++ b/js/video.js @@ -0,0 +1,9 @@ +$('document').ready(function() { + $('a.media, a.mediamp3').append(' [PLAY]'); + $('a.mediamp3').html('').css('display', 'block').css('width', '224px').css('height','24px').flowplayer('../bin/flowplayer-3.0.5.swf'); + $('a.media').click(function() { + $('').attr('href', $(this).attr('href')).flowplayer('../bin/flowplayer-3.0.5.swf').modal({'closeHTML':''}); + return false; + }); +}); + diff --git a/lib/action.php b/lib/action.php index cd0db5399..79e8c9547 100644 --- a/lib/action.php +++ b/lib/action.php @@ -153,10 +153,17 @@ class Action extends HTMLOutputter // lawsuit { if (Event::handle('StartShowStyles', array($this))) { if (Event::handle('StartShowLaconicaStyles', array($this))) { + $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', 'base') . '?version=' . LACONICA_VERSION, 'media' => 'screen, projection, tv')); + + + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/modal.css', 'base') . '?version=' . LACONICA_VERSION, + 'media' => 'screen, projection, tv')); $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', null) . '?version=' . LACONICA_VERSION, @@ -196,6 +203,13 @@ class Action extends HTMLOutputter // lawsuit $this->element('script', array('type' => 'text/javascript', 'src' => common_path('js/jquery.form.js')), ' '); + + + $this->element('script', array('type' => 'text/javascript', + 'src' => common_path('js/jquery.simplemodal-1.2.2.pack.js')), + ' '); + + Event::handle('EndShowJQueryScripts', array($this)); } if (Event::handle('StartShowLaconicaScripts', array($this))) { @@ -205,6 +219,18 @@ class Action extends HTMLOutputter // lawsuit $this->element('script', array('type' => 'text/javascript', 'src' => common_path('js/util.js?version='.LACONICA_VERSION)), ' '); + + + $this->element('script', array('type' => 'text/javascript', + 'src' => common_path('js/flowplayer-3.0.5.min.js')), + ' '); + + $this->element('script', array('type' => 'text/javascript', + 'src' => common_path('js/video.js')), + ' '); + + + Event::handle('EndShowLaconicaScripts', array($this)); } Event::handle('EndShowScripts', array($this)); diff --git a/lib/util.php b/lib/util.php index b065c2d74..094b2750c 100644 --- a/lib/util.php +++ b/lib/util.php @@ -474,11 +474,17 @@ function common_replace_urls_callback($text, $callback) { function common_linkify($url) { // It comes in special'd, so we unspecial it before passing to the stringifying // functions + $ext = pathinfo($url, PATHINFO_EXTENSION); $url = htmlspecialchars_decode($url); + $video_ext = array('mp4', 'flv', 'avi', 'mpg', 'mp3', 'ogg'); $display = $url; $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url; $attrs = array('href' => $url, 'rel' => 'external'); + + if (in_array($ext, $video_ext)) { + $attrs['class'] = 'media'; + } if ($longurl = common_longurl($url)) { $attrs['title'] = $longurl; diff --git a/theme/base/css/modal.css b/theme/base/css/modal.css new file mode 100644 index 000000000..985e4adfa --- /dev/null +++ b/theme/base/css/modal.css @@ -0,0 +1,22 @@ +/* + * SimpleModal Basic Modal Dialog + * http://www.ericmmartin.com/projects/simplemodal/ + * http://code.google.com/p/simplemodal/ + * + * Copyright (c) 2008 Eric Martin - http://ericmmartin.com + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Revision: $Id: basic.css 162 2008-12-01 23:36:58Z emartin24 $ + * + */ + + +/* Overlay */ +#simplemodal-overlay {background-color:#000; cursor:wait;} + +/* Container */ +#simplemodal-container {height:240px; width:320px; background-color:#fff; border:3px solid #ccc;} +#simplemodal-container a.modalCloseImg {background:url(../images/x.png) no-repeat; width:25px; height:29px; display:inline; z-index:3200; position:absolute; top:-15px; right:-18px; cursor:pointer;} +#simplemodal-container #basicModalContent {padding:8px;} diff --git a/theme/base/css/modal_ie.css b/theme/base/css/modal_ie.css new file mode 100644 index 000000000..eab4637c0 --- /dev/null +++ b/theme/base/css/modal_ie.css @@ -0,0 +1,16 @@ +/* + * SimpleModal Basic Modal Dialog + * http://www.ericmmartin.com/projects/simplemodal/ + * http://code.google.com/p/simplemodal/ + * + * Copyright (c) 2008 Eric Martin - http://ericmmartin.com + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/mit-license.php + * + * Revision: $Id: basic_ie.css 162 2008-12-01 23:36:58Z emartin24 $ + * + */ + +/* IE 6 hacks*/ +#simplemodal-container a.modalCloseImg {background:none; right:-14px; width:22px; height:26px; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='../images/x.png',sizingMethod='scale');} diff --git a/theme/base/images/x.png b/theme/base/images/x.png new file mode 100644 index 000000000..c11f7af69 Binary files /dev/null and b/theme/base/images/x.png differ -- cgit v1.2.3-54-g00ecf From c8e71d359cee093dcb15c1d32684d90f81e10204 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 16 Feb 2009 18:02:04 -0500 Subject: error in hashtag link generation --- lib/util.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 094b2750c..46aa7b9df 100644 --- a/lib/util.php +++ b/lib/util.php @@ -481,7 +481,7 @@ function common_linkify($url) { $url = (!preg_match('#^([a-z]+://|(mailto|aim|tel):)#i', $url)) ? 'http://'.$url : $url; $attrs = array('href' => $url, 'rel' => 'external'); - + if (in_array($ext, $video_ext)) { $attrs['class'] = 'media'; } @@ -596,7 +596,7 @@ function common_tag_link($tag) $xs->element('a', array('href' => $url, 'rel' => 'tag'), $tag); - $xs->elementEnd(); + $xs->elementEnd('span'); return $xs->getString(); } -- cgit v1.2.3-54-g00ecf From 175c4665cc33c07bbbc42bbf96dd07cf90ba7bbb Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Mon, 16 Feb 2009 18:26:15 -0500 Subject: send mail when @-replies are received --- classes/Notice.php | 32 +++++++++++++++++++++----------- lib/mail.php | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/classes/Notice.php b/classes/Notice.php index 8e08ad503..570d76f61 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -34,22 +34,23 @@ class Notice extends Memcached_DataObject ###START_AUTOCODE /* the code below is auto generated do not remove the above tag */ - public $__table = 'notice'; // table name - public $id; // int(4) primary_key not_null - public $profile_id; // int(4) not_null + public $__table = 'notice'; // table name + public $id; // int(4) primary_key not_null + public $profile_id; // int(4) not_null public $uri; // varchar(255) unique_key public $content; // varchar(140) - public $rendered; // text() + public $rendered; // text() public $url; // varchar(255) - public $created; // datetime() not_null - public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP - public $reply_to; // int(4) - public $is_local; // tinyint(1) - public $source; // varchar(32) + public $created; // datetime() not_null + public $modified; // timestamp() not_null default_CURRENT_TIMESTAMP + public $reply_to; // int(4) + public $is_local; // tinyint(1) + public $source; // varchar(32) /* Static get */ - function staticGet($k,$v=null) - { return Memcached_DataObject::staticGet('Notice',$k,$v); } + function staticGet($k,$v=NULL) { + return Memcached_DataObject::staticGet('Notice',$k,$v); + } /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE @@ -746,10 +747,19 @@ class Notice extends Memcached_DataObject if (!$id) { common_log_db_error($reply, 'INSERT', __FILE__); return; + } else { + $replied[$recipient->id] = 1; } } } } } + + foreach (array_keys($replied) as $recipient) { + $user = User::staticGet('id', $recipient); + if ($user) { + mail_attn_notify($user, $notice); + } + } } } diff --git a/lib/mail.php b/lib/mail.php index a1faefc80..9fa86de5c 100644 --- a/lib/mail.php +++ b/lib/mail.php @@ -573,3 +573,53 @@ function mail_notify_fave($other, $user, $notice) common_init_locale(); mail_to_user($other, $subject, $body); } + +/** + * notify a user that they have received an "attn:" message AKA "@-reply" + * + * @param User $user The user who recevied the notice + * @param Notice $notice The notice that was sent + * + * @return void + */ + +function mail_notify_attn($user, $notice) +{ + if (!$user->email || !$user->emailnotifyattn) { + return; + } + + $sender = $notice->getProfile(); + + $bestname = $sender->getBestName(); + + common_init_locale($user->language); + + $subject = sprintf(_('%s sent a notice to your attention'), $bestname); + + $body = sprintf(_("%1\$s just sent a notice to your attention (an '@-reply') on %2\$s.\n\n". + "The notice is here:\n\n". + "\t%3\$s\n\n" . + "It reads:\n\n". + "\t%4\$s\n\n" . + "You can reply back here:\n\n". + "\t%5\$s\n\n" . + "The list of all @-replies for you here:\n\n" . + "%6\$s\n\n" . + "Faithfully yours,\n" . + "%2\$s\n\n" . + "P.S. You can turn off these email notifications here: %7\$s\n"), + $bestname, + common_config('site', 'name'), + common_local_url('shownotice', + array('notice' => $notice->id)), + $notice->content, + common_local_url('newnotice', + array('replyto' => $sender->nickname)), + common_local_url('replies', + array('nickname' => $user->nickname)), + common_local_url('emailsettings')); + + common_init_locale(); + mail_to_user($user, $subject, $body); +} -- cgit v1.2.3-54-g00ecf From d8b6762e6dcb776571797f51d7c7d4cb99c9ef31 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 18 Feb 2009 09:35:59 -0500 Subject: move peoplesearchresults to its own module --- actions/peoplesearch.php | 26 +--------------- lib/peoplesearchresults.php | 75 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 25 deletions(-) create mode 100644 lib/peoplesearchresults.php (limited to 'lib') diff --git a/actions/peoplesearch.php b/actions/peoplesearch.php index 615201c46..14177fcf0 100644 --- a/actions/peoplesearch.php +++ b/actions/peoplesearch.php @@ -86,33 +86,9 @@ class PeoplesearchAction extends SearchAction } $profile->free(); - + $this->pagination($page > 1, $cnt > PROFILES_PER_PAGE, $page, 'peoplesearch', array('q' => $q)); } } -class PeopleSearchResults extends ProfileList -{ - var $terms = null; - var $pattern = null; - - function __construct($profile, $terms, $action) - { - parent::__construct($profile, $terms, $action); - $this->terms = array_map('preg_quote', - array_map('htmlspecialchars', $terms)); - $this->pattern = '/('.implode('|',$terms).')/i'; - } - - function highlight($text) - { - return preg_replace($this->pattern, '\\1', htmlspecialchars($text)); - } - - function isReadOnly() - { - return true; - } -} - diff --git a/lib/peoplesearchresults.php b/lib/peoplesearchresults.php new file mode 100644 index 000000000..f8ab7cf3b --- /dev/null +++ b/lib/peoplesearchresults.php @@ -0,0 +1,75 @@ + + * @author Robin Millette + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/profilelist.php'; + +/** + * People search results class + * + * Derivative of ProfileList with specialization for highlighting search terms. + * + * @category Widget + * @package Laconica + * @author Evan Prodromou + * @author Robin Millette + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * @see PeoplesearchAction + */ + +class PeopleSearchResults extends ProfileList +{ + var $terms = null; + var $pattern = null; + + function __construct($profile, $terms, $action) + { + parent::__construct($profile, $terms, $action); + $this->terms = array_map('preg_quote', + array_map('htmlspecialchars', $terms)); + $this->pattern = '/('.implode('|',$terms).')/i'; + } + + function highlight($text) + { + return preg_replace($this->pattern, '\\1', htmlspecialchars($text)); + } + + function isReadOnly() + { + return true; + } +} + -- cgit v1.2.3-54-g00ecf From c9def4a8768239093823fbe34367d97f9e30d320 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 18 Feb 2009 23:43:26 +0000 Subject: more correct handling of etags and last-modified --- lib/action.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index e2d09ace2..b1e700b67 100644 --- a/lib/action.php +++ b/lib/action.php @@ -209,12 +209,10 @@ class Action extends HTMLOutputter // lawsuit 'src' => common_path('js/jquery.form.js')), ' '); - $this->element('script', array('type' => 'text/javascript', 'src' => common_path('js/jquery.simplemodal-1.2.2.pack.js')), ' '); - Event::handle('EndShowJQueryScripts', array($this)); } if (Event::handle('StartShowLaconicaScripts', array($this))) { @@ -813,8 +811,10 @@ class Action extends HTMLOutputter // lawsuit if ($if_modified_since) { $ims = strtotime($if_modified_since); if ($lm <= $ims) { - if (!$etag || - $this->_hasEtag($etag, $_SERVER['HTTP_IF_NONE_MATCH'])) { + $if_none_match = $_SERVER['HTTP_IF_NONE_MATCH']; + if (!$if_none_match || + !$etag || + $this->_hasEtag($etag, $if_none_match)) { header('HTTP/1.1 304 Not Modified'); // Better way to do this? exit(0); @@ -832,9 +832,11 @@ class Action extends HTMLOutputter // lawsuit * * @return boolean */ + function _hasEtag($etag, $if_none_match) { - return ($if_none_match) && in_array($etag, explode(',', $if_none_match)); + $etags = explode(',', $if_none_match); + return in_array($etag, $etags) || in_array('*', $etags); } /** -- cgit v1.2.3-54-g00ecf From 1abeaf931e2e22806cbf747690df3a3350b401f8 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 14:58:38 +0000 Subject: handle if-modified-since in RSS feeds --- lib/rssaction.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'lib') diff --git a/lib/rssaction.php b/lib/rssaction.php index 131e8ac65..66c2d9e8c 100644 --- a/lib/rssaction.php +++ b/lib/rssaction.php @@ -38,6 +38,7 @@ class Rss10Action extends Action var $creators = array(); var $limit = DEFAULT_RSS_LIMIT; + var $notices = null; /** * Constructor @@ -93,6 +94,9 @@ class Rss10Action extends Action function handle($args) { + // Get the list of notices + $this->notices = $this->getNotices(); + // Parent handling, including cache check parent::handle($args); $this->showRss($this->limit); } @@ -258,5 +262,25 @@ class Rss10Action extends Action { $this->elementEnd('rdf:RDF'); } + + /** + * When was this page last modified? + * + */ + + function lastModified() + { + if (empty($this->notices)) { + return null; + } + + if (count($this->notices) == 0) { + return null; + } + + // FIXME: doesn't handle modified profiles, avatars, deleted notices + + return strtotime($this->notices[0]->created); + } } -- cgit v1.2.3-54-g00ecf From 5ec5a22dc75cb8f4d896b41ca24067c68d3e1de6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 10:04:28 -0500 Subject: make tagother work with router --- actions/tagother.php | 3 ++- lib/router.php | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/actions/tagother.php b/actions/tagother.php index 79151c911..0d18945a0 100644 --- a/actions/tagother.php +++ b/actions/tagother.php @@ -135,7 +135,8 @@ class TagotherAction extends Action 'id' => 'form_tag_user', 'class' => 'form_settings', 'name' => 'tagother', - 'action' => $this->selfUrl())); + 'action' => common_local_url('tagother', array('id' => $this->profile->id)))); + $this->elementStart('fieldset'); $this->element('legend', null, _('Tag user')); $this->hidden('token', common_session_token()); diff --git a/lib/router.php b/lib/router.php index d47ad7118..e55b597f2 100644 --- a/lib/router.php +++ b/lib/router.php @@ -98,12 +98,14 @@ class Router $main = array('login', 'logout', 'register', 'subscribe', 'unsubscribe', 'confirmaddress', 'recoverpassword', 'invite', 'favor', 'disfavor', 'sup', - 'tagother', 'block'); + 'block'); foreach ($main as $a) { $m->connect('main/'.$a, array('action' => $a)); } + $m->connect('main/tagother/:id', array('action' => 'tagother')); + // these take a code foreach (array('register', 'confirmaddress', 'recoverpassword') as $c) { -- cgit v1.2.3-54-g00ecf From 17a6e6603058d412f3c3a7c6800f5d47fcf0def0 Mon Sep 17 00:00:00 2001 From: Leslie Michael Orchard Date: Tue, 17 Feb 2009 23:25:00 -0500 Subject: PROFILES_PER_PAGE already defined in lib/common.php --- lib/profilelist.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/profilelist.php b/lib/profilelist.php index 8bef49dce..c2040fbc2 100644 --- a/lib/profilelist.php +++ b/lib/profilelist.php @@ -34,8 +34,6 @@ if (!defined('LACONICA')) { require_once INSTALLDIR.'/lib/widget.php'; -define('PROFILES_PER_PAGE', 20); - /** * Widget to show a list of profiles * -- cgit v1.2.3-54-g00ecf From 5bb32ccfd0d7bb813c8b35cfb0411625418c5402 Mon Sep 17 00:00:00 2001 From: Leslie Michael Orchard Date: Tue, 17 Feb 2009 23:09:57 -0500 Subject: Attempt to access non-existent OPENID_COOKIE_KEY cookie causing a warning --- lib/openid.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/openid.php b/lib/openid.php index 860573702..5c3d460da 100644 --- a/lib/openid.php +++ b/lib/openid.php @@ -64,6 +64,9 @@ function oid_set_last($openid_url) function oid_get_last() { + if (empty($_COOKIE[OPENID_COOKIE_KEY])) { + return null; + } $openid_url = $_COOKIE[OPENID_COOKIE_KEY]; if ($openid_url && strlen($openid_url) > 0) { return $openid_url; -- cgit v1.2.3-54-g00ecf From 76d506cf1644390a073e5178774675c60e1c3332 Mon Sep 17 00:00:00 2001 From: Leslie Michael Orchard Date: Tue, 17 Feb 2009 22:59:48 -0500 Subject: NOTICES_PER_SECTION already defined in lib/noticesection.php, causing a warning --- lib/popularnoticesection.php | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index 5380563b9..c7c7f0215 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -31,8 +31,6 @@ if (!defined('LACONICA')) { exit(1); } -define('NOTICES_PER_SECTION', 5); - /** * Base class for sections showing lists of notices * -- cgit v1.2.3-54-g00ecf From 85eb53247d7c0eac767de9fd79ba70183b7f57be Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 16:48:49 -0500 Subject: change static in router to var --- lib/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index e55b597f2..0640a5911 100644 --- a/lib/router.php +++ b/lib/router.php @@ -47,7 +47,7 @@ require_once 'Net/URL/Mapper.php'; class Router { - static $m = null; + var $m = null; static $inst = null; static function get() -- cgit v1.2.3-54-g00ecf From a76099c59b616004886e3c7add06db1de53e4acf Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 16:50:05 -0500 Subject: make check for ->value better --- lib/noticesection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/noticesection.php b/lib/noticesection.php index 97b517529..b31f18744 100644 --- a/lib/noticesection.php +++ b/lib/noticesection.php @@ -96,7 +96,7 @@ class NoticeSection extends Section $this->out->elementStart('p', 'entry-content'); $this->out->raw($notice->rendered); $this->out->elementEnd('p'); - if ($notice->value) { + if (!empty($notice->value)) { $this->out->elementStart('p'); $this->out->text($notice->value); $this->out->elementEnd('p'); -- cgit v1.2.3-54-g00ecf From d5bf7e5cfb4b4de335cafec69d93c565e0c9d2f4 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 16:51:39 -0500 Subject: fix notice in searchaction --- lib/searchaction.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/searchaction.php b/lib/searchaction.php index fdfb8dc5a..df6876445 100644 --- a/lib/searchaction.php +++ b/lib/searchaction.php @@ -79,10 +79,11 @@ class SearchAction extends Action function showTop($arr=null) { + $error = null; if ($arr) { $error = $arr[1]; } - if ($error) { + if (!empty($error)) { $this->element('p', 'error', $error); } else { $instr = $this->getInstructions(); -- cgit v1.2.3-54-g00ecf From 5845f19b051d440125f4921ad0a15184a993d287 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 17:02:34 -0500 Subject: fix some notices in omb.php --- lib/omb.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/omb.php b/lib/omb.php index f2dbef5ba..29e14c75f 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -239,7 +239,7 @@ function omb_broadcast_profile($profile) while ($sub->fetch()) { $rp = Remote_profile::staticGet('id', $sub->subscriber); if ($rp) { - if (!$updated[$rp->updateprofileurl]) { + if (!array_key_exists($rp->updateprofileurl, $updated)) { if (omb_update_profile($profile, $rp, $sub)) { $updated[$rp->updateprofileurl] = true; } @@ -295,7 +295,9 @@ function omb_update_profile($profile, $remote_profile, $subscription) common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); - if ($result->status == 403) { # not authorized, don't send again + if (empty($result) || $result) { + common_debug("Unable to contact " . $req->get_normalized_http_url()); + } else if ($result->status == 403) { # not authorized, don't send again common_debug('403 result, deleting subscription', __FILE__); $subscription->delete(); return false; -- cgit v1.2.3-54-g00ecf From f39dd40ffa9ae9e52fb0e83c2dfaae5f65ca5f80 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 17:29:40 -0500 Subject: fix notices in lib/grouplist.php --- lib/grouplist.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/grouplist.php b/lib/grouplist.php index 6801ab426..1b8547499 100644 --- a/lib/grouplist.php +++ b/lib/grouplist.php @@ -151,7 +151,7 @@ class GroupList extends Widget # If we're on a list with an owner (subscriptions or subscribers)... - if ($user && $user->id == $this->owner->id) { + if (!empty($user) && !empty($this->owner) && $user->id == $this->owner->id) { $this->showOwnerControls(); } -- cgit v1.2.3-54-g00ecf From 3a999af4d905d3cd23ea9163f47b6ed5c35f606c Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Fri, 20 Feb 2009 17:30:09 -0500 Subject: Change common_local_url() to take 4 arguments I changed common_local_url() to take an additional optional argument -- for query parameters. Being persnickety, I made it the third of four, and moved the last one ($fragment) down a slot. That required changing a couple of calls. --- actions/twitapistatuses.php | 2 +- actions/userrss.php | 11 +++++------ lib/router.php | 4 ++-- lib/util.php | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'lib') diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 18e24c0f5..51c256589 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -204,7 +204,7 @@ class TwitapistatusesAction extends TwitterapiAction # FriendFeed's SUP protocol # Also added RSS and Atom feeds - $suplink = common_local_url('sup', null, $user->id); + $suplink = common_local_url('sup', null, null, $user->id); header('X-SUP-ID: '.$suplink); # XXX: since diff --git a/actions/userrss.php b/actions/userrss.php index 04855ccca..a3e5a3aab 100644 --- a/actions/userrss.php +++ b/actions/userrss.php @@ -46,13 +46,13 @@ class UserrssAction extends Rss10Action { $user = $this->user; - + if (is_null($user)) { return null; } - + $notice = $user->getNotices(0, ($limit == 0) ? NOTICES_PER_PAGE : $limit); - + while ($notice->fetch()) { $notices[] = clone($notice); } @@ -87,10 +87,10 @@ class UserrssAction extends Rss10Action } # override parent to add X-SUP-ID URL - + function initRss($limit=0) { - $url = common_local_url('sup', null, $this->user->id); + $url = common_local_url('sup', null, null, $this->user->id); header('X-SUP-ID: '.$url); parent::initRss($limit); } @@ -100,4 +100,3 @@ class UserrssAction extends Rss10Action return true; } } - diff --git a/lib/router.php b/lib/router.php index 0640a5911..85425bed2 100644 --- a/lib/router.php +++ b/lib/router.php @@ -350,7 +350,7 @@ class Router return $this->m->match($path); } - function build($action, $args=null, $fragment=null) + function build($action, $args=null, $params=null, $fragment=null) { $action_arg = array('action' => $action); @@ -360,6 +360,6 @@ class Router $args = $action_arg; } - return $this->m->generate($args, null, $fragment); + return $this->m->generate($args, $params, $fragment); } } \ No newline at end of file diff --git a/lib/util.php b/lib/util.php index 46aa7b9df..5345a08bb 100644 --- a/lib/util.php +++ b/lib/util.php @@ -705,10 +705,10 @@ function common_relative_profile($sender, $nickname, $dt=null) return null; } -function common_local_url($action, $args=null, $fragment=null) +function common_local_url($action, $args=null, $params=null, $fragment=null) { $r = Router::get(); - $path = $r->build($action, $args, $fragment); + $path = $r->build($action, $args, $params, $fragment); if ($path) { } if (common_config('site','fancy')) { -- cgit v1.2.3-54-g00ecf From 5e816d7be208fc24419288234559c78da7391c8b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 20 Feb 2009 15:07:59 -0800 Subject: Fixed routing for direct messages and favorites in the API --- lib/router.php | 50 ++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 14 deletions(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index d47ad7118..9d0d3a3f0 100644 --- a/lib/router.php +++ b/lib/router.php @@ -226,20 +226,31 @@ class Router // direct messages - $m->connect('api/direct_messages/:method', - array('action' => 'api', - 'apiaction' => 'direct_messages'), - array('method' => '(sent|new)(\.(xml|json|atom|rss))?')); + foreach (array('xml', 'json') as $e) { + $m->connect('api/direct_messages/new.'.$e, + array('action' => 'api', + 'apiaction' => 'direct_messages', + 'method' => 'create.'.$e)); + } + + foreach (array('xml', 'json', 'rss', 'atom') as $e) { + $m->connect('api/direct_messages.'.$e, + array('action' => 'api', + 'apiaction' => 'direct_messages', + 'method' => 'direct_messages.'.$e)); + } + + foreach (array('xml', 'json', 'rss', 'atom') as $e) { + $m->connect('api/direct_message/sent.'.$e, + array('action' => 'api', + 'apiaction' => 'direct_messages', + 'method' => 'sent.'.$e)); + } $m->connect('api/direct_messages/destroy/:argument', array('action' => 'api', 'apiaction' => 'direct_messages')); - $m->connect('api/:method', - array('action' => 'api', - 'apiaction' => 'direct_messages'), - array('method' => 'direct_messages(\.(xml|json|atom|rss))?')); - // friendships $m->connect('api/friendships/:method/:argument', @@ -269,10 +280,12 @@ class Router 'apiaction' => 'favorites', 'method' => 'favorites')); - $m->connect('api/:method', - array('action' => 'api', - 'apiaction' => 'favorites'), - array('method' => 'favorites(\.(xml|json|rss|atom))?')); + foreach (array('xml', 'json', 'rss', 'atom') as $e) { + $m->connect('api/favorites.'.$e, + array('action' => 'api', + 'apiaction' => 'favorites', + 'method' => 'favorites.'.$e)); + } // notifications @@ -345,7 +358,16 @@ class Router function map($path) { - return $this->m->match($path); + try { + $match = $this->m->match($path); + } catch (Net_URL_Mapper_InvalidException $e) { + common_log(LOG_ERR, "Problem getting route for $path - " . + $e->getMessage()); + $cac = new ClientErrorAction("Page not found.", 404); + $cac->showPage(); + } + + return $match; } function build($action, $args=null, $fragment=null) -- cgit v1.2.3-54-g00ecf From f75c2328ccb87650e107e90b89b4d2a16d7a29cd Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 20 Feb 2009 23:47:24 +0000 Subject: Hooks for: local navigation --- EVENTS.txt | 6 ++++++ lib/action.php | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index af0bee587..37e2203d5 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -82,3 +82,9 @@ StartNoticeSave: before inserting a notice (good place for content filters) EndNoticeSave: after inserting a notice and related code - $notice: notice that was saved (with ID and URI) +StartShowLocalNavBlock: Showing the local nav menu +- $action: the current action + +EndShowLocalNavBlock: At the end of the local nav menu +- $action: the current action + diff --git a/lib/action.php b/lib/action.php index b1e700b67..a468c638c 100644 --- a/lib/action.php +++ b/lib/action.php @@ -474,7 +474,10 @@ class Action extends HTMLOutputter // lawsuit function showCore() { $this->elementStart('div', array('id' => 'core')); - $this->showLocalNavBlock(); + if (Event::handle('StartShowLocalNavBlock', array($this))) { + $this->showLocalNavBlock(); + Event::handle('EndShowLocalNavBlock', array($this)); + } if (Event::handle('StartShowContentBlock', array($this))) { $this->showContentBlock(); Event::handle('EndShowContentBlock', array($this)); -- cgit v1.2.3-54-g00ecf From 1fdb35bbf105fe462dcc663ea20b6aa56d654001 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 20 Feb 2009 17:17:20 -0800 Subject: New doc page for Identi.ca badge and minor updates to badge's js --- doc-src/badge | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++ js/identica-badge.js | 3 ++- lib/action.php | 2 ++ scripts/sitemap.php | 3 ++- 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 doc-src/badge (limited to 'lib') diff --git a/doc-src/badge b/doc-src/badge new file mode 100644 index 000000000..1c368eb69 --- /dev/null +++ b/doc-src/badge @@ -0,0 +1,65 @@ +Install the %%site.name%% badge on you blog or web site to show the latest updates +from you and your friends! + + + + + +Things to try +-------------- + +* Click an avatar and the badge will refresh with that user's timeline +* Click a nickname to open a user's profile in your browser +* Click a notice's timestamp to view the notice in your browser +* @-replies and #tags are live links + +## Installation instructions + +Copy and paste the following JavaScript into an HTML page where +you want the badge to show up. Substitute your own ID in the user +parameter. + +
+	<script type="text/javascript" src="http://identi.ca/js/identica-badge.js">
+	{
+	   "user":"kentbrew",
+	   "server":"identi.ca",
+	   "headerText":" and friends"
+	}
+	</script>
+
+
+ + + +Valid parameters for the badge: +------------------------------- + +* user : defaults to 7000 (@kentbrew) +* headerText : defaults to empty +* height : defaults to 350px +* width : defaults to 300px +* background : defaults to #193441. If you set evenBackground, oddBackground, + and headerBackground, you won't see it at all. +* border : defaults to 1px solid black +* userColor : defaults to whatever link color is set to on your page +* headerBackground : defaults to transparent +* headerColor : defaults to white +* evenBackground : defaults to #fff +* oddBackground : defaults to #eee +* thumbnailBorder : 1px solid black +* thumbnailSize : defaults to 24px +* padding : defaults to 3px +* server : defaults to identi.ca + +Licence +------- + +Identi.ca badge by [Kent Brewster](http://kentbrewster.com/identica-badge/). +Licenced under [CC-BY-SA-3](http://kentbrewster.com/rights-and-permissions/). diff --git a/js/identica-badge.js b/js/identica-badge.js index 5c586b5d6..869230b7a 100644 --- a/js/identica-badge.js +++ b/js/identica-badge.js @@ -1,4 +1,5 @@ // identica badge -- updated to work with the native API, 12-4-2008 +// Modified to point to Identi.ca, 2-20-2009 by Zach // copyright Kent Brewster 2008 // see http://kentbrewster.com/identica-badge for info ( function() { @@ -127,7 +128,7 @@ var a = document.createElement('A'); a.innerHTML = 'get this'; a.target = '_blank'; - a.href = 'http://kentbrewster.com/identica-badge'; + a.href = 'http://identica/doc/badge'; $.s.f.appendChild(a); $.s.appendChild($.s.f); $.f.getUser(); diff --git a/lib/action.php b/lib/action.php index b1e700b67..0c4d0181d 100644 --- a/lib/action.php +++ b/lib/action.php @@ -657,6 +657,8 @@ class Action extends HTMLOutputter // lawsuit _('Source')); $this->menuItem(common_local_url('doc', array('title' => 'contact')), _('Contact')); + $this->menuItem(common_local_url('doc', array('title' => 'badge')), + _('Badge')); Event::handle('EndSecondaryNav', array($this)); } $this->elementEnd('ul'); diff --git a/scripts/sitemap.php b/scripts/sitemap.php index 51a9bbd75..39eb859bb 100755 --- a/scripts/sitemap.php +++ b/scripts/sitemap.php @@ -61,7 +61,8 @@ function standard_map() ) ); - $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', 'privacy', 'source'); + $docs = array('about', 'faq', 'contact', 'im', 'openid', 'openmublog', + 'privacy', 'source', 'badge'); foreach($docs as $title) { $standard_map_urls .= url( -- cgit v1.2.3-54-g00ecf From 5e646ead492fc62b52f67af6c3a23295ef502345 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 22 Feb 2009 18:01:55 -0800 Subject: Minor routing fix for friends_timeline API method --- lib/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index e842604e9..a41d35f22 100644 --- a/lib/router.php +++ b/lib/router.php @@ -213,7 +213,7 @@ class Router $m->connect('api/statuses/:method/:argument', array('action' => 'api', 'apiaction' => 'statuses'), - array('method' => '(user_timeline|show|destroy|friends|followers)')); + array('method' => '(user_timeline|friends_timeline|show|destroy|friends|followers)')); // users -- cgit v1.2.3-54-g00ecf From cab322d21b8c8077192a1396bf13050d734c2aba Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Sun, 22 Feb 2009 20:04:47 -0800 Subject: Ticket #1108 - Added 'social graph' methods to the API --- actions/twitapistatuses.php | 52 +++++++++++++++++++++++++++++++++++++++------ lib/router.php | 27 +++++++++++++++++++++++ 2 files changed, 73 insertions(+), 6 deletions(-) (limited to 'lib') diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 51c256589..216835026 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -470,19 +470,28 @@ class TwitapistatusesAction extends TwitterapiAction return $this->subscriptions($apidata, 'subscribed', 'subscriber'); } - function followers($args, $apidata) + function friendsIDs($args, $apidata) { parent::handle($args); + return $this->subscriptions($apidata, 'subscribed', 'subscriber', true); + } + function followers($args, $apidata) + { + parent::handle($args); return $this->subscriptions($apidata, 'subscriber', 'subscribed'); } - function subscriptions($apidata, $other_attr, $user_attr) + function followersIDs($args, $apidata) { + parent::handle($args); + return $this->subscriptions($apidata, 'subscriber', 'subscribed', true); + } - # XXX: lite + function subscriptions($apidata, $other_attr, $user_attr, $onlyIDs=false) + { - $this->auth_user = $apidate['user']; + $this->auth_user = $apidata['user']; $user = $this->get_user($apidata['api_arg'], $apidata); if (!$user) { @@ -514,7 +523,10 @@ class TwitapistatusesAction extends TwitterapiAction } $sub->orderBy('created DESC'); - $sub->limit(($page-1)*100, 100); + + if (!$onlyIDs) { + $sub->limit(($page-1)*100, 100); + } $others = array(); @@ -529,7 +541,13 @@ class TwitapistatusesAction extends TwitterapiAction $type = $apidata['content-type']; $this->init_document($type); - $this->show_profiles($others, $type); + + if ($onlyIDs) { + $this->showIDs($others, $type); + } else { + $this->show_profiles($others, $type); + } + $this->end_document($type); } @@ -555,6 +573,28 @@ class TwitapistatusesAction extends TwitterapiAction } } + function showIDs($profiles, $type) + { + switch ($type) { + case 'xml': + $this->elementStart('ids'); + foreach ($profiles as $profile) { + $this->element('id', null, $profile->id); + } + $this->elementEnd('ids'); + break; + case 'json': + $ids = array(); + foreach ($profiles as $profile) { + $ids[] = (int)$profile->id; + } + print json_encode($ids); + break; + default: + $this->clientError(_('unsupported file type')); + } + } + function featured($args, $apidata) { parent::handle($args); diff --git a/lib/router.php b/lib/router.php index a41d35f22..b18a5523e 100644 --- a/lib/router.php +++ b/lib/router.php @@ -265,6 +265,33 @@ class Router 'apiaction' => 'friendships'), array('method' => 'exists(\.(xml|json|rss|atom))')); + + // Social graph + + $m->connect('api/friends/ids/:argument', + array('action' => 'api', + 'apiaction' => 'statuses', + 'method' => 'friendsIDs')); + + foreach (array('xml', 'json') as $e) { + $m->connect('api/friends/ids.'.$e, + array('action' => 'api', + 'apiaction' => 'statuses', + 'method' => 'friendsIDs.'.$e)); + } + + $m->connect('api/followers/ids/:argument', + array('action' => 'api', + 'apiaction' => 'statuses', + 'method' => 'followersIDs')); + + foreach (array('xml', 'json') as $e) { + $m->connect('api/followers/ids.'.$e, + array('action' => 'api', + 'apiaction' => 'statuses', + 'method' => 'followersIDs.'.$e)); + } + // account $m->connect('api/account/:method', -- cgit v1.2.3-54-g00ecf From d30590de23f2b9a138ec6923016c4e9af6b9a989 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Tue, 24 Feb 2009 04:31:31 +0000 Subject: Print stylesheet --- lib/action.php | 4 ++++ theme/base/css/print.css | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 theme/base/css/print.css (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index 455ebeff0..dd7dd44e7 100644 --- a/lib/action.php +++ b/lib/action.php @@ -173,6 +173,10 @@ class Action extends HTMLOutputter // lawsuit // TODO: "handheld" CSS for other mobile devices 'media' => 'only screen and (max-device-width: 480px)')); // Mobile WebKit } + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/print.css', 'base') . '?version=' . LACONICA_VERSION, + 'media' => 'print')); Event::handle('EndShowLaconicaStyles', array($this)); } if (Event::handle('StartShowUAStyles', array($this))) { diff --git a/theme/base/css/print.css b/theme/base/css/print.css new file mode 100644 index 000000000..cf3ac0391 --- /dev/null +++ b/theme/base/css/print.css @@ -0,0 +1,28 @@ +body { font-size:12pt; } +a:after { background-color:#fff; } +a:not([href^="#"]):after { content:" ( "attr(href)" ) "; } +a:not([href^="http:"]):after { content: " ( http://identi.ca/"attr(href)" ) "; } +a[href^="/"]:after { content: " ( http://identi.ca" attr(href) " ) "; } + +img { border:none; } +p { orphans: 2; widows: 1; } + +#site_nav_global_primary, +#site_nav_local_views, +#form_notice, +.pagination, +#site_nav_global_secondary, +.entity_actions, +.notice-options, +#aside_primary { +display:none; +} + +.timestamp dt, .timestamp dd, +.device dt, .device dd { +display:inline; +} + +.notices li { +margin-bottom:18px; +} -- cgit v1.2.3-54-g00ecf From 7af6f5392be2b847c4c026f2632fc1c900338b81 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Thu, 26 Feb 2009 19:56:31 +0000 Subject: Hook for setting document content type, charset, language, DOCTYPE and html element properties --- EVENTS.txt | 6 ++++++ lib/action.php | 5 ++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index 37e2203d5..ed461ee9f 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -88,3 +88,9 @@ StartShowLocalNavBlock: Showing the local nav menu EndShowLocalNavBlock: At the end of the local nav menu - $action: the current action +StartShowHTML: Chance to set document content type, charset, language, DOCTYPE and html element properties +- $action: the current action + +EndShowHTML: Showing after the html element +- $action: the current action + diff --git a/lib/action.php b/lib/action.php index dd7dd44e7..9c71a153d 100644 --- a/lib/action.php +++ b/lib/action.php @@ -93,7 +93,10 @@ class Action extends HTMLOutputter // lawsuit */ function showPage() { - $this->startHTML(); + if (Event::handle('StartShowHTML', array($this))) { + $this->startHTML(); + Event::handle('EndShowHTML', array($this)); + } $this->showHead(); $this->showBody(); $this->endHTML(); -- cgit v1.2.3-54-g00ecf From ee92d0b0a8870143ee462b5833b0adf47673a613 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 26 Feb 2009 13:36:27 -0800 Subject: fix notice in action with caching --- lib/action.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index 455ebeff0..f19a047cf 100644 --- a/lib/action.php +++ b/lib/action.php @@ -812,11 +812,12 @@ class Action extends HTMLOutputter // lawsuit } if ($lm) { header('Last-Modified: ' . date(DATE_RFC1123, $lm)); - $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; - if ($if_modified_since) { + if (array_key_exists('HTTP_IF_MODIFIED_SINCE', $_SERVER)) { + $if_modified_since = $_SERVER['HTTP_IF_MODIFIED_SINCE']; $ims = strtotime($if_modified_since); if ($lm <= $ims) { - $if_none_match = $_SERVER['HTTP_IF_NONE_MATCH']; + $if_none_match = (array_key_exists('HTTP_IF_NONE_MATCH', $_SERVER)) ? + $_SERVER['HTTP_IF_NONE_MATCH'] : null; if (!$if_none_match || !$etag || $this->_hasEtag($etag, $if_none_match)) { -- cgit v1.2.3-54-g00ecf From 2674d40b62934a579c083f4f4f7f1173d64d777b Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 26 Feb 2009 13:36:38 -0800 Subject: fix notice with twitter broadcast --- lib/twitter.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/twitter.php b/lib/twitter.php index deb6fd276..8a54afb9c 100644 --- a/lib/twitter.php +++ b/lib/twitter.php @@ -210,7 +210,7 @@ function save_twitter_friends($user, $twitter_id, $screen_name, $password) function is_twitter_bound($notice, $flink) { // Check to see if notice should go to Twitter - if (($flink->noticesync & FOREIGN_NOTICE_SEND)) { + if (!empty($flink) && ($flink->noticesync & FOREIGN_NOTICE_SEND)) { // If it's not a Twitter-style reply, or if the user WANTS to send replies. if (!preg_match('/^@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) || @@ -218,7 +218,7 @@ function is_twitter_bound($notice, $flink) { return true; } } - + return false; } @@ -227,10 +227,10 @@ function broadcast_twitter($notice) global $config; $success = true; - $flink = Foreign_link::getByUserID($notice->profile_id, + $flink = Foreign_link::getByUserID($notice->profile_id, TWITTER_SERVICE); - - // XXX: Not sure WHERE to check whether a notice should go to + + // XXX: Not sure WHERE to check whether a notice should go to // Twitter. Should we even put in the queue if it shouldn't? --Zach if (is_twitter_bound($notice, $flink)) { @@ -245,7 +245,7 @@ function broadcast_twitter($notice) $options = array( CURLOPT_USERPWD => "$twitter_user:$twitter_password", CURLOPT_POST => true, - CURLOPT_POSTFIELDS => + CURLOPT_POSTFIELDS => array( 'status' => $statustxt, 'source' => $config['integration']['source'] @@ -293,7 +293,7 @@ function broadcast_twitter($notice) $success = false; } } - + return $success; } -- cgit v1.2.3-54-g00ecf From 42eecfabca67e5caee1f4e5894b711cacd0a9f9d Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 21 Feb 2009 18:51:56 +0100 Subject: Adds some missing routes. --- lib/router.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index b18a5523e..b142022f0 100644 --- a/lib/router.php +++ b/lib/router.php @@ -117,6 +117,11 @@ class Router $m->connect('main/openid', array('action' => 'openidlogin')); $m->connect('main/remote', array('action' => 'remotesubscribe')); + foreach (array('requesttoken', 'accesstoken', 'userauthorization', + 'postnotice', 'updateprofile') as $action) { + $m->connect('index.php?action=' . $action, array('action' => $action)); + } + // settings foreach (array('profile', 'avatar', 'password', 'openid', 'im', @@ -411,4 +416,4 @@ class Router return $this->m->generate($args, $params, $fragment); } -} \ No newline at end of file +} -- cgit v1.2.3-54-g00ecf From 616fd16bc528ce78d7fc1fa8a6ad5a67f10ae5eb Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 21 Feb 2009 19:43:18 +0100 Subject: Auth_Yadis_Yadis::PlainHTTPFetcher expects plain arrays, not hashes. --- actions/finishremotesubscribe.php | 2 +- actions/remotesubscribe.php | 3 +-- lib/omb.php | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) (limited to 'lib') diff --git a/actions/finishremotesubscribe.php b/actions/finishremotesubscribe.php index 76db887de..acfacbdc1 100644 --- a/actions/finishremotesubscribe.php +++ b/actions/finishremotesubscribe.php @@ -283,7 +283,7 @@ class FinishremotesubscribeAction extends Action $fetcher = Auth_Yadis_Yadis::getHTTPFetcher(); $result = $fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), - array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); + array('User-Agent: Laconica/' . LACONICA_VERSION)); common_debug('got result: "'.print_r($result,true).'"', __FILE__); diff --git a/actions/remotesubscribe.php b/actions/remotesubscribe.php index f727a63b8..7ea7acd6d 100644 --- a/actions/remotesubscribe.php +++ b/actions/remotesubscribe.php @@ -321,8 +321,7 @@ class RemotesubscribeAction extends Action $result = $fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), - array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); - + array('User-Agent: Laconica/' . LACONICA_VERSION)); if ($result->status != 200) { return null; } diff --git a/lib/omb.php b/lib/omb.php index 29e14c75f..befcf4666 100644 --- a/lib/omb.php +++ b/lib/omb.php @@ -206,7 +206,7 @@ function omb_post_notice_keys($notice, $postnoticeurl, $tk, $secret) $result = $fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), - array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); + array('User-Agent: Laconica/' . LACONICA_VERSION)); common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); @@ -291,7 +291,7 @@ function omb_update_profile($profile, $remote_profile, $subscription) common_debug('postdata = '.$req->to_postdata(), __FILE__); $result = $fetcher->post($req->get_normalized_http_url(), $req->to_postdata(), - array('User-Agent' => 'Laconica/' . LACONICA_VERSION)); + array('User-Agent: Laconica/' . LACONICA_VERSION)); common_debug('Got HTTP result "'.print_r($result,true).'"', __FILE__); -- cgit v1.2.3-54-g00ecf From c87349350d0422157575f93ab4dd9abc108cc8d8 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sat, 21 Feb 2009 22:48:30 +0100 Subject: Add finishremotesubscribe to the unrouted actions list. --- lib/router.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index b142022f0..e5b8e7d23 100644 --- a/lib/router.php +++ b/lib/router.php @@ -118,7 +118,7 @@ class Router $m->connect('main/remote', array('action' => 'remotesubscribe')); foreach (array('requesttoken', 'accesstoken', 'userauthorization', - 'postnotice', 'updateprofile') as $action) { + 'postnotice', 'updateprofile', 'finishremotesubscribe') as $action) { $m->connect('index.php?action=' . $action, array('action' => $action)); } -- cgit v1.2.3-54-g00ecf From fa82722e5abd2e1cbf75050aea594f65a384d8d7 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 22 Feb 2009 13:31:50 +0100 Subject: More routes. --- lib/router.php | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index e5b8e7d23..f70b67f38 100644 --- a/lib/router.php +++ b/lib/router.php @@ -133,6 +133,7 @@ class Router foreach (array('group', 'people', 'notice') as $s) { $m->connect('search/'.$s, array('action' => $s.'search')); + $m->connect('search/'.$s.'?q=:q', array('action' => $s.'search'), array('q' => '.+')); } $m->connect('search/notice/rss', array('action' => 'noticesearchrss')); @@ -140,6 +141,9 @@ class Router // notice $m->connect('notice/new', array('action' => 'newnotice')); + $m->connect('notice/new?replyto=:replyto', + array('action' => 'newnotice'), + array('replyto' => '[A-Za-z0-9_-]+')); $m->connect('notice/:notice', array('action' => 'shownotice'), array('notice' => '[0-9]+')); -- cgit v1.2.3-54-g00ecf From 32e0fb148312bb2a052111513ed71fc4948a9fb7 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 22 Feb 2009 14:27:09 +0100 Subject: Route for remote subscribe link on profile page. --- lib/router.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index f70b67f38..95ce77e5e 100644 --- a/lib/router.php +++ b/lib/router.php @@ -116,6 +116,7 @@ class Router $m->connect('main/openid', array('action' => 'openidlogin')); $m->connect('main/remote', array('action' => 'remotesubscribe')); + $m->connect('main/remote?nickname=:nickname', array('action' => 'remotesubscribe'), array('nickname' => '[A-Za-z0-9_-]+')); foreach (array('requesttoken', 'accesstoken', 'userauthorization', 'postnotice', 'updateprofile', 'finishremotesubscribe') as $action) { -- cgit v1.2.3-54-g00ecf From 120eb77400843669980850882dfae83ca7f8e7e7 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Sun, 22 Feb 2009 17:45:26 +0100 Subject: Fixes #1258: A period in a hashtag leads to the tag being interpreted as url and hence breaking the tag. --- lib/util.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index 5345a08bb..18e4f310c 100644 --- a/lib/util.php +++ b/lib/util.php @@ -456,6 +456,9 @@ function common_replace_urls_callback($text, $callback) { if (!in_array($url_parts[2], $tlds)) continue; + // Make sure we didn't capture a hash tag + if (strpos($url, '#') === 0) continue; + // Put the url back the way we found it. $url = (mb_strpos($orig_url, htmlspecialchars($url)) === FALSE) ? $url:htmlspecialchars($url); -- cgit v1.2.3-54-g00ecf From 3f7d70c5e4c5e91d552cc629a9371109cb859bc3 Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Wed, 25 Feb 2009 01:36:58 +0100 Subject: Hopefully fixes #1260: Mess with norwegian languages. Moreover corrected ltr/rtl for Italian and Hebrew and added Finnish. --- lib/language.php | 61 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 32 insertions(+), 29 deletions(-) (limited to 'lib') diff --git a/lib/language.php b/lib/language.php index a73b73f28..79e9030ae 100644 --- a/lib/language.php +++ b/lib/language.php @@ -94,40 +94,43 @@ function get_nice_language_list() * Get a list of all languages that are enabled in the default config * * This should ONLY be called when setting up the default config in common.php. - * Any other attempt to get a list of lanugages should instead call + * Any other attempt to get a list of languages should instead call * common_config('site','languages') * * @return array mapping of language codes to language info */ function get_all_languages() { return array( - 'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'), - 'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'), - 'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'), - 'de' => array('q' => 0.5, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'), - 'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'), - 'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), - 'en-gb' => array('q' => 0.3, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'), - 'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English', 'direction' => 'ltr'), - 'es' => array('q' => 0.5, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'), - 'fr-fr' => array('q' => 0.2, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'), - 'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'ltr'), - 'it' => array('q' => 0.9, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'rtl'), - 'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), -# 'ko' => array('q' => 0, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'), - 'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), - 'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (bokmal)', 'direction' => 'ltr'), - 'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'), - 'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'), -# 'pt' => array('q' => 0, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'), - 'pt-br' => array('q' => 0.7, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'), - 'ru' => array('q' => 0.1, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'), - 'sv' => array('q' => 0.9, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'), - 'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'), - 'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'), - 'uk' => array('q' => 0.7, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'), - 'vi' => array('q' => 0.7, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'), - 'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'), - 'zh-hant' => array('q' => 0.2, 'lang' => 'zh_hant', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'), + 'bg' => array('q' => 0.8, 'lang' => 'bg_BG', 'name' => 'Bulgarian', 'direction' => 'ltr'), + 'ca' => array('q' => 0.5, 'lang' => 'ca_ES', 'name' => 'Catalan', 'direction' => 'ltr'), + 'cs' => array('q' => 0.5, 'lang' => 'cs_CZ', 'name' => 'Czech', 'direction' => 'ltr'), + 'de' => array('q' => 0.5, 'lang' => 'de_DE', 'name' => 'German', 'direction' => 'ltr'), + 'el' => array('q' => 0.1, 'lang' => 'el', 'name' => 'Greek', 'direction' => 'ltr'), + 'en-us' => array('q' => 1, 'lang' => 'en_US', 'name' => 'English (US)', 'direction' => 'ltr'), + 'en-gb' => array('q' => 0.3, 'lang' => 'en_GB', 'name' => 'English (British)', 'direction' => 'ltr'), + 'en' => array('q' => 1, 'lang' => 'en', 'name' => 'English', 'direction' => 'ltr'), + 'es' => array('q' => 0.5, 'lang' => 'es', 'name' => 'Spanish', 'direction' => 'ltr'), + 'fi' => array('q' => 0.5, 'lang' => 'fi', 'name' => 'Finnish', 'direction' => 'ltr'), + 'fr-fr' => array('q' => 0.2, 'lang' => 'fr_FR', 'name' => 'French', 'direction' => 'ltr'), + 'he' => array('q' => 0.5, 'lang' => 'he_IL', 'name' => 'Hebrew', 'direction' => 'rtl'), + 'it' => array('q' => 0.9, 'lang' => 'it_IT', 'name' => 'Italian', 'direction' => 'ltr'), + 'jp' => array('q' => 0.5, 'lang' => 'ja_JP', 'name' => 'Japanese', 'direction' => 'ltr'), +# 'ko' => array('q' => 0, 'lang' => 'ko', 'name' => 'Korean', 'direction' => 'ltr'), + 'mk' => array('q' => 0.5, 'lang' => 'mk_MK', 'name' => 'Macedonian', 'direction' => 'ltr'), + 'nb' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), + 'no' => array('q' => 0.1, 'lang' => 'nb_NO', 'name' => 'Norwegian (Bokmål)', 'direction' => 'ltr'), + 'nn' => array('q' => 0.1, 'lang' => 'nn_NO', 'name' => 'Norwegian (Nynorsk)', 'direction' => 'ltr'), + 'nl' => array('q' => 0.5, 'lang' => 'nl_NL', 'name' => 'Dutch', 'direction' => 'ltr'), + 'pl' => array('q' => 0.5, 'lang' => 'pl_PL', 'name' => 'Polish', 'direction' => 'ltr'), +# 'pt' => array('q' => 0, 'lang' => 'pt', 'name' => 'Portuguese', 'direction' => 'ltr'), + 'pt-br' => array('q' => 0.7, 'lang' => 'pt_BR', 'name' => 'Portuguese Brazil', 'direction' => 'ltr'), + 'ru' => array('q' => 0.1, 'lang' => 'ru_RU', 'name' => 'Russian', 'direction' => 'ltr'), + 'sv' => array('q' => 0.9, 'lang' => 'sv_SE', 'name' => 'Swedish', 'direction' => 'ltr'), + 'te' => array('q' => 0.3, 'lang' => 'te_IN', 'name' => 'Telugu', 'direction' => 'ltr'), + 'tr' => array('q' => 0.5, 'lang' => 'tr_TR', 'name' => 'Turkish', 'direction' => 'ltr'), + 'uk' => array('q' => 0.7, 'lang' => 'uk_UA', 'name' => 'Ukrainian', 'direction' => 'ltr'), + 'vi' => array('q' => 0.7, 'lang' => 'vi_VN', 'name' => 'Vietnamese', 'direction' => 'ltr'), + 'zh-cn' => array('q' => 0.9, 'lang' => 'zh_CN', 'name' => 'Chinese (Simplified)', 'direction' => 'ltr'), + 'zh-hant' => array('q' => 0.2, 'lang' => 'zh_hant', 'name' => 'Chinese (Taiwanese)', 'direction' => 'ltr'), ); } -- cgit v1.2.3-54-g00ecf From d92beda526f1495d16b54880a40ebb3c7d7e5f2e Mon Sep 17 00:00:00 2001 From: Adrian Lang Date: Wed, 25 Feb 2009 16:59:32 +0100 Subject: Add route for new message to user. --- lib/router.php | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/router.php b/lib/router.php index 95ce77e5e..4b70c0150 100644 --- a/lib/router.php +++ b/lib/router.php @@ -154,6 +154,7 @@ class Router array('notice' => '[0-9]+')); $m->connect('message/new', array('action' => 'newmessage')); + $m->connect('message/new?to=:to', array('action' => 'newmessage'), array('to' => '[A-Za-z0-9_-]')); $m->connect('message/:message', array('action' => 'showmessage'), array('message' => '[0-9]+')); -- cgit v1.2.3-54-g00ecf From 02ba71b0f186b406071a97c3267603d4863a4b21 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 28 Feb 2009 15:12:31 -0800 Subject: start conversation action --- actions/conversation.php | 123 +++++++++++++++++++++++++++++++++++++++++++++++ lib/router.php | 11 +++-- 2 files changed, 131 insertions(+), 3 deletions(-) create mode 100644 actions/conversation.php (limited to 'lib') diff --git a/actions/conversation.php b/actions/conversation.php new file mode 100644 index 000000000..0c22fe123 --- /dev/null +++ b/actions/conversation.php @@ -0,0 +1,123 @@ + + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + * + * Laconica - a distributed open-source microblogging tool + * Copyright (C) 2008, Controlez-Vous, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * Conversation tree in the browser + * + * @category Action + * @package Laconica + * @author Evan Prodromou + * @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3 + * @link http://laconi.ca/ + */ +class ConversationAction extends Action +{ + var $id = null; + var $notices = null; + var $page = null; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if id not passed in + */ + + function prepare($args) + { + parent::prepare($args); + $this->id = $this->trimmed('id'); + if (!$this->id) { + return false; + } + $this->notices = $this->getNotices(); + $this->page = $this->trimmed('page'); + if (empty($this->page)) { + $this->page = 1; + } + return true; + } + + /** + * Get notices + * + * @param integer $limit max number of notices to return + * + * @return array notices + */ + + function getNotices($limit=0) + { + $qry = 'SELECT notice.*, '. + 'FROM notice WHERE conversation = %d '. + 'ORDER BY created '; + + $offset = 0; + $limit = NOTICES_PER_PAGE + 1; + + if (common_config('db', 'type') == 'pgsql') { + $qry .= ' LIMIT ' . $limit . ' OFFSET ' . $offset; + } else { + $qry .= ' LIMIT ' . $offset . ', ' . $limit; + } + + return Notice::getStream(sprintf($qry, $this->id), + 'notice:conversation:'.$this->id, + $offset, $limit); + } + + function handle($args) + { + $this->showPage(); + } + + function title() + { + return _("Conversation"); + } + + function showContent() + { + // FIXME this needs to be a tree, not a list + + $nl = new NoticeList($this->notices, $this); + + $cnt = $nl->show(); + + $this->pagination($this->page > 1, $cnt > NOTICES_PER_PAGE, + $this->page, 'conversation', array('id' => $this->id)); + } + +} + diff --git a/lib/router.php b/lib/router.php index b18a5523e..4c036e7b2 100644 --- a/lib/router.php +++ b/lib/router.php @@ -143,6 +143,12 @@ class Router array('action' => 'deletenotice'), array('notice' => '[0-9]+')); + // conversation + + $m->connect('conversation/:id', + array('action' => 'conversation'), + array('id' => '[0-9]+')); + $m->connect('message/new', array('action' => 'newmessage')); $m->connect('message/:message', array('action' => 'showmessage'), @@ -265,21 +271,20 @@ class Router 'apiaction' => 'friendships'), array('method' => 'exists(\.(xml|json|rss|atom))')); - // Social graph $m->connect('api/friends/ids/:argument', array('action' => 'api', 'apiaction' => 'statuses', 'method' => 'friendsIDs')); - + foreach (array('xml', 'json') as $e) { $m->connect('api/friends/ids.'.$e, array('action' => 'api', 'apiaction' => 'statuses', 'method' => 'friendsIDs.'.$e)); } - + $m->connect('api/followers/ids/:argument', array('action' => 'api', 'apiaction' => 'statuses', -- cgit v1.2.3-54-g00ecf From f0d3ba2bc2b9a4391a89e343e9dea2622d7d9972 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 28 Feb 2009 17:42:12 -0800 Subject: Add a flag for if there's no config file --- lib/common.php | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index 4fc749ca0..2298c5f88 100644 --- a/lib/common.php +++ b/lib/common.php @@ -178,9 +178,12 @@ if (strlen($_path) > 0) { $_config_files[] = INSTALLDIR.'/config.php'; +$_have_a_config = false; + foreach ($_config_files as $_config_file) { if (file_exists($_config_file)) { include_once($_config_file); + $_have_a_config = true; } } -- cgit v1.2.3-54-g00ecf From b70218dc437c5decc8b27a2bb70e2e1b6ec6e9e3 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 28 Feb 2009 20:32:31 -0800 Subject: automatically handle non-laconica-named databases --- lib/common.php | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib') diff --git a/lib/common.php b/lib/common.php index 2298c5f88..0fff3af2e 100644 --- a/lib/common.php +++ b/lib/common.php @@ -187,6 +187,16 @@ foreach ($_config_files as $_config_file) { } } +// XXX: Throw a conniption if database not installed + +// Fixup for laconica.ini + +$_db_name = substr($config['db']['database'], strrpos($config['db']['database'], '/') + 1); + +if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'])) { + $config['db']['ini_'.$_db_name] = INSTALLDIR.'/classes/laconica.ini'; +} + // XXX: how many of these could be auto-loaded on use? require_once('Validate.php'); -- cgit v1.2.3-54-g00ecf From 7279554681da728deb74a87230de3a1021182f71 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 4 Mar 2009 00:23:34 +0000 Subject: Additional (optional, defaults to off) logging of PEAR error details, which allows database issues to be more easily diagnosed. --- config.php.sample | 3 +++ index.php | 6 +++++- lib/common.php | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/config.php.sample b/config.php.sample index 6e55eaffc..a6cada77a 100644 --- a/config.php.sample +++ b/config.php.sample @@ -34,6 +34,9 @@ $config['site']['path'] = 'laconica'; # If you want logging sent to a file instead of syslog #$config['site']['logfile'] = '/tmp/laconica.log'; +# Enables extra log information, for example full details of PEAR DB errors +#$config['site']['logdebug'] = true; + # This is a PEAR DB DSN, see http://pear.php.net/manual/en/package.database.db.intro-dsn.php # Set it to match your actual database diff --git a/index.php b/index.php index 914ba5bde..03c044415 100644 --- a/index.php +++ b/index.php @@ -43,7 +43,11 @@ function handleError($error) return; } - common_log(LOG_ERR, "PEAR error: " . $error->getMessage()); + $logmsg = "PEAR error: " . $error->getMessage(); + if(common_config('site', 'logdebug')) { + $logmsg .= " : ". $error->getDebugInfo(); + } + common_log(LOG_ERR, $logmsg); $msg = sprintf(_('The database for %s isn\'t responding correctly, '. 'so the site won\'t work properly. '. 'The site admins probably know about the problem, '. diff --git a/lib/common.php b/lib/common.php index 0fff3af2e..3df68d98a 100644 --- a/lib/common.php +++ b/lib/common.php @@ -73,6 +73,7 @@ $config = 'theme' => 'default', 'path' => $_path, 'logfile' => null, + 'logdebug' => false, 'fancy' => false, 'locale_path' => INSTALLDIR.'/locale', 'language' => 'en_US', -- cgit v1.2.3-54-g00ecf From 78a715bc37041a852d9e0eb6dc3e3dc0a0b9e279 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Wed, 4 Mar 2009 05:23:41 +0000 Subject: Hooks for: Public group nav in order to place a list-anchor item at the start or end of the list. --- EVENTS.txt | 7 ++++++- lib/publicgroupnav.php | 28 ++++++++++++++++------------ 2 files changed, 22 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index ed461ee9f..2f33b2d5d 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -88,9 +88,14 @@ StartShowLocalNavBlock: Showing the local nav menu EndShowLocalNavBlock: At the end of the local nav menu - $action: the current action -StartShowHTML: Chance to set document content type, charset, language, DOCTYPE and html element properties +StartShowHTML: Chance to set document headers (e.g., content type, charset, language), DOCTYPE and html element properties - $action: the current action EndShowHTML: Showing after the html element - $action: the current action +StartPublicGroupNav: Showing the public group nav menu +- $action: the current action + +EndPublicGroupNav: At the end of the public group nav menu +- $action: the current action diff --git a/lib/publicgroupnav.php b/lib/publicgroupnav.php index d72475e20..485d25e20 100644 --- a/lib/publicgroupnav.php +++ b/lib/publicgroupnav.php @@ -39,6 +39,7 @@ require_once INSTALLDIR.'/lib/widget.php'; * @category Output * @package Laconica * @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://laconi.ca/ * @@ -73,23 +74,26 @@ class PublicGroupNav extends Widget $this->action->elementStart('ul', array('class' => 'nav')); - $this->out->menuItem(common_local_url('public'), _('Public'), - _('Public timeline'), $action_name == 'public', 'nav_timeline_public'); + if (Event::handle('StartPublicGroupNav', array($this))) { + $this->out->menuItem(common_local_url('public'), _('Public'), + _('Public timeline'), $action_name == 'public', 'nav_timeline_public'); - $this->out->menuItem(common_local_url('groups'), _('Groups'), - _('User groups'), $action_name == 'groups', 'nav_groups'); + $this->out->menuItem(common_local_url('groups'), _('Groups'), + _('User groups'), $action_name == 'groups', 'nav_groups'); - $this->out->menuItem(common_local_url('publictagcloud'), _('Recent tags'), - _('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags'); + $this->out->menuItem(common_local_url('publictagcloud'), _('Recent tags'), + _('Recent tags'), $action_name == 'publictagcloud', 'nav_recent-tags'); - if (count(common_config('nickname', 'featured')) > 0) { - $this->out->menuItem(common_local_url('featured'), _('Featured'), - _('Featured users'), $action_name == 'featured', 'nav_featured'); - } + if (count(common_config('nickname', 'featured')) > 0) { + $this->out->menuItem(common_local_url('featured'), _('Featured'), + _('Featured users'), $action_name == 'featured', 'nav_featured'); + } - $this->out->menuItem(common_local_url('favorited'), _('Popular'), - _("Popular notices"), $action_name == 'favorited', 'nav_timeline_favorited'); + $this->out->menuItem(common_local_url('favorited'), _('Popular'), + _("Popular notices"), $action_name == 'favorited', 'nav_timeline_favorited'); + Event::handle('EndPublicGroupNav', array($this)); + } $this->action->elementEnd('ul'); } } -- cgit v1.2.3-54-g00ecf From c0115bf3bc8957fd2db2dd135ad885ed1b8d6158 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 4 Mar 2009 05:29:21 -0800 Subject: fix pagination links with new URL mapper --- lib/action.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/action.php b/lib/action.php index 9c71a153d..812df635e 100644 --- a/lib/action.php +++ b/lib/action.php @@ -976,17 +976,17 @@ class Action extends HTMLOutputter // lawsuit } if ($have_before) { $pargs = array('page' => $page-1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; $this->elementStart('li', array('class' => 'nav_prev')); - $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'prev'), + $this->element('a', array('href' => common_local_url($action, $args, $pargs), + 'rel' => 'prev'), _('After')); $this->elementEnd('li'); } if ($have_after) { $pargs = array('page' => $page+1); - $newargs = $args ? array_merge($args, $pargs) : $pargs; $this->elementStart('li', array('class' => 'nav_next')); - $this->element('a', array('href' => common_local_url($action, $newargs), 'rel' => 'next'), + $this->element('a', array('href' => common_local_url($action, $args, $pargs), + 'rel' => 'next'), _('Before')); $this->elementEnd('li'); } -- cgit v1.2.3-54-g00ecf From f9babf6a7d4215e763a8c1766a2e6592fe274953 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 4 Mar 2009 06:24:33 -0800 Subject: Check for config file when running When running the full system, check for a config file, and throw an error if none is found. --- index.php | 8 ++++++++ lib/common.php | 6 ++++++ lib/util.php | 6 +++++- 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/index.php b/index.php index 914ba5bde..7f580b836 100644 --- a/index.php +++ b/index.php @@ -61,6 +61,14 @@ function main() { global $user, $action; + if (!_have_config()) { + $msg = sprintf(_("No configuration file found. Try running ". + "the installation program first.")); + $sac = new ServerErrorAction($msg); + $sac->showPage(); + return; + } + // For database errors PEAR::setErrorHandling(PEAR_ERROR_CALLBACK, 'handleError'); diff --git a/lib/common.php b/lib/common.php index 0fff3af2e..ca8dedeef 100644 --- a/lib/common.php +++ b/lib/common.php @@ -187,6 +187,12 @@ foreach ($_config_files as $_config_file) { } } +function _have_config() +{ + global $_have_a_config; + return $_have_a_config; +} + // XXX: Throw a conniption if database not installed // Fixup for laconica.ini diff --git a/lib/util.php b/lib/util.php index 18e4f310c..f9a787d47 100644 --- a/lib/util.php +++ b/lib/util.php @@ -81,7 +81,7 @@ function common_language() // If there is a user logged in and they've set a language preference // then return that one... - if (common_logged_in()) { + if (_have_config() && common_logged_in()) { $user = common_current_user(); $user_language = $user->language; if ($user_language) @@ -315,6 +315,10 @@ function common_current_user() { global $_cur; + if (!_have_config()) { + return null; + } + if ($_cur === false) { if (isset($_REQUEST[session_name()]) || (isset($_SESSION['userid']) && $_SESSION['userid'])) { -- cgit v1.2.3-54-g00ecf From cf4e1872ab8109ea6a3230e43cc70899a17dd075 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 4 Mar 2009 06:27:30 -0800 Subject: Error actions use HTTP code name for title Change the title of error actions to the HTTP code name, like 'internal server error'. --- lib/clienterroraction.php | 15 ++++++++++----- lib/servererroraction.php | 20 ++++++++++++-------- 2 files changed, 22 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/clienterroraction.php b/lib/clienterroraction.php index 5019dc06d..0c48414d5 100644 --- a/lib/clienterroraction.php +++ b/lib/clienterroraction.php @@ -49,7 +49,7 @@ class ClientErrorAction extends ErrorAction function __construct($message='Error', $code=400) { parent::__construct($message, $code); - + $this->status = array(400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', @@ -72,7 +72,7 @@ class ClientErrorAction extends ErrorAction } // XXX: Should these error actions even be invokable via URI? - + function handle($args) { parent::handle($args); @@ -84,11 +84,16 @@ class ClientErrorAction extends ErrorAction } $this->message = $this->trimmed('message'); - + if (!$this->message) { - $this->message = "Client Error $this->code"; - } + $this->message = "Client Error $this->code"; + } $this->showPage(); } + + function title() + { + return $this->status[$this->code]; + } } diff --git a/lib/servererroraction.php b/lib/servererroraction.php index 80a3fdd7b..595dcf147 100644 --- a/lib/servererroraction.php +++ b/lib/servererroraction.php @@ -42,7 +42,7 @@ require_once INSTALLDIR.'/lib/error.php'; * says that 500 errors should be treated similarly to 400 errors, and * it's easier to give an HTML response. Maybe we can customize these * to display some funny animal cartoons. If not, we can probably role - * these classes up into a single class. + * these classes up into a single class. * * See: http://tools.ietf.org/html/rfc2616#section-10 * @@ -57,19 +57,19 @@ class ServerErrorAction extends ErrorAction function __construct($message='Error', $code=500) { parent::__construct($message, $code); - + $this->status = array(500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported'); - + $this->default = 500; } // XXX: Should these error actions even be invokable via URI? - + function handle($args) { parent::handle($args); @@ -81,12 +81,16 @@ class ServerErrorAction extends ErrorAction } $this->message = $this->trimmed('message'); - + if (!$this->message) { - $this->message = "Server Error $this->code"; - } + $this->message = "Server Error $this->code"; + } $this->showPage(); } - + + function title() + { + return $this->status[$this->code]; + } } -- cgit v1.2.3-54-g00ecf From 115519a5e7e84e57656c653918efb39ab4107fe9 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 4 Mar 2009 15:32:26 +0000 Subject: PostgreSQL - made all 'weight' calculating SQL expressions compatible with both databases, and made some GROUP BY queries more explicit about the fields they are selecting, for the same reason. --- actions/favorited.php | 8 +++++++- lib/groupsbymemberssection.php | 2 +- lib/groupsbypostssection.php | 2 +- lib/grouptagcloudsection.php | 8 +++++++- lib/personaltagcloudsection.php | 10 ++++++++-- lib/popularnoticesection.php | 12 +++++++++--- 6 files changed, 33 insertions(+), 9 deletions(-) (limited to 'lib') diff --git a/actions/favorited.php b/actions/favorited.php index fd5ff413c..5082f4a4e 100644 --- a/actions/favorited.php +++ b/actions/favorited.php @@ -169,8 +169,14 @@ class FavoritedAction extends Action function showContent() { + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; + } + $qry = 'SELECT notice.*, '. - 'sum(exp(-(now() - fave.modified) / %s)) as weight ' . + $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . 'GROUP BY fave.notice_id ' . 'ORDER BY weight DESC'; diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php index 4fa07a244..5f26c6626 100644 --- a/lib/groupsbymemberssection.php +++ b/lib/groupsbymemberssection.php @@ -45,7 +45,7 @@ class GroupsByMembersSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.*, count(*) as value ' . + $qry = 'SELECT user_group.id, count(*) as value ' . 'FROM user_group JOIN group_member '. 'ON user_group.id = group_member.group_id ' . 'GROUP BY user_group.id ' . diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php index a5e33a93d..1a60ddb4f 100644 --- a/lib/groupsbypostssection.php +++ b/lib/groupsbypostssection.php @@ -45,7 +45,7 @@ class GroupsByPostsSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.*, count(*) as value ' . + $qry = 'SELECT user_group.id, count(*) as value ' . 'FROM user_group JOIN group_inbox '. 'ON user_group.id = group_inbox.group_id ' . 'GROUP BY user_group.id ' . diff --git a/lib/grouptagcloudsection.php b/lib/grouptagcloudsection.php index f05be85cb..5d68af28b 100644 --- a/lib/grouptagcloudsection.php +++ b/lib/grouptagcloudsection.php @@ -58,8 +58,14 @@ class GroupTagCloudSection extends TagCloudSection function getTags() { + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; + } + $qry = 'SELECT notice_tag.tag, '. - 'sum(exp(-(now() - notice_tag.created)/%s)) as weight ' . + $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'JOIN group_inbox on group_inbox.notice_id = notice.id ' . diff --git a/lib/personaltagcloudsection.php b/lib/personaltagcloudsection.php index 0882822db..978153a84 100644 --- a/lib/personaltagcloudsection.php +++ b/lib/personaltagcloudsection.php @@ -58,8 +58,14 @@ class PersonalTagCloudSection extends TagCloudSection function getTags() { - $qry = 'SELECT notice_tag.tag, '. - 'sum(exp(-(now() - notice_tag.created)/%s)) as weight ' . + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - notice_tag.created)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - notice_tag.created) / %s))'; + } + + $qry = 'SELECT notice_tag.tag, '. + $weightexpr . ' as weight ' . 'FROM notice_tag JOIN notice ' . 'ON notice_tag.notice_id = notice.id ' . 'WHERE notice.profile_id = %d ' . diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index c7c7f0215..f7fb93554 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -48,10 +48,16 @@ class PopularNoticeSection extends NoticeSection { function getNotices() { - $qry = 'SELECT notice.*, '. - 'sum(exp(-(now() - fave.modified) / %s)) as weight ' . + if (common_config('db', 'type') == 'pgsql') { + $weightexpr='sum(exp(-extract(epoch from (now() - fave.modified)) / %s))'; + } else { + $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; + } + + $qry = 'SELECT notice.id, '. + $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . - 'GROUP BY fave.notice_id ' . + 'GROUP BY notice.id ' . 'ORDER BY weight DESC'; $offset = 0; -- cgit v1.2.3-54-g00ecf From a7efd4ff556bbf6bafcfc81db758ab192b8802ad Mon Sep 17 00:00:00 2001 From: CiaranG Date: Wed, 4 Mar 2009 15:34:04 +0000 Subject: Plugins - added a new event (RouterInitialized) which allows a plugin to register new paths to be routed --- EVENTS.txt | 4 ++++ lib/router.php | 2 ++ 2 files changed, 6 insertions(+) (limited to 'lib') diff --git a/EVENTS.txt b/EVENTS.txt index 2f33b2d5d..5edf59245 100644 --- a/EVENTS.txt +++ b/EVENTS.txt @@ -99,3 +99,7 @@ StartPublicGroupNav: Showing the public group nav menu EndPublicGroupNav: At the end of the public group nav menu - $action: the current action + +RouterInitialized: After the router instance has been initialized +- $m: the Net_URL_Mapper that has just been set up + diff --git a/lib/router.php b/lib/router.php index 4b70c0150..d4a4d2ca9 100644 --- a/lib/router.php +++ b/lib/router.php @@ -393,6 +393,8 @@ class Router array('action' => 'showstream'), array('nickname' => '[a-zA-Z0-9]{1,64}')); + Event::handle('RouterInitialized', array($m)); + return $m; } -- cgit v1.2.3-54-g00ecf From 00c358956fcece251b8d78f2c6a41098571472c7 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Wed, 4 Mar 2009 12:07:53 -0800 Subject: check for profile record --- lib/noticesection.php | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'lib') diff --git a/lib/noticesection.php b/lib/noticesection.php index b31f18744..94c2738ef 100644 --- a/lib/noticesection.php +++ b/lib/noticesection.php @@ -73,6 +73,11 @@ class NoticeSection extends Section function showNotice($notice) { $profile = $notice->getProfile(); + if (empty($profile)) { + common_log(LOG_WARNING, sprintf("Notice %d has no profile", + $notice->id)); + return; + } $this->out->elementStart('li', 'hentry notice'); $this->out->elementStart('div', 'entry-title'); $avatar = $profile->getAvatar(AVATAR_MINI_SIZE); -- cgit v1.2.3-54-g00ecf From 36bb33fb1d7b4befe2fb68c2eef0712619359293 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 4 Mar 2009 16:17:40 -0800 Subject: Made /api/account/verify_credentials.format return an extended user object. Updates to status and user API objects. --- actions/twitapiaccount.php | 20 ++++++++++-------- actions/twitapiusers.php | 52 +++++++++++++++++++++++++++++++++------------- lib/router.php | 11 +++++----- lib/twitterapi.php | 41 +++++++++++++++++------------------- 4 files changed, 73 insertions(+), 51 deletions(-) (limited to 'lib') diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php index c19cd370d..68a18cb57 100644 --- a/actions/twitapiaccount.php +++ b/actions/twitapiaccount.php @@ -23,22 +23,24 @@ require_once(INSTALLDIR.'/lib/twitterapi.php'); class TwitapiaccountAction extends TwitterapiAction { - function verify_credentials($args, $apidata) { - if ($apidata['content-type'] == 'xml') { - header('Content-Type: application/xml; charset=utf-8'); - print 'true'; - } elseif ($apidata['content-type'] == 'json') { - header('Content-Type: application/json; charset=utf-8'); - print '{"authorized":true}'; - } else { + parent::handle($args); + + switch ($apidata['content-type']) { + case 'xml': + case 'json': + $action_obj = new TwitapiusersAction(); + $action_obj->prepare($args); + call_user_func(array($action_obj, 'show'), $args, $apidata); + break; + default: header('Content-Type: text/html; charset=utf-8'); print 'Authorized'; } } - function end_session($args, $apidata) + function end_session($args, $apidata) { parent::handle($args); $this->serverError(_('API method under construction.'), $code=501); diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index 8f16e5613..2894b7486 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -25,25 +25,29 @@ class TwitapiusersAction extends TwitterapiAction { function show($args, $apidata) - { + { parent::handle($args); - if (!in_array($apidata['content-type'], array('xml', 'json'))) { + if (!in_array($apidata['content-type'], array('xml', 'json'))) { $this->clientError(_('API method not found!'), $code = 404); return; } - - $this->auth_user = $apidata['user']; + $user = null; $email = $this->arg('email'); + $user_id = $this->arg('user_id'); if ($email) { $user = User::staticGet('email', $email); + } elseif ($user_id) { + $user = $this->get_user($user_id); } elseif (isset($apidata['api_arg'])) { $user = $this->get_user($apidata['api_arg']); - } - - if (!$user) { + } elseif (isset($apidata['user'])) { + $user = $apidata['user']; + } + + if (!$user) { // XXX: Twitter returns a random(?) user instead of throwing and err! -- Zach $this->client_error(_('Not found.'), 404, $apidata['content-type']); return; @@ -74,9 +78,12 @@ class TwitapiusersAction extends TwitterapiAction // Other fields Twitter sends... $twitter_user['profile_background_color'] = ''; + $twitter_user['profile_background_image_url'] = ''; $twitter_user['profile_text_color'] = ''; $twitter_user['profile_link_color'] = ''; $twitter_user['profile_sidebar_fill_color'] = ''; + $twitter_user['profile_sidebar_border_color'] = ''; + $twitter_user['profile_background_tile'] = 'false'; $faves = DB_DataObject::factory('fave'); $faves->user_id = $user->id; @@ -94,18 +101,27 @@ class TwitapiusersAction extends TwitterapiAction $twitter_user['utc_offset'] = $t->format('Z'); $twitter_user['time_zone'] = $timezone; - if (isset($this->auth_user)) { + if (isset($apidata['user'])) { - if ($this->auth_user->isSubscribed($profile)) { + if ($apidata['user']->isSubscribed($profile)) { $twitter_user['following'] = 'true'; } else { $twitter_user['following'] = 'false'; } - - // Not implemented yet - $twitter_user['notifications'] = 'false'; - } - + + // Notifications on? + $sub = Subscription::pkeyGet(array('subscriber' => + $apidata['user']->id, 'subscribed' => $profile->id)); + + if ($sub) { + if ($sub->jabber || $sub->sms) { + $twitter_user['notifications'] = 'true'; + } else { + $twitter_user['notifications'] = 'false'; + } + } + } + if ($apidata['content-type'] == 'xml') { $this->init_document('xml'); $this->show_twitter_xml_user($twitter_user); @@ -114,7 +130,13 @@ class TwitapiusersAction extends TwitterapiAction $this->init_document('json'); $this->show_json_objects($twitter_user); $this->end_document('json'); - } + } else { + + // This is in case 'show' was called via /account/verify_credentials + // without a format (xml or json). + header('Content-Type: text/html; charset=utf-8'); + print 'Authorized'; + } } } diff --git a/lib/router.php b/lib/router.php index 4b70c0150..a36cd2691 100644 --- a/lib/router.php +++ b/lib/router.php @@ -228,14 +228,15 @@ class Router // users - $m->connect('api/users/show/:argument', + $m->connect('api/users/:method/:argument', array('action' => 'api', - 'apiaction' => 'users')); + 'apiaction' => 'users'), + array('method' => 'show(\.(xml|json))?')); $m->connect('api/users/:method', array('action' => 'api', 'apiaction' => 'users'), - array('method' => 'show(\.(xml|json|atom|rss))?')); + array('method' => 'show(\.(xml|json))?')); // direct messages @@ -304,11 +305,11 @@ class Router } // account - + $m->connect('api/account/:method', array('action' => 'api', 'apiaction' => 'account')); - + // favorites $m->connect('api/favorites/:method/:argument', diff --git a/lib/twitterapi.php b/lib/twitterapi.php index a4d183fcd..74f265cbb 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -60,20 +60,34 @@ class TwitterapiAction extends Action function twitter_status_array($notice, $include_user=true) { - $profile = $notice->getProfile(); $twitter_status = array(); $twitter_status['text'] = $notice->content; $twitter_status['truncated'] = 'false'; # Not possible on Laconica $twitter_status['created_at'] = $this->date_twitter($notice->created); - $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? intval($notice->reply_to) : null; + $twitter_status['in_reply_to_status_id'] = ($notice->reply_to) ? + intval($notice->reply_to) : null; $twitter_status['source'] = $this->source_link($notice->source); $twitter_status['id'] = intval($notice->id); - $twitter_status['in_reply_to_user_id'] = ($notice->reply_to) ? $this->replier_by_reply(intval($notice->reply_to)) : null; + + $replier_profile = null; + + if ($notice->reply_to) { + $reply = Notice::staticGet(intval($notice->reply_to)); + if ($reply) { + $replier_profile = $reply->getProfile(); + } + } + + $twitter_status['in_reply_to_user_id'] = + ($replier_profile) ? intval($replier_profile->id) : null; + $twitter_status['in_reply_to_screen_name'] = + ($replier_profile) ? $replier_profile->nickname : null; if (isset($this->auth_user)) { - $twitter_status['favorited'] = ($this->auth_user->hasFave($notice)) ? 'true' : 'false'; + $twitter_status['favorited'] = + ($this->auth_user->hasFave($notice)) ? 'true' : 'false'; } else { $twitter_status['favorited'] = 'false'; } @@ -137,7 +151,6 @@ class TwitterapiAction extends Action function twitter_dmsg_array($message) { - $twitter_dm = array(); $from_profile = $message->getFrom(); @@ -386,23 +399,7 @@ class TwitterapiAction extends Action $t = strtotime($dt); return date("D M d G:i:s O Y", $t); } - - function replier_by_reply($reply_id) - { - $notice = Notice::staticGet($reply_id); - if ($notice) { - $profile = $notice->getProfile(); - if ($profile) { - return intval($profile->id); - } else { - common_debug('Can\'t find a profile for notice: ' . $notice->id, __FILE__); - } - } else { - common_debug("Can't get notice: $reply_id", __FILE__); - } - return null; - } - + // XXX: Candidate for a general utility method somewhere? function count_subscriptions($profile) { -- cgit v1.2.3-54-g00ecf From 38b6946349d39359ce9f4b5ec37967a48e192862 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Wed, 4 Mar 2009 18:14:52 -0800 Subject: Stubs for Twitter-compatible API search methods --- actions/twitapisearch.php | 97 +++++++++++++++++++++++++++++++++++++++++++++++ actions/twitapitrends.php | 90 +++++++++++++++++++++++++++++++++++++++++++ lib/router.php | 20 +++++++--- 3 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 actions/twitapisearch.php create mode 100644 actions/twitapitrends.php (limited to 'lib') diff --git a/actions/twitapisearch.php b/actions/twitapisearch.php new file mode 100644 index 000000000..822ee77e1 --- /dev/null +++ b/actions/twitapisearch.php @@ -0,0 +1,97 @@ +. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/twitterapi.php'; + +/** + * Action handler for Twitter-compatible API search + * + * @category Search + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see TwitterapiAction + */ + +class TwitapisearchAction extends TwitterapiAction +{ + + var $query; + var $limit; + var $callback; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + + function prepare($args) + { + parent::prepare($args); + $qeury = $this->trimmed('query'); + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showResults($this->limit); + } + + /** + * Show search results + * + * @param int $limit Number of notices to show + * + * @return void + */ + + function showResults($limit) + { + $this->serverError(_('API method under construction.'), $code = 501); + } + +} diff --git a/actions/twitapitrends.php b/actions/twitapitrends.php new file mode 100644 index 000000000..c73d89446 --- /dev/null +++ b/actions/twitapitrends.php @@ -0,0 +1,90 @@ +. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/twitterapi.php'; + +/** + * Returns the top ten queries that are currently trending + * + * @category Search + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + * @see TwitterapiAction + */ + +class TwitapitrendsAction extends TwitterapiAction +{ + + var $callback; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + function prepare($args) + { + parent::prepare($args); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showTrends(); + } + + /** + * Output the trends + * + * @return void + */ + function showTrends() + { + $this->serverError(_('API method under construction.'), $code = 501); + } + +} \ No newline at end of file diff --git a/lib/router.php b/lib/router.php index da57f8417..41c376a72 100644 --- a/lib/router.php +++ b/lib/router.php @@ -230,7 +230,7 @@ class Router $m->connect('api/users/:method/:argument', array('action' => 'api', - 'apiaction' => 'users'), + 'apiaction' => 'users'), array('method' => 'show(\.(xml|json))?')); $m->connect('api/users/:method', @@ -284,14 +284,14 @@ class Router array('action' => 'api', 'apiaction' => 'statuses', 'method' => 'friendsIDs')); - + foreach (array('xml', 'json') as $e) { $m->connect('api/friends/ids.'.$e, array('action' => 'api', 'apiaction' => 'statuses', 'method' => 'friendsIDs.'.$e)); } - + $m->connect('api/followers/ids/:argument', array('action' => 'api', 'apiaction' => 'statuses', @@ -305,11 +305,11 @@ class Router } // account - + $m->connect('api/account/:method', array('action' => 'api', 'apiaction' => 'account')); - + // favorites $m->connect('api/favorites/:method/:argument', @@ -352,6 +352,16 @@ class Router array('action' => 'api', 'apiaction' => 'laconica')); + + // search + + foreach (array('json', 'atom') as $e) { + $m->connect('api/search.'.$e, + array('action' => 'twitapisearch')); + } + + $m->connect('api/trends.json', array('action' => 'twitapitrends')); + // user stuff foreach (array('subscriptions', 'subscribers', -- cgit v1.2.3-54-g00ecf From 0c066db428843a6ca969c8523f0be2bcdfa278f7 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Thu, 5 Mar 2009 14:35:50 +0000 Subject: Undo my previous change that breaks the Popular Notices section on the public timeline under MySQL --- lib/popularnoticesection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index f7fb93554..cbf458c34 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -54,7 +54,7 @@ class PopularNoticeSection extends NoticeSection $weightexpr='sum(exp(-(now() - fave.modified) / %s))'; } - $qry = 'SELECT notice.id, '. + $qry = 'SELECT notice.*, '. $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . 'GROUP BY notice.id ' . -- cgit v1.2.3-54-g00ecf From ea0c5f565c9ca4b34c1071a51333f0f842a954b9 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Thu, 5 Mar 2009 14:52:35 +0000 Subject: The correct version of the bad fix I undid in the previous commit. Must explicitly specify all relevant columns in the GROUP BY. --- lib/popularnoticesection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/popularnoticesection.php b/lib/popularnoticesection.php index cbf458c34..0505f0fa9 100644 --- a/lib/popularnoticesection.php +++ b/lib/popularnoticesection.php @@ -57,7 +57,9 @@ class PopularNoticeSection extends NoticeSection $qry = 'SELECT notice.*, '. $weightexpr . ' as weight ' . 'FROM notice JOIN fave ON notice.id = fave.notice_id ' . - 'GROUP BY notice.id ' . + 'GROUP BY notice.id,notice.profile_id,notice.content,notice.uri,' . + 'notice.rendered,notice.url,notice.created,notice.modified,' . + 'notice.reply_to,notice.is_local,notice.source ' . 'ORDER BY weight DESC'; $offset = 0; -- cgit v1.2.3-54-g00ecf From 3087e4ad5dfbccb7218c12ca747e1dbcf3a6415c Mon Sep 17 00:00:00 2001 From: CiaranG Date: Thu, 5 Mar 2009 16:23:39 +0000 Subject: Fixed bad field name in oauthstore. (fix submitted by oxygene) --- lib/oauthstore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/oauthstore.php b/lib/oauthstore.php index 7ad3be20e..9af05ea2d 100644 --- a/lib/oauthstore.php +++ b/lib/oauthstore.php @@ -63,7 +63,7 @@ class LaconicaOAuthDataStore extends OAuthDataStore if ($n->find(true)) { return true; } else { - $n->timestamp = $timestamp; + $n->ts = $timestamp; $n->created = DB_DataObject_Cast::dateTime(); $n->insert(); return false; -- cgit v1.2.3-54-g00ecf From b9781258bbfaac0e7fc91af4f77f1f340274a88e Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Thu, 5 Mar 2009 11:03:42 -0800 Subject: @-links go to permalinks for local users --- lib/util.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/util.php b/lib/util.php index f9a787d47..167508d2b 100644 --- a/lib/util.php +++ b/lib/util.php @@ -622,9 +622,15 @@ function common_at_link($sender_id, $nickname) $sender = Profile::staticGet($sender_id); $recipient = common_relative_profile($sender, common_canonical_nickname($nickname)); if ($recipient) { + $user = User::staticGet('id', $recipient->id); + if ($user) { + $url = common_local_url('userbyid', array('id' => $user->id)); + } else { + $url = $recipient->profileurl; + } $xs = new XMLStringer(false); $xs->elementStart('span', 'vcard'); - $xs->elementStart('a', array('href' => $recipient->profileurl, + $xs->elementStart('a', array('href' => $url, 'class' => 'url')); $xs->element('span', 'fn nickname', $nickname); $xs->elementEnd('a'); -- cgit v1.2.3-54-g00ecf From 896f0340bf3710b79b117236e940b487a4b56460 Mon Sep 17 00:00:00 2001 From: CiaranG Date: Fri, 6 Mar 2009 19:28:15 +0000 Subject: Fixed problem with group lists not display all details - broken (by me) in 115519a5e7e84e57656c653918efb39ab4107fe9 --- lib/groupsbymemberssection.php | 4 ++-- lib/groupsbypostssection.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/groupsbymemberssection.php b/lib/groupsbymemberssection.php index 5f26c6626..963e21f15 100644 --- a/lib/groupsbymemberssection.php +++ b/lib/groupsbymemberssection.php @@ -45,10 +45,10 @@ class GroupsByMembersSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.id, count(*) as value ' . + $qry = 'SELECT user_group.*, count(*) as value ' . 'FROM user_group JOIN group_member '. 'ON user_group.id = group_member.group_id ' . - 'GROUP BY user_group.id ' . + 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' . 'ORDER BY value DESC '; $limit = GROUPS_PER_SECTION; diff --git a/lib/groupsbypostssection.php b/lib/groupsbypostssection.php index 1a60ddb4f..325b4033f 100644 --- a/lib/groupsbypostssection.php +++ b/lib/groupsbypostssection.php @@ -45,10 +45,10 @@ class GroupsByPostsSection extends GroupSection { function getGroups() { - $qry = 'SELECT user_group.id, count(*) as value ' . + $qry = 'SELECT user_group.*, count(*) as value ' . 'FROM user_group JOIN group_inbox '. 'ON user_group.id = group_inbox.group_id ' . - 'GROUP BY user_group.id ' . + 'GROUP BY user_group.id,user_group.nickname,user_group.fullname,user_group.homepage,user_group.description,user_group.location,user_group.original_logo,user_group.homepage_logo,user_group.stream_logo,user_group.mini_logo,user_group.created,user_group.modified ' . 'ORDER BY value DESC '; $limit = GROUPS_PER_SECTION; -- cgit v1.2.3-54-g00ecf From b1f337fe018dd3910c68589a98b0242470743a4c Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 6 Mar 2009 13:33:47 -0800 Subject: First crack at Twitter-like JSON search results for the API --- actions/twitapisearch.php | 97 ---------------- actions/twitapisearchjson.php | 149 ++++++++++++++++++++++++ lib/jsonsearchresultslist.php | 259 ++++++++++++++++++++++++++++++++++++++++++ lib/router.php | 10 +- lib/twitterapi.php | 28 ++++- 5 files changed, 436 insertions(+), 107 deletions(-) delete mode 100644 actions/twitapisearch.php create mode 100644 actions/twitapisearchjson.php create mode 100644 lib/jsonsearchresultslist.php (limited to 'lib') diff --git a/actions/twitapisearch.php b/actions/twitapisearch.php deleted file mode 100644 index 822ee77e1..000000000 --- a/actions/twitapisearch.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * - * @category Search - * @package Laconica - * @author Zach Copley - * @copyright 2008-2009 Control Yourself, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - */ - -if (!defined('LACONICA')) { - exit(1); -} - -require_once INSTALLDIR.'/lib/twitterapi.php'; - -/** - * Action handler for Twitter-compatible API search - * - * @category Search - * @package Laconica - * @author Zach Copley - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 - * @link http://laconi.ca/ - * @see TwitterapiAction - */ - -class TwitapisearchAction extends TwitterapiAction -{ - - var $query; - var $limit; - var $callback; - - /** - * Initialization. - * - * @param array $args Web and URL arguments - * - * @return boolean false if user doesn't exist - */ - - function prepare($args) - { - parent::prepare($args); - $qeury = $this->trimmed('query'); - - return true; - } - - /** - * Handle a request - * - * @param array $args Arguments from $_REQUEST - * - * @return void - */ - - function handle($args) - { - parent::handle($args); - $this->showResults($this->limit); - } - - /** - * Show search results - * - * @param int $limit Number of notices to show - * - * @return void - */ - - function showResults($limit) - { - $this->serverError(_('API method under construction.'), $code = 501); - } - -} diff --git a/actions/twitapisearchjson.php b/actions/twitapisearchjson.php new file mode 100644 index 000000000..b50aa86b7 --- /dev/null +++ b/actions/twitapisearchjson.php @@ -0,0 +1,149 @@ +. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +require_once INSTALLDIR.'/lib/twitterapi.php'; +require_once INSTALLDIR.'/lib/jsonsearchresultslist.php'; + +/** + * Action handler for Twitter-compatible API search + * + * @category Search + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see TwitterapiAction + */ + +class TwitapisearchjsonAction extends TwitterapiAction +{ + var $query; + var $lang; + var $rpp; + var $page; + var $since_id; + var $limit; + var $geocode; + + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean true if nothing goes wrong + */ + + function prepare($args) + { + parent::prepare($args); + + $this->query = $this->trimmed('q'); + $this->lang = $this->trimmed('lang'); + $this->rpp = $this->trimmed('rpp'); + + if (!$this->rpp) { + $this->rpp = 15; + } + + if ($this->rpp > 100) { + $this->rpp = 100; + } + + $this->page = $this->trimmed('page'); + + if (!$this->page) { + $this->page = 1; + } + + $this->since_id = $this->trimmed('since_id'); + $this->geocode = $this->trimmed('geocode'); + + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + + function handle($args) + { + parent::handle($args); + $this->showResults(); + } + + /** + * Show search results + * + * @return void + */ + + function showResults() + { + + // TODO: Support search operators like from: and to: + + $notice = new Notice(); + + // lcase it for comparison + $q = strtolower($this->query); + + $search_engine = $notice->getSearchEngine('identica_notices'); + $search_engine->set_sort_mode('chron'); + $search_engine->limit(($this->page - 1) * $this->rpp, $this->rpp + 1, true); + $search_engine->query($q); + $cnt = $notice->find(); + + // TODO: since_id, lang, geocode + + $results = new JSONSearchResultsList($notice, $q, $this->rpp, $this->page); + + $this->init_document('json'); + $results->show(); + $this->end_document('json'); + } + + /** + * This is a read-only action + * + * @return boolean true + */ + + function isReadOnly() + { + return true; + } +} \ No newline at end of file diff --git a/lib/jsonsearchresultslist.php b/lib/jsonsearchresultslist.php new file mode 100644 index 000000000..171e1db4d --- /dev/null +++ b/lib/jsonsearchresultslist.php @@ -0,0 +1,259 @@ +. + * + * @category Search + * @package Laconica + * @author Zach Copley + * @copyright 2008-2009 Control Yourself, Inc. + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + */ + +if (!defined('LACONICA')) { + exit(1); +} + +/** + * widget-like class for showing JSON search results + * + * @category Search + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * + */ + +class JSONSearchResultsList +{ + protected $notice; // protected attrs invisible to json_encode() + protected $rpp; + + // The below attributes are carefully named so the JSON output from + // this obj matches the output from search.twitter.com + + var $results; + var $since_id; + var $max_id; + var $refresh_url; + var $results_per_page; + var $completed_in; + var $page; + var $query; + + /** + * constructor + * + * @param Notice $notice stream of notices from DB_DataObject + */ + + function __construct($notice, $query, $rpp, $page, $since_id = 0) + { + $this->notice = $notice; + $this->query = urlencode($query); + $this->results_per_page = $this->rpp = $rpp; + $this->page = $page; + $this->since_id = $since_id; + $this->results = array(); + } + + /** + * show the list of search results + * + * @return int count of the search results listed. + */ + + function show() + { + $cnt = 0; + + $time_start = microtime(true); + + while ($this->notice->fetch() && $cnt <= $this->rpp) { + $cnt++; + + // XXX: Hmmm. this depends on desc sort order + if (!$this->max_id) { + $this->max_id = (int)$this->notice->id; + } + + if ($cnt > $this->rpp) { + break; + } + + $item = new ResultItem($this->notice); + array_push($this->results, $item); + } + + $time_end = microtime(true); + $this->completed_in = $time_end - $time_start; + + // Set other attrs + + $this->refresh_url = '?since_id=' . $this->max_id . + '&q=' . $this->query; + + // pagination stuff + + if ($cnt > $this->rpp) { + $this->next_page = '?page=' . ($this->page + 1) . + '&max_id=' . $this->max_id; + if ($this->rpp != 15) { + $this->next_page .= '&rpp=' . $this->rpp; + } + $this->next_page .= '&q=' . $this->query; + } + + if ($this->page > 1) { + $this->previous_page = '?page=' . ($this->page - 1) . + '&max_id=' . $this->max_id; + if ($this->rpp != 15) { + $this->previous_page .= '&rpp=' . $this->rpp; + } + $this->previous_page .= '&q=' . $this->query; + } + + print json_encode($this); + + return $cnt; + } +} + +/** + * widget for displaying a single JSON search result + * + * @category UI + * @package Laconica + * @author Zach Copley + * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0 + * @link http://laconi.ca/ + * @see JSONSearchResultsList + */ + +class ResultItem +{ + /** The notice this item is based on. */ + + protected $notice; // protected attrs invisible to json_encode() + + /** The profile associated with the notice. */ + + protected $profile; + + // The below attributes are carefully named so the JSON output from + // this obj matches the output from search.twitter.com + + var $text; + var $to_user_id; + var $to_user; + var $from_user; + var $id; + var $from_user_id; + var $iso_language_code; + var $source; + var $profile_image_url; + var $created_at; + + /** + * constructor + * + * Also initializes the profile attribute. + * + * @param Notice $notice The notice we'll display + */ + + function __construct($notice) + { + $this->notice = $notice; + $this->profile = $notice->getProfile(); + $this->buildResult(); + } + + /** + * Build a search result object + * + * This populates the the result in preparation for JSON encoding. + * + * @return void + */ + + function buildResult() + { + $this->text = $this->notice->content; + $replier_profile = null; + + if ($this->notice->reply_to) { + $reply = Notice::staticGet(intval($notice->reply_to)); + if ($reply) { + $replier_profile = $reply->getProfile(); + } + } + + $this->to_user_id = ($replier_profile) ? + intval($replier_profile->id) : null; + $this->to_user = ($replier_profile) ? + $replier_profile->nickname : null; + $this->from_user = $this->profile->nickname; + $this->id = $this->notice->id; + $this->from_user_id = $this->profile->id; + + $user = User::staticGet('id', $this->profile->id); + $this->iso_language_code = $this->user->language; + + $this->source = $this->getSourceLink($this->notice->source); + + $avatar = $this->profile->getAvatar(AVATAR_STREAM_SIZE); + $this->profile_image_url = ($avatar) ? + $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE); + + $this->created_at = date('r', $this->notice->created); + } + + /** + * Show the source of the notice + * + * Either the name (and link) of the API client that posted the notice, + * or one of other other channels. + * + * @return string the source of the Notice + */ + + function getSourceLink($source) + { + $source_name = _($source); + switch ($source) { + case 'web': + case 'xmpp': + case 'mail': + case 'omb': + case 'api': + break; + default: + $ns = Notice_source::staticGet($source); + if ($ns) { + $source_name = '' . $ns->name . ''; + } + break; + } + return $source_name; + } + +} diff --git a/lib/router.php b/lib/router.php index 41c376a72..516b48122 100644 --- a/lib/router.php +++ b/lib/router.php @@ -354,17 +354,13 @@ class Router // search - - foreach (array('json', 'atom') as $e) { - $m->connect('api/search.'.$e, - array('action' => 'twitapisearch')); - } - + $m->connect('api/search.atom', array('action' => 'twitapisearchatom')); + $m->connect('api/search.json', array('action' => 'twitapisearchjson')); $m->connect('api/trends.json', array('action' => 'twitapitrends')); // user stuff - foreach (array('subscriptions', 'subscribers', + foreach (array('subscriptions', 'subscribers', 'nudge', 'xrds', 'all', 'foaf', 'replies', 'inbox', 'outbox', 'microsummary') as $a) { $m->connect(':nickname/'.$a, diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 74f265cbb..1de169a0b 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -24,11 +24,33 @@ class TwitterapiAction extends Action var $auth_user; + /** + * Initialization. + * + * @param array $args Web and URL arguments + * + * @return boolean false if user doesn't exist + */ + + function prepare($args) + { + parent::prepare($args); + return true; + } + + /** + * Handle a request + * + * @param array $args Arguments from $_REQUEST + * + * @return void + */ + function handle($args) { parent::handle($args); } - + function twitter_user_array($profile, $get_notice=false) { @@ -86,7 +108,7 @@ class TwitterapiAction extends Action ($replier_profile) ? $replier_profile->nickname : null; if (isset($this->auth_user)) { - $twitter_status['favorited'] = + $twitter_status['favorited'] = ($this->auth_user->hasFave($notice)) ? 'true' : 'false'; } else { $twitter_status['favorited'] = 'false'; @@ -399,7 +421,7 @@ class TwitterapiAction extends Action $t = strtotime($dt); return date("D M d G:i:s O Y", $t); } - + // XXX: Candidate for a general utility method somewhere? function count_subscriptions($profile) { -- cgit v1.2.3-54-g00ecf