Merge pull request #14853 from Art4/eventdispatcher-part3

Replace Hooks with EventDispatcher Part 3
This commit is contained in:
Philipp 2025-05-13 08:32:27 +02:00 committed by GitHub
commit 3481c3ad15
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 1871 additions and 423 deletions

View file

@ -46,7 +46,7 @@ function item_post()
$eventDispatcher = DI::eventDispatcher(); $eventDispatcher = DI::eventDispatcher();
$_REQUEST = $eventDispatcher->dispatch( $_REQUEST = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL_START, $_REQUEST) new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL_START, $_REQUEST)
)->getArray(); )->getArray();
$return_path = $_REQUEST['return'] ?? ''; $return_path = $_REQUEST['return'] ?? '';
@ -281,10 +281,16 @@ function item_process(array $post, array $request, bool $preview, string $return
$eventDispatcher = DI::eventDispatcher(); $eventDispatcher = DI::eventDispatcher();
$post = $eventDispatcher->dispatch( $hook_data = [
new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL, $post) 'item' => $post,
];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL, $hook_data)
)->getArray(); )->getArray();
$post = $hook_data['item'] ?? $post;
unset($post['edit']); unset($post['edit']);
unset($post['self']); unset($post['self']);
unset($post['api_source']); unset($post['api_source']);

View file

@ -1011,10 +1011,16 @@ class Item
Tag::createImplicitMentions($post['uri-id'], $post['thr-parent-id']); Tag::createImplicitMentions($post['uri-id'], $post['thr-parent-id']);
} }
$post = $this->eventDispatcher->dispatch( $hook_data = [
new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL_END, $post) 'item' => $post,
];
$hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL_END, $hook_data)
)->getArray(); )->getArray();
$post = $hook_data['item'] ?? $post;
$author = DBA::selectFirst('contact', ['thumb'], ['uid' => $post['uid'], 'self' => true]); $author = DBA::selectFirst('contact', ['thumb'], ['uid' => $post['uid'], 'self' => true]);
foreach ($recipients as $recipient) { foreach ($recipients as $recipient) {

View file

@ -171,8 +171,8 @@ class Hook
* Use this function when you want to be able to allow a hook to manipulate * Use this function when you want to be able to allow a hook to manipulate
* the provided data. * the provided data.
* *
* @param string $name of the hook to call * @param string $name of the hook to call
* @param string|array|null $data to transmit to the callback handler * @param int|string|array|null $data to transmit to the callback handler
* @return void * @return void
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
*/ */

View file

@ -43,15 +43,45 @@ final class HookEventBridge
ArrayFilterEvent::NAV_INFO => 'nav_info', ArrayFilterEvent::NAV_INFO => 'nav_info',
ArrayFilterEvent::FEATURE_ENABLED => 'isEnabled', ArrayFilterEvent::FEATURE_ENABLED => 'isEnabled',
ArrayFilterEvent::FEATURE_GET => 'get', ArrayFilterEvent::FEATURE_GET => 'get',
ArrayFilterEvent::POST_LOCAL_START => 'post_local_start', ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT => 'lockview_content',
ArrayFilterEvent::POST_LOCAL => 'post_local', ArrayFilterEvent::INSERT_POST_LOCAL_START => 'post_local_start',
ArrayFilterEvent::POST_LOCAL_END => 'post_local_end', ArrayFilterEvent::INSERT_POST_LOCAL => 'post_local',
ArrayFilterEvent::INSERT_POST_LOCAL_END => 'post_local_end',
ArrayFilterEvent::INSERT_POST_REMOTE => 'post_remote',
ArrayFilterEvent::INSERT_POST_REMOTE_END => 'post_remote_end',
ArrayFilterEvent::PREPARE_POST_START => 'prepare_body_init',
ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'prepare_body_content_filter',
ArrayFilterEvent::PREPARE_POST => 'prepare_body',
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_TABS => 'network_tabs',
ArrayFilterEvent::PARSE_LINK => 'parse_link',
ArrayFilterEvent::CONVERSATION_START => 'conversation_start', ArrayFilterEvent::CONVERSATION_START => 'conversation_start',
ArrayFilterEvent::FETCH_ITEM_BY_LINK => 'item_by_link',
ArrayFilterEvent::ITEM_TAGGED => 'tagged',
ArrayFilterEvent::DISPLAY_ITEM => 'display_item', ArrayFilterEvent::DISPLAY_ITEM => 'display_item',
ArrayFilterEvent::CACHE_ITEM => 'put_item_in_cache',
ArrayFilterEvent::CHECK_ITEM_NOTIFICATION => 'check_item_notification',
ArrayFilterEvent::ENOTIFY => 'enotify',
ArrayFilterEvent::ENOTIFY_STORE => 'enotify_store',
ArrayFilterEvent::ENOTIFY_MAIL => 'enotify_mail',
ArrayFilterEvent::DETECT_LANGUAGES => 'detect_languages',
ArrayFilterEvent::RENDER_LOCATION => 'render_location', ArrayFilterEvent::RENDER_LOCATION => 'render_location',
ArrayFilterEvent::ITEM_PHOTO_MENU => 'item_photo_menu', ArrayFilterEvent::ITEM_PHOTO_MENU => 'item_photo_menu',
ArrayFilterEvent::DIRECTORY_ITEM => 'directory_item',
ArrayFilterEvent::CONTACT_PHOTO_MENU => 'contact_photo_menu',
ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY => 'profile_sidebar_enter',
ArrayFilterEvent::PROFILE_SIDEBAR => 'profile_sidebar',
ArrayFilterEvent::PROFILE_TABS => 'profile_tabs',
ArrayFilterEvent::PROFILE_SETTINGS_FORM => 'profile_edit',
ArrayFilterEvent::PROFILE_SETTINGS_POST => 'profile_post',
ArrayFilterEvent::MODERATION_USERS_TABS => 'moderation_users_tabs',
ArrayFilterEvent::ACL_LOOKUP_END => 'acl_lookup_end',
ArrayFilterEvent::OEMBED_FETCH_END => 'oembed_fetch_url', ArrayFilterEvent::OEMBED_FETCH_END => 'oembed_fetch_url',
ArrayFilterEvent::PAGE_INFO => 'page_info_data', ArrayFilterEvent::PAGE_INFO => 'page_info_data',
ArrayFilterEvent::SMILEY_LIST => 'smilie', ArrayFilterEvent::SMILEY_LIST => 'smilie',
@ -62,11 +92,34 @@ final class HookEventBridge
ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'support_follow', ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'support_follow',
ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'support_revoke_follow', ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'support_revoke_follow',
ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'support_probe', ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'support_probe',
ArrayFilterEvent::FOLLOW_CONTACT => 'follow',
ArrayFilterEvent::UNFOLLOW_CONTACT => 'unfollow',
ArrayFilterEvent::REVOKE_FOLLOW_CONTACT => 'revoke_follow',
ArrayFilterEvent::BLOCK_CONTACT => 'block',
ArrayFilterEvent::UNBLOCK_CONTACT => 'unblock',
ArrayFilterEvent::EDIT_CONTACT_FORM => 'contact_edit',
ArrayFilterEvent::EDIT_CONTACT_POST => 'contact_edit_post',
ArrayFilterEvent::AVATAR_LOOKUP => 'avatar_lookup',
ArrayFilterEvent::ACCOUNT_AUTHENTICATE => 'authenticate',
ArrayFilterEvent::ACCOUNT_REGISTER_FORM => 'register_form',
ArrayFilterEvent::ACCOUNT_REGISTER_POST => 'register_post',
ArrayFilterEvent::ACCOUNT_REGISTER => 'register_account',
ArrayFilterEvent::ACCOUNT_REMOVE => 'remove_user',
ArrayFilterEvent::EVENT_CREATED => 'event_created',
ArrayFilterEvent::EVENT_UPDATED => 'event_updated',
ArrayFilterEvent::ADD_WORKER_TASK => 'proc_run',
ArrayFilterEvent::STORAGE_CONFIG => 'storage_config',
ArrayFilterEvent::STORAGE_INSTANCE => 'storage_instance',
ArrayFilterEvent::DB_STRUCTURE_DEFINITION => 'dbstructure_definition',
ArrayFilterEvent::DB_VIEW_DEFINITION => 'dbview_definition',
HtmlFilterEvent::HEAD => 'head', HtmlFilterEvent::HEAD => 'head',
HtmlFilterEvent::FOOTER => 'footer', HtmlFilterEvent::FOOTER => 'footer',
HtmlFilterEvent::PAGE_HEADER => 'page_header', HtmlFilterEvent::PAGE_HEADER => 'page_header',
HtmlFilterEvent::PAGE_CONTENT_TOP => 'page_content_top', HtmlFilterEvent::PAGE_CONTENT_TOP => 'page_content_top',
HtmlFilterEvent::PAGE_END => 'page_end', HtmlFilterEvent::PAGE_END => 'page_end',
HtmlFilterEvent::MOD_HOME_CONTENT => 'home_content',
HtmlFilterEvent::MOD_ABOUT_CONTENT => 'about_hook',
HtmlFilterEvent::MOD_PROFILE_CONTENT => 'profile_advanced',
HtmlFilterEvent::JOT_TOOL => 'jot_tool', HtmlFilterEvent::JOT_TOOL => 'jot_tool',
HtmlFilterEvent::CONTACT_BLOCK_END => 'contact_block_end', HtmlFilterEvent::CONTACT_BLOCK_END => 'contact_block_end',
]; ];
@ -85,15 +138,45 @@ final class HookEventBridge
ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent', ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent',
ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent',
ArrayFilterEvent::FEATURE_GET => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_GET => 'onArrayFilterEvent',
ArrayFilterEvent::POST_LOCAL_START => 'onArrayFilterEvent', ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT => 'onPermissionTooltipContentEvent',
ArrayFilterEvent::POST_LOCAL => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_LOCAL_START => 'onArrayFilterEvent',
ArrayFilterEvent::POST_LOCAL_END => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_LOCAL => 'onInsertPostLocalEvent',
ArrayFilterEvent::INSERT_POST_LOCAL_END => 'onInsertPostLocalEndEvent',
ArrayFilterEvent::INSERT_POST_REMOTE => 'onArrayFilterEvent',
ArrayFilterEvent::INSERT_POST_REMOTE_END => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST_START => 'onPreparePostStartEvent',
ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST => '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_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::PARSE_LINK => 'onArrayFilterEvent',
ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent', ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent',
ArrayFilterEvent::FETCH_ITEM_BY_LINK => 'onArrayFilterEvent',
ArrayFilterEvent::ITEM_TAGGED => 'onArrayFilterEvent',
ArrayFilterEvent::DISPLAY_ITEM => 'onArrayFilterEvent', ArrayFilterEvent::DISPLAY_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CACHE_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CHECK_ITEM_NOTIFICATION => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY_STORE => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY_MAIL => 'onArrayFilterEvent',
ArrayFilterEvent::DETECT_LANGUAGES => 'onArrayFilterEvent',
ArrayFilterEvent::RENDER_LOCATION => 'onArrayFilterEvent', ArrayFilterEvent::RENDER_LOCATION => 'onArrayFilterEvent',
ArrayFilterEvent::ITEM_PHOTO_MENU => 'onArrayFilterEvent', ArrayFilterEvent::ITEM_PHOTO_MENU => 'onArrayFilterEvent',
ArrayFilterEvent::DIRECTORY_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CONTACT_PHOTO_MENU => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY => 'onProfileSidebarEntryEvent',
ArrayFilterEvent::PROFILE_SIDEBAR => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SETTINGS_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SETTINGS_POST => 'onArrayFilterEvent',
ArrayFilterEvent::MODERATION_USERS_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::ACL_LOOKUP_END => 'onArrayFilterEvent',
ArrayFilterEvent::OEMBED_FETCH_END => 'onOembedFetchEndEvent', ArrayFilterEvent::OEMBED_FETCH_END => 'onOembedFetchEndEvent',
ArrayFilterEvent::PAGE_INFO => 'onArrayFilterEvent', ArrayFilterEvent::PAGE_INFO => 'onArrayFilterEvent',
ArrayFilterEvent::SMILEY_LIST => 'onArrayFilterEvent', ArrayFilterEvent::SMILEY_LIST => 'onArrayFilterEvent',
@ -104,11 +187,34 @@ final class HookEventBridge
ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'onArrayFilterEvent',
ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'onArrayFilterEvent',
ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'onArrayFilterEvent',
ArrayFilterEvent::FOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::UNFOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::REVOKE_FOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::BLOCK_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::UNBLOCK_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::EDIT_CONTACT_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::EDIT_CONTACT_POST => 'onArrayFilterEvent',
ArrayFilterEvent::AVATAR_LOOKUP => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_AUTHENTICATE => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER_POST => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER => 'onAccountRegisterEvent',
ArrayFilterEvent::ACCOUNT_REMOVE => 'onAccountRemoveEvent',
ArrayFilterEvent::EVENT_CREATED => 'onEventCreatedEvent',
ArrayFilterEvent::EVENT_UPDATED => 'onEventUpdatedEvent',
ArrayFilterEvent::ADD_WORKER_TASK => 'onArrayFilterEvent',
ArrayFilterEvent::STORAGE_CONFIG => 'onArrayFilterEvent',
ArrayFilterEvent::STORAGE_INSTANCE => 'onArrayFilterEvent',
ArrayFilterEvent::DB_STRUCTURE_DEFINITION => 'onArrayFilterEvent',
ArrayFilterEvent::DB_VIEW_DEFINITION => 'onArrayFilterEvent',
HtmlFilterEvent::HEAD => 'onHtmlFilterEvent', HtmlFilterEvent::HEAD => 'onHtmlFilterEvent',
HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent', HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_HEADER => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_HEADER => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_HOME_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_ABOUT_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_PROFILE_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::JOT_TOOL => 'onHtmlFilterEvent', HtmlFilterEvent::JOT_TOOL => 'onHtmlFilterEvent',
HtmlFilterEvent::CONTACT_BLOCK_END => 'onHtmlFilterEvent', HtmlFilterEvent::CONTACT_BLOCK_END => 'onHtmlFilterEvent',
]; ];
@ -131,6 +237,103 @@ final class HookEventBridge
); );
} }
/**
* Map the PERMISSION_TOOLTIP_CONTENT event to `lockview_content` hook
*/
public static function onPermissionTooltipContentEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$model = (array) $data['model'] ?? [];
$data['model'] = static::callHook($event->getName(), $model);
$event->setArray($data);
}
/**
* Map the INSERT_POST_LOCAL event to `post_local` hook
*/
public static function onInsertPostLocalEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$item = (array) $data['item'] ?? [];
$data['item'] = static::callHook($event->getName(), $item);
$event->setArray($data);
}
/**
* Map the INSERT_POST_LOCAL_END event to `post_local_end` hook
*/
public static function onInsertPostLocalEndEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$item = (array) $data['item'] ?? [];
$data['item'] = static::callHook($event->getName(), $item);
$event->setArray($data);
}
/**
* Map the PREPARE_POST_START event to `prepare_body_init` hook
*/
public static function onPreparePostStartEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$item = (array) $data['item'] ?? [];
$data['item'] = static::callHook($event->getName(), $item);
$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
*/
public static function onProfileSidebarEntryEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$profile = (array) $data['profile'] ?? [];
$data['profile'] = static::callHook($event->getName(), $profile);
$event->setArray($data);
}
/** /**
* Map the OEMBED_FETCH_END event to `oembed_fetch_url` hook * Map the OEMBED_FETCH_END event to `oembed_fetch_url` hook
*/ */
@ -187,6 +390,60 @@ final class HookEventBridge
$event->setArray($data); $event->setArray($data);
} }
/**
* Map the ACCOUNT_REGISTER event to `register_account` hook
*/
public static function onAccountRegisterEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$uid = (int) $data['uid'] ?? 0;
$data['uid'] = static::callHook($event->getName(), $uid);
$event->setArray($data);
}
/**
* Map the ACCOUNT_REMOVE event to `remove_account` hook
*/
public static function onAccountRemoveEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$user = (array) $data['user'] ?? [];
$data['user'] = static::callHook($event->getName(), $user);
$event->setArray($data);
}
/**
* Map the EVENT_CREATED event to `event_created` hook
*/
public static function onEventCreatedEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$id = (int) $data['event']['id'] ?? 0;
// one-way-event: we don't care about the returned value
static::callHook($event->getName(), $id);
}
/**
* Map the EVENT_UPDATED event to `event_updated` hook
*/
public static function onEventUpdatedEvent(ArrayFilterEvent $event): void
{
$data = $event->getArray();
$id = (int) $data['event']['id'] ?? 0;
// one-way-event: we don't care about the returned value
static::callHook($event->getName(), $id);
}
public static function onArrayFilterEvent(ArrayFilterEvent $event): void public static function onArrayFilterEvent(ArrayFilterEvent $event): void
{ {
$event->setArray( $event->setArray(
@ -202,9 +459,9 @@ final class HookEventBridge
} }
/** /**
* @param string|array|object $data * @param int|string|array|object $data
* *
* @return string|array|object * @return int|string|array|object
*/ */
private static function callHook(string $name, $data) private static function callHook(string $name, $data)
{ {

View file

@ -183,7 +183,12 @@ class Protocol
'uid' => $owner['uid'], 'uid' => $owner['uid'],
'result' => null, 'result' => null,
]; ];
Hook::callAll('unfollow', $hook_data);
$eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::UNFOLLOW_CONTACT, $hook_data),
)->getArray();
return $hook_data['result']; return $hook_data['result'];
} }
@ -218,7 +223,12 @@ class Protocol
'uid' => $owner['uid'], 'uid' => $owner['uid'],
'result' => null, 'result' => null,
]; ];
Hook::callAll('revoke_follow', $hook_data);
$eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::REVOKE_FOLLOW_CONTACT, $hook_data),
)->getArray();
return $hook_data['result']; return $hook_data['result'];
} }
@ -256,7 +266,12 @@ class Protocol
'uid' => $uid, 'uid' => $uid,
'result' => null, 'result' => null,
]; ];
Hook::callAll('block', $hook_data);
$eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::BLOCK_CONTACT, $hook_data),
)->getArray();
return $hook_data['result']; return $hook_data['result'];
} }
@ -295,7 +310,12 @@ class Protocol
'uid' => $uid, 'uid' => $uid,
'result' => null, 'result' => null,
]; ];
Hook::callAll('unblock', $hook_data);
$eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::UNBLOCK_CONTACT, $hook_data),
)->getArray();
return $hook_data['result']; return $hook_data['result'];
} }

View file

@ -20,7 +20,9 @@ use Friendica\Core\Storage\Capability\ICanWriteToStorage;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Core\Storage\Type; use Friendica\Core\Storage\Type;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\InternalServerErrorException;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -55,6 +57,7 @@ class StorageManager
private $config; private $config;
/** @var LoggerInterface */ /** @var LoggerInterface */
private $logger; private $logger;
private EventDispatcherInterface $eventDispatcher;
/** @var L10n */ /** @var L10n */
private $l10n; private $l10n;
@ -71,13 +74,14 @@ class StorageManager
* @throws InvalidClassStorageException in case the active backend class is invalid * @throws InvalidClassStorageException in case the active backend class is invalid
* @throws StorageException in case of unexpected errors during the active backend class loading * @throws StorageException in case of unexpected errors during the active backend class loading
*/ */
public function __construct(Database $dba, IManageConfigValues $config, LoggerInterface $logger, L10n $l10n, bool $includeAddon = true) public function __construct(Database $dba, IManageConfigValues $config, LoggerInterface $logger, EventDispatcherInterface $eventDispatcher, L10n $l10n, bool $includeAddon = true)
{ {
$this->dba = $dba; $this->dba = $dba;
$this->config = $config; $this->config = $config;
$this->logger = $logger; $this->logger = $logger;
$this->l10n = $l10n; $this->eventDispatcher = $eventDispatcher;
$this->validBackends = $config->get('storage', 'backends', self::DEFAULT_BACKENDS); $this->l10n = $l10n;
$this->validBackends = $config->get('storage', 'backends', self::DEFAULT_BACKENDS);
$currentName = $this->config->get('storage', 'name'); $currentName = $this->config->get('storage', 'name');
@ -146,8 +150,12 @@ class StorageManager
'name' => $name, 'name' => $name,
'storage_config' => null, 'storage_config' => null,
]; ];
try { try {
Hook::callAll('storage_config', $data); $data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::STORAGE_CONFIG, $data),
)->getArray();
if (!($data['storage_config'] ?? null) instanceof ICanConfigureStorage) { if (!($data['storage_config'] ?? null) instanceof ICanConfigureStorage) {
throw new InvalidClassStorageException(sprintf('Configuration for backend %s was not found', $name)); throw new InvalidClassStorageException(sprintf('Configuration for backend %s was not found', $name));
} }
@ -201,8 +209,12 @@ class StorageManager
'name' => $name, 'name' => $name,
'storage' => null, 'storage' => null,
]; ];
try { try {
Hook::callAll('storage_instance', $data); $data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::STORAGE_INSTANCE, $data),
)->getArray();
if (!($data['storage'] ?? null) instanceof ICanReadFromStorage) { if (!($data['storage'] ?? null) instanceof ICanReadFromStorage) {
throw new InvalidClassStorageException(sprintf('Backend %s was not found', $name)); throw new InvalidClassStorageException(sprintf('Backend %s was not found', $name));
} }

