Create event for photo upload hooks

This commit is contained in:
Art4 2025-04-10 14:17:20 +00:00
parent 8ebbe8141a
commit 86ebbecff5
5 changed files with 155 additions and 23 deletions

View file

@ -54,6 +54,9 @@ final class HookEventBridge
ArrayFilterEvent::PREPARE_POST => 'prepare_body', ArrayFilterEvent::PREPARE_POST => 'prepare_body',
ArrayFilterEvent::PREPARE_POST_END => 'prepare_body_final', ArrayFilterEvent::PREPARE_POST_END => 'prepare_body_final',
ArrayFilterEvent::PHOTO_UPLOAD_FORM => 'photo_upload_form', 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_TO_NAME => 'network_to_name',
ArrayFilterEvent::NETWORK_CONTENT_START => 'network_content_init', ArrayFilterEvent::NETWORK_CONTENT_START => 'network_content_init',
ArrayFilterEvent::NETWORK_CONTENT_TABS => 'network_tabs', ArrayFilterEvent::NETWORK_CONTENT_TABS => 'network_tabs',
@ -139,6 +142,9 @@ final class HookEventBridge
ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent',
ArrayFilterEvent::PHOTO_UPLOAD_FORM => '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_TO_NAME => 'onArrayFilterEvent',
ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent',
ArrayFilterEvent::NETWORK_CONTENT_TABS => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_TABS => 'onArrayFilterEvent',
@ -273,6 +279,33 @@ final class HookEventBridge
$event->setArray($data); $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 * Map the PROFILE_SIDEBAR_ENTRY event to `profile_sidebar_enter` hook
*/ */

View file

@ -58,6 +58,12 @@ final class ArrayFilterEvent extends Event
public const PHOTO_UPLOAD_FORM = 'friendica.data.photo_upload_form'; 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_TO_NAME = 'friendica.data.network_to_name';
public const NETWORK_CONTENT_START = 'friendica.data.network_content_start'; public const NETWORK_CONTENT_START = 'friendica.data.network_content_start';

View file

@ -14,12 +14,12 @@ use Friendica\AppHelper;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\Photo; use Friendica\Model\Photo;
@ -34,6 +34,7 @@ use Friendica\Util\DateTimeFormat;
use Friendica\Util\Images; use Friendica\Util\Images;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Strings; use Friendica\Util\Strings;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Photos extends \Friendica\Module\BaseProfile class Photos extends \Friendica\Module\BaseProfile
@ -52,11 +53,28 @@ class Photos extends \Friendica\Module\BaseProfile
private $systemMessages; private $systemMessages;
/** @var ACLFormatter */ /** @var ACLFormatter */
private $aclFormatter; private $aclFormatter;
private EventDispatcherInterface $eventDispatcher;
/** @var array owner-view record */ /** @var array owner-view record */
private $owner; 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); parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->session = $session; $this->session = $session;
@ -66,6 +84,7 @@ class Photos extends \Friendica\Module\BaseProfile
$this->database = $database; $this->database = $database;
$this->systemMessages = $systemMessages; $this->systemMessages = $systemMessages;
$this->aclFormatter = $aclFormatter; $this->aclFormatter = $aclFormatter;
$this->eventDispatcher = $eventDispatcher;
$owner = Profile::load($this->appHelper, $this->parameters['nickname'] ?? '', false); $owner = Profile::load($this->appHelper, $this->parameters['nickname'] ?? '', false);
if (!$owner || $owner['account_removed'] || $owner['account_expired']) { 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'])); $str_contact_allow .= $this->aclFormatter->toString(Contact::getPublicIdByUserId($this->owner['uid']));
} }
$hook_data = [
'request' => $request,
];
// default post action - upload a photo // 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 // Determine the album to use
$album = trim($request['album'] ?? ''); $album = trim($request['album'] ?? '');
@ -127,19 +154,27 @@ class Photos extends \Friendica\Module\BaseProfile
$visible = 0; $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; $src = null;
$filename = ''; $filename = '';
$filesize = 0; $filesize = 0;
$type = ''; $type = '';
Hook::callAll('photo_post_file', $ret); if (!empty($hook_data['src']) && !empty($hook_data['filesize'])) {
$src = $hook_data['src'];
if (!empty($ret['src']) && !empty($ret['filesize'])) { $filename = $hook_data['filename'];
$src = $ret['src']; $filesize = $hook_data['filesize'];
$filename = $ret['filename']; $type = $hook_data['type'];
$filesize = $ret['filesize'];
$type = $ret['type'];
$error = UPLOAD_ERR_OK; $error = UPLOAD_ERR_OK;
} elseif (!empty($_FILES['userfile'])) { } elseif (!empty($_FILES['userfile'])) {
$src = $_FILES['userfile']['tmp_name']; $src = $_FILES['userfile']['tmp_name'];
@ -176,8 +211,10 @@ class Photos extends \Friendica\Module\BaseProfile
@unlink($src); @unlink($src);
} }
$foo = 0; $this->eventDispatcher->dispatch(
Hook::callAll('photo_post_end', $foo); new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]),
);
return; return;
} }
@ -188,16 +225,22 @@ class Photos extends \Friendica\Module\BaseProfile
if ($maximagesize && ($filesize > $maximagesize)) { if ($maximagesize && ($filesize > $maximagesize)) {
$this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize))); $this->systemMessages->addNotice($this->t('Image exceeds size limit of %s', Strings::formatBytes($maximagesize)));
@unlink($src); @unlink($src);
$foo = 0;
Hook::callAll('photo_post_end', $foo); $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]),
);
return; return;
} }
if (!$filesize) { if (!$filesize) {
$this->systemMessages->addNotice($this->t('Image file is empty.')); $this->systemMessages->addNotice($this->t('Image file is empty.'));
@unlink($src); @unlink($src);
$foo = 0;
Hook::callAll('photo_post_end', $foo); $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]),
);
return; return;
} }
@ -211,8 +254,11 @@ class Photos extends \Friendica\Module\BaseProfile
$this->logger->notice('unable to process image'); $this->logger->notice('unable to process image');
$this->systemMessages->addNotice($this->t('Unable to process image.')); $this->systemMessages->addNotice($this->t('Unable to process image.'));
@unlink($src); @unlink($src);
$foo = 0;
Hook::callAll('photo_post_end',$foo); $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PHOTO_UPLOAD_END, ['id' => 0]),
);
return; return;
} }
@ -274,10 +320,11 @@ class Photos extends \Friendica\Module\BaseProfile
// Update the photo albums cache // Update the photo albums cache
Photo::clearAlbumCache($this->owner['uid']); Photo::clearAlbumCache($this->owner['uid']);
Hook::callAll('photo_post_end', $item_id); // addon uploaders should call "exit()" within the PHOTO_UPLOAD_END event
// addon uploaders should call "exit()" within the photo_post_end hook
// if they do not wish to be redirected // 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'); $this->baseUrl->redirect($this->session->get('photo_return') ?? 'profile/' . $this->owner['nickname'] . '/photos');
} }

