Merge pull request #4924 from annando/item-distribution
Item distribution is now done via the public post
This commit is contained in:
commit
8d8aef5624
8 changed files with 117 additions and 84 deletions
9
boot.php
9
boot.php
|
@ -232,10 +232,11 @@ define('ACCOUNT_TYPE_RELAY', 4);
|
||||||
* Type of the community page
|
* Type of the community page
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
define('CP_NO_COMMUNITY_PAGE', -1);
|
define('CP_NO_INTERNAL_COMMUNITY', -2);
|
||||||
define('CP_USERS_ON_SERVER', 0);
|
define('CP_NO_COMMUNITY_PAGE', -1);
|
||||||
define('CP_GLOBAL_COMMUNITY', 1);
|
define('CP_USERS_ON_SERVER', 0);
|
||||||
define('CP_USERS_AND_GLOBAL', 2);
|
define('CP_GLOBAL_COMMUNITY', 1);
|
||||||
|
define('CP_USERS_AND_GLOBAL', 2);
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1262,6 +1262,7 @@ function admin_page_site(App $a)
|
||||||
|
|
||||||
/* Community page style */
|
/* Community page style */
|
||||||
$community_page_style_choices = [
|
$community_page_style_choices = [
|
||||||
|
CP_NO_INTERNAL_COMMUNITY => L10n::t("No community page for local users"),
|
||||||
CP_NO_COMMUNITY_PAGE => L10n::t("No community page"),
|
CP_NO_COMMUNITY_PAGE => L10n::t("No community page"),
|
||||||
CP_USERS_ON_SERVER => L10n::t("Public postings from users of this site"),
|
CP_USERS_ON_SERVER => L10n::t("Public postings from users of this site"),
|
||||||
CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"),
|
CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"),
|
||||||
|
|
|
@ -30,6 +30,11 @@ function community_content(App $a, $update = 0)
|
||||||
|
|
||||||
$page_style = Config::get('system', 'community_page_style');
|
$page_style = Config::get('system', 'community_page_style');
|
||||||
|
|
||||||
|
if ($page_style == CP_NO_INTERNAL_COMMUNITY) {
|
||||||
|
notice(L10n::t('Access denied.') . EOL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ($a->argc > 1) {
|
if ($a->argc > 1) {
|
||||||
$content = $a->argv[1];
|
$content = $a->argv[1];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -198,9 +198,6 @@ function dfrn_notify_post(App $a) {
|
||||||
|
|
||||||
function dfrn_dispatch_public($postdata)
|
function dfrn_dispatch_public($postdata)
|
||||||
{
|
{
|
||||||
/// @todo Currently disabled, until there is a working item distribution for public posts
|
|
||||||
return false;
|
|
||||||
|
|
||||||
$msg = Diaspora::decodeRaw([], $postdata);
|
$msg = Diaspora::decodeRaw([], $postdata);
|
||||||
if (!$msg) {
|
if (!$msg) {
|
||||||
// We have to fail silently to be able to hand it over to the salmon parser
|
// We have to fail silently to be able to hand it over to the salmon parser
|
||||||
|
|
|
@ -161,7 +161,8 @@ class Nav
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) {
|
if ((local_user() || Config::get('system', 'community_page_style') != CP_NO_COMMUNITY_PAGE) &&
|
||||||
|
!(Config::get('system', 'community_page_style') == CP_NO_INTERNAL_COMMUNITY)) {
|
||||||
$nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')];
|
$nav['community'] = ['community', L10n::t('Community'), '', L10n::t('Conversations on this and other servers')];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -839,6 +839,81 @@ class Item extends BaseObject
|
||||||
return $current_post;
|
return $current_post;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Distributes public items to the receivers
|
||||||
|
*
|
||||||
|
* @param integer $itemid Item ID that should be added
|
||||||
|
*/
|
||||||
|
public static function distribute($itemid)
|
||||||
|
{
|
||||||
|
$condition = ["`id` IN (SELECT `parent` FROM `item` WHERE `id` = ?)", $itemid];
|
||||||
|
$parent = dba::selectFirst('item', ['owner-id'], $condition);
|
||||||
|
if (!DBM::is_result($parent)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only distribute public items from native networks
|
||||||
|
$condition = ['id' => $itemid, 'uid' => 0,
|
||||||
|
'network' => [NETWORK_DFRN, NETWORK_DIASPORA, NETWORK_OSTATUS, ""],
|
||||||
|
'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => false];
|
||||||
|
$item = dba::selectFirst('item', [], ['id' => $itemid]);
|
||||||
|
if (!DBM::is_result($item)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($item['id']);
|
||||||
|
|
||||||
|
$condition = ["`nurl` IN (SELECT `nurl` FROM `contact` WHERE `id` = ?) AND `uid` != 0 AND NOT `blocked` AND `rel` IN (?, ?)",
|
||||||
|
$parent['owner-id'], CONTACT_IS_SHARING, CONTACT_IS_FRIEND];
|
||||||
|
$contacts = dba::select('contact', ['uid'], $condition);
|
||||||
|
while ($contact = dba::fetch($contacts)) {
|
||||||
|
self::storeForUser($itemid, $item, $contact['uid']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Store public items for the receivers
|
||||||
|
*
|
||||||
|
* @param integer $itemid Item ID that should be added
|
||||||
|
* @param array $item The item entry that will be stored
|
||||||
|
* @param integer $uid The user that will receive the item entry
|
||||||
|
*/
|
||||||
|
private static function storeForUser($itemid, $item, $uid)
|
||||||
|
{
|
||||||
|
$item['uid'] = $uid;
|
||||||
|
$item['origin'] = 0;
|
||||||
|
$item['wall'] = 0;
|
||||||
|
if ($item['uri'] == $item['parent-uri']) {
|
||||||
|
$item['contact-id'] = Contact::getIdForURL($item['owner-link'], $uid);
|
||||||
|
} else {
|
||||||
|
$item['contact-id'] = Contact::getIdForURL($item['author-link'], $uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($item['contact-id'])) {
|
||||||
|
$self = dba::selectFirst('contact', ['id'], ['self' => true, 'uid' => $uid]);
|
||||||
|
if (!DBM::is_result($self)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$item['contact-id'] = $self['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($item['type'], ["net-comment", "wall-comment"])) {
|
||||||
|
$item['type'] = 'remote-comment';
|
||||||
|
} elseif ($item['type'] == 'wall') {
|
||||||
|
$item['type'] = 'remote';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @todo Handling of "event-id"
|
||||||
|
|
||||||
|
$distributed = self::insert($item, false, false, true);
|
||||||
|
|
||||||
|
if (!$distributed) {
|
||||||
|
logger("Distributed public item " . $itemid . " for user " . $uid . " wasn't stored", LOGGER_DEBUG);
|
||||||
|
} else {
|
||||||
|
logger("Distributed public item " . $itemid . " for user " . $uid . " with id " . $distributed, LOGGER_DEBUG);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a shadow entry for a given item id that is a thread starter
|
* @brief Add a shadow entry for a given item id that is a thread starter
|
||||||
*
|
*
|
||||||
|
@ -850,8 +925,8 @@ class Item extends BaseObject
|
||||||
*/
|
*/
|
||||||
public static function addShadow($itemid)
|
public static function addShadow($itemid)
|
||||||
{
|
{
|
||||||
$fields = ['uid', 'wall', 'private', 'moderated', 'visible', 'contact-id', 'deleted', 'network', 'author-id', 'owner-id'];
|
$fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network'];
|
||||||
$condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid];
|
$condition = ['id' => $itemid, 'parent' => [0, $itemid]];
|
||||||
$item = dba::selectFirst('item', $fields, $condition);
|
$item = dba::selectFirst('item', $fields, $condition);
|
||||||
|
|
||||||
if (!DBM::is_result($item)) {
|
if (!DBM::is_result($item)) {
|
||||||
|
@ -873,27 +948,9 @@ class Item extends BaseObject
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only do these checks if the post isn't a wall post
|
|
||||||
if (!$item["wall"]) {
|
|
||||||
// Check, if hide-friends is activated - then don't do a shadow entry
|
|
||||||
if (dba::exists('profile', ['is-default' => true, 'uid' => $item['uid'], 'hide-friends' => true])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the contact is hidden or blocked
|
|
||||||
if (!dba::exists('contact', ['hidden' => false, 'blocked' => false, 'id' => $item['contact-id']])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only add a shadow, if the profile isn't hidden
|
|
||||||
if (dba::exists('user', ['uid' => $item['uid'], 'hidewall' => true])) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$item = dba::selectFirst('item', [], ['id' => $itemid]);
|
$item = dba::selectFirst('item', [], ['id' => $itemid]);
|
||||||
|
|
||||||
if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
|
if (DBM::is_result($item) && ($item["allow_cid"] == '') && ($item["allow_gid"] == '') &&
|
||||||
($item["deny_cid"] == '') && ($item["deny_gid"] == '')) {
|
($item["deny_cid"] == '') && ($item["deny_gid"] == '')) {
|
||||||
|
|
||||||
if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
|
if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) {
|
||||||
|
|
|
@ -2773,6 +2773,10 @@ class DFRN
|
||||||
if ($posted_id) {
|
if ($posted_id) {
|
||||||
logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG);
|
logger("Reply from contact ".$item["contact-id"]." was stored with id ".$posted_id, LOGGER_DEBUG);
|
||||||
|
|
||||||
|
if ($item['uid'] == 0) {
|
||||||
|
Item::distribute($posted_id);
|
||||||
|
}
|
||||||
|
|
||||||
$item["id"] = $posted_id;
|
$item["id"] = $posted_id;
|
||||||
|
|
||||||
$r = q(
|
$r = q(
|
||||||
|
@ -2827,6 +2831,10 @@ class DFRN
|
||||||
|
|
||||||
logger("Item was stored with id ".$posted_id, LOGGER_DEBUG);
|
logger("Item was stored with id ".$posted_id, LOGGER_DEBUG);
|
||||||
|
|
||||||
|
if ($item['uid'] == 0) {
|
||||||
|
Item::distribute($posted_id);
|
||||||
|
}
|
||||||
|
|
||||||
if (stristr($item["verb"], ACTIVITY_POKE)) {
|
if (stristr($item["verb"], ACTIVITY_POKE)) {
|
||||||
self::doPoke($item, $importer, $posted_id);
|
self::doPoke($item, $importer, $posted_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -590,57 +590,13 @@ class Diaspora
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!($postdata = self::validPosting($msg))) {
|
if (!($fields = self::validPosting($msg))) {
|
||||||
logger("Invalid posting");
|
logger("Invalid posting");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fields = $postdata['fields'];
|
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
||||||
|
$message_id = self::dispatch($importer, $msg, $fields);
|
||||||
// Is it a an action (comment, like, ...) for our own post?
|
|
||||||
if (isset($fields->parent_guid) && !$postdata["relayed"]) {
|
|
||||||
$guid = notags(unxmlify($fields->parent_guid));
|
|
||||||
$importer = self::importerForGuid($guid);
|
|
||||||
if (is_array($importer)) {
|
|
||||||
logger("delivering to origin: ".$importer["name"]);
|
|
||||||
$message_id = self::dispatch($importer, $msg, $fields);
|
|
||||||
return $message_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process item retractions. This has to be done separated from the other stuff,
|
|
||||||
// since retractions for comments could come even from non followers.
|
|
||||||
if (!empty($fields) && in_array($fields->getName(), ['retraction'])) {
|
|
||||||
$target = notags(unxmlify($fields->target_type));
|
|
||||||
if (in_array($target, ["Comment", "Like", "Post", "Reshare", "StatusMessage"])) {
|
|
||||||
logger('processing retraction for '.$target, LOGGER_DEBUG);
|
|
||||||
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
|
||||||
$message_id = self::dispatch($importer, $msg, $fields);
|
|
||||||
return $message_id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now distribute it to the followers
|
|
||||||
$r = q(
|
|
||||||
"SELECT `user`.* FROM `user` WHERE `user`.`uid` IN
|
|
||||||
(SELECT `contact`.`uid` FROM `contact` WHERE `contact`.`network` = '%s' AND `contact`.`addr` = '%s')
|
|
||||||
AND NOT `account_expired` AND NOT `account_removed`",
|
|
||||||
dbesc(NETWORK_DIASPORA),
|
|
||||||
dbesc($msg["author"])
|
|
||||||
);
|
|
||||||
|
|
||||||
if (DBM::is_result($r)) {
|
|
||||||
foreach ($r as $rr) {
|
|
||||||
logger("delivering to: ".$rr["username"]);
|
|
||||||
self::dispatch($rr, $msg, $fields);
|
|
||||||
}
|
|
||||||
} elseif (!Config::get('system', 'relay_subscribe', false)) {
|
|
||||||
logger("Unwanted message from ".$msg["author"]." send by ".$_SERVER["REMOTE_ADDR"]." with ".$_SERVER["HTTP_USER_AGENT"].": ".print_r($msg, true), LOGGER_DEBUG);
|
|
||||||
} else {
|
|
||||||
// Use a dummy importer to import the data for the public copy
|
|
||||||
$importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE];
|
|
||||||
$message_id = self::dispatch($importer, $msg, $fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $message_id;
|
return $message_id;
|
||||||
}
|
}
|
||||||
|
@ -662,11 +618,10 @@ class Diaspora
|
||||||
|
|
||||||
// This is only needed for private postings since this is already done for public ones before
|
// This is only needed for private postings since this is already done for public ones before
|
||||||
if (is_null($fields)) {
|
if (is_null($fields)) {
|
||||||
if (!($postdata = self::validPosting($msg))) {
|
if (!($fields = self::validPosting($msg))) {
|
||||||
logger("Invalid posting");
|
logger("Invalid posting");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$fields = $postdata['fields'];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $fields->getName();
|
$type = $fields->getName();
|
||||||
|
@ -840,7 +795,7 @@ class Diaspora
|
||||||
|
|
||||||
// Only some message types have signatures. So we quit here for the other types.
|
// Only some message types have signatures. So we quit here for the other types.
|
||||||
if (!in_array($type, ["comment", "like"])) {
|
if (!in_array($type, ["comment", "like"])) {
|
||||||
return ["fields" => $fields, "relayed" => false];
|
return $fields;
|
||||||
}
|
}
|
||||||
// No author_signature? This is a must, so we quit.
|
// No author_signature? This is a must, so we quit.
|
||||||
if (!isset($author_signature)) {
|
if (!isset($author_signature)) {
|
||||||
|
@ -849,16 +804,12 @@ class Diaspora
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isset($parent_author_signature)) {
|
if (isset($parent_author_signature)) {
|
||||||
$relayed = true;
|
|
||||||
|
|
||||||
$key = self::key($msg["author"]);
|
$key = self::key($msg["author"]);
|
||||||
|
|
||||||
if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) {
|
if (!Crypto::rsaVerify($signed_data, $parent_author_signature, $key, "sha256")) {
|
||||||
logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
|
logger("No valid parent author signature for parent author ".$msg["author"]. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$parent_author_signature, LOGGER_DEBUG);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
$relayed = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = self::key($fields->author);
|
$key = self::key($fields->author);
|
||||||
|
@ -867,7 +818,7 @@ class Diaspora
|
||||||
logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
|
logger("No valid author signature for author ".$fields->author. " in type ".$type." - signed data: ".$signed_data." - Message: ".$msg["message"]." - Signature ".$author_signature, LOGGER_DEBUG);
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return ["fields" => $fields, "relayed" => $relayed];
|
return $fields;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1836,6 +1787,9 @@ class Diaspora
|
||||||
|
|
||||||
if ($message_id) {
|
if ($message_id) {
|
||||||
logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
logger("Stored comment ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||||
|
if ($datarray['uid'] == 0) {
|
||||||
|
Item::distribute($message_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are the origin of the parent we store the original data and notify our followers
|
// If we are the origin of the parent we store the original data and notify our followers
|
||||||
|
@ -2157,6 +2111,9 @@ class Diaspora
|
||||||
|
|
||||||
if ($message_id) {
|
if ($message_id) {
|
||||||
logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
logger("Stored like ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||||
|
if ($datarray['uid'] == 0) {
|
||||||
|
Item::distribute($message_id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// like on comments have the comment as parent. So we need to fetch the toplevel parent
|
// like on comments have the comment as parent. So we need to fetch the toplevel parent
|
||||||
|
@ -2883,6 +2840,9 @@ class Diaspora
|
||||||
|
|
||||||
if ($message_id) {
|
if ($message_id) {
|
||||||
logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||||
|
if ($datarray['uid'] == 0) {
|
||||||
|
Item::distribute($message_id);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -3107,6 +3067,9 @@ class Diaspora
|
||||||
|
|
||||||
if ($message_id) {
|
if ($message_id) {
|
||||||
logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG);
|
||||||
|
if ($datarray['uid'] == 0) {
|
||||||
|
Item::distribute($message_id);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in a new issue