View file

@ -13,6 +13,7 @@ use Friendica\Core\Logger\Type\WorkerLogger;
use Friendica\Core\Worker\Entity\Process; use Friendica\Core\Worker\Entity\Process;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
/** /**
@ -1238,10 +1239,6 @@ class Worker
* @return int '0' if worker queue entry already existed or there had been an error, otherwise the ID of the worker task * @return int '0' if worker queue entry already existed or there had been an error, otherwise the ID of the worker task
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @note $cmd and string args are surrounded with '' * @note $cmd and string args are surrounded with ''
*
* @hooks 'proc_run'
* array $arr
*
*/ */
public static function add(...$args) public static function add(...$args)
{ {
@ -1251,7 +1248,12 @@ class Worker
$arr = ['args' => $args, 'run_cmd' => true]; $arr = ['args' => $args, 'run_cmd' => true];
Hook::callAll('proc_run', $arr); $eventDispatcher = DI::eventDispatcher();
$arr = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ADD_WORKER_TASK, $arr),
)->getArray();
if (!$arr['run_cmd'] || !count($args)) { if (!$arr['run_cmd'] || !count($args)) {
return 1; return 1;
} }

View file

@ -8,9 +8,8 @@
namespace Friendica\Database\Definition; namespace Friendica\Database\Definition;
use Exception; use Exception;
use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
/** /**
* Stores the whole database definition * Stores the whole database definition
@ -109,12 +108,16 @@ class DbaDefinition
{ {
$definition = require $this->configFile; $definition = require $this->configFile;
if (!$definition) { if (!is_array($definition)) {
throw new Exception('Corrupted database structure config file static/dbstructure.config.php'); throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
} }
if ($withAddonStructure) { if ($withAddonStructure) {
Hook::callAll('dbstructure_definition', $definition); $eventDispatcher = DI::eventDispatcher();
$definition = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::DB_STRUCTURE_DEFINITION, $definition),
)->getArray();
} }
$this->definition = $definition; $this->definition = $definition;

View file

@ -8,7 +8,8 @@
namespace Friendica\Database\Definition; namespace Friendica\Database\Definition;
use Exception; use Exception;
use Friendica\Core\Hook; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
/** /**
* Stores the whole View definitions * Stores the whole View definitions
@ -62,12 +63,16 @@ class ViewDefinition
{ {
$definition = require $this->configFile; $definition = require $this->configFile;
if (!$definition) { if (!is_array($definition)) {
throw new Exception('Corrupted database structure config file static/dbstructure.config.php'); throw new Exception('Corrupted database structure config file static/dbstructure.config.php');
} }
if ($withAddonStructure) { if ($withAddonStructure) {
Hook::callAll('dbview_definition', $definition); $eventDispatcher = DI::eventDispatcher();
$definition = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::DB_VIEW_DEFINITION, $definition),
)->getArray();
} }
$this->definition = $definition; $this->definition = $definition;

View file

@ -24,24 +24,96 @@ final class ArrayFilterEvent extends Event
public const FEATURE_GET = 'friendica.data.feature_get'; public const FEATURE_GET = 'friendica.data.feature_get';
public const POST_LOCAL_START = 'friendica.data.post_local_start'; public const PERMISSION_TOOLTIP_CONTENT = 'friendica.data.permission_tooltip_content';
public const POST_LOCAL = 'friendica.data.post_local'; public const INSERT_POST_LOCAL_START = 'friendica.data.insert_post_local_start';
public const POST_LOCAL_END = 'friendica.data.post_local_end'; public const INSERT_POST_LOCAL = 'friendica.data.insert_post_local';
public const INSERT_POST_LOCAL_END = 'friendica.data.insert_post_local_end';
public const INSERT_POST_REMOTE = 'friendica.data.insert_post_remote';
public const INSERT_POST_REMOTE_END = 'friendica.data.insert_post_remote_end';
/**
* item array before any work
*/
public const PREPARE_POST_START = 'friendica.data.prepare_post_start';
/**
* before first bbcode to html
*/
public const PREPARE_POST_FILTER_CONTENT = 'friendica.data.prepare_post_filter_content';
/**
* after first bbcode to html
*/
public const PREPARE_POST = 'friendica.data.prepare_post';
/**
* after attach icons and blockquote special case handling (spoiler, author)
*/
public const PREPARE_POST_END = 'friendica.data.prepare_post_end';
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_TABS = 'friendica.data.network_content_tabs';
public const PARSE_LINK = 'friendica.data.parse_link';
public const CONVERSATION_START = 'friendica.data.conversation_start'; public const CONVERSATION_START = 'friendica.data.conversation_start';
public const FETCH_ITEM_BY_LINK = 'friendica.data.fetch_item_by_link';
public const ITEM_TAGGED = 'friendica.data.item_tagged';
public const DISPLAY_ITEM = 'friendica.data.display_item'; public const DISPLAY_ITEM = 'friendica.data.display_item';
public const CACHE_ITEM = 'friendica.data.cache_item';
public const CHECK_ITEM_NOTIFICATION = 'friendica.data.check_item_notification';
public const ENOTIFY = 'friendica.data.enotify';
public const ENOTIFY_STORE = 'friendica.data.enotify_store';
public const ENOTIFY_MAIL = 'friendica.data.enotify_mail';
public const DETECT_LANGUAGES = 'friendica.data.detect_languages';
public const RENDER_LOCATION = 'friendica.data.render_location'; public const RENDER_LOCATION = 'friendica.data.render_location';
public const ITEM_PHOTO_MENU = 'friendica.data.item_photo_menu'; public const ITEM_PHOTO_MENU = 'friendica.data.item_photo_menu';
public const DIRECTORY_ITEM = 'friendica.data.directory_item';
public const CONTACT_PHOTO_MENU = 'friendica.data.contact_photo_menu';
public const PROFILE_SIDEBAR_ENTRY = 'friendica.data.profile_sidebar_entry';
public const PROFILE_SIDEBAR = 'friendica.data.profile_sidebar';
public const PROFILE_TABS = 'friendica.data.profile_tabs';
public const PROFILE_SETTINGS_FORM = 'friendica.data.profile_settings_form';
public const PROFILE_SETTINGS_POST = 'friendica.data.profile_settings_post';
public const MODERATION_USERS_TABS = 'friendica.data.moderation_users_tabs';
public const ACL_LOOKUP_END = 'friendica.data.acl_lookup_end';
public const OEMBED_FETCH_END = 'friendica.data.oembed_fetch_end'; public const OEMBED_FETCH_END = 'friendica.data.oembed_fetch_end';
public const PAGE_INFO = 'friendica.data.page_info'; public const PAGE_INFO = 'friendica.data.page_info';
@ -62,6 +134,46 @@ final class ArrayFilterEvent extends Event
public const PROTOCOL_SUPPORTS_PROBE = 'friendica.data.protocol_supports_probe'; public const PROTOCOL_SUPPORTS_PROBE = 'friendica.data.protocol_supports_probe';
public const FOLLOW_CONTACT = 'friendica.data.follow_contact';
public const UNFOLLOW_CONTACT = 'friendica.data.unfollow_contact';
public const REVOKE_FOLLOW_CONTACT = 'friendica.data.revoke_follow_contact';
public const BLOCK_CONTACT = 'friendica.data.block_contact';
public const UNBLOCK_CONTACT = 'friendica.data.unblock_contact';
public const EDIT_CONTACT_FORM = 'friendica.data.edit_contact_form';
public const EDIT_CONTACT_POST = 'friendica.data.edit_contact_post';
public const AVATAR_LOOKUP = 'friendica.data.avatar_lookup';
public const ACCOUNT_AUTHENTICATE = 'friendica.data.account_authenticate';
public const ACCOUNT_REGISTER_FORM = 'friendica.data.account_register_form';
public const ACCOUNT_REGISTER_POST = 'friendica.data.account_register_post';
public const ACCOUNT_REGISTER = 'friendica.data.account_register';
public const ACCOUNT_REMOVE = 'friendica.data.account_remove';
public const EVENT_CREATED = 'friendica.data.event_created';
public const EVENT_UPDATED = 'friendica.data.event_updated';
public const ADD_WORKER_TASK = 'friendica.data.add_worker_task';
public const STORAGE_CONFIG = 'friendica.data.storage_config';
public const STORAGE_INSTANCE = 'friendica.data.storage_instance';
public const DB_STRUCTURE_DEFINITION = 'friendica.data.db_structure_definition';
public const DB_VIEW_DEFINITION = 'friendica.data.db_view_definition';
private array $array; private array $array;
public function __construct(string $name, array $array) public function __construct(string $name, array $array)

View file

@ -26,6 +26,12 @@ final class HtmlFilterEvent extends Event
public const PAGE_END = 'friendica.html.page_end'; public const PAGE_END = 'friendica.html.page_end';
public const MOD_HOME_CONTENT = 'friendica.html.mod_home_content';
public const MOD_ABOUT_CONTENT = 'friendica.html.mod_about_content';
public const MOD_PROFILE_CONTENT = 'friendica.html.mod_profile_content';
public const JOT_TOOL = 'friendica.html.jot_tool'; public const JOT_TOOL = 'friendica.html.jot_tool';
public const CONTACT_BLOCK_END = 'friendica.html.contact_block_end'; public const CONTACT_BLOCK_END = 'friendica.html.contact_block_end';

View file

@ -14,7 +14,6 @@ use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException;
use Friendica\Content\Conversation as ConversationContent; use Friendica\Content\Conversation as ConversationContent;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Content\Text\HTML; use Friendica\Content\Text\HTML;
use Friendica\Core\Hook;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
@ -22,6 +21,7 @@ use Friendica\Core\Worker;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPClient\Client\HttpClientOptions;
use Friendica\Network\HTTPException\NotFoundException; use Friendica\Network\HTTPException\NotFoundException;
@ -1311,9 +1311,17 @@ class Contact
} }
} }
$args = ['contact' => $contact, 'menu' => &$menu]; $args = ['contact' => $contact, 'menu' => $menu];
Hook::callAll('contact_photo_menu', $args); $eventDispatcher = DI::eventDispatcher();
$args = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::CONTACT_PHOTO_MENU, $args),
)->getArray();
if (is_array($args['menu'])) {
$menu = $args['menu'];
}
$menucondensed = []; $menucondensed = [];
@ -2196,7 +2204,11 @@ class Contact
$avatar['url'] = ''; $avatar['url'] = '';
$avatar['success'] = false; $avatar['success'] = false;
Hook::callAll('avatar_lookup', $avatar); $eventDispatcher = DI::eventDispatcher();
$avatar = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::AVATAR_LOOKUP, $avatar),
)->getArray();
if ($avatar['success'] && !empty($avatar['url'])) { if ($avatar['success'] && !empty($avatar['url'])) {
return $avatar['url']; return $avatar['url'];
@ -3144,7 +3156,11 @@ class Contact
$arr = ['url' => $url, 'uid' => $uid, 'contact' => []]; $arr = ['url' => $url, 'uid' => $uid, 'contact' => []];
Hook::callAll('follow', $arr); $eventDispatcher = DI::eventDispatcher();
$arr = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::FOLLOW_CONTACT, $arr),
)->getArray();
if (empty($arr)) { if (empty($arr)) {
$result['message'] = DI::l10n()->t('The contact could not be added. Please check the relevant network credentials in your Settings -> Social Networks page.'); $result['message'] = DI::l10n()->t('The contact could not be added. Please check the relevant network credentials in your Settings -> Social Networks page.');

View file

@ -9,11 +9,11 @@ namespace Friendica\Model;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\System; use Friendica\Core\System;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\Network\HTTPException\NotFoundException; use Friendica\Network\HTTPException\NotFoundException;
use Friendica\Network\HTTPException\UnauthorizedException; use Friendica\Network\HTTPException\UnauthorizedException;
@ -255,6 +255,7 @@ class Event
'finish' => DateTimeFormat::utc(($arr['finish'] ?? '') ?: DBA::NULL_DATETIME), 'finish' => DateTimeFormat::utc(($arr['finish'] ?? '') ?: DBA::NULL_DATETIME),
]; ];
$eventDispatcher = DI::eventDispatcher();
if ($event['finish'] < DBA::NULL_DATETIME) { if ($event['finish'] < DBA::NULL_DATETIME) {
$event['finish'] = DBA::NULL_DATETIME; $event['finish'] = DBA::NULL_DATETIME;
@ -295,14 +296,18 @@ class Event
Item::update($fields, ['id' => $item['id']]); Item::update($fields, ['id' => $item['id']]);
} }
Hook::callAll('event_updated', $event['id']); $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::EVENT_UPDATED, ['event' => $event]),
);
} else { } else {
// New event. Store it. // New event. Store it.
DBA::insert('event', $event); DBA::insert('event', $event);
$event['id'] = DBA::lastInsertId(); $event['id'] = DBA::lastInsertId();
Hook::callAll("event_created", $event['id']); $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::EVENT_CREATED, ['event' => $event]),
);
} }
return (int) $event['id']; return (int) $event['id'];

View file

@ -14,7 +14,6 @@ use Friendica\Content\Post\Collection\PostMedias;
use Friendica\Content\Post\Entity\PostMedia; use Friendica\Content\Post\Entity\PostMedia;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML; use Friendica\Content\Text\HTML;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
@ -849,17 +848,26 @@ class Item
$dummy_session = false; $dummy_session = false;
} }
/** @var array<string,mixed> */ $hook_data = [
$item = $eventDispatcher->dispatch( 'item' => $item,
new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL, $item) ];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL, $hook_data)
)->getArray(); )->getArray();
/** @var array<string,mixed> */
$item = $hook_data['item'] ?? $item;
if ($dummy_session) { if ($dummy_session) {
unset($_SESSION['authenticated']); unset($_SESSION['authenticated']);
unset($_SESSION['uid']); unset($_SESSION['uid']);
} }
} elseif (!$notify) { } elseif (!$notify) {
Hook::callAll('post_remote', $item); /** @var array<string,mixed> */
$item = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_REMOTE, $item)
)->getArray();
} }
if (!empty($item['cancel'])) { if (!empty($item['cancel'])) {
@ -1116,7 +1124,11 @@ class Item
DI::contentItem()->copyPermissions($posted_item['thr-parent-id'], $posted_item['uri-id'], $posted_item['parent-uri-id']); DI::contentItem()->copyPermissions($posted_item['thr-parent-id'], $posted_item['uri-id'], $posted_item['parent-uri-id']);
} }
} else { } else {
Hook::callAll('post_remote_end', $posted_item); $eventDispatcher = DI::eventDispatcher();
$posted_item = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_REMOTE_END, $posted_item)
)->getArray();
} }
if ($posted_item['gravity'] === self::GRAVITY_PARENT) { if ($posted_item['gravity'] === self::GRAVITY_PARENT) {
@ -1901,18 +1913,23 @@ class Item
$result = []; $result = [];
$eventDispatcher = DI::eventDispatcher();
foreach (self::splitByBlocks($searchtext) as $block) { foreach (self::splitByBlocks($searchtext) as $block) {
$languages = $ld->detect($block)->close() ?: []; $languages = $ld->detect($block)->close() ?: [];
$data = [ $hook_data = [
'text' => $block, 'text' => $block,
'detected' => $languages, 'detected' => $languages,
'uri-id' => $uri_id, 'uri-id' => $uri_id,
'author-id' => $author_id, 'author-id' => $author_id,
]; ];
Hook::callAll('detect_languages', $data);
foreach ($data['detected'] as $language => $quality) { $hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::DETECT_LANGUAGES, $hook_data),
)->getArray();
foreach ($hook_data['detected'] as $language => $quality) {
$result[$language] = max($result[$language] ?? 0, $quality * (strlen($block) / strlen($searchtext))); $result[$language] = max($result[$language] ?? 0, $quality * (strlen($block) / strlen($searchtext)));
} }
} }
@ -2278,9 +2295,16 @@ class Item
return true; return true;
} }
$arr = ['item' => $item, 'user' => $owner]; $eventDispatcher = DI::eventDispatcher();
Hook::callAll('tagged', $arr); $arr = [
'item' => $item,
'user' => $owner,
];
$eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ITEM_TAGGED, $arr),
);
} else { } else {
if (Tag::isMentioned($item['parent-uri-id'], $owner['url'])) { if (Tag::isMentioned($item['parent-uri-id'], $owner['url'])) {
DI::logger()->info('Mention found in parent tag.', ['uri' => $item['uri'], 'uid' => $uid, 'id' => $item_id, 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]); DI::logger()->info('Mention found in parent tag.', ['uri' => $item['uri'], 'uid' => $uid, 'id' => $item_id, 'uri-id' => $item['uri-id'], 'guid' => $item['guid']]);
@ -3024,8 +3048,18 @@ class Item
$item['rendered-html'] = BBCode::convertForUriId($item['uri-id'], $item['body']); $item['rendered-html'] = BBCode::convertForUriId($item['uri-id'], $item['body']);
$item['rendered-hash'] = hash('md5', BBCode::VERSION . '::' . $body); $item['rendered-hash'] = hash('md5', BBCode::VERSION . '::' . $body);
$hook_data = ['item' => $item, 'rendered-html' => $item['rendered-html'], 'rendered-hash' => $item['rendered-hash']]; $hook_data = [
Hook::callAll('put_item_in_cache', $hook_data); 'rendered-html' => $item['rendered-html'],
'rendered-hash' => $item['rendered-hash'],
'item' => $item,
];
$eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::CACHE_ITEM, $hook_data),
)->getArray();
$item['rendered-html'] = $hook_data['rendered-html']; $item['rendered-html'] = $hook_data['rendered-html'];
$item['rendered-hash'] = $hook_data['rendered-hash']; $item['rendered-hash'] = $hook_data['rendered-hash'];
unset($hook_data); unset($hook_data);
@ -3056,23 +3090,22 @@ class Item
* @return string item body html * @return string item body html
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
* @hook prepare_body_init item array before any work
* @hook prepare_body_content_filter ('item'=>item array, 'filter_reasons'=>string array) before first bbcode to html
* @hook prepare_body ('item'=>item array, 'html'=>body string, 'is_preview'=>boolean, 'filter_reasons'=>string array) after first bbcode to html
* @hook prepare_body_final ('item'=>item array, 'html'=>body string) after attach icons and blockquote special case handling (spoiler, author)
*/ */
public static function prepareBody(array &$item, bool $attach = false, bool $is_preview = false, bool $only_cache = false): string public static function prepareBody(array &$item, bool $attach = false, bool $is_preview = false, bool $only_cache = false): string
{ {
$appHelper = DI::appHelper(); $appHelper = DI::appHelper();
$uid = DI::userSession()->getLocalUserId(); $uid = DI::userSession()->getLocalUserId();
$eventDispatcher = DI::eventDispatcher();
$item_copy = $item; $hook_data = [
'item' => $item,
];
Hook::callAll('prepare_body_init', $item_copy); $hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_START, $hook_data),
)->getArray();
if (is_array($item_copy)) { $item = $hook_data['item'] ?? $item;
$item = $item_copy;
}
// In order to provide theme developers more possibilities, event items // In order to provide theme developers more possibilities, event items
// are treated differently. // are treated differently.
@ -3191,7 +3224,11 @@ class Item
'item' => $item, 'item' => $item,
'filter_reasons' => $filter_reasons 'filter_reasons' => $filter_reasons
]; ];
Hook::callAll('prepare_body_content_filter', $hook_data);
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, $hook_data),
)->getArray();
$filter_reasons = $hook_data['filter_reasons']; $filter_reasons = $hook_data['filter_reasons'];
unset($hook_data); unset($hook_data);
} }
@ -3210,7 +3247,11 @@ class Item
'preview' => $is_preview, 'preview' => $is_preview,
'filter_reasons' => $filter_reasons 'filter_reasons' => $filter_reasons
]; ];
Hook::callAll('prepare_body', $hook_data);
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST, $hook_data),
)->getArray();
$s = $hook_data['html']; $s = $hook_data['html'];
unset($hook_data); unset($hook_data);
@ -3262,9 +3303,16 @@ class Item
$s = HTML::applyContentFilter($s, $filter_reasons); $s = HTML::applyContentFilter($s, $filter_reasons);
$hook_data = ['item' => $item, 'html' => $s]; $hook_data = [
Hook::callAll('prepare_body_final', $hook_data); 'item' => $item,
return $hook_data['html']; 'html' => $s,
];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_END, $hook_data),
)->getArray();
return (string) $hook_data['html'] ?? $s;
} }
/** /**
@ -3913,17 +3961,21 @@ class Item
return 0; return 0;
} }
$hookData = [ $eventDispatcher = DI::eventDispatcher();
$hook_data = [
'uri' => $uri, 'uri' => $uri,
'uid' => $uid, 'uid' => $uid,
'item_id' => null, 'item_id' => null,
]; ];
Hook::callAll('item_by_link', $hookData); $hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::FETCH_ITEM_BY_LINK, $hook_data)
)->getArray();
if (isset($hookData['item_id'])) { if (isset($hook_data['item_id'])) {
DI::logger()->info('Hook link fetched', ['uid' => $uid, 'uri' => $uri, 'id' => $hookData['item_id']]); DI::logger()->info('Hook link fetched', ['uid' => $uid, 'uri' => $uri, 'id' => $hook_data['item_id']]);
return is_numeric($hookData['item_id']) ? $hookData['item_id'] : 0; return is_numeric($hook_data['item_id']) ? $hook_data['item_id'] : 0;
} }
if (!$mimetype) { if (!$mimetype) {

View file

@ -9,10 +9,10 @@ namespace Friendica\Model\Post;
use BadMethodCallException; use BadMethodCallException;
use Exception; use Exception;
use Friendica\Core\Hook;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Item; use Friendica\Model\Item;
use Friendica\Model\Post; use Friendica\Model\Post;
@ -396,7 +396,12 @@ class UserNotification
$profiles = [$owner['nurl']]; $profiles = [$owner['nurl']];
$notification_data = ['uid' => $uid, 'profiles' => []]; $notification_data = ['uid' => $uid, 'profiles' => []];
Hook::callAll('check_item_notification', $notification_data);
$eventDispatcher = DI::eventDispatcher();
$notification_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::CHECK_ITEM_NOTIFICATION, $notification_data),
)->getArray();
// Normalize the connector profiles // Normalize the connector profiles
foreach ($notification_data['profiles'] as $profile) { foreach ($notification_data['profiles'] as $profile) {

View file

@ -12,13 +12,13 @@ use Friendica\AppHelper;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Widget\ContactBlock; use Friendica\Content\Widget\ContactBlock;
use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Enum\Duration;
use Friendica\Core\Hook;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Search; use Friendica\Core\Search;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Protocol\Activity; use Friendica\Protocol\Activity;
use Friendica\Protocol\Diaspora; use Friendica\Protocol\Diaspora;
@ -258,11 +258,6 @@ class Profile
* @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
* @note Returns empty string if passed $profile is wrong type or not populated * @note Returns empty string if passed $profile is wrong type or not populated
*
* @hooks 'profile_sidebar_enter'
* array $profile - profile data
* @hooks 'profile_sidebar'
* array $arr
*/ */
public static function getVCardHtml(array $profile, bool $block, bool $show_contacts): string public static function getVCardHtml(array $profile, bool $block, bool $show_contacts): string
{ {
@ -282,7 +277,17 @@ class Profile
$profile['network_link'] = ''; $profile['network_link'] = '';
Hook::callAll('profile_sidebar_enter', $profile); $eventDispatcher = DI::eventDispatcher();
$hook_data = [
'profile' => $profile,
];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY, $hook_data),
)->getArray();
$profile = $hook_data['profile'] ?? $profile;
$profile_url = $profile['url']; $profile_url = $profile['url'];
@ -473,9 +478,17 @@ class Profile
'$network_url' => $network_url, '$network_url' => $network_url,
]); ]);
$arr = ['profile' => &$profile, 'entry' => &$o]; $hook_data = [
'profile' => &$profile,
'entry' => &$o,
];
Hook::callAll('profile_sidebar', $arr); $hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SIDEBAR, $hook_data),
)->getArray();
$profile = $hook_data['profile'] ?? $profile;
$o = $hook_data['entry'] ?? $o;
return $o; return $o;
} }

