streams/include/api.php

2359 lines
66 KiB
PHP
Raw Normal View History

2013-02-26 01:09:40 +00:00
<?php /** @file */
2013-01-19 14:08:13 +00:00
require_once("bbcode.php");
require_once("datetime.php");
require_once("conversation.php");
require_once("oauth.php");
require_once("html2plain.php");
require_once('include/security.php');
require_once('include/photos.php');
2014-01-25 02:50:47 +00:00
require_once('include/items.php');
require_once('include/attach.php');
require_once('include/api_auth.php');
2013-01-16 23:51:21 +00:00
/*
*
* Red API. Loosely based on and possibly compatible with a Twitter-Like API but all similarities end there.
*
2011-02-15 11:24:21 +00:00
*/
2013-01-19 14:08:13 +00:00
/**
** TWITTER API
*/
$API = array();
$called_api = Null;
2011-04-21 15:03:31 +00:00
// All commands which require authentication accept a "channel" parameter
// which is the left hand side of the channel address/nickname.
// If provided, the desired channel is selected before caarying out the command.
// If not provided, the default channel associated with the account is used.
// If channel selection fails, the API command requiring login will fail.
2013-01-16 23:51:21 +00:00
function api_user() {
$aid = get_account_id();
$channel = get_app()->get_channel();
if(($aid) && (x($_REQUEST,'channel'))) {
// Only change channel if it is different than the current channel
if($channel && x($channel,'channel_address') && $channel['channel_address'] != $_REQUEST['channel']) {
$c = q("select channel_id from channel where channel_address = '%s' and channel_account_id = %d limit 1",
dbesc($_REQUEST['channel']),
intval($aid)
);
if((! $c) || (! change_channel($c[0]['channel_id'])))
return false;
}
}
2013-01-16 23:51:21 +00:00
if ($_SESSION["allow_api"])
2015-01-29 04:56:04 +00:00
return local_channel();
2013-01-16 23:51:21 +00:00
return false;
}
2011-02-15 11:24:21 +00:00
function api_date($str){
//Wed May 23 06:01:13 +0000 2007
2011-08-16 11:55:38 +00:00
return datetime_convert('UTC', 'UTC', $str, "D M d H:i:s +0000 Y" );
2011-02-15 11:24:21 +00:00
}
2011-02-15 11:24:21 +00:00
function api_register_func($path, $func, $auth=false){
global $API;
$API[$path] = array('func'=>$func,
2011-02-16 07:56:47 +00:00
'auth'=>$auth);
2011-02-15 11:24:21 +00:00
}
2011-02-15 11:24:21 +00:00
2011-04-21 15:03:31 +00:00
/**************************
* MAIN API ENTRY POINT *
**************************/
2013-01-19 14:08:13 +00:00
2011-02-15 11:24:21 +00:00
function api_call(&$a){
2011-08-26 14:35:51 +00:00
GLOBAL $API, $called_api;
2012-02-20 00:53:22 +00:00
// preset
$type="json";
2011-02-15 11:24:21 +00:00
foreach ($API as $p=>$info){
if (strpos($a->query_string, $p)===0){
2011-08-26 14:35:51 +00:00
$called_api= explode("/",$p);
2012-01-12 23:46:39 +00:00
//unset($_SERVER['PHP_AUTH_USER']);
2013-01-17 03:18:10 +00:00
if ($info['auth'] === true && api_user() === false) {
2011-04-21 15:03:31 +00:00
api_login($a);
2011-02-15 11:24:21 +00:00
}
2011-07-31 23:35:53 +00:00
2013-01-16 23:51:21 +00:00
load_contact_links(api_user());
2011-07-31 23:35:53 +00:00
2013-01-17 03:18:10 +00:00
$channel = $a->get_channel();
logger('API call for ' . $channel['channel_name'] . ': ' . $a->query_string);
logger('API parameters: ' . print_r($_REQUEST,true));
2013-01-17 03:18:10 +00:00
2012-02-20 00:53:22 +00:00
$type="json";
2013-01-17 03:18:10 +00:00
2011-04-21 15:03:31 +00:00
if (strpos($a->query_string, ".xml")>0) $type="xml";
if (strpos($a->query_string, ".json")>0) $type="json";
if (strpos($a->query_string, ".rss")>0) $type="rss";
2012-02-20 00:53:22 +00:00
if (strpos($a->query_string, ".atom")>0) $type="atom";
if (strpos($a->query_string, ".as")>0) $type="as";
2012-02-20 00:53:22 +00:00
2011-04-21 15:03:31 +00:00
$r = call_user_func($info['func'], $a, $type);
if ($r===false) return;
switch($type){
case "xml":
$r = mb_convert_encoding($r, "UTF-8",mb_detect_encoding($r));
header ("Content-Type: text/xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
2012-02-20 00:53:22 +00:00
case "json":
2013-01-17 03:18:10 +00:00
header ("Content-Type: application/json");
2011-06-21 00:16:13 +00:00
foreach($r as $rr)
2014-10-16 09:02:11 +00:00
$json = json_encode($rr);
if ($_GET['callback'])
$json = $_GET['callback']."(".$json.")";
return $json;
2011-04-21 15:03:31 +00:00
break;
case "rss":
header ("Content-Type: application/rss+xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
case "atom":
header ("Content-Type: application/atom+xml");
2011-04-21 15:03:31 +00:00
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
case "as":
//header ("Content-Type: application/json");
//foreach($r as $rr)
// return json_encode($rr);
return json_encode($r);
break;
2012-02-20 00:53:22 +00:00
2011-02-15 11:24:21 +00:00
}
//echo "<pre>"; var_dump($r); die();
}
}
header("HTTP/1.1 404 Not Found");
2012-02-20 10:15:22 +00:00
logger('API call not implemented: '.$a->query_string." - ".print_r($_REQUEST,true));
2011-08-01 03:01:00 +00:00
$r = '<status><error>not implemented</error></status>';
switch($type){
case "xml":
header ("Content-Type: text/xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
2012-02-20 00:53:22 +00:00
case "json":
header ("Content-Type: application/json");
2011-08-01 03:01:00 +00:00
return json_encode(array('error' => 'not implemented'));
break;
case "rss":
header ("Content-Type: application/rss+xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
case "atom":
header ("Content-Type: application/atom+xml");
return '<?xml version="1.0" encoding="UTF-8"?>'."\n".$r;
break;
}
2011-02-15 11:24:21 +00:00
}
2011-04-21 15:03:31 +00:00
/**
* RSS extra info
*/
function api_rss_extra(&$a, $arr, $user_info){
if (is_null($user_info)) $user_info = api_get_user($a);
$arr['$user'] = $user_info;
2011-04-21 15:03:31 +00:00
$arr['$rss'] = array(
'alternate' => $user_info['url'],
'self' => $a->get_baseurl(). "/". $a->query_string,
2011-07-31 23:35:53 +00:00
'base' => $a->get_baseurl(),
2011-04-21 15:03:31 +00:00
'updated' => api_date(null),
2011-07-31 23:35:53 +00:00
'atom_updated' => datetime_convert('UTC','UTC','now',ATOM_TIME),
2011-04-21 15:03:31 +00:00
'language' => $user_info['language'],
2013-11-23 19:01:11 +00:00
'logo' => $a->get_baseurl()."/images/rm-64.png",
2011-04-21 15:03:31 +00:00
);
return $arr;
}
2011-02-15 11:24:21 +00:00
/**
2011-04-21 15:03:31 +00:00
* Returns user info array.
2011-02-15 11:24:21 +00:00
*/
2015-04-20 01:14:17 +00:00
function api_get_user(&$a, $contact_id = null, $contact_xchan = null){
2011-08-26 14:35:51 +00:00
global $called_api;
2011-02-15 11:24:21 +00:00
$user = null;
$extra_query = "";
2011-07-31 07:53:46 +00:00
2011-08-19 14:55:43 +00:00
2015-04-20 01:14:17 +00:00
if(! is_null($contact_xchan)) {
$user = local_channel();
$extra_query = " and abook_xchan = '" . dbesc($contact_xchan) . "' ";
2011-02-15 11:24:21 +00:00
}
2015-04-20 01:14:17 +00:00
else {
if(!is_null($contact_id)){
$user=$contact_id;
$extra_query = " AND abook_id = %d ";
}
2011-02-15 11:24:21 +00:00
2015-04-20 01:14:17 +00:00
if(is_null($user) && x($_GET, 'user_id')) {
$user = intval($_GET['user_id']);
$extra_query = " AND abook_id = %d ";
2015-04-20 01:14:17 +00:00
}
if(is_null($user) && x($_GET, 'screen_name')) {
$user = dbesc($_GET['screen_name']);
$extra_query = " AND xchan_addr like '%s@%%' ";
2015-04-20 01:14:17 +00:00
if (api_user()!==false)
$extra_query .= " AND abook_channel = ".intval(api_user());
2011-02-15 11:24:21 +00:00
}
2015-04-20 01:14:17 +00:00
if (is_null($user) && argc() > (count($called_api)-1) && (strstr($a->cmd,'/users'))){
2015-04-20 01:14:17 +00:00
$argid = count($called_api);
list($xx, $null) = explode(".",argv($argid));
if(is_numeric($xx)){
$user = intval($xx);
2015-04-20 01:14:17 +00:00
$extra_query = " AND abook_id = %d ";
} else {
$user = dbesc($xx);
2015-04-20 01:14:17 +00:00
$extra_query = " AND xchan_addr like '%s@%%' ";
if (api_user() !== false)
$extra_query .= " AND abook_channel = ".intval(api_user());
}
}
2011-02-15 11:24:21 +00:00
}
if (! $user) {
if (api_user() === false) {
api_login($a);
return False;
2011-02-16 07:56:47 +00:00
} else {
2015-01-29 04:56:04 +00:00
$user = local_channel();
2015-06-15 04:08:00 +00:00
$extra_query = " AND abook_channel = %d AND abook_self = 1 ";
2011-02-16 07:56:47 +00:00
}
2011-02-15 11:24:21 +00:00
}
logger('api_user: ' . $extra_query . ', user: ' . $user);
2011-02-15 11:24:21 +00:00
// user info
$uinfo = q("SELECT * from abook left join xchan on abook_xchan = xchan_hash
WHERE 1
2011-02-15 11:24:21 +00:00
$extra_query",
$user
);
2011-02-15 11:24:21 +00:00
if (count($uinfo)==0) {
return False;
}
2015-06-15 04:08:00 +00:00
if(intval($uinfo[0]['abook_self'])) {
$usr = q("select * from channel where channel_id = %d limit 1",
2013-01-16 23:51:21 +00:00
intval(api_user())
2011-08-05 12:17:18 +00:00
);
2012-08-31 01:17:38 +00:00
$profile = q("select * from profile where uid = %d and `is_default` = 1 limit 1",
2013-01-16 23:51:21 +00:00
intval(api_user())
2011-08-05 12:17:18 +00:00
);
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
2011-08-01 03:01:00 +00:00
// count public wall messages
$r = q("SELECT COUNT(`id`) as `count` FROM `item`
2013-01-17 03:18:10 +00:00
WHERE `uid` = %d
2015-06-10 23:59:04 +00:00
AND item_wall = 1 $item_normal
2011-08-01 03:01:00 +00:00
AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
intval($usr[0]['channel_id'])
2011-08-01 03:01:00 +00:00
);
$countitms = $r[0]['count'];
}
else {
$r = q("SELECT COUNT(`id`) as `count` FROM `item`
WHERE author_xchan = '%s'
2011-08-01 03:01:00 +00:00
AND `allow_cid`='' AND `allow_gid`='' AND `deny_cid`='' AND `deny_gid`=''",
intval($uinfo[0]['xchan_hash'])
2011-08-01 03:01:00 +00:00
);
$countitms = $r[0]['count'];
}
2011-02-15 11:24:21 +00:00
// count friends
2013-01-17 03:18:10 +00:00
if($usr) {
$r = q("SELECT COUNT(abook_id) as `count` FROM abook
2015-06-15 04:08:00 +00:00
WHERE abook_channel = %d AND abook_self = 0 ",
2013-01-17 03:18:10 +00:00
intval($usr[0]['channel_id'])
);
$countfriends = $r[0]['count'];
$countfollowers = $r[0]['count'];
}
2011-08-01 05:22:34 +00:00
2015-06-10 23:59:04 +00:00
$r = q("SELECT count(`id`) as `count` FROM item where item_starred = 1 and uid = %d " . item_normal(),
intval($uinfo[0]['channel_id'])
2011-08-05 12:17:18 +00:00
);
$starred = $r[0]['count'];
2015-06-15 04:08:00 +00:00
if(! intval($uinfo[0]['abook_self'])) {
2011-08-01 03:01:00 +00:00
$countfriends = 0;
2011-08-01 05:22:34 +00:00
$countfollowers = 0;
2011-08-05 12:17:18 +00:00
$starred = 0;
2011-08-01 03:01:00 +00:00
}
2011-02-16 07:56:47 +00:00
$ret = Array(
2013-01-17 03:18:10 +00:00
'id' => intval($uinfo[0]['abook_id']),
2015-06-15 04:08:00 +00:00
'self' => (intval($uinfo[0]['abook_self']) ? 1 : 0),
2013-01-17 03:18:10 +00:00
'uid' => intval($uinfo[0]['abook_channel']),
'guid' => $uinfo[0]['xchan_hash'],
'name' => (($uinfo[0]['xchan_name']) ? $uinfo[0]['xchan_name'] : substr($uinfo[0]['xchan_addr'],0,strpos($uinfo[0]['xchan_addr'],'@'))),
'screen_name' => substr($uinfo[0]['xchan_addr'],0,strpos($uinfo[0]['xchan_addr'],'@')),
'location' => ($usr) ? $usr[0]['channel_location'] : '',
'profile_image_url' => $uinfo[0]['xchan_photo_l'],
'url' => $uinfo[0]['xchan_url'],
//FIXME
'contact_url' => $a->get_baseurl() . "/connections/".$uinfo[0]['abook_id'],
2011-08-05 12:17:18 +00:00
'protected' => false,
'friends_count' => intval($countfriends),
2013-01-17 03:18:10 +00:00
'created_at' => api_date($uinfo[0]['abook_created']),
2011-08-05 12:17:18 +00:00
'utc_offset' => "+00:00",
'time_zone' => 'UTC', //$uinfo[0]['timezone'],
2011-02-16 07:56:47 +00:00
'geo_enabled' => false,
2015-04-20 00:39:17 +00:00
'statuses_count' => intval($countitms), //#XXX: fix me
2013-01-17 03:18:10 +00:00
'lang' => get_app()->language,
2011-08-05 12:17:18 +00:00
'description' => (($profile) ? $profile[0]['pdesc'] : ''),
'followers_count' => intval($countfollowers),
'favourites_count' => intval($starred),
2011-02-16 07:56:47 +00:00
'contributors_enabled' => false,
2011-08-26 14:35:51 +00:00
'follow_request_sent' => true,
2011-02-16 07:56:47 +00:00
'profile_background_color' => 'cfe8f6',
'profile_text_color' => '000000',
'profile_link_color' => 'FF8500',
'profile_sidebar_fill_color' =>'AD0066',
'profile_sidebar_border_color' => 'AD0066',
'profile_background_image_url' => '',
'profile_background_tile' => false,
'profile_use_background_image' => false,
2011-04-21 15:03:31 +00:00
'notifications' => false,
2015-04-20 00:39:17 +00:00
'following' => '', // #XXX: fix me
'verified' => true // #XXX: fix me
2011-02-16 07:56:47 +00:00
);
2015-04-20 00:39:17 +00:00
$x = api_get_status($uinfo[0]['xchan_hash']);
if($x)
$ret['status'] = $x;
// logger('api_get_user: ' . print_r($ret,true));
2011-02-16 07:56:47 +00:00
return $ret;
}
2011-04-21 15:03:31 +00:00
function api_client_register(&$a,$type) {
$ret = array();
$key = random_string(16);
$secret = random_string(16);
$name = trim(escape_tags($_REQUEST['application_name']));
if(! $name)
json_return_and_die($ret);
if(is_array($_REQUEST['redirect_uris']))
$redirect = trim($_REQUEST['redirect_uris'][0]);
else
$redirect = trim($_REQUEST['redirect_uris']);
$icon = trim($_REQUEST['logo_uri']);
$r = q("INSERT INTO clients (client_id, pw, name, redirect_uri, icon, uid)
VALUES ('%s','%s','%s','%s','%s',%d)",
dbesc($key),
dbesc($secret),
dbesc($name),
dbesc($redirect),
dbesc($icon),
intval(0)
);
$ret['client_id'] = $key;
$ret['client_secret'] = $secret;
$ret['expires_at'] = 0;
json_return_and_die($ret);
}
api_register_func('api/client/register','api_client_register', false);
2011-07-31 07:53:46 +00:00
function api_item_get_user(&$a, $item) {
global $usercache;
2011-07-31 23:35:53 +00:00
// The author is our direct contact, in a conversation with us.
2013-01-19 14:08:13 +00:00
if($item['author']['abook_id']) {
return api_get_user($a,$item['author']['abook_id']);
}
2011-07-31 23:35:53 +00:00
// We don't know this person directly.
2011-08-19 18:33:34 +00:00
$nick = substr($item['author']['xchan_addr'],0,strpos($item['author']['xchan_addr'],'@'));
$name = $item['author']['xchan_name'];
// Generating a random ID
if (is_null($usercache[$nick]) or !array_key_exists($nick, $usercache))
$usercache[$nick] = mt_rand(2000000, 2100000);
2011-07-31 07:53:46 +00:00
$ret = array(
'id' => $usercache[$nick],
2011-08-19 18:33:34 +00:00
'name' => $name,
'screen_name' => $nick,
2011-07-31 07:53:46 +00:00
'location' => '', //$uinfo[0]['default-location'],
'description' => '',
'profile_image_url' => $item['author']['xchan_photo_m'],
'url' => $item['author']['xchan_url'],
2015-04-20 00:39:17 +00:00
'protected' => false,
'followers_count' => 0,
2011-07-31 07:53:46 +00:00
'friends_count' => 0,
2011-07-31 23:35:53 +00:00
'created_at' => '',
'favourites_count' => 0,
2015-04-20 00:39:17 +00:00
'utc_offset' => 0, // #XXX: fix me
2011-07-31 07:53:46 +00:00
'time_zone' => '', //$uinfo[0]['timezone'],
'statuses_count' => 0,
'following' => 1,
'statusnet_blocking' => false,
'notifications' => false,
'uid' => 0,
'contact_url' => 0,
'geo_enabled' => false,
2015-04-20 00:39:17 +00:00
'lang' => 'en', // #XXX: fix me
2011-07-31 07:53:46 +00:00
'contributors_enabled' => false,
'follow_request_sent' => false,
'profile_background_color' => 'cfe8f6',
'profile_text_color' => '000000',
'profile_link_color' => 'FF8500',
'profile_sidebar_fill_color' =>'AD0066',
'profile_sidebar_border_color' => 'AD0066',
'profile_background_image_url' => '',
'profile_background_tile' => false,
'profile_use_background_image' => false,
2015-04-20 00:39:17 +00:00
'verified' => true, // #XXX: fix me
'followers' => '' // #XXX: fix me
2011-07-31 07:53:46 +00:00
);
return $ret;
}
2011-04-21 15:03:31 +00:00
/**
* load api $templatename for $type and replace $data array
*/
function api_apply_template($templatename, $type, $data){
2011-06-21 00:16:13 +00:00
2011-07-31 23:35:53 +00:00
$a = get_app();
2011-04-21 15:03:31 +00:00
switch($type){
case "atom":
2011-07-31 23:35:53 +00:00
case "rss":
2011-04-21 15:03:31 +00:00
case "xml":
2011-10-27 08:54:52 +00:00
$data = array_xmlify($data);
2011-05-11 11:37:13 +00:00
$tpl = get_markup_template("api_".$templatename."_".$type.".tpl");
2011-04-21 15:03:31 +00:00
$ret = replace_macros($tpl, $data);
break;
case "json":
$ret = $data;
break;
}
return $ret;
}
2011-02-16 07:56:47 +00:00
/**
* Returns an HTTP 200 OK response code and a representation of the requesting user if authentication was successful;
* returns a 401 status code and an error message if not.
* http://developer.twitter.com/doc/get/account/verify_credentials
*/
2011-04-21 15:03:31 +00:00
function api_account_verify_credentials(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
2011-02-16 07:56:47 +00:00
$user_info = api_get_user($a);
2011-04-21 15:03:31 +00:00
return api_apply_template("user", $type, array('$user' => $user_info));
2011-02-16 07:56:47 +00:00
}
api_register_func('api/account/verify_credentials','api_account_verify_credentials', true);
2013-01-17 03:18:10 +00:00
function api_account_logout(&$a, $type){
require_once('include/auth.php');
nuke_session();
return api_apply_template("user", $type, array('$user' => null));
}
api_register_func('api/account/logout','api_account_logout', false);
2011-02-16 07:56:47 +00:00
2013-01-17 03:18:10 +00:00
/**
2013-01-17 03:18:10 +00:00
* get data from $_REQUEST ( e.g. $_POST or $_GET )
*/
2013-01-17 03:18:10 +00:00
function requestdata($k) {
if(array_key_exists($k,$_REQUEST))
return $_REQUEST[$k];
return null;
}
2011-09-12 04:52:50 +00:00
/*
* Red basic channel export
*/
function api_export_basic(&$a, $type) {
if(api_user() === false) {
logger('api_export_basic: no user');
return false;
}
require_once('include/identity.php');
json_return_and_die(identity_basic_export(api_user(),(($_REQUEST['posts']) ? intval($_REQUEST['posts']) : 0 )));
}
api_register_func('api/export/basic','api_export_basic', true);
api_register_func('api/red/channel/export/basic','api_export_basic', true);
function api_channel_stream(&$a, $type) {
if(api_user() === false) {
logger('api_channel_stream: no user');
return false;
}
if($_SERVER['REQUEST_METHOD'] == 'POST') {
json_return_and_die(post_activity_item($_REQUEST));
}
else {
// fetch stream
2013-05-23 02:16:05 +00:00
}
}
api_register_func('api/red/channel/stream','api_channel_stream', true);
function api_attach_list(&$a,$type) {
logger('api_user: ' . api_user());
2015-10-13 23:15:34 +00:00
json_return_and_die(attach_list_files(api_user(),get_observer_hash(),'','','','created asc'));
}
api_register_func('api/red/files','api_attach_list', true);
function api_file_meta(&$a,$type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
intval(api_user()),
dbesc($_REQUEST['file_id'])
);
if($r) {
unset($r[0]['data']);
$ret = array('attach' => $r[0]);
json_return_and_die($ret);
}
killme();
}
api_register_func('api/red/filemeta', 'api_file_meta', true);
function api_file_data(&$a,$type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$start = (($_REQUEST['start']) ? intval($_REQUEST['start']) : 0);
$length = (($_REQUEST['length']) ? intval($_REQUEST['length']) : 0);
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
intval(api_user()),
dbesc($_REQUEST['file_id'])
);
if($r) {
$ptr = $r[0];
if($length === 0)
$length = intval($ptr['filesize']);
if($ptr['is_dir'])
$ptr['data'] = '';
elseif(! intval($r[0]['os_storage'])) {
$ptr['start'] = $start;
$x = substr(dbunescbin($ptr['data'],$start,$length));
$ptr['length'] = strlen($x);
$ptr['data'] = base64_encode($x);
}
else {
$fp = fopen(dbunescbin($ptr['data']),'r');
if($fp) {
$seek = fseek($fp,$start,SEEK_SET);
$x = fread($fp,$length);
$ptr['start'] = $start;
$ptr['length'] = strlen($x);
$ptr['data'] = base64_encode($x);
}
}
$ret = array('attach' => $ptr);
json_return_and_die($ret);
}
killme();
}
api_register_func('api/red/filedata', 'api_file_data', true);
function api_file_detail(&$a,$type) {
if (api_user()===false) return false;
if(! $_REQUEST['file_id']) return false;
$r = q("select * from attach where uid = %d and hash = '%s' limit 1",
intval(api_user()),
dbesc($_REQUEST['file_id'])
);
if($r) {
if($r[0]['is_dir'])
$r[0]['data'] = '';
elseif(intval($r[0]['os_storage']))
$r[0]['data'] = base64_encode(file_get_contents(dbunescbin($r[0]['data'])));
else
$r[0]['data'] = base64_encode(dbunescbin($r[0]['data']));
$ret = array('attach' => $r[0]);
json_return_and_die($ret);
}
killme();
}
api_register_func('api/red/file', 'api_file_detail', true);
function api_albums(&$a,$type) {
json_return_and_die(photos_albums_list($a->get_channel(),$a->get_observer()));
}
api_register_func('api/red/albums','api_albums', true);
function api_photos(&$a,$type) {
$album = $_REQUEST['album'];
json_return_and_die(photos_list_photos($a->get_channel(),$a->get_observer(),$album));
}
api_register_func('api/red/photos','api_photos', true);
2015-08-19 05:14:16 +00:00
function api_photo_detail(&$a,$type) {
if (api_user()===false) return false;
if(! $_REQUEST['photo_id']) return false;
$scale = ((array_key_exists('scale',$_REQUEST)) ? intval($_REQUEST['scale']) : 0);
$r = q("select * from photo where uid = %d and resource_id = '%s' and scale = %d limit 1",
intval(local_channel()),
dbesc($_REQUEST['photo_id']),
intval($scale)
);
if($r) {
$data = dbunescbin($r[0]['data']);
if(array_key_exists('os_storage',$r[0]) && intval($r[0]['os_storage']))
$data = file_get_contents($data);
$r[0]['data'] = base64_encode($data);
2015-08-27 05:11:50 +00:00
$ret = array('photo' => $r[0]);
$i = q("select id from item where uid = %d and resource_type = 'photo' and resource_id = '%s' limit 1",
intval(local_channel()),
dbesc($_REQUEST['photo_id'])
);
if($i) {
$ii = q("select * from item where parent = %d order by id",
intval($i[0]['id'])
);
if($ii) {
xchan_query($ii,true,0);
$ii = fetch_post_tags($ii,true);
if($ii) {
$ret['item'] = array();
foreach($ii as $iii)
$ret['item'][] = encode_item($iii,true);
2015-08-27 05:11:50 +00:00
}
}
}
json_return_and_die($ret);
2015-08-19 05:14:16 +00:00
}
killme();
}
api_register_func('api/red/photo', 'api_photo_detail', true);
function api_group_members(&$a,$type) {
if(api_user() === false)
return false;
if($_REQUEST['group_id']) {
$r = q("select * from groups where uid = %d and id = %d limit 1",
intval(api_user()),
intval($_REQUEST['group_id'])
);
if($r) {
$x = q("select * from group_member left join xchan on group_member.xchan = xchan.xchan_hash
left join abook on abook_xchan = xchan_hash where gid = %d",
intval($_REQUEST['group_id'])
);
json_return_and_die($x);
}
}
}
api_register_func('api/red/group_members','api_group_members', true);
function api_group(&$a,$type) {
if(api_user() === false)
return false;
$r = q("select * from groups where uid = %d",
intval(api_user())
);
json_return_and_die($r);
}
api_register_func('api/red/group','api_group', true);
2014-10-24 02:33:47 +00:00
function api_red_xchan(&$a,$type) {
logger('api_xchan');
2014-10-24 02:33:47 +00:00
if(api_user() === false)
return false;
logger('api_xchan');
2014-10-24 02:33:47 +00:00
require_once('include/hubloc.php');
if($_SERVER['REQUEST_METHOD'] === 'POST') {
2014-10-24 02:33:47 +00:00
$r = xchan_store($_REQUEST);
}
$r = xchan_fetch($_REQUEST);
json_return_and_die($r);
};
2014-10-24 02:33:47 +00:00
api_register_func('api/red/xchan','api_red_xchan',true);
2015-08-19 05:14:16 +00:00
function api_statuses_mediap(&$a, $type) {
2013-01-19 14:08:13 +00:00
if (api_user() === false) {
logger('api_statuses_update: no user');
return false;
}
$user_info = api_get_user($a);
2015-11-17 23:03:27 +00:00
// logger('status_with_media: ' . print_r($_REQUEST,true), LOGGER_DEBUG);
2013-01-19 14:08:13 +00:00
$_REQUEST['type'] = 'wall';
$_REQUEST['profile_uid'] = api_user();
$_REQUEST['api_source'] = true;
2015-08-19 05:14:16 +00:00
2013-01-19 14:08:13 +00:00
$txt = requestdata('status');
require_once('library/HTMLPurifier.auto.php');
require_once('include/html2bbcode.php');
if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
$txt = html2bb_video($txt);
$config = HTMLPurifier_Config::createDefault();
2013-01-19 14:08:13 +00:00
$config->set('Cache.DefinitionImpl', null);
$purifier = new HTMLPurifier($config);
2013-01-19 14:08:13 +00:00
$txt = $purifier->purify($txt);
}
$txt = html2bbcode($txt);
2015-08-19 05:14:16 +00:00
$a->argv[1] = $user_info['screen_name'];
$_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo
$_FILES['userfile'] = $_FILES['media'];
2015-03-16 22:35:46 +00:00
require_once('mod/wall_attach.php');
$posted = wall_attach_post($a);
2015-08-19 05:14:16 +00:00
//now that we have the img url in bbcode we can add it to the status and insert the wall item.
2013-01-19 14:08:13 +00:00
$_REQUEST['body']=$txt."\n\n".$posted;
2013-01-17 03:18:10 +00:00
require_once('mod/item.php');
item_post($a);
2013-01-17 03:18:10 +00:00
// this should output the last post (the one we just posted).
return api_status_show($a,$type);
}
api_register_func('api/statuses/mediap','api_statuses_mediap', true);
function api_statuses_update(&$a, $type) {
if (api_user() === false) {
logger('api_statuses_update: no user');
return false;
}
logger('api_statuses_update: REQUEST ' . print_r($_REQUEST,true));
logger('api_statuses_update: FILES ' . print_r($_FILES,true));
// set this so that the item_post() function is quiet and doesn't redirect or emit json
$_REQUEST['api_source'] = true;
$user_info = api_get_user($a);
// convert $_POST array items to the form we use for web posts.
// logger('api_post: ' . print_r($_POST,true));
2011-09-12 04:52:50 +00:00
if(requestdata('htmlstatus')) {
require_once('library/HTMLPurifier.auto.php');
require_once('include/html2bbcode.php');
$txt = requestdata('htmlstatus');
2011-09-12 04:52:50 +00:00
if((strpos($txt,'<') !== false) || (strpos($txt,'>') !== false)) {
$txt = html2bb_video($txt);
2011-09-12 04:52:50 +00:00
$config = HTMLPurifier_Config::createDefault();
$config->set('Cache.DefinitionImpl', null);
$purifier = new HTMLPurifier($config);
$txt = $purifier->purify($txt);
}
$_REQUEST['body'] = html2bbcode($txt);
2011-09-12 04:52:50 +00:00
}
else
$_REQUEST['body'] = requestdata('status');
$parent = requestdata('in_reply_to_status_id');
if(ctype_digit($parent))
$_REQUEST['parent'] = $parent;
else
$_REQUEST['parent_mid'] = $parent;
2015-03-23 03:30:23 +00:00
if($_REQUEST['namespace'] && $parent) {
$x = q("select iid from item_id where service = '%s' and sid = '%s' limit 1",
dbesc($_REQUEST['namespace']),
dbesc($parent)
);
if($x) {
$_REQUEST['parent'] = $x[0]['iid'];
}
}
if(requestdata('lat') && requestdata('long'))
$_REQUEST['coord'] = sprintf("%s %s",requestdata('lat'),requestdata('long'));
2013-01-16 23:51:21 +00:00
$_REQUEST['profile_uid'] = api_user();
2012-06-26 00:45:33 +00:00
if($parent)
$_REQUEST['type'] = 'net-comment';
else {
$_REQUEST['type'] = 'wall';
if(x($_FILES,'media')) {
$_FILES['userfile'] = $_FILES['media'];
// upload the image if we have one
$_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo
require_once('mod/wall_attach.php');
$media = wall_attach_post($a);
if(strlen($media)>0)
$_REQUEST['body'] .= "\n\n".$media;
}
}
// call out normal post function
require_once('mod/item.php');
item_post($a);
// this should output the last post (the one we just posted).
return api_status_show($a,$type);
}
api_register_func('api/statuses/update','api_statuses_update', true);
function red_item_new(&$a, $type) {
if (api_user() === false) {
logger('api_red_item_new: no user');
return false;
}
logger('api_red_item_new: REQUEST ' . print_r($_REQUEST,true));
logger('api_red_item_new: FILES ' . print_r($_FILES,true));
// set this so that the item_post() function is quiet and doesn't redirect or emit json
$_REQUEST['api_source'] = true;
$_REQUEST['profile_uid'] = api_user();
if(x($_FILES,'media')) {
$_FILES['userfile'] = $_FILES['media'];
// upload the image if we have one
$_REQUEST['silent']='1'; //tell wall_upload function to return img info instead of echo
require_once('mod/wall_upload.php');
$media = wall_upload_post($a);
if(strlen($media)>0)
$_REQUEST['body'] .= "\n\n".$media;
}
require_once('mod/item.php');
$x = item_post($a);
json_return_and_die($x);
}
api_register_func('api/red/item/new','red_item_new', true);
function red_item(&$a, $type) {
if (api_user() === false) {
logger('api_red_item_full: no user');
return false;
}
if($_REQUEST['mid']) {
$arr = array('mid' => $_REQUEST['mid']);
}
elseif($_REQUEST['item_id']) {
$arr = array('item_id' => $_REQUEST['item_id']);
}
else
json_return_and_die(array());
$arr['start'] = 0;
$arr['records'] = 999999;
$arr['item_type'] = '*';
$i = items_fetch($arr,$a->get_channel(),get_observer_hash());
if(! $i)
json_return_and_die(array());
$ret = array();
$tmp = array();
$str = '';
foreach($i as $ii) {
$tmp[] = encode_item($ii,true);
if($str)
$str .= ',';
$str .= $ii['id'];
}
$ret['item'] = $tmp;
if($str) {
$r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item.id in ( $str ) ");
if($r)
$ret['item_id'] = $r;
}
json_return_and_die($ret);
}
api_register_func('api/red/item/full','red_item', true);
function api_get_status($xchan_hash) {
require_once('include/security.php');
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
$lastwall = q("SELECT * from item where
2015-06-10 23:59:04 +00:00
item_private = 0 $item_normal
and author_xchan = '%s'
and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = ''
and verb = '%s'
order by created desc limit 1",
dbesc($xchan_hash),
dbesc(ACTIVITY_POST)
);
if($lastwall){
$lastwall = $lastwall[0];
$in_reply_to_status_id = '';
$in_reply_to_user_id = '';
$in_reply_to_screen_name = '';
if($lastwall['author_xchan'] != $lastwall['owner_xchan']) {
$w = q("select * from abook left join xchan on abook_xchan = xchan_hash where
xchan_hash = '%s' limit 1",
dbesc($lastwall['owner_xchan'])
);
if($w) {
$in_reply_to_user_id = $w[0]['abook_id'];
$in_reply_to_screen_name = substr($w[0]['xchan_addr'],0,strpos($w[0]['xchan_addr'],'@'));
}
}
if ($lastwall['parent']!=$lastwall['id']) {
$in_reply_to_status_id=$lastwall['thr_parent'];
if(! $in_reply_to_user_id) {
$in_reply_to_user_id = $user_info['id'];
$in_reply_to_screen_name = $user_info['screen_name'];
}
}
unobscure($lastwall);
$status_info = array(
'text' => html2plain(prepare_text($lastwall['body'],$lastwall['mimetype']), 0),
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'id' => ($lastwall['id']),
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => '',
'favorited' => false,
'coordinates' => $lastwall['coord'],
'place' => $lastwall['location'],
'contributors' => ''
);
}
return $status_info;
}
function api_status_show(&$a, $type){
$user_info = api_get_user($a);
2013-01-17 03:18:10 +00:00
// get last public message
2013-01-21 02:36:33 +00:00
require_once('include/security.php');
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
2013-01-21 02:36:33 +00:00
2015-02-16 23:08:53 +00:00
$lastwall = q("SELECT * from item where
2015-06-10 23:59:04 +00:00
item_private = 0 $item_normal
2013-01-17 03:18:10 +00:00
and author_xchan = '%s'
and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = ''
and verb = '%s'
order by created desc limit 1",
dbesc($user_info['guid']),
dbesc(ACTIVITY_POST)
);
2013-01-17 03:18:10 +00:00
if($lastwall){
$lastwall = $lastwall[0];
$in_reply_to_status_id = '';
$in_reply_to_user_id = '';
$in_reply_to_screen_name = '';
2013-01-17 03:18:10 +00:00
if($lastwall['author_xchan'] != $lastwall['owner_xchan']) {
$w = q("select * from abook left join xchan on abook_xchan = xchan_hash where
xchan_hash = '%s' limit 1",
dbesc($lastwall['owner_xchan'])
);
if($w) {
$in_reply_to_user_id = $w[0]['abook_id'];
$in_reply_to_screen_name = substr($w[0]['xchan_addr'],0,strpos($w[0]['xchan_addr'],'@'));
}
}
if ($lastwall['parent']!=$lastwall['id']) {
2013-01-17 03:18:10 +00:00
$in_reply_to_status_id=$lastwall['thr_parent'];
if(! $in_reply_to_user_id) {
$in_reply_to_user_id = $user_info['id'];
$in_reply_to_screen_name = $user_info['screen_name'];
}
}
unobscure($lastwall);
$status_info = array(
'text' => html2plain(prepare_text($lastwall['body'],$lastwall['mimetype']), 0),
'truncated' => false,
'created_at' => api_date($lastwall['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
2013-11-27 00:38:48 +00:00
'id' => ($lastwall['id']),
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => '',
'favorited' => false,
'coordinates' => $lastwall['coord'],
'place' => $lastwall['location'],
'contributors' => ''
);
$status_info['user'] = $user_info;
}
return api_apply_template("status", $type, array('$status' => $status_info));
}
2011-02-16 07:56:47 +00:00
/**
* Returns extended information of a given user, specified by ID or screen name as per the required id parameter.
* The author's most recent status will be returned inline.
* http://developer.twitter.com/doc/get/users/show
*/
2013-01-17 03:18:10 +00:00
// FIXME - this is essentially the same as api_status_show except for the template formatting at the end. Consolidate.
2011-04-21 15:03:31 +00:00
function api_users_show(&$a, $type){
2011-02-16 07:56:47 +00:00
$user_info = api_get_user($a);
2013-01-17 03:18:10 +00:00
2013-01-21 02:36:33 +00:00
require_once('include/security.php');
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
2013-01-21 02:36:33 +00:00
2013-01-17 03:18:10 +00:00
$lastwall = q("SELECT * from item where 1
2015-06-10 23:59:04 +00:00
and item_private != 0 $item_normal
2013-01-17 03:18:10 +00:00
and author_xchan = '%s'
and allow_cid = '' and allow_gid = '' and deny_cid = '' and deny_gid = ''
and verb = '%s'
order by created desc limit 1",
dbesc($user_info['guid']),
dbesc(ACTIVITY_POST)
2011-02-15 11:24:21 +00:00
);
2011-02-16 07:56:47 +00:00
2013-01-17 03:18:10 +00:00
if($lastwall){
2011-04-21 15:03:31 +00:00
$lastwall = $lastwall[0];
$in_reply_to_status_id = '';
$in_reply_to_user_id = '';
$in_reply_to_screen_name = '';
2013-01-17 03:18:10 +00:00
if($lastwall['author_xchan'] != $lastwall['owner_xchan']) {
$w = q("select * from abook left join xchan on abook_xchan = xchan_hash where
xchan_hash = '%s' limit 1",
dbesc($lastwall['owner_xchan'])
);
if($w) {
$in_reply_to_user_id = $w[0]['abook_id'];
$in_reply_to_screen_name = substr($w[0]['xchan_addr'],0,strpos($w[0]['xchan_addr'],'@'));
}
}
2011-04-21 15:03:31 +00:00
if ($lastwall['parent']!=$lastwall['id']) {
2013-01-17 03:18:10 +00:00
$in_reply_to_status_id=$lastwall['thr_parent'];
if(! $in_reply_to_user_id) {
$in_reply_to_user_id = $user_info['id'];
$in_reply_to_screen_name = $user_info['screen_name'];
}
2011-04-21 15:03:31 +00:00
}
unobscure($lastwall);
2011-04-21 15:03:31 +00:00
$user_info['status'] = array(
'text' => html2plain(prepare_text($lastwall['body'],$lastwall['mimetype']), 0),
2011-04-21 15:03:31 +00:00
'truncated' => false,
2013-01-17 03:18:10 +00:00
'created_at' => api_date($lastwall['created']),
2011-04-21 15:03:31 +00:00
'in_reply_to_status_id' => $in_reply_to_status_id,
2013-01-17 03:18:10 +00:00
'source' => (($lastwall['app']) ? $lastwall['app'] : 'web'),
'id' => (($w) ? $w[0]['abook_id'] : $user_info['id']),
2011-04-21 15:03:31 +00:00
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => '',
2013-01-17 03:18:10 +00:00
'favorited' => false,
2011-04-21 15:03:31 +00:00
'coordinates' => $lastwall['coord'],
'place' => $lastwall['location'],
2013-01-17 03:18:10 +00:00
'contributors' => ''
2011-04-21 15:03:31 +00:00
);
2013-01-17 03:18:10 +00:00
2011-04-21 15:03:31 +00:00
}
return api_apply_template("user", $type, array('$user' => $user_info));
2011-02-15 11:24:21 +00:00
}
api_register_func('api/users/show','api_users_show');
2011-02-15 11:24:21 +00:00
/**
*
2011-02-15 11:24:21 +00:00
* http://developer.twitter.com/doc/get/statuses/home_timeline
*
2011-04-21 15:03:31 +00:00
* TODO: Optional parameters
* TODO: Add reply info
2011-02-15 11:24:21 +00:00
*/
2011-04-21 15:03:31 +00:00
function api_statuses_home_timeline(&$a, $type){
2013-01-19 14:08:13 +00:00
if (api_user() === false)
return false;
2011-02-16 07:56:47 +00:00
$user_info = api_get_user($a);
2013-01-19 14:08:13 +00:00
// get last network messages
2011-07-31 23:35:53 +00:00
2011-08-26 14:35:51 +00:00
// params
2013-01-19 14:08:13 +00:00
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if($page < 0)
$page = 0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
$exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$sql_extra = '';
2012-03-18 18:00:24 +00:00
if ($max_id > 0)
$sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
if ($exclude_replies > 0)
$sql_extra .= ' AND `item`.`parent` = `item`.`id`';
2012-03-18 18:00:24 +00:00
2013-01-20 23:36:04 +00:00
if (api_user() != $user_info['uid']) {
$observer = get_app()->get_observer();
require_once('include/permissions.php');
if(! perm_is_allowed($user_info['uid'],(($observer) ? $observer['xchan_hash'] : ''),'view_stream'))
return '';
$sql_extra .= " and item_private = 0 ";
}
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
$r = q("SELECT * from item WHERE uid = %d $item_normal
2011-07-31 23:35:53 +00:00
$sql_extra
2013-01-19 14:08:13 +00:00
AND id > %d
ORDER BY received DESC LIMIT %d ,%d ",
2011-07-31 23:35:53 +00:00
intval($user_info['uid']),
2011-08-19 18:33:34 +00:00
intval($since_id),
2013-01-19 14:08:13 +00:00
intval($start),
intval($count)
2011-07-31 23:35:53 +00:00
);
xchan_query($r,true);
2013-01-19 14:08:13 +00:00
2011-07-31 23:35:53 +00:00
$ret = api_format_items($r,$user_info);
// We aren't going to try to figure out at the item, group, and page
// level which items you've seen and which you haven't. If you're looking
// at the network timeline just mark everything seen.
2013-01-20 23:36:04 +00:00
if (api_user() == $user_info['uid']) {
$r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 and uid = %d",
2013-01-20 23:36:04 +00:00
intval($user_info['uid'])
);
}
2011-07-31 23:35:53 +00:00
$data = array('$statuses' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
break;
case "as":
$as = api_format_as($a, $ret, $user_info);
2012-04-08 18:19:14 +00:00
$as['title'] = $a->config['sitename']." Home Timeline";
$as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all";
return($as);
break;
2011-07-31 23:35:53 +00:00
}
2011-07-31 23:35:53 +00:00
return api_apply_template("timeline", $type, $data);
}
api_register_func('api/statuses/home_timeline','api_statuses_home_timeline', true);
api_register_func('api/statuses/friends_timeline','api_statuses_home_timeline', true);
2012-04-08 18:19:14 +00:00
function api_statuses_public_timeline(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
2012-04-08 18:19:14 +00:00
$user_info = api_get_user($a);
2015-04-20 01:57:12 +00:00
$sys = get_sys_channel();
2012-04-08 18:19:14 +00:00
// params
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if ($page<0) $page=0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
2012-04-08 18:19:14 +00:00
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
if ($max_id > 0)
$sql_extra = 'AND `item`.`id` <= '.intval($max_id);
require_once('include/security.php');
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
2012-04-08 18:19:14 +00:00
2015-06-10 23:59:04 +00:00
$r = q("select * from item where allow_cid = '' and allow_gid = ''
2013-01-19 14:08:13 +00:00
and deny_cid = '' and deny_gid = ''
and item_private = 0
2015-06-10 23:59:04 +00:00
$item_normal
2015-04-20 01:57:12 +00:00
and uid = " . $sys['channel_id'] . "
2012-04-08 18:19:14 +00:00
$sql_extra
AND id > %d group by mid
2015-08-19 05:14:16 +00:00
order by received desc LIMIT %d OFFSET %d ",
2012-04-08 18:19:14 +00:00
intval($since_id),
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
intval($count),
intval($start)
2013-01-19 14:08:13 +00:00
);
xchan_query($r,true);
2012-04-08 18:19:14 +00:00
$ret = api_format_items($r,$user_info);
2012-04-08 18:19:14 +00:00
$data = array('$statuses' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
break;
case "as":
$as = api_format_as($a, $ret, $user_info);
2013-01-19 14:08:13 +00:00
$as['title'] = $a->config['sitename']. " " . t('Public Timeline');
2012-04-08 18:19:14 +00:00
$as['link']['url'] = $a->get_baseurl()."/";
return($as);
break;
}
2012-04-08 18:19:14 +00:00
return api_apply_template("timeline", $type, $data);
}
api_register_func('api/statuses/public_timeline','api_statuses_public_timeline', true);
/**
*
2013-01-19 14:08:13 +00:00
*/
function api_statuses_show(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
$user_info = api_get_user($a);
// params
2013-01-19 14:08:13 +00:00
$id = intval(argv(3));
logger('API: api_statuses_show: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$conversation = (x($_REQUEST,'conversation')?1:0);
$sql_extra = '';
if ($conversation)
$sql_extra .= " AND `item`.`parent` = %d ORDER BY `received` ASC ";
else
$sql_extra .= " AND `item`.`id` = %d";
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
$r = q("select * from item where true $item_normal $sql_extra",
intval($id)
);
xchan_query($r,true);
$ret = api_format_items($r,$user_info);
if ($conversation) {
$data = array('$statuses' => $ret);
return api_apply_template("timeline", $type, $data);
} else {
$data = array('$status' => $ret[0]);
/*switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}*/
return api_apply_template("status", $type, $data);
}
}
api_register_func('api/statuses/show','api_statuses_show', true);
2011-07-31 23:35:53 +00:00
/**
*
*/
function api_statuses_repeat(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
$user_info = api_get_user($a);
// params
2013-01-21 02:36:33 +00:00
$id = intval(argv(3));
logger('API: api_statuses_repeat: '.$id);
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
2013-01-21 02:36:33 +00:00
$observer = get_app()->get_observer();
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
$r = q("SELECT * from item where and id = %d $item_normal limit 1",
intval($id)
);
2013-01-21 02:36:33 +00:00
if(perm_is_allowed($r[0]['uid'],$observer['xchan_hash'],'view_stream')) {
if ($r[0]['body'] != "") {
$_REQUEST['body'] = html_entity_decode("&#x2672; ", ENT_QUOTES, 'UTF-8')."[zrl=".$r[0]['reply_url']."]".$r[0]['reply_author']."[/zrl] \n".$r[0]['body'];
2013-01-21 02:36:33 +00:00
$_REQUEST['profile_uid'] = api_user();
$_REQUEST['type'] = 'wall';
$_REQUEST['api_source'] = true;
2013-01-21 02:36:33 +00:00
require_once('mod/item.php');
item_post($a);
}
}
2013-01-21 02:36:33 +00:00
else
return false;
if ($type == 'xml')
$ok = "true";
else
$ok = "ok";
return api_apply_template('test', $type, array('$ok' => $ok));
}
api_register_func('api/statuses/retweet','api_statuses_repeat', true);
/**
*
*/
2013-01-21 02:36:33 +00:00
function api_statuses_destroy(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
$user_info = api_get_user($a);
// params
2013-01-20 23:36:04 +00:00
$id = intval(argv(3));
if($id) {
// first prove that we own the item
$r = q("select * from item where id = %d and uid = %d limit 1",
intval($id),
intval($user_info['uid'])
);
if(! $r)
return false;
}
else {
if($_REQUEST['namespace'] && $_REQUEST['remote_id']) {
$r = q("select * from item_id where service = '%s' and sid = '%s' and uid = %d limit 1",
dbesc($_REQUEST['namespace']),
dbesc($_REQUEST['remote_id']),
intval($user_info['uid'])
);
if(! $r)
return false;
$id = $r[0]['iid'];
}
if($_REQUEST['namespace'] && $_REQUEST['comment_id']) {
$r = q("select * from item_id left join item on item.id = item_id.iid where service = '%s' and sid = '%s' and uid = %d and item.id != item.parent limit 1",
dbesc($_REQUEST['namespace']),
dbesc($_REQUEST['comment_id']),
intval($user_info['uid'])
);
if(! $r)
return false;
$id = $r[0]['iid'];
}
}
if(! $id)
return false;
2013-11-27 00:38:48 +00:00
logger('API: api_statuses_destroy: '.$id);
require_once('include/items.php');
drop_item($id, false);
if ($type == 'xml')
$ok = "true";
else
$ok = "ok";
return api_apply_template('test', $type, array('$ok' => $ok));
}
api_register_func('api/statuses/destroy','api_statuses_destroy', true);
/**
*
* http://developer.twitter.com/doc/get/statuses/mentions
*
*/
2013-01-20 23:36:04 +00:00
function api_statuses_mentions(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
$user_info = api_get_user($a);
// get last network messages
// params
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if ($page<0) $page=0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
$myurl = $a->get_baseurl() . '/channel/'. $a->user['nickname'];
$myurl = substr($myurl,strpos($myurl,'://')+3);
$myurl = str_replace(array('www.','.'),array('','\\.'),$myurl);
$diasp_url = str_replace('/channel/','/u/',$myurl);
$sql_extra .= " AND item_mentionsme = 1 ";
if ($max_id > 0)
$sql_extra .= " AND item.id <= " . intval($max_id) . " ";
require_once('include/security.php');
$item_normal = item_normal();
$r = q("select * from item where uid = " . intval(api_user()) . "
$item_normal $sql_extra
AND id > %d group by mid
order by received desc LIMIT %d OFFSET %d ",
intval($since_id),
intval($count),
intval($start)
);
xchan_query($r,true);
$ret = api_format_items($r,$user_info);
$data = array('$statuses' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
break;
case "as":
$as = api_format_as($a, $ret, $user_info);
$as["title"] = $a->config['sitename']." Mentions";
2012-04-08 18:19:14 +00:00
$as['link']['url'] = $a->get_baseurl()."/";
return($as);
break;
}
return api_apply_template("timeline", $type, $data);
}
api_register_func('api/statuses/mentions','api_statuses_mentions', true);
2013-01-20 23:36:04 +00:00
// FIXME?? I don't think mentions and replies are congruent in this case
api_register_func('api/statuses/replies','api_statuses_mentions', true);
2012-03-18 18:00:24 +00:00
2011-07-31 23:35:53 +00:00
function api_statuses_user_timeline(&$a, $type){
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
2011-07-31 23:35:53 +00:00
$user_info = api_get_user($a);
2013-01-20 23:36:04 +00:00
// get last network messages
2011-07-31 23:35:53 +00:00
2011-08-26 14:35:51 +00:00
2013-01-16 23:51:21 +00:00
logger("api_statuses_user_timeline: api_user: ". api_user() .
2011-08-26 14:35:51 +00:00
"\nuser_info: ".print_r($user_info, true) .
"\n_REQUEST: ".print_r($_REQUEST, true),
LOGGER_DEBUG);
// params
2011-08-19 18:33:34 +00:00
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if ($page<0) $page=0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
//$since_id = 0;//$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$start = $page*$count;
$sql_extra = '';
if ($user_info['self']==1) $sql_extra .= " AND `item`.`wall` = 1 ";
2014-01-25 23:51:10 +00:00
//FIXME - this isn't yet implemented
if ($exclude_replies > 0) $sql_extra .= ' AND `item`.`parent` = `item`.`id`';
2014-01-25 02:50:47 +00:00
// $r = q("SELECT `item`.*, `item`.`id` AS `item_id`,
// `contact`.`name`, `contact`.`photo`, `contact`.`url`, `contact`.`rel`,
// `contact`.`network`, `contact`.`thumb`, `contact`.`dfrn_id`, `contact`.`self`,
// `contact`.`id` AS `cid`, `contact`.`uid` AS `contact-uid`
// FROM `item`, `contact`
// WHERE `item`.`uid` = %d
// AND `item`.`contact-id` = %d
// AND `item`.`visible` = 1 and `item`.`moderated` = 0 AND `item`.`deleted` = 0
// AND `contact`.`id` = `item`.`contact-id`
// AND `contact`.`blocked` = 0 AND `contact`.`pending` = 0
// $sql_extra
// AND `item`.`id`>%d
// ORDER BY `item`.`received` DESC LIMIT %d ,%d ",
// intval(api_user()),
// intval($user_info['id']),
// intval($since_id),
// intval($start), intval($count)
// );
2014-01-25 23:51:10 +00:00
$arr = array(
2015-08-19 05:14:16 +00:00
'uid' => api_user(),
'since_id' => $since_id,
'start' => $start,
'records' => $count);
2014-01-25 23:51:10 +00:00
if ($user_info['self']==1)
$arr['wall'] = 1;
else
$arr['cid'] = $user_info['id'];
$r = items_fetch($arr,get_app()->get_channel(),get_observer_hash());
2015-08-19 05:14:16 +00:00
2011-07-31 23:35:53 +00:00
$ret = api_format_items($r,$user_info);
2011-07-31 23:35:53 +00:00
$data = array('$statuses' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}
2011-07-31 23:35:53 +00:00
return api_apply_template("timeline", $type, $data);
}
api_register_func('api/statuses/user_timeline','api_statuses_user_timeline', true);
2015-08-19 05:14:16 +00:00
/**
* Star/unstar an item
* param: id : id of the item
*
* api v1 : https://web.archive.org/web/20131019055350/https://dev.twitter.com/docs/api/1/post/favorites/create/%3Aid
*/
function api_favorites_create_destroy(&$a, $type){
logger('favorites_create_destroy');
2015-08-19 05:14:16 +00:00
if (api_user()===false)
return false;
2015-08-19 05:14:16 +00:00
$action = str_replace(".".$type,"",argv(2));
if (argc() > 3) {
$itemid = intval(argv(3));
} else {
$itemid = intval($_REQUEST['id']);
}
$item = q("SELECT * FROM item WHERE id = %d AND uid = %d",
intval($itemid),
intval(api_user())
);
2015-08-19 05:14:16 +00:00
if (! $item)
return false;
switch($action){
case "create":
$flags = $item[0]['item_starred'] = 1;
break;
case "destroy":
$flags = $item[0]['item_starred'] = 0;
break;
default:
return false;
}
$r = q("UPDATE item SET item_starred = %d where id = %d and uid = %d",
intval($flags),
intval($itemid),
intval(api_user())
);
if(! $r)
return false;
$item = q("SELECT * FROM item WHERE id = %d AND uid = %d",
intval($itemid),
intval(api_user())
);
xchan_query($item,true);
2015-08-19 05:14:16 +00:00
$user_info = api_get_user($a);
$rets = api_format_items($item,$user_info);
$ret = $rets[0];
2015-08-19 05:14:16 +00:00
$data = array('$status' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}
2015-08-19 05:14:16 +00:00
return api_apply_template("status", $type, $data);
}
2015-08-19 05:14:16 +00:00
api_register_func('api/favorites/create', 'api_favorites_create_destroy', true);
api_register_func('api/favorites/destroy', 'api_favorites_create_destroy', true);
2011-07-31 23:35:53 +00:00
function api_favorites(&$a, $type){
if (api_user()===false)
return false;
2011-07-31 23:35:53 +00:00
$user_info = api_get_user($a);
// params
2015-08-19 05:14:16 +00:00
$count = (x($_REQUEST,'count')?$_REQUEST['count']:20);
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if($page < 0)
$page = 0;
$since_id = (x($_REQUEST,'since_id')?$_REQUEST['since_id']:0);
$max_id = (x($_REQUEST,'max_id')?$_REQUEST['max_id']:0);
$exclude_replies = (x($_REQUEST,'exclude_replies')?1:0);
$start = $page*$count;
//$include_entities = (x($_REQUEST,'include_entities')?$_REQUEST['include_entities']:false);
2011-07-31 23:35:53 +00:00
$sql_extra = '';
if ($max_id > 0)
$sql_extra .= ' AND `item`.`id` <= '.intval($max_id);
if ($exclude_replies > 0)
$sql_extra .= ' AND `item`.`parent` = `item`.`id`';
if (api_user() != $user_info['uid']) {
$observer = get_app()->get_observer();
require_once('include/permissions.php');
if(! perm_is_allowed($user_info['uid'],(($observer) ? $observer['xchan_hash'] : ''),'view_stream'))
return '';
$sql_extra .= " and item_private = 0 ";
2011-08-26 14:35:51 +00:00
}
2015-06-10 23:59:04 +00:00
$item_normal = item_normal();
$r = q("SELECT * from item WHERE uid = %d $item_normal
and item_starred = 1 $sql_extra
AND id > %d
ORDER BY received DESC LIMIT %d ,%d ",
intval($user_info['uid']),
intval($since_id),
intval($start),
intval($count)
);
xchan_query($r,true);
$ret = api_format_items($r,$user_info);
2011-07-31 23:35:53 +00:00
$data = array('$statuses' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
break;
case "as":
$as = api_format_as($a, $ret, $user_info);
$as['title'] = $a->config['sitename']." Home Timeline";
$as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all";
return($as);
break;
2011-07-31 23:35:53 +00:00
}
2011-07-31 23:35:53 +00:00
return api_apply_template("timeline", $type, $data);
2011-07-31 23:35:53 +00:00
}
api_register_func('api/favorites','api_favorites', true);
function api_format_as($a, $ret, $user_info) {
$as = array();
$as['title'] = $a->config['sitename']." Public Timeline";
$items = array();
foreach ($ret as $item) {
$singleitem["actor"]["displayName"] = $item["user"]["name"];
$singleitem["actor"]["id"] = $item["user"]["contact_url"];
$avatar[0]["url"] = $item["user"]["profile_image_url"];
$avatar[0]["rel"] = "avatar";
$avatar[0]["type"] = "";
$avatar[0]["width"] = 96;
$avatar[0]["height"] = 96;
$avatar[1]["url"] = $item["user"]["profile_image_url"];
$avatar[1]["rel"] = "avatar";
$avatar[1]["type"] = "";
$avatar[1]["width"] = 48;
$avatar[1]["height"] = 48;
$avatar[2]["url"] = $item["user"]["profile_image_url"];
$avatar[2]["rel"] = "avatar";
$avatar[2]["type"] = "";
$avatar[2]["width"] = 24;
$avatar[2]["height"] = 24;
$singleitem["actor"]["avatarLinks"] = $avatar;
$singleitem["actor"]["image"]["url"] = $item["user"]["profile_image_url"];
$singleitem["actor"]["image"]["rel"] = "avatar";
$singleitem["actor"]["image"]["type"] = "";
$singleitem["actor"]["image"]["width"] = 96;
$singleitem["actor"]["image"]["height"] = 96;
$singleitem["actor"]["type"] = "person";
$singleitem["actor"]["url"] = $item["person"]["contact_url"];
$singleitem["actor"]["statusnet:profile_info"]["local_id"] = $item["user"]["id"];
$singleitem["actor"]["statusnet:profile_info"]["following"] = $item["user"]["following"] ? "true" : "false";
$singleitem["actor"]["statusnet:profile_info"]["blocking"] = "false";
$singleitem["actor"]["contact"]["preferredUsername"] = $item["user"]["screen_name"];
$singleitem["actor"]["contact"]["displayName"] = $item["user"]["name"];
$singleitem["actor"]["contact"]["addresses"] = "";
$singleitem["body"] = $item["text"];
$singleitem["object"]["displayName"] = $item["text"];
$singleitem["object"]["id"] = $item["url"];
$singleitem["object"]["type"] = "note";
$singleitem["object"]["url"] = $item["url"];
//$singleitem["context"] =;
$singleitem["postedTime"] = date("c", strtotime($item["published"]));
$singleitem["provider"]["objectType"] = "service";
$singleitem["provider"]["displayName"] = "Test";
$singleitem["provider"]["url"] = "http://test.tld";
$singleitem["title"] = $item["text"];
$singleitem["verb"] = "post";
$singleitem["statusnet:notice_info"]["local_id"] = $item["id"];
$singleitem["statusnet:notice_info"]["source"] = $item["source"];
$singleitem["statusnet:notice_info"]["favorite"] = "false";
$singleitem["statusnet:notice_info"]["repeated"] = "false";
//$singleitem["original"] = $item;
$items[] = $singleitem;
}
$as['items'] = $items;
2012-04-08 18:19:14 +00:00
$as['link']['url'] = $a->get_baseurl()."/".$user_info["screen_name"]."/all";
$as['link']['rel'] = "alternate";
$as['link']['type'] = "text/html";
return($as);
}
2015-04-19 20:41:12 +00:00
function api_format_message($item, $recipient, $sender) {
// standard meta information
2013-01-19 14:08:13 +00:00
$ret = array(
'id' => $item['id'],
'created_at' => api_date($item['created']),
'sender_id' => $sender['id'] ,
'sender_screen_name' => $sender['screen_name'],
'sender' => $sender,
'recipient_id' => $recipient['id'],
'recipient_screen_name' => $recipient['screen_name'],
'recipient' => $recipient,
);
2015-04-19 20:41:12 +00:00
unobscure_mail($item);
//don't send title to regular StatusNET requests to avoid confusing these apps
if (x($_GET, 'getText')) {
$ret['title'] = $item['title'] ;
if ($_GET["getText"] == "html") {
$ret['text'] = prepare_text($item['body'],$item['mimetype']);
}
elseif ($_GET["getText"] == "plain") {
$ret['text'] = html2plain(prepare_text($item['body'],$item['mimetype']), 0);
}
}
else {
$ret['text'] = $item['title']."\n".html2plain(prepare_text($item['body'],$item['mimetype']), 0);
}
if (isset($_GET["getUserObjects"]) && $_GET["getUserObjects"] == "false") {
unset($ret['sender']);
unset($ret['recipient']);
}
return $ret;
}
2011-07-31 23:35:53 +00:00
function api_format_items($r,$user_info) {
2011-08-01 03:01:00 +00:00
//logger('api_format_items: ' . print_r($r,true));
//logger('api_format_items: ' . print_r($user_info,true));
2011-07-31 23:35:53 +00:00
$a = get_app();
2013-01-19 14:08:13 +00:00
$ret = array();
2011-02-15 11:24:21 +00:00
2014-08-15 00:55:14 +00:00
if(! $r)
return $ret;
2011-02-16 07:56:47 +00:00
foreach($r as $item) {
2011-08-26 14:35:51 +00:00
localize_item($item);
$status_user = (($item['author_xchan']==$user_info['guid'])?$user_info: api_item_get_user($a,$item));
2015-04-20 00:39:17 +00:00
if(array_key_exists('status',$status_user))
unset($status_user['status']);
2013-01-19 14:08:13 +00:00
if($item['parent'] != $item['id']) {
$r = q("select id from item where parent= %d and id < %d order by id desc limit 1",
intval($item['parent']),
intval($item['id'])
);
2012-03-18 17:21:51 +00:00
if ($r)
$in_reply_to_status_id = $r[0]['id'];
else
$in_reply_to_status_id = $item['parent'];
xchan_query($r,true);
2013-01-19 14:08:13 +00:00
$in_reply_to_screen_name = $r[0]['author']['xchan_name'];
$in_reply_to_user_id = $r[0]['author']['abook_id'];
2012-03-18 17:21:51 +00:00
} else {
$in_reply_to_screen_name = '';
$in_reply_to_user_id = 0;
2012-03-18 17:21:51 +00:00
$in_reply_to_status_id = 0;
}
unobscure($item);
// Workaround for ostatus messages where the title is identically to the body
$statusbody = trim(html2plain(prepare_text($item['body'],$item['mimetype']), 0));
$statustitle = trim($item['title']);
if (($statustitle != '') and (strpos($statusbody, $statustitle) !== false))
$statustext = trim($statusbody);
else
$statustext = trim($statustitle."\n\n".$statusbody);
2011-04-21 15:03:31 +00:00
$status = array(
2013-01-19 14:08:13 +00:00
'text' => $statustext,
'truncated' => False,
'created_at' => api_date($item['created']),
'in_reply_to_status_id' => $in_reply_to_status_id,
'source' => (($item['app']) ? $item['app'] : 'web'),
'id' => intval($item['id']),
'in_reply_to_user_id' => $in_reply_to_user_id,
'in_reply_to_screen_name' => $in_reply_to_screen_name,
'geo' => '',
'favorited' => (intval($item['item_starred']) ? true : false),
2013-01-19 14:08:13 +00:00
'user' => $status_user ,
2014-03-16 22:20:04 +00:00
'statusnet_html' => trim(prepare_text($item['body'],$item['mimetype'])),
'statusnet_conversation_id' => $item['parent'],
2011-04-21 15:03:31 +00:00
);
// Seesmic doesn't like the following content
if ($_SERVER['HTTP_USER_AGENT'] != 'Seesmic') {
$status2 = array(
2013-01-19 14:08:13 +00:00
'updated' => api_date($item['edited']),
'published' => api_date($item['created']),
'message_id' => $item['mid'],
2013-01-19 14:08:13 +00:00
'url' => $item['plink'],
'coordinates' => $item['coord'],
'place' => $item['location'],
'contributors' => '',
'annotations' => '',
2013-01-19 14:08:13 +00:00
'entities' => '',
'objecttype' => (($item['obj_type']) ? $item['obj_type'] : ACTIVITY_OBJ_NOTE),
'verb' => (($item['verb']) ? $item['verb'] : ACTIVITY_POST),
'self' => $a->get_baseurl()."/api/statuses/show/".$item['id'].".".$type,
'edit' => $a->get_baseurl()."/api/statuses/show/".$item['id'].".".$type,
);
$status = array_merge($status, $status2);
}
2011-02-15 11:24:21 +00:00
$ret[]=$status;
};
2011-07-31 23:35:53 +00:00
return $ret;
2011-02-16 07:56:47 +00:00
}
2011-07-31 23:35:53 +00:00
2011-06-21 00:16:13 +00:00
function api_account_rate_limit_status(&$a,$type) {
$hash = array(
'reset_time_in_seconds' => strtotime('now + 1 hour'),
2011-06-21 00:16:13 +00:00
'remaining_hits' => (string) 150,
'hourly_limit' => (string) 150,
'reset_time' => datetime_convert('UTC','UTC','now + 1 hour',ATOM_TIME),
);
if ($type == "xml")
$hash['resettime_in_seconds'] = $hash['reset_time_in_seconds'];
2011-06-21 00:16:13 +00:00
return api_apply_template('ratelimit', $type, array('$hash' => $hash));
}
api_register_func('api/account/rate_limit_status','api_account_rate_limit_status',true);
2011-07-29 04:56:56 +00:00
function api_help_test(&$a,$type) {
if ($type == 'xml')
$ok = "true";
else
$ok = "ok";
return api_apply_template('test', $type, array('$ok' => $ok));
}
2013-03-11 01:45:58 +00:00
api_register_func('api/help/test','api_help_test',false);
/**
* https://dev.twitter.com/docs/api/1/get/statuses/friends
* This function is deprecated by Twitter
* returns: json, xml
**/
function api_statuses_f(&$a, $type, $qtype) {
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
$user_info = api_get_user($a);
2011-08-26 14:35:51 +00:00
// friends and followers only for self
if ($user_info['self']==0){
return false;
}
if (x($_GET,'cursor') && $_GET['cursor']=='undefined'){
/* this is to stop Hotot to load friends multiple times
* I'm not sure if I'm missing return something or
* is a bug in hotot. Workaround, meantime
*/
2011-08-26 14:35:51 +00:00
/*$ret=Array();
return array('$users' => $ret);*/
return false;
}
2013-01-21 02:36:33 +00:00
// For Red, the closest thing we can do to figure out if you're friends is if both of you are sending each other your streams.
// This won't work if either of you send your stream to everybody on the network
if($qtype == 'friends')
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = sprintf(" AND ( abook_their_perms & %d )>0 and ( abook_my_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM));
if($qtype == 'followers')
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = sprintf(" AND ( abook_my_perms & %d )>0 and not ( abook_their_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM));
2015-06-15 04:08:00 +00:00
$r = q("SELECT abook_id FROM abook where abook_self = 0 and abook_channel = %d $sql_extra",
2013-01-16 23:51:21 +00:00
intval(api_user())
);
$ret = array();
foreach($r as $cid){
$ret[] = api_get_user($a, $cid['abook_id']);
}
2011-08-26 14:35:51 +00:00
return array('$users' => $ret);
}
function api_statuses_friends(&$a, $type){
2011-08-26 14:35:51 +00:00
$data = api_statuses_f($a,$type,"friends");
if ($data===false) return false;
return api_apply_template("friends", $type, $data);
}
function api_statuses_followers(&$a, $type){
2011-08-26 14:35:51 +00:00
$data = api_statuses_f($a,$type,"followers");
if ($data===false) return false;
return api_apply_template("friends", $type, $data);
}
api_register_func('api/statuses/friends','api_statuses_friends',true);
api_register_func('api/statuses/followers','api_statuses_followers',true);
2011-07-29 04:56:56 +00:00
function api_statusnet_config(&$a,$type) {
2013-01-16 23:51:21 +00:00
load_config('system');
$name = get_config('system','sitename');
2011-07-29 04:56:56 +00:00
$server = $a->get_hostname();
2013-11-23 19:01:11 +00:00
$logo = $a->get_baseurl() . '/images/rm-64.png';
2013-01-16 23:51:21 +00:00
$email = get_config('system','admin_email');
$closed = ((get_config('system','register_policy') == REGISTER_CLOSED) ? 'true' : 'false');
$private = ((get_config('system','block_public')) ? 'true' : 'false');
$textlimit = (string) ((get_config('system','max_import_size')) ? get_config('system','max_import_size') : 200000);
if(get_config('system','api_import_size'))
$texlimit = string(get_config('system','api_import_size'));
$ssl = ((get_config('system','have_ssl')) ? 'true' : 'false');
2011-07-29 04:56:56 +00:00
$sslserver = (($ssl === 'true') ? str_replace('http:','https:',$a->get_baseurl()) : '');
$config = array(
'site' => array('name' => $name,'server' => $server, 'theme' => 'default', 'path' => '',
2013-01-16 23:51:21 +00:00
'logo' => $logo, 'fancy' => 'true', 'language' => 'en', 'email' => $email, 'broughtby' => '',
'broughtbyurl' => '', 'timezone' => 'UTC', 'closed' => $closed, 'inviteonly' => 'false',
'private' => $private, 'textlimit' => $textlimit, 'sslserver' => $sslserver, 'ssl' => $ssl,
'shorturllength' => '30',
2015-05-05 10:56:10 +00:00
'hubzilla' => array(
'PLATFORM_NAME' => PLATFORM_NAME,
2013-04-15 05:24:47 +00:00
'RED_VERSION' => RED_VERSION,
2013-01-16 23:51:21 +00:00
'ZOT_REVISION' => ZOT_REVISION,
'DB_UPDATE_VERSION' => DB_UPDATE_VERSION
)
));
2011-07-29 04:56:56 +00:00
return api_apply_template('config', $type, array('$config' => $config));
}
api_register_func('api/statusnet/config','api_statusnet_config',false);
2013-01-16 23:51:21 +00:00
api_register_func('api/friendica/config','api_statusnet_config',false);
api_register_func('api/red/config','api_statusnet_config',false);
2011-07-29 04:56:56 +00:00
2011-07-30 01:21:54 +00:00
function api_statusnet_version(&$a,$type) {
// liar
if($type === 'xml') {
header("Content-type: application/xml");
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>0.9.7</version>' . "\r\n";
killme();
}
elseif($type === 'json') {
header("Content-type: application/json");
echo '"0.9.7"';
killme();
}
}
api_register_func('api/statusnet/version','api_statusnet_version',false);
2011-08-01 05:22:34 +00:00
2013-01-16 23:51:21 +00:00
function api_friendica_version(&$a,$type) {
if($type === 'xml') {
header("Content-type: application/xml");
2013-04-15 05:24:47 +00:00
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<version>' . RED_VERSION . '</version>' . "\r\n";
2013-01-16 23:51:21 +00:00
killme();
}
elseif($type === 'json') {
header("Content-type: application/json");
2013-04-15 05:24:47 +00:00
echo '"' . RED_VERSION . '"';
2013-01-16 23:51:21 +00:00
killme();
}
}
api_register_func('api/friendica/version','api_friendica_version',false);
api_register_func('api/red/version','api_friendica_version',false);
2011-08-01 05:22:34 +00:00
function api_ff_ids(&$a,$type,$qtype) {
2013-01-16 23:51:21 +00:00
if(! api_user())
2011-08-01 05:22:34 +00:00
return false;
2013-01-21 02:36:33 +00:00
// For Red, the closest thing we can do to figure out if you're friends is if both of you are sending each other your streams.
// This won't work if either of you send your stream to everybody on the network
2011-08-01 05:22:34 +00:00
if($qtype == 'friends')
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = sprintf(" AND ( abook_their_perms & %d )>0 and ( abook_my_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM));
2011-08-01 05:22:34 +00:00
if($qtype == 'followers')
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
$sql_extra = sprintf(" AND ( abook_my_perms & %d )>0 and not ( abook_their_perms & %d )>0 ", intval(PERMS_W_STREAM), intval(PERMS_W_STREAM));
2011-08-01 05:22:34 +00:00
2015-06-15 04:08:00 +00:00
$r = q("SELECT abook_id FROM abook where abook_self = 0 and abook_channel = %d $sql_extra",
2013-01-16 23:51:21 +00:00
intval(api_user())
2011-08-01 05:22:34 +00:00
);
if(is_array($r)) {
if($type === 'xml') {
header("Content-type: application/xml");
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\r\n" . '<ids>' . "\r\n";
foreach($r as $rr)
echo '<id>' . $rr['abook_id'] . '</id>' . "\r\n";
2011-08-01 05:22:34 +00:00
echo '</ids>' . "\r\n";
killme();
}
elseif($type === 'json') {
$ret = array();
header("Content-type: application/json");
foreach($r as $rr) $ret[] = $rr['abook_id'];
2011-08-01 05:22:34 +00:00
echo json_encode($ret);
killme();
}
}
}
function api_friends_ids(&$a,$type) {
api_ff_ids($a,$type,'friends');
}
function api_followers_ids(&$a,$type) {
api_ff_ids($a,$type,'followers');
}
api_register_func('api/friends/ids','api_friends_ids',true);
api_register_func('api/followers/ids','api_followers_ids',true);
2011-08-19 14:55:43 +00:00
function api_direct_messages_new(&$a, $type) {
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
2011-08-19 14:55:43 +00:00
if (!x($_POST, "text") || !x($_POST,"screen_name")) return;
2011-08-19 14:55:43 +00:00
$sender = api_get_user($a);
require_once("include/message.php");
// in a decentralised world the screen name is ambiguous
$r = q("SELECT `abook_id` FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel`=%d and xchan_addr like '%s'",
intval(api_user()),
dbesc($_POST['screen_name'] . '@%')
);
$recipient = api_get_user($a, $r[0]['abook_id']);
$replyto = '';
$sub = '';
if (x($_REQUEST,'replyto')) {
$r = q('SELECT `parent_mid`, `title` FROM `mail` WHERE `uid`=%d AND `id`=%d',
2013-01-16 23:51:21 +00:00
intval(api_user()),
intval($_REQUEST['replyto']));
$replyto = $r[0]['parent_mid'];
$sub = $r[0]['title'];
}
else {
if (x($_REQUEST,'title')) {
$sub = $_REQUEST['title'];
}
else {
$sub = ((strlen($_POST['text'])>10)?substr($_POST['text'],0,10)."...":$_POST['text']);
}
}
$id = send_message(api_user(),$recipient['guid'], $_POST['text'], $sub, $replyto);
2011-08-19 14:55:43 +00:00
if ($id>-1) {
$r = q("SELECT * FROM `mail` WHERE id=%d", intval($id));
2015-04-19 20:41:12 +00:00
$ret = api_format_message($r[0], $recipient, $sender);
2011-08-19 14:55:43 +00:00
} else {
$ret = array("error"=>$id);
}
$data = Array('$messages'=>$ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}
return api_apply_template("direct_messages", $type, $data);
}
api_register_func('api/direct_messages/new','api_direct_messages_new',true);
function api_direct_messages_box(&$a, $type, $box) {
2013-01-16 23:51:21 +00:00
if (api_user()===false) return false;
2011-08-19 14:55:43 +00:00
$user_info = api_get_user($a);
// params
$count = (x($_GET,'count')?$_GET['count']:20);
2011-08-19 18:33:34 +00:00
$page = (x($_REQUEST,'page')?$_REQUEST['page']-1:0);
if ($page<0) $page=0;
2011-08-19 14:55:43 +00:00
$start = $page*$count;
$channel = $a->get_channel();
$profile_url = $a->get_baseurl() . '/channel/' . $channel['channel_address'];
2011-08-19 14:55:43 +00:00
if ($box=="sentbox") {
$sql_extra = "`from_xchan`='".dbesc( $channel['channel_hash'] )."'";
}
elseif ($box=="conversation") {
$sql_extra = "`parent_mid`='".dbesc( $_GET["uri"] ) ."'";
}
elseif ($box=="all") {
$sql_extra = "true";
}
elseif ($box=="inbox") {
$sql_extra = "`from_xchan`!='".dbesc( $channel['channel_hash'] )."'";
2011-08-19 14:55:43 +00:00
}
$r = q("SELECT * FROM `mail` WHERE channel_id = %d AND $sql_extra ORDER BY created DESC LIMIT %d OFFSET %d",
2013-01-16 23:51:21 +00:00
intval(api_user()),
PostgreSQL support initial commit There were 11 main types of changes: - UPDATE's and DELETE's sometimes had LIMIT 1 at the end of them. This is not only non-compliant but it would certainly not do what whoever wrote it thought it would. It is likely this mistake was just copied from Friendica. All of these instances, the LIMIT 1 was simply removed. - Bitwise operations (and even some non-zero int checks) erroneously rely on MySQL implicit integer-boolean conversion in the WHERE clauses. This is non-compliant (and bad programming practice to boot). Proper explicit boolean conversions were added. New queries should use proper conventions. - MySQL has a different operator for bitwise XOR than postgres. Rather than add yet another dba_ func, I converted them to "& ~" ("AND NOT") when turning off, and "|" ("OR") when turning on. There were no true toggles (XOR). New queries should refrain from using XOR when not necessary. - There are several fields which the schema has marked as NOT NULL, but the inserts don't specify them. The reason this works is because mysql totally ignores the constraint and adds an empty text default automatically. Again, non-compliant, obviously. In these cases a default of empty text was added. - Several statements rely on a non-standard MySQL feature (http://dev.mysql.com/doc/refman/5.5/en/group-by-handling.html). These queries can all be rewritten to be standards compliant. Interestingly enough, the newly rewritten standards compliant queries run a zillion times faster, even on MySQL. - A couple of function/operator name translations were needed (RAND/RANDOM, GROUP_CONCAT/STRING_AGG, UTC_NOW, REGEXP/~, ^/#) -- assist functions added in the dba_ - INTERVALs: postgres requires quotes around the value, mysql requires that there are not quotes around the value -- assist functions added in the dba_ - NULL_DATE's -- Postgres does not allow the invalid date '0000-00-00 00:00:00' (there is no such thing as year 0 or month 0 or day 0). We use '0001-01-01 00:00:00' for postgres. Conversions are handled in Zot/item packets automagically by quoting all dates with dbescdate(). - char(##) specifications in the schema creates fields with blank spaces that aren't trimmed in the code. MySQL apparently treats char(##) as varchar(##), again, non-compliant. Since postgres works better with text fields anyway, this ball of bugs was simply side-stepped by using 'text' datatype for all text fields in the postgres schema. varchar was used in a couple of places where it actually seemed appropriate (size constraint), but without rigorously vetting that all of the PHP code actually validates data, new bugs might come out from under the rug. - postgres doesn't store nul bytes and a few other non-printables in text fields, even when quoted. bytea fields were used when storing binary data (photo.data, attach.data). A new dbescbin() function was added to handle this transparently. - postgres does not support LIMIT #,# syntax. All databases support LIMIT # OFFSET # syntax. Statements were updated to be standard. These changes require corresponding changes in the coding standards. Please review those before adding any code going forward. Still on my TODO list: - remove quotes from non-reserved identifiers and make reserved identifiers use dba func for quoting - Rewrite search queries for better results (both MySQL and Postgres)
2014-11-13 20:21:58 +00:00
intval($count), intval($start)
2012-06-23 17:21:48 +00:00
);
2011-08-19 14:55:43 +00:00
$ret = Array();
2014-08-15 00:55:14 +00:00
if($r) {
foreach($r as $item) {
2015-04-20 01:14:17 +00:00
if ($item['from_xchan'] == $channel['channel_hash']) {
2014-08-15 00:55:14 +00:00
$sender = $user_info;
2015-04-20 01:14:17 +00:00
$recipient = api_get_user($a, null, $item['to_xchan']);
}
else {
$sender = api_get_user($a, null, $item['from_xchan']);
$recipient = $user_info;
2014-08-15 00:55:14 +00:00
}
2015-04-19 20:41:12 +00:00
$ret[]=api_format_message($item, $recipient, $sender);
}
2011-08-19 14:55:43 +00:00
}
$data = array('$messages' => $ret);
switch($type){
case "atom":
case "rss":
$data = api_rss_extra($a, $data, $user_info);
}
return api_apply_template("direct_messages", $type, $data);
}
function api_direct_messages_sentbox(&$a, $type){
return api_direct_messages_box($a, $type, "sentbox");
}
function api_direct_messages_inbox(&$a, $type){
return api_direct_messages_box($a, $type, "inbox");
}
2012-06-23 17:21:48 +00:00
function api_direct_messages_all(&$a, $type){
return api_direct_messages_box($a, $type, "all");
}
function api_direct_messages_conversation(&$a, $type){
return api_direct_messages_box($a, $type, "conversation");
}
api_register_func('api/direct_messages/conversation','api_direct_messages_conversation',true);
api_register_func('api/direct_messages/all','api_direct_messages_all',true);
2011-08-19 14:55:43 +00:00
api_register_func('api/direct_messages/sent','api_direct_messages_sentbox',true);
api_register_func('api/direct_messages','api_direct_messages_inbox',true);
2011-10-20 13:57:35 +00:00
function api_oauth_request_token(&$a, $type){
try{
$oauth = new FKOAuth1();
$req = OAuthRequest::from_request();
logger('Req: ' . var_export($req,true));
$r = $oauth->fetch_request_token($req);
2011-10-20 13:57:35 +00:00
}catch(Exception $e){
logger('oauth_exception: ' . print_r($e->getMessage(),true));
echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage());
killme();
2011-10-20 13:57:35 +00:00
}
2011-11-07 16:36:58 +00:00
echo $r;
2011-10-20 13:57:35 +00:00
killme();
}
function api_oauth_access_token(&$a, $type){
try{
$oauth = new FKOAuth1();
$req = OAuthRequest::from_request();
$r = $oauth->fetch_access_token($req);
2011-10-20 13:57:35 +00:00
}catch(Exception $e){
echo "error=". OAuthUtil::urlencode_rfc3986($e->getMessage()); killme();
}
2011-11-07 16:36:58 +00:00
echo $r;
2011-10-20 13:57:35 +00:00
killme();
}
2011-10-26 15:15:36 +00:00
2011-10-20 13:57:35 +00:00
api_register_func('api/oauth/request_token', 'api_oauth_request_token', false);
api_register_func('api/oauth/access_token', 'api_oauth_access_token', false);
2011-10-26 15:15:36 +00:00
/*
Not implemented by now:
statuses/retweets_of_me
friendships/create
friendships/destroy
friendships/exists
friendships/show
account/update_location
account/update_profile_background_image
account/update_profile_image
blocks/create
blocks/destroy
Not implemented in status.net:
statuses/retweeted_to_me
statuses/retweeted_by_me
direct_messages/destroy
account/end_session
account/update_delivery_device
notifications/follow
notifications/leave
blocks/exists
blocks/blocking
lists
*/