$author_user = $status_user;
- $status_user["protected"] = $item['private'] ?? 0;
+ $status_user["protected"] = $item['private'] == Item::PRIVATE;
if (($item['thr-parent'] ?? '') == ($item['uri'] ?? '')) {
$owner_user = api_get_user($a, $item['owner-id'] ?? null);
'author-id'=> $ownerId,
'uid' => $uid,
'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT],
- 'private' => false
+ 'private' => [Item::PUBLIC, Item::UNLISTED]
];
$item = api_get_item($condition);
$start = max(0, ($page - 1) * $count);
if ($exclude_replies && !$conversation_id) {
- $condition = ["`gravity` IN (?, ?) AND `iid` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND NOT `author`.`hidden`",
- GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
+ $condition = ["`gravity` IN (?, ?) AND `iid` > ? AND `private` = ? AND `wall` AND NOT `author`.`hidden`",
+ GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `thread`.`iid` <= ?";
$r = Item::inArray($statuses);
} else {
- $condition = ["`gravity` IN (?, ?) AND `id` > ? AND NOT `private` AND `wall` AND NOT `user`.`hidewall` AND `item`.`origin` AND NOT `author`.`hidden`",
- GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
+ $condition = ["`gravity` IN (?, ?) AND `id` > ? AND `private` = ? AND `wall` AND `item`.`origin` AND NOT `author`.`hidden`",
+ GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `item`.`id` <= ?";
$start = max(0, ($page - 1) * $count);
- $condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND NOT `private`",
- GRAVITY_PARENT, GRAVITY_COMMENT, $since_id];
+ $condition = ["`uid` = 0 AND `gravity` IN (?, ?) AND `thread`.`iid` > ? AND `private` = ?",
+ GRAVITY_PARENT, GRAVITY_COMMENT, $since_id, Item::PUBLIC];
if ($max_id > 0) {
$condition[0] .= " AND `thread`.`iid` <= ?";
Logger::log('API: api_statuses_repeat: '.$id);
$fields = ['body', 'title', 'attach', 'tag', 'author-name', 'author-link', 'author-avatar', 'guid', 'created', 'plink'];
- $item = Item::selectFirst($fields, ['id' => $id, 'private' => false]);
+ $item = Item::selectFirst($fields, ['id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED]]);
if (DBA::isResult($item) && $item['body'] != "") {
if (strpos($item['body'], "[/share]") !== false) {
'user' => $status_user,
'friendica_author' => $author_user,
'friendica_owner' => $owner_user,
- 'friendica_private' => $item['private'] == 1,
+ 'friendica_private' => $item['private'] == Item::PRIVATE,
//'entities' => NULL,
'statusnet_html' => $converted["html"],
'statusnet_conversation_id' => $item['parent'],
// Is this item private but could be visible to the remove visitor?
if (!DBA::isResult($item) && remote_user()) {
- $item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
+ $item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => Item::PRIVATE, 'origin' => true]);
if (DBA::isResult($item)) {
if (!Contact::isFollower(remote_user(), $item['uid'])) {
$item = null;
// Is it an item with uid=0?
if (!DBA::isResult($item)) {
- $item = Item::selectFirstForUser(local_user(), $fields, ['guid' => $a->argv[1], 'private' => [0, 2], 'uid' => 0]);
+ $item = Item::selectFirstForUser(local_user(), $fields, ['guid' => $a->argv[1], 'private' => [Item::PUBLIC, Item::UNLISTED], 'uid' => 0]);
}
} elseif ($a->argc >= 3 && $nick == 'feed-item') {
$item_id = $a->argv[2];
if (substr($item_id, -5) == '.atom') {
$item_id = substr($item_id, 0, -5);
}
- $item = Item::selectFirstForUser(local_user(), $fields, ['id' => $item_id, 'private' => [0, 2], 'uid' => 0]);
+ $item = Item::selectFirstForUser(local_user(), $fields, ['id' => $item_id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'uid' => 0]);
}
if (!DBA::isResult($item)) {
}
if (($item_parent == 0) && remote_user()) {
- $item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => 1, 'origin' => true]);
+ $item = Item::selectFirst($fields, ['guid' => $a->argv[1], 'private' => Item::PRIVATE, 'origin' => true]);
if (DBA::isResult($item) && Contact::isFollower(remote_user(), $item['uid'])) {
$item_id = $item["id"];
$item_parent = $item["parent"];
}
if ($item_parent == 0) {
- $condition = ['private' => [0, 2], 'guid' => $a->argv[1], 'uid' => 0];
+ $condition = ['private' => [Item::PUBLIC, Item::UNLISTED], 'guid' => $a->argv[1], 'uid' => 0];
$item = Item::selectFirstForUser(local_user(), $fields, $condition);
if (DBA::isResult($item)) {
$item_id = $item["id"];
}
// We are displaying an "alternate" link if that post was public. See issue 2864
- $is_public = Item::exists(['id' => $item_id, 'private' => [0, 2]]);
+ $is_public = Item::exists(['id' => $item_id, 'private' => [Item::PUBLIC, Item::UNLISTED]]);
if ($is_public) {
// For the atom feed the nickname doesn't matter at all, we only need the item id.
$alternate = DI::baseUrl().'/display/feed-item/'.$item_id.'.atom';
use Friendica\Database\DBA;
use Friendica\DI;
use Friendica\Model\Attach;
+use Friendica\Model\Config\PConfig;
use Friendica\Model\Contact;
use Friendica\Model\Conversation;
use Friendica\Model\FileTag;
$postopts = $_REQUEST['postopts'] ?? '';
- $private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
+ if (strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) {
+ $private = Item::PRIVATE;
+ } elseif (PConfig::get($profile_uid, 'system', 'unlisted')) {
+ $private == Item::UNLISTED;
+ } else {
+ $private == Item::PUBLIC;
+ }
// If this is a comment, set the permissions from the parent.
}
if (isset($item['private'])
- && $item['private'] == 1
+ && $item['private'] == Item::PRIVATE
&& empty($item['allow_cid'])
&& empty($item['allow_gid'])
&& empty($item['deny_cid'])
$deny_gid = $item['deny_gid'];
}
} else {
- $private = (!empty($_GET['private']) ? intval($_GET['private']) : 0);
+ $private = (!empty($_GET['private']) ? intval($_GET['private']) : Item::PUBLIC);
$allow_cid = ($private ? '<' . $target['id']. '>' : $a->user['allow_cid']);
$allow_gid = ($private ? '' : $a->user['allow_gid']);
// fetch user from database given the nickname
$condition = ['nickname' => $nick, 'account_expired' => false, 'account_removed' => false];
- $owner = DBA::selectFirst('user', ['uid', 'hidewall', 'nickname'], $condition);
+ $owner = DBA::selectFirst('user', ['uid', 'nickname'], $condition);
if (!DBA::isResult($owner)) {
Logger::log('Local account not found: ' . $nick . ' - topic: ' . $hub_topic . ' - callback: ' . $hub_callback);
throw new \Friendica\Network\HTTPException\NotFoundException();
}
- // abort if user's wall is supposed to be private
- if ($owner['hidewall']) {
- Logger::log('Local user ' . $nick . 'has chosen to hide wall, ignoring.');
- throw new \Friendica\Network\HTTPException\ForbiddenException();
- }
-
// get corresponding row from contact table
$condition = ['uid' => $owner['uid'], 'blocked' => false,
'pending' => false, 'self' => true];
$cntunkmail = (!empty($_POST['cntunkmail']) ? intval($_POST['cntunkmail']) : 0);
$hide_friends = (($_POST['hide-friends'] == 1) ? 1: 0);
$hidewall = (($_POST['hidewall'] == 1) ? 1: 0);
+ $unlisted = (($_POST['unlisted'] == 1) ? 1: 0);
$email_textonly = (($_POST['email_textonly'] == 1) ? 1 : 0);
$detailed_notif = (($_POST['detailed_notif'] == 1) ? 1 : 0);
DI::pConfig()->set(local_user(), 'system', 'email_textonly', $email_textonly);
DI::pConfig()->set(local_user(), 'system', 'detailed_notif', $detailed_notif);
+ DI::pConfig()->set(local_user(), 'system', 'unlisted', $unlisted);
if ($page_flags == User::PAGE_FLAGS_PRVGROUP) {
$hidewall = 1;
'$field' => ['hidewall', DI::l10n()->t('Hide your profile details from anonymous viewers?'), $a->user['hidewall'], DI::l10n()->t('Anonymous visitors will only see your profile picture, your display name and the nickname you are using on your profile page. Your public posts and replies will still be accessible by other means.')],
]);
+ $unlisted = Renderer::replaceMacros($opt_tpl, [
+ '$field' => ['unlisted', DI::l10n()->t('Should public posts be unlisted?'), DI::pConfig()->get(local_user(), 'system', 'unlisted'), DI::l10n()->t('Your public posts will not appear on the community page or in search results, nor will they be transported to relay servers.')],
+ ]);
+
$blockwall = Renderer::replaceMacros($opt_tpl, [
'$field' => ['blockwall', DI::l10n()->t('Allow friends to post to your profile page?'), (intval($a->user['blockwall']) ? '0' : '1'), DI::l10n()->t('Your contacts may write posts on your profile wall. These posts will be distributed to your contacts')],
]);
'$profile_in_net_dir' => $profile_in_net_dir,
'$hide_friends' => $hide_friends,
'$hide_wall' => $hide_wall,
+ '$unlisted' => $unlisted,
'$unkmail' => $unkmail,
'$cntunkmail' => ['cntunkmail', DI::l10n()->t('Maximum private messages per day from unknown people:'), $cntunkmail , DI::l10n()->t("\x28to prevent spam abuse\x29")],
'guid', 'created', 'plink', 'title'];
$item = Item::selectFirst($fields, ['id' => $post_id]);
- if (!DBA::isResult($item) || $item['private'] == 1) {
+ if (!DBA::isResult($item) || $item['private'] == Item::PRIVATE) {
exit();
}
Contact::getIdForURL($attributes['profile'], 0, true, $default);
$author_contact = Contact::getDetailsByURL($attributes['profile']);
- $author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
+ $author_contact['url'] = ($author_contact['url'] ?? $attributes['profile']);
+ $author_contact['addr'] = ($author_contact['addr'] ?? '') ?: Protocol::getAddrFromProfileUrl($attributes['profile']);
$attributes['author'] = ($author_contact['name'] ?? '') ?: $attributes['author'];
$attributes['avatar'] = ($author_contact['micro'] ?? '') ?: $attributes['avatar'];
Activity::FOLLOW,
Activity::ANNOUNCE];
+ const PUBLIC = 0;
+ const PRIVATE = 1;
+ const UNLISTED = 2;
+
private static $legacy_mode = null;
public static function isLegacyMode()
$item['allow_gid'] = trim($item['allow_gid'] ?? '');
$item['deny_cid'] = trim($item['deny_cid'] ?? '');
$item['deny_gid'] = trim($item['deny_gid'] ?? '');
- $item['private'] = intval($item['private'] ?? 0);
+ $item['private'] = intval($item['private'] ?? self::PUBLIC);
$item['body'] = trim($item['body'] ?? '');
$item['tag'] = trim($item['tag'] ?? '');
$item['attach'] = trim($item['attach'] ?? '');
* The original author commented, but as this is a comment, the permissions
* weren't fixed up so it will still show the comment as private unless we fix it here.
*/
- if ((intval($parent['forum_mode']) == 1) && $parent['private']) {
- $item['private'] = 0;
+ if ((intval($parent['forum_mode']) == 1) && ($parent['private'] != self::PUBLIC)) {
+ $item['private'] = self::PUBLIC;
}
// If its a post that originated here then tag the thread as "mention"
// ACL settings
if (strlen($allow_cid) || strlen($allow_gid) || strlen($deny_cid) || strlen($deny_gid)) {
- $private = 1;
+ $private = self::PRIVATE;
} else {
$private = $item['private'];
}
// Only distribute public items from native networks
$condition = ['id' => $itemid, 'uid' => 0,
'network' => array_merge(Protocol::FEDERATED ,['']),
- 'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => false];
+ 'visible' => true, 'deleted' => false, 'moderated' => false, 'private' => [self::PUBLIC, self::UNLISTED]];
$item = self::selectFirst(self::ITEM_FIELDLIST, $condition);
if (!DBA::isResult($item)) {
return;
}
// Is it a visible public post?
- if (!$item["visible"] || $item["deleted"] || $item["moderated"] || $item["private"]) {
+ if (!$item["visible"] || $item["deleted"] || $item["moderated"] || ($item["private"] == Item::PRIVATE)) {
return;
}
Contact::unmarkForArchival($contact);
}
- $update = (!$arr['private'] && ((($arr['author-link'] ?? '') === ($arr['owner-link'] ?? '')) || ($arr["parent-uri"] === $arr["uri"])));
+ $update = (($arr['private'] != self::PRIVATE) && ((($arr['author-link'] ?? '') === ($arr['owner-link'] ?? '')) || ($arr["parent-uri"] === $arr["uri"])));
// Is it a forum? Then we don't care about the rules from above
if (!$update && in_array($arr["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN]) && ($arr["parent-uri"] === $arr["uri"])) {
['id' => $arr['contact-id']]);
}
// Now do the same for the system wide contacts with uid=0
- if (!$arr['private']) {
+ if ($arr['private'] != self::PRIVATE) {
DBA::update('contact', ['success_update' => $arr['received'], 'last-item' => $arr['received']],
['id' => $arr['owner-id']]);
// also reset all the privacy bits to the forum default permissions
- $private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? 1 : 0;
+ $private = ($user['allow_cid'] || $user['allow_gid'] || $user['deny_cid'] || $user['deny_gid']) ? self::PRIVATE : self::PUBLIC;
$psid = PermissionSet::getIdFromACL(
$user['uid'],
return false;
}
- if (($contact['network'] != Protocol::FEED) && $datarray['private']) {
+ if (($contact['network'] != Protocol::FEED) && ($datarray['private'] == self::PRIVATE)) {
Logger::log('Not public', Logger::DEBUG);
return false;
}
$urlpart = parse_url($datarray2['author-link']);
$datarray["app"] = $urlpart["host"];
} else {
- $datarray['private'] = 0;
+ $datarray['private'] = self::PUBLIC;
}
}
*
* default permissions - anonymous user
*/
- $sql = " AND NOT `item`.`private`";
+ $sql = sprintf(" AND `item`.`private` != %d", self::PRIVATE);
// Profile owner - everything is visible
if ($local_user && ($local_user == $owner_id)) {
$set = PermissionSet::get($owner_id, $remote_user);
if (!empty($set)) {
- $sql_set = " OR (`item`.`private` IN (1,2) AND `item`.`wall` AND `item`.`psid` IN (" . implode(',', $set) . "))";
+ $sql_set = sprintf(" OR (`item`.`private` = %d AND `item`.`wall` AND `item`.`psid` IN (", self::PRIVATE) . implode(',', $set) . "))";
} else {
$sql_set = '';
}
- $sql = " AND (NOT `item`.`private`" . $sql_set . ")";
+ $sql = sprintf(" AND (`item`.`private` != %d", self::PRIVATE) . $sql_set . ")";
}
return $sql;
continue;
}
- if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($item['contact-id'] != $app->contact['id']) && ($item['network'] == Protocol::DFRN)) {
+ if ((local_user() == $item['uid']) && ($item['private'] == self::PRIVATE) && ($item['contact-id'] != $app->contact['id']) && ($item['network'] == Protocol::DFRN)) {
$img_url = 'redir/' . $item['contact-id'] . '?url=' . urlencode($mtch[1]);
$item['body'] = str_replace($mtch[0], '[img]' . $img_url . '[/img]', $item['body']);
}
$ret["title"] = DI::l10n()->t('link to source');
}
- } elseif (!empty($item['plink']) && ($item['private'] != 1)) {
+ } elseif (!empty($item['plink']) && ($item['private'] != self::PRIVATE)) {
$ret = [
'href' => $item['plink'],
'orig' => $item['plink'],
WHERE `thread`.`visible`
AND NOT `thread`.`deleted`
AND NOT `thread`.`moderated`
- AND NOT `thread`.`private`
+ AND `thread`.`private` = ?
AND t.`uid` = 0
AND t.`otype` = ?
AND t.`type` = ?
GROUP BY `term`
ORDER BY `score` DESC
LIMIT ?",
+ Item::PUBLIC,
Term::OBJECT_TYPE_POST,
Term::HASHTAG,
$period,
FROM `term` t
JOIN `item` i ON i.`id` = t.`oid` AND i.`uid` = t.`uid`
JOIN `thread` ON `thread`.`iid` = i.`id`
- JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
WHERE `thread`.`visible`
AND NOT `thread`.`deleted`
AND NOT `thread`.`moderated`
- AND NOT `thread`.`private`
+ AND `thread`.`private` = ?
AND `thread`.`wall`
AND `thread`.`origin`
AND t.`otype` = ?
GROUP BY `term`
ORDER BY `score` DESC
LIMIT ?",
+ Item::PUBLIC,
Term::OBJECT_TYPE_POST,
Term::HASHTAG,
$period,
$values[] = $itemspage;
- /// @todo Use "unsearchable" here as well (instead of "hidewall")
$r = DBA::p("SELECT `item`.`uri`, `author`.`url` AS `author-link`, `thread`.`commented` FROM `thread`
- STRAIGHT_JOIN `user` ON `user`.`uid` = `thread`.`uid` AND NOT `user`.`hidewall`
STRAIGHT_JOIN `item` ON `item`.`id` = `thread`.`iid`
STRAIGHT_JOIN `contact` AS `author` ON `author`.`id`=`item`.`author-id`
WHERE `thread`.`visible` AND NOT `thread`.`deleted` AND NOT `thread`.`moderated`
- AND NOT `thread`.`private` AND `thread`.`wall` AND `thread`.`origin`
+ AND `thread`.`private` = ? AND `thread`.`wall` AND `thread`.`origin`
$sql_accounttype
$sql_boundaries
ORDER BY `thread`.`commented` DESC
- LIMIT ?", $values);
+ LIMIT ?", Item::PUBLIC, $values);
} elseif (self::$content == 'global') {
if (!is_null(self::$accounttype)) {
- $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable` AND `owner`.`contact-type` = ?", 0, self::$accounttype];
+ $condition = ["`uid` = ? AND `private` = ? AND `owner`.`contact-type` = ?", 0, Item::PUBLIC, self::$accounttype];
} else {
- $condition = ["`uid` = ? AND NOT `author`.`unsearchable` AND NOT `owner`.`unsearchable`", 0];
+ $condition = ["`uid` = ? AND `private` = ?", 0, Item::PUBLIC];
}
if (isset($max_id)) {
'uid', 'title', 'body', 'guid', 'contact-id', 'private', 'created', 'received', 'app', 'location', 'coord', 'network',
'event-id', 'resource-id', 'author-link', 'author-avatar', 'author-name', 'plink', 'owner-link', 'attach'
];
- $condition = ['wall' => true, 'private' => false, 'guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]];
+ $condition = ['wall' => true, 'private' => [Item::PUBLIC, Item::UNLISTED], 'guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]];
$item = Item::selectFirst($fields, $condition);
if (empty($item)) {
$condition = ['guid' => $guid, 'network' => [Protocol::DFRN, Protocol::DIASPORA]];
// At first we try the original post with that guid
// @TODO: Replace with parameter from router
- $item = Item::selectFirst(['id'], ['guid' => $a->argv[1], 'origin' => true, 'private' => false]);
+ $item = Item::selectFirst(['id'], ['guid' => $a->argv[1], 'origin' => true, 'private' => [item::PRIVATE, Item::UNLISTED]]);
if (!DBA::isResult($item)) {
// If no original post could be found, it could possibly be a forum post, there we remove the "origin" field.
// @TODO: Replace with parameter from router
- $item = Item::selectFirst(['id', 'author-link'], ['guid' => $a->argv[1], 'private' => false]);
+ $item = Item::selectFirst(['id', 'author-link'], ['guid' => $a->argv[1], 'private' => [item::PRIVATE, Item::UNLISTED]]);
if (!DBA::isResult($item) || !strstr($item['author-link'], DI::baseUrl()->get())) {
throw new \Friendica\Network\HTTPException\NotFoundException();
}
$conv = $this->getThread();
- $lock = ((($item['private'] == 1) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
+ $lock = ((($item['private'] == Item::PRIVATE) || (($item['uid'] == local_user()) && (strlen($item['allow_cid']) || strlen($item['allow_gid'])
|| strlen($item['deny_cid']) || strlen($item['deny_gid']))))
? DI::l10n()->t('Private Message')
: false);
- $shareable = in_array($conv->getProfileOwner(), [0, local_user()]) && $item['private'] != 1;
+ $shareable = in_array($conv->getProfileOwner(), [0, local_user()]) && $item['private'] != Item::PRIVATE;
$edpost = false;
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;
}
}
$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'])) {
$stored = false;
foreach ($activity['receiver'] as $receiver) {
+ if ($receiver == -1) {
+ continue;
+ }
+
$item['uid'] = $receiver;
if ($isForum) {
}
// 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') {
/**
* 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 = [];
$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]
}
}
- $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:
$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);
$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);
$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);
$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'];
}
}
// 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`
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);
}
}
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 {
$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'];
}
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']) {
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;
// 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)) {
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)) {
$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"];
}
$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"])) {
private static function sendParticipation(array $contact, array $item)
{
// Don't send notifications for private postings
- if ($item['private']) {
+ if ($item['private'] == Item::PRIVATE) {
return;
}
$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,
$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;
$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)) {
{
$item["id"] = $item["parent"] = 0;
$item["created"] = $item["edited"] = date("c");
- $item["private"] = true;
+ $item["private"] = Item::PRIVATE;
$contact = Probe::uri($item['follow']);
]);
}
- 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",
$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` = ? ";
'ostatus' => (object)['@id' => 'http://ostatus.org#', '@type' => '@id'],
'dc' => (object)['@id' => 'http://purl.org/dc/terms/', '@type' => '@id'],
'toot' => (object)['@id' => 'http://joinmastodon.org/ns#', '@type' => '@id'],
- 'litepub' => (object)['@id' => 'http://litepub.social/ns#', '@type' => '@id']];
+ 'litepub' => (object)['@id' => 'http://litepub.social/ns#', '@type' => '@id'],
+ 'sc' => (object)['@id' => 'http://schema.org#', '@type' => '@id'],
+ 'pt' => (object)['@id' => 'https://joinpeertube.org/ns#', '@type' => '@id']];
// Preparation for adding possibly missing content to the context
if (!empty($json['@context']) && is_string($json['@context'])) {
&& empty($parent['allow_gid'])
&& empty($parent['deny_cid'])
&& empty($parent['deny_gid'])
- && !$parent["private"]) {
+ && ($parent["private"] != Model\Item::PRIVATE)) {
$public_message = true;
}
}
// If this is a public conversation, notify the feed hub
$public_message = true;
+ $unlisted = false;
+
// Do a PuSH
$push_notify = false;
Logger::info('Threaded comment', ['diaspora_delivery' => (int)$diaspora_delivery]);
}
+ $unlisted = $target_item['private'] == Item::UNLISTED;
+
// This is IMPORTANT!!!!
// We will only send a "notify owner to relay" or followup message if the referenced post
Logger::info('Followup', ['target' => $target_id, 'guid' => $target_item['guid'], 'to' => $parent['contact-id']]);
- //if (!$target_item['private'] && $target_item['wall'] &&
- if (!$target_item['private'] &&
+ if (($target_item['private'] != Item::PRIVATE) &&
(strlen($target_item['allow_cid'].$target_item['allow_gid'].
$target_item['deny_cid'].$target_item['deny_gid']) == 0))
$push_notify = true;
if ($public_message && !in_array($cmd, [Delivery::MAIL, Delivery::SUGGESTION]) && !$followup) {
$relay_list = [];
- if ($diaspora_delivery) {
+ if ($diaspora_delivery && !$unlisted) {
$batch_delivery = true;
$relay_list_stmt = DBA::p(
$datarray['owner-avatar'] = $contact['photo'];
if ($datarray['parent-uri'] === $datarray['uri']) {
- $datarray['private'] = 1;
+ $datarray['private'] = Item::PRIVATE;
}
if (!DI::pConfig()->get($importer_uid, 'system', 'allow_public_email_replies')) {
- $datarray['private'] = 1;
+ $datarray['private'] = Item::PRIVATE;
$datarray['allow_cid'] = '<' . $contact['id'] . '>';
}
use Friendica\Database\DBA;
if (!defined('DB_UPDATE_VERSION')) {
- define('DB_UPDATE_VERSION', 1333);
+ define('DB_UPDATE_VERSION', 1334);
}
return [
"extid" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""],
"post-type" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "Post type (personal note, bookmark, ...)"],
"global" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
- "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "distribution is restricted"],
+ "private" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => "distribution is restricted"],
"visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"moderated" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "item has been deleted"],
"received" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"changed" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""],
"wall" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
- "private" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
+ "private" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""],
"pubmail" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"moderated" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
"visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""],
{{$hide_wall nofilter}}
+{{$unlisted nofilter}}
+
{{$blockwall nofilter}}
{{$blocktags nofilter}}
{{$hide_wall nofilter}}
+ {{$unlisted nofilter}}
+
{{$blockwall nofilter}}
{{$blocktags nofilter}}