View file

@ -13,7 +13,6 @@ use ErrorException;
use Exception; use Exception;
use Friendica\App; use Friendica\App;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Search; use Friendica\Core\Search;
@ -21,6 +20,7 @@ use Friendica\Core\System;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Module; use Friendica\Module;
use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPClient\Client\HttpClientOptions;
@ -758,12 +758,16 @@ class User
'user_record' => null 'user_record' => null
]; ];
/* $eventDispatcher = DI::eventDispatcher();
/**
* An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record
* Addons should never set 'authenticated' except to indicate success - as hooks may be chained * Addons should never set 'authenticated' except to indicate success - as hooks may be chained
* and later addons should not interfere with an earlier one that succeeded. * and later addons should not interfere with an earlier one that succeeded.
*/ */
Hook::callAll('authenticate', $addon_auth); $addon_auth = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_AUTHENTICATE, $addon_auth),
)->getArray();
if ($addon_auth['authenticated'] && $addon_auth['user_record']) { if ($addon_auth['authenticated'] && $addon_auth['user_record']) {
return $addon_auth['user_record']['uid']; return $addon_auth['user_record']['uid'];
@ -1460,11 +1464,20 @@ class User
Contact::updateSelfFromUserID($uid, true); Contact::updateSelfFromUserID($uid, true);
} }
Hook::callAll('register_account', $uid); $eventDispatcher = DI::eventDispatcher();
$hook_data = [
'uid' => $uid,
];
$eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REGISTER, $hook_data),
);
self::setRegisterMethodByUserCount(); self::setRegisterMethodByUserCount();
$return['user'] = $user; $return['user'] = $user;
return $return; return $return;
} }
@ -1787,7 +1800,17 @@ class User
throw new \RuntimeException(DI::l10n()->t("User with delegates can't be removed, please remove delegate users first")); throw new \RuntimeException(DI::l10n()->t("User with delegates can't be removed, please remove delegate users first"));
} }
Hook::callAll('remove_user', $user); $eventDispatcher = DI::eventDispatcher();
$hook_data = [
'user' => $user,
];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REMOVE, $hook_data),
)->getArray();
$user = $hook_data['user'] ?? $user;
// save username (actually the nickname as it is guaranteed // save username (actually the nickname as it is guaranteed
// unique), so it cannot be re-registered in the future. // unique), so it cannot be re-registered in the future.

View file

@ -9,9 +9,9 @@ namespace Friendica\Module;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Feature; use Friendica\Content\Feature;
use Friendica\Core\Hook;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\User; use Friendica\Model\User;
class BaseProfile extends BaseModule class BaseProfile extends BaseModule
@ -128,12 +128,16 @@ class BaseProfile extends BaseModule
]; ];
} }
$arr = ['is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => $current, 'tabs' => $tabs]; $hook_data = ['is_owner' => $is_owner, 'nickname' => $nickname, 'tab' => $current, 'tabs' => $tabs];
Hook::callAll('profile_tabs', $arr); $eventDispatcher = DI::eventDispatcher();
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_TABS, $hook_data),
)->getArray();
$tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); $tpl = Renderer::getMarkupTemplate('common_tabs.tpl');
return Renderer::replaceMacros($tpl, ['$tabs' => $arr['tabs'], '$more' => DI::l10n()->t('More')]); return Renderer::replaceMacros($tpl, ['$tabs' => $hook_data['tabs'], '$more' => DI::l10n()->t('More')]);
} }
} }

View file

@ -7,31 +7,37 @@
namespace Friendica\Module\Contact; namespace Friendica\Module\Contact;
use Friendica\App; use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\App\Page;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Contact\LocalRelationship;
use Friendica\Contact\LocalRelationship\Entity\LocalRelationship as LocalRelationshipEntity; use Friendica\Contact\LocalRelationship\Entity\LocalRelationship as LocalRelationshipEntity;
use Friendica\Contact\LocalRelationship\Repository\LocalRelationship as LocalRelationshipRepository;
use Friendica\Content\ContactSelector; use Friendica\Content\ContactSelector;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Widget; use Friendica\Content\Widget;
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\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Circle; use Friendica\Model\Circle;
use Friendica\Model\Contact; use Friendica\Model\Contact as ContactModel;
use Friendica\Module; use Friendica\Model\Contact\User as UserContact;
use Friendica\Module\Contact as ContactModule;
use Friendica\Module\Response; use Friendica\Module\Response;
use Friendica\Module\Security\Login;
use Friendica\Navigation\SystemMessages; use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException\InternalServerErrorException;
use Friendica\User\Settings; use Friendica\Network\HTTPException\NotFoundException;
use Friendica\User\Settings\Repository\UserGServer as UserGServerRepository;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -39,9 +45,9 @@ use Psr\Log\LoggerInterface;
*/ */
class Profile extends BaseModule class Profile extends BaseModule
{ {
/** @var LocalRelationship\Repository\LocalRelationship */ /** @var LocalRelationshipRepository */
private $localRelationship; private $localRelationship;
/** @var App\Page */ /** @var Page */
private $page; private $page;
/** @var IManageConfigValues */ /** @var IManageConfigValues */
private $config; private $config;
@ -51,11 +57,28 @@ class Profile extends BaseModule
private $systemMessages; private $systemMessages;
/** @var Database */ /** @var Database */
private $db; private $db;
/** @var Settings\Repository\UserGServer */ /** @var UserGServerRepository */
private $userGServer; private $userGServer;
private EventDispatcherInterface $eventDispatcher;
public function __construct(Settings\Repository\UserGServer $userGServer, Database $db, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, LocalRelationship\Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) public function __construct(
{ UserGServerRepository $userGServer,
EventDispatcherInterface $eventDispatcher,
Database $db,
SystemMessages $systemMessages,
IHandleUserSessions $session,
L10n $l10n,
LocalRelationshipRepository $localRelationship,
BaseURL $baseUrl,
Arguments $args,
LoggerInterface $logger,
Profiler $profiler,
Response $response,
Page $page,
IManageConfigValues $config,
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->localRelationship = $localRelationship; $this->localRelationship = $localRelationship;
@ -65,6 +88,7 @@ class Profile extends BaseModule
$this->systemMessages = $systemMessages; $this->systemMessages = $systemMessages;
$this->db = $db; $this->db = $db;
$this->userGServer = $userGServer; $this->userGServer = $userGServer;
$this->eventDispatcher = $eventDispatcher;
} }
protected function post(array $request = []) protected function post(array $request = [])
@ -77,12 +101,14 @@ class Profile extends BaseModule
// Backward compatibility: The update still needs a user-specific contact ID // Backward compatibility: The update still needs a user-specific contact ID
// Change to user-contact table check by version 2022.03 // Change to user-contact table check by version 2022.03
$ucid = Contact::getUserContactId($contact_id, $this->session->getLocalUserId()); $ucid = ContactModel::getUserContactId($contact_id, $this->session->getLocalUserId());
if (!$ucid || !$this->db->exists('contact', ['id' => $ucid, 'deleted' => false])) { if (!$ucid || !$this->db->exists('contact', ['id' => $ucid, 'deleted' => false])) {
return; return;
} }
Hook::callAll('contact_edit_post', $request); $request = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::EDIT_CONTACT_POST, $request),
)->getArray();
$fields = []; $fields = [];
@ -120,14 +146,14 @@ class Profile extends BaseModule
} }
if (isset($request['channel_frequency'])) { if (isset($request['channel_frequency'])) {
Contact\User::setChannelFrequency($ucid, $this->session->getLocalUserId(), $request['channel_frequency']); UserContact::setChannelFrequency($ucid, $this->session->getLocalUserId(), $request['channel_frequency']);
} }
if (isset($request['channel_only'])) { if (isset($request['channel_only'])) {
Contact\User::setChannelOnly($ucid, $this->session->getLocalUserId(), $request['channel_only']); UserContact::setChannelOnly($ucid, $this->session->getLocalUserId(), $request['channel_only']);
} }
if (!Contact::update($fields, ['id' => $ucid, 'uid' => $this->session->getLocalUserId()])) { if (!ContactModel::update($fields, ['id' => $ucid, 'uid' => $this->session->getLocalUserId()])) {
$this->systemMessages->addNotice($this->t('Failed to update contact record.')); $this->systemMessages->addNotice($this->t('Failed to update contact record.'));
} }
$this->baseUrl->redirect('contact/' . $contact_id); $this->baseUrl->redirect('contact/' . $contact_id);
@ -136,43 +162,43 @@ class Profile extends BaseModule
protected function content(array $request = []): string protected function content(array $request = []): string
{ {
if (!$this->session->getLocalUserId()) { if (!$this->session->getLocalUserId()) {
return Module\Security\Login::form($_SERVER['REQUEST_URI']); return Login::form($_SERVER['REQUEST_URI']);
} }
// Backward compatibility: Ensure to use the public contact when the user contact is provided // Backward compatibility: Ensure to use the public contact when the user contact is provided
// Remove by version 2022.03 // Remove by version 2022.03
$data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), $this->session->getLocalUserId()); $data = ContactModel::getPublicAndUserContactID(intval($this->parameters['id']), $this->session->getLocalUserId());
if (empty($data)) { if (empty($data)) {
throw new HTTPException\NotFoundException($this->t('Contact not found.')); throw new NotFoundException($this->t('Contact not found.'));
} }
$contact = Contact::getById($data['public']); $contact = ContactModel::getById($data['public']);
if (!$this->db->isResult($contact)) { if (!$this->db->isResult($contact)) {
throw new HTTPException\NotFoundException($this->t('Contact not found.')); throw new NotFoundException($this->t('Contact not found.'));
} }
// Fetch the protocol from the user's contact. // Fetch the protocol from the user's contact.
if ($data['user']) { if ($data['user']) {
$usercontact = Contact::getById($data['user'], ['network', 'protocol']); $usercontact = ContactModel::getById($data['user'], ['network', 'protocol']);
if ($this->db->isResult($usercontact)) { if ($this->db->isResult($usercontact)) {
$contact['network'] = $usercontact['network']; $contact['network'] = $usercontact['network'];
$contact['protocol'] = $usercontact['protocol']; $contact['protocol'] = $usercontact['protocol'];
} }
} }
if (empty($contact['network']) && Contact::isLocal($contact['url']) ) { if (empty($contact['network']) && ContactModel::isLocal($contact['url']) ) {
$contact['network'] = Protocol::DFRN; $contact['network'] = Protocol::DFRN;
$contact['protocol'] = Protocol::ACTIVITYPUB; $contact['protocol'] = Protocol::ACTIVITYPUB;
} }
// Don't display contacts that are about to be deleted // Don't display contacts that are about to be deleted
if ($contact['deleted'] || $contact['network'] == Protocol::PHANTOM) { if ($contact['deleted'] || $contact['network'] == Protocol::PHANTOM) {
throw new HTTPException\NotFoundException($this->t('Contact not found.')); throw new NotFoundException($this->t('Contact not found.'));
} }
$localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $contact['id']); $localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $contact['id']);
if ($localRelationship->rel === Contact::SELF) { if ($localRelationship->rel === ContactModel::SELF) {
$this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile'); $this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile');
} }
@ -180,8 +206,8 @@ class Profile extends BaseModule
self::checkFormSecurityTokenRedirectOnError('contact/' . $contact['id'], 'contact_action', 't'); self::checkFormSecurityTokenRedirectOnError('contact/' . $contact['id'], 'contact_action', 't');
$cmd = $this->parameters['action']; $cmd = $this->parameters['action'];
if ($cmd === 'update' && $localRelationship->rel !== Contact::NOTHING) { if ($cmd === 'update' && $localRelationship->rel !== ContactModel::NOTHING) {
Module\Contact::updateContactFromPoll($contact['id']); ContactModule::updateContactFromPoll($contact['id']);
} }
if ($cmd === 'updateprofile') { if ($cmd === 'updateprofile') {
@ -191,12 +217,12 @@ class Profile extends BaseModule
if ($cmd === 'block') { if ($cmd === 'block') {
if ($localRelationship->blocked) { if ($localRelationship->blocked) {
// @TODO Backward compatibility, replace with $localRelationship->unblock() // @TODO Backward compatibility, replace with $localRelationship->unblock()
Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), false); UserContact::setBlocked($contact['id'], $this->session->getLocalUserId(), false);
$message = $this->t('Contact has been unblocked'); $message = $this->t('Contact has been unblocked');
} else { } else {
// @TODO Backward compatibility, replace with $localRelationship->block() // @TODO Backward compatibility, replace with $localRelationship->block()
Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), true); UserContact::setBlocked($contact['id'], $this->session->getLocalUserId(), true);
$message = $this->t('Contact has been blocked'); $message = $this->t('Contact has been blocked');
} }
@ -207,12 +233,12 @@ class Profile extends BaseModule
if ($cmd === 'ignore') { if ($cmd === 'ignore') {
if ($localRelationship->ignored) { if ($localRelationship->ignored) {
// @TODO Backward compatibility, replace with $localRelationship->unblock() // @TODO Backward compatibility, replace with $localRelationship->unblock()
Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), false); UserContact::setIgnored($contact['id'], $this->session->getLocalUserId(), false);
$message = $this->t('Contact has been unignored'); $message = $this->t('Contact has been unignored');
} else { } else {
// @TODO Backward compatibility, replace with $localRelationship->block() // @TODO Backward compatibility, replace with $localRelationship->block()
Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), true); UserContact::setIgnored($contact['id'], $this->session->getLocalUserId(), true);
$message = $this->t('Contact has been ignored'); $message = $this->t('Contact has been ignored');
} }
@ -223,12 +249,12 @@ class Profile extends BaseModule
if ($cmd === 'collapse') { if ($cmd === 'collapse') {
if ($localRelationship->collapsed) { if ($localRelationship->collapsed) {
// @TODO Backward compatibility, replace with $localRelationship->unblock() // @TODO Backward compatibility, replace with $localRelationship->unblock()
Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), false); UserContact::setCollapsed($contact['id'], $this->session->getLocalUserId(), false);
$message = $this->t('Contact has been uncollapsed'); $message = $this->t('Contact has been uncollapsed');
} else { } else {
// @TODO Backward compatibility, replace with $localRelationship->block() // @TODO Backward compatibility, replace with $localRelationship->block()
Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), true); UserContact::setCollapsed($contact['id'], $this->session->getLocalUserId(), true);
$message = $this->t('Contact has been collapsed'); $message = $this->t('Contact has been collapsed');
} }
@ -239,10 +265,10 @@ class Profile extends BaseModule
$this->baseUrl->redirect('contact/' . $contact['id']); $this->baseUrl->redirect('contact/' . $contact['id']);
} }
$vcard_widget = Widget\VCard::getHTML($contact); $vcard_widget = Widget\VCard::getHTML($contact);
$circles_widget = ''; $circles_widget = '';
if (!in_array($localRelationship->rel, [Contact::NOTHING, Contact::SELF])) { if (!in_array($localRelationship->rel, [ContactModel::NOTHING, ContactModel::SELF])) {
$circles_widget = Circle::sidebarWidget('contact', 'circle', 'full', 'everyone', $data['user']); $circles_widget = Circle::sidebarWidget('contact', 'circle', 'full', 'everyone', $data['user']);
} }
@ -257,9 +283,15 @@ class Profile extends BaseModule
]); ]);
switch ($localRelationship->rel) { switch ($localRelationship->rel) {
case Contact::FRIEND: $relation_text = $this->t('You are mutual friends with %s', $contact['name']); break; case ContactModel::FRIEND:
case Contact::FOLLOWER: $relation_text = $this->t('You are sharing with %s', $contact['name']); break; $relation_text = $this->t('You are mutual friends with %s', $contact['name']);
case Contact::SHARING: $relation_text = $this->t('%s is sharing with you', $contact['name']); break; break;
case ContactModel::FOLLOWER:
$relation_text = $this->t('You are sharing with %s', $contact['name']);
break;
case ContactModel::SHARING:
$relation_text = $this->t('%s is sharing with you', $contact['name']);
break;
default: default:
$relation_text = ''; $relation_text = '';
} }
@ -268,7 +300,7 @@ class Profile extends BaseModule
$relation_text = ''; $relation_text = '';
} }
$url = Contact::magicLinkByContact($contact); $url = ContactModel::magicLinkByContact($contact);
if (strpos($url, 'contact/redir/') === 0) { if (strpos($url, 'contact/redir/') === 0) {
$sparkle = ' class="sparkle" '; $sparkle = ' class="sparkle" ';
} else { } else {
@ -282,8 +314,7 @@ class Profile extends BaseModule
$this->logger->notice('Empty gsid for contact', ['contact' => $contact]); $this->logger->notice('Empty gsid for contact', ['contact' => $contact]);
} }
$serverIgnored = $serverIgnored = $contact['gsid'] &&
$contact['gsid'] &&
$this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ? $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ?
$this->t('This contact is on a server you ignored.') $this->t('This contact is on a server you ignored.')
: ''; : '';
@ -300,7 +331,7 @@ class Profile extends BaseModule
$nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['protocol'], $contact['gsid'])); $nettype = $this->t('Network type: %s', ContactSelector::networkToName($contact['network'], $contact['protocol'], $contact['gsid']));
// tabs // tabs
$tab_str = Module\Contact::getTabsHTML($contact, Module\Contact::TAB_PROFILE); $tab_str = ContactModule::getTabsHTML($contact, ContactModule::TAB_PROFILE);
$lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : ''); $lost_contact = (($contact['archive'] && $contact['term-date'] > DBA::NULL_DATETIME && $contact['term-date'] < DateTimeFormat::utcNow()) ? $this->t('Communications lost with this contact!') : '');
@ -312,10 +343,10 @@ class Profile extends BaseModule
$localRelationship->fetchFurtherInformation, $localRelationship->fetchFurtherInformation,
$this->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'), $this->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'),
[ [
LocalRelationship\Entity\LocalRelationship::FFI_NONE => $this->t('Disabled'), LocalRelationshipEntity::FFI_NONE => $this->t('Disabled'),
LocalRelationship\Entity\LocalRelationship::FFI_INFORMATION => $this->t('Fetch information'), LocalRelationshipEntity::FFI_INFORMATION => $this->t('Fetch information'),
LocalRelationship\Entity\LocalRelationship::FFI_KEYWORD => $this->t('Fetch keywords'), LocalRelationshipEntity::FFI_KEYWORD => $this->t('Fetch keywords'),
LocalRelationship\Entity\LocalRelationship::FFI_BOTH => $this->t('Fetch information and keywords') LocalRelationshipEntity::FFI_BOTH => $this->t('Fetch information and keywords')
] ]
]; ];
} }
@ -346,8 +377,8 @@ class Profile extends BaseModule
]; ];
} }
$channel_frequency = Contact\User::getChannelFrequency($contact['id'], $this->session->getLocalUserId()); $channel_frequency = UserContact::getChannelFrequency($contact['id'], $this->session->getLocalUserId());
$channel_only = Contact\User::getChannelOnly($contact['id'], $this->session->getLocalUserId()); $channel_only = UserContact::getChannelOnly($contact['id'], $this->session->getLocalUserId());
$poll_interval = null; $poll_interval = null;
if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) { if ((($contact['network'] == Protocol::FEED) && !$this->config->get('system', 'adjust_poll_frequency')) || ($contact['network'] == Protocol::MAIL)) {
@ -356,12 +387,12 @@ class Profile extends BaseModule
$contact_actions = $this->getContactActions($contact, $localRelationship); $contact_actions = $this->getContactActions($contact, $localRelationship);
if (Contact\User::isIsBlocked($contact['id'], $this->session->getLocalUserId())) { if (UserContact::isIsBlocked($contact['id'], $this->session->getLocalUserId())) {
$relation_text = $this->t('%s has blocked you', $contact['name'] ?: $contact['nick']); $relation_text = $this->t('%s has blocked you', $contact['name'] ?: $contact['nick']);
unset($contact_actions['follow']); unset($contact_actions['follow']);
} }
if ($localRelationship->rel !== Contact::NOTHING) { if ($localRelationship->rel !== ContactModel::NOTHING) {
$lbl_info1 = $this->t('Contact Information / Notes'); $lbl_info1 = $this->t('Contact Information / Notes');
$contact_settings_label = $this->t('Contact Settings'); $contact_settings_label = $this->t('Contact Settings');
} else { } else {
@ -407,13 +438,13 @@ class Profile extends BaseModule
'$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')], '$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')],
'$fetch_further_information' => $fetch_further_information, '$fetch_further_information' => $fetch_further_information,
'$ffi_keyword_denylist' => ['ffi_keyword_denylist', $this->t('Keyword Deny List'), $localRelationship->ffiKeywordDenylist, $this->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')], '$ffi_keyword_denylist' => ['ffi_keyword_denylist', $this->t('Keyword Deny List'), $localRelationship->ffiKeywordDenylist, $this->t('Comma separated list of keywords that should not be converted to hashtags, when "Fetch information and keywords" is selected')],
'$photo' => Contact::getPhoto($contact), '$photo' => ContactModel::getPhoto($contact),
'$name' => $contact['name'], '$name' => $contact['name'],
'$sparkle' => $sparkle, '$sparkle' => $sparkle,
'$url' => $url, '$url' => $url,
'$profileurllabel' => $this->t('Profile URL'), '$profileurllabel' => $this->t('Profile URL'),
'$profileurl' => $contact['url'], '$profileurl' => $contact['url'],
'$account_type' => Contact::getAccountType($contact['contact-type']), '$account_type' => ContactModel::getAccountType($contact['contact-type']),
'$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']), '$location' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['location']),
'$location_label' => $this->t('Location:'), '$location_label' => $this->t('Location:'),
'$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']), '$xmpp' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['xmpp']),
@ -440,18 +471,23 @@ class Profile extends BaseModule
'$channel_settings_label' => $this->t('Channel Settings'), '$channel_settings_label' => $this->t('Channel Settings'),
'$frequency_label' => $this->t('Frequency of this contact in relevant channels'), '$frequency_label' => $this->t('Frequency of this contact in relevant channels'),
'$frequency_description' => $this->t("Depending on the type of the channel not all posts from this contact are displayed. By default, posts need to have a minimum amount of interactions (comments, likes) to show in your channels. On the other hand there can be contacts who flood the channel, so you might want to see only some of their posts. Or you don't want to see their content at all, but you don't want to block or hide the contact completely."), '$frequency_description' => $this->t("Depending on the type of the channel not all posts from this contact are displayed. By default, posts need to have a minimum amount of interactions (comments, likes) to show in your channels. On the other hand there can be contacts who flood the channel, so you might want to see only some of their posts. Or you don't want to see their content at all, but you don't want to block or hide the contact completely."),
'$frequency_default' => ['channel_frequency', $this->t('Default frequency'), Contact\User::FREQUENCY_DEFAULT, $this->t('Posts by this contact are displayed in the "for you" channel if you interact often with this contact or if a post reached some level of interaction.'), $channel_frequency == Contact\User::FREQUENCY_DEFAULT], '$frequency_default' => ['channel_frequency', $this->t('Default frequency'), UserContact::FREQUENCY_DEFAULT, $this->t('Posts by this contact are displayed in the "for you" channel if you interact often with this contact or if a post reached some level of interaction.'), $channel_frequency == UserContact::FREQUENCY_DEFAULT],
'$frequency_always' => ['channel_frequency', $this->t('Display all posts of this contact'), Contact\User::FREQUENCY_ALWAYS, $this->t('All posts from this contact will appear on the "for you" channel'), $channel_frequency == Contact\User::FREQUENCY_ALWAYS], '$frequency_always' => ['channel_frequency', $this->t('Display all posts of this contact'), UserContact::FREQUENCY_ALWAYS, $this->t('All posts from this contact will appear on the "for you" channel'), $channel_frequency == UserContact::FREQUENCY_ALWAYS],
'$frequency_reduced' => ['channel_frequency', $this->t('Display only few posts'), Contact\User::FREQUENCY_REDUCED, $this->t('When a contact creates a lot of posts in a short period, this setting reduces the number of displayed posts in every channel.'), $channel_frequency == Contact\User::FREQUENCY_REDUCED], '$frequency_reduced' => ['channel_frequency', $this->t('Display only few posts'), UserContact::FREQUENCY_REDUCED, $this->t('When a contact creates a lot of posts in a short period, this setting reduces the number of displayed posts in every channel.'), $channel_frequency == UserContact::FREQUENCY_REDUCED],
'$frequency_never' => ['channel_frequency', $this->t('Never display posts'), Contact\User::FREQUENCY_NEVER, $this->t('Posts from this contact will never be displayed in any channel'), $channel_frequency == Contact\User::FREQUENCY_NEVER], '$frequency_never' => ['channel_frequency', $this->t('Never display posts'), UserContact::FREQUENCY_NEVER, $this->t('Posts from this contact will never be displayed in any channel'), $channel_frequency == UserContact::FREQUENCY_NEVER],
'$channel_only' => ['channel_only', $this->t('Channel Only'), $channel_only, $this->t('If enabled, posts from this contact will only appear in channels and network streams in circles, but not in the general network stream.')], '$channel_only' => ['channel_only', $this->t('Channel Only'), $channel_only, $this->t('If enabled, posts from this contact will only appear in channels and network streams in circles, but not in the general network stream.')],
]); ]);
$arr = ['contact' => $contact, 'output' => $o]; $hook_data = [
'contact' => $contact,
'output' => $o,
];
Hook::callAll('contact_edit', $arr); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::EDIT_CONTACT_FORM, $hook_data),
)->getArray();
return $arr['output']; return $hook_data['output'] ?? $o;
} }
/** /**
@ -460,18 +496,18 @@ class Profile extends BaseModule
* This includes actions like e.g. 'block', 'hide', 'delete' and others * This includes actions like e.g. 'block', 'hide', 'delete' and others
* *
* @param array $contact Public contact row * @param array $contact Public contact row
* @param LocalRelationship\Entity\LocalRelationship $localRelationship *
* @return array with contact related actions * @return array with contact related actions
* @throws HTTPException\InternalServerErrorException * @throws InternalServerErrorException
*/ */
private function getContactActions(array $contact, LocalRelationship\Entity\LocalRelationship $localRelationship): array private function getContactActions(array $contact, LocalRelationshipEntity $localRelationship): array
{ {
$poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::FEED, Protocol::MAIL]); $poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::FEED, Protocol::MAIL]);
$contact_actions = []; $contact_actions = [];
$formSecurityToken = self::getFormSecurityToken('contact_action'); $formSecurityToken = self::getFormSecurityToken('contact_action');
if ($localRelationship->rel & Contact::SHARING) { if ($localRelationship->rel & ContactModel::SHARING) {
$contact_actions['unfollow'] = [ $contact_actions['unfollow'] = [
'label' => $this->t('Unfollow'), 'label' => $this->t('Unfollow'),
'url' => 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1', 'url' => 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1',
@ -544,7 +580,7 @@ class Profile extends BaseModule
'id' => 'toggle-collapse', 'id' => 'toggle-collapse',
]; ];
if (Protocol::supportsRevokeFollow($contact['network']) && in_array($localRelationship->rel, [Contact::FOLLOWER, Contact::FRIEND])) { if (Protocol::supportsRevokeFollow($contact['network']) && in_array($localRelationship->rel, [ContactModel::FOLLOWER, ContactModel::FRIEND])) {
$contact_actions['revoke_follow'] = [ $contact_actions['revoke_follow'] = [
'label' => $this->t('Revoke Follow'), 'label' => $this->t('Revoke Follow'),
'url' => 'contact/' . $contact['id'] . '/revoke', 'url' => 'contact/' . $contact['id'] . '/revoke',
@ -562,7 +598,7 @@ class Profile extends BaseModule
* *
* @param int $contact_id Id of the contact with uid != 0 * @param int $contact_id Id of the contact with uid != 0
* @return void * @return void
* @throws HTTPException\InternalServerErrorException * @throws InternalServerErrorException
* @throws \ImagickException * @throws \ImagickException
*/ */
private function updateContactFromProbe(int $contact_id) private function updateContactFromProbe(int $contact_id)
@ -572,6 +608,6 @@ class Profile extends BaseModule
} }
// Update the entry in the contact table // Update the entry in the contact table
Contact::updateFromProbe($contact_id); ContactModel::updateFromProbe($contact_id);
} }
} }

