Merge branch 'master' of git@gitorious.org:laconica/mainline

This commit is contained in:
Evan Prodromou 2009-08-10 16:33:36 -04:00
commit 6aee059033
10 changed files with 478 additions and 231 deletions

View File

@ -1,5 +1,16 @@
<?php
/*
/**
* Unsubscribe handler
*
* PHP version 5
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*
* Laconica - a distributed open-source microblogging tool
* Copyright (C) 2008, 2009, Control Yourself, Inc.
*
@ -17,6 +28,20 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
if (!defined('LACONICA')) {
exit(1);
}
/**
* Unsubscribe handler
*
* @category Action
* @package Laconica
* @author Evan Prodromou <evan@controlyourself.ca>
* @author Robin Millette <millette@controlyourself.ca>
* @license http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
* @link http://laconi.ca/
*/
class UnsubscribeAction extends Action
{
@ -31,16 +56,18 @@ class UnsubscribeAction extends Action
$user = common_current_user();
if ($_SERVER['REQUEST_METHOD'] != 'POST') {
common_redirect(common_local_url('subscriptions', array('nickname' => $user->nickname)));
common_redirect(common_local_url('subscriptions',
array('nickname' => $user->nickname)));
return;
}
# CSRF protection
/* Use a session token for 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.'));
$this->clientError(_('There was a problem with your session token. ' .
'Try again, please.'));
return;
}
@ -53,7 +80,7 @@ class UnsubscribeAction extends Action
$other = Profile::staticGet('id', $other_id);
if (!$other_id) {
if (!$other) {
$this->clientError(_('No profile with that id.'));
return;
}
@ -76,8 +103,8 @@ class UnsubscribeAction extends Action
$this->elementEnd('body');
$this->elementEnd('html');
} else {
common_redirect(common_local_url('subscriptions', array('nickname' =>
$user->nickname)),
common_redirect(common_local_url('subscriptions',
array('nickname' => $user->nickname)),
303);
}
}

View File

@ -115,7 +115,7 @@ class Design extends Memcached_DataObject
return new WebColor($color);
} catch (WebColorException $e) {
// This shouldn't happen
common_log(LOG_ERR, "Unable to create color for design $id.",
common_log(LOG_ERR, "Unable to create web color for $color",
__FILE__);
return null;
}
@ -204,7 +204,10 @@ class Design extends Memcached_DataObject
'disposition');
foreach ($attrs as $attr) {
$siteDesign->$attr = common_config('design', $attr);
$val = common_config('design', $attr);
if ($val !== false) {
$siteDesign->$attr = $val;
}
}
}

View File

@ -107,13 +107,13 @@ class Facebook {
* @param bool resolve_auth_token convert an auth token into a session
*/
public function validate_fb_params($resolve_auth_token=true) {
$this->fb_params = $this->get_valid_fb_params($_POST, 48*3600, 'fb_sig');
$this->fb_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_sig');
// note that with preload FQL, it's possible to receive POST params in
// addition to GET, so use a different prefix to differentiate them
if (!$this->fb_params) {
$fb_params = $this->get_valid_fb_params($_GET, 48*3600, 'fb_sig');
$fb_post_params = $this->get_valid_fb_params($_POST, 48*3600, 'fb_post_sig');
$fb_params = $this->get_valid_fb_params($_GET, 48 * 3600, 'fb_sig');
$fb_post_params = $this->get_valid_fb_params($_POST, 48 * 3600, 'fb_post_sig');
$this->fb_params = array_merge($fb_params, $fb_post_params);
}

View File

@ -55,6 +55,7 @@ class FacebookRestClient {
private $pending_batch;
private $call_as_apikey;
private $use_curl_if_available;
private $format = null;
const BATCH_MODE_DEFAULT = 0;
const BATCH_MODE_SERVER_PARALLEL = 0;
@ -178,39 +179,32 @@ function toggleDisplay(id, type) {
private function execute_server_side_batch() {
$item_count = count($this->batch_queue);
$method_feed = array();
foreach($this->batch_queue as $batch_item) {
foreach ($this->batch_queue as $batch_item) {
$method = $batch_item['m'];
$params = $batch_item['p'];
$this->finalize_params($method, $params);
$method_feed[] = $this->create_post_string($method, $params);
list($get, $post) = $this->finalize_params($method, $params);
$method_feed[] = $this->create_url_string(array_merge($post, $get));
}
$method_feed_json = json_encode($method_feed);
$serial_only =
($this->batch_mode == FacebookRestClient::BATCH_MODE_SERIAL_ONLY);
$params = array('method_feed' => $method_feed_json,
'serial_only' => $serial_only);
if ($this->call_as_apikey) {
$params['call_as_apikey'] = $this->call_as_apikey;
}
$xml = $this->post_request('batch.run', $params);
$result = $this->convert_xml_to_result($xml, 'batch.run', $params);
$params = array('method_feed' => json_encode($method_feed),
'serial_only' => $serial_only,
'format' => $this->format);
$result = $this->call_method('facebook.batch.run', $params);
if (is_array($result) && isset($result['error_code'])) {
throw new FacebookRestClientException($result['error_msg'],
$result['error_code']);
}
for($i = 0; $i < $item_count; $i++) {
for ($i = 0; $i < $item_count; $i++) {
$batch_item = $this->batch_queue[$i];
$batch_item_result_xml = $result[$i];
$batch_item_result = $this->convert_xml_to_result($batch_item_result_xml,
$batch_item['m'],
$batch_item['p']);
$batch_item['p']['format'] = $this->format;
$batch_item_result = $this->convert_result($result[$i],
$batch_item['m'],
$batch_item['p']);
if (is_array($batch_item_result) &&
isset($batch_item_result['error_code'])) {
@ -516,12 +510,20 @@ function toggleDisplay(id, type) {
* behalf of app. Successful creation guarantees app will be admin.
*
* @param assoc array $event_info json encoded event information
* @param string $file (Optional) filename of picture to set
*
* @return int event id
*/
public function &events_create($event_info) {
return $this->call_method('facebook.events.create',
public function events_create($event_info, $file = null) {
if ($file) {
return $this->call_upload_method('facebook.events.create',
array('event_info' => $event_info),
$file,
Facebook::get_facebook_url('api-photo') . '/restserver.php');
} else {
return $this->call_method('facebook.events.create',
array('event_info' => $event_info));
}
}
/**
@ -529,13 +531,21 @@ function toggleDisplay(id, type) {
*
* @param int $eid event id
* @param assoc array $event_info json encoded event information
* @param string $file (Optional) filename of new picture to set
*
* @return bool true if successful
*/
public function &events_edit($eid, $event_info) {
return $this->call_method('facebook.events.edit',
public function events_edit($eid, $event_info, $file = null) {
if ($file) {
return $this->call_upload_method('facebook.events.edit',
array('eid' => $eid, 'event_info' => $event_info),
$file,
Facebook::get_facebook_url('api-photo') . '/restserver.php');
} else {
return $this->call_method('facebook.events.edit',
array('eid' => $eid,
'event_info' => $event_info));
'event_info' => $event_info));
}
}
/**
@ -935,7 +945,7 @@ function toggleDisplay(id, type) {
/**
* Makes an FQL query. This is a generalized way of accessing all the data
* in the API, as an alternative to most of the other method calls. More
* info at http://developers.facebook.com/documentation.php?v=1.0&doc=fql
* info at http://wiki.developers.facebook.com/index.php/FQL
*
* @param string $query the query to evaluate
*
@ -946,6 +956,21 @@ function toggleDisplay(id, type) {
array('query' => $query));
}
/**
* Makes a set of FQL queries in parallel. This method takes a dictionary
* of FQL queries where the keys are names for the queries. Results from
* one query can be used within another query to fetch additional data. More
* info about FQL queries at http://wiki.developers.facebook.com/index.php/FQL
*
* @param string $queries JSON-encoded dictionary of queries to evaluate
*
* @return array generalized array representing the results
*/
public function &fql_multiquery($queries) {
return $this->call_method('facebook.fql.multiquery',
array('queries' => $queries));
}
/**
* Returns whether or not pairs of users are friends.
* Note that the Facebook friend relationship is symmetric.
@ -994,6 +1019,23 @@ function toggleDisplay(id, type) {
}
/**
* Returns the mutual friends between the target uid and a source uid or
* the current session user.
*
* @param int $target_uid Target uid for which mutual friends will be found.
* @param int $source_uid (optional) Source uid for which mutual friends will
* be found. If no source_uid is specified,
* source_id will default to the session
* user.
* @return array An array of friend uids
*/
public function &friends_getMutualFriends($target_uid, $source_uid = null) {
return $this->call_method('facebook.friends.getMutualFriends',
array("target_uid" => $target_uid,
"source_uid" => $source_uid));
}
/**
* Returns the set of friend lists for the current session user.
*
@ -1168,6 +1210,44 @@ function toggleDisplay(id, type) {
array('permissions_apikey' => $permissions_apikey));
}
/**
* Payments Order API
*/
/**
* Set Payments properties for an app.
*
* @param properties a map from property names to values
* @return true on success
*/
public function payments_setProperties($properties) {
return $this->call_method ('facebook.payments.setProperties',
array('properties' => json_encode($properties)));
}
public function payments_getOrderDetails($order_id) {
return json_decode($this->call_method(
'facebook.payments.getOrderDetails',
array('order_id' => $order_id)), true);
}
public function payments_updateOrder($order_id, $status,
$params) {
return $this->call_method('facebook.payments.updateOrder',
array('order_id' => $order_id,
'status' => $status,
'params' => json_encode($params)));
}
public function payments_getOrders($status, $start_time,
$end_time, $test_mode=false) {
return json_decode($this->call_method('facebook.payments.getOrders',
array('status' => $status,
'start_time' => $start_time,
'end_time' => $end_time,
'test_mode' => $test_mode)), true);
}
/**
* Creates a note with the specified title and content.
*
@ -1233,7 +1313,6 @@ function toggleDisplay(id, type) {
* notes.
*/
public function &notes_get($uid, $note_ids = null) {
return $this->call_method('notes.get',
array('uid' => $uid,
'note_ids' => $note_ids));
@ -1631,6 +1710,63 @@ function toggleDisplay(id, type) {
return $this->call_method('facebook.users.setStatus', $args);
}
/**
* Gets the comments for a particular xid. This is essentially a wrapper
* around the comment FQL table.
*
* @param string $xid external id associated with the comments
*
* @return array of comment objects
*/
public function &comments_get($xid) {
$args = array('xid' => $xid);
return $this->call_method('facebook.comments.get', $args);
}
/**
* Add a comment to a particular xid on behalf of a user. If called
* without an app_secret (with session secret), this will only work
* for the session user.
*
* @param string $xid external id associated with the comments
* @param string $text text of the comment
* @param int $uid user adding the comment (def: session user)
* @param string $title optional title for the stream story
* @param string $url optional url for the stream story
* @param bool $publish_to_stream publish a feed story about this comment?
* a link will be generated to title/url in the story
*
* @return string comment_id associated with the comment
*/
public function &comments_add($xid, $text, $uid=0, $title='', $url='',
$publish_to_stream=false) {
$args = array(
'xid' => $xid,
'uid' => $this->get_uid($uid),
'text' => $text,
'title' => $title,
'url' => $url,
'publish_to_stream' => $publish_to_stream);
return $this->call_method('facebook.comments.add', $args);
}
/**
* Remove a particular comment.
*
* @param string $xid the external id associated with the comments
* @param string $comment_id id of the comment to remove (returned by
* comments.add and comments.get)
*
* @return boolean
*/
public function &comments_remove($xid, $comment_id) {
$args = array(
'xid' => $xid,
'comment_id' => $comment_id);
return $this->call_method('facebook.comments.remove', $args);
}
/**
* Gets the stream on behalf of a user using a set of users. This
* call will return the latest $limit queries between $start_time
@ -1642,11 +1778,16 @@ function toggleDisplay(id, type) {
* @param int $end_time end time to look for stories (def: now)
* @param int $limit number of stories to attempt to fetch (def: 30)
* @param string $filter_key key returned by stream.getFilters to fetch
* @param array $metadata metadata to include with the return, allows
* requested metadata to be returned, such as
* profiles, albums, photo_tags
*
* @return array(
* 'posts' => array of posts,
* 'profiles' => array of profile metadata of users/pages in posts
* 'albums' => array of album metadata in posts
* 'posts' => array of posts,
* // if requested, the following data may be returned
* 'profiles' => array of profile metadata of users/pages in posts
* 'albums' => array of album metadata in posts
* 'photo_tags' => array of photo_tags for photos in posts
* )
*/
public function &stream_get($viewer_id = null,
@ -2849,6 +2990,7 @@ function toggleDisplay(id, type) {
array('uids' => $uids ? json_encode($uids) : null));
}
/* UTILITY FUNCTIONS */
/**
@ -2862,18 +3004,15 @@ function toggleDisplay(id, type) {
* See: http://wiki.developers.facebook.com/index.php/Using_batching_API
*/
public function &call_method($method, $params = array()) {
if ($this->format) {
$params['format'] = $this->format;
}
if (!$this->pending_batch()) {
if ($this->call_as_apikey) {
$params['call_as_apikey'] = $this->call_as_apikey;
}
$data = $this->post_request($method, $params);
if (empty($params['format']) || strtolower($params['format']) != 'json') {
$result = $this->convert_xml_to_result($data, $method, $params);
}
else {
$result = json_decode($data, true);
}
$result = $this->convert_result($data, $method, $params);
if (is_array($result) && isset($result['error_code'])) {
throw new FacebookRestClientException($result['error_msg'],
$result['error_code']);
@ -2888,6 +3027,32 @@ function toggleDisplay(id, type) {
return $result;
}
protected function convert_result($data, $method, $params) {
$is_xml = (empty($params['format']) ||
strtolower($params['format']) != 'json');
return ($is_xml) ? $this->convert_xml_to_result($data, $method, $params)
: json_decode($data, true);
}
/**
* Change the response format
*
* @param string $format The response format (json, xml)
*/
public function setFormat($format) {
$this->format = $format;
return $this;
}
/**
* get the current response serialization format
*
* @return string 'xml', 'json', or null (which means 'xml')
*/
public function getFormat() {
return $this->format;
}
/**
* Calls the specified file-upload POST method with the specified parameters
*
@ -2906,8 +3071,14 @@ function toggleDisplay(id, type) {
throw new FacebookRestClientException($description, $code);
}
$xml = $this->post_upload_request($method, $params, $file, $server_addr);
$result = $this->convert_xml_to_result($xml, $method, $params);
if ($this->format) {
$params['format'] = $this->format;
}
$data = $this->post_upload_request($method,
$params,
$file,
$server_addr);
$result = $this->convert_result($data, $method, $params);
if (is_array($result) && isset($result['error_code'])) {
throw new FacebookRestClientException($result['error_msg'],
@ -2946,11 +3117,13 @@ function toggleDisplay(id, type) {
return $result;
}
private function finalize_params($method, &$params) {
$this->add_standard_params($method, $params);
protected function finalize_params($method, $params) {
list($get, $post) = $this->add_standard_params($method, $params);
// we need to do this before signing the params
$this->convert_array_values_to_json($params);
$params['sig'] = Facebook::generate_sig($params, $this->secret);
$this->convert_array_values_to_json($post);
$post['sig'] = Facebook::generate_sig(array_merge($get, $post),
$this->secret);
return array($get, $post);
}
private function convert_array_values_to_json(&$params) {
@ -2961,28 +3134,38 @@ function toggleDisplay(id, type) {
}
}
private function add_standard_params($method, &$params) {
/**
* Add the generally required params to our request.
* Params method, api_key, and v should be sent over as get.
*/
private function add_standard_params($method, $params) {
$post = $params;
$get = array();
if ($this->call_as_apikey) {
$params['call_as_apikey'] = $this->call_as_apikey;
$get['call_as_apikey'] = $this->call_as_apikey;
}
$params['method'] = $method;
$params['session_key'] = $this->session_key;
$params['api_key'] = $this->api_key;
$params['call_id'] = microtime(true);
if ($params['call_id'] <= $this->last_call_id) {
$params['call_id'] = $this->last_call_id + 0.001;
$get['method'] = $method;
$get['session_key'] = $this->session_key;
$get['api_key'] = $this->api_key;
$post['call_id'] = microtime(true);
if ($post['call_id'] <= $this->last_call_id) {
$post['call_id'] = $this->last_call_id + 0.001;
}
$this->last_call_id = $params['call_id'];
if (!isset($params['v'])) {
$params['v'] = '1.0';
$this->last_call_id = $post['call_id'];
if (isset($post['v'])) {
$get['v'] = $post['v'];
unset($post['v']);
} else {
$get['v'] = '1.0';
}
if (isset($this->use_ssl_resources) &&
$this->use_ssl_resources) {
$params['return_ssl_resources'] = true;
$post['return_ssl_resources'] = true;
}
return array($get, $post);
}
private function create_post_string($method, $params) {
private function create_url_string($params) {
$post_params = array();
foreach ($params as $key => &$val) {
$post_params[] = $key.'='.urlencode($val);
@ -3022,48 +3205,64 @@ function toggleDisplay(id, type) {
}
public function post_request($method, $params) {
$this->finalize_params($method, $params);
$post_string = $this->create_post_string($method, $params);
list($get, $post) = $this->finalize_params($method, $params);
$post_string = $this->create_url_string($post);
$get_string = $this->create_url_string($get);
$url_with_get = $this->server_addr . '?' . $get_string;
if ($this->use_curl_if_available && function_exists('curl_init')) {
$useragent = 'Facebook API PHP5 Client 1.1 (curl) ' . phpversion();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->server_addr);
curl_setopt($ch, CURLOPT_URL, $url_with_get);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$result = curl_exec($ch);
$result = $this->curl_exec($ch);
curl_close($ch);
} else {
$content_type = 'application/x-www-form-urlencoded';
$content = $post_string;
$result = $this->run_http_post_transaction($content_type,
$content,
$this->server_addr);
$url_with_get);
}
return $result;
}
/**
* execute a curl transaction -- this exists mostly so subclasses can add
* extra options and/or process the response, if they wish.
*
* @param resource $ch a curl handle
*/
protected function curl_exec($ch) {
$result = curl_exec($ch);
return $result;
}
private function post_upload_request($method, $params, $file, $server_addr = null) {
$server_addr = $server_addr ? $server_addr : $this->server_addr;
$this->finalize_params($method, $params);
list($get, $post) = $this->finalize_params($method, $params);
$get_string = $this->create_url_string($get);
$url_with_get = $server_addr . '?' . $get_string;
if ($this->use_curl_if_available && function_exists('curl_init')) {
// prepending '@' causes cURL to upload the file; the key is ignored.
$params['_file'] = '@' . $file;
$post['_file'] = '@' . $file;
$useragent = 'Facebook API PHP5 Client 1.1 (curl) ' . phpversion();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $server_addr);
curl_setopt($ch, CURLOPT_URL, $url_with_get);
// this has to come before the POSTFIELDS set!
curl_setopt($ch, CURLOPT_POST, 1 );
curl_setopt($ch, CURLOPT_POST, 1);
// passing an array gets curl to use the multipart/form-data content type
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, $useragent);
$result = curl_exec($ch);
$result = $this->curl_exec($ch);
curl_close($ch);
} else {
$result = $this->run_multipart_http_transaction($method, $params, $file, $server_addr);
$result = $this->run_multipart_http_transaction($method, $post,
$file, $url_with_get);
}
return $result;
}
@ -3110,7 +3309,7 @@ function toggleDisplay(id, type) {
}
}
private function get_uid($uid) {
protected function get_uid($uid) {
return $uid ? $uid : $this->user;
}
}
@ -3145,6 +3344,7 @@ class FacebookAPIErrorCodes {
const API_EC_DEPRECATED = 11;
const API_EC_VERSION = 12;
const API_EC_INTERNAL_FQL_ERROR = 13;
const API_EC_HOST_PUP = 14;
/*
* PARAMETER ERRORS
@ -3179,6 +3379,7 @@ class FacebookAPIErrorCodes {
const API_EC_PERMISSION = 200;
const API_EC_PERMISSION_USER = 210;
const API_EC_PERMISSION_NO_DEVELOPERS = 211;
const API_EC_PERMISSION_OFFLINE_ACCESS = 212;
const API_EC_PERMISSION_ALBUM = 220;
const API_EC_PERMISSION_PHOTO = 221;
const API_EC_PERMISSION_MESSAGE = 230;
@ -3267,6 +3468,7 @@ class FacebookAPIErrorCodes {
const FQL_EC_DEPRECATED_TABLE = 611;
const FQL_EC_EXTENDED_PERMISSION = 612;
const FQL_EC_RATE_LIMIT_EXCEEDED = 613;
const FQL_EC_UNRESOLVED_DEPENDENCY = 614;
const API_EC_REF_SET_FAILED = 700;
@ -3318,6 +3520,21 @@ class FacebookAPIErrorCodes {
const API_EC_LIVEMESSAGE_EVENT_NAME_TOO_LONG = 1101;
const API_EC_LIVEMESSAGE_MESSAGE_TOO_LONG = 1102;
/*
* PAYMENTS API ERRORS
*/
const API_EC_PAYMENTS_UNKNOWN = 1150;
const API_EC_PAYMENTS_APP_INVALID = 1151;
const API_EC_PAYMENTS_DATABASE = 1152;
const API_EC_PAYMENTS_PERMISSION_DENIED = 1153;
const API_EC_PAYMENTS_APP_NO_RESPONSE = 1154;
const API_EC_PAYMENTS_APP_ERROR_RESPONSE = 1155;
const API_EC_PAYMENTS_INVALID_ORDER = 1156;
const API_EC_PAYMENTS_INVALID_PARAM = 1157;
const API_EC_PAYMENTS_INVALID_OPERATION = 1158;
const API_EC_PAYMENTS_PAYMENT_FAILED = 1159;
const API_EC_PAYMENTS_DISABLED = 1160;
/*
* CONNECT SESSION ERRORS
*/
@ -3347,6 +3564,7 @@ class FacebookAPIErrorCodes {
const API_EC_COMMENTS_INVALID_XID = 1703;
const API_EC_COMMENTS_INVALID_UID = 1704;
const API_EC_COMMENTS_INVALID_POST = 1705;
const API_EC_COMMENTS_INVALID_REMOVE = 1706;
/**
* This array is no longer maintained; to view the description of an error

View File

@ -36,7 +36,7 @@ function getFacebook()
$facebook = new Facebook($apikey, $secret);
}
if (!$facebook) {
if (empty($facebook)) {
common_log(LOG_ERR, 'Could not make new Facebook client obj!',
__FILE__);
}
@ -44,71 +44,37 @@ function getFacebook()
return $facebook;
}
function updateProfileBox($facebook, $flink, $notice) {
$fbaction = new FacebookAction($output='php://output', $indent=true, $facebook, $flink);
$fbaction->updateProfileBox($notice);
}
function isFacebookBound($notice, $flink) {
if (empty($flink)) {
return false;
}
// Avoid a loop
if ($notice->source == 'Facebook') {
common_log(LOG_INFO, "Skipping notice $notice->id because its " .
'source is Facebook.');
return false;
}
// If the user does not want to broadcast to Facebook, move along
if (!($flink->noticesync & FOREIGN_NOTICE_SEND == FOREIGN_NOTICE_SEND)) {
common_log(LOG_INFO, "Skipping notice $notice->id " .
'because user has FOREIGN_NOTICE_SEND bit off.');
return false;
}
$success = false;
// If it's not a reply, or if the user WANTS to send @-replies,
// then, yeah, it can go to Facebook.
// If it's not a reply, or if the user WANTS to send @-replies...
if (!preg_match('/@[a-zA-Z0-9_]{1,15}\b/u', $notice->content) ||
($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY)) {
$success = true;
// The two condition below are deal breakers:
// Avoid a loop
if ($notice->source == 'Facebook') {
common_log(LOG_INFO, "Skipping notice $notice->id because its " .
'source is Facebook.');
$success = false;
}
$facebook = getFacebook();
$fbuid = $flink->foreign_id;
try {
// Check to see if the user has given the FB app status update perms
$result = $facebook->api_client->
users_hasAppPermission('publish_stream', $fbuid);
if ($result != 1) {
$result = $facebook->api_client->
users_hasAppPermission('status_update', $fbuid);
}
if ($result != 1) {
$user = $flink->getUser();
$msg = "Not sending notice $notice->id to Facebook " .
"because user $user->nickname hasn't given the " .
'Facebook app \'status_update\' or \'publish_stream\' permission.';
common_debug($msg);
$success = false;
}
} catch(FacebookRestClientException $e){
common_log(LOG_ERR, $e->getMessage());
$success = false;
}
return true;
}
return $success;
return false;
}
@ -119,112 +85,129 @@ function facebookBroadcastNotice($notice)
if (isFacebookBound($notice, $flink)) {
// Okay, we're good to go, update the FB status
$status = null;
$fbuid = $flink->foreign_id;
$user = $flink->getUser();
// Get the status 'verb' (prefix) the user has set
$attachments = $notice->attachments();
try {
$prefix = $facebook->api_client->
data_getUserPreference(FACEBOOK_NOTICE_PREFIX, $fbuid);
// Get the status 'verb' (prefix) the user has set
// XXX: Does this call count against our per user FB request limit?
// If so we should consider storing verb elsewhere or not storing
$prefix = $facebook->api_client->data_getUserPreference(FACEBOOK_NOTICE_PREFIX,
$fbuid);
$status = "$prefix $notice->content";
} catch(FacebookRestClientException $e) {
common_log(LOG_WARNING, $e->getMessage());
common_log(LOG_WARNING,
'Unable to get the status verb setting from Facebook ' .
"for $user->nickname (user id: $user->id).");
}
$can_publish = $facebook->api_client->users_hasAppPermission('publish_stream',
$fbuid);
// Okay, we're good to go, update the FB status
$can_update = $facebook->api_client->users_hasAppPermission('status_update',
$fbuid);
try {
$result = $facebook->api_client->
users_hasAppPermission('publish_stream', $fbuid);
if($result == 1){
// authorized to use the stream api, so use it
$fbattachment = null;
$attachments = $notice->attachments();
if($attachments){
$fbattachment=array();
$fbattachment['media']=array();
//facebook only supports one attachment per item
$attachment = $attachments[0];
$fbmedia=array();
if(strncmp($attachment->mimetype,'image/',strlen('image/'))==0){
$fbmedia['type']='image';
$fbmedia['src']=$attachment->url;
$fbmedia['href']=$attachment->url;
$fbattachment['media'][]=$fbmedia;
/* Video doesn't seem to work. The notice never makes it to facebook, and no error is reported.
}else if(strncmp($attachment->mimetype,'video/',strlen('image/'))==0 || $attachment->mimetype="application/ogg"){
$fbmedia['type']='video';
$fbmedia['video_src']=$attachment->url;
// http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
// says that preview_img is required... but we have no value to put in it
// $fbmedia['preview_img']=$attachment->url;
if($attachment->title){
$fbmedia['video_title']=$attachment->title;
}
$fbmedia['video_type']=$attachment->mimetype;
$fbattachment['media'][]=$fbmedia;
*/
}else if($attachment->mimetype=='audio/mpeg'){
$fbmedia['type']='mp3';
$fbmedia['src']=$attachment->url;
$fbattachment['media'][]=$fbmedia;
}else if($attachment->mimetype=='application/x-shockwave-flash'){
$fbmedia['type']='flash';
// http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
// says that imgsrc is required... but we have no value to put in it
// $fbmedia['imgsrc']='';
$fbmedia['swfsrc']=$attachment->url;
$fbattachment['media'][]=$fbmedia;
}else{
$fbattachment['name']=($attachment->title?$attachment->title:$attachment->url);
$fbattachment['href']=$attachment->url;
}
}
$facebook->api_client->stream_publish($status, $fbattachment, null, null, $fbuid);
}else{
if (!empty($attachments) && $can_publish == 1) {
$fbattachment = format_attachments($attachments);
$facebook->api_client->stream_publish($status, $fbattachment,
null, null, $fbuid);
common_log(LOG_INFO,
"Posted notice $notice->id w/attachment " .
"to Facebook user's stream (fbuid = $fbuid).");
} elseif ($can_update == 1 || $can_publish == 1) {
$facebook->api_client->users_setStatus($status, $fbuid, false, true);
common_log(LOG_INFO,
"Posted notice $notice->id to Facebook " .
"as a status update (fbuid = $fbuid).");
} else {
$msg = "Not sending notice $notice->id to Facebook " .
"because user $user->nickname hasn't given the " .
'Facebook app \'status_update\' or \'publish_stream\' permission.';
common_log(LOG_WARNING, $msg);
}
} catch(FacebookRestClientException $e) {
common_log(LOG_ERR, $e->getMessage());
common_log(LOG_ERR,
'Unable to update Facebook status for ' .
"$user->nickname (user id: $user->id)!");
// Finally, attempt to update the user's profile box
if ($can_publish == 1 || $can_update == 1) {
updateProfileBox($facebook, $flink, $notice);
}
} catch (FacebookRestClientException $e) {
$code = $e->getCode();
if ($code >= 200) {
common_log(LOG_WARNING, 'Facebook returned error code ' .
$code . ': ' . $e->getMessage());
common_log(LOG_WARNING,
'Unable to update Facebook status for ' .
"$user->nickname (user id: $user->id)!");
if ($code == 200 || $code == 250) {
// 200 The application does not have permission to operate on the passed in uid parameter.
// 250 Updating status requires the extended permission status_update or publish_stream.
// see: http://wiki.developers.facebook.com/index.php/Users.setStatus#Example_Return_XML
remove_facebook_app($flink);
} else {
// Try sending again later.
return false;
}
}
// Now try to update the profile box
try {
updateProfileBox($facebook, $flink, $notice);
} catch(FacebookRestClientException $e) {
common_log(LOG_WARNING, $e->getMessage());
common_log(LOG_WARNING,
'Unable to update Facebook profile box for ' .
"$user->nickname (user id: $user->id).");
}
}
return true;
}
function updateProfileBox($facebook, $flink, $notice) {
$fbaction = new FacebookAction($output = 'php://output',
$indent = true, $facebook, $flink);
$fbaction->updateProfileBox($notice);
}
function format_attachments($attachments)
{
$fbattachment = array();
$fbattachment['media'] = array();
// Facebook only supports one attachment per item
$attachment = $attachments[0];
$fbmedia = array();
if (strncmp($attachment->mimetype, 'image/', strlen('image/')) == 0) {
$fbmedia['type'] = 'image';
$fbmedia['src'] = $attachment->url;
$fbmedia['href'] = $attachment->url;
$fbattachment['media'][] = $fbmedia;
} else if ($attachment->mimetype == 'audio/mpeg') {
$fbmedia['type'] = 'mp3';
$fbmedia['src'] = $attachment->url;
$fbattachment['media'][] = $fbmedia;
}else if ($attachment->mimetype == 'application/x-shockwave-flash') {
$fbmedia['type'] = 'flash';
// http://wiki.developers.facebook.com/index.php/Attachment_%28Streams%29
// says that imgsrc is required... but we have no value to put in it
// $fbmedia['imgsrc']='';
$fbmedia['swfsrc'] = $attachment->url;
$fbattachment['media'][] = $fbmedia;
}else{
$fbattachment['name'] = ($attachment->title ?
$attachment->title : $attachment->url);
$fbattachment['href'] = $attachment->url;
}
return $fbattachment;
}
function remove_facebook_app($flink)

View File

@ -679,17 +679,17 @@ function mail_facebook_app_removed($user)
$site_name = common_config('site', 'name');
$subject = sprintf(
_('Your %s Facebook application access has been disabled.',
_('Your %1\$s Facebook application access has been disabled.',
$site_name));
$body = sprintf(_("Hi, %1\$s. We're sorry to inform you that we are " .
'unable to update your Facebook status from %s, and have disabled ' .
'unable to update your Facebook status from %2\$s, and have disabled ' .
'the Facebook application for your account. This may be because ' .
'you have removed the Facebook application\'s authorization, or ' .
'have deleted your Facebook account. You can re-enable the ' .
'Facebook application and automatic status updating by ' .
"re-installing the %1\$s Facebook application.\n\nRegards,\n\n%1\$s"),
$site_name);
"re-installing the %2\$s Facebook application.\n\nRegards,\n\n%2\$s"),
$user->nickname, $site_name);
common_init_locale();
return mail_to_user($user, $subject, $body);

View File

@ -97,11 +97,7 @@ class Rss10Action extends Action
// Parent handling, including cache check
parent::handle($args);
// Get the list of notices
if (empty($this->tag)) {
$this->notices = $this->getNotices($this->limit);
} else {
$this->notices = $this->getTaggedNotices($this->tag, $this->limit);
}
$this->notices = $this->getNotices($this->limit);
$this->showRss();
}

View File

@ -188,15 +188,18 @@ class TwitterapiAction extends Action
# Enclosures
$attachments = $notice->attachments();
$twitter_status['attachments']=array();
if($attachments){
foreach($attachments as $attachment){
if (!empty($attachments)) {
$twitter_status['attachments'] = array();
foreach ($attachments as $attachment) {
if ($attachment->isEnclosure()) {
$enclosure=array();
$enclosure['url']=$attachment->url;
$enclosure['mimetype']=$attachment->mimetype;
$enclosure['size']=$attachment->size;
$twitter_status['attachments'][]=$enclosure;
$enclosure = array();
$enclosure['url'] = $attachment->url;
$enclosure['mimetype'] = $attachment->mimetype;
$enclosure['size'] = $attachment->size;
$twitter_status['attachments'][] = $enclosure;
}
}
}
@ -369,6 +372,9 @@ class TwitterapiAction extends Action
case 'text':
$this->element($element, null, common_xml_safe_str($value));
break;
case 'attachments':
$this->show_xml_attachments($twitter_status['attachments']);
break;
default:
$this->element($element, null, $value);
}
@ -389,6 +395,20 @@ class TwitterapiAction extends Action
$this->elementEnd($role);
}
function show_xml_attachments($attachments) {
if (!empty($attachments)) {
$this->elementStart('attachments', array('type' => 'array'));
foreach ($attachments as $attachment) {
$attrs = array();
$attrs['url'] = $attachment['url'];
$attrs['mimetype'] = $attachment['mimetype'];
$attrs['size'] = $attachment['size'];
$this->element('enclosure', $attrs, '');
}
$this->elementEnd('attachments');
}
}
function show_twitter_rss_item($entry)
{
$this->elementStart('item');

View File

@ -140,7 +140,7 @@ function common_have_session()
function common_ensure_session()
{
$c = null;
if (array_key_exists(session_name, $_COOKIE)) {
if (array_key_exists(session_name(), $_COOKIE)) {
$c = $_COOKIE[session_name()];
}
if (!common_have_session()) {

View File

@ -122,7 +122,7 @@ class FBConnectPlugin extends Plugin
FB_RequireFeatures(
["XFBML"],
function() {
FB.Facebook.init("%s", "../xd_receiver.html");
FB.init("%s", "../xd_receiver.html");
}
); }
@ -220,11 +220,11 @@ class FBConnectPlugin extends Plugin
try {
$facebook = getFacebook();
$fbuid = getFacebook()->get_loggedin_user();
$fbuid = $facebook->get_loggedin_user();
} catch (Exception $e) {
common_log(LOG_WARNING,
'Problem getting Facebook client: ' .
'Problem getting Facebook user: ' .
$e->getMessage());
}
@ -297,9 +297,9 @@ class FBConnectPlugin extends Plugin
$title = _('Logout from the site');
$text = _('Logout');
$html = sprintf('<li id="nav_logout"><a href="%s" title="%s" ' .
'onclick="FB.Connect.logout(function() { goto_logout() })">%s</a></li>',
$logout_url, $title, $text);
$html = sprintf('<li id="nav_logout"><a href="#" title="%s" ' .
'onclick="FB.Connect.logoutAndRedirect(\'%s\');">%s</a></li>',
$title, $logout_url, $text);
$action->raw($html);