X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=mod%2Fitem.php;h=68fa6fbf6dfe284ea529e8907d13149ffb8830e7;hb=215c6ecc14b799dc5359fd933275d9307ccd35ed;hp=e2d47ae2fab08c03ad02763df4699662850bbbd7;hpb=631095eefdd8cc9698190c60a26322a35b57fc1b;p=friendica.git diff --git a/mod/item.php b/mod/item.php index e2d47ae2fa..68fa6fbf6d 100644 --- a/mod/item.php +++ b/mod/item.php @@ -35,7 +35,6 @@ use Friendica\Content\Text\BBCode; use Friendica\Core\Hook; use Friendica\Core\Logger; use Friendica\Core\Protocol; -use Friendica\Core\Renderer; use Friendica\Core\Session; use Friendica\Core\System; use Friendica\Core\Worker; @@ -46,16 +45,18 @@ use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\FileTag; use Friendica\Model\Item; +use Friendica\Model\Notify; use Friendica\Model\Notify\Type; use Friendica\Model\Photo; +use Friendica\Model\Post; use Friendica\Model\Tag; +use Friendica\Model\User; use Friendica\Network\HTTPException; use Friendica\Object\EMail\ItemCCEMail; use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Security; -use Friendica\Util\Strings; +use Friendica\Security\Security; use Friendica\Worker\Delivery; function item_post(App $a) { @@ -81,8 +82,6 @@ function item_post(App $a) { $api_source = $_REQUEST['api_source'] ?? false; - $message_id = ((!empty($_REQUEST['message_id']) && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); - $return_path = $_REQUEST['return'] ?? ''; $preview = intval($_REQUEST['preview'] ?? 0); @@ -101,30 +100,33 @@ function item_post(App $a) { } // Is this a reply to something? - $toplevel_item_id = intval($_REQUEST['parent'] ?? 0); + $parent_item_id = intval($_REQUEST['parent'] ?? 0); $thr_parent_uri = trim($_REQUEST['parent_uri'] ?? ''); + $parent_item = null; $toplevel_item = null; - $parent_user = null; + $toplevel_item_id = 0; + $toplevel_user_id = null; $objecttype = null; $profile_uid = ($_REQUEST['profile_uid'] ?? 0) ?: local_user(); $posttype = ($_REQUEST['post_type'] ?? '') ?: Item::PT_ARTICLE; - if ($toplevel_item_id || $thr_parent_uri) { - if ($toplevel_item_id) { - $toplevel_item = Item::selectFirst([], ['id' => $toplevel_item_id]); + if ($parent_item_id || $thr_parent_uri) { + if ($parent_item_id) { + $parent_item = Post::selectFirst([], ['id' => $parent_item_id]); } elseif ($thr_parent_uri) { - $toplevel_item = Item::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]); + $parent_item = Post::selectFirst([], ['uri' => $thr_parent_uri, 'uid' => $profile_uid]); } // if this isn't the top-level parent of the conversation, find it - if (DBA::isResult($toplevel_item)) { + if (DBA::isResult($parent_item)) { // The URI and the contact is taken from the direct parent which needn't to be the top parent - $thr_parent_uri = $toplevel_item['uri']; + $thr_parent_uri = $parent_item['uri']; + $toplevel_item = $parent_item; - if ($toplevel_item['gravity'] != GRAVITY_PARENT) { - $toplevel_item = Item::selectFirst([], ['id' => $toplevel_item['parent']]); + if ($parent_item['gravity'] != GRAVITY_PARENT) { + $toplevel_item = Post::selectFirst([], ['id' => $toplevel_item['parent']]); } } @@ -136,8 +138,18 @@ function item_post(App $a) { throw new HTTPException\NotFoundException(DI::l10n()->t('Unable to locate original post.')); } + // When commenting on a public post then store the post for the current user + // This enables interaction like starring and saving into folders + if ($toplevel_item['uid'] == 0) { + $stored = Item::storeForUserByUriId($toplevel_item['uri-id'], local_user()); + Logger::info('Public item stored for user', ['uri-id' => $toplevel_item['uri-id'], 'uid' => $uid, 'stored' => $stored]); + if ($stored) { + $toplevel_item = Post::selectFirst([], ['id' => $stored]); + } + } + $toplevel_item_id = $toplevel_item['id']; - $parent_user = $toplevel_item['uid']; + $toplevel_user_id = $toplevel_item['uid']; $objecttype = Activity\ObjectType::COMMENT; } @@ -159,16 +171,8 @@ function item_post(App $a) { } // Ensure that the user id in a thread always stay the same - if (!is_null($parent_user) && in_array($parent_user, [local_user(), 0])) { - $profile_uid = $parent_user; - } - - // Check for multiple posts with the same message id (when the post was created via API) - if (($message_id != '') && ($profile_uid != 0)) { - if (Item::exists(['uri' => $message_id, 'uid' => $profile_uid])) { - Logger::info('Message already exists for user', ['uri' => $message_id, 'uid' => $profile_uid]); - return 0; - } + if (!is_null($toplevel_user_id) && in_array($toplevel_user_id, [local_user(), 0])) { + $profile_uid = $toplevel_user_id; } // Allow commenting if it is an answer to a public post @@ -189,11 +193,10 @@ function item_post(App $a) { // is this an edited post? if ($post_id > 0) { - $orig_post = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); + $orig_post = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); } - $user = DBA::selectFirst('user', [], ['uid' => $profile_uid]); - + $user = User::getById($profile_uid, ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']); if (!DBA::isResult($user) && !$toplevel_item_id) { return 0; } @@ -249,8 +252,8 @@ function item_post(App $a) { $verb = $orig_post['verb']; $objecttype = $orig_post['object-type']; $app = $orig_post['app']; - $categories = $orig_post['file'] ?? ''; - $title = Strings::escapeTags(trim($_REQUEST['title'])); + $categories = Post\Category::getTextByURIId($orig_post['uri-id'], $orig_post['uid']); + $title = trim($_REQUEST['title'] ?? ''); $body = trim($body); $private = $orig_post['private']; $pubmail_enabled = $orig_post['pubmail']; @@ -258,26 +261,30 @@ function item_post(App $a) { $guid = $orig_post['guid']; $extid = $orig_post['extid']; } else { - $str_contact_allow = ''; - $str_group_allow = ''; - $str_contact_deny = ''; - $str_group_deny = ''; - - if (($_REQUEST['visibility'] ?? '') !== 'public') { - $aclFormatter = DI::aclFormatter(); - $str_contact_allow = isset($_REQUEST['contact_allow']) ? $aclFormatter->toString($_REQUEST['contact_allow']) : $user['allow_cid'] ?? ''; - $str_group_allow = isset($_REQUEST['group_allow']) ? $aclFormatter->toString($_REQUEST['group_allow']) : $user['allow_gid'] ?? ''; - $str_contact_deny = isset($_REQUEST['contact_deny']) ? $aclFormatter->toString($_REQUEST['contact_deny']) : $user['deny_cid'] ?? ''; - $str_group_deny = isset($_REQUEST['group_deny']) ? $aclFormatter->toString($_REQUEST['group_deny']) : $user['deny_gid'] ?? ''; - } - - $title = Strings::escapeTags(trim($_REQUEST['title'] ?? '')); - $location = Strings::escapeTags(trim($_REQUEST['location'] ?? '')); - $coord = Strings::escapeTags(trim($_REQUEST['coord'] ?? '')); - $verb = Strings::escapeTags(trim($_REQUEST['verb'] ?? '')); - $emailcc = Strings::escapeTags(trim($_REQUEST['emailcc'] ?? '')); + $aclFormatter = DI::aclFormatter(); + $str_contact_allow = isset($_REQUEST['contact_allow']) ? $aclFormatter->toString($_REQUEST['contact_allow']) : $user['allow_cid'] ?? ''; + $str_group_allow = isset($_REQUEST['group_allow']) ? $aclFormatter->toString($_REQUEST['group_allow']) : $user['allow_gid'] ?? ''; + $str_contact_deny = isset($_REQUEST['contact_deny']) ? $aclFormatter->toString($_REQUEST['contact_deny']) : $user['deny_cid'] ?? ''; + $str_group_deny = isset($_REQUEST['group_deny']) ? $aclFormatter->toString($_REQUEST['group_deny']) : $user['deny_gid'] ?? ''; + + $visibility = $_REQUEST['visibility'] ?? ''; + if ($visibility === 'public') { + // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected + $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + } else if ($visibility === 'custom') { + // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL + // case that would make it public. So we always append the author's contact id to the allowed contacts. + // See https://github.com/friendica/friendica/issues/9672 + $str_contact_allow .= $aclFormatter->toString(Contact::getPublicIdByUserId($uid)); + } + + $title = trim($_REQUEST['title'] ?? ''); + $location = trim($_REQUEST['location'] ?? ''); + $coord = trim($_REQUEST['coord'] ?? ''); + $verb = trim($_REQUEST['verb'] ?? ''); + $emailcc = trim($_REQUEST['emailcc'] ?? ''); $body = trim($body); - $network = Strings::escapeTags(trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN)); + $network = trim(($_REQUEST['network'] ?? '') ?: Protocol::DFRN); $guid = System::createUUID(); $postopts = $_REQUEST['postopts'] ?? ''; @@ -323,7 +330,7 @@ function item_post(App $a) { System::jsonExit(['preview' => '']); } - info(DI::l10n()->t('Empty post discarded.')); + notice(DI::l10n()->t('Empty post discarded.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -337,10 +344,7 @@ function item_post(App $a) { $filedas = FileTag::fileToArray($categories); } - // save old and new categories, so we can determine what needs to be deleted from pconfig - $categories_old = $categories; $categories = FileTag::listToFile(trim($_REQUEST['category'] ?? ''), 'category'); - $categories_new = $categories; if (!empty($filedas) && is_array($filedas)) { // append the fileas stuff to the new categories list @@ -522,9 +526,8 @@ function item_post(App $a) { if (strlen($attachments)) { $attachments .= ','; } - $attachments .= '[attach]href="' . DI::baseUrl() . '/attach/' . $attachment['id'] . - '" length="' . $attachment['filesize'] . '" type="' . $attachment['filetype'] . - '" title="' . ($attachment['filename'] ? $attachment['filename'] : '') . '"[/attach]'; + $attachments .= Post\Media::getAttachElement(DI::baseUrl() . '/attach/' . $attachment['id'], + $attachment['filesize'], $attachment['filetype'], $attachment['filename'] ?? ''); } $body = str_replace($match[1],'',$body); } @@ -550,7 +553,7 @@ function item_post(App $a) { $origin = $_REQUEST['origin']; } - $uri = ($message_id ? $message_id : Item::newURI($api_source ? $profile_uid : $uid, $guid)); + $uri = Item::newURI($api_source ? $profile_uid : $uid, $guid); // Fallback so that we alway have a parent uri if (!$thr_parent_uri || !$toplevel_item_id) { @@ -597,8 +600,7 @@ function item_post(App $a) { $datarray['pubmail'] = $pubmail_enabled; $datarray['attach'] = $attachments; - // This is not a bug. The item store function changes 'parent-uri' to 'thr-parent' and fetches 'parent-uri' new. (We should change this) - $datarray['parent-uri'] = $thr_parent_uri; + $datarray['thr-parent'] = $thr_parent_uri; $datarray['postopts'] = $postopts; $datarray['origin'] = $origin; @@ -617,9 +619,10 @@ function item_post(App $a) { $datarray['api_source'] = $api_source; // This field is for storing the raw conversation data - $datarray['protocol'] = Conversation::PARCEL_DFRN; + $datarray['protocol'] = Conversation::PARCEL_DIRECT; + $datarray['direction'] = Conversation::PUSH; - $conversation = DBA::selectFirst('conversation', ['conversation-uri', 'conversation-href'], ['item-uri' => $datarray['parent-uri']]); + $conversation = DBA::selectFirst('conversation', ['conversation-uri', 'conversation-href'], ['item-uri' => $datarray['thr-parent']]); if (DBA::isResult($conversation)) { if ($conversation['conversation-uri'] != '') { $datarray['conversation-uri'] = $conversation['conversation-uri']; @@ -690,10 +693,6 @@ function item_post(App $a) { Item::update($fields, ['id' => $post_id]); - // update filetags in pconfig - FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category'); - - info(DI::l10n()->t('Post updated.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -715,7 +714,7 @@ function item_post(App $a) { $post_id = Item::insert($datarray); if (!$post_id) { - info(DI::l10n()->t('Item wasn\'t stored.')); + notice(DI::l10n()->t('Item wasn\'t stored.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -723,7 +722,7 @@ function item_post(App $a) { throw new HTTPException\InternalServerErrorException(DI::l10n()->t('Item wasn\'t stored.')); } - $datarray = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); + $datarray = Post::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); if (!DBA::isResult($datarray)) { Logger::error('Item couldn\'t be fetched.', ['post_id' => $post_id]); @@ -740,44 +739,27 @@ function item_post(App $a) { Tag::createImplicitMentions($datarray['uri-id'], $datarray['thr-parent-id']); } - // update filetags in pconfig - FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category'); - // These notifications are sent if someone else is commenting other your wall if ($contact_record != $author) { if ($toplevel_item_id) { notification([ - 'type' => Type::COMMENT, - 'notify_flags' => $user['notify-flags'], - 'language' => $user['language'], - 'to_name' => $user['username'], - 'to_email' => $user['email'], - 'uid' => $user['uid'], - 'item' => $datarray, - 'link' => DI::baseUrl().'/display/'.urlencode($datarray['guid']), - 'source_name' => $datarray['author-name'], - 'source_link' => $datarray['author-link'], - 'source_photo' => $datarray['author-avatar'], - 'verb' => Activity::POST, - 'otype' => 'item', - 'parent' => $toplevel_item_id, - 'parent_uri' => $toplevel_item['uri'] + 'type' => Type::COMMENT, + 'otype' => Notify\ObjectType::ITEM, + 'verb' => Activity::POST, + 'uid' => $profile_uid, + 'cid' => $datarray['author-id'], + 'item' => $datarray, + 'link' => DI::baseUrl() . '/display/' . urlencode($datarray['guid']), ]); } elseif (empty($forum_contact)) { notification([ - 'type' => Type::WALL, - 'notify_flags' => $user['notify-flags'], - 'language' => $user['language'], - 'to_name' => $user['username'], - 'to_email' => $user['email'], - 'uid' => $user['uid'], - 'item' => $datarray, - 'link' => DI::baseUrl().'/display/'.urlencode($datarray['guid']), - 'source_name' => $datarray['author-name'], - 'source_link' => $datarray['author-link'], - 'source_photo' => $datarray['author-avatar'], - 'verb' => Activity::POST, - 'otype' => 'item' + 'type' => Type::WALL, + 'otype' => Notify\ObjectType::ITEM, + 'verb' => Activity::POST, + 'uid' => $profile_uid, + 'cid' => $datarray['author-id'], + 'item' => $datarray, + 'link' => DI::baseUrl() . '/display/' . urlencode($datarray['guid']), ]); } } @@ -798,12 +780,6 @@ function item_post(App $a) { } } - // Insert an item entry for UID=0 for global entries. - // We now do it in the background to save some time. - // This is important in interactive environments like the frontend or the API. - // We don't fork a new process since this is done anyway with the following command - Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => true], "CreateShadowEntry", $post_id); - // 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) { @@ -816,7 +792,6 @@ function item_post(App $a) { return $post_id; } - info(DI::l10n()->t('Post published.')); item_post_return(DI::baseUrl(), $api_source, $return_path); // NOTREACHED } @@ -877,10 +852,10 @@ function drop_item(int $id, string $return = '') { // locate item to be deleted $fields = ['id', 'uid', 'guid', 'contact-id', 'deleted', 'gravity', 'parent']; - $item = Item::selectFirstForUser(local_user(), $fields, ['id' => $id]); + $item = Post::selectFirstForUser(local_user(), $fields, ['id' => $id]); if (!DBA::isResult($item)) { - notice(DI::l10n()->t('Item not found.') . EOL); + notice(DI::l10n()->t('Item not found.')); DI::baseUrl()->redirect('network'); } @@ -896,40 +871,8 @@ function drop_item(int $id, string $return = '') } if ((local_user() == $item['uid']) || $contact_id) { - // Check if we should do HTML-based delete confirmation - if (!empty($_REQUEST['confirm'])) { - //
can't take arguments in its "action" parameter - // so add any arguments as hidden inputs - $query = explode_querystring(DI::args()->getQueryString()); - $inputs = []; - - foreach ($query['args'] as $arg) { - if (strpos($arg, 'confirm=') === false) { - $arg_parts = explode('=', $arg); - $inputs[] = ['name' => $arg_parts[0], 'value' => $arg_parts[1]]; - } - } - - return Renderer::replaceMacros(Renderer::getMarkupTemplate('confirm.tpl'), [ - '$method' => 'get', - '$message' => DI::l10n()->t('Do you really want to delete this item?'), - '$extra_inputs' => $inputs, - '$confirm' => DI::l10n()->t('Yes'), - '$confirm_url' => $query['base'], - '$confirm_name' => 'confirmed', - '$cancel' => DI::l10n()->t('Cancel'), - ]); - } - // Now check how the user responded to the confirmation query - if (!empty($_REQUEST['canceled'])) { - DI::baseUrl()->redirect('display/' . $item['guid']); - } - - $is_comment = $item['gravity'] == GRAVITY_COMMENT; - $parentitem = null; if (!empty($item['parent'])) { - $fields = ['guid']; - $parentitem = Item::selectFirstForUser(local_user(), $fields, ['id' => $item['parent']]); + $parentitem = Post::selectFirstForUser(local_user(), ['guid'], ['id' => $item['parent']]); } // delete the item @@ -941,7 +884,7 @@ function drop_item(int $id, string $return = '') $return_url = str_replace("update_", "", $return_url); // Check if delete a comment - if ($is_comment) { + if ($item['gravity'] == GRAVITY_COMMENT) { // Return to parent guid if (!empty($parentitem)) { DI::baseUrl()->redirect('display/' . $parentitem['guid']);