View file

@ -31,7 +31,6 @@ use Friendica\Content\Widget\TrendingTags;
use Friendica\Core\ACL; use Friendica\Core\ACL;
use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCache;
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\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
@ -39,6 +38,7 @@ use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Circle; use Friendica\Model\Circle;
use Friendica\Model\Post; use Friendica\Model\Post;
@ -49,6 +49,7 @@ use Friendica\Network\HTTPException;
use Friendica\Navigation\SystemMessages; use Friendica\Navigation\SystemMessages;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Network extends Timeline class Network extends Timeline
@ -90,12 +91,55 @@ class Network extends Timeline
protected $community; protected $community;
/** @var NetworkFactory */ /** @var NetworkFactory */
protected $networkFactory; protected $networkFactory;
private EventDispatcherInterface $eventDispatcher;
public function __construct(UserDefinedChannelFactory $userDefinedChannel, NetworkFactory $network, CommunityFactory $community, ChannelFactory $channelFactory, UserDefinedChannel $channel, AppHelper $appHelper, TimelineFactory $timeline, SystemMessages $systemMessages, Mode $mode, Conversation $conversation, Page $page, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ UserDefinedChannelFactory $userDefinedChannel,
parent::__construct($channel, $mode, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); NetworkFactory $network,
CommunityFactory $community,
ChannelFactory $channelFactory,
UserDefinedChannel $channel,
AppHelper $appHelper,
EventDispatcherInterface $eventDispatcher,
TimelineFactory $timeline,
SystemMessages $systemMessages,
Mode $mode,
Conversation $conversation,
Page $page,
IHandleUserSessions $session,
Database $database,
IManagePersonalConfigValues $pConfig,
IManageConfigValues $config,
ICanCache $cache,
L10n $l10n,
BaseURL $baseUrl,
Arguments $args,
LoggerInterface $logger,
Profiler $profiler,
Response $response,
array $server,
array $parameters = []
) {
parent::__construct(
$channel,
$mode,
$session,
$database,
$pConfig,
$config,
$cache,
$l10n,
$baseUrl,
$args,
$logger,
$profiler,
$response,
$server,
$parameters,
);
$this->appHelper = $appHelper; $this->appHelper = $appHelper;
$this->eventDispatcher = $eventDispatcher;
$this->timeline = $timeline; $this->timeline = $timeline;
$this->systemMessages = $systemMessages; $this->systemMessages = $systemMessages;
$this->conversation = $conversation; $this->conversation = $conversation;
@ -116,8 +160,13 @@ class Network extends Timeline
$module = 'network'; $module = 'network';
$arr = ['query' => $this->args->getQueryString()]; $hook_data = [
Hook::callAll('network_content_init', $arr); 'query' => $this->args->getQueryString(),
];
$this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::NETWORK_CONTENT_START, $hook_data)
);
$o = ''; $o = '';
@ -275,19 +324,24 @@ class Network extends Timeline
$tabs = array_merge($tabs, $this->getTabArray($this->community->getTimelines(true), 'network', 'channel')); $tabs = array_merge($tabs, $this->getTabArray($this->community->getTimelines(true), 'network', 'channel'));
} }
$arr = ['tabs' => $tabs]; $hook_data = [
Hook::callAll('network_tabs', $arr); 'tabs' => $tabs,
];
$hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::NETWORK_CONTENT_TABS, $hook_data)
)->getArray();
if (!empty($network_timelines)) { if (!empty($network_timelines)) {
$tabs = []; $tabs = [];
foreach ($arr['tabs'] as $tab) { foreach ($hook_data['tabs'] as $tab) {
if (in_array($tab['code'], $network_timelines)) { if (in_array($tab['code'], $network_timelines)) {
$tabs[] = $tab; $tabs[] = $tab;
} }
} }
} else { } else {
$tabs = $arr['tabs']; $tabs = $hook_data['tabs'];
} }
$tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); $tpl = Renderer::getMarkupTemplate('common_tabs.tpl');

View file

@ -11,10 +11,10 @@ use Friendica\BaseModule;
use Friendica\Content\Nav; use Friendica\Content\Nav;
use Friendica\Content\Pager; use Friendica\Content\Pager;
use Friendica\Content\Widget; use Friendica\Content\Widget;
use Friendica\Core\Hook;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Search; use Friendica\Core\Search;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model; use Friendica\Model;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
@ -39,7 +39,7 @@ class Directory extends BaseModule
DI::page()['aside'] .= Widget::follow(); DI::page()['aside'] .= Widget::follow();
} }
$output = ''; $output = '';
$entries = []; $entries = [];
Nav::setSelected('directory'); Nav::setSelected('directory');
@ -47,7 +47,7 @@ class Directory extends BaseModule
$search = trim(rawurldecode($_REQUEST['search'] ?? '')); $search = trim(rawurldecode($_REQUEST['search'] ?? ''));
$gDirPath = ''; $gDirPath = '';
$dirURL = Search::getGlobalDirectory(); $dirURL = Search::getGlobalDirectory();
if (strlen($dirURL)) { if (strlen($dirURL)) {
$gDirPath = OpenWebAuth::getZrlUrl($dirURL, true); $gDirPath = OpenWebAuth::getZrlUrl($dirURL, true);
} }
@ -161,13 +161,22 @@ class Directory extends BaseModule
]; ];
$hook = ['contact' => $contact, 'entry' => $entry]; $eventDispatcher = DI::eventDispatcher();
Hook::callAll('directory_item', $hook); $hook_data = [
'contact' => $contact,
'entry' => $entry,
];
$hook_data = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::DIRECTORY_ITEM, $hook_data),
)->getArray();
$entry = $hook_data['entry'] ?? $entry;
unset($profile); unset($profile);
unset($location); unset($location);
return $hook['entry']; return $entry;
} }
} }

View file

