From 5f2cf2553cbe97b9983c8c5d0a85abb00b1a8375 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 02:23:19 +0000 Subject: Ticket #1196 - Fixed: Warning on invite tab in Facebook App --- actions/facebookinvite.php | 65 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'actions') diff --git a/actions/facebookinvite.php b/actions/facebookinvite.php index 1302064ad..2207580f7 100644 --- a/actions/facebookinvite.php +++ b/actions/facebookinvite.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/facebookaction.php'); @@ -67,7 +69,7 @@ class FacebookinviteAction extends FacebookAction function showSuccessContent() { - $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), + $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), common_config('site', 'name'))); $this->element('p', null, _('Invitations have been sent to the following users:')); @@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction function showFormContent() { - - // Get a list of users who are already using the app for exclusion - $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); - $exclude_ids_csv = null; - - // fbml needs these as a csv string, not an array - if ($exclude_ids) { - $exclude_ids_csv = implode(',', $exclude_ids); - } - $content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) . htmlentities(''); @@ -109,36 +101,43 @@ class FacebookinviteAction extends FacebookAction 'content' => $content)); $this->hidden('invite', 'true'); $actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name')); - - $multi_params = array('showborder' => 'false'); + + $multi_params = array('showborder' => 'false'); $multi_params['actiontext'] = $actiontext; - - if ($exclude_ids_csv) { + $multi_params['bypass'] = 'cancel'; + + // Get a list of users who are already using the app for exclusion + $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); + $exclude_ids_csv = null; + + // fbml needs these as a csv string, not an array + if ($exclude_ids) { + $exclude_ids_csv = implode(',', $exclude_ids); $multi_params['exclude_ids'] = $exclude_ids_csv; } - $multi_params['bypass'] = 'cancel'; - $this->element('fb:multi-friend-selector', $multi_params); - $this->elementEnd('fb:request-form'); - $this->element('h2', null, sprintf(_('Friends already using %s:'), - common_config('site', 'name'))); - $this->elementStart('ul', array('id' => 'facebook-friends')); - - foreach ($exclude_ids as $friend) { - $this->elementStart('li'); - $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); - $this->element('fb:name', array('uid' => $friend, - 'capitalize' => 'true')); - $this->elementEnd('li'); - } + if ($exclude_ids) { - $this->elementEnd("ul"); + $this->element('h2', null, sprintf(_('Friends already using %s:'), + common_config('site', 'name'))); + $this->elementStart('ul', array('id' => 'facebook-friends')); + + foreach ($exclude_ids as $friend) { + $this->elementStart('li'); + $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); + $this->element('fb:name', array('uid' => $friend, + 'capitalize' => 'true')); + $this->elementEnd('li'); + } + + $this->elementEnd("ul"); + } } - - function title() + + function title() { return sprintf(_('Send invitations')); } -- cgit v1.2.3-54-g00ecf From b2c28faf526e55ddc97d42692048e644b004e1f8 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 21:14:42 +0000 Subject: Removed silly "dented:" status prefix from Facebook App --- actions/facebookhome.php | 3 --- 1 file changed, 3 deletions(-) (limited to 'actions') diff --git a/actions/facebookhome.php b/actions/facebookhome.php index 5946e6c98..4c2b26355 100644 --- a/actions/facebookhome.php +++ b/actions/facebookhome.php @@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction function setDefaults() { - // A default prefix string for notices - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_NOTICE_PREFIX, 'dented: '); $this->facebook->api_client->data_setUserPreference( FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); } -- cgit v1.2.3-54-g00ecf From 0a4ce0ef9938ba91ff3d9286ea2cffb4cebd528b Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 02:23:19 +0000 Subject: Ticket #1196 - Fixed: Warning on invite tab in Facebook App --- actions/facebookinvite.php | 65 +++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'actions') diff --git a/actions/facebookinvite.php b/actions/facebookinvite.php index 1302064ad..2207580f7 100644 --- a/actions/facebookinvite.php +++ b/actions/facebookinvite.php @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -if (!defined('LACONICA')) { exit(1); } +if (!defined('LACONICA')) { + exit(1); +} require_once(INSTALLDIR.'/lib/facebookaction.php'); @@ -67,7 +69,7 @@ class FacebookinviteAction extends FacebookAction function showSuccessContent() { - $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), + $this->element('h2', null, sprintf(_('Thanks for inviting your friends to use %s'), common_config('site', 'name'))); $this->element('p', null, _('Invitations have been sent to the following users:')); @@ -89,16 +91,6 @@ class FacebookinviteAction extends FacebookAction function showFormContent() { - - // Get a list of users who are already using the app for exclusion - $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); - $exclude_ids_csv = null; - - // fbml needs these as a csv string, not an array - if ($exclude_ids) { - $exclude_ids_csv = implode(',', $exclude_ids); - } - $content = sprintf(_('You have been invited to %s'), common_config('site', 'name')) . htmlentities(''); @@ -109,36 +101,43 @@ class FacebookinviteAction extends FacebookAction 'content' => $content)); $this->hidden('invite', 'true'); $actiontext = sprintf(_('Invite your friends to use %s'), common_config('site', 'name')); - - $multi_params = array('showborder' => 'false'); + + $multi_params = array('showborder' => 'false'); $multi_params['actiontext'] = $actiontext; - - if ($exclude_ids_csv) { + $multi_params['bypass'] = 'cancel'; + + // Get a list of users who are already using the app for exclusion + $exclude_ids = $this->facebook->api_client->friends_getAppUsers(); + $exclude_ids_csv = null; + + // fbml needs these as a csv string, not an array + if ($exclude_ids) { + $exclude_ids_csv = implode(',', $exclude_ids); $multi_params['exclude_ids'] = $exclude_ids_csv; } - $multi_params['bypass'] = 'cancel'; - $this->element('fb:multi-friend-selector', $multi_params); - $this->elementEnd('fb:request-form'); - $this->element('h2', null, sprintf(_('Friends already using %s:'), - common_config('site', 'name'))); - $this->elementStart('ul', array('id' => 'facebook-friends')); - - foreach ($exclude_ids as $friend) { - $this->elementStart('li'); - $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); - $this->element('fb:name', array('uid' => $friend, - 'capitalize' => 'true')); - $this->elementEnd('li'); - } + if ($exclude_ids) { - $this->elementEnd("ul"); + $this->element('h2', null, sprintf(_('Friends already using %s:'), + common_config('site', 'name'))); + $this->elementStart('ul', array('id' => 'facebook-friends')); + + foreach ($exclude_ids as $friend) { + $this->elementStart('li'); + $this->element('fb:profile-pic', array('uid' => $friend, 'size' => 'square')); + $this->element('fb:name', array('uid' => $friend, + 'capitalize' => 'true')); + $this->elementEnd('li'); + } + + $this->elementEnd("ul"); + } } - - function title() + + function title() { return sprintf(_('Send invitations')); } -- cgit v1.2.3-54-g00ecf From 0664be924f5f24de0e63d63ea78a56d798a67362 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 21:14:42 +0000 Subject: Removed silly "dented:" status prefix from Facebook App --- actions/facebookhome.php | 3 --- 1 file changed, 3 deletions(-) (limited to 'actions') diff --git a/actions/facebookhome.php b/actions/facebookhome.php index 5946e6c98..4c2b26355 100644 --- a/actions/facebookhome.php +++ b/actions/facebookhome.php @@ -138,9 +138,6 @@ class FacebookhomeAction extends FacebookAction function setDefaults() { - // A default prefix string for notices - $this->facebook->api_client->data_setUserPreference( - FACEBOOK_NOTICE_PREFIX, 'dented: '); $this->facebook->api_client->data_setUserPreference( FACEBOOK_PROMPTED_UPDATE_PREF, 'false'); } -- cgit v1.2.3-54-g00ecf From 69a656af2210acf9211aa4fcb1c05bfd5c5a2e1f Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 23:21:10 +0000 Subject: Some adjustments to allow the Facebook app work with Laconica 0.8 --- actions/facebookhome.php | 2 +- lib/facebookaction.php | 262 ++++++++++++++++++++--------------------------- 2 files changed, 110 insertions(+), 154 deletions(-) (limited to 'actions') diff --git a/actions/facebookhome.php b/actions/facebookhome.php index 4c2b26355..00b35ef68 100644 --- a/actions/facebookhome.php +++ b/actions/facebookhome.php @@ -115,7 +115,7 @@ class FacebookhomeAction extends FacebookAction $flink->foreign_id = $this->fbuid; $flink->service = FACEBOOK_SERVICE; $flink->created = common_sql_now(); - $flink->set_flags(true, false, false); + $flink->set_flags(true, false, false, false); $flink_id = $flink->insert(); diff --git a/lib/facebookaction.php b/lib/facebookaction.php index 637a6284d..a445750f7 100644 --- a/lib/facebookaction.php +++ b/lib/facebookaction.php @@ -38,14 +38,14 @@ require_once INSTALLDIR.'/lib/noticeform.php'; class FacebookAction extends Action { - + var $facebook = null; var $fbuid = null; var $flink = null; var $action = null; var $app_uri = null; var $app_name = null; - + /** * Constructor * @@ -60,71 +60,71 @@ class FacebookAction extends Action function __construct($output='php://output', $indent=true, $facebook=null, $flink=null) { parent::__construct($output, $indent); - + $this->facebook = $facebook; $this->flink = $flink; - + if ($this->flink) { - $this->fbuid = $flink->foreign_id; + $this->fbuid = $flink->foreign_id; $this->user = $flink->getUser(); } - + $this->args = array(); } - + function prepare($argarray) - { + { parent::prepare($argarray); - + $this->facebook = getFacebook(); $this->fbuid = $this->facebook->require_login(); - + $this->action = $this->trimmed('action'); - + $app_props = $this->facebook->api_client->Admin_getAppProperties( array('canvas_name', 'application_name')); - + $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; $this->app_name = $app_props['application_name']; $this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE); - + return true; - + } - + function showStylesheets() { // Add a timestamp to the file so Facebook cache wont ignore our changes $ts = filemtime(INSTALLDIR.'/theme/base/css/display.css'); - $this->element('link', array('rel' => 'stylesheet', - 'type' => 'text/css', - 'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts)); - + $this->element('link', array('rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => theme_path('css/display.css', 'base') . '?ts=' . $ts)); + $theme = common_config('site', 'theme'); - + $ts = filemtime(INSTALLDIR. '/theme/' . $theme .'/css/display.css'); - + $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/display.css', null) . '?ts=' . $ts)); - + $ts = filemtime(INSTALLDIR.'/theme/base/css/facebookapp.css'); - + $this->element('link', array('rel' => 'stylesheet', 'type' => 'text/css', 'href' => theme_path('css/facebookapp.css', 'base') . '?ts=' . $ts)); } - + function showScripts() { // Add a timestamp to the file so Facebook cache wont ignore our changes $ts = filemtime(INSTALLDIR.'/js/facebookapp.js'); - + $this->element('script', array('src' => common_path('js/facebookapp.js') . '?ts=' . $ts)); } - + /** * Start an Facebook ready HTML document * @@ -138,11 +138,11 @@ class FacebookAction extends Action * @return void */ - function startHTML($type=null) - { + function startHTML($type=null) + { $this->showStylesheets(); $this->showScripts(); - + $this->elementStart('div', array('class' => 'facebook-page')); } @@ -177,18 +177,18 @@ class FacebookAction extends Action $this->showFooter(); $this->elementEnd('div'); } - + function showAside() { } function showHead($error, $success) { - + if ($error) { $this->element("h1", null, $error); } - + if ($success) { $this->element("h1", null, $success); } @@ -198,10 +198,10 @@ class FacebookAction extends Action $this->element('fb:add-section-button', array('section' => 'profile')); $this->elementEnd('span'); $this->elementEnd('fb:if-section-not-added'); - + } - + // Make this into a widget later function showLocalNav() { @@ -229,8 +229,8 @@ class FacebookAction extends Action $this->elementEnd('li'); $this->elementEnd('ul'); - } - + } + /** * Show header of the page. * @@ -245,7 +245,7 @@ class FacebookAction extends Action $this->showNoticeForm(); $this->elementEnd('div'); } - + /** * Show page, a template method. * @@ -258,7 +258,7 @@ class FacebookAction extends Action $this->showBody(); $this->endHTML(); } - + function showInstructions() { @@ -278,7 +278,7 @@ class FacebookAction extends Action $this->element('a', array('href' => common_local_url('register')), _('Register')); $this->text($loginmsg_part2); - $this->elementEnd('p'); + $this->elementEnd('p'); $this->elementEnd('dd'); $this->elementEnd('dl'); @@ -317,7 +317,7 @@ class FacebookAction extends Action $this->elementEnd('ul'); $this->submit('submit', _('Login')); - $this->elementEnd('fieldset'); + $this->elementEnd('fieldset'); $this->elementEnd('form'); $this->elementStart('p'); @@ -329,73 +329,73 @@ class FacebookAction extends Action $this->elementEnd('div'); } - - + + function updateProfileBox($notice) { // Need to include inline CSS for styling the Profile box - $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); - $icon_url = $app_props['icon_url']; + $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url')); + $icon_url = $app_props['icon_url']; $style = ''; + #facebook_laconica_app { + text-indent:-9999px; + height:16px; + width:16px; + display:block; + background:url('.$icon_url.') no-repeat 0 0; + float:right; + } + '; $this->xw->openMemory(); @@ -407,12 +407,12 @@ class FacebookAction extends Action $fbml_main = "$style " . $this->xw->outputMemory(false) . ""; - $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); + $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main); $this->xw->openURI('php://output'); } - - + + /** * Generate pagination links * @@ -457,24 +457,24 @@ class FacebookAction extends Action $this->elementEnd('div'); } } - - function updateFacebookStatus($notice) + + function updateFacebookStatus($notice) { $prefix = $this->facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $this->fbuid); $content = "$prefix $notice->content"; - + if ($this->facebook->api_client->users_hasAppPermission('status_update', $this->fbuid)) { $this->facebook->api_client->users_setStatus($content, $this->fbuid, false, true); } } - + function saveNewNotice() { $user = $this->flink->getUser(); $content = $this->trimmed('status_textarea'); - + if (!$content) { $this->showPage(_('No notice content!')); return; @@ -492,9 +492,9 @@ class FacebookAction extends Action $cmd = $inter->handle_command($user, $content_shortened); if ($cmd) { - + // XXX fix this - + $cmd->execute(new WebChannel()); return; } @@ -510,20 +510,20 @@ class FacebookAction extends Action } common_broadcast_notice($notice); - + // Also update the user's Facebook status $this->updateFacebookStatus($notice); $this->updateProfileBox($notice); - + } } -class FacebookNoticeForm extends NoticeForm +class FacebookNoticeForm extends NoticeForm { - + var $post_action = null; - + /** * Constructor * @@ -532,13 +532,13 @@ class FacebookNoticeForm extends NoticeForm * @param string $content content to pre-fill */ - function __construct($out=null, $action=null, $content=null, + function __construct($out=null, $action=null, $content=null, $post_action=null, $user=null) { parent::__construct($out, $action, $content, $user); $this->post_action = $post_action; } - + /** * Action of the form * @@ -554,7 +554,7 @@ class FacebookNoticeForm extends NoticeForm class FacebookNoticeList extends NoticeList { - + /** * constructor * @@ -565,7 +565,7 @@ class FacebookNoticeList extends NoticeList { parent::__construct($notice, $out); } - + /** * show the list of notices * @@ -619,7 +619,7 @@ class FacebookNoticeList extends NoticeList } class FacebookNoticeListItem extends NoticeListItem -{ +{ /** * constructor @@ -646,51 +646,19 @@ class FacebookNoticeListItem extends NoticeListItem function show() { $this->showStart(); + $this->showNotice(); + $this->showNoticeInfo(); - $this->out->elementStart('div', 'entry-title'); - $this->showAuthor(); - $this->showContent(); - $this->out->elementEnd('div'); - - $this->out->elementStart('div', 'entry-content'); - $this->showNoticeLink(); - $this->showNoticeSource(); - $this->showReplyTo(); - $this->out->elementEnd('div'); + // XXX: Need to update to show attachements and controls $this->showEnd(); } - function showNoticeLink() - { - $noticeurl = common_local_url('shownotice', - array('notice' => $this->notice->id)); - // XXX: we need to figure this out better. Is this right? - if (strcmp($this->notice->uri, $noticeurl) != 0 && - preg_match('/^http/', $this->notice->uri)) { - $noticeurl = $this->notice->uri; - } - - $this->out->elementStart('dl', 'timestamp'); - $this->out->element('dt', null, _('Published')); - $this->out->elementStart('dd', null); - $this->out->elementStart('a', array('rel' => 'bookmark', - 'href' => $noticeurl)); - $dt = common_date_iso8601($this->notice->created); - $this->out->element('abbr', array('class' => 'published', - 'title' => $dt), - common_date_string($this->notice->created)); - $this->out->elementEnd('a'); - $this->out->elementEnd('dd'); - $this->out->elementEnd('dl'); - } - } - class FacebookProfileBoxNotice extends FacebookNoticeListItem -{ - +{ + /** * constructor * @@ -703,36 +671,24 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem { parent::__construct($notice, $out); } - + /** - * Recipe function for displaying a single notice in the - * Facebook App's Profile + * Recipe function for displaying a single notice in the + * Facebook App profile notice box * * @return void */ function show() { - - $this->out->elementStart('div', 'entry-title'); - $this->showAuthor(); - $this->showContent(); - $this->out->elementEnd('div'); - - $this->out->elementStart('div', 'entry-content'); - - $this->showNoticeLink(); - $this->showNoticeSource(); - $this->showReplyTo(); - $this->out->elementEnd('div'); - + $this->showNotice(); + $this->showNoticeInfo(); $this->showAppLink(); - } - function showAppLink() + function showAppLink() { - + $this->facebook = getFacebook(); $app_props = $this->facebook->api_client->Admin_getAppProperties( @@ -740,7 +696,7 @@ class FacebookProfileBoxNotice extends FacebookNoticeListItem $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name']; $this->app_name = $app_props['application_name']; - + $this->out->elementStart('a', array('id' => 'facebook_laconica_app', 'href' => $this->app_uri)); $this->out->text($this->app_name); -- cgit v1.2.3-54-g00ecf From 1034bd67b015ae3023042dc3cb0ba684e3ee4c72 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Tue, 26 May 2009 23:59:12 +0000 Subject: Fixed warning on Facebook app settings page --- actions/facebooksettings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/facebooksettings.php b/actions/facebooksettings.php index 236460c1c..227e12316 100644 --- a/actions/facebooksettings.php +++ b/actions/facebooksettings.php @@ -55,7 +55,7 @@ class FacebooksettingsAction extends FacebookAction $prefix = $this->trimmed('prefix'); $original = clone($this->flink); - $this->flink->set_flags($noticesync, $replysync, false); + $this->flink->set_flags($noticesync, $replysync, false, false); $result = $this->flink->update($original); $this->facebook->api_client->data_setUserPreference(FACEBOOK_NOTICE_PREFIX, -- cgit v1.2.3-54-g00ecf From af700ea27703bbec5aa1078a84f9fd44c0260322 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Tue, 26 May 2009 21:20:04 -0400 Subject: Let's you upload a file with a notice and have it shown with other attachments. --- actions/newnotice.php | 37 +++++++++++++++++++++++++++++++++++-- js/jquery.form.js | 4 ++-- js/util.js | 12 ++++++++++++ lib/attachmentlist.php | 6 ++++-- lib/form.php | 16 +++++++++++----- lib/noticeform.php | 12 ++++++++++-- lib/noticelist.php | 11 +++++++++++ lib/router.php | 6 ++++++ 8 files changed, 91 insertions(+), 13 deletions(-) (limited to 'actions') diff --git a/actions/newnotice.php b/actions/newnotice.php index ae0ff9636..d7507c118 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -109,6 +109,10 @@ class NewnoticeAction extends Action } } + function isFileAttached() { + return $_FILES['attach']['error'] === UPLOAD_ERR_OK; + } + /** * Save a new notice, based on arguments * @@ -158,7 +162,6 @@ class NewnoticeAction extends Action $replyto = 'false'; } -// $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); @@ -167,6 +170,9 @@ class NewnoticeAction extends Action return; } + if ($this->isFileAttached()) { + $this->storeFile($notice); + } $this->saveUrls($notice); common_broadcast_notice($notice); @@ -194,6 +200,33 @@ class NewnoticeAction extends Action } } + function storeFile($notice) { + $filename = basename($_FILES['attach']['name']); + $destination = "file/{$notice->id}-$filename"; + if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) { + $file = new File; +// $file->url = common_local_url('file', array('notice' => $notice->id)); + $file->url = common_path($destination); + $file->size = filesize(INSTALLDIR . "/$destination"); + $file->date = time(); + $file->mimetype = $_FILES['attach']['type']; + if ($ok = $file->insert()) { + $f2p = new File_to_post; + $f2p->file_id = $ok; + $f2p->post_id = $notice->id; + $f2p->insert(); + } else { + die('inserting file, dying'); + } + } +/* + $url = common_local_url('file', array('notice' => $notice->id)); + echo "$destination
"; + die($url); +*/ + } + + /** save all urls in the notice to the db * * follow redirects and save all available file information @@ -203,7 +236,7 @@ class NewnoticeAction extends Action * * @return void */ - function saveUrls($notice) { + function saveUrls($notice, $uploaded = null) { common_replace_urls_callback($notice->content, array($this, 'saveUrl'), $notice->id); } diff --git a/js/jquery.form.js b/js/jquery.form.js index cb8b5a660..936b847ab 100644 --- a/js/jquery.form.js +++ b/js/jquery.form.js @@ -157,7 +157,7 @@ $.fn.ajaxSubmit = function(options) { function fileUpload() { var form = $form[0]; - if ($(':input[@name=submit]', form).length) { + if ($(':input[name=submit]', form).length) { alert('Error: Form elements must not be named "submit".'); return; } @@ -570,7 +570,7 @@ $.fn.clearForm = function() { $.fn.clearFields = $.fn.clearInputs = function() { return this.each(function() { var t = this.type, tag = this.tagName.toLowerCase(); - if (t == 'text' || t == 'password' || tag == 'textarea') + if (t == 'file' || t == 'text' || t == 'password' || tag == 'textarea') this.value = ''; else if (t == 'checkbox' || t == 'radio') this.checked = false; diff --git a/js/util.js b/js/util.js index b1b6ec82b..85ab48b4c 100644 --- a/js/util.js +++ b/js/util.js @@ -17,6 +17,17 @@ */ $(document).ready(function(){ + $('input#notice_data-attach').toggle(); + $('label[for=notice_data-attach]').text('Upload a file as an attachment?'); + $('label[for=notice_data-attach]').click(function () { + if ('Upload a file as an attachment?' == $(this).text()) { + $(this).text('Upload: '); + $('input#notice_data-attach').slideDown('fast'); + } else { + $('input#notice_data-attach').slideUp('fast', function() {$('label[for=notice_data-attach]').text('Upload a file as an attachment?');}); + } + }); + $('a.attachment').click(function() {$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); return false; }); $("a.thumbnail").hover( function() { @@ -227,6 +238,7 @@ $(document).ready(function(){ } } $("#notice_data-text").val(""); + $("#notice_data-attach").val(""); counter(); } $("#form_notice").removeClass("processing"); diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index d0478bad3..a58a50f6f 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -80,13 +80,15 @@ class AttachmentList extends Widget function show() { + $atts = new File; + $att = $atts->getAttachments($this->notice->id); + if (empty($att)) return 0; + $this->out->elementStart('dl', array('id' =>'attachment')); $this->out->element('dt', null, _('Attachments')); $this->out->elementStart('dd'); $this->out->elementStart('ul', array('class' => 'attachments')); - $atts = new File; - $att = $atts->getAttachments($this->notice->id); foreach ($att as $n=>$attachment) { $item = $this->newListItem($attachment); $item->show(); diff --git a/lib/form.php b/lib/form.php index 5317df471..f872aef0b 100644 --- a/lib/form.php +++ b/lib/form.php @@ -52,6 +52,8 @@ require_once INSTALLDIR.'/lib/widget.php'; class Form extends Widget { + var $enctype = null; + /** * Show the form * @@ -63,11 +65,15 @@ class Form extends Widget function show() { - $this->out->elementStart('form', - array('id' => $this->id(), - 'class' => $this->formClass(), - 'method' => 'post', - 'action' => $this->action())); + $attributes = array('id' => $this->id(), + 'class' => $this->formClass(), + 'method' => 'post', + 'action' => $this->action()); + + if (!empty($this->enctype)) { + $attributes['enctype'] = $this->enctype; + } + $this->out->elementStart('form', $attributes); $this->out->elementStart('fieldset'); $this->formLegend(); $this->sessionToken(); diff --git a/lib/noticeform.php b/lib/noticeform.php index 606b5d028..707768cd5 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -89,7 +89,8 @@ class NoticeForm extends Form } else { $this->user = common_current_user(); } - + + $this->enctype = 'multipart/form-data'; } /** @@ -136,18 +137,25 @@ class NoticeForm extends Form { $this->out->element('label', array('for' => 'notice_data-text'), sprintf(_('What\'s up, %s?'), $this->user->nickname)); + $this->out->elementStart('span', array('style' => 'float: right; margin-top: 2em;')); +// $this->out->element('a', array('href' => '#attach'), ' [ATTACH]'); + $this->out->elementEnd('span'); // XXX: vary by defined max size $this->out->element('textarea', array('id' => 'notice_data-text', 'cols' => 35, 'rows' => 4, 'name' => 'status_textarea'), ($this->content) ? $this->content : ''); - $this->out->elementStart('dl', 'form_note'); $this->out->element('dt', null, _('Available characters')); $this->out->element('dd', array('id' => 'notice_text-count'), '140'); $this->out->elementEnd('dl'); + $this->out->element('br', array('style' => 'clear:both')); +// $this->out->elementStart('a', array('href' => '#')); + $this->out->element('label', array('for' => 'notice_data-attach'), _('Upload: ')); +// $this->out->elementEnd('a'); + $this->out->element('input', array('id' => 'notice_data-attach', 'type' => 'file', 'name' => 'attach')); if ($this->action) { $this->out->hidden('notice_return-to', $this->action, 'returnto'); diff --git a/lib/noticelist.php b/lib/noticelist.php index 50a95cfcb..420272515 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -206,6 +206,7 @@ class NoticeListItem extends Widget return 'shownotice' !== $this->out->args['action']; } +/* function attachmentCount($discriminant = true) { $file_oembed = new File_oembed; $query = "select count(*) as c from file_oembed join file_to_post on file_oembed.file_id = file_to_post.file_id where post_id=" . $this->notice->id; @@ -213,11 +214,16 @@ class NoticeListItem extends Widget $file_oembed->fetch(); return intval($file_oembed->c); } +*/ + + function showWithAttachment() { + } function showNoticeInfo() { $this->out->elementStart('div', 'entry-content'); $this->showNoticeLink(); +// $this->showWithAttachment(); $this->showNoticeSource(); $this->showContext(); $this->out->elementEnd('div'); @@ -388,6 +394,11 @@ class NoticeListItem extends Widget $this->out->element('abbr', array('class' => 'published', 'title' => $dt), common_date_string($this->notice->created)); + + $f2p = File_to_post::staticGet('post_id', $this->notice->id); + if (!empty($f2p)) { + $this->out->text(_(' (with attachments) ')); + } $this->out->elementEnd('a'); $this->out->elementEnd('dd'); $this->out->elementEnd('dl'); diff --git a/lib/router.php b/lib/router.php index fc119821b..bd482eafa 100644 --- a/lib/router.php +++ b/lib/router.php @@ -164,6 +164,12 @@ class Router array('action' => 'newnotice'), array('replyto' => '[A-Za-z0-9_-]+')); +/* + $m->connect('notice/:notice/file', + array('action' => 'file'), + array('notice' => '[0-9]+')); +*/ + $m->connect('notice/:notice', array('action' => 'shownotice'), array('notice' => '[0-9]+')); -- cgit v1.2.3-54-g00ecf From ed1e1d9f440acfbb99c7a6e3d2b5c11fdcfa27ce Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Wed, 27 May 2009 03:47:45 -0400 Subject: Handles local aliases (redirection) for file uploads attached to notices. --- .gitignore | 6 ++++++ actions/file.php | 40 ++++++++++++++++++++++++++++++++++++++++ actions/newnotice.php | 15 ++++++++++----- classes/File_redirection.php | 2 +- lib/router.php | 2 -- lib/util.php | 5 +++++ 6 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 actions/file.php (limited to 'actions') diff --git a/.gitignore b/.gitignore index da6947bfd..3418d8ee5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ avatar/* files/* +file/* _darcs/* logs/* config.php @@ -16,3 +17,8 @@ dataobject.ini .buildpath .project .settings +TODO.rym +config-*.php +good-config.php +lac08.log +php.log diff --git a/actions/file.php b/actions/file.php new file mode 100644 index 000000000..1179dbe9a --- /dev/null +++ b/actions/file.php @@ -0,0 +1,40 @@ +. + */ + +if (!defined('LACONICA')) { exit(1); } + +require_once(INSTALLDIR.'/actions/shownotice.php'); + +class FileAction extends ShowNoticeAction +{ + function showPage() { + $source_url = common_local_url('file', array('notice' => $this->notice->id)); + $query = "select file_redirection.url as url from file join file_redirection on file.id = file_redirection.file_id where file.url = '$source_url'"; + $file = new File_redirection; + $file->query($query); + $file->fetch(); + if (empty($file->url)) { + die('nothing attached here'); + } else { + header("Location: {$file->url}"); + die(); + } + } +} + diff --git a/actions/newnotice.php b/actions/newnotice.php index d7507c118..aebdab3cc 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -110,7 +110,7 @@ class NewnoticeAction extends Action } function isFileAttached() { - return $_FILES['attach']['error'] === UPLOAD_ERR_OK; + return isset($_FILES['attach']['error']) && ($_FILES['attach']['error'] === UPLOAD_ERR_OK); } /** @@ -205,14 +205,19 @@ class NewnoticeAction extends Action $destination = "file/{$notice->id}-$filename"; if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) { $file = new File; -// $file->url = common_local_url('file', array('notice' => $notice->id)); - $file->url = common_path($destination); + $file->url = common_local_url('file', array('notice' => $notice->id)); +// $file->url = common_path($destination); $file->size = filesize(INSTALLDIR . "/$destination"); $file->date = time(); $file->mimetype = $_FILES['attach']['type']; - if ($ok = $file->insert()) { + if ($file_id = $file->insert()) { + $file_redir = new File_redirection; + $file_redir->url = common_path($destination); + $file_redir->file_id = $file_id; + $file_redir->insert(); + $f2p = new File_to_post; - $f2p->file_id = $ok; + $f2p->file_id = $file_id; $f2p->post_id = $notice->id; $f2p->insert(); } else { diff --git a/classes/File_redirection.php b/classes/File_redirection.php index 0eae68178..212cc3615 100644 --- a/classes/File_redirection.php +++ b/classes/File_redirection.php @@ -133,7 +133,7 @@ class File_redirection extends Memcached_DataObject $file->limit(1); $file->orderBy('len'); $file->find(true); - if (!empty($file->id)) { + if (!empty($file->url) && (strlen($file->url) < strlen($long_url))) { return $file->url; } diff --git a/lib/router.php b/lib/router.php index bd482eafa..456d1793e 100644 --- a/lib/router.php +++ b/lib/router.php @@ -164,11 +164,9 @@ class Router array('action' => 'newnotice'), array('replyto' => '[A-Za-z0-9_-]+')); -/* $m->connect('notice/:notice/file', array('action' => 'file'), array('notice' => '[0-9]+')); -*/ $m->connect('notice/:notice', array('action' => 'shownotice'), diff --git a/lib/util.php b/lib/util.php index d56f44f7b..ab1272309 100644 --- a/lib/util.php +++ b/lib/util.php @@ -499,6 +499,11 @@ function common_linkify($url) { // if this URL is an attachment, then we set class='attachment' and id='attahcment-ID' // where ID is the id of the attachment for the given URL. +// +// we need a better test telling what can be shown as an attachment +// we're currently picking up oembeds only. +// I think the best option is another file_view table in the db +// and associated dbobject. $query = "select file_oembed.file_id as file_id from file join file_oembed on file.id = file_oembed.file_id where file.url='$longurl'"; $file = new File; $file->query($query); -- cgit v1.2.3-54-g00ecf From 5e53a97a41038151959c0280d988c609c0834aa2 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 28 May 2009 16:18:58 -0700 Subject: Warning log msg when http basic auth fails --- actions/api.php | 1 + 1 file changed, 1 insertion(+) (limited to 'actions') diff --git a/actions/api.php b/actions/api.php index 8762b4bcd..b25ba99f3 100644 --- a/actions/api.php +++ b/actions/api.php @@ -67,6 +67,7 @@ class ApiAction extends Action $this->process_command(); } else { # basic authentication failed + common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname."); $this->show_basic_auth_error(); } } -- cgit v1.2.3-54-g00ecf From 8e8853a7141b10d01814d68021f24f2c78b2f193 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Thu, 28 May 2009 16:18:58 -0700 Subject: Warning log msg when http basic auth fails --- actions/api.php | 1 + 1 file changed, 1 insertion(+) (limited to 'actions') diff --git a/actions/api.php b/actions/api.php index 8762b4bcd..b25ba99f3 100644 --- a/actions/api.php +++ b/actions/api.php @@ -67,6 +67,7 @@ class ApiAction extends Action $this->process_command(); } else { # basic authentication failed + common_log(LOG_WARNING, "Failed API auth attempt, nickname: $nickname."); $this->show_basic_auth_error(); } } -- cgit v1.2.3-54-g00ecf From b8de7935568e631bc99aec6120f2bc4090f50fec Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Fri, 29 May 2009 02:38:38 +0000 Subject: Changed ul to ol and added xoxo for notice lists. --- actions/conversation.php | 10 +++++----- actions/shownotice.php | 4 ++-- lib/noticelist.php | 4 ++-- lib/noticesection.php | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) (limited to 'actions') diff --git a/actions/conversation.php b/actions/conversation.php index ef189016a..0d7cb9a87 100644 --- a/actions/conversation.php +++ b/actions/conversation.php @@ -179,14 +179,14 @@ class ConversationTree extends NoticeList $this->out->elementStart('div', array('id' =>'notices_primary')); $this->out->element('h2', null, _('Notices')); - $this->out->elementStart('ul', array('class' => 'notices')); + $this->out->elementStart('ol', array('class' => 'notices xoxo')); if (array_key_exists('root', $this->tree)) { $rootid = $this->tree['root'][0]; $this->showNoticePlus($rootid); } - $this->out->elementEnd('ul'); + $this->out->elementEnd('ol'); $this->out->elementEnd('div'); return $cnt; @@ -215,13 +215,13 @@ class ConversationTree extends NoticeList if (array_key_exists($id, $this->tree)) { $children = $this->tree[$id]; - $this->out->elementStart('ul', array('class' => 'notices')); + $this->out->elementStart('ol', array('class' => 'notices')); foreach ($children as $child) { $this->showNoticePlus($child); } - $this->out->elementEnd('ul'); + $this->out->elementEnd('ol'); } $this->out->elementEnd('li'); @@ -295,4 +295,4 @@ class ConversationTreeItem extends NoticeListItem { return; } -} \ No newline at end of file +} diff --git a/actions/shownotice.php b/actions/shownotice.php index 2c469c9de..34c8a8e94 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -208,10 +208,10 @@ class ShownoticeAction extends Action function showContent() { - $this->elementStart('ul', array('class' => 'notices')); + $this->elementStart('ol', array('class' => 'notices xoxo')); $nli = new NoticeListItem($this->notice, $this); $nli->show(); - $this->elementEnd('ul'); + $this->elementEnd('ol'); } /** diff --git a/lib/noticelist.php b/lib/noticelist.php index 50a95cfcb..0e80a9778 100644 --- a/lib/noticelist.php +++ b/lib/noticelist.php @@ -86,7 +86,7 @@ class NoticeList extends Widget { $this->out->elementStart('div', array('id' =>'notices_primary')); $this->out->element('h2', null, _('Notices')); - $this->out->elementStart('ul', array('class' => 'notices')); + $this->out->elementStart('ol', array('class' => 'notices xoxo')); $cnt = 0; @@ -101,7 +101,7 @@ class NoticeList extends Widget $item->show(); } - $this->out->elementEnd('ul'); + $this->out->elementEnd('ol'); $this->out->elementEnd('div'); return $cnt; diff --git a/lib/noticesection.php b/lib/noticesection.php index 37aafdaf6..ca1432686 100644 --- a/lib/noticesection.php +++ b/lib/noticesection.php @@ -52,12 +52,12 @@ class NoticeSection extends Section { $notices = $this->getNotices(); $cnt = 0; - $this->out->elementStart('ul', 'notices'); + $this->out->elementStart('ol', 'notices xoxo'); while ($notices->fetch() && ++$cnt <= NOTICES_PER_SECTION) { $this->showNotice($notices); } - $this->out->elementEnd('ul'); + $this->out->elementEnd('ol'); return ($cnt > NOTICES_PER_SECTION); } -- cgit v1.2.3-54-g00ecf From eb76a3bbb36e1f73007cb9b602001ec14f6853c6 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 29 May 2009 16:32:55 -0700 Subject: Ticket #1567 - API: Change before_id parameter to max_id --- actions/twitapidirect_messages.php | 6 +++--- actions/twitapistatuses.php | 36 ++++++++++++++++-------------------- classes/Fave.php | 6 +++--- classes/Notice_inbox.php | 10 +++++----- classes/Notice_tag.php | 6 +++--- classes/Reply.php | 10 +++++----- classes/User_group.php | 6 +++--- 7 files changed, 38 insertions(+), 42 deletions(-) (limited to 'actions') diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index 7101db8df..ab8f07810 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -43,7 +43,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction $count = $this->arg('count'); $since = $this->arg('since'); $since_id = $this->arg('since_id'); - $before_id = $this->arg('before_id'); + $max_id = $this->arg('max_id'); $page = $this->arg('page'); @@ -74,8 +74,8 @@ class Twitapidirect_messagesAction extends TwitterapiAction $link = $server . $user->nickname . '/outbox'; } - if ($before_id) { - $message->whereAdd("id < $before_id"); + if ($max_id) { + $message->whereAdd("id < $max_id"); } if ($since_id) { diff --git a/actions/twitapistatuses.php b/actions/twitapistatuses.php index 3abeba367..1fbde6639 100644 --- a/actions/twitapistatuses.php +++ b/actions/twitapistatuses.php @@ -45,22 +45,21 @@ class TwitapistatusesAction extends TwitterapiAction $page = $this->arg('page'); $since_id = $this->arg('since_id'); - $before_id = $this->arg('before_id'); + $max_id = $this->arg('max_id'); - // NOTE: page, since_id, and before_id are extensions to Twitter API -- TB if (!$page) { $page = 1; } if (!$since_id) { $since_id = 0; } - if (!$before_id) { - $before_id = 0; + if (!$max_id) { + $max_id = 0; } $since = strtotime($this->arg('since')); - $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $before_id, $since); + $notice = Notice::publicStream((($page-1)*$MAX_PUBSTATUSES), $MAX_PUBSTATUSES, $since_id, $max_id, $since); if ($notice) { @@ -97,7 +96,7 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = $this->arg('since_id'); $count = $this->arg('count'); $page = $this->arg('page'); - $before_id = $this->arg('before_id'); + $max_id = $this->arg('max_id'); if (!$page) { $page = 1; @@ -111,9 +110,8 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = 0; } - // NOTE: before_id is an extension to Twitter API -- TB - if (!$before_id) { - $before_id = 0; + if (!$max_id) { + $max_id = 0; } $since = strtotime($this->arg('since')); @@ -133,7 +131,7 @@ class TwitapistatusesAction extends TwitterapiAction $link = common_local_url('all', array('nickname' => $user->nickname)); $subtitle = sprintf(_('Updates from %1$s and friends on %2$s!'), $user->nickname, $sitename); - $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $before_id, $since); + $notice = $user->noticesWithFriends(($page-1)*20, $count, $since_id, $max_id, $since); switch($apidata['content-type']) { case 'xml': @@ -184,7 +182,7 @@ class TwitapistatusesAction extends TwitterapiAction $since = $this->arg('since'); $since_id = $this->arg('since_id'); $page = $this->arg('page'); - $before_id = $this->arg('before_id'); + $max_id = $this->arg('max_id'); if (!$page) { $page = 1; @@ -198,9 +196,8 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = 0; } - // NOTE: before_id is an extensions to Twitter API -- TB - if (!$before_id) { - $before_id = 0; + if (!$max_id) { + $max_id = 0; } $since = strtotime($this->arg('since')); @@ -220,7 +217,7 @@ class TwitapistatusesAction extends TwitterapiAction # XXX: since - $notice = $user->getNotices((($page-1)*20), $count, $since_id, $before_id, $since); + $notice = $user->getNotices((($page-1)*20), $count, $since_id, $max_id, $since); switch($apidata['content-type']) { case 'xml': @@ -353,7 +350,7 @@ class TwitapistatusesAction extends TwitterapiAction $count = $this->arg('count'); $page = $this->arg('page'); $since_id = $this->arg('since_id'); - $before_id = $this->arg('before_id'); + $max_id = $this->arg('max_id'); $user = $this->get_user($apidata['api_arg'], $apidata); $this->auth_user = $apidata['user']; @@ -380,15 +377,14 @@ class TwitapistatusesAction extends TwitterapiAction $since_id = 0; } - // NOTE: before_id is an extension to Twitter API -- TB - if (!$before_id) { - $before_id = 0; + if (!$max_id) { + $max_id = 0; } $since = strtotime($this->arg('since')); $notice = $user->getReplies((($page-1)*20), - $count, $since_id, $before_id, $since); + $count, $since_id, $max_id, $since); $notices = array(); while ($notice->fetch()) { diff --git a/classes/Fave.php b/classes/Fave.php index 915b4572f..cdb479856 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -46,7 +46,7 @@ class Fave extends Memcached_DataObject return $ids; } - function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since) + function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since) { $fav = new Fave(); @@ -59,8 +59,8 @@ class Fave extends Memcached_DataObject $fav->whereAdd('notice_id > ' . $since_id); } - if ($before_id != 0) { - $fav->whereAdd('notice_id < ' . $before_id); + if ($max_id != 0) { + $fav->whereAdd('notice_id < ' . $max_id); } if (!is_null($since)) { diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index dec14b0d1..65d7927b7 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -43,15 +43,15 @@ class Notice_inbox extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function stream($user_id, $offset, $limit, $since_id, $before_id, $since) + function stream($user_id, $offset, $limit, $since_id, $max_id, $since) { return Notice::stream(array('Notice_inbox', '_streamDirect'), array($user_id), 'notice_inbox:by_user:'.$user_id, - $offset, $limit, $since_id, $before_id, $since); + $offset, $limit, $since_id, $max_id, $since); } - function _streamDirect($user_id, $offset, $limit, $since_id, $before_id, $since) + function _streamDirect($user_id, $offset, $limit, $since_id, $max_id, $since) { $inbox = new Notice_inbox(); @@ -61,8 +61,8 @@ class Notice_inbox extends Memcached_DataObject $inbox->whereAdd('notice_id > ' . $since_id); } - if ($before_id != 0) { - $inbox->whereAdd('notice_id < ' . $before_id); + if ($max_id != 0) { + $inbox->whereAdd('notice_id < ' . $max_id); } if (!is_null($since)) { diff --git a/classes/Notice_tag.php b/classes/Notice_tag.php index e5b772243..758a66594 100644 --- a/classes/Notice_tag.php +++ b/classes/Notice_tag.php @@ -46,7 +46,7 @@ class Notice_tag extends Memcached_DataObject return Notice::getStreamByIds($ids); } - function _streamDirect($tag, $offset, $limit, $since_id, $before_id, $since) + function _streamDirect($tag, $offset, $limit, $since_id, $max_id, $since) { $nt = new Notice_tag(); @@ -59,8 +59,8 @@ class Notice_tag extends Memcached_DataObject $nt->whereAdd('notice_id > ' . $since_id); } - if ($before_id != 0) { - $nt->whereAdd('notice_id < ' . $before_id); + if ($max_id != 0) { + $nt->whereAdd('notice_id < ' . $max_id); } if (!is_null($since)) { diff --git a/classes/Reply.php b/classes/Reply.php index 4439053b4..49b1e05e5 100644 --- a/classes/Reply.php +++ b/classes/Reply.php @@ -22,16 +22,16 @@ class Reply extends Memcached_DataObject /* the code above is auto generated do not remove the tag below */ ###END_AUTOCODE - function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) + function stream($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) { $ids = Notice::stream(array('Reply', '_streamDirect'), array($user_id), 'reply:stream:' . $user_id, - $offset, $limit, $since_id, $before_id, $since); + $offset, $limit, $since_id, $max_id, $since); return $ids; } - function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0, $since=null) + function _streamDirect($user_id, $offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0, $since=null) { $reply = new Reply(); $reply->profile_id = $user_id; @@ -40,8 +40,8 @@ class Reply extends Memcached_DataObject $reply->whereAdd('notice_id > ' . $since_id); } - if ($before_id != 0) { - $reply->whereAdd('notice_id < ' . $before_id); + if ($max_id != 0) { + $reply->whereAdd('notice_id < ' . $max_id); } if (!is_null($since)) { diff --git a/classes/User_group.php b/classes/User_group.php index 7cc31e702..43591d655 100755 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -58,7 +58,7 @@ class User_group extends Memcached_DataObject return Notice::getStreamByIds($ids); } - function _streamDirect($offset, $limit, $since_id, $before_id, $since) + function _streamDirect($offset, $limit, $since_id, $max_id, $since) { $inbox = new Group_inbox(); @@ -71,8 +71,8 @@ class User_group extends Memcached_DataObject $inbox->whereAdd('notice_id > ' . $since_id); } - if ($before_id != 0) { - $inbox->whereAdd('notice_id < ' . $before_id); + if ($max_id != 0) { + $inbox->whereAdd('notice_id < ' . $max_id); } if (!is_null($since)) { -- cgit v1.2.3-54-g00ecf From 425f9d703c5258920079b268c085b0c7112c3b70 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 29 May 2009 16:54:24 -0700 Subject: Ticket #1567 - Change max_id to return notices <= ID instead of < ID --- actions/twitapidirect_messages.php | 2 +- classes/Fave.php | 2 +- classes/Notice.php | 32 ++++++++++++++++---------------- classes/Notice_inbox.php | 2 +- classes/Profile.php | 10 +++++----- classes/User_group.php | 2 +- 6 files changed, 25 insertions(+), 25 deletions(-) (limited to 'actions') diff --git a/actions/twitapidirect_messages.php b/actions/twitapidirect_messages.php index ab8f07810..d2dbdb619 100644 --- a/actions/twitapidirect_messages.php +++ b/actions/twitapidirect_messages.php @@ -75,7 +75,7 @@ class Twitapidirect_messagesAction extends TwitterapiAction } if ($max_id) { - $message->whereAdd("id < $max_id"); + $message->whereAdd("id <= $max_id"); } if ($since_id) { diff --git a/classes/Fave.php b/classes/Fave.php index cdb479856..572334ce4 100644 --- a/classes/Fave.php +++ b/classes/Fave.php @@ -60,7 +60,7 @@ class Fave extends Memcached_DataObject } if ($max_id != 0) { - $fav->whereAdd('notice_id < ' . $max_id); + $fav->whereAdd('notice_id <= ' . $max_id); } if (!is_null($since)) { diff --git a/classes/Notice.php b/classes/Notice.php index 8dd14b3b7..3f6c5cebb 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -426,22 +426,22 @@ class Notice extends Memcached_DataObject # XXX: too many args; we need to move to named params or even a separate # class for notice streams - static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $order=null, $since=null) { + static function getStream($qry, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $order=null, $since=null) { if (common_config('memcached', 'enabled')) { - # Skip the cache if this is a since, since_id or before_id qry - if ($since_id > 0 || $before_id > 0 || $since) { - return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since); + # Skip the cache if this is a since, since_id or max_id qry + if ($since_id > 0 || $max_id > 0 || $since) { + return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since); } else { return Notice::getCachedStream($qry, $cachekey, $offset, $limit, $order); } } - return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since); + return Notice::getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since); } - static function getStreamDirect($qry, $offset, $limit, $since_id, $before_id, $order, $since) { + static function getStreamDirect($qry, $offset, $limit, $since_id, $max_id, $order, $since) { $needAnd = false; $needWhere = true; @@ -463,7 +463,7 @@ class Notice extends Memcached_DataObject $qry .= ' notice.id > ' . $since_id; } - if ($before_id > 0) { + if ($max_id > 0) { if ($needWhere) { $qry .= ' WHERE '; @@ -472,7 +472,7 @@ class Notice extends Memcached_DataObject $qry .= ' AND '; } - $qry .= ' notice.id < ' . $before_id; + $qry .= ' notice.id <= ' . $max_id; } if ($since) { @@ -630,17 +630,17 @@ class Notice extends Memcached_DataObject } } - function publicStream($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null) + function publicStream($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null) { $ids = Notice::stream(array('Notice', '_publicStreamDirect'), array(), 'public', - $offset, $limit, $since_id, $before_id, $since); + $offset, $limit, $since_id, $max_id, $since); return Notice::getStreamByIds($ids); } - function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $before_id=0, $since=null) + function _publicStreamDirect($offset=0, $limit=20, $since_id=0, $max_id=0, $since=null) { $notice = new Notice(); @@ -664,8 +664,8 @@ class Notice extends Memcached_DataObject $notice->whereAdd('id > ' . $since_id); } - if ($before_id != 0) { - $notice->whereAdd('id < ' . $before_id); + if ($max_id != 0) { + $notice->whereAdd('id <= ' . $max_id); } if (!is_null($since)) { @@ -998,15 +998,15 @@ class Notice extends Memcached_DataObject } } - function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $before_id=0, $since=null) + function stream($fn, $args, $cachekey, $offset=0, $limit=20, $since_id=0, $max_id=0, $since=null) { $cache = common_memcache(); if (empty($cache) || - $since_id != 0 || $before_id != 0 || !is_null($since) || + $since_id != 0 || $max_id != 0 || !is_null($since) || ($offset + $limit) > NOTICE_CACHE_WINDOW) { return call_user_func_array($fn, array_merge($args, array($offset, $limit, $since_id, - $before_id, $since))); + $max_id, $since))); } $idkey = common_cache_key($cachekey); diff --git a/classes/Notice_inbox.php b/classes/Notice_inbox.php index 65d7927b7..8a27e1747 100644 --- a/classes/Notice_inbox.php +++ b/classes/Notice_inbox.php @@ -62,7 +62,7 @@ class Notice_inbox extends Memcached_DataObject } if ($max_id != 0) { - $inbox->whereAdd('notice_id < ' . $max_id); + $inbox->whereAdd('notice_id <= ' . $max_id); } if (!is_null($since)) { diff --git a/classes/Profile.php b/classes/Profile.php index ae5641d79..3d13cd46a 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -153,18 +153,18 @@ class Profile extends Memcached_DataObject return null; } - function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $before_id=0) + function getNotices($offset=0, $limit=NOTICES_PER_PAGE, $since_id=0, $max_id=0) { // XXX: I'm not sure this is going to be any faster. It probably isn't. $ids = Notice::stream(array($this, '_streamDirect'), array(), 'profile:notice_ids:' . $this->id, - $offset, $limit, $since_id, $before_id); + $offset, $limit, $since_id, $max_id); return Notice::getStreamByIds($ids); } - function _streamDirect($offset, $limit, $since_id, $before_id, $since) + function _streamDirect($offset, $limit, $since_id, $max_id, $since) { $notice = new Notice(); @@ -177,8 +177,8 @@ class Profile extends Memcached_DataObject $notice->whereAdd('id > ' . $since_id); } - if ($before_id != 0) { - $notice->whereAdd('id < ' . $before_id); + if ($max_id != 0) { + $notice->whereAdd('id <= ' . $max_id); } if (!is_null($since)) { diff --git a/classes/User_group.php b/classes/User_group.php index 43591d655..a135015ba 100755 --- a/classes/User_group.php +++ b/classes/User_group.php @@ -72,7 +72,7 @@ class User_group extends Memcached_DataObject } if ($max_id != 0) { - $inbox->whereAdd('notice_id < ' . $max_id); + $inbox->whereAdd('notice_id <= ' . $max_id); } if (!is_null($since)) { -- cgit v1.2.3-54-g00ecf From 78f8b91a13ee07ed3344fd6411a0829a16bef4b1 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 29 May 2009 19:23:53 -0700 Subject: Ticket #1568 - API should return full user objects --- actions/twitapiusers.php | 145 ++++++++++++++++------------------------------- lib/twitterapi.php | 77 ++++++++++++++++++++++--- 2 files changed, 117 insertions(+), 105 deletions(-) (limited to 'actions') diff --git a/actions/twitapiusers.php b/actions/twitapiusers.php index 1542cfb33..b90bbfa98 100644 --- a/actions/twitapiusers.php +++ b/actions/twitapiusers.php @@ -25,110 +25,61 @@ 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; } - - $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']); - } 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; - } - - $profile = $user->getProfile(); - - if (!$profile) { - common_server_error(_('User has no profile.')); - return; - } - - $twitter_user = $this->twitter_user_array($profile, true); - - // Add in extended user fields offered up by this method - $twitter_user['created_at'] = $this->date_twitter($profile->created); - - $subbed = DB_DataObject::factory('subscription'); - $subbed->subscriber = $profile->id; - $subbed_count = (int) $subbed->count() - 1; - - $notices = DB_DataObject::factory('notice'); - $notices->profile_id = $profile->id; - $notice_count = (int) $notices->count(); - - $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0; - $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0; - - // 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; - $faves_count = (int) $faves->count(); - $twitter_user['favourites_count'] = $faves_count; - - $timezone = 'UTC'; - - if ($user->timezone) { - $timezone = $user->timezone; - } - - $t = new DateTime; - $t->setTimezone(new DateTimeZone($timezone)); - $twitter_user['utc_offset'] = $t->format('Z'); - $twitter_user['time_zone'] = $timezone; - - if (isset($apidata['user'])) { - - $twitter_user['following'] = $apidata['user']->isSubscribed($profile); - - // Notifications on? - $sub = Subscription::pkeyGet(array('subscriber' => - $apidata['user']->id, 'subscribed' => $profile->id)); - - if ($sub) { - $twitter_user['notifications'] = ($sub->jabber || $sub->sms); - } - } - - if ($apidata['content-type'] == 'xml') { - $this->init_document('xml'); - $this->show_twitter_xml_user($twitter_user); - $this->end_document('xml'); - } elseif ($apidata['content-type'] == 'json') { - $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). + + $user = null; + $email = $this->arg('email'); + $user_id = $this->arg('user_id'); + + // XXX: email field deprecated in Twitter's API + + // XXX: Also: need to add screen_name param + + 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']); + } elseif (isset($apidata['user'])) { + $user = $apidata['user']; + } + + if (!$user) { + $this->client_error(_('Not found.'), 404, $apidata['content-type']); + return; + } + + $profile = $user->getProfile(); + + if (!$profile) { + common_server_error(_('User has no profile.')); + return; + } + + $twitter_user = $this->twitter_user_array($profile, true); + + if ($apidata['content-type'] == 'xml') { + $this->init_document('xml'); + $this->show_twitter_xml_user($twitter_user); + $this->end_document('xml'); + } elseif ($apidata['content-type'] == 'json') { + $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/twitterapi.php b/lib/twitterapi.php index caf8c0716..1d527b935 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -54,7 +54,7 @@ class TwitterapiAction extends Action /** * Overrides XMLOutputter::element to write booleans as strings (true|false). * See that method's documentation for more info. - * + * * @param string $tag Element type or tagname * @param array $attrs Array of element attributes, as * key-value pairs @@ -70,24 +70,85 @@ class TwitterapiAction extends Action return parent::element($tag, $attrs, $content); } - + function twitter_user_array($profile, $get_notice=false) { - $twitter_user = array(); + $twitter_user['id'] = intval($profile->id); $twitter_user['name'] = $profile->getBestName(); - $twitter_user['followers_count'] = $this->count_subscriptions($profile); $twitter_user['screen_name'] = $profile->nickname; - $twitter_user['description'] = ($profile->bio) ? $profile->bio : null; $twitter_user['location'] = ($profile->location) ? $profile->location : null; - $twitter_user['id'] = intval($profile->id); + $twitter_user['description'] = ($profile->bio) ? $profile->bio : null; $avatar = $profile->getAvatar(AVATAR_STREAM_SIZE); + $twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : + Avatar::defaultImage(AVATAR_STREAM_SIZE); - $twitter_user['profile_image_url'] = ($avatar) ? $avatar->displayUrl() : Avatar::defaultImage(AVATAR_STREAM_SIZE); - $twitter_user['protected'] = false; # not supported by Laconica yet $twitter_user['url'] = ($profile->homepage) ? $profile->homepage : null; + $twitter_user['protected'] = false; # not supported by Laconica yet + $twitter_user['followers_count'] = $this->count_subscriptions($profile); + + // To be supported soon... + $twitter_user['profile_background_color'] = ''; + $twitter_user['profile_text_color'] = ''; + $twitter_user['profile_link_color'] = ''; + $twitter_user['profile_sidebar_fill_color'] = ''; + $twitter_user['profile_sidebar_border_color'] = ''; + + $subbed = DB_DataObject::factory('subscription'); + $subbed->subscriber = $profile->id; + $subbed_count = (int) $subbed->count() - 1; + $twitter_user['friends_count'] = (is_int($subbed_count)) ? $subbed_count : 0; + + $twitter_user['created_at'] = $this->date_twitter($profile->created); + + $faves = DB_DataObject::factory('fave'); + $faves->user_id = $user->id; + $faves_count = (int) $faves->count(); + $twitter_user['favourites_count'] = $faves_count; // British spelling! + + // Need to pull up the user for some of this + $user = User::staticGet($profile->id); + + $timezone = 'UTC'; + + if ($user->timezone) { + $timezone = $user->timezone; + } + + $t = new DateTime; + $t->setTimezone(new DateTimeZone($timezone)); + + $twitter_user['utc_offset'] = $t->format('Z'); + $twitter_user['time_zone'] = $timezone; + + // To be supported some day, perhaps + $twitter_user['profile_background_image_url'] = ''; + $twitter_user['profile_background_tile'] = false; + + $notices = DB_DataObject::factory('notice'); + $notices->profile_id = $profile->id; + $notice_count = (int) $notices->count(); + + $twitter_user['statuses_count'] = (is_int($notice_count)) ? $notice_count : 0; + + // Is the requesting user following this user? + $twitter_user['following'] = false; + $twitter_user['notifications'] = false; + + if (isset($apidata['user'])) { + + $twitter_user['following'] = $apidata['user']->isSubscribed($profile); + + // Notifications on? + $sub = Subscription::pkeyGet(array('subscriber' => + $apidata['user']->id, 'subscribed' => $profile->id)); + + if ($sub) { + $twitter_user['notifications'] = ($sub->jabber || $sub->sms); + } + } if ($get_notice) { $notice = $profile->getCurrentNotice(); -- cgit v1.2.3-54-g00ecf From 791f5defaf07372de6453ac7903a9a32611b0284 Mon Sep 17 00:00:00 2001 From: Zach Copley Date: Fri, 29 May 2009 20:23:32 -0700 Subject: Ticket #1572 - Implement Twitter's account/rate_limit_status API method We don't have a rate limit (yet) but some clients check this method. This dummy implementation always says the auth user has 100 requests left. --- actions/twitapiaccount.php | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/twitapiaccount.php b/actions/twitapiaccount.php index 68a18cb57..8b956f897 100644 --- a/actions/twitapiaccount.php +++ b/actions/twitapiaccount.php @@ -98,9 +98,31 @@ class TwitapiaccountAction extends TwitterapiAction $this->serverError(_('API method under construction.'), $code=501); } + // We don't have a rate limit, but some clients check this method. + // It always returns the same thing: 100 hit left. function rate_limit_status($args, $apidata) { parent::handle($args); - $this->serverError(_('API method under construction.'), $code=501); + + $type = $apidata['content-type']; + $this->init_document($type); + + if ($apidata['content-type'] == 'xml') { + $this->elementStart('hash'); + $this->element('remaining-hits', array('type' => 'integer'), 100); + $this->element('hourly-limit', array('type' => 'integer'), 100); + $this->element('reset-time', array('type' => 'datetime'), null); + $this->element('reset_time_in_seconds', array('type' => 'integer'), 0); + $this->elementEnd('hash'); + } elseif ($apidata['content-type'] == 'json') { + + $out = array('reset_time_in_seconds' => 0, + 'remaining_hits' => 100, + 'hourly_limit' => 100, + 'reset_time' => ''); + print json_encode($out); + } + + $this->end_document($type); } } -- cgit v1.2.3-54-g00ecf From 08b98a3d4d8edf2bc0b781953706744c026388b9 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sat, 30 May 2009 19:45:34 +0000 Subject: Typo in label @for --- actions/designsettings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/designsettings.php b/actions/designsettings.php index 315e5a199..5d3bf1a03 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -82,7 +82,7 @@ class DesignsettingsAction extends AccountSettingsAction $this->element('legend', null, _('Change background image')); $this->elementStart('ul', 'form_data'); $this->elementStart('li'); - $this->element('label', array('for' => 'design_ background-image_file'), + $this->element('label', array('for' => 'design_background-image_file'), _('Upload file')); $this->element('input', array('name' => 'design_background-image_file', 'type' => 'file', -- cgit v1.2.3-54-g00ecf From 36fe5a85b2de9f71a5c963abd0074dd5b7ae1e61 Mon Sep 17 00:00:00 2001 From: Sarven Capadisli Date: Sat, 30 May 2009 19:47:05 +0000 Subject: Using lowercase for form action 'post' --- actions/designsettings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/designsettings.php b/actions/designsettings.php index 5d3bf1a03..5774b8537 100644 --- a/actions/designsettings.php +++ b/actions/designsettings.php @@ -70,7 +70,7 @@ class DesignsettingsAction extends AccountSettingsAction function showContent() { $user = common_current_user(); - $this->elementStart('form', array('method' => 'POST', + $this->elementStart('form', array('method' => 'post', 'id' => 'form_settings_design', 'class' => 'form_settings', 'action' => -- cgit v1.2.3-54-g00ecf From 4ec1c333073fd693147ff34895cf7e3664f83cf6 Mon Sep 17 00:00:00 2001 From: Evan Prodromou Date: Sat, 30 May 2009 21:45:11 -0400 Subject: correct last-modified date for shownotice.php --- actions/shownotice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'actions') diff --git a/actions/shownotice.php b/actions/shownotice.php index 2c469c9de..1be1e2414 100644 --- a/actions/shownotice.php +++ b/actions/shownotice.php @@ -122,7 +122,7 @@ class ShownoticeAction extends Action function lastModified() { - return max(strtotime($this->notice->created), + return max(strtotime($this->notice->modified), strtotime($this->profile->modified), ($this->avatar) ? strtotime($this->avatar->modified) : 0); } -- cgit v1.2.3-54-g00ecf From 3e0c291810d23bb54c337c0fe95c1ba441459c4c Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Sun, 31 May 2009 16:42:29 -0400 Subject: Added configurable options for attachments: supported mimetypes and quotas for uploads. --- actions/newnotice.php | 118 ++++++++-- config.php.sample | 8 + extlib/MIME/Type.php | 523 +++++++++++++++++++++++++++++++++++++++++ extlib/MIME/Type/Extension.php | 298 +++++++++++++++++++++++ extlib/MIME/Type/Parameter.php | 163 +++++++++++++ lib/common.php | 56 ++++- 6 files changed, 1136 insertions(+), 30 deletions(-) create mode 100644 extlib/MIME/Type.php create mode 100644 extlib/MIME/Type/Extension.php create mode 100644 extlib/MIME/Type/Parameter.php (limited to 'actions') diff --git a/actions/newnotice.php b/actions/newnotice.php index aebdab3cc..29b748dd1 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -84,20 +84,24 @@ class NewnoticeAction extends Action function handle($args) { - parent::handle($args); - if (!common_logged_in()) { $this->clientError(_('Not logged in.')); } else if ($_SERVER['REQUEST_METHOD'] == 'POST') { + // check for this before token since all POST and FILES data + // is losts when size is exceeded + if (empty($_POST) && $_SERVER['CONTENT_LENGTH']) { + $this->clientError(sprintf(_('The server was unable to handle ' . + 'that much POST data (%s bytes) due to its current configuration.'), + $_SERVER['CONTENT_LENGTH'])); + } + parent::handle($args); // CSRF protection $token = $this->trimmed('token'); if (!$token || $token != common_session_token()) { $this->clientError(_('There was a problem with your session token. '. 'Try again, please.')); - return; } - try { $this->saveNewNotice(); } catch (Exception $e) { @@ -109,8 +113,55 @@ class NewnoticeAction extends Action } } - function isFileAttached() { - return isset($_FILES['attach']['error']) && ($_FILES['attach']['error'] === UPLOAD_ERR_OK); + function isSupportedFileType() { + require_once 'MIME/Type.php'; + + $filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']); + if (in_array($filetype, common_config('attachments', 'supported'))) { + return true; + } + $media = MIME_Type::getMedia($filetype); + if ('application' !== $media) { + $hint = sprintf(_(' Try using another %s format.'), $media); + } else { + $hint = ''; + } + $this->clientError(sprintf( + _('%s is not a supported filetype on this server.'), $filetype) . $hint); + } + + function isRespectsQuota($user) { + if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) { + $this->clientError(sprintf(_('No file may be larger than %d bytes ' . + 'and the file you sent was %d bytes. Try to upload a smaller version.'), + common_config('attachments', 'file_quota'), $_FILES['attach']['size'])); + } + + $query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'"; + $file = new File; + $file->query($query); + $file->fetch(); + $total = $file->total + $_FILES['attach']['size']; + if ($total > common_config('attachments', 'user_quota')) { + $this->clientError(sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'))); + } + + $query .= ' month(modified) = month(now()) and year(modified) = year(now())'; + $file2 = new File; + $file2->query($query); + $file2->fetch(); + $total2 = $file2->total + $_FILES['attach']['size']; + if ($total2 > common_config('attachments', 'monthly_quota')) { + $this->clientError(sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'))); + } + return true; + } + + function isValidFileAttached($user) { + return isset($_FILES['attach']['error']) + && ($_FILES['attach']['error'] === UPLOAD_ERR_OK) + && $this->isSupportedFileType() + && $this->isRespectsQuota($user); } /** @@ -135,7 +186,6 @@ class NewnoticeAction extends Action $this->clientError(_('No content!')); } else { $content_shortened = common_shorten_links($content); - if (mb_strlen($content_shortened) > 140) { $this->clientError(_('That\'s too long. '. 'Max notice size is 140 chars.')); @@ -162,19 +212,54 @@ class NewnoticeAction extends Action $replyto = 'false'; } + switch ($_FILES['attach']['error']) { + case UPLOAD_ERR_NO_FILE: + // no file uploaded + // nothing to do + break; + + case UPLOAD_ERR_OK: + // file was uploaded alright + // lets check if we really support its format + // and it doesn't go over quotas + + + if (!$this->isValidFileAttached($user)) { + die('clientError() should trigger an exception before reaching here.'); + } + break; + + case UPLOAD_ERR_INI_SIZE: + $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.')); + + case UPLOAD_ERR_FORM_SIZE: + $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.')); + + case UPLOAD_ERR_PARTIAL: + $this->clientError(_('The uploaded file was only partially uploaded.')); + + case UPLOAD_ERR_NO_TMP_DIR: + $this->clientError(_('Missing a temporary folder.')); + + case UPLOAD_ERR_CANT_WRITE: + $this->clientError(_('Failed to write file to disk.')); + + case UPLOAD_ERR_EXTENSION: + $this->clientError(_('File upload stopped by extension.')); + + default: + die('Should never reach here.'); + } + $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); if (is_string($notice)) { $this->clientError($notice); - return; } - if ($this->isFileAttached()) { - $this->storeFile($notice); - } + $this->storeFile($notice); $this->saveUrls($notice); - common_broadcast_notice($notice); if ($this->boolean('ajax')) { @@ -201,12 +286,12 @@ class NewnoticeAction extends Action } function storeFile($notice) { + if (UPLOAD_ERR_NO_FILE === $_FILES['attach']['error']) return; $filename = basename($_FILES['attach']['name']); $destination = "file/{$notice->id}-$filename"; if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) { $file = new File; $file->url = common_local_url('file', array('notice' => $notice->id)); -// $file->url = common_path($destination); $file->size = filesize(INSTALLDIR . "/$destination"); $file->date = time(); $file->mimetype = $_FILES['attach']['type']; @@ -221,14 +306,9 @@ class NewnoticeAction extends Action $f2p->post_id = $notice->id; $f2p->insert(); } else { - die('inserting file, dying'); + $this->clientError(_('There was a database error while saving your file. Please try again.')); } } -/* - $url = common_local_url('file', array('notice' => $notice->id)); - echo "$destination
"; - die($url); -*/ } diff --git a/config.php.sample b/config.php.sample index 282826a7f..636f4cf8e 100644 --- a/config.php.sample +++ b/config.php.sample @@ -215,3 +215,11 @@ $config['sphinx']['port'] = 3312; // $config['snapshot']['run'] = 'never'; // If you want to report statistics in a cron job instead. // $config['snapshot']['run'] = 'cron'; + +// Support for file uploads (attachments), +// select supported mimetypes and quotas (in bytes) +// $config['attachments']['supported'] = array('image/png', 'application/ogg'); +// $config['attachments']['file_quota'] = 5000000; +// $config['attachments']['user_quota'] = 50000000; +// $config['attachments']['monthly_quota'] = 15000000; + diff --git a/extlib/MIME/Type.php b/extlib/MIME/Type.php new file mode 100644 index 000000000..c335f8d92 --- /dev/null +++ b/extlib/MIME/Type.php @@ -0,0 +1,523 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Type.php,v 1.6 2009/01/16 11:49:45 cweiske Exp $ + +require_once 'PEAR.php'; + +$_fileCmd = &PEAR::getStaticProperty('MIME_Type', 'fileCmd'); +$_fileCmd = 'file'; + +/** + * Class for working with MIME types + * + * @category MIME + * @package MIME_Type + * @license PHP License 3.0 + * @version 1.2.0 + * @link http://pear.php.net/package/MIME_Type + * @author Ian Eure + */ +class MIME_Type +{ + /** + * The MIME media type + * + * @var string + */ + var $media = ''; + + /** + * The MIME media sub-type + * + * @var string + */ + var $subType = ''; + + /** + * Optional MIME parameters + * + * @var array + */ + var $parameters = array(); + + /** + * List of valid media types. + * A media type is the string in front of the slash. + * The media type of "text/xml" would be "text". + * + * @var array + */ + var $validMediaTypes = array( + 'text', + 'image', + 'audio', + 'video', + 'application', + 'multipart', + 'message' + ); + + + /** + * Constructor. + * + * If $type is set, if will be parsed and the appropriate class vars set. + * If not, you get an empty class. + * This is useful, but not quite as useful as parsing a type. + * + * @param string $type MIME type + * + * @return void + */ + function MIME_Type($type = false) + { + if ($type) { + $this->parse($type); + } + } + + + /** + * Parse a mime-type and set the class variables. + * + * @param string $type MIME type to parse + * + * @return void + */ + function parse($type) + { + $this->media = $this->getMedia($type); + $this->subType = $this->getSubType($type); + $this->parameters = array(); + if (MIME_Type::hasParameters($type)) { + require_once 'MIME/Type/Parameter.php'; + foreach (MIME_Type::getParameters($type) as $param) { + $param = new MIME_Type_Parameter($param); + $this->parameters[$param->name] = $param; + } + } + } + + + /** + * Does this type have any parameters? + * + * @param string $type MIME type to check + * + * @return boolean true if $type has parameters, false otherwise + * @static + */ + function hasParameters($type) + { + if (strstr($type, ';')) { + return true; + } + return false; + } + + + /** + * Get a MIME type's parameters + * + * @param string $type MIME type to get parameters of + * + * @return array $type's parameters + * @static + */ + function getParameters($type) + { + $params = array(); + $tmp = explode(';', $type); + for ($i = 1; $i < count($tmp); $i++) { + $params[] = trim($tmp[$i]); + } + return $params; + } + + + /** + * Strip parameters from a MIME type string. + * + * @param string $type MIME type string + * + * @return string MIME type with parameters removed + * @static + */ + function stripParameters($type) + { + if (strstr($type, ';')) { + return substr($type, 0, strpos($type, ';')); + } + return $type; + } + + + /** + * Removes comments from a media type, subtype or parameter. + * + * @param string $string String to strip comments from + * @param string &$comment Comment is stored in there. + * + * @return string String without comments + * @static + */ + function stripComments($string, &$comment) + { + if (strpos($string, '(') === false) { + return $string; + } + + $inquote = false; + $quoting = false; + $incomment = 0; + $newstring = ''; + + for ($n = 0; $n < strlen($string); $n++) { + if ($quoting) { + if ($incomment == 0) { + $newstring .= $string[$n]; + } else if ($comment !== null) { + $comment .= $string[$n]; + } + $quoting = false; + } else if ($string[$n] == '\\') { + $quoting = true; + } else if (!$inquote && $incomment > 0 && $string[$n] == ')') { + $incomment--; + if ($incomment == 0 && $comment !== null) { + $comment .= ' '; + } + } else if (!$inquote && $string[$n] == '(') { + $incomment++; + } else if ($string[$n] == '"') { + if ($inquote) { + $inquote = false; + } else { + $inquote = true; + } + } else if ($incomment == 0) { + $newstring .= $string[$n]; + } else if ($comment !== null) { + $comment .= $string[$n]; + } + } + + if ($comment !== null) { + $comment = trim($comment); + } + + return $newstring; + } + + + /** + * Get a MIME type's media + * + * @note 'media' refers to the portion before the first slash + * + * @param string $type MIME type to get media of + * + * @return string $type's media + * @static + */ + function getMedia($type) + { + $tmp = explode('/', $type); + return strtolower(trim(MIME_Type::stripComments($tmp[0], $null))); + } + + + /** + * Get a MIME type's subtype + * + * @param string $type MIME type to get subtype of + * + * @return string $type's subtype, null if invalid mime type + * @static + */ + function getSubType($type) + { + $tmp = explode('/', $type); + if (!isset($tmp[1])) { + return null; + } + $tmp = explode(';', $tmp[1]); + return strtolower(trim(MIME_Type::stripComments($tmp[0], $null))); + } + + + /** + * Create a textual MIME type from object values + * + * This function performs the opposite function of parse(). + * + * @return string MIME type string + */ + function get() + { + $type = strtolower($this->media . '/' . $this->subType); + if (count($this->parameters)) { + foreach ($this->parameters as $key => $null) { + $type .= '; ' . $this->parameters[$key]->get(); + } + } + return $type; + } + + + /** + * Is this type experimental? + * + * @note Experimental types are denoted by a leading 'x-' in the media or + * subtype, e.g. text/x-vcard or x-world/x-vrml. + * + * @param string $type MIME type to check + * + * @return boolean true if $type is experimental, false otherwise + * @static + */ + function isExperimental($type) + { + if (substr(MIME_Type::getMedia($type), 0, 2) == 'x-' || + substr(MIME_Type::getSubType($type), 0, 2) == 'x-') { + return true; + } + return false; + } + + + /** + * Is this a vendor MIME type? + * + * @note Vendor types are denoted with a leading 'vnd. in the subtype. + * + * @param string $type MIME type to check + * + * @return boolean true if $type is a vendor type, false otherwise + * @static + */ + function isVendor($type) + { + if (substr(MIME_Type::getSubType($type), 0, 4) == 'vnd.') { + return true; + } + return false; + } + + + /** + * Is this a wildcard type? + * + * @param string $type MIME type to check + * + * @return boolean true if $type is a wildcard, false otherwise + * @static + */ + function isWildcard($type) + { + if ($type == '*/*' || MIME_Type::getSubtype($type) == '*') { + return true; + } + return false; + } + + + /** + * Perform a wildcard match on a MIME type + * + * Example: + * MIME_Type::wildcardMatch('image/*', 'image/png') + * + * @param string $card Wildcard to check against + * @param string $type MIME type to check + * + * @return boolean true if there was a match, false otherwise + * @static + */ + function wildcardMatch($card, $type) + { + if (!MIME_Type::isWildcard($card)) { + return false; + } + + if ($card == '*/*') { + return true; + } + + if (MIME_Type::getMedia($card) == MIME_Type::getMedia($type)) { + return true; + } + + return false; + } + + + /** + * Add a parameter to this type + * + * @param string $name Attribute name + * @param string $value Attribute value + * @param string $comment Comment for this parameter + * + * @return void + */ + function addParameter($name, $value, $comment = false) + { + $tmp = new MIME_Type_Parameter(); + + $tmp->name = $name; + $tmp->value = $value; + $tmp->comment = $comment; + $this->parameters[$name] = $tmp; + } + + + /** + * Remove a parameter from this type + * + * @param string $name Parameter name + * + * @return void + */ + function removeParameter($name) + { + unset($this->parameters[$name]); + } + + + /** + * Autodetect a file's MIME-type + * + * This function may be called staticly. + * + * @internal Tries to use fileinfo extension at first. If that + * does not work, mime_magic is used. If this is also not available + * or does not succeed, "file" command is tried to be executed with + * System_Command. When that fails, too, then we use our in-built + * extension-to-mimetype-mapping list. + * + * @param string $file Path to the file to get the type of + * @param bool $params Append MIME parameters if true + * + * @return string $file's MIME-type on success, PEAR_Error otherwise + * + * @since 1.0.0beta1 + * @static + */ + function autoDetect($file, $params = false) + { + // Sanity checks + if (!file_exists($file)) { + return PEAR::raiseError("File \"$file\" doesn't exist"); + } + + if (!is_readable($file)) { + return PEAR::raiseError("File \"$file\" is not readable"); + } + + if (function_exists('finfo_file')) { + $finfo = finfo_open(FILEINFO_MIME); + $type = finfo_file($finfo, $file); + finfo_close($finfo); + if ($type !== false && $type !== '') { + return MIME_Type::_handleDetection($type, $params); + } + } + + if (function_exists('mime_content_type')) { + $type = mime_content_type($file); + if ($type !== false && $type !== '') { + return MIME_Type::_handleDetection($type, $params); + } + } + + @include_once 'System/Command.php'; + if (class_exists('System_Command')) { + return MIME_Type::_handleDetection( + MIME_Type::_fileAutoDetect($file), + $params + ); + } + + require_once 'MIME/Type/Extension.php'; + $mte = new MIME_Type_Extension(); + return $mte->getMIMEType($file); + } + + + /** + * Handles a detected MIME type and modifies it if necessary. + * + * @param string $type MIME Type of a file + * @param bool $params Append MIME parameters if true + * + * @return string $file's MIME-type on success, PEAR_Error otherwise + */ + function _handleDetection($type, $params) + { + // _fileAutoDetect() may have returned an error. + if (PEAR::isError($type)) { + return $type; + } + + // Don't return an empty string + if (!$type || !strlen($type)) { + return PEAR::raiseError("Sorry, couldn't determine file type."); + } + + // Strip parameters if present & requested + if (MIME_Type::hasParameters($type) && !$params) { + $type = MIME_Type::stripParameters($type); + } + + return $type; + } + + + /** + * Autodetect a file's MIME-type with 'file' and System_Command + * + * This function may be called staticly. + * + * @param string $file Path to the file to get the type of + * + * @return string $file's MIME-type + * + * @since 1.0.0beta1 + * @static + */ + function _fileAutoDetect($file) + { + $cmd = new System_Command(); + + // Make sure we have the 'file' command. + $fileCmd = PEAR::getStaticProperty('MIME_Type', 'fileCmd'); + if (!$cmd->which($fileCmd)) { + unset($cmd); + return PEAR::raiseError("Can't find file command \"{$fileCmd}\""); + } + + $cmd->pushCommand($fileCmd, "-bi " . escapeshellarg($file)); + $res = $cmd->execute(); + unset($cmd); + + return $res; + } +} + diff --git a/extlib/MIME/Type/Extension.php b/extlib/MIME/Type/Extension.php new file mode 100644 index 000000000..1987e2a10 --- /dev/null +++ b/extlib/MIME/Type/Extension.php @@ -0,0 +1,298 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Extension.php,v 1.1 2009/01/16 11:49:45 cweiske Exp $ + +require_once 'PEAR.php'; + +/** + * Class for mapping file extensions to MIME types. + * + * @category MIME + * @package MIME_Type + * @author Christian Schmidt + * @license PHP License 3.0 + * @version 1.2.0 + * @link http://pear.php.net/package/MIME_Type + */ +class MIME_Type_Extension +{ + /** + * Mapping between file extension and MIME type. + * + * @internal The array is sorted alphabetically by value and with primary + * extension first. Be careful about not adding duplicate keys - PHP + * silently ignores duplicates. The following command can be used for + * checking for duplicates: + * grep "=> '" Extension.php | cut -d\' -f2 | sort | uniq -d + * application/octet-stream is generally used as fallback when no other + * MIME-type can be found, but the array does not contain a lot of such + * unknown extension. One entry exists, though, to allow detection of + * file extension for this MIME-type. + * + * @var array + */ + var $extensionToType = array ( + 'ez' => 'application/andrew-inset', + 'atom' => 'application/atom+xml', + 'jar' => 'application/java-archive', + 'hqx' => 'application/mac-binhex40', + 'cpt' => 'application/mac-compactpro', + 'mathml' => 'application/mathml+xml', + 'doc' => 'application/msword', + 'dat' => 'application/octet-stream', + 'oda' => 'application/oda', + 'ogg' => 'application/ogg', + 'pdf' => 'application/pdf', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + 'rdf' => 'application/rdf+xml', + 'rss' => 'application/rss+xml', + 'smi' => 'application/smil', + 'smil' => 'application/smil', + 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'kml' => 'application/vnd.google-earth.kml+xml', + 'kmz' => 'application/vnd.google-earth.kmz', + 'mif' => 'application/vnd.mif', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xls' => 'application/vnd.ms-excel', + 'xlb' => 'application/vnd.ms-excel', + 'xlt' => 'application/vnd.ms-excel', + 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', + 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', + 'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12', + 'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12', + 'docm' => 'application/vnd.ms-word.document.macroEnabled.12', + 'dotm' => 'application/vnd.ms-word.template.macroEnabled.12', + 'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12', + 'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12', + 'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12', + 'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12', + 'ppt' => 'application/vnd.ms-powerpoint', + 'pps' => 'application/vnd.ms-powerpoint', + 'odc' => 'application/vnd.oasis.opendocument.chart', + 'odb' => 'application/vnd.oasis.opendocument.database', + 'odf' => 'application/vnd.oasis.opendocument.formula', + 'odg' => 'application/vnd.oasis.opendocument.graphics', + 'otg' => 'application/vnd.oasis.opendocument.graphics-template', + 'odi' => 'application/vnd.oasis.opendocument.image', + 'odp' => 'application/vnd.oasis.opendocument.presentation', + 'otp' => 'application/vnd.oasis.opendocument.presentation-template', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', + 'odt' => 'application/vnd.oasis.opendocument.text', + 'odm' => 'application/vnd.oasis.opendocument.text-master', + 'ott' => 'application/vnd.oasis.opendocument.text-template', + 'oth' => 'application/vnd.oasis.opendocument.text-web', + 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', + 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', + 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', + 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', + 'vsd' => 'application/vnd.visio', + 'wbxml' => 'application/vnd.wap.wbxml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'vxml' => 'application/voicexml+xml', + 'bcpio' => 'application/x-bcpio', + 'vcd' => 'application/x-cdlink', + 'pgn' => 'application/x-chess-pgn', + 'cpio' => 'application/x-cpio', + 'csh' => 'application/x-csh', + 'dcr' => 'application/x-director', + 'dir' => 'application/x-director', + 'dxr' => 'application/x-director', + 'dvi' => 'application/x-dvi', + 'spl' => 'application/x-futuresplash', + 'tgz' => 'application/x-gtar', + 'gtar' => 'application/x-gtar', + 'hdf' => 'application/x-hdf', + 'js' => 'application/x-javascript', + 'skp' => 'application/x-koan', + 'skd' => 'application/x-koan', + 'skt' => 'application/x-koan', + 'skm' => 'application/x-koan', + 'latex' => 'application/x-latex', + 'nc' => 'application/x-netcdf', + 'cdf' => 'application/x-netcdf', + 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', + 'swf' => 'application/x-shockwave-flash', + 'sit' => 'application/x-stuffit', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', + 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', + 'tex' => 'application/x-tex', + 'texinfo' => 'application/x-texinfo', + 'texi' => 'application/x-texinfo', + 't' => 'application/x-troff', + 'tr' => 'application/x-troff', + 'roff' => 'application/x-troff', + 'man' => 'application/x-troff-man', + 'me' => 'application/x-troff-me', + 'ms' => 'application/x-troff-ms', + 'ustar' => 'application/x-ustar', + 'src' => 'application/x-wais-source', + 'xhtml' => 'application/xhtml+xml', + 'xht' => 'application/xhtml+xml', + 'xslt' => 'application/xslt+xml', + 'xml' => 'application/xml', + 'xsl' => 'application/xml', + 'dtd' => 'application/xml-dtd', + 'zip' => 'application/zip', + 'au' => 'audio/basic', + 'snd' => 'audio/basic', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'kar' => 'audio/midi', + 'mpga' => 'audio/mpeg', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'aif' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'm3u' => 'audio/x-mpegurl', + 'wma' => 'audio/x-ms-wma', + 'wax' => 'audio/x-ms-wax', + 'ram' => 'audio/x-pn-realaudio', + 'ra' => 'audio/x-pn-realaudio', + 'rm' => 'application/vnd.rn-realmedia', + 'wav' => 'audio/x-wav', + 'pdb' => 'chemical/x-pdb', + 'xyz' => 'chemical/x-xyz', + 'bmp' => 'image/bmp', + 'cgm' => 'image/cgm', + 'gif' => 'image/gif', + 'ief' => 'image/ief', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'jpe' => 'image/jpeg', + 'png' => 'image/png', + 'svg' => 'image/svg+xml', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'djvu' => 'image/vnd.djvu', + 'djv' => 'image/vnd.djvu', + 'wbmp' => 'image/vnd.wap.wbmp', + 'ras' => 'image/x-cmu-raster', + 'ico' => 'image/x-icon', + 'pnm' => 'image/x-portable-anymap', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'ppm' => 'image/x-portable-pixmap', + 'rgb' => 'image/x-rgb', + 'xbm' => 'image/x-xbitmap', + 'psd' => 'image/x-photoshop', + 'xpm' => 'image/x-xpixmap', + 'xwd' => 'image/x-xwindowdump', + 'eml' => 'message/rfc822', + 'igs' => 'model/iges', + 'iges' => 'model/iges', + 'msh' => 'model/mesh', + 'mesh' => 'model/mesh', + 'silo' => 'model/mesh', + 'wrl' => 'model/vrml', + 'vrml' => 'model/vrml', + 'ics' => 'text/calendar', + 'ifb' => 'text/calendar', + 'css' => 'text/css', + 'csv' => 'text/csv', + 'html' => 'text/html', + 'htm' => 'text/html', + 'txt' => 'text/plain', + 'asc' => 'text/plain', + 'rtx' => 'text/richtext', + 'rtf' => 'text/rtf', + 'sgml' => 'text/sgml', + 'sgm' => 'text/sgml', + 'tsv' => 'text/tab-separated-values', + 'wml' => 'text/vnd.wap.wml', + 'wmls' => 'text/vnd.wap.wmlscript', + 'etx' => 'text/x-setext', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpe' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + 'mxu' => 'video/vnd.mpegurl', + 'm4u' => 'video/vnd.mpegurl', + 'flv' => 'video/x-flv', + 'asf' => 'video/x-ms-asf', + 'asx' => 'video/x-ms-asf', + 'wmv' => 'video/x-ms-wmv', + 'wm' => 'video/x-ms-wm', + 'wmx' => 'video/x-ms-wmx', + 'avi' => 'video/x-msvideo', + 'ogv' => 'video/ogg', + 'movie' => 'video/x-sgi-movie', + 'ice' => 'x-conference/x-cooltalk', + ); + + + + /** + * Autodetect a file's MIME-type. + * + * @param string $file Path to the file to get the type of + * + * @return string $file's MIME-type on success, PEAR_Error otherwise + */ + function getMIMEType($file) + { + $extension = substr(strrchr($file, '.'), 1); + if ($extension === false) { + return PEAR::raiseError("File has no extension."); + } + + if (!isset($this->extensionToType[$extension])) { + return PEAR::raiseError("Sorry, couldn't determine file type."); + } + + return $this->extensionToType[$extension]; + } + + + + /** + * Return default MIME-type for the specified extension. + * + * @param string $type MIME-type + * + * @return string A file extension without leading period. + */ + function getExtension($type) + { + require_once 'MIME/Type.php'; + // Strip parameters and comments. + $type = MIME_Type::getMedia($type) . '/' . MIME_Type::getSubType($type); + + $extension = array_search($type, $this->extensionToType); + if ($extension === false) { + return PEAR::raiseError("Sorry, couldn't determine extension."); + } + return $extension; + } + +} + +?> \ No newline at end of file diff --git a/extlib/MIME/Type/Parameter.php b/extlib/MIME/Type/Parameter.php new file mode 100644 index 000000000..399d3dd7a --- /dev/null +++ b/extlib/MIME/Type/Parameter.php @@ -0,0 +1,163 @@ + | +// +----------------------------------------------------------------------+ +// +// $Id: Parameter.php,v 1.1 2007/03/25 10:10:21 cweiske Exp $ + +/** + * Class for working with MIME type parameters + * + * @version 1.2.0 + * @package MIME_Type + * @author Ian Eure + */ +class MIME_Type_Parameter { + /** + * Parameter name + * + * @var string + */ + var $name; + + /** + * Parameter value + * + * @var string + */ + var $value; + + /** + * Parameter comment + * + * @var string + */ + var $comment; + + + /** + * Constructor. + * + * @param string $param MIME parameter to parse, if set. + * @return void + */ + function MIME_Type_Parameter($param = false) + { + if ($param) { + $this->parse($param); + } + } + + + /** + * Parse a MIME type parameter and set object fields + * + * @param string $param MIME type parameter to parse + * @return void + */ + function parse($param) + { + $comment = ''; + $param = MIME_Type::stripComments($param, $comment); + $this->name = $this->getAttribute($param); + $this->value = $this->getValue($param); + $this->comment = $comment; + } + + + /** + * Get a parameter attribute (e.g. name) + * + * @param string MIME type parameter + * @return string Attribute name + * @static + */ + function getAttribute($param) + { + $tmp = explode('=', $param); + return trim($tmp[0]); + } + + + /** + * Get a parameter value + * + * @param string $param MIME type parameter + * @return string Value + * @static + */ + function getValue($param) + { + $tmp = explode('=', $param, 2); + $value = $tmp[1]; + $value = trim($value); + if ($value[0] == '"' && $value[strlen($value)-1] == '"') { + $value = substr($value, 1, -1); + } + $value = str_replace('\\"', '"', $value); + return $value; + } + + + /** + * Get a parameter comment + * + * @param string $param MIME type parameter + * @return string Parameter comment + * @see getComment() + * @static + */ + function getComment($param) + { + $cs = strpos($param, '('); + $comment = substr($param, $cs); + return trim($comment, '() '); + } + + + /** + * Does this parameter have a comment? + * + * @param string $param MIME type parameter + * @return boolean true if $param has a comment, false otherwise + * @static + */ + function hasComment($param) + { + if (strstr($param, '(')) { + return true; + } + return false; + } + + + /** + * Get a string representation of this parameter + * + * This function performs the oppsite of parse() + * + * @return string String representation of parameter + */ + function get() + { + $val = $this->name . '="' . str_replace('"', '\\"', $this->value) . '"'; + if ($this->comment) { + $val .= ' (' . $this->comment . ')'; + } + return $val; + } +} +?> \ No newline at end of file diff --git a/lib/common.php b/lib/common.php index 0ce46442d..ede8d6277 100644 --- a/lib/common.php +++ b/lib/common.php @@ -163,6 +163,40 @@ $config = array('run' => 'web', 'frequency' => 10000, 'reporturl' => 'http://laconi.ca/stats/report'), + 'attachments' => + array('supported' => array('image/png', + 'image/jpeg', + 'image/gif', + 'image/svg+xml', + 'audio/mpeg', + 'application/ogg', + 'application/pdf', + 'application/vnd.oasis.opendocument.text', + 'application/vnd.oasis.opendocument.text-template', + 'application/vnd.oasis.opendocument.graphics', + 'application/vnd.oasis.opendocument.graphics-template', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.presentation-template', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.spreadsheet-template', + 'application/vnd.oasis.opendocument.chart', + 'application/vnd.oasis.opendocument.chart-template', + 'application/vnd.oasis.opendocument.image', + 'application/vnd.oasis.opendocument.image-template', + 'application/vnd.oasis.opendocument.formula', + 'application/vnd.oasis.opendocument.formula-template', + 'application/vnd.oasis.opendocument.text-master', + 'application/vnd.oasis.opendocument.text-web', + 'application/zip', + 'text/plain', + 'video/mpeg', + 'video/mp4', + 'video/quicktime', + 'video/mpeg'), + 'file_quota' => 5000000, + 'user_quota' => 50000000, + 'monthly_quota' => 15000000, + ), ); $config['db'] = &PEAR::getStaticProperty('DB_DataObject','options'); @@ -223,19 +257,19 @@ if ($_db_name != 'laconica' && !array_key_exists('ini_'.$_db_name, $config['db'] // XXX: how many of these could be auto-loaded on use? -require_once('Validate.php'); -require_once('markdown.php'); +require_once 'Validate.php'; +require_once 'markdown.php'; -require_once(INSTALLDIR.'/lib/util.php'); -require_once(INSTALLDIR.'/lib/action.php'); -require_once(INSTALLDIR.'/lib/theme.php'); -require_once(INSTALLDIR.'/lib/mail.php'); -require_once(INSTALLDIR.'/lib/subs.php'); -require_once(INSTALLDIR.'/lib/Shorturl_api.php'); -require_once(INSTALLDIR.'/lib/twitter.php'); +require_once INSTALLDIR.'/lib/util.php'; +require_once INSTALLDIR.'/lib/action.php'; +require_once INSTALLDIR.'/lib/theme.php'; +require_once INSTALLDIR.'/lib/mail.php'; +require_once INSTALLDIR.'/lib/subs.php'; +require_once INSTALLDIR.'/lib/Shorturl_api.php'; +require_once INSTALLDIR.'/lib/twitter.php'; -require_once(INSTALLDIR.'/lib/clientexception.php'); -require_once(INSTALLDIR.'/lib/serverexception.php'); +require_once INSTALLDIR.'/lib/clientexception.php'; +require_once INSTALLDIR.'/lib/serverexception.php'; // XXX: other formats here -- cgit v1.2.3-54-g00ecf From f8dae2bbc9600a4ad474e924dc540491e29e2767 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Sun, 31 May 2009 21:03:55 -0400 Subject: Refactored some attachment code and fixed upload bug in interface. --- actions/newnotice.php | 38 ++++++-------------------------------- classes/File.php | 26 ++++++++++++++++++++++++++ lib/noticeform.php | 2 -- 3 files changed, 32 insertions(+), 34 deletions(-) (limited to 'actions') diff --git a/actions/newnotice.php b/actions/newnotice.php index 29b748dd1..a24d62684 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -131,37 +131,10 @@ class NewnoticeAction extends Action } function isRespectsQuota($user) { - if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) { - $this->clientError(sprintf(_('No file may be larger than %d bytes ' . - 'and the file you sent was %d bytes. Try to upload a smaller version.'), - common_config('attachments', 'file_quota'), $_FILES['attach']['size'])); - } - - $query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'"; $file = new File; - $file->query($query); - $file->fetch(); - $total = $file->total + $_FILES['attach']['size']; - if ($total > common_config('attachments', 'user_quota')) { - $this->clientError(sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota'))); - } - - $query .= ' month(modified) = month(now()) and year(modified) = year(now())'; - $file2 = new File; - $file2->query($query); - $file2->fetch(); - $total2 = $file2->total + $_FILES['attach']['size']; - if ($total2 > common_config('attachments', 'monthly_quota')) { - $this->clientError(sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota'))); - } - return true; - } - - function isValidFileAttached($user) { - return isset($_FILES['attach']['error']) - && ($_FILES['attach']['error'] === UPLOAD_ERR_OK) - && $this->isSupportedFileType() - && $this->isRespectsQuota($user); + $ret = $file->isRespectsQuota($user); + if (true === $ret) return true; + $this->clientError($ret); } /** @@ -212,6 +185,7 @@ class NewnoticeAction extends Action $replyto = 'false'; } + if (isset($_FILES['attach']['error'])) { switch ($_FILES['attach']['error']) { case UPLOAD_ERR_NO_FILE: // no file uploaded @@ -223,8 +197,7 @@ class NewnoticeAction extends Action // lets check if we really support its format // and it doesn't go over quotas - - if (!$this->isValidFileAttached($user)) { + if (!$this->isSupportedFileType() || !$this->isRespectsQuota($user)) { die('clientError() should trigger an exception before reaching here.'); } break; @@ -250,6 +223,7 @@ class NewnoticeAction extends Action default: die('Should never reach here.'); } + } $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, ($replyto == 'false') ? null : $replyto); diff --git a/classes/File.php b/classes/File.php index e5913115b..24ab11b8e 100644 --- a/classes/File.php +++ b/classes/File.php @@ -120,4 +120,30 @@ class File extends Memcached_DataObject File_to_post::processNew($file_id, $notice_id); return $x; } + + function isRespectsQuota($user) { + if ($_FILES['attach']['size'] > common_config('attachments', 'file_quota')) { + return sprintf(_('No file may be larger than %d bytes ' . + 'and the file you sent was %d bytes. Try to upload a smaller version.'), + common_config('attachments', 'file_quota'), $_FILES['attach']['size']); + } + + $query = "select sum(size) as total from file join file_to_post on file_to_post.file_id = file.id join notice on file_to_post.post_id = notice.id where profile_id = {$user->id} and file.url like '%/notice/%/file'"; + $this->query($query); + $this->fetch(); + $total = $this->total + $_FILES['attach']['size']; + if ($total > common_config('attachments', 'user_quota')) { + return sprintf(_('A file this large would exceed your user quota of %d bytes.'), common_config('attachments', 'user_quota')); + } + + $query .= ' month(modified) = month(now()) and year(modified) = year(now())'; + $this->query($query); + $this->fetch(); + $total = $this->total + $_FILES['attach']['size']; + if ($total > common_config('attachments', 'monthly_quota')) { + return sprintf(_('A file this large would exceed your monthly quota of %d bytes.'), common_config('attachments', 'monthly_quota')); + } + return true; + } } + diff --git a/lib/noticeform.php b/lib/noticeform.php index 5f438327d..7c88bd7b1 100644 --- a/lib/noticeform.php +++ b/lib/noticeform.php @@ -156,9 +156,7 @@ class NoticeForm extends Form $this->out->hidden('notice_return-to', $this->action, 'returnto'); } $this->out->hidden('notice_in-reply-to', $this->action, 'inreplyto'); - $this->out->hidden('MAX_FILE_SIZE', common_config('attachments', 'file_quota')); - } /** -- cgit v1.2.3-54-g00ecf From 683b835c3ed0be5f691795c64b1217896e1dad95 Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 1 Jun 2009 14:02:59 -0400 Subject: Attachments popups for supported files are now embedded with the object xhtml tag. --- actions/newnotice.php | 69 ++++++++++++++++++++++++-------------------------- lib/attachmentlist.php | 17 +++++++++++++ lib/common.php | 1 + 3 files changed, 51 insertions(+), 36 deletions(-) (limited to 'actions') diff --git a/actions/newnotice.php b/actions/newnotice.php index a24d62684..3e6ff1518 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -113,12 +113,12 @@ class NewnoticeAction extends Action } } - function isSupportedFileType() { + function getUploadedFileType() { require_once 'MIME/Type.php'; $filetype = MIME_Type::autoDetect($_FILES['attach']['tmp_name']); if (in_array($filetype, common_config('attachments', 'supported'))) { - return true; + return $filetype; } $media = MIME_Type::getMedia($filetype); if ('application' !== $media) { @@ -186,43 +186,39 @@ class NewnoticeAction extends Action } if (isset($_FILES['attach']['error'])) { - switch ($_FILES['attach']['error']) { - case UPLOAD_ERR_NO_FILE: - // no file uploaded - // nothing to do - break; + switch ($_FILES['attach']['error']) { + case UPLOAD_ERR_NO_FILE: + // no file uploaded, nothing to do + break; - case UPLOAD_ERR_OK: - // file was uploaded alright - // lets check if we really support its format - // and it doesn't go over quotas + case UPLOAD_ERR_OK: + $mimetype = $this->getUploadedFileType(); + if (!$this->isRespectsQuota($user)) { + die('clientError() should trigger an exception before reaching here.'); + } + break; - if (!$this->isSupportedFileType() || !$this->isRespectsQuota($user)) { - die('clientError() should trigger an exception before reaching here.'); - } - break; + case UPLOAD_ERR_INI_SIZE: + $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.')); - case UPLOAD_ERR_INI_SIZE: - $this->clientError(_('The uploaded file exceeds the upload_max_filesize directive in php.ini.')); + case UPLOAD_ERR_FORM_SIZE: + $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.')); - case UPLOAD_ERR_FORM_SIZE: - $this->clientError(_('The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.')); + case UPLOAD_ERR_PARTIAL: + $this->clientError(_('The uploaded file was only partially uploaded.')); - case UPLOAD_ERR_PARTIAL: - $this->clientError(_('The uploaded file was only partially uploaded.')); + case UPLOAD_ERR_NO_TMP_DIR: + $this->clientError(_('Missing a temporary folder.')); - case UPLOAD_ERR_NO_TMP_DIR: - $this->clientError(_('Missing a temporary folder.')); + case UPLOAD_ERR_CANT_WRITE: + $this->clientError(_('Failed to write file to disk.')); - case UPLOAD_ERR_CANT_WRITE: - $this->clientError(_('Failed to write file to disk.')); + case UPLOAD_ERR_EXTENSION: + $this->clientError(_('File upload stopped by extension.')); - case UPLOAD_ERR_EXTENSION: - $this->clientError(_('File upload stopped by extension.')); - - default: - die('Should never reach here.'); - } + default: + die('Should never reach here.'); + } } $notice = Notice::saveNew($user->id, $content_shortened, 'web', 1, @@ -232,7 +228,9 @@ class NewnoticeAction extends Action $this->clientError($notice); } - $this->storeFile($notice); + if (isset($mimetype)) { + $this->storeFile($notice, $mimetype); + } $this->saveUrls($notice); common_broadcast_notice($notice); @@ -259,8 +257,7 @@ class NewnoticeAction extends Action } } - function storeFile($notice) { - if (UPLOAD_ERR_NO_FILE === $_FILES['attach']['error']) return; + function storeFile($notice, $mimetype) { $filename = basename($_FILES['attach']['name']); $destination = "file/{$notice->id}-$filename"; if (move_uploaded_file($_FILES['attach']['tmp_name'], INSTALLDIR . "/$destination")) { @@ -268,7 +265,7 @@ class NewnoticeAction extends Action $file->url = common_local_url('file', array('notice' => $notice->id)); $file->size = filesize(INSTALLDIR . "/$destination"); $file->date = time(); - $file->mimetype = $_FILES['attach']['type']; + $file->mimetype = $mimetype; if ($file_id = $file->insert()) { $file_redir = new File_redirection; $file_redir->url = common_path($destination); @@ -285,7 +282,6 @@ class NewnoticeAction extends Action } } - /** save all urls in the notice to the db * * follow redirects and save all available file information @@ -408,3 +404,4 @@ class NewnoticeAction extends Action $nli->show(); } } + diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 61749dca5..45e4fa319 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -268,6 +268,23 @@ class Attachment extends AttachmentListItem case 'image/jpeg': $this->out->element('img', array('src' => $this->attachment->url, 'alt' => 'alt')); break; + + case 'application/ogg': + case 'audio/x-speex': + case 'video/mpeg': + case 'audio/mpeg': + case 'video/mp4': + case 'video/quicktime': + $arr = array('type' => $this->attachment->mimetype, + 'data' => $this->attachment->url, + 'width' => 320, + 'height' => 240 + ); + $this->out->elementStart('object', $arr); + $this->out->element('param', array('name' => 'src', 'value' => $this->attachment->url)); + $this->out->element('param', array('name' => 'autoStart', 'value' => 1)); + $this->out->elementEnd('object'); + break; } } } else { diff --git a/lib/common.php b/lib/common.php index 838f52f9d..ceb50337c 100644 --- a/lib/common.php +++ b/lib/common.php @@ -169,6 +169,7 @@ $config = 'image/gif', 'image/svg+xml', 'audio/mpeg', + 'audio/x-speex', 'application/ogg', 'application/pdf', 'application/vnd.oasis.opendocument.text', -- cgit v1.2.3-54-g00ecf From fe38827a76520e4a910f9e988b11d0914872d44e Mon Sep 17 00:00:00 2001 From: Robin Millette Date: Mon, 1 Jun 2009 17:40:53 -0400 Subject: Remove js that crept back in, added another error string. --- actions/newnotice.php | 2 ++ js/util.js | 24 ------------------------ lib/attachmentlist.php | 2 +- 3 files changed, 3 insertions(+), 25 deletions(-) (limited to 'actions') diff --git a/actions/newnotice.php b/actions/newnotice.php index 3e6ff1518..02976a2ae 100644 --- a/actions/newnotice.php +++ b/actions/newnotice.php @@ -279,6 +279,8 @@ class NewnoticeAction extends Action } else { $this->clientError(_('There was a database error while saving your file. Please try again.')); } + } else { + $this->clientError(_('File could not be moved to destination directory.')); } } diff --git a/js/util.js b/js/util.js index acf44a17c..bffbf916f 100644 --- a/js/util.js +++ b/js/util.js @@ -28,30 +28,6 @@ $(document).ready(function(){ } }); - $('a.attachment').click(function() {$().jOverlay({url: $('address .url')[0].href+'/attachment/' + ($(this).attr('id').substring('attachment'.length + 1)) + '/ajax'}); return false; }); - $("a.thumbnail").hover( - function() { - var anchor = $(this); - $("a.thumbnail").children('img').remove(); - - setTimeout(function() { - anchor.closest(".entry-title").addClass('ov'); - $.get($('address .url')[0].href+'/attachment/' + (anchor.attr('id').substring('attachment'.length + 1)) + '/thumbnail', null, function(data) { - anchor.append(data); - }); - }, 250); - - setTimeout(function() { - anchor.children('img').remove(); - anchor.closest(".entry-title").removeClass('ov'); - }, 3000); - }, - function() { - $(this).children('img').remove(); - $(this).closest(".entry-title").removeClass('ov'); - } - ); - // count character on keyup function counter(event){ var maxLength = 140; diff --git a/lib/attachmentlist.php b/lib/attachmentlist.php index 898be1bb0..45e4fa319 100644 --- a/lib/attachmentlist.php +++ b/lib/attachmentlist.php @@ -83,7 +83,7 @@ class AttachmentList extends Widget $atts = new File; $att = $atts->getAttachments($this->notice->id); if (empty($att)) return 0; - $this->out->elementStart('dl', array('id' =>'attachment')); + $this->out->elementStart('dl', array('id' =>'attachments')); $this->out->element('dt', null, _('Attachments')); $this->out->elementStart('dd'); $this->out->elementStart('ol', array('class' => 'attachments')); -- cgit v1.2.3-54-g00ecf From 6658e2a2ee9517bebd59cf69d7483e6eda691b4e Mon Sep 17 00:00:00 2001 From: Dan Moore Date: Thu, 4 Jun 2009 17:57:03 -0400 Subject: Handle the ways Twitter accepts passing the user in the query string. --- actions/api.php | 4 ++-- lib/twitterapi.php | 22 +++++++++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'actions') diff --git a/actions/api.php b/actions/api.php index b25ba99f3..b8da852b5 100644 --- a/actions/api.php +++ b/actions/api.php @@ -144,8 +144,8 @@ class ApiAction extends Action } if (in_array($fullname, $bareauth)) { - # bareauth: only needs auth if without an argument - if ($this->api_arg) { + # bareauth: only needs auth if without an argument or query param specifying user + if ($this->api_arg || $this->arg('id') || is_numeric($this->arg('user_id')) || $this->arg('screen_name')) { return false; } else { return true; diff --git a/lib/twitterapi.php b/lib/twitterapi.php index 1d527b935..ca8b03cdc 100644 --- a/lib/twitterapi.php +++ b/lib/twitterapi.php @@ -673,7 +673,27 @@ class TwitterapiAction extends Action function get_user($id, $apidata=null) { if (!$id) { - return $apidata['user']; + + // Twitter supports these other ways of passing the user ID + if (is_numeric($this->arg('id'))) { + return User::staticGet($this->arg('id')); + } else if ($this->arg('id')) { + $nickname = common_canonical_nickname($this->arg('id')); + return User::staticGet('nickname', $nickname); + } else if ($this->arg('user_id')) { + // This is to ensure that a non-numeric user_id still + // overrides screen_name even if it doesn't get used + if (is_numeric($this->arg('user_id'))) { + return User::staticGet('id', $this->arg('user_id')); + } + } else if ($this->arg('screen_name')) { + $nickname = common_canonical_nickname($this->arg('screen_name')); + return User::staticGet('nickname', $nickname); + } else { + // Fall back to trying the currently authenticated user + return $apidata['user']; + } + } else if (is_numeric($id)) { return User::staticGet($id); } else { -- cgit v1.2.3-54-g00ecf