diff --git a/doc/Addons.md b/doc/Addons.md index b43a8a915d..171b5681a1 100644 --- a/doc/Addons.md +++ b/doc/Addons.md @@ -790,10 +790,6 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('post_local', $datarray); Hook::callAll('post_local_end', $datarray); -### mod/editpost.php - - Hook::callAll('jot_tool', $jotplugins); - ### src/Render/FriendicaSmartyEngine.php Hook::callAll("template_vars", $arr); @@ -855,6 +851,10 @@ Here is a complete list of all hook callbacks with file locations (as of 24-Sep- Hook::callAll('lockview_content', $item); +### src/Module/Post/Edit.php + + Hook::callAll('jot_tool', $jotplugins); + ### src/Module/Settings/Delegation.php Hook::callAll('authenticate', $addon_auth); diff --git a/doc/de/Addons.md b/doc/de/Addons.md index 342dd1b815..143e309cbb 100644 --- a/doc/de/Addons.md +++ b/doc/de/Addons.md @@ -309,10 +309,6 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('post_local', $datarray); Hook::callAll('post_local_end', $datarray); -### mod/editpost.php - - Hook::callAll('jot_tool', $jotplugins); - ### src/Network/FKOAuth1.php Hook::callAll('logged_in', $a->user); @@ -422,6 +418,10 @@ Eine komplette Liste aller Hook-Callbacks mit den zugehörigen Dateien (am 01-Ap Hook::callAll('lockview_content', $item); +### src/Module/Post/Edit.php + + Hook::callAll('jot_tool', $jotplugins); + ### src/Worker/Directory.php Hook::callAll('globaldir_update', $arr); diff --git a/mod/editpost.php b/mod/editpost.php deleted file mode 100644 index bec5d3449e..0000000000 --- a/mod/editpost.php +++ /dev/null @@ -1,166 +0,0 @@ -. - * - */ - -use Friendica\App; -use Friendica\Content\Feature; -use Friendica\Core\Hook; -use Friendica\Core\Renderer; -use Friendica\Database\DBA; -use Friendica\DI; -use Friendica\Model\Contact; -use Friendica\Model\Post; -use Friendica\Model\User; -use Friendica\Util\Crypto; - -function editpost_content(App $a) -{ - $o = ''; - - if (!DI::userSession()->getLocalUserId()) { - DI::sysmsg()->addNotice(DI::l10n()->t('Permission denied.')); - return; - } - - $post_id = ((DI::args()->getArgc() > 1) ? intval(DI::args()->getArgv()[1]) : 0); - - if (!$post_id) { - DI::sysmsg()->addNotice(DI::l10n()->t('Item not found')); - return; - } - - $fields = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', - 'body', 'title', 'uri-id', 'wall', 'post-type', 'guid']; - - $item = Post::selectFirstForUser(DI::userSession()->getLocalUserId(), $fields, ['id' => $post_id, 'uid' => DI::userSession()->getLocalUserId()]); - - if (!DBA::isResult($item)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Item not found')); - return; - } - - $user = User::getById(DI::userSession()->getLocalUserId()); - - $geotag = ''; - - $o .= Renderer::replaceMacros(Renderer::getMarkupTemplate("section_title.tpl"), [ - '$title' => DI::l10n()->t('Edit post') - ]); - - $tpl = Renderer::getMarkupTemplate('jot-header.tpl'); - DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [ - '$ispublic' => ' ', // DI::l10n()->t('Visible to everybody'), - '$geotag' => $geotag, - '$nickname' => $a->getLoggedInUserNickname(), - '$is_mobile' => DI::mode()->isMobile(), - ]); - - if (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) { - $lockstate = 'lock'; - } else { - $lockstate = 'unlock'; - } - - $jotplugins = ''; - $jotnets = ''; - - Hook::callAll('jot_tool', $jotplugins); - - $tpl = Renderer::getMarkupTemplate('jot.tpl'); - $o .= Renderer::replaceMacros($tpl, [ - '$is_edit' => true, - '$return_path' => '/display/' . $item['guid'], - '$action' => 'item', - '$share' => DI::l10n()->t('Save'), - '$loading' => DI::l10n()->t('Loading...'), - '$upload' => DI::l10n()->t('Upload photo'), - '$shortupload' => DI::l10n()->t('upload photo'), - '$attach' => DI::l10n()->t('Attach file'), - '$shortattach' => DI::l10n()->t('attach file'), - '$weblink' => DI::l10n()->t('Insert web link'), - '$shortweblink' => DI::l10n()->t('web link'), - '$video' => DI::l10n()->t('Insert video link'), - '$shortvideo' => DI::l10n()->t('video link'), - '$audio' => DI::l10n()->t('Insert audio link'), - '$shortaudio' => DI::l10n()->t('audio link'), - '$setloc' => DI::l10n()->t('Set your location'), - '$shortsetloc' => DI::l10n()->t('set location'), - '$noloc' => DI::l10n()->t('Clear browser location'), - '$shortnoloc' => DI::l10n()->t('clear location'), - '$wait' => DI::l10n()->t('Please wait'), - '$permset' => DI::l10n()->t('Permission settings'), - '$wall' => $item['wall'], - '$posttype' => $item['post-type'], - '$content' => undo_post_tagging($item['body']), - '$post_id' => $post_id, - '$defloc' => $user['default-location'], - '$visitor' => 'none', - '$pvisit' => 'none', - '$emailcc' => DI::l10n()->t('CC: email addresses'), - '$public' => DI::l10n()->t('Public post'), - '$jotnets' => $jotnets, - '$title' => $item['title'], - '$placeholdertitle' => DI::l10n()->t('Set title'), - '$category' => Post\Category::getCSVByURIId($item['uri-id'], DI::userSession()->getLocalUserId(), Post\Category::CATEGORY), - '$placeholdercategory' => (Feature::isEnabled(DI::userSession()->getLocalUserId(),'categories') ? DI::l10n()->t("Categories \x28comma-separated list\x29") : ''), - '$emtitle' => DI::l10n()->t('Example: bob@example.com, mary@example.com'), - '$lockstate' => $lockstate, - '$acl' => '', // populate_acl((($group) ? $group_acl : $a->user)), - '$bang' => ($lockstate === 'lock' ? '!' : ''), - '$profile_uid' => $_SESSION['uid'], - '$preview' => DI::l10n()->t('Preview'), - '$jotplugins' => $jotplugins, - '$cancel' => DI::l10n()->t('Cancel'), - '$rand_num' => Crypto::randomDigits(12), - - // Formatting button labels - '$edbold' => DI::l10n()->t('Bold'), - '$editalic' => DI::l10n()->t('Italic'), - '$eduline' => DI::l10n()->t('Underline'), - '$edquote' => DI::l10n()->t('Quote'), - '$edcode' => DI::l10n()->t('Code'), - '$edurl' => DI::l10n()->t('Link'), - '$edattach' => DI::l10n()->t('Link or Media'), - - //jot nav tab (used in some themes) - '$message' => DI::l10n()->t('Message'), - '$browser' => DI::l10n()->t('Browser'), - '$shortpermset' => DI::l10n()->t('Permissions'), - - '$compose_link_title' => DI::l10n()->t('Open Compose page'), - ]); - - return $o; -} - -function undo_post_tagging($s) { - $matches = null; - $cnt = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $s, $matches, PREG_SET_ORDER); - if ($cnt) { - foreach ($matches as $mtch) { - if (in_array($mtch[1], ['!', '@'])) { - $contact = Contact::getByURL($mtch[2], false, ['addr']); - $mtch[3] = empty($contact['addr']) ? $mtch[2] : $contact['addr']; - } - $s = str_replace($mtch[0], $mtch[1] . $mtch[3],$s); - } - } - return $s; -} diff --git a/src/Module/Post/Edit.php b/src/Module/Post/Edit.php new file mode 100644 index 0000000000..5531cb249e --- /dev/null +++ b/src/Module/Post/Edit.php @@ -0,0 +1,228 @@ +. + * + */ + +namespace Friendica\Module\Post; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Content\Feature; +use Friendica\Core\Hook; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Model\Contact; +use Friendica\Model\Post; +use Friendica\Model\User; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException; +use Friendica\Util\Crypto; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +/** + * Controller to edit a post + */ +class Edit extends BaseModule +{ + /** @var IHandleUserSessions */ + protected $session; + /** @var SystemMessages */ + protected $sysMessages; + /** @var App\Page */ + protected $page; + /** @var App\Mode */ + protected $mode; + /** @var App */ + protected $app; + /** @var bool */ + protected $isModal = false; + + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, SystemMessages $sysMessages, App\Page $page, App\Mode $mode, App $app, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->sysMessages = $sysMessages; + $this->page = $page; + $this->mode = $mode; + $this->app = $app; + } + + + protected function content(array $request = []): string + { + $this->isModal = $request['mode'] ?? '' === 'none'; + + if (!$this->session->getLocalUserId()) { + $this->errorExit($this->t('Permission denied.'), HTTPException\UnauthorizedException::class); + } + + $postId = $this->parameters['post_id']; + + if (empty($postId)) { + $this->errorExit($this->t('Post not found.'), HTTPException\BadRequestException::class); + } + + $fields = ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', + 'body', 'title', 'uri-id', 'wall', 'post-type', 'guid']; + + $item = Post::selectFirstForUser($this->session->getLocalUserId(), $fields, [ + 'id' => $postId, + 'uid' => $this->session->getLocalUserId(), + ]); + + if (empty($item)) { + $this->errorExit($this->t('Post not found.'), HTTPException\BadRequestException::class); + } + + $user = User::getById($this->session->getLocalUserId()); + $geoTag = ''; + + $output = Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), [ + '$title' => $this->t('Edit post'), + ]); + + $this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('jot-header.tpl'), [ + '$ispublic' => ' ', // $this->t('Visible to everybody'), + '$geotag' => $geoTag, + '$nickname' => $this->app->getLoggedInUserNickname(), + '$is_mobile' => $this->mode->isMobile(), + ]); + + if (strlen($item['allow_cid']) || strlen($item['allow_gid']) || strlen($item['deny_cid']) || strlen($item['deny_gid'])) { + $lockstate = 'lock'; + } else { + $lockstate = 'unlock'; + } + + $jotplugins = ''; + $jotnets = ''; + + Hook::callAll('jot_tool', $jotplugins); + + $output .= Renderer::replaceMacros(Renderer::getMarkupTemplate('jot.tpl'), [ + '$is_edit' => true, + '$return_path' => '/display/' . $item['guid'], + '$action' => 'item', + '$share' => $this->t('Save'), + '$loading' => $this->t('Loading...'), + '$upload' => $this->t('Upload photo'), + '$shortupload' => $this->t('upload photo'), + '$attach' => $this->t('Attach file'), + '$shortattach' => $this->t('attach file'), + '$weblink' => $this->t('Insert web link'), + '$shortweblink' => $this->t('web link'), + '$video' => $this->t('Insert video link'), + '$shortvideo' => $this->t('video link'), + '$audio' => $this->t('Insert audio link'), + '$shortaudio' => $this->t('audio link'), + '$setloc' => $this->t('Set your location'), + '$shortsetloc' => $this->t('set location'), + '$noloc' => $this->t('Clear browser location'), + '$shortnoloc' => $this->t('clear location'), + '$wait' => $this->t('Please wait'), + '$permset' => $this->t('Permission settings'), + '$wall' => $item['wall'], + '$posttype' => $item['post-type'], + '$content' => $this->undoPostTagging($item['body']), + '$post_id' => $postId, + '$defloc' => $user['default-location'], + '$visitor' => 'none', + '$pvisit' => 'none', + '$emailcc' => $this->t('CC: email addresses'), + '$public' => $this->t('Public post'), + '$jotnets' => $jotnets, + '$title' => $item['title'], + '$placeholdertitle' => $this->t('Set title'), + '$category' => Post\Category::getCSVByURIId($item['uri-id'], $this->session->getLocalUserId(), Post\Category::CATEGORY), + '$placeholdercategory' => (Feature::isEnabled($this->session->getLocalUserId(), 'categories') ? $this->t("Categories \x28comma-separated list\x29") : ''), + '$emtitle' => $this->t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', // populate_acl((($group) ? $group_acl : $a->user)), + '$bang' => ($lockstate === 'lock' ? '!' : ''), + '$profile_uid' => $_SESSION['uid'], + '$preview' => $this->t('Preview'), + '$jotplugins' => $jotplugins, + '$cancel' => $this->t('Cancel'), + '$rand_num' => Crypto::randomDigits(12), + + // Formatting button labels + '$edbold' => $this->t('Bold'), + '$editalic' => $this->t('Italic'), + '$eduline' => $this->t('Underline'), + '$edquote' => $this->t('Quote'), + '$edcode' => $this->t('Code'), + '$edurl' => $this->t('Link'), + '$edattach' => $this->t('Link or Media'), + + //jot nav tab (used in some themes) + '$message' => $this->t('Message'), + '$browser' => $this->t('Browser'), + '$shortpermset' => $this->t('Permissions'), + + '$compose_link_title' => $this->t('Open Compose page'), + ]); + + return $output; + } + + /** + * Removes Tags from the item-body + * + * @param string $body The item body + * + * @return string the new item body without tagging + */ + protected function undoPostTagging(string $body) + { + $matches = null; + $content = preg_match_all('/([!#@])\[url=(.*?)\](.*?)\[\/url\]/ism', $body, $matches, PREG_SET_ORDER); + if ($content) { + foreach ($matches as $match) { + if (in_array($match[1], ['!', '@'])) { + $contact = Contact::getByURL($match[2], false, ['addr']); + $match[3] = empty($contact['addr']) ? $match[2] : $contact['addr']; + } + $body = str_replace($match[0], $match[1] . $match[3], $body); + } + } + return $body; + } + + /** + * Exists the current Module because of an error + * + * @param string $message The error message + * @param string $exceptionClass In case it's a modal, throw an exception instead of an redirect + * + * @return void + */ + protected function errorExit(string $message, string $exceptionClass) + { + if ($this->isModal) { + throw new $exceptionClass($message); + } else { + $this->sysMessages->addNotice($message); + $this->baseUrl->redirect(); + } + } +} diff --git a/src/Object/Post.php b/src/Object/Post.php index 87951c19cc..8b8463f858 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -220,7 +220,7 @@ class Post if ($item['event-id'] != 0) { $edpost = ['calendar/event/edit/' . $item['event-id'], DI::l10n()->t('Edit')]; } else { - $edpost = ['editpost/' . $item['id'], DI::l10n()->t('Edit')]; + $edpost = [sprintf('post/%s/edit', $item['id']), DI::l10n()->t('Edit')]; } } $dropping = in_array($item['uid'], [0, DI::userSession()->getLocalUserId()]); diff --git a/static/routes.config.php b/static/routes.config.php index 7a86d8d034..5f5c238e05 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -552,6 +552,7 @@ return [ '/ping' => [Module\Notifications\Ping::class, [R::GET]], '/post' => [ + '/{post_id}/edit' => [Module\Post\Edit::class, [R::GET ]], '/{post_id}/share' => [Module\Post\Share::class, [R::GET ]], '/{item_id}/tag/add' => [Module\Post\Tag\Add::class, [ R::POST]], '/{item_id}/tag/remove[/{tag_name}]' => [Module\Post\Tag\Remove::class, [R::GET, R::POST]],