diff --git a/boot.php b/boot.php index 217a5f4e1..1ca8b8d8d 100644 --- a/boot.php +++ b/boot.php @@ -232,10 +232,11 @@ define('ACCOUNT_TYPE_RELAY', 4); * Type of the community page * @{ */ -define('CP_NO_COMMUNITY_PAGE', -1); -define('CP_USERS_ON_SERVER', 0); -define('CP_GLOBAL_COMMUNITY', 1); -define('CP_USERS_AND_GLOBAL', 2); +define('CP_NO_INTERNAL_COMMUNITY', -2); +define('CP_NO_COMMUNITY_PAGE', -1); +define('CP_USERS_ON_SERVER', 0); +define('CP_GLOBAL_COMMUNITY', 1); +define('CP_USERS_AND_GLOBAL', 2); /** * @} */ diff --git a/mod/admin.php b/mod/admin.php index 3debb57be..7749cff6d 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -1262,6 +1262,7 @@ function admin_page_site(App $a) /* Community page style */ $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_USERS_ON_SERVER => L10n::t("Public postings from users of this site"), CP_GLOBAL_COMMUNITY => L10n::t("Public postings from the federated network"), diff --git a/mod/community.php b/mod/community.php index 40ebdbb6e..876339dea 100644 --- a/mod/community.php +++ b/mod/community.php @@ -30,6 +30,11 @@ function community_content(App $a, $update = 0) $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) { $content = $a->argv[1]; } else { diff --git a/mod/dfrn_notify.php b/mod/dfrn_notify.php index 27e8ed63f..e2f0336db 100644 --- a/mod/dfrn_notify.php +++ b/mod/dfrn_notify.php @@ -198,9 +198,6 @@ function dfrn_notify_post(App $a) { function dfrn_dispatch_public($postdata) { - /// @todo Currently disabled, until there is a working item distribution for public posts - return false; - $msg = Diaspora::decodeRaw([], $postdata); if (!$msg) { // We have to fail silently to be able to hand it over to the salmon parser diff --git a/src/Content/Nav.php b/src/Content/Nav.php index c437c6e2a..cd2cfb363 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -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')]; } diff --git a/src/Model/Item.php b/src/Model/Item.php index 499ec25c1..8125c4ac7 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -839,6 +839,81 @@ class Item extends BaseObject 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 * @@ -850,8 +925,8 @@ class Item extends BaseObject */ public static function addShadow($itemid) { - $fields = ['uid', 'wall', 'private', 'moderated', 'visible', 'contact-id', 'deleted', 'network', 'author-id', 'owner-id']; - $condition = ["`id` = ? AND (`parent` = ? OR `parent` = 0)", $itemid, $itemid]; + $fields = ['uid', 'private', 'moderated', 'visible', 'deleted', 'network']; + $condition = ['id' => $itemid, 'parent' => [0, $itemid]]; $item = dba::selectFirst('item', $fields, $condition); if (!DBM::is_result($item)) { @@ -873,27 +948,9 @@ class Item extends BaseObject 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]); - 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"] == '')) { if (!dba::exists('item', ['uri' => $item['uri'], 'uid' => 0])) { diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index 4821f3e4a..74975159e 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -2773,6 +2773,10 @@ class DFRN if ($posted_id) { 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; $r = q( @@ -2827,6 +2831,10 @@ class DFRN logger("Item was stored with id ".$posted_id, LOGGER_DEBUG); + if ($item['uid'] == 0) { + Item::distribute($posted_id); + } + if (stristr($item["verb"], ACTIVITY_POKE)) { self::doPoke($item, $importer, $posted_id); } diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index e81c53499..6d7981819 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -590,57 +590,13 @@ class Diaspora return false; } - if (!($postdata = self::validPosting($msg))) { + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['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); - } + $importer = ["uid" => 0, "page-flags" => PAGE_FREELOVE]; + $message_id = self::dispatch($importer, $msg, $fields); 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 if (is_null($fields)) { - if (!($postdata = self::validPosting($msg))) { + if (!($fields = self::validPosting($msg))) { logger("Invalid posting"); return false; } - $fields = $postdata['fields']; } $type = $fields->getName(); @@ -840,7 +795,7 @@ class Diaspora // Only some message types have signatures. So we quit here for the other types. if (!in_array($type, ["comment", "like"])) { - return ["fields" => $fields, "relayed" => false]; + return $fields; } // No author_signature? This is a must, so we quit. if (!isset($author_signature)) { @@ -849,16 +804,12 @@ class Diaspora } if (isset($parent_author_signature)) { - $relayed = true; - $key = self::key($msg["author"]); 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); return false; } - } else { - $relayed = false; } $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); return false; } else { - return ["fields" => $fields, "relayed" => $relayed]; + return $fields; } } @@ -1836,6 +1787,9 @@ class Diaspora if ($message_id) { 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 @@ -2157,6 +2111,9 @@ class Diaspora if ($message_id) { 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 @@ -2883,6 +2840,9 @@ class Diaspora if ($message_id) { logger("Stored reshare ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false; @@ -3107,6 +3067,9 @@ class Diaspora if ($message_id) { logger("Stored item ".$datarray["guid"]." with message id ".$message_id, LOGGER_DEBUG); + if ($datarray['uid'] == 0) { + Item::distribute($message_id); + } return true; } else { return false;