From 694d93ded98280bb0d13ef20f8bf1e9786cb7f0f Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:31:13 -0500 Subject: [PATCH 1/7] Replace json_encode + exit by System::jsonExit in mod/item --- mod/item.php | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/mod/item.php b/mod/item.php index 8b795d28c..cfbe8f225 100644 --- a/mod/item.php +++ b/mod/item.php @@ -54,8 +54,7 @@ function item_post(App $a) { $arr_drop = explode(',', $_REQUEST['dropitems']); drop_items($arr_drop); $json = ['success' => 1]; - echo json_encode($json); - exit(); + System::jsonExit($json); } Hook::callAll('post_local_start', $_REQUEST); @@ -319,7 +318,7 @@ function item_post(App $a) { if (!strlen($body)) { if ($preview) { - exit(); + System::jsonExit(['preview' => '']); } info(DI::l10n()->t('Empty post discarded.') . EOL); if (!empty($_REQUEST['return'])) { @@ -665,8 +664,8 @@ function item_post(App $a) { $o = conversation($a, [array_merge($contact_record, $datarray)], new Pager(DI::args()->getQueryString()), 'search', false, true); Logger::log('preview: ' . $o); - echo json_encode(['preview' => $o]); - exit(); + + System::jsonExit(['preview' => $o]); } Hook::callAll('post_local',$datarray); @@ -682,8 +681,7 @@ function item_post(App $a) { $json['reload'] = DI::baseUrl() . '/' . $_REQUEST['jsreload']; } - echo json_encode($json); - exit(); + System::jsonExit($json); } if ($orig_post) { @@ -841,8 +839,7 @@ function item_post_return($baseurl, $api_source, $return_path) Logger::log('post_json: ' . print_r($json, true), Logger::DEBUG); - echo json_encode($json); - exit(); + System::jsonExit($json); } function item_content(App $a) @@ -867,8 +864,7 @@ function item_content(App $a) if (DI::mode()->isAjax()) { // ajax return: [, 0 (no perm) | ] - echo json_encode([intval($a->argv[2]), intval($o)]); - exit(); + System::jsonExit([intval($a->argv[2]), intval($o)]); } } From c17b2efb7a4b20b3ec563cd9442f16f3c4027fdf Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:34:32 -0500 Subject: [PATCH 2/7] Normalize redirect in item_post() --- mod/item.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/mod/item.php b/mod/item.php index cfbe8f225..324cd8ead 100644 --- a/mod/item.php +++ b/mod/item.php @@ -119,7 +119,7 @@ function item_post(App $a) { if (!DBA::isResult($toplevel_item)) { notice(DI::l10n()->t('Unable to locate original post.') . EOL); - if (!empty($_REQUEST['return'])) { + if ($return_path) { DI::baseUrl()->redirect($return_path); } exit(); @@ -166,8 +166,7 @@ function item_post(App $a) { // Now check that valid personal details have been provided if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) { notice(DI::l10n()->t('Permission denied.') . EOL); - - if (!empty($_REQUEST['return'])) { + if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -321,7 +320,7 @@ function item_post(App $a) { System::jsonExit(['preview' => '']); } info(DI::l10n()->t('Empty post discarded.') . EOL); - if (!empty($_REQUEST['return'])) { + if ($return_path) { DI::baseUrl()->redirect($return_path); } exit(); @@ -705,8 +704,7 @@ function item_post(App $a) { // update filetags in pconfig FileTag::updatePconfig($uid, $categories_old, $categories_new, 'category'); - if (!empty($_REQUEST['return']) && strlen($return_path)) { - Logger::log('return: ' . $return_path); + if ($return_path) { DI::baseUrl()->redirect($return_path); } exit(); @@ -727,14 +725,18 @@ function item_post(App $a) { if (!$post_id) { Logger::log("Item wasn't stored."); - DI::baseUrl()->redirect($return_path); + if ($return_path) { + DI::baseUrl()->redirect($return_path); + } } $datarray = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); if (!DBA::isResult($datarray)) { Logger::log("Item with id ".$post_id." couldn't be fetched."); - DI::baseUrl()->redirect($return_path); + if ($return_path) { + DI::baseUrl()->redirect($return_path); + } } // update filetags in pconfig From b03796957b333c8fac440696b4034e48a47316c0 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:42:49 -0500 Subject: [PATCH 3/7] Improve logging in mod/item - Set legacy Logger constants as deprecated --- mod/item.php | 19 +++++++++---------- src/Core/Logger.php | 6 ++++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/mod/item.php b/mod/item.php index 324cd8ead..58f9c02fa 100644 --- a/mod/item.php +++ b/mod/item.php @@ -59,7 +59,7 @@ function item_post(App $a) { Hook::callAll('post_local_start', $_REQUEST); - Logger::log('postvars ' . print_r($_REQUEST, true), Logger::DATA); + Logger::debug('postvars', ['_REQUEST' => $_REQUEST]); $api_source = $_REQUEST['api_source'] ?? false; @@ -75,7 +75,7 @@ function item_post(App $a) { */ if (!$preview && !empty($_REQUEST['post_id_random'])) { if (!empty($_SESSION['post-random']) && $_SESSION['post-random'] == $_REQUEST['post_id_random']) { - Logger::log("item post: duplicate post", Logger::DEBUG); + Logger::info('item post: duplicate post'); item_post_return(DI::baseUrl(), $api_source, $return_path); } else { $_SESSION['post-random'] = $_REQUEST['post_id_random']; @@ -132,7 +132,7 @@ function item_post(App $a) { } if ($toplevel_item_id) { - Logger::info('mod_item: item_post parent=' . $toplevel_item_id); + Logger::info('mod_item: item_post', ['parent' => $toplevel_item_id]); } $post_id = intval($_REQUEST['post_id'] ?? 0); @@ -155,7 +155,7 @@ function item_post(App $a) { // 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::log("Message with URI ".$message_id." already exists for user ".$profile_uid, Logger::DEBUG); + Logger::info('Message already exists for user', ['uri' => $message_id, 'uid' => $profile_uid]); return 0; } } @@ -662,7 +662,6 @@ function item_post(App $a) { $datarray["author-network"] = Protocol::DFRN; $o = conversation($a, [array_merge($contact_record, $datarray)], new Pager(DI::args()->getQueryString()), 'search', false, true); - Logger::log('preview: ' . $o); System::jsonExit(['preview' => $o]); } @@ -670,7 +669,7 @@ function item_post(App $a) { Hook::callAll('post_local',$datarray); if (!empty($datarray['cancel'])) { - Logger::log('mod_item: post cancelled by addon.'); + Logger::info('mod_item: post cancelled by addon.'); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -724,7 +723,7 @@ function item_post(App $a) { $post_id = Item::insert($datarray); if (!$post_id) { - Logger::log("Item wasn't stored."); + info(DI::l10n()->t('Item wasn\'t stored.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -733,7 +732,7 @@ function item_post(App $a) { $datarray = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); if (!DBA::isResult($datarray)) { - Logger::log("Item with id ".$post_id." couldn't be fetched."); + Logger::error('Item couldn\'t be fetched.', ['post_id' => $post_id]); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -811,7 +810,7 @@ function item_post(App $a) { Worker::add(['priority' => PRIORITY_HIGH, 'dont_fork' => false], "Notifier", Delivery::POST, $post_id); } - Logger::log('post_complete'); + Logger::info('post_complete'); if ($api_source) { return $post_id; @@ -839,7 +838,7 @@ function item_post_return($baseurl, $api_source, $return_path) $json['reload'] = $baseurl . '/' . $_REQUEST['jsreload']; } - Logger::log('post_json: ' . print_r($json, true), Logger::DEBUG); + Logger::info('post_json', ['json' => $json]); System::jsonExit($json); } diff --git a/src/Core/Logger.php b/src/Core/Logger.php index 3d6594b18..05895bb89 100644 --- a/src/Core/Logger.php +++ b/src/Core/Logger.php @@ -16,26 +16,32 @@ class Logger { /** * @see Logger::error() + * @deprecated since 2019.01 */ const WARNING = LogLevel::ERROR; /** * @see Logger::warning() + * @deprecated since 2019.01 */ const INFO = LogLevel::WARNING; /** * @see Logger::notice() + * @deprecated since 2019.01 */ const TRACE = LogLevel::NOTICE; /** * @see Logger::info() + * @deprecated since 2019.01 */ const DEBUG = LogLevel::INFO; /** * @see Logger::debug() + * @deprecated since 2019.01 */ const DATA = LogLevel::DEBUG; /** * @see Logger::debug() + * @deprecated since 2019.01 */ const ALL = LogLevel::DEBUG; From 4faad5a47cc2e1a3ad5f4a87e64901cd89a1c263 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:43:37 -0500 Subject: [PATCH 4/7] Replace exit calls with exception throwing in mod/item --- mod/item.php | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/mod/item.php b/mod/item.php index 58f9c02fa..dd598028e 100644 --- a/mod/item.php +++ b/mod/item.php @@ -33,6 +33,7 @@ use Friendica\Model\FileTag; use Friendica\Model\Item; use Friendica\Model\Photo; use Friendica\Model\Term; +use Friendica\Network\HTTPException; use Friendica\Object\EMail\ItemCCEMail; use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; @@ -45,7 +46,7 @@ require_once __DIR__ . '/../include/items.php'; function item_post(App $a) { if (!Session::isAuthenticated()) { - return 0; + throw new HTTPException\ForbiddenException(); } $uid = local_user(); @@ -122,7 +123,7 @@ function item_post(App $a) { if ($return_path) { DI::baseUrl()->redirect($return_path); } - exit(); + throw new HTTPException\NotFoundException(DI::l10n()->t('Unable to locate original post.')); } $toplevel_item_id = $toplevel_item['id']; @@ -170,7 +171,7 @@ function item_post(App $a) { DI::baseUrl()->redirect($return_path); } - exit(); + throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.')); } // Init post instance @@ -323,7 +324,8 @@ function item_post(App $a) { if ($return_path) { DI::baseUrl()->redirect($return_path); } - exit(); + + throw new HTTPException\BadRequestException(DI::l10n()->t('Empty post discarded.')); } } @@ -706,7 +708,8 @@ function item_post(App $a) { if ($return_path) { DI::baseUrl()->redirect($return_path); } - exit(); + + throw new HTTPException\OKException(DI::l10n()->t('Post updated.')); } unset($datarray['edit']); @@ -727,6 +730,8 @@ function item_post(App $a) { if ($return_path) { DI::baseUrl()->redirect($return_path); } + + throw new HTTPException\InternalServerErrorException(DI::l10n()->t('Item wasn\'t stored.')); } $datarray = Item::selectFirst(Item::ITEM_FIELDLIST, ['id' => $post_id]); @@ -736,6 +741,8 @@ function item_post(App $a) { if ($return_path) { DI::baseUrl()->redirect($return_path); } + + throw new HTTPException\InternalServerErrorException(DI::l10n()->t('Item couldn\'t be fetched.')); } // update filetags in pconfig @@ -886,7 +893,7 @@ function item_content(App $a) * * @return array|bool ['replaced' => $replaced, 'contact' => $contact]; * @throws ImagickException - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws HTTPException\InternalServerErrorException */ function handle_tag(&$body, &$inform, &$str_tags, $profile_uid, $tag, $network = "") { From b86083de065c694ae26999e7f2d2b7c4372956f6 Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:44:09 -0500 Subject: [PATCH 5/7] Remove superfluous code in mod/item --- mod/item.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/mod/item.php b/mod/item.php index dd598028e..7578e38ef 100644 --- a/mod/item.php +++ b/mod/item.php @@ -119,7 +119,7 @@ function item_post(App $a) { } if (!DBA::isResult($toplevel_item)) { - notice(DI::l10n()->t('Unable to locate original post.') . EOL); + notice(DI::l10n()->t('Unable to locate original post.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -166,7 +166,7 @@ function item_post(App $a) { // Now check that valid personal details have been provided if (!Security::canWriteToUserWall($profile_uid) && !$allow_comment) { - notice(DI::l10n()->t('Permission denied.') . EOL); + notice(DI::l10n()->t('Permission denied.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -320,7 +320,8 @@ function item_post(App $a) { if ($preview) { System::jsonExit(['preview' => '']); } - info(DI::l10n()->t('Empty post discarded.') . EOL); + + info(DI::l10n()->t('Empty post discarded.')); if ($return_path) { DI::baseUrl()->redirect($return_path); } @@ -502,9 +503,6 @@ function item_post(App $a) { $body = DI::bbCodeVideo()->transform($body); - // Fold multi-line [code] sequences - $body = preg_replace('/\[\/code\]\s*\[code\]/ism', "\n", $body); - $body = BBCode::scaleExternalImages($body); // Setting the object type if not defined before @@ -829,9 +827,6 @@ function item_post(App $a) { function item_post_return($baseurl, $api_source, $return_path) { - // figure out how to return, depending on from whence we came - $a = DI::app(); - if ($api_source) { return; } From 3370300376c42060db4fe43a175e7125ea95b72c Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:45:13 -0500 Subject: [PATCH 6/7] Add new info messages to mod/item --- mod/item.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mod/item.php b/mod/item.php index 7578e38ef..3edf49f86 100644 --- a/mod/item.php +++ b/mod/item.php @@ -703,6 +703,7 @@ function item_post(App $a) { // 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); } @@ -821,6 +822,7 @@ function item_post(App $a) { return $post_id; } + info(DI::l10n()->t('Post published.')); item_post_return(DI::baseUrl(), $api_source, $return_path); // NOTREACHED } From b2143cae53395390b3d150faeca7f940a45df1ae Mon Sep 17 00:00:00 2001 From: Hypolite Petovan Date: Wed, 29 Jan 2020 22:50:10 -0500 Subject: [PATCH 7/7] [frio] Add new asynchronous submission of modal form - Add loading state for jot submit buttons --- include/conversation.php | 1 + mod/editpost.php | 1 + view/theme/frio/templates/jot-header.tpl | 46 ++++++++++++++++++++++-- view/theme/frio/templates/jot.tpl | 12 +++++-- 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/include/conversation.php b/include/conversation.php index 0194e4ea5..a58848476 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1214,6 +1214,7 @@ function status_editor(App $a, $x, $notes_cid = 0, $popup = false) '$return_path' => $query_str, '$action' => 'item', '$share' => ($x['button'] ?? '') ?: DI::l10n()->t('Share'), + '$loading' => DI::l10n()->t('Loading...'), '$upload' => DI::l10n()->t('Upload photo'), '$shortupload' => DI::l10n()->t('upload photo'), '$attach' => DI::l10n()->t('Attach file'), diff --git a/mod/editpost.php b/mod/editpost.php index 2bbc2f2b6..ca5db3e08 100644 --- a/mod/editpost.php +++ b/mod/editpost.php @@ -70,6 +70,7 @@ function editpost_content(App $a) '$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'), diff --git a/view/theme/frio/templates/jot-header.tpl b/view/theme/frio/templates/jot-header.tpl index 9f226cda4..67b136ae1 100644 --- a/view/theme/frio/templates/jot-header.tpl +++ b/view/theme/frio/templates/jot-header.tpl @@ -67,11 +67,53 @@ jotTextOpenUI(document.getElementById("profile-jot-text")); jotActive(); addeditortext(embedcode); - }); - $('body').on('fbrowser.file.main', function(e, filename, embedcode, id) { + }) + .on('fbrowser.file.main', function(e, filename, embedcode, id) { jotTextOpenUI(document.getElementById("profile-jot-text")); jotActive(); addeditortext(embedcode); + }) + // Asynchronous jot submission + .on('submit', '#profile-jot-form', function (e) { + e.preventDefault(); + + // Disable jot submit buttons during processing + let $share = $('#profile-jot-submit').button('loading'); + let $sharePreview = $('#profile-jot-preview-submit').button('loading'); + + let formData = new FormData(e.target); + // This cancels the automatic redirection after item submission + formData.delete('return'); + + $.ajax({ + url: 'item', + data: formData, + processData: false, + contentType: false, + type: 'POST', + }) + .then(function () { + // Reset to form for jot reuse in the same page + e.target.reset(); + $('#jot-modal').modal('hide'); + }) + .always(function() { + // Reset the post_id_random to avoid duplicate post errors + let new_post_id_random = Math.floor(Math.random() * (Number.MAX_SAFE_INTEGER - (Number.MAX_SAFE_INTEGER / 10))) + Number.MAX_SAFE_INTEGER / 10; + $('#profile-jot-form [name=post_id_random]').val(new_post_id_random); + + // Reset jot submit button state + $share.button('reset'); + $sharePreview.button('reset'); + + // Force the display update of the edited post/comment + if (formData.get('post_id')) { + force_update = true; + update_item = formData.get('post_id'); + } + + NavUpdate(); + }) }); $('#wall-image-upload').on('click', function(){ diff --git a/view/theme/frio/templates/jot.tpl b/view/theme/frio/templates/jot.tpl index d4a430ecc..fe756880f 100644 --- a/view/theme/frio/templates/jot.tpl +++ b/view/theme/frio/templates/jot.tpl @@ -104,7 +104,11 @@
  • --> - +