@ -13,16 +13,17 @@ use Friendica\App\BaseURL;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Addon\AddonHelper; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook;
use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs;
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\Database\PostUpdate; use Friendica\Database\PostUpdate;
use Friendica\Event\HtmlFilterEvent;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Protocol\ActivityPub; use Friendica\Protocol\ActivityPub;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -32,6 +33,7 @@ use Psr\Log\LoggerInterface;
class Friendica extends BaseModule class Friendica extends BaseModule
{ {
private AddonHelper $addonHelper; private AddonHelper $addonHelper;
private EventDispatcherInterface $eventDispatcher;
/** @var IManageConfigValues */ /** @var IManageConfigValues */
private $config; private $config;
/** @var IManageKeyValuePairs */ /** @var IManageKeyValuePairs */
@ -39,14 +41,28 @@ class Friendica extends BaseModule
/** @var IHandleUserSessions */ /** @var IHandleUserSessions */
private $session; private $session;
public function __construct(AddonHelper $addonHelper, IHandleUserSessions $session, IManageKeyValuePairs $keyValue, IManageConfigValues $config, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ AddonHelper $addonHelper,
EventDispatcherInterface $eventDispatcher,
IHandleUserSessions $session,
IManageKeyValuePairs $keyValue,
IManageConfigValues $config,
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->config = $config; $this->config = $config;
$this->keyValue = $keyValue; $this->keyValue = $keyValue;
$this->session = $session; $this->session = $session;
$this->addonHelper = $addonHelper; $this->eventDispatcher = $eventDispatcher;
$this->addonHelper = $addonHelper;
} }
protected function content(array $request = []): string protected function content(array $request = []): string
@ -99,7 +115,9 @@ class Friendica extends BaseModule
$hooked = ''; $hooked = '';
Hook::callAll('about_hook', $hooked); $hooked = $this->eventDispatcher->dispatch(
new HtmlFilterEvent(HtmlFilterEvent::MOD_ABOUT_CONTENT, $hooked),
)->getHtml();
$tpl = Renderer::getMarkupTemplate('friendica.tpl'); $tpl = Renderer::getMarkupTemplate('friendica.tpl');

View file

@ -8,10 +8,10 @@
namespace Friendica\Module; namespace Friendica\Module;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Core\Hook;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\Event; use Friendica\Event\Event;
use Friendica\Event\HtmlFilterEvent;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Module\Security\Login; use Friendica\Module\Security\Login;
use Friendica\Protocol\ActivityPub; use Friendica\Protocol\ActivityPub;
@ -66,7 +66,10 @@ class Home extends BaseModule
$login = Login::form(DI::args()->getQueryString(), Register::getPolicy() !== Register::CLOSED); $login = Login::form(DI::args()->getQueryString(), Register::getPolicy() !== Register::CLOSED);
$content = ''; $content = '';
Hook::callAll('home_content', $content);
$content = $eventDispatcher->dispatch(
new HtmlFilterEvent(HtmlFilterEvent::MOD_HOME_CONTENT, $content),
)->getHtml();
$tpl = Renderer::getMarkupTemplate('home.tpl'); $tpl = Renderer::getMarkupTemplate('home.tpl');
return Renderer::replaceMacros($tpl, [ return Renderer::replaceMacros($tpl, [

View file

@ -11,11 +11,11 @@ use Friendica\App\Arguments;
use Friendica\App\BaseURL; use Friendica\App\BaseURL;
use Friendica\App\Page; use Friendica\App\Page;
use Friendica\AppHelper; use Friendica\AppHelper;
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\Database\Database; use Friendica\Database\Database;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Register; use Friendica\Model\Register;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Module\BaseModeration; use Friendica\Module\BaseModeration;
@ -24,6 +24,7 @@ use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPException\ServiceUnavailableException; use Friendica\Network\HTTPException\ServiceUnavailableException;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
abstract class BaseUsers extends BaseModeration abstract class BaseUsers extends BaseModeration
@ -31,11 +32,28 @@ abstract class BaseUsers extends BaseModeration
/** @var Database */ /** @var Database */
protected $database; protected $database;
public function __construct(Database $database, Page $page, AppHelper $appHelper, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) private EventDispatcherInterface $eventDispatcher;
{
public function __construct(
Database $database,
EventDispatcherInterface $eventDispatcher,
Page $page,
AppHelper $appHelper,
SystemMessages $systemMessages,
IHandleUserSessions $session,
L10n $l10n,
BaseURL $baseUrl,
Arguments $args,
LoggerInterface $logger,
Profiler $profiler,
Response $response,
array $server,
array $parameters = []
) {
parent::__construct($page, $appHelper, $systemMessages, $session, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); parent::__construct($page, $appHelper, $systemMessages, $session, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->database = $database; $this->database = $database;
$this->eventDispatcher = $eventDispatcher;
} }
/** /**
@ -95,11 +113,21 @@ abstract class BaseUsers extends BaseModeration
'accesskey' => 'd', 'accesskey' => 'd',
], ],
]; ];
$tabs_arr = ['tabs' => $tabs, 'selectedTab' => $selectedTab];
Hook::callAll('moderation_users_tabs', $tabs_arr); $hook_data = [
'tabs' => $tabs,
'selectedTab' => $selectedTab,
];
$hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::MODERATION_USERS_TABS, $hook_data),
)->getArray();
$tabs = $hook_data['tabs'] ?? $tabs;
$tpl = Renderer::getMarkupTemplate('common_tabs.tpl'); $tpl = Renderer::getMarkupTemplate('common_tabs.tpl');
return Renderer::replaceMacros($tpl, ['$tabs' => $tabs_arr['tabs'], '$more' => $this->t('More')]);
return Renderer::replaceMacros($tpl, ['$tabs' => $tabs, '$more' => $this->t('More')]);
} }
protected function setupUserCallback(): \Closure protected function setupUserCallback(): \Closure

View file

@ -11,12 +11,13 @@ use Friendica\App\Arguments;
use Friendica\App\BaseURL; use Friendica\App\BaseURL;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Network\HTTPException\BadRequestException; use Friendica\Network\HTTPException\BadRequestException;
use Friendica\Util; use Friendica\Util;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class ParseUrl extends BaseModule class ParseUrl extends BaseModule
@ -24,11 +25,14 @@ class ParseUrl extends BaseModule
/** @var IHandleUserSessions */ /** @var IHandleUserSessions */
protected $userSession; protected $userSession;
public function __construct(L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $userSession, $server, array $parameters = []) private EventDispatcherInterface $eventDispatcher;
public function __construct(L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $userSession, EventDispatcherInterface $eventDispatcher, $server, array $parameters = [])
{ {
parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->userSession = $userSession; $this->userSession = $userSession;
$this->eventDispatcher = $eventDispatcher;
} }
protected function rawContent(array $request = []) protected function rawContent(array $request = [])
@ -37,10 +41,10 @@ class ParseUrl extends BaseModule
throw new \Friendica\Network\HTTPException\ForbiddenException(); throw new \Friendica\Network\HTTPException\ForbiddenException();
} }
$format = ''; $format = '';
$title = ''; $title = '';
$description = ''; $description = '';
$ret = ['success' => false, 'contentType' => '']; $ret = ['success' => false, 'contentType' => ''];
if (!empty($_GET['binurl']) && Util\Strings::isHex($_GET['binurl'])) { if (!empty($_GET['binurl']) && Util\Strings::isHex($_GET['binurl'])) {
$url = trim(hex2bin($_GET['binurl'])); $url = trim(hex2bin($_GET['binurl']));
@ -80,15 +84,21 @@ class ParseUrl extends BaseModule
} }
} }
$arr = ['url' => $url, 'format' => $format, 'text' => null]; $hook_data = [
'url' => $url,
'format' => $format,
'text' => null,
];
Hook::callAll('parse_link', $arr); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PARSE_LINK, $hook_data),
)->getArray();
if ($arr['text']) { if ($hook_data['text']) {
if ($format == 'json') { if ($format == 'json') {
$this->jsonExit($arr['text']); $this->jsonExit($hook_data['text']);
} else { } else {
$this->httpExit($arr['text']); $this->httpExit($hook_data['text']);
} }
} }
@ -109,14 +119,14 @@ class ParseUrl extends BaseModule
} }
$ret['contentType'] = $content_type; $ret['contentType'] = $content_type;
$ret['data'] = ['url' => $url]; $ret['data'] = ['url' => $url];
$ret['success'] = true; $ret['success'] = true;
} else { } else {
unset($siteinfo['keywords']); unset($siteinfo['keywords']);
$ret['data'] = $siteinfo; $ret['data'] = $siteinfo;
$ret['contentType'] = 'attachment'; $ret['contentType'] = 'attachment';
$ret['success'] = true; $ret['success'] = true;
} }
$this->jsonExit($ret); $this->jsonExit($ret);

View file

@ -31,6 +31,7 @@ use Friendica\Module\Conversation\Network as NetworkModule;
use Friendica\Module\Response; use Friendica\Module\Response;
use Friendica\Navigation\SystemMessages; use Friendica\Navigation\SystemMessages;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Network extends NetworkModule class Network extends NetworkModule
@ -40,9 +41,61 @@ class Network extends NetworkModule
*/ */
private $lock; private $lock;
public function __construct(ICanLock $lock, UserDefinedChannelFactory $userDefinedChannel, NetworkFactory $network, CommunityFactory $community, ChannelFactory $channelFactory, UserDefinedChannel $channel, AppHelper $appHelper, TimelineFactory $timeline, SystemMessages $systemMessages, Mode $mode, Conversation $conversation, Page $page, IHandleUserSessions $session, Database $database, IManagePersonalConfigValues $pConfig, IManageConfigValues $config, ICanCache $cache, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ ICanLock $lock,
parent::__construct($userDefinedChannel, $network, $community, $channelFactory, $channel, $appHelper, $timeline, $systemMessages, $mode, $conversation, $page, $session, $database, $pConfig, $config, $cache, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); UserDefinedChannelFactory $userDefinedChannel,
NetworkFactory $network,
CommunityFactory $community,
ChannelFactory $channelFactory,
UserDefinedChannel $channel,
AppHelper $appHelper,
EventDispatcherInterface $eventDispatcher,
TimelineFactory $timeline,
SystemMessages $systemMessages,
Mode $mode,
Conversation $conversation,
Page $page,
IHandleUserSessions $session,
Database $database,
IManagePersonalConfigValues $pConfig,
IManageConfigValues $config,
ICanCache $cache,
L10n $l10n,
BaseURL $baseUrl,
Arguments $args,
LoggerInterface $logger,
Profiler $profiler,
Response $response,
array $server,
array $parameters = []
) {
parent::__construct(
$userDefinedChannel,
$network,
$community,
$channelFactory,
$channel,
$appHelper,
$eventDispatcher,
$timeline,
$systemMessages,
$mode,
$conversation,
$page,
$session,
$database,
$pConfig,
$config,
$cache,
$l10n,
$baseUrl,
$args,
$logger,
$profiler,
$response,
$server,
$parameters
);
$this->lock = $lock; $this->lock = $lock;
} }

View file

@ -153,10 +153,16 @@ EOT;
$post['id'] = $post_id; $post['id'] = $post_id;
$post = $this->eventDispatcher->dispatch( $hook_data = [
new ArrayFilterEvent(ArrayFilterEvent::POST_LOCAL_END, $post) 'item' => $post,
];
$hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL_END, $hook_data)
)->getArray(); )->getArray();
$post = $hook_data['item'] ?? $post;
$post = Post::selectFirst(['uri-id', 'uid'], ['id' => $post_id]); $post = Post::selectFirst(['uri-id', 'uid'], ['id' => $post_id]);
Worker::add(Worker::PRIORITY_HIGH, 'Notifier', Delivery::POST, $post['uri-id'], $post['uid']); Worker::add(Worker::PRIORITY_HIGH, 'Notifier', Delivery::POST, $post['uri-id'], $post['uid']);

View file

@ -7,14 +7,16 @@
namespace Friendica\Module\Privacy; namespace Friendica\Module\Privacy;
use Friendica\App; use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\BaseModule;
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\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model; use Friendica\Model;
use Friendica\Module\Response; use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
@ -23,33 +25,50 @@ use Friendica\Privacy\Entity;
use Friendica\Security\PermissionSet\Repository\PermissionSet; use Friendica\Security\PermissionSet\Repository\PermissionSet;
use Friendica\Util\ACLFormatter; use Friendica\Util\ACLFormatter;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
* Outputs the permission tooltip HTML content for the provided item, photo or event id. * Outputs the permission tooltip HTML content for the provided item, photo or event id.
*/ */
class PermissionTooltip extends \Friendica\BaseModule class PermissionTooltip extends BaseModule
{ {
private Database $dba; private Database $dba;
private ACLFormatter $aclFormatter; private ACLFormatter $aclFormatter;
private IHandleUserSessions $session; private IHandleUserSessions $session;
private IManageConfigValues $config; private IManageConfigValues $config;
private PermissionSet $permissionSet; private PermissionSet $permissionSet;
private EventDispatcherInterface $eventDispatcher;
public function __construct(PermissionSet $permissionSet, IManageConfigValues $config, IHandleUserSessions $session, ACLFormatter $aclFormatter, Database $dba, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ PermissionSet $permissionSet,
IManageConfigValues $config,
IHandleUserSessions $session,
ACLFormatter $aclFormatter,
Database $dba,
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->dba = $dba; $this->dba = $dba;
$this->aclFormatter = $aclFormatter; $this->aclFormatter = $aclFormatter;
$this->session = $session; $this->session = $session;
$this->config = $config; $this->config = $config;
$this->permissionSet = $permissionSet; $this->permissionSet = $permissionSet;
$this->eventDispatcher = $eventDispatcher;
} }
protected function rawContent(array $request = []) protected function rawContent(array $request = [])
{ {
$type = $this->parameters['type']; $type = $this->parameters['type'];
$referenceId = $this->parameters['id']; $referenceId = $this->parameters['id'];
$expectedTypes = ['item', 'photo', 'event']; $expectedTypes = ['item', 'photo', 'event'];
@ -60,10 +79,10 @@ class PermissionTooltip extends \Friendica\BaseModule
$condition = ['id' => $referenceId, 'uid' => [0, $this->session->getLocalUserId()]]; $condition = ['id' => $referenceId, 'uid' => [0, $this->session->getLocalUserId()]];
if ($type == 'item') { if ($type == 'item') {
$fields = ['uid', 'psid', 'private', 'uri-id', 'origin', 'network']; $fields = ['uid', 'psid', 'private', 'uri-id', 'origin', 'network'];
$model = Model\Post::selectFirst($fields, $condition, ['order' => ['uid' => true]]); $model = Model\Post::selectFirst($fields, $condition, ['order' => ['uid' => true]]);
if ($model['origin'] || ($model['network'] != Protocol::ACTIVITYPUB)) { if ($model['origin'] || ($model['network'] != Protocol::ACTIVITYPUB)) {
$permissionSet = $this->permissionSet->selectOneById($model['psid'], $model['uid']); $permissionSet = $this->permissionSet->selectOneById($model['psid'], $model['uid']);
$model['allow_cid'] = $permissionSet->allow_cid; $model['allow_cid'] = $permissionSet->allow_cid;
$model['allow_gid'] = $permissionSet->allow_gid; $model['allow_gid'] = $permissionSet->allow_gid;
$model['deny_cid'] = $permissionSet->deny_cid; $model['deny_cid'] = $permissionSet->deny_cid;
@ -75,8 +94,8 @@ class PermissionTooltip extends \Friendica\BaseModule
$model['deny_gid'] = []; $model['deny_gid'] = [];
} }
} else { } else {
$fields = ['uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']; $fields = ['uid', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid'];
$model = $this->dba->selectFirst($type, $fields, $condition); $model = $this->dba->selectFirst($type, $fields, $condition);
$model['allow_cid'] = $this->aclFormatter->expand($model['allow_cid']); $model['allow_cid'] = $this->aclFormatter->expand($model['allow_cid']);
$model['allow_gid'] = $this->aclFormatter->expand($model['allow_gid']); $model['allow_gid'] = $this->aclFormatter->expand($model['allow_gid']);
$model['deny_cid'] = $this->aclFormatter->expand($model['deny_cid']); $model['deny_cid'] = $this->aclFormatter->expand($model['deny_cid']);
@ -87,10 +106,17 @@ class PermissionTooltip extends \Friendica\BaseModule
throw new HttpException\NotFoundException($this->t('Model not found')); throw new HttpException\NotFoundException($this->t('Model not found'));
} }
// Kept for backwards compatibility $hook_data = [
Hook::callAll('lockview_content', $model); 'model' => $model,
];
$aclReceivers = new Entity\AclReceivers(); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT, $hook_data),
)->getArray();
$model = $hook_data['model'] ?? $model;
$aclReceivers = new Entity\AclReceivers();
$addressedReceivers = new Entity\AddressedReceivers(); $addressedReceivers = new Entity\AddressedReceivers();
if (!empty($model['allow_cid']) || !empty($model['allow_gid']) || !empty($model['deny_cid']) || !empty($model['deny_gid'])) { if (!empty($model['allow_cid']) || !empty($model['allow_gid']) || !empty($model['deny_cid']) || !empty($model['deny_gid'])) {
$aclReceivers = $this->fetchReceiversFromACL($model); $aclReceivers = $this->fetchReceiversFromACL($model);
@ -100,30 +126,35 @@ class PermissionTooltip extends \Friendica\BaseModule
$privacy = ''; $privacy = '';
switch ($model['private'] ?? null) { switch ($model['private'] ?? null) {
case Model\Item::PUBLIC: $privacy = $this->t('Public'); break; case Model\Item::PUBLIC:
case Model\Item::UNLISTED: $privacy = $this->t('Unlisted'); break; $privacy = $this->t('Public');
case Model\Item::PRIVATE: $privacy = $this->t('Limited/Private'); break; break;
case Model\Item::UNLISTED:
$privacy = $this->t('Unlisted');
break;
case Model\Item::PRIVATE:
$privacy = $this->t('Limited/Private');
break;
} }
if ($aclReceivers->isEmpty() && $addressedReceivers->isEmpty() && empty($privacy)) if ($aclReceivers->isEmpty() && $addressedReceivers->isEmpty() && empty($privacy)) {
{
echo $this->t('Remote privacy information not available.'); echo $this->t('Remote privacy information not available.');
exit; exit;
} }
$tpl = Renderer::getMarkupTemplate('privacy/permission_tooltip.tpl'); $tpl = Renderer::getMarkupTemplate('privacy/permission_tooltip.tpl');
$output = Renderer::replaceMacros($tpl, [ $output = Renderer::replaceMacros($tpl, [
'$l10n' => [ '$l10n' => [
'visible_to' => $this->t('Visible to:'), 'visible_to' => $this->t('Visible to:'),
'to' => $this->t('To:'), 'to' => $this->t('To:'),
'cc' => $this->t('CC:'), 'cc' => $this->t('CC:'),
'bcc' => $this->t('BCC:'), 'bcc' => $this->t('BCC:'),
'audience' => $this->t('Audience:'), 'audience' => $this->t('Audience:'),
'attributed' => $this->t('Attributed To:'), 'attributed' => $this->t('Attributed To:'),
], ],
'$aclReceivers' => $aclReceivers, '$aclReceivers' => $aclReceivers,
'$addressedReceivers' => $addressedReceivers, '$addressedReceivers' => $addressedReceivers,
'$privacy' => $privacy, '$privacy' => $privacy,
]); ]);
$this->httpExit($output); $this->httpExit($output);
@ -197,7 +228,7 @@ class PermissionTooltip extends \Friendica\BaseModule
private function fetchAddressedReceivers(int $uriId): Entity\AddressedReceivers private function fetchAddressedReceivers(int $uriId): Entity\AddressedReceivers
{ {
$own_url = ''; $own_url = '';
$uid = $this->session->getLocalUserId(); $uid = $this->session->getLocalUserId();
if ($uid) { if ($uid) {
$owner = Model\User::getOwnerDataById($uid); $owner = Model\User::getOwnerDataById($uid);
if (!empty($owner['url'])) { if (!empty($owner['url'])) {
@ -220,11 +251,11 @@ class PermissionTooltip extends \Friendica\BaseModule
$receivers[$receiver['type']][] = $this->t('Collection (%s)', $receiver['name']); $receivers[$receiver['type']][] = $this->t('Collection (%s)', $receiver['name']);
break; break;
case Model\Tag::FOLLOWER_COLLECTION: case Model\Tag::FOLLOWER_COLLECTION:
$apcontact = $this->dba->selectFirst('apcontact', ['name'], ['followers' => $receiver['url']]); $apcontact = $this->dba->selectFirst('apcontact', ['name'], ['followers' => $receiver['url']]);
$receivers[$receiver['type']][] = $this->t('Followers (%s)', $apcontact['name'] ?? $receiver['name']); $receivers[$receiver['type']][] = $this->t('Followers (%s)', $apcontact['name'] ?? $receiver['name']);
break; break;
case Model\Tag::ACCOUNT: case Model\Tag::ACCOUNT:
$apcontact = Model\APContact::getByURL($receiver['url'], false); $apcontact = Model\APContact::getByURL($receiver['url'], false);
$receivers[$receiver['type']][] = $apcontact['name'] ?? $receiver['name']; $receivers[$receiver['type']][] = $apcontact['name'] ?? $receiver['name'];
break; break;
default: default:
@ -234,19 +265,19 @@ class PermissionTooltip extends \Friendica\BaseModule
} }
foreach ($receivers as $type => $receiver) { foreach ($receivers as $type => $receiver) {
$max = $this->config->get('system', 'max_receivers'); $max = $this->config->get('system', 'max_receivers');
$total = count($receiver); $total = count($receiver);
if ($total > $max) { if ($total > $max) {
$receivers[$type] = array_slice($receiver, 0, $max); $receivers[$type] = array_slice($receiver, 0, $max);
$receivers[$type][] = $this->t('%d more', $total - $max); $receivers[$type][] = $this->t('%d more', $total - $max);
} }
} }
return new Entity\AddressedReceivers( return new Entity\AddressedReceivers(
$receivers[Model\Tag::TO] ?? [], $receivers[Model\Tag::TO] ?? [],
$receivers[Model\Tag::CC] ?? [], $receivers[Model\Tag::CC] ?? [],
$receivers[Model\Tag::BCC] ?? [], $receivers[Model\Tag::BCC] ?? [],
$receivers[Model\Tag::AUDIENCE] ?? [], $receivers[Model\Tag::AUDIENCE] ?? [],
$receivers[Model\Tag::ATTRIBUTED] ?? [], $receivers[Model\Tag::ATTRIBUTED] ?? [],
); );
} }

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,20 +53,38 @@ 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;
$this->page = $page; $this->page = $page;
$this->config = $config; $this->config = $config;
$this->appHelper = $appHelper; $this->appHelper = $appHelper;
$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']) {
@ -90,15 +109,23 @@ class Photos extends \Friendica\Module\BaseProfile
if ($visibility === 'public') { if ($visibility === 'public') {
// The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected
$str_contact_allow = $str_circle_allow = $str_contact_deny = $str_circle_deny = ''; $str_contact_allow = $str_circle_allow = $str_contact_deny = $str_circle_deny = '';
} else if ($visibility === 'custom') { } elseif ($visibility === 'custom') {
// Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL // 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. // 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 // See https://github.com/friendica/friendica/issues/9672
$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'];
@ -148,7 +183,7 @@ class Photos extends \Friendica\Module\BaseProfile
$type = $_FILES['userfile']['type']; $type = $_FILES['userfile']['type'];
$error = $_FILES['userfile']['error']; $error = $_FILES['userfile']['error'];
} else { } else {
$error = UPLOAD_ERR_NO_FILE; $error = UPLOAD_ERR_NO_FILE;
} }
if ($error !== UPLOAD_ERR_OK) { if ($error !== UPLOAD_ERR_OK) {
@ -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;
} }
@ -268,16 +314,17 @@ class Photos extends \Friendica\Module\BaseProfile
$arr['visible'] = $visible; $arr['visible'] = $visible;
$arr['origin'] = 1; $arr['origin'] = 1;
$arr['body'] = Images::getBBCodeByResource($resource_id, $this->owner['nickname'], $preview, $image->getExt()); $arr['body'] = Images::getBBCodeByResource($resource_id, $this->owner['nickname'], $preview, $image->getExt());
$item_id = Item::insert($arr); $item_id = Item::insert($arr);
// 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');
} }
@ -336,7 +383,7 @@ class Photos extends \Friendica\Module\BaseProfile
$pager->getItemsPerPage() $pager->getItemsPerPage()
)); ));
$photos = array_map(function ($photo){ $photos = array_map(function ($photo) {
return [ return [
'id' => $photo['id'], 'id' => $photo['id'],
'link' => 'photos/' . $this->owner['nickname'] . '/image/' . $photo['resource-id'], 'link' => 'photos/' . $this->owner['nickname'] . '/image/' . $photo['resource-id'],

View file

@ -17,13 +17,13 @@ use Friendica\Content\Nav;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\HTML; use Friendica\Content\Text\HTML;
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\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Event\HtmlFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile as ProfileModel; use Friendica\Model\Profile as ProfileModel;
use Friendica\Model\Tag; use Friendica\Model\Tag;
@ -40,6 +40,7 @@ use Friendica\Util\Network;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
use GuzzleHttp\Psr7\Uri; use GuzzleHttp\Psr7\Uri;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Profile extends BaseProfile class Profile extends BaseProfile
@ -56,17 +57,34 @@ class Profile extends BaseProfile
private $page; private $page;
/** @var ProfileField */ /** @var ProfileField */
private $profileField; private $profileField;
private EventDispatcherInterface $eventDispatcher;
public function __construct(ProfileField $profileField, Page $page, IManageConfigValues $config, IHandleUserSessions $session, AppHelper $appHelper, Database $database, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ ProfileField $profileField,
Page $page,
IManageConfigValues $config,
IHandleUserSessions $session,
AppHelper $appHelper,
Database $database,
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->database = $database; $this->database = $database;
$this->appHelper = $appHelper; $this->appHelper = $appHelper;
$this->session = $session; $this->session = $session;
$this->config = $config; $this->config = $config;
$this->page = $page; $this->page = $page;
$this->profileField = $profileField; $this->profileField = $profileField;
$this->eventDispatcher = $eventDispatcher;
} }
protected function rawContent(array $request = []) protected function rawContent(array $request = [])
@ -255,7 +273,7 @@ class Profile extends BaseProfile
} }
$tpl = Renderer::getMarkupTemplate('profile/profile.tpl'); $tpl = Renderer::getMarkupTemplate('profile/profile.tpl');
$o .= Renderer::replaceMacros($tpl, [ $o .= Renderer::replaceMacros($tpl, [
'$title' => $this->t('Profile'), '$title' => $this->t('Profile'),
'$yourself' => $this->t('Yourself'), '$yourself' => $this->t('Yourself'),
'$view_as_contacts' => $view_as_contacts, '$view_as_contacts' => $view_as_contacts,
@ -275,14 +293,16 @@ class Profile extends BaseProfile
'title' => '', 'title' => '',
'label' => $this->t('Edit profile') 'label' => $this->t('Edit profile')
], ],
'$viewas_link' => [ '$viewas_link' => [
'url' => $this->args->getQueryString() . '#viewas', 'url' => $this->args->getQueryString() . '#viewas',
'title' => '', 'title' => '',
'label' => $this->t('View as') 'label' => $this->t('View as')
], ],
]); ]);
Hook::callAll('profile_advanced', $o); $o = $this->eventDispatcher->dispatch(
new HTmlFilterEvent(HtmlFilterEvent::MOD_PROFILE_CONTENT, $o),
)->getHtml();
return $o; return $o;
} }
@ -342,7 +362,7 @@ class Profile extends BaseProfile
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/" title="' . $this->t('%s\'s posts', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n"; $htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/" title="' . $this->t('%s\'s posts', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n";
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/comments" title="' . $this->t('%s\'s comments', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n"; $htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/comments" title="' . $this->t('%s\'s comments', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n";
$htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/activity" title="' . $this->t('%s\'s timeline', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n"; $htmlhead .= '<link rel="alternate" type="application/atom+xml" href="' . $this->baseUrl . '/feed/' . $nickname . '/activity" title="' . $this->t('%s\'s timeline', htmlspecialchars($profile['name'], ENT_COMPAT, 'UTF-8', true)) . '"/>' . "\n";
$uri = urlencode('acct:' . $profile['nickname'] . '@' . $this->baseUrl->getHost() . ($this->baseUrl->getPath() ? '/' . $this->baseUrl->getPath() : '')); $uri = urlencode('acct:' . $profile['nickname'] . '@' . $this->baseUrl->getHost() . ($this->baseUrl->getPath() ? '/' . $this->baseUrl->getPath() : ''));
$htmlhead .= '<link rel="lrdd" type="application/xrd+xml" href="' . $this->baseUrl . '/xrd/?uri=' . $uri . '" />' . "\n"; $htmlhead .= '<link rel="lrdd" type="application/xrd+xml" href="' . $this->baseUrl . '/xrd/?uri=' . $uri . '" />' . "\n";
header('Link: <' . $this->baseUrl . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false); header('Link: <' . $this->baseUrl . '/xrd/?uri=' . $uri . '>; rel="lrdd"; type="application/xrd+xml"', false);