View file

@ -43,6 +43,9 @@ class HookEventBridgeTest extends TestCase
ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent', ArrayFilterEvent::PREPARE_POST_END => 'onArrayFilterEvent',
ArrayFilterEvent::PHOTO_UPLOAD_FORM => '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_TO_NAME => 'onArrayFilterEvent',
ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent', ArrayFilterEvent::NETWORK_CONTENT_START => 'onArrayFilterEvent',
ArrayFilterEvent::NETWORK_CONTENT_TABS => '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 public function testOnProfileSidebarEntryEventCallsHookWithCorrectValue(): void
{ {
$event = new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY, ['profile' => ['uid' => 0, 'name' => 'original']]); $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, 'prepare_body'],
[ArrayFilterEvent::PREPARE_POST_END, 'prepare_body_final'], [ArrayFilterEvent::PREPARE_POST_END, 'prepare_body_final'],
[ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'photo_upload_form'], [ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'photo_upload_form'],
[ArrayFilterEvent::PHOTO_UPLOAD, 'photo_post_file'],
[ArrayFilterEvent::NETWORK_TO_NAME, 'network_to_name'], [ArrayFilterEvent::NETWORK_TO_NAME, 'network_to_name'],
[ArrayFilterEvent::NETWORK_CONTENT_START, 'network_content_init'], [ArrayFilterEvent::NETWORK_CONTENT_START, 'network_content_init'],
[ArrayFilterEvent::NETWORK_CONTENT_TABS, 'network_tabs'], [ArrayFilterEvent::NETWORK_CONTENT_TABS, 'network_tabs'],

View file

@ -40,6 +40,9 @@ class ArrayFilterEventTest extends TestCase
[ArrayFilterEvent::PREPARE_POST, 'friendica.data.prepare_post'], [ArrayFilterEvent::PREPARE_POST, 'friendica.data.prepare_post'],
[ArrayFilterEvent::PREPARE_POST_END, 'friendica.data.prepare_post_end'], [ArrayFilterEvent::PREPARE_POST_END, 'friendica.data.prepare_post_end'],
[ArrayFilterEvent::PHOTO_UPLOAD_FORM, 'friendica.data.photo_upload_form'], [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_TO_NAME, 'friendica.data.network_to_name'],
[ArrayFilterEvent::NETWORK_CONTENT_START, 'friendica.data.network_content_start'], [ArrayFilterEvent::NETWORK_CONTENT_START, 'friendica.data.network_content_start'],
[ArrayFilterEvent::NETWORK_CONTENT_TABS, 'friendica.data.network_content_tabs'], [ArrayFilterEvent::NETWORK_CONTENT_TABS, 'friendica.data.network_content_tabs'],