Merge pull request #209 from annando/master

appnet, statusnet and twitter: Now a parent is provided in the notifications so threading of the mails will work.
pull/210/head^2
fabrixxm 2014-08-25 19:29:53 +02:00
commit 986e149eab
5 changed files with 129 additions and 61 deletions

View File

@ -750,13 +750,30 @@ function appnet_fetchstream($a, $uid) {
foreach ($mentions AS $post) { foreach ($mentions AS $post) {
$postarray = appnet_createpost($a, $uid, $post, $me, $user, $ownid, false); $postarray = appnet_createpost($a, $uid, $post, $me, $user, $ownid, false);
if (isset($postarray["id"])) if (isset($postarray["id"])) {
$item = $postarray["id"]; $item = $postarray["id"];
elseif (isset($postarray["body"])) { $parent_id = $postarray['parent'];
} elseif (isset($postarray["body"])) {
$item = item_store($postarray); $item = item_store($postarray);
$parent_id = 0;
logger('appnet_fetchstream: User '.$uid.' posted mention item '.$item); logger('appnet_fetchstream: User '.$uid.' posted mention item '.$item);
} else } else {
$item = 0; $item = 0;
$parent_id = 0;
}
// Fetch the parent and id
if (($parent_id == 0) AND ($postarray['uri'] != "")) {
$r = q("SELECT `id`, `parent` FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($postarray['uri']),
intval($uid)
);
if (count($r)) {
$item = $r[0]['id'];
$parent_id = $r[0]['parent'];
}
}
$lastid = $post["id"]; $lastid = $post["id"];
@ -776,7 +793,8 @@ function appnet_fetchstream($a, $uid) {
'source_link' => $postarray['author-link'], 'source_link' => $postarray['author-link'],
'source_photo' => $postarray['author-avatar'], 'source_photo' => $postarray['author-avatar'],
'verb' => ACTIVITY_TAG, 'verb' => ACTIVITY_TAG,
'otype' => 'item' 'otype' => 'item',
'parent' => $parent_id,
)); ));
} }
} }
@ -792,7 +810,7 @@ function appnet_fetchstream($a, $uid) {
*/ */
} }
function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $threadcompletion = true) { function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $threadcompletion = true, $nodupcheck = false) {
require_once('include/items.php'); require_once('include/items.php');
if ($post["machine_only"]) if ($post["machine_only"])
@ -807,25 +825,33 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$postarray['wall'] = 0; $postarray['wall'] = 0;
$postarray['verb'] = ACTIVITY_POST; $postarray['verb'] = ACTIVITY_POST;
$postarray['network'] = dbesc(NETWORK_APPNET); $postarray['network'] = dbesc(NETWORK_APPNET);
$postarray['uri'] = "adn::".$post["id"]; if (is_array($post["repost_of"])) {
// You can't reply to reposts. So use the original id and thread-id
$postarray['uri'] = "adn::".$post["repost_of"]["id"];
$postarray['parent-uri'] = "adn::".$post["repost_of"]["thread_id"];
} else {
$postarray['uri'] = "adn::".$post["id"];
$postarray['parent-uri'] = "adn::".$post["thread_id"];
}
$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", if (!$nodupcheck) {
dbesc($postarray['uri']), $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
intval($uid) dbesc($postarray['uri']),
); intval($uid)
);
if (count($r)) if (count($r))
return($r[0]); return($r[0]);
$r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
dbesc($postarray['uri']), dbesc($postarray['uri']),
intval($uid) intval($uid)
); );
if (count($r)) if (count($r))
return($r[0]); return($r[0]);
}
$postarray['parent-uri'] = "adn::".$post["thread_id"];
if (isset($post["reply_to"]) AND ($post["reply_to"] != "")) { if (isset($post["reply_to"]) AND ($post["reply_to"] != "")) {
$postarray['thr-parent'] = "adn::".$post["reply_to"]; $postarray['thr-parent'] = "adn::".$post["reply_to"];
@ -875,8 +901,6 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$postarray['object-type'] = ACTIVITY_OBJ_NOTE; $postarray['object-type'] = ACTIVITY_OBJ_NOTE;
} }
$postarray['plink'] = $post["canonical_url"];
if (($post["user"]["id"] != $ownid) OR ($postarray['thr-parent'] == $postarray['uri'])) { if (($post["user"]["id"] != $ownid) OR ($postarray['thr-parent'] == $postarray['uri'])) {
$postarray['owner-name'] = $post["user"]["name"]; $postarray['owner-name'] = $post["user"]["name"];
$postarray['owner-link'] = $post["user"]["canonical_url"]; $postarray['owner-link'] = $post["user"]["canonical_url"];
@ -905,6 +929,8 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$content = $post; $content = $post;
} }
$postarray['plink'] = $content["canonical_url"];
if (is_array($content["entities"])) { if (is_array($content["entities"])) {
$converted = appnet_expand_entities($a, $content["text"], $content["entities"]); $converted = appnet_expand_entities($a, $content["text"], $content["entities"]);
$postarray['body'] = $converted["body"]; $postarray['body'] = $converted["body"];
@ -918,7 +944,7 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$links[$url] = $link["url"]; $links[$url] = $link["url"];
} }
if (sizeof($content["annotations"])) /* if (sizeof($content["annotations"]))
foreach($content["annotations"] AS $annotation) { foreach($content["annotations"] AS $annotation) {
if ($annotation[type] == "net.app.core.oembed") { if ($annotation[type] == "net.app.core.oembed") {
if (isset($annotation["value"]["embeddable_url"])) { if (isset($annotation["value"]["embeddable_url"])) {
@ -927,7 +953,6 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
unset($links[$url]); unset($links[$url]);
} }
} elseif ($annotation[type] == "com.friendica.post") { } elseif ($annotation[type] == "com.friendica.post") {
// Nur zum Testen deaktiviert
//$links = array(); //$links = array();
//if (isset($annotation["value"]["post-title"])) //if (isset($annotation["value"]["post-title"]))
// $postarray['title'] = $annotation["value"]["post-title"]; // $postarray['title'] = $annotation["value"]["post-title"];
@ -948,7 +973,7 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$postarray['author-avatar'] = $annotation["value"]["author-avatar"]; $postarray['author-avatar'] = $annotation["value"]["author-avatar"];
} }
} } */
$page_info = ""; $page_info = "";
@ -969,11 +994,13 @@ function appnet_createpost($a, $uid, $post, $me, $user, $ownid, $createuser, $th
$link = array_pop($links); $link = array_pop($links);
$url = str_replace(array('/', '.'), array('\/', '\.'), $link); $url = str_replace(array('/', '.'), array('\/', '\.'), $link);
$removedlink = preg_replace("/\[url\=".$url."\](.*?)\[\/url\]/ism", '', $postarray['body']);
if (($removedlink == "") OR strstr($postarray['body'], $removedlink))
$postarray['body'] = $removedlink;
$page_info = add_page_info($link, false, $photo["url"]); $page_info = add_page_info($link, false, $photo["url"]);
if (trim($page_info) != "") {
$removedlink = preg_replace("/\[url\=".$url."\](.*?)\[\/url\]/ism", '', $postarray['body']);
if (($removedlink == "") OR strstr($postarray['body'], $removedlink))
$postarray['body'] = $removedlink;
}
} }
$postarray['body'] .= $page_info; $postarray['body'] .= $page_info;

