use Friendica\Content\Pager;
use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML;
-use Friendica\Core\Addon;
use Friendica\Core\Config;
+use Friendica\Core\Hook;
use Friendica\Core\L10n;
use Friendica\Core\Logger;
use Friendica\Core\Protocol;
use Friendica\Core\System;
+use Friendica\Core\Session;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
+use Friendica\Model\Attach;
use Friendica\Model\Contact;
use Friendica\Model\Conversation;
use Friendica\Model\FileTag;
use Friendica\Model\Item;
use Friendica\Model\Photo;
+use Friendica\Model\Term;
use Friendica\Protocol\Diaspora;
use Friendica\Protocol\Email;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer;
use Friendica\Util\Security;
use Friendica\Util\Strings;
+use Friendica\Worker\Delivery;
+
+require_once 'include/items.php';
function item_post(App $a) {
- if (!local_user() && !remote_user()) {
+ if (!Session::isAuthenticated()) {
return 0;
}
exit();
}
- Addon::callHooks('post_local_start', $_REQUEST);
+ Hook::callAll('post_local_start', $_REQUEST);
Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA);
}
// Is this a reply to something?
- $thr_parent = intval(defaults($_REQUEST, 'parent', 0));
+ $toplevel_item_id = intval(defaults($_REQUEST, 'parent', 0));
$thr_parent_uri = trim(defaults($_REQUEST, 'parent_uri', ''));
- $thr_parent_contact = null;
+ $thread_parent_id = 0;
+ $thread_parent_contact = null;
- $parent = 0;
- $parent_item = null;
+ $toplevel_item = null;
$parent_user = null;
$parent_contact = null;
$profile_uid = defaults($_REQUEST, 'profile_uid', local_user());
$posttype = defaults($_REQUEST, 'post_type', Item::PT_ARTICLE);
- if ($thr_parent || $thr_parent_uri) {
- if ($thr_parent) {
- $parent_item = Item::selectFirst([], ['id' => $thr_parent]);
+ if ($toplevel_item_id || $thr_parent_uri) {
+ if ($toplevel_item_id) {
+ $toplevel_item = Item::selectFirst([], ['id' => $toplevel_item_id]);
} elseif ($thr_parent_uri) {
- $parent_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]);
+ $toplevel_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]);
}
- // if this isn't the real parent of the conversation, find it
- if (DBA::isResult($parent_item)) {
+ // if this isn't the top-level parent of the conversation, find it
+ if (DBA::isResult($toplevel_item)) {
// The URI and the contact is taken from the direct parent which needn't to be the top parent
- $thr_parent_uri = $parent_item['uri'];
- $thr_parent_contact = Contact::getDetailsByURL($parent_item["author-link"]);
+ $thread_parent_id = $toplevel_item['id'];
+ $thr_parent_uri = $toplevel_item['uri'];
+ $thread_parent_contact = Contact::getDetailsByURL($toplevel_item["author-link"]);
- if ($parent_item['id'] != $parent_item['parent']) {
- $parent_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $parent_item['parent']]);
+ if ($toplevel_item['id'] != $toplevel_item['parent']) {
+ $toplevel_item = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $toplevel_item['parent']]);
}
}
- if (!DBA::isResult($parent_item)) {
+ if (!DBA::isResult($toplevel_item)) {
notice(L10n::t('Unable to locate original post.') . EOL);
if (!empty($_REQUEST['return'])) {
$a->internalRedirect($return_path);
exit();
}
- $parent = $parent_item['id'];
- $parent_user = $parent_item['uid'];
-
- $parent_contact = Contact::getDetailsByURL($parent_item["author-link"]);
+ $toplevel_item_id = $toplevel_item['id'];
+ $parent_user = $toplevel_item['uid'];
$objecttype = ACTIVITY_OBJ_COMMENT;
}
- if ($parent) {
- Logger::log('mod_item: item_post parent=' . $parent);
+ if ($toplevel_item_id) {
+ Logger::info('mod_item: item_post parent=' . $toplevel_item_id);
}
$post_id = intval(defaults($_REQUEST, 'post_id', 0));
}
// Allow commenting if it is an answer to a public post
- $allow_comment = local_user() && ($profile_uid == 0) && $parent && in_array($parent_item['network'], [Protocol::ACTIVITYPUB, Protocol::OSTATUS, Protocol::DIASPORA, Protocol::DFRN]);
+ $allow_comment = local_user() && ($profile_uid == 0) && $toplevel_item_id && in_array($toplevel_item['network'], Protocol::FEDERATED);
// Now check that valid personal details have been provided
if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) {
$user = DBA::selectFirst('user', [], ['uid' => $profile_uid]);
- if (!DBA::isResult($user) && !$parent) {
+ if (!DBA::isResult($user) && !$toplevel_item_id) {
return 0;
}
$categories = '';
$postopts = '';
$emailcc = '';
+ $body = defaults($_REQUEST, 'body', '');
+ $has_attachment = defaults($_REQUEST, 'has_attachment', 0);
+
+ // If we have a speparate attachment, we need to add it to the body.
+ if (!empty($has_attachment)) {
+ $attachment_type = defaults($_REQUEST, 'attachment_type', '');
+ $attachment_title = defaults($_REQUEST, 'attachment_title', '');
+ $attachment_text = defaults($_REQUEST, 'attachment_text', '');
+
+ $attachment_url = hex2bin(defaults($_REQUEST, 'attachment_url', ''));
+ $attachment_img_src = hex2bin(defaults($_REQUEST, 'attachment_img_src', ''));
+
+ $attachment_img_width = defaults($_REQUEST, 'attachment_img_width', 0);
+ $attachment_img_height = defaults($_REQUEST, 'attachment_img_height', 0);
+ $attachment = [
+ 'type' => $attachment_type,
+ 'title' => $attachment_title,
+ 'text' => $attachment_text,
+ 'url' => $attachment_url,
+ ];
+
+ if (!empty($attachment_img_src)) {
+ $attachment['images'] = [
+ 0 => [
+ 'src' => $attachment_img_src,
+ 'width' => $attachment_img_width,
+ 'height' => $attachment_img_height
+ ]
+ ];
+ }
+
+ $att_bbcode = add_page_info_data($attachment);
+ $body .= $att_bbcode;
+ }
if (!empty($orig_post)) {
$str_group_allow = $orig_post['allow_gid'];
$app = $orig_post['app'];
$categories = $orig_post['file'];
$title = Strings::escapeTags(trim($_REQUEST['title']));
- $body = Strings::escapeHtml(trim($_REQUEST['body']));
+ $body = Strings::escapeHtml(trim($body));
$private = $orig_post['private'];
$pubmail_enabled = $orig_post['pubmail'];
$network = $orig_post['network'];
$coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , '')));
$verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , '')));
$emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , '')));
- $body = Strings::escapeHtml(trim(defaults($_REQUEST, 'body' , '')));
+ $body = Strings::escapeHtml(trim($body));
$network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN)));
$guid = System::createUUID();
$private = ((strlen($str_group_allow) || strlen($str_contact_allow) || strlen($str_group_deny) || strlen($str_contact_deny)) ? 1 : 0);
- if ($user['hidewall']) {
- $private = 2;
- }
-
// If this is a comment, set the permissions from the parent.
- if ($parent_item) {
+ if ($toplevel_item) {
// for non native networks use the network of the original post as network of the item
- if (($parent_item['network'] != Protocol::DIASPORA)
- && ($parent_item['network'] != Protocol::OSTATUS)
+ if (($toplevel_item['network'] != Protocol::DIASPORA)
+ && ($toplevel_item['network'] != Protocol::OSTATUS)
&& ($network == "")) {
- $network = $parent_item['network'];
+ $network = $toplevel_item['network'];
}
- $str_contact_allow = $parent_item['allow_cid'];
- $str_group_allow = $parent_item['allow_gid'];
- $str_contact_deny = $parent_item['deny_cid'];
- $str_group_deny = $parent_item['deny_gid'];
- $private = $parent_item['private'];
+ $str_contact_allow = $toplevel_item['allow_cid'];
+ $str_group_allow = $toplevel_item['allow_gid'];
+ $str_contact_deny = $toplevel_item['deny_cid'];
+ $str_group_deny = $toplevel_item['deny_gid'];
+ $private = $toplevel_item['private'];
- $wall = $parent_item['wall'];
+ $wall = $toplevel_item['wall'];
}
$pubmail_enabled = defaults($_REQUEST, 'pubmail_enable', false) && !$private;
}
}
- if (!empty($categories))
- {
+ if (!empty($categories)) {
// get the "fileas" tags for this post
- $filedas = FileTag::fileToList($categories, 'file');
+ $filedas = FileTag::fileToArray($categories);
}
// save old and new categories, so we can determine what needs to be deleted from pconfig
$categories = FileTag::listToFile(trim(defaults($_REQUEST, 'category', '')), 'category');
$categories_new = $categories;
- if (!empty($filedas))
- {
+ if (!empty($filedas) && is_array($filedas)) {
// append the fileas stuff to the new categories list
- $categories .= FileTag::listToFile($filedas, 'file');
+ $categories .= FileTag::arrayToFile($filedas);
}
// get contact info for poster
if (local_user() && ((local_user() == $profile_uid) || $allow_comment)) {
$self = true;
$author = DBA::selectFirst('contact', [], ['uid' => local_user(), 'self' => true]);
- } elseif (remote_user()) {
- if (!empty($_SESSION['remote']) && is_array($_SESSION['remote'])) {
- foreach ($_SESSION['remote'] as $v) {
- if ($v['uid'] == $profile_uid) {
- $contact_id = $v['cid'];
- break;
- }
- }
- }
- if ($contact_id) {
- $author = DBA::selectFirst('contact', [], ['id' => $contact_id]);
- }
+ } elseif (!empty(Session::getRemoteContactID($profile_uid))) {
+ $author = DBA::selectFirst('contact', [], ['id' => Session::getRemoteContactID($profile_uid)]);
}
if (DBA::isResult($author)) {
$tags = BBCode::getTags($body);
- // Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them)
- if ($parent && in_array($thr_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) {
- $contact = '@[url=' . $thr_parent_contact['url'] . ']' . $thr_parent_contact['nick'] . '[/url]';
- if (!stripos(implode($tags), '[url=' . $thr_parent_contact['url'] . ']')) {
- $tags[] = $contact;
- }
+ if ($thread_parent_id && !\Friendica\Content\Feature::isEnabled($uid, 'explicit_mentions')) {
+ $tags = item_add_implicit_mentions($tags, $thread_parent_contact, $thread_parent_id);
}
$tagged = [];
foreach ($tags as $tag) {
$tag_type = substr($tag, 0, 1);
- if ($tag_type == '#') {
+ if ($tag_type == Term::TAG_CHARACTER[Term::HASHTAG]) {
continue;
}
continue;
}
- $success = handle_tag($a, $body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network);
+ $success = handle_tag($body, $inform, $str_tags, local_user() ? local_user() : $profile_uid, $tag, $network);
if ($success['replaced']) {
$tagged[] = $tag;
}
// When the forum is private or the forum is addressed with a "!" make the post private
- if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == '!'))) {
+ if (is_array($success['contact']) && (!empty($success['contact']['prv']) || ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]))) {
$private_forum = $success['contact']['prv'];
- $only_to_forum = ($tag_type == '!');
+ $only_to_forum = ($tag_type == Term::TAG_CHARACTER[Term::EXCLUSIVE_MENTION]);
$private_id = $success['contact']['id'];
$forum_contact = $success['contact'];
} elseif (is_array($success['contact']) && !empty($success['contact']['forum']) &&
$original_contact_id = $contact_id;
- if (!$parent && count($forum_contact) && ($private_forum || $only_to_forum)) {
+ if (!$toplevel_item_id && count($forum_contact) && ($private_forum || $only_to_forum)) {
// we tagged a forum in a top level post. Now we change the post
$private = $private_forum;
$match = null;
- /// @todo these lines should be moved to Model/Photo
- if (!$preview && preg_match_all("/\[img([\=0-9x]*?)\](.*?)\[\/img\]/",$body,$match)) {
- $images = $match[2];
- if (count($images)) {
-
- $objecttype = ACTIVITY_OBJ_IMAGE;
-
- foreach ($images as $image) {
- if (!stristr($image, System::baseUrl() . '/photo/')) {
- continue;
- }
- $image_uri = substr($image,strrpos($image,'/') + 1);
- $image_uri = substr($image_uri,0, strpos($image_uri,'-'));
- if (!strlen($image_uri)) {
- continue;
- }
-
- // Ensure to only modify photos that you own
- $srch = '<' . intval($original_contact_id) . '>';
-
- $condition = [
- 'allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '',
- 'resource-id' => $image_uri, 'uid' => $profile_uid
- ];
- if (!Photo::exists($condition)) {
- continue;
- }
-
- $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
- 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
- $condition = ['resource-id' => $image_uri, 'uid' => $profile_uid];
- Photo::update($fields, $condition);
- }
- }
+ if (!$preview && Photo::setPermissionFromBody($body, $profile_uid, $original_contact_id, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny)) {
+ $objecttype = ACTIVITY_OBJ_IMAGE;
}
-
/*
* Next link in any attachment references we find in the post.
*/
$condition = ['allow_cid' => $srch, 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '',
'id' => $attach];
- if (!DBA::exists('attach', $condition)) {
+ if (!Attach::exists($condition)) {
continue;
}
$fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow,
'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny];
$condition = ['id' => $attach];
- DBA::update('attach', $fields, $condition);
+ Attach::update($fields, $condition);
}
}
}
if (preg_match_all('/(\[attachment\]([0-9]+)\[\/attachment\])/',$body,$match)) {
foreach ($match[2] as $mtch) {
$fields = ['id', 'filename', 'filesize', 'filetype'];
- $attachment = DBA::selectFirst('attach', $fields, ['id' => $mtch]);
- if (DBA::isResult($attachment)) {
+ $attachment = Attach::selectFirst($fields, ['id' => $mtch]);
+ if ($attachment !== false) {
if (strlen($attachments)) {
$attachments .= ',';
}
$network = Protocol::DFRN;
}
- $gravity = ($parent ? GRAVITY_COMMENT : GRAVITY_PARENT);
+ $gravity = ($toplevel_item_id ? GRAVITY_COMMENT : GRAVITY_PARENT);
// even if the post arrived via API we are considering that it
// originated on this site by default for determining relayability.
$origin = $_REQUEST['origin'];
}
- $notify_type = ($parent ? 'comment-new' : 'wall-new');
-
$uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid));
// Fallback so that we alway have a parent uri
- if (!$thr_parent_uri || !$parent) {
+ if (!$thr_parent_uri || !$toplevel_item_id) {
$thr_parent_uri = $uri;
}
* 'self' if true indicates the owner is posting on their own wall
* If parent is 0 it is a top-level post.
*/
- $datarray['parent'] = $parent;
+ $datarray['parent'] = $toplevel_item_id;
$datarray['self'] = $self;
// This triggers posts via API and the mirror functions
exit();
}
- Addon::callHooks('post_local',$datarray);
+ Hook::callAll('post_local',$datarray);
if (!empty($datarray['cancel'])) {
Logger::log('mod_item: post cancelled by addon.');
$a->internalRedirect($return_path);
}
exit();
- } else {
- $post_id = 0;
}
unset($datarray['edit']);
FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category');
// These notifications are sent if someone else is commenting other your wall
- if ($parent) {
+ if ($toplevel_item_id) {
if ($contact_record != $author) {
notification([
'type' => NOTIFY_COMMENT,
'source_photo' => $datarray['author-avatar'],
'verb' => ACTIVITY_POST,
'otype' => 'item',
- 'parent' => $parent,
- 'parent_uri' => $parent_item['uri']
+ 'parent' => $toplevel_item_id,
+ 'parent_uri' => $toplevel_item['uri']
]);
}
} else {
}
}
- Addon::callHooks('post_local_end', $datarray);
+ Hook::callAll('post_local_end', $datarray);
if (strlen($emailcc) && $profile_uid == local_user()) {
$erecips = explode(',', $emailcc);
// When we are doing some forum posting via ! we have to start the notifier manually.
// These kind of posts don't initiate the notifier call in the item class.
if ($only_to_forum) {
- Worker::add(PRIORITY_HIGH, "Notifier", $notify_type, $post_id);
+ Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => false], "Notifier", Delivery::POST, $post_id);
}
Logger::log('post_complete');
function item_content(App $a)
{
- if (!local_user() && !remote_user()) {
+ if (!Session::isAuthenticated()) {
return;
}
/**
* This function removes the tag $tag from the text $body and replaces it with
- * the appropiate link.
+ * the appropriate link.
*
- * @param App $a Application instance @TODO is unused in this function's scope (excluding included files)
- * @param string $body the text to replace the tag in
- * @param string $inform a comma-seperated string containing everybody to inform
- * @param string $str_tags string to add the tag to
+ * @param App $a
+ * @param string $body the text to replace the tag in
+ * @param string $inform a comma-seperated string containing everybody to inform
+ * @param string $str_tags string to add the tag to
* @param integer $profile_uid
- * @param string $tag the tag to replace
- * @param string $network The network of the post
+ * @param string $tag the tag to replace
+ * @param string $network The network of the post
*
- * @return boolean true if replaced, false if not replaced
+ * @return array|bool ['replaced' => $replaced, 'contact' => $contact];
+ * @throws ImagickException
+ * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/
-function handle_tag(App $a, &$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "")
+function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "")
{
$replaced = false;
$r = null;
- $tag_type = '@';
//is it a person tag?
- if ((strpos($tag, '@') === 0) || (strpos($tag, '!') === 0)) {
+ if (Term::isType($tag, Term::MENTION, Term::IMPLICIT_MENTION, Term::EXCLUSIVE_MENTION)) {
$tag_type = substr($tag, 0, 1);
//is it already replaced?
if (strpos($tag, '[url=')) {
return $replaced;
}
- $stat = false;
//get the person's name
$name = substr($tag, 1);
* Status.Net seems to require the numeric ID URL in a mention if the person isn't
* subscribed to you. But the nickname URL is OK if they are. Grrr. We'll tag both.
*/
- if (strlen($alias)) {
+ if (!empty($alias)) {
$newtag = '@[url=' . $alias . ']' . $newname . '[/url]';
if (!stripos($str_tags, '[url=' . $alias . ']')) {
if (strlen($str_tags)) {
return ['replaced' => $replaced, 'contact' => $contact];
}
+
+function item_add_implicit_mentions(array $tags, array $thread_parent_contact, $thread_parent_id)
+{
+ if (Config::get('system', 'disable_implicit_mentions')) {
+ // Add a tag if the parent contact is from ActivityPub or OStatus (This will notify them)
+ if (in_array($thread_parent_contact['network'], [Protocol::OSTATUS, Protocol::ACTIVITYPUB])) {
+ $contact = Term::TAG_CHARACTER[Term::MENTION] . '[url=' . $thread_parent_contact['url'] . ']' . $thread_parent_contact['nick'] . '[/url]';
+ if (!stripos(implode($tags), '[url=' . $thread_parent_contact['url'] . ']')) {
+ $tags[] = $contact;
+ }
+ }
+ } else {
+ $implicit_mentions = [
+ $thread_parent_contact['url'] => $thread_parent_contact['nick']
+ ];
+
+ $parent_terms = Term::tagArrayFromItemId($thread_parent_id, [Term::MENTION, Term::IMPLICIT_MENTION]);
+
+ foreach ($parent_terms as $parent_term) {
+ $implicit_mentions[$parent_term['url']] = $parent_term['term'];
+ }
+
+ foreach ($implicit_mentions as $url => $label) {
+ if ($url != \Friendica\Model\Profile::getMyURL() && !stripos(implode($tags), '[url=' . $url . ']')) {
+ $tags[] = Term::TAG_CHARACTER[Term::IMPLICIT_MENTION] . '[url=' . $url . ']' . $label . '[/url]';
+ }
+ }
+ }
+
+ return $tags;
+}