View file

@ -12,18 +12,19 @@ use Friendica\App\BaseURL;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Text\BBCode; use Friendica\Content\Text\BBCode;
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\Worker; use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model; use Friendica\Model;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Proxy; use Friendica\Util\Proxy;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -41,13 +42,16 @@ class Register extends BaseModule
/** @var IHandleUserSessions */ /** @var IHandleUserSessions */
private $session; private $session;
public function __construct(IHandleUserSessions $session, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManageConfigValues $config, array $server, array $parameters = []) private EventDispatcherInterface $eventDispatcher;
public function __construct(IHandleUserSessions $session, EventDispatcherInterface $eventDispatcher, L10n $l10n, BaseURL $baseUrl, Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IManageConfigValues $config, 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->tos = new Tos($l10n, $baseUrl, $args, $logger, $profiler, $response, $config, $server, $parameters); $this->tos = new Tos($l10n, $baseUrl, $args, $logger, $profiler, $response, $config, $server, $parameters);
$this->session = $session; $this->session = $session;
$this->eventDispatcher = $eventDispatcher;
} }
/** /**
@ -129,11 +133,15 @@ class Register extends BaseModule
$tpl = Renderer::getMarkupTemplate('register.tpl'); $tpl = Renderer::getMarkupTemplate('register.tpl');
$arr = ['template' => $tpl]; $hook_data = [
'template' => $tpl,
];
Hook::callAll('register_form', $arr); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REGISTER_FORM, $hook_data),
)->getArray();
$tpl = $arr['template']; $tpl = $hook_data['template'] ?? $tpl;
$o = Renderer::replaceMacros($tpl, [ $o = Renderer::replaceMacros($tpl, [
'$invitations' => DI::config()->get('system', 'invitation_only'), '$invitations' => DI::config()->get('system', 'invitation_only'),
@ -190,8 +198,13 @@ class Register extends BaseModule
{ {
BaseModule::checkFormSecurityTokenRedirectOnError('/register', 'register'); BaseModule::checkFormSecurityTokenRedirectOnError('/register', 'register');
$arr = ['post' => $_POST]; $arr = [
Hook::callAll('register_post', $arr); 'post' => $_POST,
];
$arr = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REGISTER_POST, $arr),
)->getArray();
$additional_account = false; $additional_account = false;

View file

@ -7,22 +7,23 @@
namespace Friendica\Module\Search; namespace Friendica\Module\Search;
use Friendica\App; use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\BaseModule; use Friendica\BaseModule;
use Friendica\Content\Widget; use Friendica\Content\Widget;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Search; use Friendica\Core\Search;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\System;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Post; use Friendica\Model\Post;
use Friendica\Module\Response; use Friendica\Module\Response;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException\UnauthorizedException;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -44,13 +45,26 @@ class Acl extends BaseModule
private $session; private $session;
/** @var Database */ /** @var Database */
private $database; private $database;
private EventDispatcherInterface $eventDispatcher;
public function __construct(Database $database, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ Database $database,
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;
$this->database = $database; $this->database = $database;
$this->eventDispatcher = $eventDispatcher;
} }
protected function post(array $request = []) protected function post(array $request = [])
@ -61,7 +75,7 @@ class Acl extends BaseModule
protected function rawContent(array $request = []) protected function rawContent(array $request = [])
{ {
if (!$this->session->getLocalUserId()) { if (!$this->session->getLocalUserId()) {
throw new HTTPException\UnauthorizedException($this->t('You must be logged in to use this module.')); throw new UnauthorizedException($this->t('You must be logged in to use this module.'));
} }
$type = $request['type'] ?? self::TYPE_MENTION_CONTACT_CIRCLE; $type = $request['type'] ?? self::TYPE_MENTION_CONTACT_CIRCLE;
@ -104,9 +118,9 @@ class Acl extends BaseModule
private function regularContactSearch(array $request, string $type): array private function regularContactSearch(array $request, string $type): array
{ {
$start = $request['start'] ?? 0; $start = $request['start'] ?? 0;
$count = $request['count'] ?? 100; $count = $request['count'] ?? 100;
$search = $request['search'] ?? ''; $search = $request['search'] ?? '';
$conv_id = $request['conversation'] ?? null; $conv_id = $request['conversation'] ?? null;
// For use with jquery.textcomplete for private mail completion // For use with jquery.textcomplete for private mail completion
@ -124,9 +138,9 @@ class Acl extends BaseModule
$condition_circle = ["`uid` = ? AND NOT `deleted`", $this->session->getLocalUserId()]; $condition_circle = ["`uid` = ? AND NOT `deleted`", $this->session->getLocalUserId()];
if ($search != '') { if ($search != '') {
$sql_extra = "AND `name` LIKE '%%" . $this->database->escape($search) . "%%'"; $sql_extra = "AND `name` LIKE '%%" . $this->database->escape($search) . "%%'";
$condition = DBA::mergeConditions($condition, ["(`attag` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $condition = DBA::mergeConditions($condition, ["(`attag` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)",
'%' . $search . '%', '%' . $search . '%', '%' . $search . '%']); '%' . $search . '%', '%' . $search . '%', '%' . $search . '%']);
$condition_circle = DBA::mergeConditions($condition_circle, ["`name` LIKE ?", '%' . $search . '%']); $condition_circle = DBA::mergeConditions($condition_circle, ["`name` LIKE ?", '%' . $search . '%']);
} }
@ -142,21 +156,27 @@ class Acl extends BaseModule
switch ($type) { switch ($type) {
case self::TYPE_MENTION_CONTACT_CIRCLE: case self::TYPE_MENTION_CONTACT_CIRCLE:
case self::TYPE_MENTION_CONTACT: case self::TYPE_MENTION_CONTACT:
$condition = DBA::mergeConditions($condition, $condition = DBA::mergeConditions(
$condition,
["NOT `self` AND NOT `blocked`", ["NOT `self` AND NOT `blocked`",
]); ]
);
break; break;
case self::TYPE_MENTION_GROUP: case self::TYPE_MENTION_GROUP:
$condition = DBA::mergeConditions($condition, $condition = DBA::mergeConditions(
$condition,
["NOT `self` AND NOT `blocked` AND (NOT `ap-posting-restricted` OR `ap-posting-restricted` IS NULL) AND `contact-type` = ?", Contact::TYPE_COMMUNITY ["NOT `self` AND NOT `blocked` AND (NOT `ap-posting-restricted` OR `ap-posting-restricted` IS NULL) AND `contact-type` = ?", Contact::TYPE_COMMUNITY
]); ]
);
break; break;
case self::TYPE_PRIVATE_MESSAGE: case self::TYPE_PRIVATE_MESSAGE:
$condition = DBA::mergeConditions($condition, $condition = DBA::mergeConditions(
$condition,
["NOT `self` AND NOT `blocked` AND `network` IN (?, ?, ?)", Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA ["NOT `self` AND NOT `blocked` AND `network` IN (?, ?, ?)", Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA
]); ]
);
break; break;
} }
@ -170,7 +190,8 @@ class Acl extends BaseModule
if ($type == self::TYPE_MENTION_CONTACT_CIRCLE || $type == self::TYPE_MENTION_CIRCLE) { if ($type == self::TYPE_MENTION_CONTACT_CIRCLE || $type == self::TYPE_MENTION_CIRCLE) {
/// @todo We should cache this query. /// @todo We should cache this query.
// This can be done when we can delete cache entries via wildcard // This can be done when we can delete cache entries via wildcard
$circles = $this->database->toArray($this->database->p("SELECT `circle`.`id`, `circle`.`name`, GROUP_CONCAT(DISTINCT `circle_member`.`contact-id` SEPARATOR ',') AS uids $circles = $this->database->toArray($this->database->p(
"SELECT `circle`.`id`, `circle`.`name`, GROUP_CONCAT(DISTINCT `circle_member`.`contact-id` SEPARATOR ',') AS uids
FROM `group` AS `circle` FROM `group` AS `circle`
INNER JOIN `group_member` AS `circle_member` ON `circle_member`.`gid` = `circle`.`id` INNER JOIN `group_member` AS `circle_member` ON `circle_member`.`gid` = `circle`.`id`
WHERE NOT `circle`.`deleted` AND `circle`.`uid` = ? WHERE NOT `circle`.`deleted` AND `circle`.`uid` = ?
@ -280,7 +301,7 @@ class Acl extends BaseModule
$resultTotal += count($unknown_contacts); $resultTotal += count($unknown_contacts);
} }
$results = [ $hook_data = [
'tot' => $resultTotal, 'tot' => $resultTotal,
'start' => $start, 'start' => $start,
'count' => $count, 'count' => $count,
@ -291,13 +312,15 @@ class Acl extends BaseModule
'search' => $search, 'search' => $search,
]; ];
Hook::callAll('acl_lookup_end', $results); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACL_LOOKUP_END, $hook_data),
)->getArray();
$o = [ $o = [
'tot' => $results['tot'], 'tot' => $hook_data['tot'],
'start' => $results['start'], 'start' => $hook_data['start'],
'count' => $results['count'], 'count' => $hook_data['count'],
'items' => $results['items'], 'items' => $hook_data['items'],
]; ];
$this->logger->info('ACL {action} - {subaction} - done', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]); $this->logger->info('ACL {action} - {subaction} - done', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]);

View file

@ -7,30 +7,33 @@
namespace Friendica\Module\Settings\Profile; namespace Friendica\Module\Settings\Profile;
use Friendica\App; use Friendica\App\Arguments;
use Friendica\App\BaseURL;
use Friendica\App\Page;
use Friendica\Core\ACL; use Friendica\Core\ACL;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Core\Protocol; use Friendica\Core\Protocol;
use Friendica\Core\Renderer; use Friendica\Core\Renderer;
use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Session\Capability\IHandleUserSessions;
use Friendica\Core\Theme; use Friendica\Core\Theme;
use Friendica\Core\Worker;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Model\Profile; use Friendica\Model\Profile;
use Friendica\Module\Response; use Friendica\Module\Response;
use Friendica\Navigation\SystemMessages;
use Friendica\Profile\ProfileField;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Module\BaseSettings; use Friendica\Module\BaseSettings;
use Friendica\Module\Security\Login; use Friendica\Module\Security\Login;
use Friendica\Navigation\SystemMessages;
use Friendica\Network\HTTPException; use Friendica\Network\HTTPException;
use Friendica\Profile\ProfileField;
use Friendica\Security\PermissionSet; use Friendica\Security\PermissionSet;
use Friendica\Util\ACLFormatter; use Friendica\Util\ACLFormatter;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Profiler; use Friendica\Util\Profiler;
use Friendica\Util\Temporal; use Friendica\Util\Temporal;
use Friendica\Core\Worker; use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class Index extends BaseSettings class Index extends BaseSettings
@ -47,9 +50,27 @@ class Index extends BaseSettings
private $permissionSetFactory; private $permissionSetFactory;
/** @var ACLFormatter */ /** @var ACLFormatter */
private $aclFormatter; private $aclFormatter;
private EventDispatcherInterface $eventDispatcher;
public function __construct(ACLFormatter $aclFormatter, PermissionSet\Factory\PermissionSet $permissionSetFactory, PermissionSet\Repository\PermissionSet $permissionSetRepo, SystemMessages $systemMessages, ProfileField\Factory\ProfileField $profileFieldFactory, ProfileField\Repository\ProfileField $profileFieldRepo, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) public function __construct(
{ ACLFormatter $aclFormatter,
PermissionSet\Factory\PermissionSet $permissionSetFactory,
PermissionSet\Repository\PermissionSet $permissionSetRepo,
SystemMessages $systemMessages,
ProfileField\Factory\ProfileField $profileFieldFactory,
ProfileField\Repository\ProfileField $profileFieldRepo,
EventDispatcherInterface $eventDispatcher,
IHandleUserSessions $session,
Page $page,
L10n $l10n,
BaseURL $baseUrl,
Arguments $args,
LoggerInterface $logger,
Profiler $profiler,
Response $response,
array $server,
array $parameters = []
) {
parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
$this->profileFieldRepo = $profileFieldRepo; $this->profileFieldRepo = $profileFieldRepo;
@ -58,6 +79,7 @@ class Index extends BaseSettings
$this->permissionSetRepo = $permissionSetRepo; $this->permissionSetRepo = $permissionSetRepo;
$this->permissionSetFactory = $permissionSetFactory; $this->permissionSetFactory = $permissionSetFactory;
$this->aclFormatter = $aclFormatter; $this->aclFormatter = $aclFormatter;
$this->eventDispatcher = $eventDispatcher;
} }
protected function post(array $request = []) protected function post(array $request = [])
@ -73,7 +95,9 @@ class Index extends BaseSettings
self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile'); self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile');
Hook::callAll('profile_post', $request); $request = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SETTINGS_POST, $request),
)->getArray();
$dob = trim($request['dob'] ?? ''); $dob = trim($request['dob'] ?? '');
@ -87,7 +111,7 @@ class Index extends BaseSettings
if (strpos($dob, '0000-') === 0 || strpos($dob, '0001-') === 0) { if (strpos($dob, '0000-') === 0 || strpos($dob, '0001-') === 0) {
$ignore_year = true; $ignore_year = true;
$dob = substr($dob, 5); $dob = substr($dob, 5);
} }
if ($ignore_year) { if ($ignore_year) {
@ -221,7 +245,7 @@ class Index extends BaseSettings
$this->session->getLocalUserId(), $this->session->getLocalUserId(),
false, false,
['allow_cid' => []], ['allow_cid' => []],
['network' => Protocol::DFRN], ['network' => Protocol::DFRN],
'profile_field[new]' 'profile_field[new]'
), ),
], ],
@ -254,7 +278,8 @@ class Index extends BaseSettings
'miscellaneous_section' => $this->t('Miscellaneous'), 'miscellaneous_section' => $this->t('Miscellaneous'),
'custom_fields_section' => $this->t('Custom Profile Fields'), 'custom_fields_section' => $this->t('Custom Profile Fields'),
'profile_photo' => $this->t('Upload Profile Photo'), 'profile_photo' => $this->t('Upload Profile Photo'),
'custom_fields_description' => $this->t('<p>Custom fields appear on <a href="%s">your profile page</a>.</p> 'custom_fields_description' => $this->t(
'<p>Custom fields appear on <a href="%s">your profile page</a>.</p>
<p>You can use BBCodes in the field values.</p> <p>You can use BBCodes in the field values.</p>
<p>Reorder by dragging the field title.</p> <p>Reorder by dragging the field title.</p>
<p>Empty the label field to remove a custom field.</p> <p>Empty the label field to remove a custom field.</p>
@ -288,8 +313,16 @@ class Index extends BaseSettings
'$custom_fields' => $custom_fields, '$custom_fields' => $custom_fields,
]); ]);
$arr = ['profile' => $owner, 'entry' => $o]; $hook_data = [
Hook::callAll('profile_edit', $arr); 'profile' => $owner,
'entry' => $o,
];
$hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::PROFILE_SETTINGS_FORM, $hook_data),
)->getArray();
$o = $hook_data['entry'] ?? $o;
return $o; return $o;
} }

View file

