use Friendica\Util\Strings;
use Text_LanguageDetect;
-require_once 'boot.php';
-require_once 'include/items.php';
-require_once 'include/text.php';
-
class Item extends BaseObject
{
// Posting types, inspired by https://www.w3.org/TR/activitystreams-vocabulary/#object-types
const PT_PERSONAL_NOTE = 128;
// Field list that is used to display the items
- const DISPLAY_FIELDLIST = ['uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid', 'network',
- 'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink',
- 'wall', 'private', 'starred', 'origin', 'title', 'body', 'file', 'attach', 'language',
- 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object',
- 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'item_id',
- 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network',
- 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network',
- 'contact-id', 'contact-link', 'contact-name', 'contact-avatar',
- 'writable', 'self', 'cid', 'alias',
- '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'];
+ const DISPLAY_FIELDLIST = [
+ 'uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid', 'network',
+ 'commented', 'created', 'edited', 'received', 'verb', 'object-type', 'postopts', 'plink',
+ 'wall', 'private', 'starred', 'origin', 'title', 'body', 'file', 'attach', 'language',
+ 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object',
+ 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'item_id',
+ 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network',
+ 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network',
+ 'contact-id', 'contact-link', 'contact-name', 'contact-avatar',
+ 'writable', 'self', 'cid', 'alias',
+ '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'
+ ];
// Field list that is used to deliver items via the protocols
const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri', 'thr-parent', 'parent-uri', 'guid',
// Field list for "item-content" table that is not present in the "item" table
const CONTENT_FIELDLIST = ['language'];
- // Field list for additional delivery data
- const DELIVERY_DATA_FIELDLIST = ['postopts', 'inform'];
-
// All fields in the item table
const ITEM_FIELDLIST = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', 'guid',
'contact-id', 'type', 'wall', 'gravity', 'extid', 'icid', 'iaid', 'psid',
// Fetch data from the item-content table whenever there is content there
if (self::isLegacyMode()) {
- $legacy_fields = array_merge(self::DELIVERY_DATA_FIELDLIST, self::MIXED_CONTENT_FIELDLIST);
+ $legacy_fields = array_merge(ItemDeliveryData::FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
foreach ($legacy_fields as $field) {
if (empty($row[$field]) && !empty($row['internal-item-' . $field])) {
$row[$field] = $row['internal-item-' . $field];
$fields['item-content'] = array_merge(self::CONTENT_FIELDLIST, self::MIXED_CONTENT_FIELDLIST);
- $fields['item-delivery-data'] = self::DELIVERY_DATA_FIELDLIST;
+ $fields['item-delivery-data'] = array_merge(ItemDeliveryData::LEGACY_FIELD_LIST, ItemDeliveryData::FIELD_LIST);
$fields['permissionset'] = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
foreach ($fields as $table => $table_fields) {
foreach ($table_fields as $field => $select) {
if (empty($selected) || in_array($select, $selected)) {
- $legacy_fields = array_merge(self::DELIVERY_DATA_FIELDLIST, self::MIXED_CONTENT_FIELDLIST);
+ $legacy_fields = array_merge(ItemDeliveryData::LEGACY_FIELD_LIST, self::MIXED_CONTENT_FIELDLIST);
if (self::isLegacyMode() && in_array($select, $legacy_fields)) {
$selection[] = "`item`.`".$select."` AS `internal-item-" . $select . "`";
}
}
}
- $clear_fields = ['bookmark', 'type', 'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link'];
+ $delivery_data = ItemDeliveryData::extractFields($fields);
+
+ $clear_fields = ['bookmark', 'type', 'author-name', 'author-avatar', 'author-link', 'owner-name', 'owner-avatar', 'owner-link', 'postopts', 'inform'];
foreach ($clear_fields as $field) {
if (array_key_exists($field, $fields)) {
$fields[$field] = null;
$files = $fields['file'];
$fields['file'] = null;
} else {
- $files = '';
+ $files = null;
}
- $delivery_data = ['postopts' => defaults($fields, 'postopts', ''),
- 'inform' => defaults($fields, 'inform', '')];
-
- $fields['postopts'] = null;
- $fields['inform'] = null;
-
if (!empty($fields)) {
$success = DBA::update('item', $fields, $condition);
}
}
- if (!empty($files)) {
+ if (!is_null($files)) {
Term::insertFromFileFieldByItemId($item['id'], $files);
if (!empty($item['file'])) {
DBA::update('item', ['file' => ''], ['id' => $item['id']]);
}
}
- self::updateDeliveryData($item['id'], $delivery_data);
+ ItemDeliveryData::update($item['id'], $delivery_data);
self::updateThread($item['id']);
$matches = false;
$cnt = preg_match_all('/<(.*?)>/', $item['file'], $matches, PREG_SET_ORDER);
- if ($cnt)
- {
- foreach ($matches as $mtch)
- {
+ if ($cnt) {
+ foreach ($matches as $mtch) {
FileTag::unsaveFile($item['uid'], $item['id'], $mtch[1],true);
}
}
$cnt = preg_match_all('/\[(.*?)\]/', $item['file'], $matches, PREG_SET_ORDER);
- if ($cnt)
- {
- foreach ($matches as $mtch)
- {
+ if ($cnt) {
+ foreach ($matches as $mtch) {
FileTag::unsaveFile($item['uid'], $item['id'], $mtch[1],false);
}
}
* generate a resource-id and therefore aren't intimately linked to the item.
*/
if (strlen($item['resource-id'])) {
- DBA::delete('photo', ['resource-id' => $item['resource-id'], 'uid' => $item['uid']]);
+ Photo::delete(['resource-id' => $item['resource-id'], 'uid' => $item['uid']]);
}
// If item is a link to an event, delete the event.
self::delete(['uri' => $item['uri'], 'uid' => 0, 'deleted' => false], $priority);
}
- DBA::delete('item-delivery-data', ['iid' => $item['id']]);
+ ItemDeliveryData::delete($item['id']);
// We don't delete the item-activity here, since we need some of the data for ActivityPub
private static function guid($item, $notify)
{
if (!empty($item['guid'])) {
- return Strings::removeTags(trim($item['guid']));
+ return Strings::escapeTags(trim($item['guid']));
}
if ($notify) {
// We have to avoid duplicates. So we create the GUID in form of a hash of the plink or uri.
// We add the hash of our own host because our host is the original creator of the post.
- $prefix_host = get_app()->getHostName();
+ $prefix_host = \get_app()->getHostName();
} else {
$prefix_host = '';
public static function insert($item, $force_parent = false, $notify = false, $dontcache = false)
{
- $a = get_app();
+ $orig_item = $item;
// If it is a posting where users should get notifications, then define it as wall posting
if ($notify) {
}
$item['guid'] = self::guid($item, $notify);
- $item['uri'] = Strings::removeTags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid']))));
+ $item['uri'] = Strings::escapeTags(trim(defaults($item, 'uri', self::newURI($item['uid'], $item['guid']))));
// Store URI data
$item['uri-id'] = ItemURI::insert(['uri' => $item['uri'], 'guid' => $item['guid']]);
$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['received'] = ((x($item, 'received') !== false) ? DateTimeFormat::utc($item['received']) : DateTimeFormat::utcNow());
- $item['created'] = ((x($item, 'created') !== false) ? DateTimeFormat::utc($item['created']) : $item['received']);
- $item['edited'] = ((x($item, 'edited') !== false) ? DateTimeFormat::utc($item['edited']) : $item['created']);
- $item['changed'] = ((x($item, 'changed') !== false) ? DateTimeFormat::utc($item['changed']) : $item['created']);
- $item['commented'] = ((x($item, 'commented') !== false) ? DateTimeFormat::utc($item['commented']) : $item['created']);
+ $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['visible'] = ((x($item, 'visible') !== false) ? intval($item['visible']) : 1);
+ $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);
// It is mainly used in the "post_local" hook.
unset($item['api_source']);
- if (x($item, 'cancel')) {
+ if (!empty($item['cancel'])) {
Logger::log('post cancelled by addon.');
return 0;
}
self::insertContent($item);
}
- $delivery_data = ['postopts' => defaults($item, 'postopts', ''),
- 'inform' => defaults($item, 'inform', '')];
+ $delivery_data = ItemDeliveryData::extractFields($item);
unset($item['postopts']);
unset($item['inform']);
if ($spoolpath != "") {
$spool = $spoolpath.'/'.$file;
- // Ensure to have the removed data from above again in the item array
- $item = array_merge($item, $delivery_data);
-
- file_put_contents($spool, json_encode($item));
+ file_put_contents($spool, json_encode($orig_item));
Logger::log("Item wasn't stored - Item was spooled into file ".$file, Logger::DEBUG);
}
return 0;
self::updateThread($parent_id);
}
- $delivery_data['iid'] = $current_post;
-
- self::insertDeliveryData($delivery_data);
+ ItemDeliveryData::insert($current_post, $delivery_data);
DBA::commit();
return $current_post;
}
- /**
- * @brief Insert a new item delivery data entry
- *
- * @param array $item The item fields that are to be inserted
- */
- private static function insertDeliveryData($delivery_data)
- {
- if (empty($delivery_data['iid']) || (empty($delivery_data['postopts']) && empty($delivery_data['inform']))) {
- return;
- }
-
- DBA::insert('item-delivery-data', $delivery_data);
- }
-
- /**
- * @brief Update an existing item delivery data entry
- *
- * @param integer $id The item id that is to be updated
- * @param array $item The item fields that are to be inserted
- */
- private static function updateDeliveryData($id, $delivery_data)
- {
- if (empty($id) || (empty($delivery_data['postopts']) && empty($delivery_data['inform']))) {
- return;
- }
-
- DBA::update('item-delivery-data', $delivery_data, ['iid' => $id], true);
- }
-
/**
* @brief Insert a new item content entry
*
* @param array $item The item fields that are to be inserted
+ * @return bool
*/
private static function insertActivity(&$item)
{
$update = (!$arr['private'] && ((defaults($arr, 'author-link', '') === defaults($arr, 'owner-link', '')) || ($arr["parent-uri"] === $arr["uri"])));
// Is it a forum? Then we don't care about the rules from above
- if (!$update && ($arr["network"] == Protocol::DFRN) && ($arr["parent-uri"] === $arr["uri"])) {
+ if (!$update && in_array($arr["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN]) && ($arr["parent-uri"] === $arr["uri"])) {
if (DBA::exists('contact', ['id' => $arr['contact-id'], 'forum' => true])) {
$update = true;
}
$basetag = str_replace('_',' ',substr($tag,1));
- $newtag = '#[url=' . System::baseUrl() . '/search?tag=' . rawurlencode($basetag) . ']' . $basetag . '[/url]';
+ $newtag = '#[url=' . System::baseUrl() . '/search?tag=' . $basetag . ']' . $basetag . '[/url]';
$item["body"] = str_replace($tag, $newtag, $item["body"]);
if (!stristr($item["tag"], "/search?tag=" . $basetag . "]" . $basetag . "[/url]")) {
if (strlen($item["tag"])) {
- $item["tag"] = ','.$item["tag"];
+ $item["tag"] = ',' . $item["tag"];
}
- $item["tag"] = $newtag.$item["tag"];
+ $item["tag"] = $newtag . $item["tag"];
}
}
public static function isRemoteSelf($contact, &$datarray)
{
- $a = get_app();
+ $a = \get_app();
if (!$contact['remote_self']) {
return false;
if ($x) {
$res = substr($i, $x + 1);
$i = substr($i, 0, $x);
- $fields = ['data', 'type', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
- $photo = DBA::selectFirst('photo', $fields, ['resource-id' => $i, 'scale' => $res, 'uid' => $uid]);
+ $photo = Photo::getPhotoForUser($uid, $i, $res);
if (DBA::isResult($photo)) {
/*
* Check to see if we should replace this photo link with an embedded image
}
}
if ($replace) {
- $data = $photo['data'];
- $type = $photo['type'];
-
+ $photo_img = Photo::getImageForPhoto($photo);
// If a custom width and height were specified, apply before embedding
if (preg_match("/\[img\=([0-9]*)x([0-9]*)\]/is", substr($orig_body, $img_start, $img_st_close), $match)) {
Logger::log('scaling photo', Logger::DEBUG);
$width = intval($match[1]);
$height = intval($match[2]);
- $Image = new Image($data, $type);
- if ($Image->isValid()) {
- $Image->scaleDown(max($width, $height));
- $data = $Image->asString();
- $type = $Image->getType();
- }
+ $photo_img->scaleDown(max($width, $height));
}
+ $data = $photo_img->asString();
+ $type = $photo_img->getType();
+
Logger::log('replacing photo', Logger::DEBUG);
$image = 'data:' . $type . ';base64,' . base64_encode($data);
Logger::log('replaced: ' . $image, Logger::DATA);
}
}
- public static function getPermissionsSQLByUserId($owner_id, $remote_verified = false, $groups = null)
+ public static function getPermissionsSQLByUserId($owner_id, $remote_verified = false, $groups = null, $remote_cid = null)
{
$local_user = local_user();
$remote_user = remote_user();
* 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_user, $groups);
+ $set = PermissionSet::get($owner_id, $remote_cid, $groups);
if (!empty($set)) {
$sql_set = " OR (`item`.`private` IN (1,2) AND `item`.`wall` AND `item`.`psid` IN (" . implode(',', $set) . "))";
$filesubtype = 'unkn';
}
- $title = Strings::escapeHtml(trim(!empty($mtch[4]) ? $mtch[4] : $mtch[1]));
+ $title = Strings::escapeHtml(trim(defaults($mtch, 4, $mtch[1])));
$title .= ' ' . $mtch[2] . ' ' . L10n::t('bytes');
$icon = '<div class="attachtype icon s22 type-' . $filetype . ' subtype-' . $filesubtype . '"></div>';
}
// Map.
- if (strpos($s, '<div class="map">') !== false && x($item, 'coord')) {
+ if (strpos($s, '<div class="map">') !== false && !empty($item['coord'])) {
$x = Map::byCoordinates(trim($item['coord']));
if ($x) {
$s = preg_replace('/\<div class\=\"map\"\>/', '$0' . $x, $s);