This commit is contained in:
Ben Liyanage 2014-11-13 03:07:20 +00:00
commit e911dcfdd6
9 changed files with 866 additions and 96 deletions

View file

@ -18,6 +18,7 @@ FBPost:
*/
require_once("addon/fbpost/fbpost.php");
require_once("include/items.php");
define('FBSYNC_DEFAULT_POLL_INTERVAL', 5); // given in minutes
@ -158,7 +159,6 @@ function fbsync_settings_post(&$a,&$b) {
function fbsync_cron($a,$b) {
$last = get_config('fbsync','last_poll');
$poll_interval = intval(get_config('fbsync','poll_interval'));
if(! $poll_interval)
$poll_interval = FBSYNC_DEFAULT_POLL_INTERVAL;
@ -166,19 +166,29 @@ function fbsync_cron($a,$b) {
if($last) {
$next = $last + ($poll_interval * 60);
if($next > time()) {
logger('fbsync_cron: poll intervall not reached');
logger('fbsync_cron: poll intervall not reached. poll interval: ' . $poll_interval * 60 . '; actual interval: ' . $poll_interval);
return;
}
}
logger('fbsync_cron: cron_start');
$r = q("SELECT * FROM `pconfig` WHERE `cat` = 'fbsync' AND `k` = 'sync' AND `v` = '1' ORDER BY RAND()");
if(count($r)) {
foreach($r as $rr) {
fbsync_get_self($rr['uid']);
logger('fbsync_cron: importing timeline from user '.$rr['uid']);
fbsync_fetchfeed($a, $rr['uid']);
logger('fbsync_cron: importing timeline from user '.$rr['uid']);
$uid = fbsync_get_self($rr['uid']);
$self_id = get_pconfig($uid,'fbsync','self_id');
$last_updated = get_pconfig($uid,'fbsync','last_updated');
$self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($uid));
$user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", intval($uid));
if(! count($user))
return;
$data = fbsync_fetchfeed($a, $uid, $self_id, $last_updated);
fbsync_processfeed($data, $self, $a, $uid, $self_id, $user, $last_updated);
}
}
@ -196,8 +206,7 @@ function fbsync_expire($a,$b) {
$r = q("DELETE FROM `item` WHERE `deleted` AND `network` = '%s'", dbesc(NETWORK_FACEBOOK));
require_once("include/items.php");
logger('fbsync_expire: expire_start');
$r = q("SELECT * FROM `pconfig` WHERE `cat` = 'fbsync' AND `k` = 'sync' AND `v` = '1' ORDER BY RAND()");
@ -211,8 +220,12 @@ function fbsync_expire($a,$b) {
logger('fbsync_expire: expire_end');
}
function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $create_user) {
function fbsync_createpost($a, $uid, $contacts, $applications, $post, $create_user) {
//Sanitize Inputs
$post->actor_id = number_format($post->actor_id, 0, '', '');
$post->source_id = number_format($post->source_id, 0, '', '');
$post->app_id = number_format($post->app_id, 0, '', '');
$access_token = get_pconfig($uid,'facebook','access_token');
require_once("include/oembed.php");
@ -224,7 +237,7 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
dbesc('fb::'.$post->post_id)
);
if(count($r))
return;
return 1;
$postarray = array();
$postarray['gravity'] = 0;
@ -298,10 +311,10 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
if ($contact_id == -1) {
logger('fbsync_createpost: Contact is blocked. Post not imported '.print_r($post, true), LOGGER_DEBUG);
return;
return 2;
} elseif (($contact_id <= 0) AND !$create_user) {
logger('fbsync_createpost: No matching contact found. Post not imported '.print_r($post, true), LOGGER_DEBUG);
return;
return 3;
} elseif ($contact_id == 0) {
// This case should never happen
logger('fbsync_createpost: No matching contact found. Using own id. (Should never happen) '.print_r($post, true), LOGGER_DEBUG);
@ -321,20 +334,21 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
// Change the object type when an attachment is present
if (isset($post->attachment->fb_object_type))
logger('fb_object_type: '.$post->attachment->fb_object_type." ".print_r($post->attachment, true), LOGGER_DEBUG);
switch ($post->attachment->fb_object_type) {
case 'photo':
$postarray['object-type'] = ACTIVITY_OBJ_IMAGE; // photo is deprecated: http://activitystrea.ms/head/activity-schema.html#image
break;
case 'video':
$postarray['object-type'] = ACTIVITY_OBJ_VIDEO;
break;
case '':
//$postarray['object-type'] = ACTIVITY_OBJ_BOOKMARK;
break;
default:
logger('Unknown object type '.$post->attachment->fb_object_type, LOGGER_DEBUG);
break;
}
switch ($post->attachment->fb_object_type) {
case 'photo':
$postarray['object-type'] = ACTIVITY_OBJ_IMAGE; // photo is deprecated: http://activitystrea.ms/head/activity-schema.html#image
break;
case 'video':
$postarray['object-type'] = ACTIVITY_OBJ_VIDEO;
break;
case '':
//$postarray['object-type'] = ACTIVITY_OBJ_BOOKMARK;
break;
default:
logger('Unknown object type '.$post->attachment->fb_object_type, LOGGER_DEBUG);
break;
}
$content = "";
$type = "";
@ -365,7 +379,7 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
$quote = $post->attachment->caption;
if ($quote.$post->attachment->href.$content.$postarray["body"] == "")
return;
return 3;
if (isset($post->attachment->media) AND (($type == "") OR ($type == "link"))) {
foreach ($post->attachment->media AS $media) {
@ -429,7 +443,7 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
$postarray["body"] = trim($postarray["body"]);
if (trim($postarray["body"]) == "")
return;
return 4;
if ($prebody != "")
$postarray["body"] = $prebody.$postarray["body"]."[/share]";
@ -444,24 +458,17 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
if(isset($post->privacy) && $post->privacy->value !== '') {
$postarray['private'] = 1;
$postarray['allow_cid'] = '<' . $self[0]['id'] . '>';
$postarray['allow_cid'] = '<' . $uid . '>';
}
/*
$postarray["location"] = $post->place->name;
postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1];
*/
//$types = array(46, 80, 237, 247, 308);
//if (!in_array($post->type, $types))
// $postarray["body"] = "Type: ".$post->type."\n".$postarray["body"];
//print_r($post);
//print_r($postarray);
$item = item_store($postarray);
logger('fbsync_createpost: User '.$self[0]["nick"].' posted feed item '.$item, LOGGER_DEBUG);
logger('fbsync_createpost: User ' . $uid . ' posted feed item '.$item, LOGGER_DEBUG);
return 0;
}
function fbsync_createcomment($a, $uid, $self_id, $self, $user, $contacts, $applications, $comment) {
//Sanitize Data
$comment->fromid = number_format($comment->fromid, 0, '', '');
// check if it was already imported
$r = q("SELECT `uri` FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
@ -654,6 +661,8 @@ function fbsync_createcomment($a, $uid, $self_id, $self, $user, $contacts, $appl
}
function fbsync_createlike($a, $uid, $self_id, $self, $contacts, $like) {
//Sanitize data
$like->user_id = number_format($like->user_id, 0, '', '');
$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc("fb::".$like->post_id),
@ -778,10 +787,26 @@ function fbsync_fetch_contact($uid, $contact, $create_user) {
if(!count($r)) {
// create contact record
q("INSERT INTO `contact` (`uid`, `created`, `url`, `nurl`, `addr`, `alias`, `notify`, `poll`,
`name`, `nick`, `photo`, `network`, `rel`, `priority`,
`writable`, `blocked`, `readonly`, `pending`)
VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, 0, 0, 0)",
q("INSERT INTO `contact` (
`uid`,
`created`,
`url`,
`nurl`,
`addr`,
`alias`,
`notify`,
`poll`,
`name`,
`nick`,
`photo`,
`network`,
`rel`,
`priority`,
`writable`,
`blocked`,
`readonly`,
`pending`
) VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d, %d)",
intval($uid),
dbesc(datetime_convert()),
dbesc($contact->url),
@ -796,7 +821,10 @@ function fbsync_fetch_contact($uid, $contact, $create_user) {
dbesc(NETWORK_FACEBOOK),
intval(CONTACT_IS_FRIEND),
intval(1),
intval(1)
intval(1),
intval(0),
intval(0),
intval(0)
);
$r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
@ -986,54 +1014,45 @@ function fbsync_fetchuser($a, $uid, $id) {
return($user);
}
function fbsync_fetchfeed($a, $uid) {
function fbsync_fetchfeed($a, $uid, $self_id, $last_updated) {
$access_token = get_pconfig($uid,'facebook','access_token');
$last_updated = get_pconfig($uid,'fbsync','last_updated');
$self_id = get_pconfig($uid,'fbsync','self_id');
$create_user = get_pconfig($uid, 'fbsync', 'create_user');
$do_likes = get_config('fbsync', 'do_likes');
$self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
intval($uid)
);
$user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1",
intval($uid)
);
if(! count($user))
return;
require_once('include/items.php');
$do_likes = get_config('fbsync', 'do_likes');
//if ($last_updated == "")
$last_updated = 0;
logger("fbsync_fetchfeed: fetching content for user ".$self_id);
logger("fbsync_fetchfeed: fetching content for user " . $self_id);
$fql = array(
"posts" => "SELECT action_links, actor_id, app_data, app_id, attachment, attribution, comment_info, created_time, filter_key, like_info, message, message_tags, parent_post_id, permalink, place, post_id, privacy, share_count, share_info, source_id, subscribed, tagged_ids, type, updated_time, with_tags FROM stream where filter_key in (SELECT filter_key FROM stream_filter WHERE uid=me() AND type='newsfeed') AND updated_time > $last_updated ORDER BY updated_time DESC LIMIT 500",
"comments" => "SELECT app_id, attachment, post_id, id, likes, fromid, time, text, text_tags, user_likes, likes FROM comment WHERE post_id IN (SELECT post_id FROM #posts) ORDER BY time DESC LIMIT 500",
"profiles" => "SELECT id, name, username, url, pic_square FROM profile WHERE id IN (SELECT actor_id FROM #posts) OR id IN (SELECT fromid FROM #comments) OR id IN (SELECT source_id FROM #posts) LIMIT 500",
"applications" => "SELECT app_id, display_name FROM application WHERE app_id IN (SELECT app_id FROM #posts) OR app_id IN (SELECT app_id FROM #comments) LIMIT 500",
"avatars" => "SELECT id, real_size, size, url FROM square_profile_pic WHERE id IN (SELECT id FROM #profiles) AND size = 256 LIMIT 500");
if ($do_likes) {
$fql["likes"] = "SELECT post_id, user_id FROM like WHERE post_id IN (SELECT post_id FROM #posts)";
$fql["profiles"] .= " OR id IN (SELECT user_id FROM #likes)";
}
$url = "https://graph.facebook.com/fql?q=".urlencode(json_encode($fql))."&access_token=".$access_token;
$feed = fetch_url($url);
logger("fbsync_fetchfeed: query: $url",LOGGER_DEBUG);
$feed = fetch_url($url);
$data = json_decode($feed);
if (!is_array($data->data)) {
logger("fbsync_fetchfeed: Error fetching data for user ".$uid.": ".print_r($data, true));
return;
}
return $data;
}
$posts = array();
function fbsync_processfeed($data, $self, $a, $uid, $self_id, $user, $last_updated){
$create_user = get_pconfig($uid, 'fbsync', 'create_user');
$posts = array();
$comments = array();
$likes = array();
$profiles = array();
@ -1069,12 +1088,14 @@ function fbsync_fetchfeed($a, $uid) {
$post_data = array();
$comment_data = array();
//These Indexes are Used for lookups in the next loop
foreach ($avatars AS $avatar) {
$avatar->id = number_format($avatar->id, 0, '', '');
$square_avatars[$avatar->id] = $avatar;
}
unset($avatars);
//These Indexes are used for lookups elsewhere
foreach ($profiles AS $profile) {
$profile->id = number_format($profile->id, 0, '', '');
@ -1086,42 +1107,31 @@ function fbsync_fetchfeed($a, $uid) {
unset($profiles);
unset($square_avatars);
//These Indexes are Used for lookups elsewhere
foreach ($applications AS $application) {
$application->app_id = number_format($application->app_id, 0, '', '');
$application_data[$application->app_id] = $application;
$application_data[$application->app_id] = $application;
}
unset($applications);
unset($applications);
foreach ($posts AS $post) {
$post->actor_id = number_format($post->actor_id, 0, '', '');
$post->source_id = number_format($post->source_id, 0, '', '');
$post->app_id = number_format($post->app_id, 0, '', '');
$post_data[$post->post_id] = $post;
}
unset($posts);
foreach($comments AS $comment) {
$comment->fromid = number_format($comment->fromid, 0, '', '');
$comment_data[$comment->id] = $comment;
}
unset($comments);
foreach ($post_data AS $post) {
if ($post->updated_time > $last_updated)
$last_updated = $post->updated_time;
fbsync_createpost($a, $uid, $self, $contacts, $application_data, $post, $create_user);
$result = fbsync_createpost($a, $uid, $contacts, $applications, $post, $create_user);
//echo $result;
}
foreach ($comment_data AS $comment) {
fbsync_createcomment($a, $uid, $self_id, $self, $user, $contacts, $application_data, $comment);
foreach ($comments AS $comment) {
fbsync_createcomment($a, $uid, $self_id, $self, $user, $contacts, $applications, $comment);
}
foreach($likes AS $like) {
$like->user_id = number_format($like->user_id, 0, '', '');
fbsync_createlike($a, $uid, $self_id, $self, $contacts, $like);
}
set_pconfig($uid,'fbsync','last_updated', $last_updated);
}
?>

View file

@ -0,0 +1,11 @@
<?php
require_once('include/items.php');
class Facebook
{
function CreatePost($a, $uid, $self, $contacts, $applications, $post, $create_user)
{
throw new Exception("CreatePost Not Implemented");
}
}
?>

View file

@ -0,0 +1,9 @@
<?php
require_once("./addon/fbsync/object/Facebook.php");
Class Facebook_Graph21 extends Facebook
{
}
?>

View file

@ -0,0 +1,349 @@
<?php
require_once("./addon/fbsync/object/Facebook.php");
Class Facebook_Graph21 extends Facebook
{
public $access_token;// = "test";
public $uid;
private $cachedContacts = array();
public $graphBase = "https://graph.facebook.com/v2.1/";
function __construct($uid)
{
$this->uid = $uid;
$this->access_token = get_pconfig($uid,'facebook','access_token');
}
function PictureURL($facebookID)
{
//Picture is always here. This url redirects to CDN. CDN images should not be used as they can move around.
//TODO: the Proxy URL that is being used to serve images is screwing up this URL
//TODO: Add this to make image sized correctly '&type=square&width=80&height=80'
return $this->graphBase . $post->from->id . '/picture';
}
//Every User Request must be processed individually.
//Facebook no longer allows you to request all of a users contacts.
function FetchContact($facebookID, $create_user)
{
/*
$facebookID - The facebook user to fetch
$create_user - If the fetched user doesn't exist, create him as a contact.
*/
//TODO: check if the contact has been updated recently before making this hit. Not sure if this is possible.
$url = $this->graphBase . $facebookID . '?access_token=' . $this->access_token;
$contact = fetch_url($url);
$contact = json_decode($contact);
$url = normalise_link($contact->link);
// Check if the unique contact is existing
$r = q("SELECT id FROM unique_contacts WHERE url='%s' LIMIT 1",
dbesc($url));
if (count($r) == 0)
q("INSERT INTO unique_contacts (url, name, nick, avatar) VALUES ('%s', '%s', '%s', '%s')",
dbesc($url),
dbesc($contact->name),
dbesc($contact->username),
dbesc($this->PictureURL($contact->id)));
else
q("UPDATE unique_contacts SET name = '%s', nick = '%s', avatar = '%s' WHERE url = '%s'",
dbesc($contact->name),
dbesc($contact->username),
dbesc($this->PictureURL($contact-id)),
dbesc($url));
$r = q("SELECT * FROM `contact` WHERE `uid` = %d AND `alias` = '%s' LIMIT 1",
intval($this->uid), dbesc("facebook::".$contact->id));
if(!count($r) AND !$create_user)
return(0);
if (count($r) AND ($r[0]["readonly"] OR $r[0]["blocked"])) {
logger("fbsync_fetch_contact: Contact '".$r[0]["nick"]."' is blocked or readonly.", LOGGER_DEBUG);
return(-1);
}
//This should probably happen always if the unique_contacts record is created.
if(!count($r))
{
// create contact record if it doesn't exist
q(" INSERT INTO `contact` (
`uid`,
`created`,
`alias`,
`poll`,
`network`,
`rel`,
`priority`,
`writable`,
`blocked`,
`readonly`,
`pending`
) VALUES ( %d, '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d, %d)",
intval($this->uid), //uid
dbesc(datetime_convert()), //created
dbesc("facebook::".$contact->id), //alias
dbesc("facebook::".$contact->id), //poll
dbesc(NETWORK_FACEBOOK), //network
intval(CONTACT_IS_FRIEND), //rel
intval(1), //priority
intval(1), //writable
intval(0), //blocked
intval(0), //readonly
intval(0) //pending
);
$r = q("SELECT * FROM `contact` WHERE `alias` = '%s' AND `uid` = %d LIMIT 1",
dbesc("facebook::".$contact->id),
intval($this->uid)
);
}
// update profile photos once every 12 hours as we have no notification of when they change.
//TODO: Probably need to test if avatar-date is null
$update_photo = ($r[0]['avatar-date'] < datetime_convert('','','now -12 hours'));
// check that we have all the photos, this has been known to fail on occasion
if((! $r[0]['photo']) || (! $r[0]['thumb']) || (! $r[0]['micro']) || ($update_photo)) {
logger("fbsync_fetch_contact: Updating contact ".$contact->username, LOGGER_DEBUG);
require_once("Photo.php");
$photos = import_profile_photo($this->PictureURL($facebookID), $this->uid, $r[0]['id']);
q("UPDATE `contact` SET
`photo` = '%s',
`thumb` = '%s',
`micro` = '%s',
`name-date` = '%s',
`uri-date` = '%s',
`avatar-date` = '%s',
`url` = '%s',
`nurl` = '%s',
`addr` = '%s',
`name` = '%s',
`nick` = '%s',
`notify` = '%s'
WHERE `id` = %d",
dbesc($photos[0]),
dbesc($photos[1]),
dbesc($photos[2]),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc($contact->url),
dbesc(normalise_link($contact->url)),
dbesc($contact->username."@facebook.com"),
dbesc($contact->name),
dbesc($contact->username),
dbesc($contact->id),
intval($r[0]['id'])
);
}
return($r[0]["id"]);
}
function CreatePost($a, $self, $contacts, $applications, $post, $create_user)
{
//Sanitize Inputs
//Check if post exists
//This is legacy--shouldn't we check if the various parts of the post was updated?
$r = q("SELECT * FROM `item` WHERE `uid` = %d AND `uri` = '%s' LIMIT 1",
intval($this->uid),
dbesc('fb::'.$post->id)
);
if(count($r))
{
logger('fbsync_createpost: skipping post $post->id--already exists', LOGGER_DEBUG);
return;
}
$postarray = array();
$postarray['gravity'] = 0;
$postarray['uid'] = $this->uid;
$postarray['wall'] = 0;
$postarray['verb'] = ACTIVITY_POST;
$postarray['network'] = dbesc(NETWORK_FACEBOOK);
$postarray['created'] = datetime_convert('UTC','UTC',date("c", $post->created_time));
$postarray['edited'] = datetime_convert('UTC','UTC',date("c", $post->updated_time));
$postarray['uri'] = "fb::". $post->id;
$postarray['thr-parent'] = $postarray['uri'];
$postarray['parent-uri'] = $postarray['uri'];
//No permalink in new api. Can use one of the action links, they seem to be all the same.
//Another option is spliting the id AAA_BBB where AAA is the id of the person, and BBB is the ID of the post. final url would be facebook.com/AAA/post/BBB
//TODO: Remove actions if not in use
$ids = split("_", $post->id);
$postarray['plink'] = 'https://www.facebook.com/' . $ids[0] . '/posts/' . $ids[1];
$postarray['author-name'] = $post->from->name; // $contacts[$post->actor_id]->name;
$postarray['author-link'] = 'https://www.facebook.com/' . $post->from->id; //$contacts[$post->actor_id]->url;
$postarray['author-avatar'] = $this->PictureURL($post->from->id);
//TODO: Source not in in graph api. What was this before? Seemed like it was the same as the author with FQL
//$postarray['owner-name'] = $contacts[$post->source_id]->name;
//$postarray['owner-link'] = $contacts[$post->source_id]->url;
//$postarray['owner-avatar'] = $contacts[$post->source_id]->pic_square;
//TODO: Parent Post Code
//TODO: Set $postarray['contact-id'] = $contact_id; Should either be the actor_id or the source_id (not in graph?)
//echo $post->from->id;
//TODO: From Needs to be added in order to be set for item?
$postarray['contact-id'] = $this->FetchContact($post->from->id, $create_user);
//Set Object Type
//TODO: This code is broken.
if (!isset($post->attachment[0]->type)) //This is never set since its from the FQL dataset.
{
//Default Object Type
$postarray['object-type'] = ACTIVITY_OBJ_NOTE; // default value - is maybe changed later when media is attached
} else {
// Change the object type when an attachment is present
$postarray['object-type'] = $post->attachment[0]->type; // default value - is maybe changed later when media is attached
}
/* More type code. I think this is not necessary.
require_once("include/oembed.php");
$oembed_data = oembed_fetch_url($post->attachment->href);
$type = $oembed_data->type;
if ($type == "rich")
$type = "link";
*/
/*
echo "type: " . $postarray['object-type'];
die();
*/
//TODO: Body needs more testing, and has some more fringe cases.
$postarray["body"] = $this->AssembleBody($post->name, $post->link, $post->description, $post->picture, $postarray['object-type']);
//TODO: Do tags
$postarray["tag"] = "This is the tag";
$postarray['app'] = ($post->application->name == "Links" ? "Facebook" : $post->application->name);
if(isset($post->privacy) && $post->privacy->value !== '') {
$postarray['private'] = 1;
$postarray['allow_cid'] = '<' . $uid . '>';
}
$item = item_store($postarray);
logger('fbsync_createpost: User ' . $uid . ' posted feed item '.$item, LOGGER_DEBUG);
return $postarray;
}
function AssembleBody($Title, $Href, $Body, $Picture, $ObjectType)
{
/*
$postarray["body"] = (isset($post->message) ? escape_tags($post->message) : '');
$msgdata = fbsync_convertmsg($a, $postarray["body"]);
$postarray["body"] = $msgdata["body"];
$postarray["tag"] = $msgdata["tags"];
*/
$content = "";
if ($Picture != "")
{
$pictureStr = '[img]' . $Picture . '[/img]';
if ($Href != "")
{
$pictureStr = '[url=' . $Href . ']' . $pictureStr . '[/url]';
}
$content .= "\n" . $pictureStr;
}
if ($Title != "" and $Href != "") {
$content .= "[bookmark=".$Href."]".$Title."[/bookmark]";
// If a link is not only attached but also added in the body, look if it can be removed in the body.
/*
$removedlink = trim(str_replace($post->attachment->href, "", $postarray["body"]));
if (($removedlink == "") OR strstr($postarray["body"], $removedlink))
$postarray["body"] = $removedlink;
*/
} elseif ($Title != "") {
$content .= "[b]" . $post->attachment->name."[/b]";
}
$content .= "\n[quote]".trim($Body)."[/quote]";
/*
if (isset($post->attachment->media) AND (($type == "") OR ($type == "link"))) {
foreach ($post->attachment->media AS $media) {
if (isset($media->type))
$type = $media->type;
if (isset($media->src))
$preview = $media->src;
if (isset($media->photo)) {
if (isset($media->photo->images) AND (count($media->photo->images) > 1))
$preview = $media->photo->images[1]->src;
if (isset($media->photo->fbid)) {
logger('fbsync_createpost: fetching fbid '.$media->photo->fbid, LOGGER_DEBUG);
$url = "https://graph.facebook.com/".$media->photo->fbid."?access_token=".$access_token;
$feed = fetch_url($url);
$data = json_decode($feed);
if (isset($data->images)) {
$preview = $data->images[0]->source;
logger('fbsync_createpost: got fbid '.$media->photo->fbid.' image '.$preview, LOGGER_DEBUG);
} else
logger('fbsync_createpost: error fetching fbid '.$media->photo->fbid.' '.print_r($data, true), LOGGER_DEBUG);
}
}
if (isset($media->href) AND ($preview != "") AND ($media->href != ""))
$content .= "\n".'[url='.$media->href.'][img]'.$preview.'[/img][/url]';
else {
if ($preview != "")
$content .= "\n".'[img]'.$preview.'[/img]';
// if just a link, it may be a wall photo - check
if (isset($post->link))
$content .= fbpost_get_photo($media->href);
}
}
}
*/
$content = '[class="type-'. $ObjectType . '"]' . $content . '[/class]';
/*
TODO:
* What is the wall-to-wall system setting supposed to do? What is the "Share" syntax used for?
This code does not seem to match what happens with the previous posts. I stripped out some stuff comparing author and source below.
if (!intval(get_config('system','wall-to-wall_share'))) {
$ShareAuthor = "Test Share Author";
$ShareAuthorLink = "http://test.com";
$content = '[share author="' . $ShareAuthor . '" profile="' . $ShareAuthorLink . '" avatar="' . $ShareAuthorAvatar . '"]' . $content . '[/share]';
}
*/
return $content;
}
}
?>

View file

@ -0,0 +1,115 @@
<?php
require_once("boot.php");
require_once("./addon/fbsync/fbsync.php");
require_once("include/dba.php");
@include(".htconfig.php");
$a = new App();
$d = datetime_convert();
global $db;
$db = new dba($db_host, $db_user, $db_pass, $db_data, $install);
//Test Data Retrieval
//$data = fbsync_fetchfeed($a, 1);
//var_dump($data);
//Test Data Prcoessing -- Constants-- used in both tests
$uid = 1;
$self_id = get_pconfig($uid,'fbsync','self_id');
$last_updated = get_pconfig($uid,'fbsync','last_updated');
$self = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", intval($uid));
$user = q("SELECT * FROM `user` WHERE `uid` = %d AND `account_expired` = 0 LIMIT 1", intval($uid));
$create_user = get_pconfig($uid, 'fbsync', 'create_user');
//Test Data Processing fql
$data = json_decode(file_get_contents("./addon/fbsync/tests/fql-full.txt"));
$result = fbsync_processfeed($data, $self, $a, $uid, $self_id, $user, $last_updated);
if ($result != 0) die("FQL Processing broken.\n");
echo "Done with fql_data processing.\n";
//die();
//Test data processing -- graph`
// Test Base Class
require_once("./addon/fbsync/object/Facebook.php");
$myFBSync = new Facebook();
// Test graph 2.1 class
require_once("./addon/fbsync/object/Facebook_Graph21.php");
$myFBSync = new Facebook_Graph21($uid);
//verify class loaded correctly
if ($myFBSync->uid != 1) die("class did not load");
if ($myFBSync->access_token == '') die("failed to load access_token");
//Test FetchContact
//TODO: build tests for facebook api requests using API test user functions
$create_user = 1;
$facebookID = 109524391244; //BaltimoreNode
$id1 = $myFBSync->FetchContact($facebookID, $uid, $create_user);
//Re fetch the user, and make sure the id mataches
$id2 = $myFBSync->FetchContact($facebookID, $uid, $create_user);
if ($id1 != $id2) die("fetch contact did not work consistently");
//Test CreatePost in friendica
$posts = json_decode(file_get_contents("./addon/fbsync/tests/graph2.1-no-filter.txt"));
$post = $myFBSync->CreatePost($a,0,0,0,$posts->data[0],0);
//verify data
if ($post['uri'] != "fb::109524391244_10152483187826245") die("uri does not match");
if ($post['plink'] != "https://www.facebook.com/109524391244/posts/10152483187826245") die("plink does not match");
//var_dump($posts->data[0]);
//TODO: test creating the same post again
echo "All done\n";
/*
Outstanding Questions:
https://developers.facebook.com/tools/explorer
SELECT action_links, actor_id, app_data, app_id, attachment, attribution, comment_info, created_time, filter_key, like_info, message, message_tags, parent_post_id, permalink, place, post_id, privacy, share_count, share_info, source_id, subscribed, tagged_ids, type, updated_time, with_tags FROM stream where filter_key ='nf' ORDER BY updated_time DESC LIMIT 5
//Todo:Actions can probably be removed
me/home?fields=actions&since=992438&updated_time=0&filter=nf&limit=1
me/home?fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares,from&limit=1
https://developers.facebook.com/docs/graph-api/reference/v2.1/test-user
"previous": "https://graph.facebook.com/v2.1/10152271780185899/home?fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares&limit=2&since=1411141640",
"next": "https://graph.facebook.com/v2.1/10152271780185899/home?fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares&limit=2&until=1411141432"
$limit = 1;
$graph = array(
array(method => GET,
"relative_url" =>"me/home?limit=$limit&fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares&since=$last_updated"
),
array(method=>GET,
"relative_url" => "me")
);
static $GETRequest = '{"method":"GET","relative_url":%s}';
var_dump($graph);
$graphURL = 'https://graph.facebook.com/v2.1/?batch=' . urlencode(json_encode($graph))
.'&access_token=' . $access_token . '&method=post'
;
//Facebook API v2.1
$graphData = json_decode(file_get_contents($graphURL));
//Facebook v2.1 Data
$posts = json_decode($graphData[0]->body);
*/
?>

101
fbsync/tests/fql-full.txt Normal file
View file

@ -0,0 +1,101 @@
{
"data": [
{
"name": "posts",
"fql_result_set": [
{
"action_links": null,
"actor_id": 568851657,
"app_data": [
],
"app_id": null,
"attachment": {
"description": ""
},
"attribution": null,
"comment_info": {
"can_comment": true,
"comment_count": 3,
"comment_order": "chronological"
},
"created_time": 1413220907,
"filter_key": "nf",
"like_info": {
"can_like": true,
"like_count": 1,
"user_likes": false
},
"message": "Max Gladstone on modern magic:\n\n\"[C]onsider the smartphone I have in my pocket. No single human being knows how to make this phone. I acquired the phone, and I use it. People who know more about the phone can tell it to do more things than I can, but they're still bound by the limits of the hardware. A few communities are dedicated to modding and hacking phones like mine, yes, but for most people most of the time a smartphone is a portable magic mirror. We make mystic passes before the glass, address the indwelling spirit with suitably respectful tones, and LEARN THE FUTURE. (\"Siri, what will the weather be like tomorrow?\") The same thought experiment works for many modern technologies.\"",
"message_tags": [
],
"parent_post_id": null,
"permalink": "https://www.facebook.com/stephen.carr.547/posts/10152403039101658",
"place": null,
"post_id": "568851657_10152403039101658",
"privacy": {
"value": ""
},
"share_count": 0,
"share_info": {
"can_share": true,
"share_count": 0
},
"source_id": 568851657,
"subscribed": false,
"tagged_ids": [
],
"type": 46,
"updated_time": 1413222111,
"with_tags": [
]
}
]
},
{
"name": "comments",
"fql_result_set": [
{
"app_id": 0,
"attachment": null,
"post_id": "568851657_10152403039101658",
"id": "10152403039101658_10152403084216658",
"likes": 0,
"fromid": 568851657,
"time": 1413222111,
"text": "And Siri said unto them, \"I'm sorry, I did not understand that.\" And the pharisees were wroth, and sought to harden the heart of Palmius Pilot against her.",
"text_tags": [
],
"user_likes": false
}
]
},
{
"name": "applications",
"fql_result_set": [
]
},
{
"name": "profiles",
"fql_result_set": [
{
"id": 568851657,
"name": "Stephen Carr",
"username": "stephen.carr.547",
"url": "https://www.facebook.com/stephen.carr.547",
"pic_square": "https://scontent-a.xx.fbcdn.net/hprofile-xpa1/v/t1.0-1/c0.0.50.50/p50x50/1229928_10152376737046658_8387683222153583301_n.jpg?oh=4c9cf110c2953f26e0c83bc644449730&oe=54B95BF9"
}
]
},
{
"name": "avatars",
"fql_result_set": [
{
"id": 568851657,
"real_size": 320,
"size": 256,
"url": "https://scontent-a.xx.fbcdn.net/hprofile-xpa1/v/t1.0-1/c0.0.320.320/p320x320/1229928_10152376737046658_8387683222153583301_n.jpg?oh=9627591ac52d10005212abbae4c1f451&oe=54AD7B88"
}
]
}
]
}

64
fbsync/tests/fql.txt Normal file
View file

@ -0,0 +1,64 @@
{
"data": [
{
"action_links": null,
"actor_id": "109524391244",
"app_data": [
],
"app_id": "2309869772",
"attachment": {
"media": [
{
"href": "http://www.theverge.com/2014/10/8/6946033/google-put-street-view-camera-on-camels-back-to-tour-desert",
"alt": "",
"type": "link",
"src": "https://fbexternal-a.akamaihd.net/safe_image.php?d=AQC6sIH1Zb6kwIlg&w=158&h=158&url=http%3A%2F%2Fcdn1.vox-cdn.com%2Fuploads%2Fchorus_image%2Fimage%2F41261020%2FScreen_Shot_2014-10-08_at_10.44.15_AM.0.0_cinema_1200.0.png"
}
],
"name": "Google put its Street View camera on a camel's back to tour the Arabian desert",
"href": "http://www.theverge.com/2014/10/8/6946033/google-put-street-view-camera-on-camels-back-to-tour-desert",
"caption": "www.theverge.com",
"description": "Google's Street View cameras have been carried around on cars, boats, people, and now camels. The company recently set out to capture 360-degree imagery of the Arabian desert, and to \"minimize\"...",
"properties": [
],
"icon": "https://fbstatic-a.akamaihd.net/rsrc.php/v2/yD/r/aS8ecmYRys0.gif"
},
"attribution": null,
"comment_info": {
"can_comment": true,
"comment_count": 0,
"comment_order": "chronological"
},
"created_time": 1412784080,
"filter_key": "nf",
"like_info": {
"can_like": true,
"like_count": 0,
"user_likes": false
},
"message": "",
"message_tags": [
],
"parent_post_id": null,
"permalink": "https://www.facebook.com/baltimorenode/posts/10152483187826245",
"place": null,
"post_id": "109524391244_10152483187826245",
"privacy": {
"value": ""
},
"share_count": 0,
"share_info": {
"can_share": true,
"share_count": 0
},
"source_id": "109524391244",
"subscribed": false,
"tagged_ids": [
],
"type": 80,
"updated_time": 1412784080,
"with_tags": [
]
}
]
}

View file

@ -0,0 +1,58 @@
{
"data": [
{
"id": "109524391244_10152483187826245",
"from": {
"category": "Non-profit organization",
"category_list": [
{
"id": "133436743388217",
"name": "Arts & Entertainment"
},
{
"id": "139823692748565",
"name": "Computers & Electronics"
},
{
"id": "292231357479999",
"name": "Robotics"
}
],
"name": "Baltimore Node",
"id": "109524391244"
},
"story": "Baltimore Node shared a link.",
"picture": "https://fbexternal-a.akamaihd.net/safe_image.php?d=AQC6sIH1Zb6kwIlg&w=158&h=158&url=http%3A%2F%2Fcdn1.vox-cdn.com%2Fuploads%2Fchorus_image%2Fimage%2F41261020%2FScreen_Shot_2014-10-08_at_10.44.15_AM.0.0_cinema_1200.0.png",
"link": "http://www.theverge.com/2014/10/8/6946033/google-put-street-view-camera-on-camels-back-to-tour-desert",
"name": "Google put its Street View camera on a camel's back to tour the Arabian desert",
"caption": "www.theverge.com",
"description": "Google's Street View cameras have been carried around on cars, boats, people, and now camels. The company recently set out to capture 360-degree imagery of the Arabian desert, and to \"minimize\"...",
"icon": "https://fbstatic-a.akamaihd.net/rsrc.php/v2/yD/r/aS8ecmYRys0.gif",
"actions": [
{
"name": "Comment",
"link": "https://www.facebook.com/109524391244/posts/10152483187826245"
},
{
"name": "Like",
"link": "https://www.facebook.com/109524391244/posts/10152483187826245"
}
],
"privacy": {
"value": ""
},
"type": "link",
"status_type": "shared_story",
"application": {
"name": "Links",
"id": "2309869772"
},
"created_time": "2014-10-08T16:01:20+0000",
"updated_time": "2014-10-08T16:01:20+0000"
}
],
"paging": {
"previous": "https://graph.facebook.com/v2.1/10152271780185899/home?limit=10&since=1412784449",
"next": "https://graph.facebook.com/v2.1/10152271780185899/home?limit=10&until=1412780437"
}
}

53
fbsync/tests/graph2.1.txt Normal file
View file

@ -0,0 +1,53 @@
{
"data": [
{
"actions": [
{
"name": "Comment",
"link": "https://www.facebook.com/109524391244/posts/10152483187826245"
},
{
"name": "Like",
"link": "https://www.facebook.com/109524391244/posts/10152483187826245"
}
],
"link": "http://www.theverge.com/2014/10/8/6946033/google-put-street-view-camera-on-camels-back-to-tour-desert",
"id": "109524391244_10152483187826245",
"created_time": "2014-10-08T16:01:20+0000",
"application": {
"name": "Links",
"id": "2309869772"
},
"updated_time": "2014-10-08T16:01:20+0000",
"description": "Google's Street View cameras have been carried around on cars, boats, people, and now camels. The company recently set out to capture 360-degree imagery of the Arabian desert, and to \"minimize\"...",
"privacy": {
"value": ""
},
"attachments": {
"data": [
{
"description": "Google's Street View cameras have been carried around on cars, boats, people, and now camels. The company recently set out to capture 360-degree imagery of the Arabian desert, and to \"minimize\"...",
"media": {
"image": {
"height": 674,
"src": "https://fbexternal-a.akamaihd.net/safe_image.php?d=AQBgDPhjhIZYFbxy&w=720&h=720&url=http%3A%2F%2Fcdn1.vox-cdn.com%2Fuploads%2Fchorus_image%2Fimage%2F41261020%2FScreen_Shot_2014-10-08_at_10.44.15_AM.0.0_cinema_1200.0.png&cfs=1",
"width": 674
}
},
"target": {
"id": "10152483187826245",
"url": "http://www.facebook.com/l.php?u=http%3A%2F%2Fwww.theverge.com%2F2014%2F10%2F8%2F6946033%2Fgoogle-put-street-view-camera-on-camels-back-to-tour-desert&h=XAQGWkIO2&s=1&enc=AZNOhgg2O7yFa63a0PeP8UE1EdJLbSArpD1HntdBft53llpu9kK38pKnp5svQCc6B355x1mgDXK3fD6dZfqIm29e"
},
"title": "Google put its Street View camera on a camel's back to tour the Arabian desert",
"type": "share",
"url": "http://www.facebook.com/l.php?u=http%3A%2F%2Fwww.theverge.com%2F2014%2F10%2F8%2F6946033%2Fgoogle-put-street-view-camera-on-camels-back-to-tour-desert&h=XAQGWkIO2&s=1&enc=AZNOhgg2O7yFa63a0PeP8UE1EdJLbSArpD1HntdBft53llpu9kK38pKnp5svQCc6B355x1mgDXK3fD6dZfqIm29e"
}
]
}
}
],
"paging": {
"previous": "https://graph.facebook.com/v2.1/10152271780185899/home?fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares&limit=1&since=1412784080",
"next": "https://graph.facebook.com/v2.1/10152271780185899/home?fields=actions,link,id,created_time,application,attachments,updated_time,object_id,with_tags,comments{can_comment,comment_count},likes,message,message_tags,description,parent_id,place,privacy,shares&limit=1&until=1412784079"
}
}