@ -13,10 +13,10 @@ use Friendica\Content\Text\BBCode;
use Friendica\Content\Text\Plaintext; use Friendica\Content\Text\Plaintext;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues;
use Friendica\Core\Hook;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory; use Friendica\Factory\Api\Mastodon\Notification as NotificationFactory;
use Friendica\Model; use Friendica\Model;
use Friendica\Navigation\Notifications\Collection; use Friendica\Navigation\Notifications\Collection;
@ -29,6 +29,7 @@ use Friendica\Object\Api\Mastodon\Notification;
use Friendica\Protocol\Activity; use Friendica\Protocol\Activity;
use Friendica\Util\DateTimeFormat; use Friendica\Util\DateTimeFormat;
use Friendica\Util\Emailer; use Friendica\Util\Emailer;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
/** /**
@ -57,16 +58,29 @@ class Notify extends BaseRepository
/** @var Factory\Notification */ /** @var Factory\Notification */
protected $notification; protected $notification;
private EventDispatcherInterface $eventDispatcher;
protected static $table_name = 'notify'; protected static $table_name = 'notify';
public function __construct(Database $database, LoggerInterface $logger, L10n $l10n, BaseURL $baseUrl, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, Emailer $emailer, Factory\Notification $notification, Factory\Notify $factory = null) public function __construct(
{ Database $database,
$this->l10n = $l10n; LoggerInterface $logger,
$this->baseUrl = $baseUrl; L10n $l10n,
$this->config = $config; BaseURL $baseUrl,
$this->pConfig = $pConfig; IManageConfigValues $config,
$this->emailer = $emailer; IManagePersonalConfigValues $pConfig,
$this->notification = $notification; Emailer $emailer,
Factory\Notification $notification,
EventDispatcherInterface $eventDispatcher,
Factory\Notify $factory = null
) {
$this->l10n = $l10n;
$this->baseUrl = $baseUrl;
$this->config = $config;
$this->pConfig = $pConfig;
$this->emailer = $emailer;
$this->notification = $notification;
$this->eventDispatcher = $eventDispatcher;
parent::__construct($database, $logger, $factory ?? new Factory\Notify($logger)); parent::__construct($database, $logger, $factory ?? new Factory\Notify($logger));
} }
@ -166,7 +180,10 @@ class Notify extends BaseRepository
$this->db->update(self::$table_name, $fields, ['id' => $Notify->id]); $this->db->update(self::$table_name, $fields, ['id' => $Notify->id]);
} else { } else {
$fields['date'] = DateTimeFormat::utcNow(); $fields['date'] = DateTimeFormat::utcNow();
Hook::callAll('enotify_store', $fields);
$fields = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ENOTIFY_STORE, $fields),
)->getArray();
$this->db->insert(self::$table_name, $fields); $this->db->insert(self::$table_name, $fields);
@ -544,7 +561,7 @@ class Notify extends BaseRepository
$subject .= " (".$nickname."@".$hostname.")"; $subject .= " (".$nickname."@".$hostname.")";
$h = [ $hook_data = [
'params' => $params, 'params' => $params,
'subject' => $subject, 'subject' => $subject,
'preamble' => $preamble, 'preamble' => $preamble,
@ -556,18 +573,20 @@ class Notify extends BaseRepository
'itemlink' => $itemlink 'itemlink' => $itemlink
]; ];
Hook::callAll('enotify', $h); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ENOTIFY, $hook_data),
)->getArray();
$subject = $h['subject']; $subject = $hook_data['subject'];
$preamble = $h['preamble']; $preamble = $hook_data['preamble'];
$epreamble = $h['epreamble']; $epreamble = $hook_data['epreamble'];
$body = $h['body']; $body = $hook_data['body'];
$tsitelink = $h['tsitelink']; $tsitelink = $hook_data['tsitelink'];
$hsitelink = $h['hsitelink']; $hsitelink = $hook_data['hsitelink'];
$itemlink = $h['itemlink']; $itemlink = $hook_data['itemlink'];
$notify_id = 0; $notify_id = 0;
@ -615,7 +634,7 @@ class Notify extends BaseRepository
} }
} }
$datarray = [ $hook_data = [
'preamble' => $preamble, 'preamble' => $preamble,
'type' => $params['type'], 'type' => $params['type'],
'parent' => $parent_id, 'parent' => $parent_id,
@ -632,31 +651,33 @@ class Notify extends BaseRepository
'headers' => $emailBuilder->getHeaders(), 'headers' => $emailBuilder->getHeaders(),
]; ];
Hook::callAll('enotify_mail', $datarray); $hook_data = $this->eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ENOTIFY_MAIL, $hook_data),
)->getArray();
$emailBuilder $emailBuilder
->withHeaders($datarray['headers']) ->withHeaders($hook_data['headers'])
->withRecipient($params['to_email']) ->withRecipient($params['to_email'])
->forUser([ ->forUser([
'uid' => $datarray['uid'], 'uid' => $hook_data['uid'],
'language' => $params['language'], 'language' => $params['language'],
]) ])
->withNotification($datarray['subject'], $datarray['preamble'], $datarray['title'], $datarray['body']) ->withNotification($hook_data['subject'], $hook_data['preamble'], $hook_data['title'], $hook_data['body'])
->withSiteLink($datarray['tsitelink'], $datarray['hsitelink']) ->withSiteLink($hook_data['tsitelink'], $hook_data['hsitelink'])
->withItemLink($datarray['itemlink']); ->withItemLink($hook_data['itemlink']);
// If a photo is present, add it to the email // If a photo is present, add it to the email
if (!empty($datarray['source_photo'])) { if (!empty($hook_data['source_photo'])) {
$emailBuilder->withPhoto( $emailBuilder->withPhoto(
$datarray['source_photo'], $hook_data['source_photo'],
$datarray['source_link'] ?? $sitelink, $hook_data['source_link'] ?? $sitelink,
$datarray['source_name'] ?? $sitename $hook_data['source_name'] ?? $sitename
); );
} }
$email = $emailBuilder->build(); $email = $emailBuilder->build();
$this->logger->debug('Send mail', $datarray); $this->logger->debug('Send mail', $hook_data);
// use the Emailer class to send the message // use the Emailer class to send the message
return $this->emailer->send($email); return $this->emailer->send($email);

View file

@ -11,6 +11,7 @@ use Exception;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\User; use Friendica\Model\User;
use Friendica\Network\HTTPException\UnauthorizedException; use Friendica\Network\HTTPException\UnauthorizedException;
@ -136,12 +137,16 @@ class BasicAuth
'user_record' => null, 'user_record' => null,
]; ];
/* $eventDispatcher = DI::eventDispatcher();
* An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record
* Addons should never set 'authenticated' except to indicate success - as hooks may be chained /**
* and later addons should not interfere with an earlier one that succeeded. * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record
*/ * Addons should never set 'authenticated' except to indicate success - as hooks may be chained
Hook::callAll('authenticate', $addon_auth); * and later addons should not interfere with an earlier one that succeeded.
*/
$addon_auth = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_AUTHENTICATE, $addon_auth),
)->getArray();
if ($addon_auth['authenticated'] && !empty($addon_auth['user_record'])) { if ($addon_auth['authenticated'] && !empty($addon_auth['user_record'])) {
$record = $addon_auth['user_record']; $record = $addon_auth['user_record'];

View file

@ -7,8 +7,8 @@
namespace Friendica\Util; namespace Friendica\Util;
use Friendica\Core\Hook;
use Friendica\DI; use Friendica\DI;
use Friendica\Event\ArrayFilterEvent;
use Friendica\Model\Contact; use Friendica\Model\Contact;
use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientAccept;
use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPClient\Client\HttpClientOptions;
@ -302,7 +302,11 @@ class Network
$avatar['url'] = ''; $avatar['url'] = '';
$avatar['success'] = false; $avatar['success'] = false;
Hook::callAll('avatar_lookup', $avatar); $eventDispatcher = DI::eventDispatcher();
$avatar = $eventDispatcher->dispatch(
new ArrayFilterEvent(ArrayFilterEvent::AVATAR_LOOKUP, $avatar),
)->getArray();
if (! $avatar['success']) { if (! $avatar['success']) {
$avatar['url'] = DI::baseUrl() . Contact::DEFAULT_AVATAR_PHOTO; $avatar['url'] = DI::baseUrl() . Contact::DEFAULT_AVATAR_PHOTO;

View file

@ -11,6 +11,7 @@ use Friendica\Capabilities\ICanCreateResponses;
use Friendica\Core\Addon\AddonHelper; use Friendica\Core\Addon\AddonHelper;
use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Config\Capability\IManageConfigValues;
use Friendica\Core\Hook; use Friendica\Core\Hook;
use Friendica\Core\Hooks\HookEventBridge;
use Friendica\DI; use Friendica\DI;
use Friendica\Module\Special\HTTPException; use Friendica\Module\Special\HTTPException;
use Friendica\Security\Authentication; use Friendica\Security\Authentication;
@ -159,6 +160,13 @@ abstract class ApiTestCase extends FixtureTestCase
; ;
DI::init($this->dice); DI::init($this->dice);
/** @var \Friendica\Event\EventDispatcher */
$eventDispatcher = DI::eventDispatcher();
foreach (HookEventBridge::getStaticSubscribedEvents() as $eventName => $methodName) {
$eventDispatcher->addListener($eventName, [HookEventBridge::class, $methodName]);
}
$this->httpExceptionMock = $this->dice->create(HTTPException::class); $this->httpExceptionMock = $this->dice->create(HTTPException::class);
AuthTestConfig::$authenticated = true; AuthTestConfig::$authenticated = true;

View file

@ -32,15 +32,45 @@ class HookEventBridgeTest extends TestCase
ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent', ArrayFilterEvent::NAV_INFO => 'onArrayFilterEvent',
ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_ENABLED => 'onArrayFilterEvent',
ArrayFilterEvent::FEATURE_GET => 'onArrayFilterEvent', ArrayFilterEvent::FEATURE_GET => 'onArrayFilterEvent',
ArrayFilterEvent::POST_LOCAL_START => 'onArrayFilterEvent', ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT => 'onPermissionTooltipContentEvent',
ArrayFilterEvent::POST_LOCAL => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_LOCAL_START => 'onArrayFilterEvent',
ArrayFilterEvent::POST_LOCAL_END => 'onArrayFilterEvent', ArrayFilterEvent::INSERT_POST_LOCAL => 'onInsertPostLocalEvent',
ArrayFilterEvent::INSERT_POST_LOCAL_END => 'onInsertPostLocalEndEvent',
ArrayFilterEvent::INSERT_POST_REMOTE => 'onArrayFilterEvent',
ArrayFilterEvent::INSERT_POST_REMOTE_END => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST_START => 'onPreparePostStartEvent',
ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT => 'onArrayFilterEvent',
ArrayFilterEvent::PREPARE_POST => '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_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::PARSE_LINK => 'onArrayFilterEvent',
ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent', ArrayFilterEvent::CONVERSATION_START => 'onArrayFilterEvent',
ArrayFilterEvent::FETCH_ITEM_BY_LINK => 'onArrayFilterEvent',
ArrayFilterEvent::ITEM_TAGGED => 'onArrayFilterEvent',
ArrayFilterEvent::DISPLAY_ITEM => 'onArrayFilterEvent', ArrayFilterEvent::DISPLAY_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CACHE_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CHECK_ITEM_NOTIFICATION => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY_STORE => 'onArrayFilterEvent',
ArrayFilterEvent::ENOTIFY_MAIL => 'onArrayFilterEvent',
ArrayFilterEvent::DETECT_LANGUAGES => 'onArrayFilterEvent',
ArrayFilterEvent::RENDER_LOCATION => 'onArrayFilterEvent', ArrayFilterEvent::RENDER_LOCATION => 'onArrayFilterEvent',
ArrayFilterEvent::ITEM_PHOTO_MENU => 'onArrayFilterEvent', ArrayFilterEvent::ITEM_PHOTO_MENU => 'onArrayFilterEvent',
ArrayFilterEvent::DIRECTORY_ITEM => 'onArrayFilterEvent',
ArrayFilterEvent::CONTACT_PHOTO_MENU => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY => 'onProfileSidebarEntryEvent',
ArrayFilterEvent::PROFILE_SIDEBAR => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SETTINGS_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::PROFILE_SETTINGS_POST => 'onArrayFilterEvent',
ArrayFilterEvent::MODERATION_USERS_TABS => 'onArrayFilterEvent',
ArrayFilterEvent::ACL_LOOKUP_END => 'onArrayFilterEvent',
ArrayFilterEvent::OEMBED_FETCH_END => 'onOembedFetchEndEvent', ArrayFilterEvent::OEMBED_FETCH_END => 'onOembedFetchEndEvent',
ArrayFilterEvent::PAGE_INFO => 'onArrayFilterEvent', ArrayFilterEvent::PAGE_INFO => 'onArrayFilterEvent',
ArrayFilterEvent::SMILEY_LIST => 'onArrayFilterEvent', ArrayFilterEvent::SMILEY_LIST => 'onArrayFilterEvent',
@ -51,11 +81,34 @@ class HookEventBridgeTest extends TestCase
ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW => 'onArrayFilterEvent',
ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW => 'onArrayFilterEvent',
ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'onArrayFilterEvent', ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE => 'onArrayFilterEvent',
ArrayFilterEvent::FOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::UNFOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::REVOKE_FOLLOW_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::BLOCK_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::UNBLOCK_CONTACT => 'onArrayFilterEvent',
ArrayFilterEvent::EDIT_CONTACT_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::EDIT_CONTACT_POST => 'onArrayFilterEvent',
ArrayFilterEvent::AVATAR_LOOKUP => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_AUTHENTICATE => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER_FORM => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER_POST => 'onArrayFilterEvent',
ArrayFilterEvent::ACCOUNT_REGISTER => 'onAccountRegisterEvent',
ArrayFilterEvent::ACCOUNT_REMOVE => 'onAccountRemoveEvent',
ArrayFilterEvent::EVENT_CREATED => 'onEventCreatedEvent',
ArrayFilterEvent::EVENT_UPDATED => 'onEventUpdatedEvent',
ArrayFilterEvent::ADD_WORKER_TASK => 'onArrayFilterEvent',
ArrayFilterEvent::STORAGE_CONFIG => 'onArrayFilterEvent',
ArrayFilterEvent::STORAGE_INSTANCE => 'onArrayFilterEvent',
ArrayFilterEvent::DB_STRUCTURE_DEFINITION => 'onArrayFilterEvent',
ArrayFilterEvent::DB_VIEW_DEFINITION => 'onArrayFilterEvent',
HtmlFilterEvent::HEAD => 'onHtmlFilterEvent', HtmlFilterEvent::HEAD => 'onHtmlFilterEvent',
HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent', HtmlFilterEvent::FOOTER => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_HEADER => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_HEADER => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_CONTENT_TOP => 'onHtmlFilterEvent',
HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent', HtmlFilterEvent::PAGE_END => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_HOME_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_ABOUT_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::MOD_PROFILE_CONTENT => 'onHtmlFilterEvent',
HtmlFilterEvent::JOT_TOOL => 'onHtmlFilterEvent', HtmlFilterEvent::JOT_TOOL => 'onHtmlFilterEvent',
HtmlFilterEvent::CONTACT_BLOCK_END => 'onHtmlFilterEvent', HtmlFilterEvent::CONTACT_BLOCK_END => 'onHtmlFilterEvent',
]; ];
@ -167,6 +220,155 @@ class HookEventBridgeTest extends TestCase
HookEventBridge::onCollectRoutesEvent($event); HookEventBridge::onCollectRoutesEvent($event);
} }
public function testOnPermissionTooltipContentEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT, ['model' => ['uid' => -1]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('lockview_content', $name);
$this->assertSame(['uid' => -1], $data);
return ['uid' => 123];
});
HookEventBridge::onPermissionTooltipContentEvent($event);
$this->assertSame(
['model' => ['uid' => 123]],
$event->getArray(),
);
}
public function testOnInsertPostLocalEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL, ['item' => ['id' => -1]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('post_local', $name);
$this->assertSame(['id' => -1], $data);
return ['id' => 123];
});
HookEventBridge::onInsertPostLocalEvent($event);
$this->assertSame(
['item' => ['id' => 123]],
$event->getArray(),
);
}
public function testOnInsertPostLocalEndEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::INSERT_POST_LOCAL_END, ['item' => ['id' => -1]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('post_local_end', $name);
$this->assertSame(['id' => -1], $data);
return ['id' => 123];
});
HookEventBridge::onInsertPostLocalEndEvent($event);
$this->assertSame(
['item' => ['id' => 123]],
$event->getArray(),
);
}
public function testOnPreparePostStartEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::PREPARE_POST_START, ['item' => ['id' => -1]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('prepare_body_init', $name);
$this->assertSame(['id' => -1], $data);
return ['id' => 123];
});
HookEventBridge::onPreparePostStartEvent($event);
$this->assertSame(
['item' => ['id' => 123]],
$event->getArray(),
);
}
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']]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('profile_sidebar_enter', $name);
$this->assertSame(['uid' => 0, 'name' => 'original'], $data);
return ['uid' => 0, 'name' => 'changed'];
});
HookEventBridge::onProfileSidebarEntryEvent($event);
$this->assertSame(
['profile' => ['uid' => 0, 'name' => 'changed']],
$event->getArray(),
);
}
public function testOnOembedFetchEndEventCallsHookWithCorrectValue(): void public function testOnOembedFetchEndEventCallsHookWithCorrectValue(): void
{ {
$event = new ArrayFilterEvent(ArrayFilterEvent::OEMBED_FETCH_END, ['url' => 'original_url']); $event = new ArrayFilterEvent(ArrayFilterEvent::OEMBED_FETCH_END, ['url' => 'original_url']);
@ -255,6 +457,74 @@ class HookEventBridgeTest extends TestCase
); );
} }
public function testOnEventCreatedEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::EVENT_CREATED, ['event' => ['id' => 123]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, int $data): int {
$this->assertSame('event_created', $name);
$this->assertSame(123, $data);
return 123;
});
HookEventBridge::onEventCreatedEvent($event);
}
public function testOnAccountRegisterEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REGISTER, ['uid' => 123]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, int $data): int {
$this->assertSame('register_account', $name);
$this->assertSame(123, $data);
return $data;
});
HookEventBridge::onAccountRegisterEvent($event);
}
public function testOnAccountRemoveEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::ACCOUNT_REMOVE, ['user' => ['uid' => 123]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, array $data): array {
$this->assertSame('remove_user', $name);
$this->assertSame(['uid' => 123], $data);
return $data;
});
HookEventBridge::onAccountRemoveEvent($event);
}
public function testOnEventUpdatedEventCallsHookWithCorrectValue(): void
{
$event = new ArrayFilterEvent(ArrayFilterEvent::EVENT_UPDATED, ['event' => ['id' => 123]]);
$reflectionProperty = new \ReflectionProperty(HookEventBridge::class, 'mockedCallHook');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue(null, function (string $name, int $data): int {
$this->assertSame('event_updated', $name);
$this->assertSame(123, $data);
return 123;
});
HookEventBridge::onEventUpdatedEvent($event);
}
public static function getArrayFilterEventData(): array public static function getArrayFilterEventData(): array
{ {
return [ return [
@ -263,21 +533,64 @@ class HookEventBridgeTest extends TestCase
[ArrayFilterEvent::NAV_INFO, 'nav_info'], [ArrayFilterEvent::NAV_INFO, 'nav_info'],
[ArrayFilterEvent::FEATURE_ENABLED, 'isEnabled'], [ArrayFilterEvent::FEATURE_ENABLED, 'isEnabled'],
[ArrayFilterEvent::FEATURE_GET, 'get'], [ArrayFilterEvent::FEATURE_GET, 'get'],
[ArrayFilterEvent::POST_LOCAL_START, 'post_local_start'], [ArrayFilterEvent::INSERT_POST_LOCAL_START, 'post_local_start'],
[ArrayFilterEvent::POST_LOCAL, 'post_local'], [ArrayFilterEvent::INSERT_POST_REMOTE, 'post_remote'],
[ArrayFilterEvent::POST_LOCAL_END, 'post_local_end'], [ArrayFilterEvent::INSERT_POST_REMOTE_END, 'post_remote_end'],
[ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, 'prepare_body_content_filter'],
[ArrayFilterEvent::PREPARE_POST, 'prepare_body'],
[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_TABS, 'network_tabs'],
[ArrayFilterEvent::PARSE_LINK, 'parse_link'],
[ArrayFilterEvent::CONVERSATION_START, 'conversation_start'], [ArrayFilterEvent::CONVERSATION_START, 'conversation_start'],
[ArrayFilterEvent::FETCH_ITEM_BY_LINK, 'item_by_link'],
[ArrayFilterEvent::ITEM_TAGGED, 'tagged'],
[ArrayFilterEvent::DISPLAY_ITEM, 'display_item'], [ArrayFilterEvent::DISPLAY_ITEM, 'display_item'],
[ArrayFilterEvent::CACHE_ITEM, 'put_item_in_cache'],
[ArrayFilterEvent::CHECK_ITEM_NOTIFICATION, 'check_item_notification'],
[ArrayFilterEvent::ENOTIFY, 'enotify'],
[ArrayFilterEvent::ENOTIFY_STORE, 'enotify_store'],
[ArrayFilterEvent::ENOTIFY_MAIL, 'enotify_mail'],
[ArrayFilterEvent::DETECT_LANGUAGES, 'detect_languages'],
[ArrayFilterEvent::RENDER_LOCATION, 'render_location'], [ArrayFilterEvent::RENDER_LOCATION, 'render_location'],
[ArrayFilterEvent::ITEM_PHOTO_MENU, 'item_photo_menu'], [ArrayFilterEvent::ITEM_PHOTO_MENU, 'item_photo_menu'],
[ArrayFilterEvent::DIRECTORY_ITEM, 'directory_item'],
[ArrayFilterEvent::CONTACT_PHOTO_MENU, 'contact_photo_menu'],
[ArrayFilterEvent::PROFILE_SIDEBAR, 'profile_sidebar'],
[ArrayFilterEvent::PROFILE_TABS, 'profile_tabs'],
[ArrayFilterEvent::PROFILE_SETTINGS_FORM, 'profile_edit'],
[ArrayFilterEvent::PROFILE_SETTINGS_POST, 'profile_post'],
[ArrayFilterEvent::MODERATION_USERS_TABS, 'moderation_users_tabs'],
[ArrayFilterEvent::ACL_LOOKUP_END, 'acl_lookup_end'],
[ArrayFilterEvent::PAGE_INFO, 'page_info_data'], [ArrayFilterEvent::PAGE_INFO, 'page_info_data'],
[ArrayFilterEvent::SMILEY_LIST, 'smilie'], [ArrayFilterEvent::SMILEY_LIST, 'smilie'],
[ArrayFilterEvent::JOT_NETWORKS, 'jot_networks'], [ArrayFilterEvent::JOT_NETWORKS, 'jot_networks'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW, 'support_follow'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW, 'support_follow'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW, 'support_revoke_follow'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW, 'support_revoke_follow'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE, 'support_probe'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE, 'support_probe'],
[ArrayFilterEvent::FOLLOW_CONTACT, 'follow'],
[ArrayFilterEvent::UNFOLLOW_CONTACT, 'unfollow'],
[ArrayFilterEvent::REVOKE_FOLLOW_CONTACT, 'revoke_follow'],
[ArrayFilterEvent::BLOCK_CONTACT, 'block'],
[ArrayFilterEvent::UNBLOCK_CONTACT, 'unblock'],
[ArrayFilterEvent::EDIT_CONTACT_FORM, 'contact_edit'],
[ArrayFilterEvent::EDIT_CONTACT_POST, 'contact_edit_post'],
[ArrayFilterEvent::AVATAR_LOOKUP, 'avatar_lookup'],
[ArrayFilterEvent::ACCOUNT_AUTHENTICATE, 'authenticate'],
[ArrayFilterEvent::ACCOUNT_REGISTER_FORM, 'register_form'],
[ArrayFilterEvent::ACCOUNT_REGISTER_POST, 'register_post'],
[ArrayFilterEvent::ACCOUNT_REGISTER, 'register_account'],
[ArrayFilterEvent::ACCOUNT_REMOVE, 'remove_user'],
[ArrayFilterEvent::EVENT_CREATED, 'event_created'],
[ArrayFilterEvent::EVENT_UPDATED, 'event_updated'],
[ArrayFilterEvent::ADD_WORKER_TASK, 'proc_run'],
[ArrayFilterEvent::STORAGE_CONFIG, 'storage_config'],
[ArrayFilterEvent::STORAGE_INSTANCE, 'storage_instance'],
[ArrayFilterEvent::DB_STRUCTURE_DEFINITION, 'dbstructure_definition'],
[ArrayFilterEvent::DB_VIEW_DEFINITION, 'dbview_definition'],
]; ];
} }
@ -310,6 +623,9 @@ class HookEventBridgeTest extends TestCase
[HtmlFilterEvent::PAGE_HEADER, 'page_header'], [HtmlFilterEvent::PAGE_HEADER, 'page_header'],
[HtmlFilterEvent::PAGE_CONTENT_TOP, 'page_content_top'], [HtmlFilterEvent::PAGE_CONTENT_TOP, 'page_content_top'],
[HtmlFilterEvent::PAGE_END, 'page_end'], [HtmlFilterEvent::PAGE_END, 'page_end'],
[HtmlFilterEvent::MOD_HOME_CONTENT, 'home_content'],
[HtmlFilterEvent::MOD_ABOUT_CONTENT, 'about_hook'],
[HtmlFilterEvent::MOD_PROFILE_CONTENT, 'profile_advanced'],
[HtmlFilterEvent::JOT_TOOL, 'jot_tool'], [HtmlFilterEvent::JOT_TOOL, 'jot_tool'],
[HtmlFilterEvent::CONTACT_BLOCK_END, 'contact_block_end'], [HtmlFilterEvent::CONTACT_BLOCK_END, 'contact_block_end'],
]; ];