View File

@ -345,6 +345,13 @@ function fbsync_createpost($a, $uid, $self, $contacts, $applications, $post, $cr
$type = "link"; $type = "link";
$content = "[bookmark=".$post->attachment->href."]".$post->attachment->name."[/bookmark]"; $content = "[bookmark=".$post->attachment->href."]".$post->attachment->name."[/bookmark]";
// If a link is not only attached but also added in the body, look if it can be removed in the body.
$removedlink = trim(str_replace($post->attachment->href, "", $postarray["body"]));
if (($removedlink == "") OR strstr($postarray["body"], $removedlink))
$postarray["body"] = $removedlink;
} elseif (isset($post->attachment->name) AND ($post->attachment->name != "")) } elseif (isset($post->attachment->name) AND ($post->attachment->name != ""))
$content = "[b]" . $post->attachment->name."[/b]"; $content = "[b]" . $post->attachment->name."[/b]";

View File

@ -521,7 +521,7 @@ function pumpio_send(&$a,&$b) {
} }
} }
function pumpio_action(&$a, $uid, $uri, $action, $content) { function pumpio_action(&$a, $uid, $uri, $action, $content = "") {
// Don't do likes and other stuff if you don't import the timeline // Don't do likes and other stuff if you don't import the timeline
if (!get_pconfig($uid,'pumpio','import')) if (!get_pconfig($uid,'pumpio','import'))

View File

@ -496,8 +496,13 @@ function statusnet_post_hook(&$a,&$b) {
$orig_post = $r[0]; $orig_post = $r[0];
} }
$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]"; //$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
$nicknameplain = "@".$orig_post["contact_nick"]; //$nicknameplain = "@".$orig_post["contact_nick"];
$nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
$nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
$nicknameplain = "@".$nick;
logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG); logger("statusnet_post_hook: comparing ".$nickname." and ".$nicknameplain." with ".$b["body"], LOGGER_DEBUG);
if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false)) if ((strpos($b["body"], $nickname) === false) AND (strpos($b["body"], $nicknameplain) === false))
@ -700,9 +705,13 @@ function statusnet_prepare_body(&$a,&$b) {
if(count($r)) { if(count($r)) {
$orig_post = $r[0]; $orig_post = $r[0];
//$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]";
//$nicknameplain = "@".$orig_post["contact_nick"];
$nickname = "@[url=".$orig_post["author-link"]."]".$orig_post["contact_nick"]."[/url]"; $nick = preg_replace("=https?://(.*)/(.*)=ism", "$2", $orig_post["author-link"]);
$nicknameplain = "@".$orig_post["contact_nick"];
$nickname = "@[url=".$orig_post["author-link"]."]".$nick."[/url]";
$nicknameplain = "@".$nick;
if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false)) if ((strpos($item["body"], $nickname) === false) AND (strpos($item["body"], $nicknameplain) === false))
$item["body"] = $nickname." ".$item["body"]; $item["body"] = $nickname." ".$item["body"];
@ -1055,7 +1064,14 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
$postarray['gravity'] = 0; $postarray['gravity'] = 0;
$postarray['uid'] = $uid; $postarray['uid'] = $uid;
$postarray['wall'] = 0; $postarray['wall'] = 0;
$postarray['uri'] = $hostname."::".$post->id;
if (is_object($post->retweeted_status)) {
$content = $post->retweeted_status;
statusnet_fetch_contact($uid, $content->user, false);
} else
$content = $post;
$postarray['uri'] = $hostname."::".$content->id;
$r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
dbesc($postarray['uri']), dbesc($postarray['uri']),
@ -1067,9 +1083,9 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
$contactid = 0; $contactid = 0;
if ($post->in_reply_to_status_id != "") { if ($content->in_reply_to_status_id != "") {
$parent = $hostname."::".$post->in_reply_to_status_id; $parent = $hostname."::".$content->in_reply_to_status_id;
$r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `item` WHERE `uri` = '%s' AND `uid` = %d LIMIT 1",
dbesc($parent), dbesc($parent),
@ -1078,6 +1094,7 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
if (count($r)) { if (count($r)) {
$postarray['thr-parent'] = $r[0]["uri"]; $postarray['thr-parent'] = $r[0]["uri"];
$postarray['parent-uri'] = $r[0]["parent-uri"]; $postarray['parent-uri'] = $r[0]["parent-uri"];
$postarray['parent'] = $r[0]["parent"];
$postarray['object-type'] = ACTIVITY_OBJ_COMMENT; $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
} else { } else {
$r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
@ -1087,6 +1104,7 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
if (count($r)) { if (count($r)) {
$postarray['thr-parent'] = $r[0]['uri']; $postarray['thr-parent'] = $r[0]['uri'];
$postarray['parent-uri'] = $r[0]['parent-uri']; $postarray['parent-uri'] = $r[0]['parent-uri'];
$postarray['parent'] = $r[0]['parent'];
$postarray['object-type'] = ACTIVITY_OBJ_COMMENT; $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
} else { } else {
$postarray['thr-parent'] = $postarray['uri']; $postarray['thr-parent'] = $postarray['uri'];
@ -1098,7 +1116,7 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
// Is it me? // Is it me?
$own_url = get_pconfig($uid, 'statusnet', 'own_url'); $own_url = get_pconfig($uid, 'statusnet', 'own_url');
if ($post->user->id == $own_url) { if ($content->user->id == $own_url) {
$r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `contact` WHERE `self` = 1 AND `uid` = %d LIMIT 1",
intval($uid)); intval($uid));
@ -1133,43 +1151,43 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
$postarray['verb'] = ACTIVITY_POST; $postarray['verb'] = ACTIVITY_POST;
$postarray['author-name'] = $postarray['owner-name']; $postarray['author-name'] = $content->user->name;
$postarray['author-link'] = $postarray['owner-link']; $postarray['author-link'] = $content->user->statusnet_profile_url;
$postarray['author-avatar'] = $postarray['owner-avatar']; $postarray['author-avatar'] = $content->user->profile_image_url;
// To-Do: Maybe unreliable? Can the api be entered without trailing "/"? // To-Do: Maybe unreliable? Can the api be entered without trailing "/"?
$hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi')); $hostname = str_replace("/api/", "/notice/", get_pconfig($uid, 'statusnet', 'baseapi'));
$postarray['plink'] = $hostname.$post->id; $postarray['plink'] = $hostname.$content->id;
$postarray['app'] = strip_tags($post->source); $postarray['app'] = strip_tags($content->source);
if ($post->user->protected) { if ($content->user->protected) {
$postarray['private'] = 1; $postarray['private'] = 1;
$postarray['allow_cid'] = '<' . $self['id'] . '>'; $postarray['allow_cid'] = '<' . $self['id'] . '>';
} }
$postarray['body'] = html2bbcode($post->statusnet_html); $postarray['body'] = html2bbcode($content->statusnet_html);
$converted = statusnet_convertmsg($a, $postarray['body'], false); $converted = statusnet_convertmsg($a, $postarray['body'], false);
$postarray['body'] = $converted["body"]; $postarray['body'] = $converted["body"];
$postarray['tag'] = $converted["tags"]; $postarray['tag'] = $converted["tags"];
$postarray['created'] = datetime_convert('UTC','UTC',$post->created_at); $postarray['created'] = datetime_convert('UTC','UTC',$content->created_at);
$postarray['edited'] = datetime_convert('UTC','UTC',$post->created_at); $postarray['edited'] = datetime_convert('UTC','UTC',$content->created_at);
if (is_string($post->place->name)) if (is_string($content->place->name))
$postarray["location"] = $post->place->name; $postarray["location"] = $content->place->name;
if (is_string($post->place->full_name)) if (is_string($content->place->full_name))
$postarray["location"] = $post->place->full_name; $postarray["location"] = $content->place->full_name;
if (is_array($post->geo->coordinates)) if (is_array($content->geo->coordinates))
$postarray["coord"] = $post->geo->coordinates[0]." ".$post->geo->coordinates[1]; $postarray["coord"] = $content->geo->coordinates[0]." ".$content->geo->coordinates[1];
if (is_array($post->coordinates->coordinates)) if (is_array($content->coordinates->coordinates))
$postarray["coord"] = $post->coordinates->coordinates[1]." ".$post->coordinates->coordinates[0]; $postarray["coord"] = $content->coordinates->coordinates[1]." ".$content->coordinates->coordinates[0];
if (is_object($post->retweeted_status)) { /*if (is_object($post->retweeted_status)) {
$postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html); $postarray['body'] = html2bbcode($post->retweeted_status->statusnet_html);
$converted = statusnet_convertmsg($a, $postarray['body'], false); $converted = statusnet_convertmsg($a, $postarray['body'], false);
@ -1182,13 +1200,15 @@ function statusnet_createpost($a, $uid, $post, $self, $create_user, $only_existi
$postarray['author-name'] = $post->retweeted_status->user->name; $postarray['author-name'] = $post->retweeted_status->user->name;
$postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url; $postarray['author-link'] = $post->retweeted_status->user->statusnet_profile_url;
$postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url; $postarray['author-avatar'] = $post->retweeted_status->user->profile_image_url;
} }*/
logger("statusnet_createpost: end", LOGGER_DEBUG); logger("statusnet_createpost: end", LOGGER_DEBUG);
return($postarray); return($postarray);
} }
function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) { function statusnet_checknotification($a, $uid, $own_url, $top_item, $postarray) {
// This function necer worked and need cleanup
$user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
intval($uid) intval($uid)
); );
@ -1405,8 +1425,10 @@ function statusnet_fetchhometimeline($a, $uid) {
dbesc($postarray['uri']), dbesc($postarray['uri']),
intval($uid) intval($uid)
); );
if (count($r)) if (count($r)) {
$item = $r[0]['id']; $item = $r[0]['id'];
$parent_id = $r[0]['parent'];
}
if ($item != 0) { if ($item != 0) {
require_once('include/enotify.php'); require_once('include/enotify.php');
@ -1423,7 +1445,8 @@ function statusnet_fetchhometimeline($a, $uid) {
'source_link' => $postarray['author-link'], 'source_link' => $postarray['author-link'],
'source_photo' => $postarray['author-avatar'], 'source_photo' => $postarray['author-avatar'],
'verb' => ACTIVITY_TAG, 'verb' => ACTIVITY_TAG,
'otype' => 'item' 'otype' => 'item',
'parent' => $parent_id,
)); ));
} }
} }

