diff --git a/src/Core/Hooks/HookEventBridge.php b/src/Core/Hooks/HookEventBridge.php index 03f8ced58c..df2a17322e 100644 --- a/src/Core/Hooks/HookEventBridge.php +++ b/src/Core/Hooks/HookEventBridge.php @@ -54,6 +54,9 @@ final class HookEventBridge ArrayFilterEvent::PREPARE_POST => 'prepare_body', ArrayFilterEvent::PREPARE_POST_END => 'prepare_body_final', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'photo_upload_form', + ArrayFilterEvent::PHOTO_UPLOAD_START => 'photo_post_init', + ArrayFilterEvent::PHOTO_UPLOAD => 'photo_post_file', + ArrayFilterEvent::PHOTO_UPLOAD_END => 'photo_post_end', ArrayFilterEvent::NETWORK_TO_NAME => 'network_to_name', ArrayFilterEvent::NETWORK_CONTENT_START => 'network_content_init', ArrayFilterEvent::NETWORK_CONTENT_TABS => 'network_tabs', @@ -139,6 +142,9 @@ final class HookEventBridge ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'onArrayFilterEvent', + ArrayFilterEvent::PHOTO_UPLOAD_START => 'onPhotoUploadStartEvent', + ArrayFilterEvent::PHOTO_UPLOAD => 'onArrayFilterEvent', + ArrayFilterEvent::PHOTO_UPLOAD_END => 'onPhotoUploadEndEvent', ArrayFilterEvent::NETWORK_TO_NAME => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_TABS => 'onArrayFilterEvent', @@ -273,6 +279,33 @@ final class HookEventBridge $event->setArray($data); } + /** + * Map the PHOTO_UPLOAD_START event to `photo_post_init` hook + */ + public static function onPhotoUploadStartEvent(ArrayFilterEvent $event): void + { + $data = $event->getArray(); + + $request = (array) $data['request'] ?? []; + + $data['request'] = static::callHook($event->getName(), $request); + + $event->setArray($data); + } + + /** + * Map the PHOTO_UPLOAD_END event to `photo_post_end` hook + */ + public static function onPhotoUploadEndEvent(ArrayFilterEvent $event): void + { + $data = $event->getArray(); + + $id = (int) $data['id'] ?? 0; + + // one-way-event: we don't care about the returned value + static::callHook($event->getName(), $id); + } + /** * Map the PROFILE_SIDEBAR_ENTRY event to `profile_sidebar_enter` hook */ diff --git a/src/Event/ArrayFilterEvent.php b/src/Event/ArrayFilterEvent.php index f1ba9887d9..7c772f4132 100644 --- a/src/Event/ArrayFilterEvent.php +++ b/src/Event/ArrayFilterEvent.php @@ -58,6 +58,12 @@ final class ArrayFilterEvent extends Event public const PHOTO_UPLOAD_FORM = 'friendica.data.photo_upload_form'; + public const PHOTO_UPLOAD_START = 'friendica.data.photo_upload_start'; + + public const PHOTO_UPLOAD = 'friendica.data.photo_upload'; + + public const PHOTO_UPLOAD_END = 'friendica.data.photo_upload_end'; + public const NETWORK_TO_NAME = 'friendica.data.network_to_name'; public const NETWORK_CONTENT_START = 'friendica.data.network_content_start'; diff --git a/src/Module/Profile/Photos.php b/src/Module/Profile/Photos.php index a377cd6dc3..29ece42ef9 100644 --- a/src/Module/Profile/Photos.php +++ b/src/Module/Profile/Photos.php @@ -14,12 +14,12 @@ use Friendica\AppHelper; use Friendica\Content\Feature; use Friendica\Content\Pager; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\Database; +use Friendica\Event\ArrayFilterEvent; use Friendica\Model\Contact; use Friendica\Model\Item; use Friendica\Model\Photo; @@ -34,6 +34,7 @@ use Friendica\Util\DateTimeFormat; use Friendica\Util\Images; use Friendica\Util\Profiler; use Friendica\Util\Strings; +use Psr\EventDispatcher\EventDispatcherInterface; use Psr\Log\LoggerInterface; class Photos extends \Friendica\Module\BaseProfile @@ -52,11 +53,28 @@ class Photos extends \Friendica\Module\BaseProfile private $systemMessages; /** @var ACLFormatter */ private $aclFormatter; + private EventDispatcherInterface $eventDispatcher; /** @var array owner-view record */ private $owner; - public function __construct(ACLFormatter $aclFormatter, SystemMessages $systemMessages, Database $database, AppHelper $appHelper, IManageConfigValues $config, Page $page, IHandleUserSessions $session, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) - { + public function __construct( + ACLFormatter $aclFormatter, + SystemMessages $systemMessages, + Database $database, + AppHelper $appHelper, + IManageConfigValues $config, + Page $page, + IHandleUserSessions $session, + EventDispatcherInterface $eventDispatcher, + L10n $l10n, + BaseURL $baseUrl, + Arguments $args, + LoggerInterface $logger, + Profiler $profiler, + Response $response, + array $server, + array $parameters = [], + ) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->session = $session; @@ -66,6 +84,7 @@ class Photos extends \Friendica\Module\BaseProfile $this->database = $database; $this->systemMessages = $systemMessages; $this->aclFormatter = $aclFormatter; + $this->eventDispatcher = $eventDispatcher; $owner = Profile::load($this->appHelper, $this->parameters['nickname'] ?? '', false); if (!$owner || $owner['account_removed'] || $owner['account_expired']) { @@ -97,8 +116,16 @@ class Photos extends \Friendica\Module\BaseProfile $str_contact_allow .= $this->aclFormatter->toString(Contact::getPublicIdByUserId($this->owner['uid'])); } + $hook_data = [ + 'request' => $request, + ]; + // default post action - upload a photo - Hook::callAll('photo_post_init', $request); + $hook_data = $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_START, $hook_data), + )->getArray(); + + $request = $hook_data['request'] ?? $request; // Determine the album to use $album = trim($request['album'] ?? ''); @@ -127,19 +154,27 @@ class Photos extends \Friendica\Module\BaseProfile $visible = 0; } - $ret = ['src' => '', 'filename' => '', 'filesize' => 0, 'type' => '']; + $hook_data = [ + 'src' => '', + 'filename' => '', + 'filesize' => 0, + 'type' => '', + ]; + + $hook_data = $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD, $hook_data), + )->getArray(); + $src = null; $filename = ''; $filesize = 0; $type = ''; - Hook::callAll('photo_post_file', $ret); - - if (!empty($ret['src']) && !empty($ret['filesize'])) { - $src = $ret['src']; - $filename = $ret['filename']; - $filesize = $ret['filesize']; - $type = $ret['type']; + if (!empty($hook_data['src']) && !empty($hook_data['filesize'])) { + $src = $hook_data['src']; + $filename = $hook_data['filename']; + $filesize = $hook_data['filesize']; + $type = $hook_data['type']; $error = UPLOAD_ERR_OK; } elseif (!empty($_FILES['userfile'])) { $src = $_FILES['userfile']['tmp_name']; @@ -176,8 +211,10 @@ class Photos extends \Friendica\Module\BaseProfile @unlink($src); } - $foo = 0; - Hook::callAll('photo_post_end', $foo); + $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]), + ); + return; } @@ -188,16 +225,22 @@ class Photos extends \Friendica\Module\BaseProfile if ($maximagesize && ($filesize > $maximagesize)) { $this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))); @unlink($src); - $foo = 0; - Hook::callAll('photo_post_end', $foo); + + $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]), + ); + return; } if (!$filesize) { $this->systemMessages->addNotice($this->t('Image file is empty.')); @unlink($src); - $foo = 0; - Hook::callAll('photo_post_end', $foo); + + $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]), + ); + return; } @@ -211,8 +254,11 @@ class Photos extends \Friendica\Module\BaseProfile $this->logger->notice('unable to process image'); $this->systemMessages->addNotice($this->t('Unable to process image.')); @unlink($src); - $foo = 0; - Hook::callAll('photo_post_end',$foo); + + $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]), + ); + return; } @@ -274,10 +320,11 @@ class Photos extends \Friendica\Module\BaseProfile // Update the photo albums cache Photo::clearAlbumCache($this->owner['uid']); - Hook::callAll('photo_post_end', $item_id); - - // addon uploaders should call "exit()" within the photo_post_end hook + // addon uploaders should call "exit()" within the PHOTO_UPLOAD_END event // if they do not wish to be redirected + $this->eventDispatcher->dispatch( + new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => $item_id]), + ); $this->baseUrl->redirect($this->session->get('photo_return') ?? 'profile/' . $this->owner['nickname'] . '/photos'); } diff --git a/tests/Unit/Core/Hooks/HookEventBridgeTest.php b/tests/Unit/Core/Hooks/HookEventBridgeTest.php index a07907e427..f30a1c2fef 100644 --- a/tests/Unit/Core/Hooks/HookEventBridgeTest.php +++ b/tests/Unit/Core/Hooks/HookEventBridgeTest.php @@ -43,6 +43,9 @@ class HookEventBridgeTest extends TestCase ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'onArrayFilterEvent', + ArrayFilterEvent::PHOTO_UPLOAD_START => 'onPhotoUploadStartEvent', + ArrayFilterEvent::PHOTO_UPLOAD => 'onArrayFilterEvent', + ArrayFilterEvent::PHOTO_UPLOAD_END => 'onPhotoUploadEndEvent', ArrayFilterEvent::NETWORK_TO_NAME => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_TABS => 'onArrayFilterEvent', @@ -298,6 +301,45 @@ class HookEventBridgeTest extends TestCase ); } + public function testOnPhotoUploadStartEventCallsHookWithCorrectValue(): void + { + $event = new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_START, ['request' => ['album' => -1]]); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, array $data): array { + $this->assertSame('photo_post_init', $name); + $this->assertSame(['album' => -1], $data); + + return ['album' => 123]; + }); + + HookEventBridge::onPhotoUploadStartEvent($event); + + $this->assertSame( + ['request' => ['album' => 123]], + $event->getArray(), + ); + } + + public function testOnPhotoUploadEndEventCallsHookWithCorrectValue(): void + { + $event = new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => -1]); + + $reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook'); + $reflectionProperty->setAccessible(true); + + $reflectionProperty->setValue(null, function (string $name, int $data): int { + $this->assertSame('photo_post_end', $name); + $this->assertSame(-1, $data); + + return 123; + }); + + HookEventBridge::onPhotoUploadEndEvent($event); + } + public function testOnProfileSidebarEntryEventCallsHookWithCorrectValue(): void { $event = new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY, ['profile' => ['uid' => 0, 'name' => 'original']]); @@ -491,6 +533,7 @@ class HookEventBridgeTest extends TestCase [ArrayFilterEvent::PREPARE_POST, 'prepare_body'], [ArrayFilterEvent::PREPARE_POST_END, 'prepare_body_final'], [ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'photo_upload_form'], + [ArrayFilterEvent::PHOTO_UPLOAD, 'photo_post_file'], [ArrayFilterEvent::NETWORK_TO_NAME, 'network_to_name'], [ArrayFilterEvent::NETWORK_CONTENT_START, 'network_content_init'], [ArrayFilterEvent::NETWORK_CONTENT_TABS, 'network_tabs'], diff --git a/tests/Unit/Event/ArrayFilterEventTest.php b/tests/Unit/Event/ArrayFilterEventTest.php index 69a8d6829d..9ecdb6feee 100644 --- a/tests/Unit/Event/ArrayFilterEventTest.php +++ b/tests/Unit/Event/ArrayFilterEventTest.php @@ -40,6 +40,9 @@ class ArrayFilterEventTest extends TestCase [ArrayFilterEvent::PREPARE_POST, 'friendica.data.prepare_post'], [ArrayFilterEvent::PREPARE_POST_END, 'friendica.data.prepare_post_end'], [ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'friendica.data.photo_upload_form'], + [ArrayFilterEvent::PHOTO_UPLOAD_START, 'friendica.data.photo_upload_start'], + [ArrayFilterEvent::PHOTO_UPLOAD, 'friendica.data.photo_upload'], + [ArrayFilterEvent::PHOTO_UPLOAD_END, 'friendica.data.photo_upload_end'], [ArrayFilterEvent::NETWORK_TO_NAME, 'friendica.data.network_to_name'], [ArrayFilterEvent::NETWORK_CONTENT_START, 'friendica.data.network_content_start'], [ArrayFilterEvent::NETWORK_CONTENT_TABS, 'friendica.data.network_content_tabs'],