View file

@ -29,24 +29,75 @@ class ArrayFilterEventTest extends TestCase
[ArrayFilterEvent::NAV_INFO, 'friendica.data.nav_info'], [ArrayFilterEvent::NAV_INFO, 'friendica.data.nav_info'],
[ArrayFilterEvent::FEATURE_ENABLED, 'friendica.data.feature_enabled'], [ArrayFilterEvent::FEATURE_ENABLED, 'friendica.data.feature_enabled'],
[ArrayFilterEvent::FEATURE_GET, 'friendica.data.feature_get'], [ArrayFilterEvent::FEATURE_GET, 'friendica.data.feature_get'],
[ArrayFilterEvent::POST_LOCAL_START, 'friendica.data.post_local_start'], [ArrayFilterEvent::PERMISSION_TOOLTIP_CONTENT, 'friendica.data.permission_tooltip_content'],
[ArrayFilterEvent::POST_LOCAL, 'friendica.data.post_local'], [ArrayFilterEvent::INSERT_POST_LOCAL_START, 'friendica.data.insert_post_local_start'],
[ArrayFilterEvent::POST_LOCAL_END, 'friendica.data.post_local_end'], [ArrayFilterEvent::INSERT_POST_LOCAL, 'friendica.data.insert_post_local'],
[ArrayFilterEvent::INSERT_POST_LOCAL_END, 'friendica.data.insert_post_local_end'],
[ArrayFilterEvent::INSERT_POST_REMOTE, 'friendica.data.insert_post_remote'],
[ArrayFilterEvent::INSERT_POST_REMOTE_END, 'friendica.data.insert_post_remote_end'],
[ArrayFilterEvent::PREPARE_POST_START, 'friendica.data.prepare_post_start'],
[ArrayFilterEvent::PREPARE_POST_FILTER_CONTENT, 'friendica.data.prepare_post_filter_content'],
[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_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_TABS, 'friendica.data.network_content_tabs'],
[ArrayFilterEvent::PARSE_LINK, 'friendica.data.parse_link'],
[ArrayFilterEvent::CONVERSATION_START, 'friendica.data.conversation_start'], [ArrayFilterEvent::CONVERSATION_START, 'friendica.data.conversation_start'],
[ArrayFilterEvent::FETCH_ITEM_BY_LINK, 'friendica.data.fetch_item_by_link'],
[ArrayFilterEvent::ITEM_TAGGED, 'friendica.data.item_tagged'],
[ArrayFilterEvent::DISPLAY_ITEM, 'friendica.data.display_item'], [ArrayFilterEvent::DISPLAY_ITEM, 'friendica.data.display_item'],
[ArrayFilterEvent::CACHE_ITEM, 'friendica.data.cache_item'],
[ArrayFilterEvent::CHECK_ITEM_NOTIFICATION, 'friendica.data.check_item_notification'],
[ArrayFilterEvent::ENOTIFY, 'friendica.data.enotify'],
[ArrayFilterEvent::ENOTIFY_STORE, 'friendica.data.enotify_store'],
[ArrayFilterEvent::ENOTIFY_MAIL, 'friendica.data.enotify_mail'],
[ArrayFilterEvent::DETECT_LANGUAGES, 'friendica.data.detect_languages'],
[ArrayFilterEvent::RENDER_LOCATION, 'friendica.data.render_location'], [ArrayFilterEvent::RENDER_LOCATION, 'friendica.data.render_location'],
[ArrayFilterEvent::ITEM_PHOTO_MENU, 'friendica.data.item_photo_menu'], [ArrayFilterEvent::ITEM_PHOTO_MENU, 'friendica.data.item_photo_menu'],
[ArrayFilterEvent::DIRECTORY_ITEM, 'friendica.data.directory_item'],
[ArrayFilterEvent::CONTACT_PHOTO_MENU, 'friendica.data.contact_photo_menu'],
[ArrayFilterEvent::PROFILE_SIDEBAR_ENTRY, 'friendica.data.profile_sidebar_entry'],
[ArrayFilterEvent::PROFILE_SIDEBAR, 'friendica.data.profile_sidebar'],
[ArrayFilterEvent::PROFILE_TABS, 'friendica.data.profile_tabs'],
[ArrayFilterEvent::PROFILE_SETTINGS_FORM, 'friendica.data.profile_settings_form'],
[ArrayFilterEvent::PROFILE_SETTINGS_POST, 'friendica.data.profile_settings_post'],
[ArrayFilterEvent::MODERATION_USERS_TABS, 'friendica.data.moderation_users_tabs'],
[ArrayFilterEvent::ACL_LOOKUP_END, 'friendica.data.acl_lookup_end'],
[ArrayFilterEvent::OEMBED_FETCH_END, 'friendica.data.oembed_fetch_end'], [ArrayFilterEvent::OEMBED_FETCH_END, 'friendica.data.oembed_fetch_end'],
[ArrayFilterEvent::PAGE_INFO, 'friendica.data.page_info'], [ArrayFilterEvent::PAGE_INFO, 'friendica.data.page_info'],
[ArrayFilterEvent::SMILEY_LIST, 'friendica.data.smiley_list'], [ArrayFilterEvent::SMILEY_LIST, 'friendica.data.smiley_list'],
[ArrayFilterEvent::BBCODE_TO_HTML_START, 'friendica.data.bbcode_to_html_start'], [ArrayFilterEvent::BBCODE_TO_HTML_START, 'friendica.data.bbcode_to_html_start'],
[ArrayFilterEvent::HTML_TO_BBCODE_END, 'friendica.data.html_to_bbcode_end'],
[ArrayFilterEvent::BBCODE_TO_MARKDOWN_END, 'friendica.data.bbcode_to_markdown_end'], [ArrayFilterEvent::BBCODE_TO_MARKDOWN_END, 'friendica.data.bbcode_to_markdown_end'],
[ArrayFilterEvent::JOT_NETWORKS, 'friendica.data.jot_networks'], [ArrayFilterEvent::JOT_NETWORKS, 'friendica.data.jot_networks'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW, 'friendica.data.protocol_supports_follow'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_FOLLOW, 'friendica.data.protocol_supports_follow'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW, 'friendica.data.protocol_supports_revoke_follow'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_REVOKE_FOLLOW, 'friendica.data.protocol_supports_revoke_follow'],
[ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE, 'friendica.data.protocol_supports_probe'], [ArrayFilterEvent::PROTOCOL_SUPPORTS_PROBE, 'friendica.data.protocol_supports_probe'],
[ArrayFilterEvent::FOLLOW_CONTACT, 'friendica.data.follow_contact'],
[ArrayFilterEvent::UNFOLLOW_CONTACT, 'friendica.data.unfollow_contact'],
[ArrayFilterEvent::REVOKE_FOLLOW_CONTACT, 'friendica.data.revoke_follow_contact'],
[ArrayFilterEvent::BLOCK_CONTACT, 'friendica.data.block_contact'],
[ArrayFilterEvent::UNBLOCK_CONTACT, 'friendica.data.unblock_contact'],
[ArrayFilterEvent::EDIT_CONTACT_FORM, 'friendica.data.edit_contact_form'],
[ArrayFilterEvent::EDIT_CONTACT_POST, 'friendica.data.edit_contact_post'],
[ArrayFilterEvent::AVATAR_LOOKUP, 'friendica.data.avatar_lookup'],
[ArrayFilterEvent::ACCOUNT_AUTHENTICATE, 'friendica.data.account_authenticate'],
[ArrayFilterEvent::ACCOUNT_REGISTER_FORM, 'friendica.data.account_register_form'],
[ArrayFilterEvent::ACCOUNT_REGISTER_POST, 'friendica.data.account_register_post'],
[ArrayFilterEvent::ACCOUNT_REGISTER, 'friendica.data.account_register'],
[ArrayFilterEvent::ACCOUNT_REMOVE, 'friendica.data.account_remove'],
[ArrayFilterEvent::EVENT_CREATED, 'friendica.data.event_created'],
[ArrayFilterEvent::EVENT_UPDATED, 'friendica.data.event_updated'],
[ArrayFilterEvent::ADD_WORKER_TASK, 'friendica.data.add_worker_task'],
[ArrayFilterEvent::STORAGE_CONFIG, 'friendica.data.storage_config'],
[ArrayFilterEvent::STORAGE_INSTANCE, 'friendica.data.storage_instance'],
[ArrayFilterEvent::DB_STRUCTURE_DEFINITION, 'friendica.data.db_structure_definition'],
[ArrayFilterEvent::DB_VIEW_DEFINITION, 'friendica.data.db_view_definition'],
]; ];
} }

View file

@ -27,8 +27,14 @@ class HtmlFilterEventTest extends TestCase
return [ return [
[HtmlFilterEvent::HEAD, 'friendica.html.head'], [HtmlFilterEvent::HEAD, 'friendica.html.head'],
[HtmlFilterEvent::FOOTER, 'friendica.html.footer'], [HtmlFilterEvent::FOOTER, 'friendica.html.footer'],
[HtmlFilterEvent::PAGE_HEADER, 'friendica.html.page_header'],
[HtmlFilterEvent::PAGE_CONTENT_TOP, 'friendica.html.page_content_top'], [HtmlFilterEvent::PAGE_CONTENT_TOP, 'friendica.html.page_content_top'],
[HtmlFilterEvent::PAGE_END, 'friendica.html.page_end'], [HtmlFilterEvent::PAGE_END, 'friendica.html.page_end'],
[HtmlFilterEvent::MOD_HOME_CONTENT, 'friendica.html.mod_home_content'],
[HtmlFilterEvent::MOD_ABOUT_CONTENT, 'friendica.html.mod_about_content'],
[HtmlFilterEvent::MOD_PROFILE_CONTENT, 'friendica.html.mod_profile_content'],
[HtmlFilterEvent::JOT_TOOL, 'friendica.html.jot_tool'],
[HtmlFilterEvent::CONTACT_BLOCK_END, 'friendica.html.contact_block_end'],
]; ];
} }

View file

@ -0,0 +1,31 @@
<?php
// Copyright (C) 2010-2024, the Friendica project
// SPDX-FileCopyrightText: 2010-2024 the Friendica project
//
// SPDX-License-Identifier: AGPL-3.0-or-later
declare(strict_types=1);
namespace Friendica\Test\Util;
use Psr\EventDispatcher\EventDispatcherInterface;
/**
* Defines a dispatcher for events.
*/
final class FakeEventDispatcher implements EventDispatcherInterface
{
/**
* Provide all relevant listeners with an event to process.
*
* @template T of object
* @param T $event
*
* @return T The passed $event MUST be returned
*/
public function dispatch(object $event): object
{
return $event;
}
}

View file

@ -23,12 +23,13 @@ use Friendica\Core\Storage\Type\SystemResource;
use Friendica\Database\Database; use Friendica\Database\Database;
use Friendica\DI; use Friendica\DI;
use Friendica\Core\Config\Factory\Config; use Friendica\Core\Config\Factory\Config;
use Friendica\Core\Hooks\HookEventBridge;
use Friendica\Core\Storage\Type; use Friendica\Core\Storage\Type;
use Friendica\Test\DatabaseTestCase; use Friendica\Test\DatabaseTestCase;
use Friendica\Test\Util\CreateDatabaseTrait; use Friendica\Test\Util\CreateDatabaseTrait;
use Friendica\Test\Util\Database\StaticDatabase; use Friendica\Test\Util\Database\StaticDatabase;
use Friendica\Test\Util\FakeEventDispatcher;
use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStream;
use Psr\Log\LoggerInterface;
use Psr\Log\NullLogger; use Psr\Log\NullLogger;
use Friendica\Test\Util\SampleStorageBackend; use Friendica\Test\Util\SampleStorageBackend;
@ -38,8 +39,6 @@ class StorageManagerTest extends DatabaseTestCase
/** @var IManageConfigValues */ /** @var IManageConfigValues */
private $config; private $config;
/** @var LoggerInterface */
private $logger;
/** @var L10n */ /** @var L10n */
private $l10n; private $l10n;
@ -56,7 +55,6 @@ class StorageManagerTest extends DatabaseTestCase
vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root); vfsStream::newDirectory(Type\FilesystemConfig::DEFAULT_BASE_FOLDER, 0777)->at($this->root);
$this->logger = new NullLogger();
$this->database = $this->getDbInstance(); $this->database = $this->getDbInstance();
$configFactory = new Config(); $configFactory = new Config();
@ -87,7 +85,14 @@ class StorageManagerTest extends DatabaseTestCase
*/ */
public function testInstance() public function testInstance()
{ {
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
self::assertInstanceOf(StorageManager::class, $storageManager); self::assertInstanceOf(StorageManager::class, $storageManager);
} }
@ -149,7 +154,14 @@ class StorageManagerTest extends DatabaseTestCase
$this->config->set('storage', 'name', $name); $this->config->set('storage', 'name', $name);
} }
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
if ($interface === ICanWriteToStorage::class) { if ($interface === ICanWriteToStorage::class) {
$storage = $storageManager->getWritableStorageByName($name); $storage = $storageManager->getWritableStorageByName($name);
@ -169,7 +181,14 @@ class StorageManagerTest extends DatabaseTestCase
*/ */
public function testIsValidBackend($name, $valid, $interface, $assert, $assertName) public function testIsValidBackend($name, $valid, $interface, $assert, $assertName)
{ {
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
// true in every of the backends // true in every of the backends
self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name)); self::assertEquals(!empty($assertName), $storageManager->isValidBackend($name));
@ -183,7 +202,14 @@ class StorageManagerTest extends DatabaseTestCase
*/ */
public function testListBackends() public function testListBackends()
{ {
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends()); self::assertEquals(StorageManager::DEFAULT_BACKENDS, $storageManager->listBackends());
} }
@ -199,7 +225,14 @@ class StorageManagerTest extends DatabaseTestCase
static::markTestSkipped('only works for ICanWriteToStorage'); static::markTestSkipped('only works for ICanWriteToStorage');
} }
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
$selBackend = $storageManager->getWritableStorageByName($name); $selBackend = $storageManager->getWritableStorageByName($name);
$storageManager->setBackend($selBackend); $storageManager->setBackend($selBackend);
@ -219,7 +252,14 @@ class StorageManagerTest extends DatabaseTestCase
$this->expectException(InvalidClassStorageException::class); $this->expectException(InvalidClassStorageException::class);
} }
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
self::assertInstanceOf($assert, $storageManager->getBackend()); self::assertInstanceOf($assert, $storageManager->getBackend());
} }
@ -240,7 +280,14 @@ class StorageManagerTest extends DatabaseTestCase
->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]); ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]);
DI::init($dice); DI::init($dice);
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
self::assertTrue($storageManager->register(SampleStorageBackend::class)); self::assertTrue($storageManager->register(SampleStorageBackend::class));
@ -268,7 +315,21 @@ class StorageManagerTest extends DatabaseTestCase
->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]); ->addRule(IHandleSessions::class, ['instanceOf' => Memory::class, 'shared' => true, 'call' => null]);
DI::init($dice); DI::init($dice);
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); /** @var \Friendica\Event\EventDispatcher */
$eventDispatcher = DI::eventDispatcher();
foreach (HookEventBridge::getStaticSubscribedEvents() as $eventName => $methodName) {
$eventDispatcher->addListener($eventName, [HookEventBridge::class, $methodName]);
}
$storageManager = new StorageManager(
$this->database,
$this->config,
new NullLogger(),
$eventDispatcher,
$this->l10n,
false
);
self::assertTrue($storageManager->register(SampleStorageBackend::class)); self::assertTrue($storageManager->register(SampleStorageBackend::class));
@ -307,8 +368,15 @@ class StorageManagerTest extends DatabaseTestCase
$this->loadFixture(__DIR__ . '/../../../../datasets/storage/database.fixture.php', $this->database); $this->loadFixture(__DIR__ . '/../../../../datasets/storage/database.fixture.php', $this->database);
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$storage = $storageManager->getWritableStorageByName($name); $this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
$storage = $storageManager->getWritableStorageByName($name);
$storageManager->move($storage); $storageManager->move($storage);
$photos = $this->database->select('photo', ['backend-ref', 'backend-class', 'id', 'data']); $photos = $this->database->select('photo', ['backend-ref', 'backend-class', 'id', 'data']);
@ -331,8 +399,15 @@ class StorageManagerTest extends DatabaseTestCase
$this->expectException(InvalidClassStorageException::class); $this->expectException(InvalidClassStorageException::class);
$this->expectExceptionMessage('Backend SystemResource is not valid'); $this->expectExceptionMessage('Backend SystemResource is not valid');
$storageManager = new StorageManager($this->database, $this->config, $this->logger, $this->l10n, false); $storageManager = new StorageManager(
$storage = $storageManager->getWritableStorageByName(SystemResource::getName()); $this->database,
$this->config,
new NullLogger(),
new FakeEventDispatcher(),
$this->l10n,
false
);
$storage = $storageManager->getWritableStorageByName(SystemResource::getName());
$storageManager->move($storage); $storageManager->move($storage);
} }
} }