View File

@ -1243,6 +1243,7 @@ function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing
if (count($r)) { if (count($r)) {
$postarray['thr-parent'] = $r[0]["uri"]; $postarray['thr-parent'] = $r[0]["uri"];
$postarray['parent-uri'] = $r[0]["parent-uri"]; $postarray['parent-uri'] = $r[0]["parent-uri"];
$postarray['parent'] = $r[0]["parent"];
$postarray['object-type'] = ACTIVITY_OBJ_COMMENT; $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
} else { } else {
$r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1", $r = q("SELECT * FROM `item` WHERE `extid` = '%s' AND `uid` = %d LIMIT 1",
@ -1252,6 +1253,7 @@ function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing
if (count($r)) { if (count($r)) {
$postarray['thr-parent'] = $r[0]['uri']; $postarray['thr-parent'] = $r[0]['uri'];
$postarray['parent-uri'] = $r[0]['parent-uri']; $postarray['parent-uri'] = $r[0]['parent-uri'];
$postarray['parent'] = $r[0]['parent'];
$postarray['object-type'] = ACTIVITY_OBJ_COMMENT; $postarray['object-type'] = ACTIVITY_OBJ_COMMENT;
} else { } else {
$postarray['thr-parent'] = $postarray['uri']; $postarray['thr-parent'] = $postarray['uri'];
@ -1404,6 +1406,8 @@ function twitter_createpost($a, $uid, $post, $self, $create_user, $only_existing
function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) { function twitter_checknotification($a, $uid, $own_id, $top_item, $postarray) {
// this whole function doesn't seem to work. Needs complete check
$user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1", $user = q("SELECT * FROM `contact` WHERE `uid` = %d AND `self` LIMIT 1",
intval($uid) intval($uid)
); );
@ -1592,6 +1596,9 @@ function twitter_fetchhometimeline($a, $uid) {
$item = item_store($postarray); $item = item_store($postarray);
if (!isset($postarray["parent"]) OR ($postarray["parent"] == 0))
$postarray["parent"] = $item;
logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item); logger('twitter_fetchhometimeline: User '.$self["nick"].' posted mention timeline item '.$item);
if ($item == 0) { if ($item == 0) {
@ -1599,9 +1606,12 @@ function twitter_fetchhometimeline($a, $uid) {
dbesc($postarray['uri']), dbesc($postarray['uri']),
intval($uid) intval($uid)
); );
if (count($r)) if (count($r)) {
$item = $r[0]['id']; $item = $r[0]['id'];
} $parent_id = $r[0]['parent'];
}
} else
$parent_id = $postarray['parent'];
if ($item != 0) { if ($item != 0) {
require_once('include/enotify.php'); require_once('include/enotify.php');
@ -1618,7 +1628,8 @@ function twitter_fetchhometimeline($a, $uid) {
'source_link' => $postarray['author-link'], 'source_link' => $postarray['author-link'],
'source_photo' => $postarray['author-avatar'], 'source_photo' => $postarray['author-avatar'],
'verb' => ACTIVITY_TAG, 'verb' => ACTIVITY_TAG,
'otype' => 'item' 'otype' => 'item',
'parent' => $parent_id
)); ));
} }
} }