Support unlisted public posts

This commit is contained in:
Michael 2020-03-02 07:57:23 +00:00
parent 357c0072bd
commit ca1b92bb34
29 changed files with 146 additions and 100 deletions

View file

@ -375,7 +375,7 @@ class Processor
Logger::warning('Unknown parent item.', ['uri' => $item['thr-parent']]);
return false;
}
if ($item_private && !$parent['private']) {
if ($item_private && ($parent['private'] == Item::PRIVATE)) {
Logger::warning('Item is private but the parent is not. Dropping.', ['item-uri' => $item['uri'], 'thr-parent' => $item['thr-parent']]);
return false;
}
@ -442,12 +442,19 @@ class Processor
}
$item['network'] = Protocol::ACTIVITYPUB;
$item['private'] = !in_array(0, $activity['receiver']);
$item['author-link'] = $activity['author'];
$item['author-id'] = Contact::getIdForURL($activity['author'], 0, true);
$item['owner-link'] = $activity['actor'];
$item['owner-id'] = Contact::getIdForURL($activity['actor'], 0, true);
if (in_array(0, $activity['receiver']) && !empty($activity['unlisted'])) {
$item['private'] = Item::UNLISTED;
} elseif (in_array(0, $activity['receiver'])) {
$item['private'] = Item::PUBLIC;
} else {
$item['private'] = Item::PRIVATE;
}
$isForum = false;
if (!empty($activity['thread-completion'])) {
@ -481,6 +488,10 @@ class Processor
$stored = false;
foreach ($activity['receiver'] as $receiver) {
if ($receiver == -1) {
continue;
}
$item['uid'] = $receiver;
if ($isForum) {
@ -530,7 +541,7 @@ class Processor
}
// Store send a follow request for every reshare - but only when the item had been stored
if ($stored && !$item['private'] && ($item['gravity'] == GRAVITY_PARENT) && ($item['author-link'] != $item['owner-link'])) {
if ($stored && ($item['private'] != Item::PRIVATE) && ($item['gravity'] == GRAVITY_PARENT) && ($item['author-link'] != $item['owner-link'])) {
$author = APContact::getByURL($item['owner-link'], false);
// We send automatic follow requests for reshared messages. (We don't need though for forum posts)
if ($author['type'] != 'Group') {

View file

@ -506,14 +506,15 @@ class Receiver
/**
* Fetch the receiver list from an activity array
*
* @param array $activity
* @param string $actor
* @param array $tags
* @param array $activity
* @param string $actor
* @param array $tags
* @param boolean $fetch_unlisted
*
* @return array with receivers (user id)
* @throws \Exception
*/
private static function getReceivers($activity, $actor, $tags = [])
private static function getReceivers($activity, $actor, $tags = [], $fetch_unlisted = false)
{
$receivers = [];
@ -551,6 +552,11 @@ class Receiver
$receivers['uid:0'] = 0;
}
// Add receiver "-1" for unlisted posts
if ($fetch_unlisted && ($receiver == self::PUBLIC_COLLECTION) && ($element == 'as:cc')) {
$receivers['uid:-1'] = -1;
}
if (($receiver == self::PUBLIC_COLLECTION) && !empty($actor)) {
// This will most likely catch all OStatus connections to Mastodon
$condition = ['alias' => [$actor, Strings::normaliseLink($actor)], 'rel' => [Contact::SHARING, Contact::FRIEND]
@ -1022,7 +1028,9 @@ class Receiver
}
}
$object_data['receiver'] = self::getReceivers($object, $object_data['actor'], $object_data['tags']);
$object_data['receiver'] = self::getReceivers($object, $object_data['actor'], $object_data['tags'], true);
$object_data['unlisted'] = in_array(-1, $object_data['receiver']);
unset($object_data['receiver']['uid:-1']);
// Common object data:

View file

@ -173,7 +173,7 @@ class Transmitter
$public_contact = Contact::getIdForURL($owner['url'], 0, true);
$condition = ['uid' => 0, 'contact-id' => $public_contact, 'author-id' => $public_contact,
'private' => false, 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
'private' => [Item::PUBLIC, Item::UNLISTED], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
'deleted' => false, 'visible' => true, 'moderated' => false];
$count = DBA::count('item', $condition);
@ -401,7 +401,7 @@ class Transmitter
$terms = Term::tagArrayFromItemId($item['id'], [Term::MENTION, Term::IMPLICIT_MENTION]);
if (!$item['private']) {
if ($item['private'] != Item::PRIVATE) {
// Directly mention the original author upon a quoted reshare.
// Else just ensure that the original author receives the reshare.
$announce = self::getAnnounceArray($item);
@ -413,7 +413,12 @@ class Transmitter
$data = array_merge($data, self::fetchPermissionBlockFromConversation($item));
$data['to'][] = ActivityPub::PUBLIC_COLLECTION;
// Check if the item is completely public or unlisted
if ($item['private'] == Item::PUBLIC) {
$data['to'][] = ActivityPub::PUBLIC_COLLECTION;
} else {
$data['cc'][] = ActivityPub::PUBLIC_COLLECTION;
}
foreach ($terms as $term) {
$profile = APContact::getByURL($term['url'], false);
@ -467,13 +472,13 @@ class Transmitter
$data['to'][] = $profile['url'];
} else {
$data['cc'][] = $profile['url'];
if (!$item['private'] && !empty($actor_profile['followers'])) {
if (($item['private'] != Item::PRIVATE) && $item['private'] && !empty($actor_profile['followers'])) {
$data['cc'][] = $actor_profile['followers'];
}
}
} else {
// Public thread parent post always are directed to the followers
if (!$item['private'] && !$forum_mode) {
if (($item['private'] != Item::PRIVATE) && !$forum_mode) {
$data['cc'][] = $actor_profile['followers'];
}
}

View file

@ -182,7 +182,7 @@ class DFRN
// default permissions - anonymous user
$sql_extra = " AND NOT `item`.`private` ";
$sql_extra = sprintf(" AND `item`.`private` != %s ", Item::PRIVATE);
$r = q(
"SELECT `contact`.*, `user`.`nickname`, `user`.`timezone`, `user`.`page-flags`, `user`.`account-type`
@ -234,7 +234,7 @@ class DFRN
if (!empty($set)) {
$sql_extra = " AND `item`.`psid` IN (" . implode(',', $set) .")";
} else {
$sql_extra = " AND NOT `item`.`private`";
$sql_extra = sprintf(" AND `item`.`private` != %s", Item::PRIVATE);
}
}
@ -332,7 +332,7 @@ class DFRN
if ($public_feed) {
$type = 'html';
// catch any email that's in a public conversation and make sure it doesn't leak
if ($item['private']) {
if ($item['private'] == Item::PRIVATE) {
continue;
}
} else {
@ -955,7 +955,7 @@ class DFRN
$entry->setAttribute("xmlns:statusnet", ActivityNamespace::STATUSNET);
}
if ($item['private']) {
if ($item['private'] == Item::PRIVATE) {
$body = Item::fixPrivatePhotos($item['body'], $owner['uid'], $item, $cid);
} else {
$body = $item['body'];
@ -1050,7 +1050,8 @@ class DFRN
}
if ($item['private']) {
XML::addElement($doc, $entry, "dfrn:private", ($item['private'] ? $item['private'] : 1));
// Friendica versions prior to 2020.3 can't handle "unlisted" properly. So we can only transmit public and private
XML::addElement($doc, $entry, "dfrn:private", ($item['private'] == Item::PRIVATE ? Item::PRIVATE : Item::PUBLIC));
}
if ($item['extid']) {

View file

@ -2211,7 +2211,7 @@ class Diaspora
return false;
}
$item = Item::selectFirst(['id'], ['guid' => $parent_guid, 'origin' => true, 'private' => false]);
$item = Item::selectFirst(['id'], ['guid' => $parent_guid, 'origin' => true, 'private' => [Item::PUBLIC, Item::UNLISTED]]);
if (!DBA::isResult($item)) {
Logger::log('Item not found, no origin or private: '.$parent_guid);
return false;
@ -2523,7 +2523,7 @@ class Diaspora
// Do we already have this item?
$fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
'author-name', 'author-link', 'author-avatar'];
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]];
$item = Item::selectFirst($fields, $condition);
if (DBA::isResult($item)) {
@ -2567,7 +2567,7 @@ class Diaspora
if ($stored) {
$fields = ['body', 'title', 'attach', 'tag', 'app', 'created', 'object-type', 'uri', 'guid',
'author-name', 'author-link', 'author-avatar'];
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => false];
$condition = ['guid' => $guid, 'visible' => true, 'deleted' => false, 'private' => [Item::PUBLIC, Item::UNLISTED]];
$item = Item::selectFirst($fields, $condition);
if (DBA::isResult($item)) {
@ -2711,7 +2711,7 @@ class Diaspora
$datarray["app"] = $original_item["app"];
$datarray["plink"] = self::plink($author, $guid);
$datarray["private"] = (($public == "false") ? 1 : 0);
$datarray["private"] = (($public == "false") ? Item::PRIVATE : Item::PUBLIC);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at;
$datarray["object-type"] = $original_item["object-type"];
@ -2941,7 +2941,7 @@ class Diaspora
}
$datarray["plink"] = self::plink($author, $guid);
$datarray["private"] = (($public == "false") ? 1 : 0);
$datarray["private"] = (($public == "false") ? Item::PRIVATE : Item::PUBLIC);
$datarray["changed"] = $datarray["created"] = $datarray["edited"] = $created_at;
if (isset($address["address"])) {
@ -3245,7 +3245,7 @@ class Diaspora
private static function sendParticipation(array $contact, array $item)
{
// Don't send notifications for private postings
if ($item['private']) {
if ($item['private'] == Item::PRIVATE) {
return;
}
@ -3536,12 +3536,12 @@ class Diaspora
$myaddr = self::myHandle($owner);
$public = ($item["private"] ? "false" : "true");
$public = ($item["private"] == Item::PRIVATE ? "false" : "true");
$created = DateTimeFormat::utc($item['received'], DateTimeFormat::ATOM);
$edited = DateTimeFormat::utc($item["edited"] ?? $item["created"], DateTimeFormat::ATOM);
// Detect a share element and do a reshare
if (!$item['private'] && ($ret = self::isReshare($item["body"]))) {
if (($item['private'] != Item::PRIVATE) && ($ret = self::isReshare($item["body"]))) {
$message = ["author" => $myaddr,
"guid" => $item["guid"],
"created_at" => $created,

View file

@ -220,7 +220,7 @@ class Feed {
$header["wall"] = 0;
$header["origin"] = 0;
$header["gravity"] = GRAVITY_PARENT;
$header["private"] = 2;
$header["private"] = Item::PUBLIC;
$header["verb"] = Activity::POST;
$header["object-type"] = Activity\ObjectType::NOTE;

View file

@ -1682,7 +1682,7 @@ class OStatus
$entry = self::entryHeader($doc, $owner, $item, $toplevel);
$condition = ['uid' => $owner["uid"], 'guid' => $repeated_guid, 'private' => false,
$condition = ['uid' => $owner["uid"], 'guid' => $repeated_guid, 'private' => [Item::PUBLIC, Item::UNLISTED],
'network' => [Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS]];
$repeated_item = Item::selectFirst([], $condition);
if (!DBA::isResult($repeated_item)) {
@ -1827,7 +1827,7 @@ class OStatus
{
$item["id"] = $item["parent"] = 0;
$item["created"] = $item["edited"] = date("c");
$item["private"] = true;
$item["private"] = Item::PRIVATE;
$contact = Probe::uri($item['follow']);
@ -2120,7 +2120,7 @@ class OStatus
]);
}
if (!$item["private"] && !$feed_mode) {
if (($item['private'] != Item::PRIVATE) && !$feed_mode) {
XML::addElement($doc, $entry, "link", "", ["rel" => "ostatus:attention",
"href" => "http://activityschema.org/collection/public"]);
XML::addElement($doc, $entry, "link", "", ["rel" => "mentioned",
@ -2212,8 +2212,8 @@ class OStatus
$authorid = Contact::getIdForURL($owner["url"], 0, true);
$condition = ["`uid` = ? AND `received` > ? AND NOT `deleted`
AND NOT `private` AND `visible` AND `wall` AND `parent-network` IN (?, ?)",
$owner["uid"], $check_date, Protocol::OSTATUS, Protocol::DFRN];
AND `private` != ? AND `visible` AND `wall` AND `parent-network` IN (?, ?)",
$owner["uid"], $check_date, Item::PRIVATE, Protocol::OSTATUS, Protocol::DFRN];
if ($filter === 'comments') {
$condition[0] .= " AND `object-type` = ? ";