use Friendica\Core\PConfig;
use Friendica\Core\Protocol;
use Friendica\Core\Renderer;
+use Friendica\Core\Session;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
+use Friendica\Protocol\Activity;
use Friendica\Protocol\ActivityPub;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\OStatus;
+use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Map;
use Friendica\Util\Network;
'event-id', 'event-created', 'event-edited', 'event-start', 'event-finish',
'event-summary', 'event-desc', 'event-location', 'event-type',
'event-nofinish', 'event-adjust', 'event-ignore', 'event-id',
- 'delivery_queue_count', 'delivery_queue_done'
+ 'delivery_queue_count', 'delivery_queue_done', 'delivery_queue_failed'
];
// Field list that is used to deliver items via the protocols
// Never reorder or remove entries from this list. Just add new ones at the end, if needed.
// The item-activity table only stores the index and needs this array to know the matching activity.
- const ACTIVITIES = [ACTIVITY_LIKE, ACTIVITY_DISLIKE, ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE, ACTIVITY_FOLLOW, ACTIVITY2_ANNOUNCE];
+ const ACTIVITIES = [
+ Activity::LIKE, Activity::DISLIKE,
+ Activity::ATTEND, Activity::ATTENDNO, Activity::ATTENDMAYBE,
+ Activity::FOLLOW,
+ Activity::ANNOUNCE];
private static $legacy_mode = null;
$row['object'] = '';
}
if (array_key_exists('object-type', $row)) {
- $row['object-type'] = ACTIVITY_OBJ_NOTE;
+ $row['object-type'] = Activity\ObjectType::NOTE;
}
- } elseif (array_key_exists('verb', $row) && in_array($row['verb'], ['', ACTIVITY_POST, ACTIVITY_SHARE])) {
+ } elseif (array_key_exists('verb', $row) && in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) {
// Posts don't have an object or target - but having tags or files.
// We safe some performance by building tag and file strings only here.
// We remove object and target since they aren't used for this type.
}
}
- if (!array_key_exists('verb', $row) || in_array($row['verb'], ['', ACTIVITY_POST, ACTIVITY_SHARE])) {
+ if (!array_key_exists('verb', $row) || in_array($row['verb'], ['', Activity::POST, Activity::SHARE])) {
// Build the tag string out of the term entries
if (array_key_exists('tag', $row) && empty($row['tag'])) {
$row['tag'] = Term::tagTextFromItemId($row['internal-iid']);
}
}
+ /**
+ * @brief Select rows from the item table and returns them as an array
+ *
+ * @param array $selected Array of selected fields, empty for all
+ * @param array $condition Array of fields for condition
+ * @param array $params Array of several parameters
+ *
+ * @return array
+ * @throws \Exception
+ */
+ public static function selectToArray(array $fields = [], array $condition = [], $params = [])
+ {
+ $result = self::select($fields, $condition, $params);
+
+ if (is_bool($result)) {
+ return [];
+ }
+
+ $data = [];
+ while ($row = self::fetch($result)) {
+ $data[] = $row;
+ }
+ DBA::close($result);
+
+ return $data;
+ }
+
/**
* @brief Select rows from the item table
*
// When there is no content for the "old" item table, this will count the fetched items
$rows = DBA::affectedRows();
+ $notify_items = [];
+
while ($item = DBA::fetch($items)) {
if (!empty($item['iaid']) || (!empty($content_fields['verb']) && (self::activityToIndex($content_fields['verb']) >= 0))) {
self::updateActivity($content_fields, ['uri-id' => $item['uri-id']]);
// We only need to notfiy others when it is an original entry from us.
// Only call the notifier when the item has some content relevant change.
if ($item['origin'] && in_array('edited', array_keys($fields))) {
- Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $item['id']);
+ $notify_items[] = $item['id'];
}
}
DBA::close($items);
DBA::commit();
+
+ foreach ($notify_items as $notify_item) {
+ Worker::add(PRIORITY_HIGH, "Notifier", Delivery::POST, $notify_item);
+ }
+
return $rows;
}
private static function deleteTagsFromItem($item)
{
- if (($item["verb"] != ACTIVITY_TAG) || ($item["object-type"] != ACTIVITY_OBJ_TAGTERM)) {
+ if (($item["verb"] != Activity::TAG) || ($item["object-type"] != Activity\ObjectType::TAGTERM)) {
return;
}
$xo = XML::parseString($item["object"], false);
$xt = XML::parseString($item["target"], false);
- if ($xt->type != ACTIVITY_OBJ_NOTE) {
+ if ($xt->type != Activity\ObjectType::NOTE) {
return;
}
private static function contactId($item)
{
- $contact_id = (int)$item["contact-id"];
-
- if (!empty($contact_id)) {
- return $contact_id;
- }
- Logger::log('Missing contact-id. Called by: '.System::callstack(), Logger::DEBUG);
- /*
- * First we are looking for a suitable contact that matches with the author of the post
- * This is done only for comments
- */
- if ($item['parent-uri'] != $item['uri']) {
+ if (!empty($item['contact-id']) && DBA::exists('contact', ['self' => true, 'id' => $item['contact-id']])) {
+ return $item['contact-id'];
+ } elseif (($item['gravity'] == GRAVITY_PARENT) && !empty($item['uid']) && !empty($item['contact-id']) && Contact::isSharing($item['contact-id'], $item['uid'])) {
+ return $item['contact-id'];
+ } elseif (!empty($item['uid']) && !Contact::isSharing($item['author-id'], $item['uid'])) {
+ return $item['author-id'];
+ } elseif (!empty($item['contact-id'])) {
+ return $item['contact-id'];
+ } else {
$contact_id = Contact::getIdForURL($item['author-link'], $item['uid']);
- }
-
- // If not present then maybe the owner was found
- if ($contact_id == 0) {
- $contact_id = Contact::getIdForURL($item['owner-link'], $item['uid']);
- }
-
- // Still missing? Then use the "self" contact of the current user
- if ($contact_id == 0) {
- $self = DBA::selectFirst('contact', ['id'], ['self' => true, 'uid' => $item['uid']]);
- if (DBA::isResult($self)) {
- $contact_id = $self["id"];
+ if (!empty($contact_id)) {
+ return $contact_id;
}
}
- Logger::log("Contact-id was missing for post ".$item['guid']." from user id ".$item['uid']." - now set to ".$contact_id, Logger::DEBUG);
-
- return $contact_id;
+ return $item['author-id'];
}
// This function will finally cover most of the preparation functionality in mod/item.php
*/
}
+ /**
+ * Write an item array into a spool file to be inserted later.
+ * This command is called whenever there are issues storing an item.
+ *
+ * @param array $item The item fields that are to be inserted
+ * @throws \Exception
+ */
+ private static function spool($orig_item)
+ {
+ // Now we store the data in the spool directory
+ // We use "microtime" to keep the arrival order and "mt_rand" to avoid duplicates
+ $file = 'item-' . round(microtime(true) * 10000) . '-' . mt_rand() . '.msg';
+
+ $spoolpath = get_spoolpath();
+ if ($spoolpath != "") {
+ $spool = $spoolpath . '/' . $file;
+
+ file_put_contents($spool, json_encode($orig_item));
+ Logger::warning("Item wasn't stored - Item was spooled into file", ['file' => $file]);
+ }
+ }
+
public static function insert($item, $force_parent = false, $notify = false, $dontcache = false)
{
$orig_item = $item;
$priority = $notify;
}
} else {
- $item['network'] = trim(defaults($item, 'network', Protocol::PHANTOM));
+ $item['network'] = trim(($item['network'] ?? '') ?: Protocol::PHANTOM);
}
$item['guid'] = self::guid($item, $notify);
- $item['uri'] = Strings::escapeTags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid']))));
+ $item['uri'] = Strings::escapeTags(trim(($item['uri'] ?? '') ?: self::newURI($item['uid'], $item['guid'])));
// Store URI data
$item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]);
$item['parent-uri'] = $item['thr-parent'];
}
+ /** @var Activity $activity */
+ $activity = self::getClass(Activity::class);
+
if (isset($item['gravity'])) {
$item['gravity'] = intval($item['gravity']);
} elseif ($item['parent-uri'] === $item['uri']) {
$item['gravity'] = GRAVITY_PARENT;
- } elseif (activity_match($item['verb'], ACTIVITY_POST)) {
+ } elseif ($activity->match($item['verb'], Activity::POST)) {
$item['gravity'] = GRAVITY_COMMENT;
- } elseif (activity_match($item['verb'], ACTIVITY_FOLLOW)) {
+ } elseif ($activity->match($item['verb'], Activity::FOLLOW)) {
$item['gravity'] = GRAVITY_ACTIVITY;
} else {
$item['gravity'] = GRAVITY_UNKNOWN; // Should not happen
* via OStatus (maybe Diasporsa as well)
*/
if (empty($item['network']) || in_array($item['network'], Protocol::FEDERATED)) {
- $condition = ["`uri` = ? AND `uid` = ? AND `network` IN (?, ?, ?)",
+ $condition = ["`uri` = ? AND `uid` = ? AND `network` IN (?, ?, ?, ?)",
trim($item['uri']), $item['uid'],
- Protocol::DIASPORA, Protocol::DFRN, Protocol::OSTATUS];
+ Protocol::ACTIVITYPUB, Protocol::DIASPORA, Protocol::DFRN, Protocol::OSTATUS];
$existing = self::selectFirst(['id', 'network'], $condition);
if (DBA::isResult($existing)) {
// We only log the entries with a different user id than 0. Otherwise we would have too many false positives
}
}
- $item['wall'] = intval(defaults($item, 'wall', 0));
- $item['extid'] = trim(defaults($item, 'extid', ''));
- $item['author-name'] = trim(defaults($item, 'author-name', ''));
- $item['author-link'] = trim(defaults($item, 'author-link', ''));
- $item['author-avatar'] = trim(defaults($item, 'author-avatar', ''));
- $item['owner-name'] = trim(defaults($item, 'owner-name', ''));
- $item['owner-link'] = trim(defaults($item, 'owner-link', ''));
- $item['owner-avatar'] = trim(defaults($item, 'owner-avatar', ''));
+ $item['wall'] = intval($item['wall'] ?? 0);
+ $item['extid'] = trim($item['extid'] ?? '');
+ $item['author-name'] = trim($item['author-name'] ?? '');
+ $item['author-link'] = trim($item['author-link'] ?? '');
+ $item['author-avatar'] = trim($item['author-avatar'] ?? '');
+ $item['owner-name'] = trim($item['owner-name'] ?? '');
+ $item['owner-link'] = trim($item['owner-link'] ?? '');
+ $item['owner-avatar'] = trim($item['owner-avatar'] ?? '');
$item['received'] = (isset($item['received']) ? DateTimeFormat::utc($item['received']) : DateTimeFormat::utcNow());
$item['created'] = (isset($item['created']) ? DateTimeFormat::utc($item['created']) : $item['received']);
$item['edited'] = (isset($item['edited']) ? DateTimeFormat::utc($item['edited']) : $item['created']);
$item['changed'] = (isset($item['changed']) ? DateTimeFormat::utc($item['changed']) : $item['created']);
$item['commented'] = (isset($item['commented']) ? DateTimeFormat::utc($item['commented']) : $item['created']);
- $item['title'] = trim(defaults($item, 'title', ''));
- $item['location'] = trim(defaults($item, 'location', ''));
- $item['coord'] = trim(defaults($item, 'coord', ''));
+ $item['title'] = trim($item['title'] ?? '');
+ $item['location'] = trim($item['location'] ?? '');
+ $item['coord'] = trim($item['coord'] ?? '');
$item['visible'] = (isset($item['visible']) ? intval($item['visible']) : 1);
$item['deleted'] = 0;
- $item['parent-uri'] = trim(defaults($item, 'parent-uri', $item['uri']));
- $item['post-type'] = defaults($item, 'post-type', self::PT_ARTICLE);
- $item['verb'] = trim(defaults($item, 'verb', ''));
- $item['object-type'] = trim(defaults($item, 'object-type', ''));
- $item['object'] = trim(defaults($item, 'object', ''));
- $item['target-type'] = trim(defaults($item, 'target-type', ''));
- $item['target'] = trim(defaults($item, 'target', ''));
- $item['plink'] = trim(defaults($item, 'plink', ''));
- $item['allow_cid'] = trim(defaults($item, 'allow_cid', ''));
- $item['allow_gid'] = trim(defaults($item, 'allow_gid', ''));
- $item['deny_cid'] = trim(defaults($item, 'deny_cid', ''));
- $item['deny_gid'] = trim(defaults($item, 'deny_gid', ''));
- $item['private'] = intval(defaults($item, 'private', 0));
- $item['body'] = trim(defaults($item, 'body', ''));
- $item['tag'] = trim(defaults($item, 'tag', ''));
- $item['attach'] = trim(defaults($item, 'attach', ''));
- $item['app'] = trim(defaults($item, 'app', ''));
- $item['origin'] = intval(defaults($item, 'origin', 0));
- $item['postopts'] = trim(defaults($item, 'postopts', ''));
- $item['resource-id'] = trim(defaults($item, 'resource-id', ''));
- $item['event-id'] = intval(defaults($item, 'event-id', 0));
- $item['inform'] = trim(defaults($item, 'inform', ''));
- $item['file'] = trim(defaults($item, 'file', ''));
+ $item['parent-uri'] = trim(($item['parent-uri'] ?? '') ?: $item['uri']);
+ $item['post-type'] = ($item['post-type'] ?? '') ?: self::PT_ARTICLE;
+ $item['verb'] = trim($item['verb'] ?? '');
+ $item['object-type'] = trim($item['object-type'] ?? '');
+ $item['object'] = trim($item['object'] ?? '');
+ $item['target-type'] = trim($item['target-type'] ?? '');
+ $item['target'] = trim($item['target'] ?? '');
+ $item['plink'] = trim($item['plink'] ?? '');
+ $item['allow_cid'] = trim($item['allow_cid'] ?? '');
+ $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['body'] = trim($item['body'] ?? '');
+ $item['tag'] = trim($item['tag'] ?? '');
+ $item['attach'] = trim($item['attach'] ?? '');
+ $item['app'] = trim($item['app'] ?? '');
+ $item['origin'] = intval($item['origin'] ?? 0);
+ $item['postopts'] = trim($item['postopts'] ?? '');
+ $item['resource-id'] = trim($item['resource-id'] ?? '');
+ $item['event-id'] = intval($item['event-id'] ?? 0);
+ $item['inform'] = trim($item['inform'] ?? '');
+ $item['file'] = trim($item['file'] ?? '');
// When there is no content then we don't post it
if ($item['body'].$item['title'] == '') {
$item['edited'] = DateTimeFormat::utcNow();
}
- $item['plink'] = defaults($item, 'plink', System::baseUrl() . '/display/' . urlencode($item['guid']));
-
- // The contact-id should be set before "self::insert" was called - but there seems to be issues sometimes
- $item["contact-id"] = self::contactId($item);
+ $item['plink'] = ($item['plink'] ?? '') ?: System::baseUrl() . '/display/' . urlencode($item['guid']);
$default = ['url' => $item['author-link'], 'name' => $item['author-name'],
'photo' => $item['author-avatar'], 'network' => $item['network']];
- $item['author-id'] = defaults($item, 'author-id', Contact::getIdForURL($item['author-link'], 0, false, $default));
+ $item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, false, $default);
if (Contact::isBlocked($item['author-id'])) {
Logger::notice('Author is blocked node-wide', ['author-link' => $item['author-link'], 'item-uri' => $item['uri']]);
$default = ['url' => $item['owner-link'], 'name' => $item['owner-name'],
'photo' => $item['owner-avatar'], 'network' => $item['network']];
- $item['owner-id'] = defaults($item, 'owner-id', Contact::getIdForURL($item['owner-link'], 0, false, $default));
+ $item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, false, $default);
if (Contact::isBlocked($item['owner-id'])) {
Logger::notice('Owner is blocked node-wide', ['owner-link' => $item['owner-link'], 'item-uri' => $item['uri']]);
unset($item['causer-id']);
unset($item['causer-link']);
+ // The contact-id should be set before "self::insert" was called - but there seems to be issues sometimes
+ $item["contact-id"] = self::contactId($item);
+
if ($item['network'] == Protocol::PHANTOM) {
$item['network'] = Protocol::DFRN;
Logger::notice('Missing network, setting to {network}.', [
return 0;
}
- if ($item['verb'] == ACTIVITY_FOLLOW) {
+ if ($item['verb'] == Activity::FOLLOW) {
if (!$item['origin'] && ($item['author-id'] == Contact::getPublicIdByUserId($uid))) {
// Our own follow request can be relayed to us. We don't store it to avoid notification chaos.
Logger::log("Follow: Don't store not origin follow request from us for " . $item['parent-uri'], Logger::DEBUG);
return 0;
}
- $condition = ['verb' => ACTIVITY_FOLLOW, 'uid' => $item['uid'],
+ $condition = ['verb' => Activity::FOLLOW, 'uid' => $item['uid'],
'parent-uri' => $item['parent-uri'], 'author-id' => $item['author-id']];
if (self::exists($condition)) {
// It happens that we receive multiple follow requests by the same author - we only store one.
}
}
- if (stristr($item['verb'], ACTIVITY_POKE)) {
+ if (stristr($item['verb'], Activity::POKE)) {
$notify_type = Delivery::POKE;
}
unset($item['owner-name']);
unset($item['owner-avatar']);
+ $like_no_comment = Config::get('system', 'like_no_comment');
+
DBA::transaction();
$ret = DBA::insert('item', $item);
DBA::rollback();
// Store the data into a spool file so that we can try again later.
-
- // At first we restore the Diaspora signature that we removed above.
- if (isset($encoded_signature)) {
- $item['dsprsig'] = $encoded_signature;
- }
-
- // Now we store the data in the spool directory
- // We use "microtime" to keep the arrival order and "mt_rand" to avoid duplicates
- $file = 'item-'.round(microtime(true) * 10000).'-'.mt_rand().'.msg';
-
- $spoolpath = get_spoolpath();
- if ($spoolpath != "") {
- $spool = $spoolpath.'/'.$file;
-
- file_put_contents($spool, json_encode($orig_item));
- Logger::log("Item wasn't stored - Item was spooled into file ".$file, Logger::DEBUG);
- }
+ self::spool($orig_item);
return 0;
}
}
Logger::log('created item '.$current_post);
- self::updateContact($item);
if (!$parent_id || ($item['parent-uri'] === $item['uri'])) {
$parent_id = $current_post;
// update the commented timestamp on the parent
// Only update "commented" if it is really a comment
- if (($item['gravity'] != GRAVITY_ACTIVITY) || !Config::get("system", "like_no_comment")) {
+ if (($item['gravity'] != GRAVITY_ACTIVITY) || !$like_no_comment) {
DBA::update('item', ['commented' => DateTimeFormat::utcNow(), 'changed' => DateTimeFormat::utcNow()], ['id' => $parent_id]);
} else {
DBA::update('item', ['changed' => DateTimeFormat::utcNow()], ['id' => $parent_id]);
DBA::insert('diaspora-interaction', ['uri-id' => $item['uri-id'], 'interaction' => $diaspora_signed_text], true);
}
- self::tagDeliver($item['uid'], $current_post);
-
- /*
- * current post can be deleted if is for a community page and no mention are
- * in it.
- */
- if (!$dontcache) {
- $posted_item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $current_post]);
- if (DBA::isResult($posted_item)) {
- if ($notify) {
- Hook::callAll('post_local_end', $posted_item);
- } else {
- Hook::callAll('post_remote_end', $posted_item);
- }
- } else {
- Logger::log('new item not found in DB, id ' . $current_post);
- }
- }
-
if ($item['parent-uri'] === $item['uri']) {
self::addThread($current_post);
} else {
Term::insertFromFileFieldByItemId($current_post, $files);
}
+ // In that function we check if this is a forum post. Additionally we delete the item under certain circumstances
+ if (self::tagDeliver($item['uid'], $current_post)) {
+ // Get the user information for the logging
+ $user = User::getById($uid);
+
+ Logger::notice('Item had been deleted', ['id' => $current_post, 'user' => $uid, 'account-type' => $user['account-type']]);
+ return 0;
+ }
+
+ if (!$dontcache) {
+ $posted_item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $current_post]);
+ if (DBA::isResult($posted_item)) {
+ if ($notify) {
+ Hook::callAll('post_local_end', $posted_item);
+ } else {
+ Hook::callAll('post_remote_end', $posted_item);
+ }
+ } else {
+ Logger::log('new item not found in DB, id ' . $current_post);
+ }
+ }
+
if ($item['parent-uri'] === $item['uri']) {
self::addShadow($current_post);
} else {
self::addShadowPost($current_post);
}
+ self::updateContact($item);
+
check_user_notification($current_post);
if ($notify || ($item['visible'] && ((!empty($parent) && $parent['origin']) || $item['origin']))) {
Contact::unmarkForArchival($contact);
}
- $update = (!$arr['private'] && ((defaults($arr, 'author-link', '') === defaults($arr, 'owner-link', '')) || ($arr["parent-uri"] === $arr["uri"])));
+ $update = (!$arr['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"])) {
*
* @param int $uid
* @param int $item_id
- * @return void true if item was deleted, else false
+ * @return boolean true if item was deleted, else false
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException
*/
$user = DBA::selectFirst('user', [], ['uid' => $uid]);
if (!DBA::isResult($user)) {
- return;
+ return false;
}
$community_page = (($user['page-flags'] == User::PAGE_FLAGS_COMMUNITY) ? true : false);
$item = self::selectFirst(self::ITEM_FIELDLIST, ['id' => $item_id]);
if (!DBA::isResult($item)) {
- return;
+ return false;
}
$link = Strings::normaliseLink(System::baseUrl() . '/profile/' . $user['nickname']);
DBA::delete('item', ['id' => $item_id]);
return true;
}
- return;
+ return false;
}
$arr = ['item' => $item, 'user' => $user];
Hook::callAll('tagged', $arr);
if (!$community_page && !$prvgroup) {
- return;
+ return false;
}
/*
* if the message originated elsewhere and is a top-level post
*/
if ($item['wall'] || $item['origin'] || ($item['id'] != $item['parent'])) {
- return;
+ return false;
}
// now change this copy of the post to a forum head message and deliver to all the tgroup members
$self = DBA::selectFirst('contact', ['id', 'name', 'url', 'thumb'], ['uid' => $uid, 'self' => true]);
if (!DBA::isResult($self)) {
- return;
+ return false;
}
$owner_id = Contact::getIdForURL($self['url']);
self::updateThread($item_id);
Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], 'Notifier', Delivery::POST, $item_id);
+
+ return false;
}
public static function isRemoteSelf($contact, &$datarray)
}
// Only forward posts
- if ($datarray["verb"] != ACTIVITY_POST) {
+ if ($datarray["verb"] != Activity::POST) {
Logger::log('No post', Logger::DEBUG);
return false;
}
$replace = true;
}
} elseif ($item) {
- if (self::samePermissions($item, $photo)) {
+ if (self::samePermissions($uid, $item, $photo)) {
$replace = true;
}
}
!empty($obj['deny_cid']) || !empty($obj['deny_gid']);
}
- private static function samePermissions($obj1, $obj2)
+ private static function samePermissions($uid, $obj1, $obj2)
{
// first part is easy. Check that these are exactly the same.
if (($obj1['allow_cid'] == $obj2['allow_cid'])
return ($recipients1 == $recipients2);
}
- // returns an array of contact-ids that are allowed to see this object
- public static function enumeratePermissions($obj)
+ /**
+ * Returns an array of contact-ids that are allowed to see this object
+ *
+ * @param array $obj Item array with at least uid, allow_cid, allow_gid, deny_cid and deny_gid
+ * @param bool $check_dead Prunes unavailable contacts from the result
+ * @return array
+ * @throws \Exception
+ */
+ public static function enumeratePermissions(array $obj, bool $check_dead = false)
{
- $allow_people = expand_acl($obj['allow_cid']);
- $allow_groups = Group::expand(expand_acl($obj['allow_gid']));
- $deny_people = expand_acl($obj['deny_cid']);
- $deny_groups = Group::expand(expand_acl($obj['deny_gid']));
+ /** @var ACLFormatter $aclFormater */
+ $aclFormater = self::getClass(ACLFormatter::class);
+
+ $allow_people = $aclFormater->expand($obj['allow_cid'] ?? '');
+ $allow_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['allow_gid'] ?? ''), $check_dead);
+ $deny_people = $aclFormater->expand($obj['deny_cid'] ?? '');
+ $deny_groups = Group::expand($obj['uid'], $aclFormater->expand($obj['deny_gid'] ?? ''), $check_dead);
$recipients = array_unique(array_merge($allow_people, $allow_groups));
$deny = array_unique(array_merge($deny_people, $deny_groups));
$recipients = array_diff($recipients, $deny);
*/
public static function performLike($item_id, $verb)
{
- if (!local_user() && !remote_user()) {
+ if (!Session::isAuthenticated()) {
return false;
}
switch ($verb) {
case 'like':
case 'unlike':
- $activity = ACTIVITY_LIKE;
+ $activity = Activity::LIKE;
break;
case 'dislike':
case 'undislike':
- $activity = ACTIVITY_DISLIKE;
+ $activity = Activity::DISLIKE;
break;
case 'attendyes':
case 'unattendyes':
- $activity = ACTIVITY_ATTEND;
+ $activity = Activity::ATTEND;
break;
case 'attendno':
case 'unattendno':
- $activity = ACTIVITY_ATTENDNO;
+ $activity = Activity::ATTENDNO;
break;
case 'attendmaybe':
case 'unattendmaybe':
- $activity = ACTIVITY_ATTENDMAYBE;
+ $activity = Activity::ATTENDMAYBE;
break;
default:
Logger::log('like: unknown verb ' . $verb . ' for item ' . $item_id);
}
// Enable activity toggling instead of on/off
- $event_verb_flag = $activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE;
+ $event_verb_flag = $activity === Activity::ATTEND || $activity === Activity::ATTENDNO || $activity === Activity::ATTENDMAYBE;
Logger::log('like: verb ' . $verb . ' item ' . $item_id);
// event participation are essentially radio toggles. If you make a subsequent choice,
// we need to eradicate your first choice.
if ($event_verb_flag) {
- $verbs = [ACTIVITY_ATTEND, ACTIVITY_ATTENDNO, ACTIVITY_ATTENDMAYBE];
+ $verbs = [Activity::ATTEND, Activity::ATTENDNO, Activity::ATTENDMAYBE];
// Translate to the index based activity index
$activities = [];
return true;
}
- $objtype = $item['resource-id'] ? ACTIVITY_OBJ_IMAGE : ACTIVITY_OBJ_NOTE;
+ $objtype = $item['resource-id'] ? Activity\ObjectType::IMAGE : Activity\ObjectType::NOTE;
$new_item = [
'guid' => System::createUUID(),
}
}
- public static function getPermissionsSQLByUserId($owner_id, $remote_verified = false, $groups = null, $remote_cid = null)
+ public static function getPermissionsSQLByUserId($owner_id)
{
$local_user = local_user();
- $remote_user = remote_user();
+ $remote_user = Session::getRemoteContactID($owner_id);
/*
* Construct permissions
* If pre-verified, the caller is expected to have already
* done this and passed the groups into this function.
*/
- $set = PermissionSet::get($owner_id, $remote_cid, $groups);
+ $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) . "))";
return L10n::t('event');
} elseif (!empty($item['resource-id'])) {
return L10n::t('photo');
- } elseif (!empty($item['verb']) && $item['verb'] !== ACTIVITY_POST) {
+ } elseif (!empty($item['verb']) && $item['verb'] !== Activity::POST) {
return L10n::t('activity');
} elseif ($item['id'] != $item['parent']) {
return L10n::t('comment');
{
$body = $item["body"];
- $rendered_hash = defaults($item, 'rendered-hash', '');
- $rendered_html = defaults($item, 'rendered-html', '');
+ $rendered_hash = $item['rendered-hash'] ?? '';
+ $rendered_html = $item['rendered-html'] ?? '';
if ($rendered_hash == ''
|| $rendered_html == ""
|| $rendered_hash != hash("md5", $item["body"])
|| Config::get("system", "ignore_cache")
) {
- $a = self::getApp();
- redir_private_images($a, $item);
+ self::addRedirToImageTags($item);
- $item["rendered-html"] = prepare_text($item["body"]);
+ $item["rendered-html"] = BBCode::convert($item["body"]);
$item["rendered-hash"] = hash("md5", $item["body"]);
$hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']];
$item["body"] = $body;
}
+ /**
+ * @brief Find any non-embedded images in private items and add redir links to them
+ *
+ * @param array &$item The field array of an item row
+ */
+ private static function addRedirToImageTags(array &$item)
+ {
+ $app = self::getApp();
+
+ $matches = [];
+ $cnt = preg_match_all('|\[img\](http[^\[]*?/photo/[a-fA-F0-9]+?(-[0-9]\.[\w]+?)?)\[\/img\]|', $item['body'], $matches, PREG_SET_ORDER);
+ if ($cnt) {
+ foreach ($matches as $mtch) {
+ if (strpos($mtch[1], '/redir') !== false) {
+ continue;
+ }
+
+ if ((local_user() == $item['uid']) && ($item['private'] == 1) && ($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']);
+ }
+ }
+ }
+ }
+
/**
* @brief Given an item array, convert the body element from bbcode to html and add smilie icons.
* If attach is true, also add icons for item attachments.
// In order to provide theme developers more possibilities, event items
// are treated differently.
- if ($item['object-type'] === ACTIVITY_OBJ_EVENT && isset($item['event-id'])) {
+ if ($item['object-type'] === Activity\ObjectType::EVENT && isset($item['event-id'])) {
$ev = Event::getItemHTML($item);
return $ev;
}
}
// Update the cached values if there is no "zrl=..." on the links.
- $update = (!local_user() && !remote_user() && ($item["uid"] == 0));
+ $update = (!Session::isAuthenticated() && ($item["uid"] == 0));
// Or update it if the current viewer is the intented viewer.
if (($item["uid"] == local_user()) && ($item["uid"] != 0)) {
$filesubtype = 'unkn';
}
- $title = Strings::escapeHtml(trim(defaults($mtch, 4, $mtch[1])));
+ $title = Strings::escapeHtml(trim(($mtch[4] ?? '') ?: $mtch[1]));
$title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes');
$icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
}
}
-
- // Look for spoiler.
- $spoilersearch = '<blockquote class="spoiler">';
-
- // Remove line breaks before the spoiler.
- while ((strpos($s, "\n" . $spoilersearch) !== false)) {
- $s = str_replace("\n" . $spoilersearch, $spoilersearch, $s);
- }
- while ((strpos($s, "<br />" . $spoilersearch) !== false)) {
- $s = str_replace("<br />" . $spoilersearch, $spoilersearch, $s);
- }
-
- while ((strpos($s, $spoilersearch) !== false)) {
- $pos = strpos($s, $spoilersearch);
- $rnd = Strings::getRandomHex(8);
- $spoilerreplace = '<br /> <span id="spoiler-wrap-' . $rnd . '" class="spoiler-wrap fakelink" onclick="openClose(\'spoiler-' . $rnd . '\');">' . L10n::t('Click to open/close') . '</span>'.
- '<blockquote class="spoiler" id="spoiler-' . $rnd . '" style="display: none;">';
- $s = substr($s, 0, $pos) . $spoilerreplace . substr($s, $pos + strlen($spoilersearch));
- }
-
- // Look for quote with author.
- $authorsearch = '<blockquote class="author">';
-
- while ((strpos($s, $authorsearch) !== false)) {
- $pos = strpos($s, $authorsearch);
- $rnd = Strings::getRandomHex(8);
- $authorreplace = '<br /> <span id="author-wrap-' . $rnd . '" class="author-wrap fakelink" onclick="openClose(\'author-' . $rnd . '\');">' . L10n::t('Click to open/close') . '</span>'.
- '<blockquote class="author" id="author-' . $rnd . '" style="display: block;">';
- $s = substr($s, 0, $pos) . $authorreplace . substr($s, $pos + strlen($authorsearch));
- }
-
// Replace friendica image url size with theme preference.
if (!empty($a->theme_info['item_image_size'])) {
$ps = $a->theme_info['item_image_size'];