use Friendica\Model\Conversation;
use Friendica\Model\Event;
use Friendica\Model\FContact;
+use Friendica\Model\GServer;
use Friendica\Model\Item;
use Friendica\Model\ItemURI;
use Friendica\Model\Mail;
-use Friendica\Model\Notify\Type;
+use Friendica\Model\Notification;
use Friendica\Model\PermissionSet;
use Friendica\Model\Post;
use Friendica\Model\Post\Category;
// default permissions - anonymous user
- $sql_extra = sprintf(" AND `item`.`private` != %s ", Item::PRIVATE);
+ $sql_extra = sprintf(" AND `private` != %s ", Item::PRIVATE);
$owner = DBA::selectFirst('owner-view', [], ['nickname' => $owner_nick]);
if (!DBA::isResult($owner)) {
$owner_id = $owner['uid'];
- $sql_post_table = "";
-
- if (! $public_feed) {
+ if (!$public_feed) {
switch ($direction) {
case (-1):
$sql_extra = sprintf(" AND `issued-id` = '%s' ", DBA::escape($dfrn_id));
break; // NOTREACHED
}
- $r = q(
- "SELECT * FROM `contact` WHERE NOT `blocked` AND `contact`.`uid` = %d $sql_extra LIMIT 1",
- intval($owner_id)
- );
-
- if (! DBA::isResult($r)) {
- Logger::log(sprintf('No contact found for uid=%d', $owner_id), Logger::WARNING);
+ $contact = DBA::selectFirst('contact', [], ["NOT `blocked` AND `contact`.`uid` = ?" . $sql_extra, $owner_id]);
+ if (!DBA::isResult($contact)) {
+ Logger::notice('No contact found', ['uid' => $owner_id]);
exit();
}
- $contact = $r[0];
-
$set = PermissionSet::get($owner_id, $contact['id']);
if (!empty($set)) {
- $sql_extra = " AND `item`.`psid` IN (" . implode(',', $set) .")";
+ $sql_extra = " AND `psid` IN (" . implode(',', $set) .")";
} else {
- $sql_extra = sprintf(" AND `item`.`private` != %s", Item::PRIVATE);
+ $sql_extra = sprintf(" AND `private` != %s", Item::PRIVATE);
}
}
- if ($public_feed) {
- $sort = 'DESC';
- } else {
- $sort = 'ASC';
- }
-
- if (! strlen($last_update)) {
+ if (!strlen($last_update)) {
$last_update = 'now -30 days';
}
if (isset($category)) {
- $sql_post_table = sprintf("INNER JOIN (SELECT `uri-id` FROM `category-view` WHERE `name` = '%s' AND `type` = %d AND `uid` = %d ORDER BY `uri-id` DESC) AS `category` ON `item`.`uri-id` = `category`.`uri-id` ",
+ $sql_extra .= sprintf(" AND `uri-id` IN (SELECT `uri-id` FROM `category-view` WHERE `name` = '%s' AND `type` = %d AND `uid` = %d)",
DBA::escape(Strings::protectSprintf($category)), intval(Category::CATEGORY), intval($owner_id));
}
if ($public_feed && ! $converse) {
- $sql_extra .= " AND `contact`.`self` = 1 ";
+ $sql_extra .= " AND `self` ";
}
$check_date = DateTimeFormat::utc($last_update);
- $r = q(
- "SELECT `item`.`id`
- FROM `item` USE INDEX (`uid_wall_changed`) $sql_post_table
- STRAIGHT_JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
- WHERE `item`.`uid` = %d AND `item`.`wall` AND `item`.`changed` > '%s'
- AND `vid` != %d AND `item`.`visible` $sql_extra
- ORDER BY `item`.`parent` ".$sort.", `item`.`received` ASC LIMIT 0, 300",
- intval($owner_id),
- DBA::escape($check_date),
- Verb::getID(Activity::ANNOUNCE),
- DBA::escape($sort)
- );
-
- $ids = [];
- foreach ($r as $item) {
- $ids[] = $item['id'];
- }
+ $condition = ["`uid` = ? AND `wall` AND `changed` > ? AND `vid` != ? AND `visible`" . $sql_extra,
+ $owner_id, $check_date, Verb::getID(Activity::ANNOUNCE)];
- if (!empty($ids)) {
- $ret = Item::select(Item::DELIVER_FIELDLIST, ['id' => $ids]);
- $items = Item::inArray($ret);
- } else {
- $items = [];
- }
+ $params = ['sort' => ['parent' => $public_feed, 'received']];
+ $items = Post::selectToArray(Item::DELIVER_FIELDLIST, $condition, $params, ['limit' => 300]);
/*
* Will check further below if this actually returned results.
}
/**
- * Generate an atom entry for a given item id
+ * Generate an atom entry for a given uri id and user
*
- * @param int $item_id The item id
+ * @param int $uri_id The uri id
+ * @param int $uid The user id
* @param boolean $conversation Show the conversation. If false show the single post.
*
* @return string DFRN feed entry
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
- public static function itemFeed($item_id, $conversation = false)
+ public static function itemFeed(int $uri_id, int $uid, bool $conversation = false)
{
if ($conversation) {
- $condition = ['parent' => $item_id];
+ $condition = ['parent-uri-id' => $uri_id];
} else {
- $condition = ['id' => $item_id];
+ $condition = ['uri-id' => $uri_id];
}
- $ret = Item::select(Item::DELIVER_FIELDLIST, $condition);
- $items = Item::inArray($ret);
+ $condition['uid'] = $uid;
+
+ $items = Post::selectToArray(Item::DELIVER_FIELDLIST, $condition);
if (!DBA::isResult($items)) {
return '';
}
$entry->appendChild($dfrnowner);
if ($item['gravity'] != GRAVITY_PARENT) {
- $parent = Item::selectFirst(['guid', 'plink'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]);
+ $parent = Post::selectFirst(['guid', 'plink'], ['uri' => $item['thr-parent'], 'uid' => $item['uid']]);
if (DBA::isResult($parent)) {
$attributes = ["ref" => $item['thr-parent'], "type" => "text/html",
"href" => $parent['plink'],
$msg["from-photo"] = XML::getFirstValue($xpath, "dfrn:sender/dfrn:avatar/text()", $mail);
$msg["contact-id"] = $importer["id"];
$msg["uri"] = XML::getFirstValue($xpath, "dfrn:id/text()", $mail);
- $msg["thr-parent"] = XML::getFirstValue($xpath, "dfrn:in-reply-to/text()", $mail);
+ $msg["parent-uri"] = XML::getFirstValue($xpath, "dfrn:in-reply-to/text()", $mail);
$msg["created"] = DateTimeFormat::utc(XML::getFirstValue($xpath, "dfrn:sentdate/text()", $mail));
$msg["title"] = XML::getFirstValue($xpath, "dfrn:subject/text()", $mail);
$msg["body"] = XML::getFirstValue($xpath, "dfrn:content/text()", $mail);
$community = true;
Logger::log("possible community action");
} else {
- $sql_extra = " AND `contact`.`self` AND `item`.`wall` ";
+ $sql_extra = " AND `self` AND `wall`";
}
// was the top-level post for this action written by somebody on this site?
// Specifically, the recipient?
+ $parent = Post::selectFirst(['forum_mode', 'wall'],
+ ["`uri` = ? AND `uid` = ?" . $sql_extra, $item["thr-parent"], $importer["importer_uid"]]);
- $is_a_remote_action = false;
-
- $parent = Item::selectFirst(['thr-parent'], ['uri' => $item["thr-parent"]]);
- if (DBA::isResult($parent)) {
- $r = q(
- "SELECT `item`.`forum_mode`, `item`.`wall` FROM `item`
- INNER JOIN `contact` ON `contact`.`id` = `item`.`contact-id`
- WHERE `item`.`uri` = '%s' AND (`item`.`thr-parent` = '%s' OR `item`.`thr-parent` = '%s')
- AND `item`.`uid` = %d
- $sql_extra
- LIMIT 1",
- DBA::escape($parent["thr-parent"]),
- DBA::escape($parent["thr-parent"]),
- DBA::escape($parent["thr-parent"]),
- intval($importer["importer_uid"])
- );
- if (DBA::isResult($r)) {
- $is_a_remote_action = true;
- }
- }
+ $is_a_remote_action = DBA::isResult($parent);
/*
* Does this have the characteristics of a community or private group action?
* valid community action. Also forum_mode makes it valid for sure.
* If neither, it's not.
*/
- if ($is_a_remote_action && $community && (!$r[0]["forum_mode"]) && (!$r[0]["wall"])) {
+ if ($is_a_remote_action && $community && (!$parent["forum_mode"]) && (!$parent["wall"])) {
$is_a_remote_action = false;
Logger::log("not a community action");
}
}
if ($Blink && Strings::compareLink($Blink, DI::baseUrl() . "/profile/" . $importer["nickname"])) {
- $author = DBA::selectFirst('contact', ['name', 'thumb', 'url'], ['id' => $item['author-id']]);
+ $author = DBA::selectFirst('contact', ['id', 'name', 'thumb', 'url'], ['id' => $item['author-id']]);
- $parent = Item::selectFirst(['id'], ['uri' => $item['thr-parent'], 'uid' => $importer["importer_uid"]]);
+ $parent = Post::selectFirst(['id'], ['uri' => $item['thr-parent'], 'uid' => $importer["importer_uid"]]);
$item['parent'] = $parent['id'];
// send a notification
notification(
[
- "type" => Type::POKE,
- "notify_flags" => $importer["notify-flags"],
- "language" => $importer["language"],
- "to_name" => $importer["username"],
- "to_email" => $importer["email"],
- "uid" => $importer["importer_uid"],
- "item" => $item,
- "link" => DI::baseUrl()."/display/".urlencode($item['guid']),
- "source_name" => $author["name"],
- "source_link" => $author["url"],
- "source_photo" => $author["thumb"],
- "verb" => $item["verb"],
- "otype" => "person",
- "activity" => $verb,
- "parent" => $item['parent']]
+ "type" => Notification\Type::POKE,
+ "otype" => Notification\ObjectType::PERSON,
+ "activity" => $verb,
+ "verb" => $item["verb"],
+ "uid" => $importer["importer_uid"],
+ "cid" => $author["id"],
+ "item" => $item,
+ "link" => DI::baseUrl() . "/display/" . urlencode($item['guid']),
+ ]
);
}
}
// split into two queries for performance issues
$condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY,
'verb' => $item['verb'], 'parent-uri' => $item['thr-parent']];
- if (Item::exists($condition)) {
+ if (Post::exists($condition)) {
return false;
}
$condition = ['uid' => $item["uid"], 'author-id' => $item["author-id"], 'gravity' => GRAVITY_ACTIVITY,
'verb' => $item['verb'], 'thr-parent' => $item['thr-parent']];
- if (Item::exists($condition)) {
+ if (Post::exists($condition)) {
return false;
}
$xt = XML::parseString($item["target"]);
if ($xt->type == Activity\ObjectType::NOTE) {
- $item_tag = Item::selectFirst(['id', 'uri-id', 'tag'], ['uri' => $xt->id, 'uid' => $importer["importer_uid"]]);
+ $item_tag = Post::selectFirst(['id', 'uri-id'], ['uri' => $xt->id, 'uid' => $importer["importer_uid"]]);
if (!DBA::isResult($item_tag)) {
Logger::log("Query failed to execute, no result returned in " . __FUNCTION__);
* @throws \ImagickException
* @todo Add type-hints
*/
- private static function processEntry($header, $xpath, $entry, $importer, $xml)
+ private static function processEntry($header, $xpath, $entry, $importer, $xml, $protocol)
{
Logger::log("Processing entries");
$item = $header;
- $item["protocol"] = Conversation::PARCEL_DFRN;
+ $item["protocol"] = $protocol;
$item["source"] = $xml;
$item["edited"] = XML::getFirstNodeValue($xpath, "atom:updated/text()", $entry);
- $current = Item::selectFirst(['id', 'uid', 'edited', 'body'],
+ $current = Post::selectFirst(['id', 'uid', 'edited', 'body'],
['uri' => $item["uri"], 'uid' => $importer["importer_uid"]]
);
// Is there an existing item?
$ev = Event::fromBBCode($item["body"]);
if ((!empty($ev['desc']) || !empty($ev['summary'])) && !empty($ev['start'])) {
Logger::log("Event in item ".$item["uri"]." was found.", Logger::DEBUG);
- $ev["cid"] = $importer["id"];
- $ev["uid"] = $importer["importer_uid"];
- $ev["uri"] = $item["uri"];
- $ev["edited"] = $item["edited"];
- $ev["private"] = $item["private"];
- $ev["guid"] = $item["guid"];
- $ev["plink"] = $item["plink"];
+ $ev["cid"] = $importer["id"];
+ $ev["uid"] = $importer["importer_uid"];
+ $ev["uri"] = $item["uri"];
+ $ev["edited"] = $item["edited"];
+ $ev["private"] = $item["private"];
+ $ev["guid"] = $item["guid"];
+ $ev["plink"] = $item["plink"];
+ $ev["network"] = $item["network"];
+ $ev["protocol"] = $item["protocol"];
+ $ev["direction"] = $item["direction"];
+ $ev["source"] = $item["source"];
$condition = ['uri' => $item["uri"], 'uid' => $importer["importer_uid"]];
$event = DBA::selectFirst('event', ['id'], $condition);
}
$condition = ['uri' => $uri, 'uid' => $importer["importer_uid"]];
- $item = Item::selectFirst(['id', 'parent', 'contact-id', 'file', 'deleted', 'gravity'], $condition);
+ $item = Post::selectFirst(['id', 'parent', 'contact-id', 'uri-id', 'deleted', 'gravity'], $condition);
if (!DBA::isResult($item)) {
Logger::log("Item with uri " . $uri . " for user " . $importer["importer_uid"] . " wasn't found.", Logger::DEBUG);
return;
}
- if (strstr($item['file'], '[')) {
- Logger::log("Item with uri " . $uri . " for user " . $importer["importer_uid"] . " is filed. So it won't be deleted.", Logger::DEBUG);
+ if (DBA::exists('post-category', ['uri-id' => $item['uri-id'], 'uid' => $importer['importer_uid'], 'type' => Post\Category::FILE])) {
+ Logger::notice("Item is filed. It won't be deleted.", ['uri' => $uri, 'uri-id' => $item['uri_id'], 'uid' => $importer["importer_uid"]]);
return;
}
// Comments can be deleted by the thread owner or comment owner
if (($item['gravity'] != GRAVITY_PARENT) && ($item['contact-id'] != $importer["id"])) {
$condition = ['id' => $item['parent'], 'contact-id' => $importer["id"]];
- if (!Item::exists($condition)) {
+ if (!Post::exists($condition)) {
Logger::log("Item with uri " . $uri . " wasn't found or mustn't be deleted by contact " . $importer["id"] . " - ignoring deletion.", Logger::DEBUG);
return;
}
/**
* Imports a DFRN message
*
- * @param string $xml The DFRN message
- * @param array $importer Record of the importer user mixed with contact of the content
- * @param bool $sort_by_date Is used when feeds are polled
+ * @param string $xml The DFRN message
+ * @param array $importer Record of the importer user mixed with contact of the content
+ * @param int $protocol Transport protocol
+ * @param int $direction Is the message pushed or pulled?
* @return integer Import status
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
* @todo set proper type-hints
*/
- public static function import($xml, $importer, $sort_by_date = false)
+ public static function import($xml, $importer, $protocol, $direction)
{
if ($xml == "") {
return 400;
$header["wall"] = 0;
$header["origin"] = 0;
$header["contact-id"] = $importer["id"];
+ $header["direction"] = $direction;
+
+ if ($direction === Conversation::RELAY) {
+ $header['post-type'] = Item::PT_RELAY;
+ }
// Update the contact table if the data has changed
Logger::log("Import DFRN message for user " . $importer["importer_uid"] . " from contact " . $importer["id"], Logger::DEBUG);
+ if (!empty($importer['gsid'])) {
+ if ($protocol == Conversation::PARCEL_DIASPORA_DFRN) {
+ GServer::setProtocol($importer['gsid'], Post\DeliveryData::DFRN);
+ } elseif ($protocol == Conversation::PARCEL_LEGACY_DFRN) {
+ GServer::setProtocol($importer['gsid'], Post\DeliveryData::LEGACY_DFRN);
+ }
+ }
+
// is it a public forum? Private forums aren't exposed with this method
$forum = intval(XML::getFirstNodeValue($xpath, "/atom:feed/dfrn:community/text()"));
}
$deletions = $xpath->query("/atom:feed/at:deleted-entry");
- foreach ($deletions as $deletion) {
- self::processDeletion($xpath, $deletion, $importer);
- }
-
- if (!$sort_by_date) {
- $entries = $xpath->query("/atom:feed/atom:entry");
- foreach ($entries as $entry) {
- self::processEntry($header, $xpath, $entry, $importer, $xml);
+ if (!empty($deletions)) {
+ foreach ($deletions as $deletion) {
+ self::processDeletion($xpath, $deletion, $importer);
}
- } else {
- $newentries = [];
- $entries = $xpath->query("/atom:feed/atom:entry");
- foreach ($entries as $entry) {
- $created = XML::getFirstNodeValue($xpath, "atom:published/text()", $entry);
- $newentries[strtotime($created)] = $entry;
+ if (count($deletions) > 0) {
+ Logger::notice('Deletions had been processed');
+ return 200;
}
+ }
- // Now sort after the publishing date
- ksort($newentries);
-
- foreach ($newentries as $entry) {
- self::processEntry($header, $xpath, $entry, $importer, $xml);
- }
+ $entries = $xpath->query("/atom:feed/atom:entry");
+ foreach ($entries as $entry) {
+ self::processEntry($header, $xpath, $entry, $importer, $xml, $protocol);
}
+
Logger::log("Import done for user " . $importer["importer_uid"] . " from contact " . $importer["id"], Logger::DEBUG);
return 200;
}