installed plugin Event Bridge for ActivityPub
version 1.1.0
This commit is contained in:
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* Class responsible for Event Plugin related admin notices.
|
||||
*
|
||||
* Notices for guiding to proper configuration of ActivityPub with event plugins.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
* @license AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\Admin;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration;
|
||||
|
||||
/**
|
||||
* Class responsible for Event Plugin related admin notices.
|
||||
*
|
||||
* Notices for guiding to proper configuration of ActivityPub with event plugins.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Event_Plugin_Admin_Notices {
|
||||
/**
|
||||
* Information about the event plugin.
|
||||
*
|
||||
* @var Event_Plugin_Integration
|
||||
*/
|
||||
protected $event_plugin;
|
||||
|
||||
/**
|
||||
* Adds admin notices to an active supported event plugin.
|
||||
*
|
||||
* @param Event_Plugin_Integration $event_plugin Class that has implements functions to handle a certain supported activate event plugin.
|
||||
*/
|
||||
public function __construct( $event_plugin ) {
|
||||
$this->event_plugin = $event_plugin;
|
||||
if ( $this->event_post_type_is_not_activitypub_enabled() ) {
|
||||
add_action( 'admin_notices', array( $this, 'admin_notice_activitypub_not_enabled_for_post_type' ), 10, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if ActivityPub is enabled for the custom post type of the event plugin.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function event_post_type_is_not_activitypub_enabled(): bool {
|
||||
return ! in_array( $this->event_plugin::get_post_type(), get_option( 'activitypub_support_post_types', array() ), true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the admin notices for the plugins.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_notice_activitypub_not_enabled_for_post_type(): void {
|
||||
if ( $this->event_plugin::is_plugin_page() ) {
|
||||
$this->do_admin_notice_post_type_not_activitypub_enabled();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print admin notice that the current post type is not enabled in the ActivityPub plugin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function do_admin_notice_post_type_not_activitypub_enabled(): void {
|
||||
$all_plugins = get_plugins();
|
||||
$event_plugin_file = $this->event_plugin::get_relative_plugin_file();
|
||||
if ( isset( $all_plugins[ $event_plugin_file ]['Name'] ) ) {
|
||||
$event_plugin_name = $all_plugins[ $event_plugin_file ]['Name'];
|
||||
} elseif ( isset( get_mu_plugins()[ $event_plugin_file ]['Name'] ) ) {
|
||||
$event_plugin_name = get_mu_plugins()[ $event_plugin_file ]['Name'];
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
$activitypub_plugin_data = get_plugin_data( ACTIVITYPUB_PLUGIN_FILE );
|
||||
$notice = sprintf(
|
||||
/* translators: 1: the name of the event plugin a admin notice is shown. 2: The name of the ActivityPub plugin. */
|
||||
_x(
|
||||
'You have installed the <i>%1$s</i> plugin, but the event post type of the plugin <i>%2$s</i> is <b>not enabled</b> in the <a href="%3$s">%1$s settings</a>.',
|
||||
'admin notice',
|
||||
'event-bridge-for-activitypub'
|
||||
),
|
||||
esc_html( $activitypub_plugin_data['Name'] ),
|
||||
esc_html( $event_plugin_name ),
|
||||
admin_url( 'options-general.php?page=activitypub&tab=settings' )
|
||||
);
|
||||
$allowed_html = array(
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
'title' => true,
|
||||
),
|
||||
'b' => array(),
|
||||
'i' => array(),
|
||||
);
|
||||
echo '<div class="notice notice-warning is-dismissible"><p>' . \wp_kses( $notice, $allowed_html ) . '</p></div>';
|
||||
}
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/**
|
||||
* Class responsible for general admin notices.
|
||||
*
|
||||
* Notices for guiding to proper configuration of this plugin.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
* @license AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\Admin;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
/**
|
||||
* Class responsible for general admin notices.
|
||||
*
|
||||
* Notices for guiding to proper configuration of this plugin.
|
||||
* - ActivityPub plugin not installed and activated
|
||||
* - No supported Event Plugin installed and activated
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class General_Admin_Notices {
|
||||
/**
|
||||
* URL of the ActivityPub plugin. Needed when the ActivityPub plugin is not installed.
|
||||
*/
|
||||
const ACTIVITYPUB_PLUGIN_URL = 'https://wordpress.org/plugins/activitypub';
|
||||
|
||||
const EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL = 'https://wordpress.org/plugins/event-bridge-for-activitypub/#installation';
|
||||
|
||||
/**
|
||||
* Allowed HTML for admin notices.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
const ALLOWED_HTML = array(
|
||||
'a' => array(
|
||||
'href' => true,
|
||||
'title' => true,
|
||||
'target' => true,
|
||||
),
|
||||
'br',
|
||||
'i',
|
||||
);
|
||||
|
||||
/**
|
||||
* Admin notice when the ActivityPub plugin is not enabled.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_admin_notice_activitypub_plugin_not_enabled(): string {
|
||||
return sprintf(
|
||||
/* translators: 1: An URL that points to the ActivityPub plugin. */
|
||||
_x(
|
||||
'For the Event Bridge for ActivityPub to work, you will need to install and activate the <a href="%1$s">ActivityPub</a> plugin.',
|
||||
'admin notice',
|
||||
'event-bridge-for-activitypub'
|
||||
),
|
||||
esc_html( self::ACTIVITYPUB_PLUGIN_URL )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin notice when the ActivityPub plugin version is too old.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_admin_notice_activitypub_plugin_version_too_old(): string {
|
||||
return sprintf(
|
||||
/* translators: 1: The name of the ActivityPub plugin. 2: The minimum required version number of the ActivityPub plugin. */
|
||||
_x(
|
||||
'Please upgrade your <a href="%1$s">ActivityPub</a> plugin. At least version %2$s is required for the Event Bridge for ActivityPub to work.',
|
||||
'admin notice',
|
||||
'event-bridge-for-activitypub'
|
||||
),
|
||||
esc_html( self::ACTIVITYPUB_PLUGIN_URL ),
|
||||
esc_html( EVENT_BRIDGE_FOR_ACTIVITYPUB_ACTIVITYPUB_PLUGIN_MIN_VERSION )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning that no supported event plugin can be found.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_admin_notice_no_supported_event_plugin_active(): string {
|
||||
return sprintf(
|
||||
/* translators: 1: An URL to the list of supported event plugins. */
|
||||
_x(
|
||||
'The Plugin <i>Event Bridge for ActivityPub</i> is of no use, because you do not have installed and activated a supported Event Plugin.
|
||||
<br> For a list of supported Event Plugins see <a href="%1$s" target="_blank">here</a>.',
|
||||
'admin notice',
|
||||
'event-bridge-for-activitypub'
|
||||
),
|
||||
esc_url( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning to fix status issues first.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_admin_notice_status_not_ok(): string {
|
||||
return sprintf(
|
||||
/* translators: 1: An URL to the list of supported event plugins. */
|
||||
_x(
|
||||
'The Plugin <i>Event Bridge for ActivityPub</i> is of no use, because you do not have installed and activated a supported Event Plugin.
|
||||
<br> For a list of supported Event Plugins see <a href="%1$s">here</a>.',
|
||||
'admin notice',
|
||||
'event-bridge-for-activitypub'
|
||||
),
|
||||
esc_html( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning if the plugin is Active and the ActivityPub plugin is not.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function activitypub_plugin_not_enabled(): void {
|
||||
$notice = self::get_admin_notice_activitypub_plugin_not_enabled();
|
||||
// @phpstan-ignore-next-line
|
||||
echo '<div class="notice notice-warning"><p>' . \wp_kses( $notice, self::ALLOWED_HTML ) . '</p></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning if the plugin is Active and the ActivityPub plugins version is too old.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function activitypub_plugin_version_too_old(): void {
|
||||
$notice = self::get_admin_notice_activitypub_plugin_version_too_old();
|
||||
// @phpstan-ignore-next-line
|
||||
echo '<div class="notice notice-warning"><p>' . \wp_kses( $notice, self::ALLOWED_HTML ) . '</p></div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning when no supported Even Plugin is installed and active.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function no_supported_event_plugin_active(): void {
|
||||
$notice = self::get_admin_notice_no_supported_event_plugin_active();
|
||||
// @phpstan-ignore-next-line
|
||||
echo '<div class="notice notice-warning"><p>' . \wp_kses( $notice, self::ALLOWED_HTML ) . '</p></div>';
|
||||
}
|
||||
}
|
@ -0,0 +1,211 @@
|
||||
<?php
|
||||
/**
|
||||
* Health_Check class.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\Admin;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Transformer\Factory as Transformer_Factory;
|
||||
use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration;
|
||||
use Event_Bridge_For_ActivityPub\Setup;
|
||||
use WP_Post;
|
||||
use WP_Query;
|
||||
|
||||
/**
|
||||
* ActivityPub Health_Check Class.
|
||||
*/
|
||||
class Health_Check {
|
||||
/**
|
||||
* Initialize health checks.
|
||||
*/
|
||||
public static function init() {
|
||||
\add_filter( 'site_status_tests', array( self::class, 'add_tests' ) );
|
||||
\add_filter( 'debug_information', array( self::class, 'add_debug_information' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tests to the Site Health Check.
|
||||
*
|
||||
* @param array $tests The test array.
|
||||
*
|
||||
* @return array The filtered test array.
|
||||
*/
|
||||
public static function add_tests( $tests ): array {
|
||||
$tests['direct']['event_bridge_for_activitypub_test'] = array(
|
||||
'label' => __( 'ActivityPub Event Transformer Test', 'event-bridge-for-activitypub' ),
|
||||
'test' => array( self::class, 'test_event_transformation' ),
|
||||
);
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* The the transformation of the most recent event posts.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function test_event_transformation(): array {
|
||||
$result = array(
|
||||
'label' => \__( 'Transformation of Events to a valid ActivityStreams representation.', 'event-bridge-for-activitypub' ),
|
||||
'status' => 'good',
|
||||
'badge' => array(
|
||||
'label' => \__( 'Event Bridge for ActivityPub', 'event-bridge-for-activitypub' ),
|
||||
'color' => 'green',
|
||||
),
|
||||
'description' => \sprintf(
|
||||
'<p>%s</p>',
|
||||
\__( 'The transformation to ActivityPub of your most recent events was successful.', 'event-bridge-for-activitypub' )
|
||||
),
|
||||
'actions' => '',
|
||||
'test' => 'test_event_transformation',
|
||||
);
|
||||
|
||||
$check = self::transform_most_recent_event_posts();
|
||||
|
||||
if ( true === $check ) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
$result['status'] = 'critical';
|
||||
$result['label'] = \__( 'One or more of your most recent events failed to transform to ActivityPub', 'event-bridge-for-activitypub' );
|
||||
$result['badge']['color'] = 'red';
|
||||
$result['description'] = \sprintf(
|
||||
'<p>%s</p>',
|
||||
\__( 'The transformation to ActivityPub of your most recent events was not successful.', 'event-bridge-for-activitypub' )
|
||||
);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if right transformer gets applied.
|
||||
*
|
||||
* @param Event_Plugin_Integration $event_plugin The event plugin definition.
|
||||
*
|
||||
* @return bool True if the check passed.
|
||||
*/
|
||||
public static function test_if_event_transformer_is_used( $event_plugin ): bool {
|
||||
if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get a (random) event post.
|
||||
$event_posts = self::get_most_recent_event_posts( $event_plugin->get_post_type(), 1 );
|
||||
|
||||
// If no post is found, we can not do this test.
|
||||
if ( isset( $event_posts[0] ) || empty( $event_posts ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Call the transformer Factory.
|
||||
$transformer = Transformer_Factory::get_transformer( \get_post( $event_posts[0] ) );
|
||||
// Check that we got the right transformer.
|
||||
$desired_transformer_class = $event_plugin::get_activitypub_event_transformer( $event_posts[0] );
|
||||
if ( $transformer instanceof $desired_transformer_class ) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the most recently published event posts of a certain event post type.
|
||||
*
|
||||
* @param ?string $event_post_type The post type of the events.
|
||||
* @param ?int $number_of_posts The maximum number of events to return.
|
||||
*
|
||||
* @return \WP_Post[] Array of event posts, or false if none are found.
|
||||
*/
|
||||
public static function get_most_recent_event_posts( $event_post_type = null, $number_of_posts = 5 ): array {
|
||||
if ( ! Setup::get_instance()->is_activitypub_plugin_active() ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
if ( ! $event_post_type ) {
|
||||
$active_event_plugins = Setup::get_instance()->get_active_event_plugins();
|
||||
$active_event_plugin = reset( $active_event_plugins );
|
||||
if ( ! $active_event_plugin ) {
|
||||
return array();
|
||||
}
|
||||
$event_post_type = $active_event_plugin->get_post_type();
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'numberposts' => $number_of_posts,
|
||||
'category' => 0,
|
||||
'orderby' => 'date',
|
||||
'order' => 'DESC',
|
||||
'include' => array(),
|
||||
'exclude' => array(),
|
||||
'meta_query' => array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => '_event_bridge_for_activitypub_event_source',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
array(
|
||||
'key' => '_event_bridge_for_activitypub_event_source',
|
||||
'value' => '',
|
||||
'compare' => '=',
|
||||
),
|
||||
),
|
||||
'post_type' => $event_post_type,
|
||||
'suppress_filters' => true,
|
||||
);
|
||||
|
||||
$query = new WP_Query();
|
||||
return $query->query( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the most recent event posts.
|
||||
*/
|
||||
public static function transform_most_recent_event_posts(): bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves information like name and version from active event plugins.
|
||||
*/
|
||||
private static function get_info_about_active_event_plugins(): array {
|
||||
$active_event_plugins = Setup::get_instance()->get_active_event_plugins();
|
||||
$info = array();
|
||||
foreach ( $active_event_plugins as $active_event_plugin ) {
|
||||
$event_plugin_file = $active_event_plugin->get_relative_plugin_file();
|
||||
$event_plugin_data = \get_plugin_data( $event_plugin_file );
|
||||
|
||||
$info[] = array(
|
||||
'event_plugin_name' => $event_plugin_data['Name'],
|
||||
'event_plugin_version' => $event_plugin_data['Version'],
|
||||
'event_plugin_file' => $event_plugin_file,
|
||||
);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static function for generating site debug data when required.
|
||||
*
|
||||
* @param array $info The debug information to be added to the core information page.
|
||||
* @return array The extended information.
|
||||
*/
|
||||
public static function add_debug_information( $info ): array {
|
||||
$info['event_bridge_for_activitypub'] = array(
|
||||
'label' => __( 'Event Bridge for ActivityPub', 'event-bridge-for-activitypub' ),
|
||||
'fields' => array(
|
||||
'plugin_version' => array(
|
||||
'label' => __( 'Plugin Version', 'event-bridge-for-activitypub' ),
|
||||
'value' => EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_VERSION,
|
||||
'private' => true,
|
||||
),
|
||||
'active_event_plugins' => self::get_info_about_active_event_plugins(),
|
||||
),
|
||||
);
|
||||
|
||||
return $info;
|
||||
}
|
||||
}
|
@ -0,0 +1,280 @@
|
||||
<?php
|
||||
/**
|
||||
* General settings class.
|
||||
*
|
||||
* This file contains the General class definition, which handles the "General" settings
|
||||
* page for the Event Bridge for ActivityPub Plugin, providing options for configuring various general settings.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\Admin;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Activitypub\Webfinger;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Source_Collection;
|
||||
use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin_Integration;
|
||||
use Event_Bridge_For_ActivityPub\Integrations\Feature_Event_Sources;
|
||||
use Event_Bridge_For_ActivityPub\Setup;
|
||||
|
||||
/**
|
||||
* Class responsible for the Event Bridge for ActivityPub related Settings.
|
||||
*
|
||||
* Class which handles the "General" settings page for the Event Bridge for ActivityPub Plugin,
|
||||
* providing options for configuring various general settings.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Settings_Page {
|
||||
const STATIC = 'Event_Bridge_For_ActivityPub\Admin\Settings_Page';
|
||||
|
||||
const SETTINGS_SLUG = 'event-bridge-for-activitypub';
|
||||
|
||||
/**
|
||||
* Init settings pages.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function init() {
|
||||
\add_filter( 'activitypub_admin_settings_tabs', array( self::class, 'add_settings_tab' ) );
|
||||
\add_action(
|
||||
'admin_init',
|
||||
array( self::class, 'maybe_add_event_source' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom tab to the ActivityPub settings.
|
||||
*
|
||||
* @param array $tabs The existing tabs array.
|
||||
* @return array The modified tabs array.
|
||||
*/
|
||||
public static function add_settings_tab( $tabs ): array {
|
||||
$tabs['event-bridge-for-activitypub'] = array(
|
||||
'label' => __( 'Event Bridge', 'event-bridge-for-activitypub' ),
|
||||
'template' => EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/tab.php',
|
||||
);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the current request wants to add an event source (ActivityPub follow) and passed on to actual handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function maybe_add_event_source() {
|
||||
if ( ! isset( $_POST['event_bridge_for_activitypub_add_event_source'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check and verify request and check capabilities.
|
||||
if ( ! \wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), 'event-bridge-for-activitypub_add-event-source-options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! \current_user_can( 'manage_options' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$event_source = \sanitize_text_field( $_POST['event_bridge_for_activitypub_add_event_source'] );
|
||||
|
||||
$actor_url = false;
|
||||
$url = \wp_parse_url( $event_source );
|
||||
|
||||
$error_message = \esc_html__( 'Failed to add Event Source', 'event-bridge-for-activitypub' );
|
||||
|
||||
// Check if URL is a Collection or a single Actor.
|
||||
$maybe_collection = \wp_safe_remote_get( $event_source );
|
||||
|
||||
if ( ! \is_wp_error( $maybe_collection ) ) {
|
||||
$maybe_collection = \json_decode( \wp_remote_retrieve_body( $maybe_collection ), true );
|
||||
}
|
||||
|
||||
$event_sources = array();
|
||||
|
||||
if ( isset( $maybe_collection['type'] ) && in_array( $maybe_collection['type'], array( 'Collection', 'OrderedCollection' ), true ) ) {
|
||||
// Return only the IDs of the items in the collection.
|
||||
$event_sources = \wp_list_pluck( $maybe_collection['items'], 'id' );
|
||||
} else {
|
||||
$event_sources[] = $event_source;
|
||||
}
|
||||
|
||||
// Iterate over all event sources and add them to the collection.
|
||||
foreach ( $event_sources as $event_source ) {
|
||||
$url = \wp_parse_url( $event_source );
|
||||
|
||||
if ( isset( $url['path'], $url['host'], $url['scheme'] ) ) {
|
||||
$actor_url = \sanitize_url( $event_source );
|
||||
} elseif ( preg_match( '/^@?' . Event_Source::ACTIVITYPUB_USER_HANDLE_REGEXP . '$/i', $event_source ) ) {
|
||||
$actor_url = Webfinger::resolve( $event_source );
|
||||
if ( \is_wp_error( $actor_url ) ) {
|
||||
\add_settings_error(
|
||||
'event-bridge-for-activitypub_add-event-source',
|
||||
'event_bridge_for_activitypub_cannot_follow_actor',
|
||||
$error_message . ': ' . esc_html__( 'Cannot find an ActivityPub actor for this user handle via Webfinger.', 'event-bridge-for-activitypub' ),
|
||||
'error'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if ( ! isset( $url['path'] ) && isset( $url['host'] ) ) {
|
||||
$actor_url = Event_Sources::get_application_actor( $url['host'] );
|
||||
} elseif ( self::is_domain( $event_source ) ) {
|
||||
$actor_url = Event_Sources::get_application_actor( $event_source );
|
||||
}
|
||||
if ( ! $actor_url ) {
|
||||
\add_settings_error(
|
||||
'event-bridge-for-activitypub_add-event-source',
|
||||
'event_bridge_for_activitypub_cannot_follow_actor',
|
||||
$error_message . ': ' . \esc_html__( 'Unable to identify the ActivityPub relay actor to follow for this domain.', 'event-bridge-for-activitypub' ),
|
||||
'error'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $actor_url ) {
|
||||
\add_settings_error(
|
||||
'event-bridge-for-activitypub_add-event-source',
|
||||
'event_bridge_for_activitypub_cannot_follow_actor',
|
||||
$error_message . ': ' . \esc_html__( 'ActivityPub actor does not exist.', 'event-bridge-for-activitypub' ),
|
||||
'error'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't proceed if on the same host!
|
||||
if ( \wp_parse_url( \home_url(), PHP_URL_HOST ) === \wp_parse_url( $actor_url, PHP_URL_HOST ) ) {
|
||||
\add_settings_error(
|
||||
'event-bridge-for-activitypub_add-event-source',
|
||||
'event_bridge_for_activitypub_cannot_follow_actor',
|
||||
$error_message . ': ' . \esc_html__( 'Cannot follow own actor on own domain.', 'event-bridge-for-activitypub' ),
|
||||
'error'
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
Event_Source_Collection::add_event_source( $actor_url );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a string is a valid domain name.
|
||||
*
|
||||
* @param string $domain The input string which might be a domain.
|
||||
* @return bool
|
||||
*/
|
||||
private static function is_domain( $domain ): bool {
|
||||
$pattern = '/^(?!\-)(?:(?:[a-zA-Z\d](?:[a-zA-Z\d\-]{0,61}[a-zA-Z\d])?)\.)+(?!\d+$)[a-zA-Z\d]{2,63}$/';
|
||||
return 1 === preg_match( $pattern, $domain );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds Link to the settings page in the plugin page.
|
||||
* It's called via apply_filter('plugin_action_links_' . PLUGIN_NAME).
|
||||
*
|
||||
* @param array $links Already added links.
|
||||
*
|
||||
* @return array Original links but with link to setting page added.
|
||||
*/
|
||||
public static function settings_link( $links ): array {
|
||||
$links[] = \sprintf(
|
||||
'<a href="%1s">%2s</a>',
|
||||
\add_query_arg( 'tab', 'event-bridge-for-activitypub', \menu_page_url( 'activitypub', false ) ),
|
||||
\__( 'Settings', 'event-bridge-for-activitypub' )
|
||||
);
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Receive the event categories (terms) used by the event plugin.
|
||||
*
|
||||
* @param Event_Plugin_Integration $event_plugin Contains info about a certain event plugin.
|
||||
*
|
||||
* @return array An array of Terms.
|
||||
*/
|
||||
private static function get_event_terms( $event_plugin ): array {
|
||||
$taxonomy = $event_plugin::get_event_category_taxonomy();
|
||||
if ( $taxonomy ) {
|
||||
$event_terms = get_terms(
|
||||
array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'hide_empty' => true,
|
||||
)
|
||||
);
|
||||
return ! is_wp_error( $event_terms ) ? $event_terms : array();
|
||||
} else {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Preparing the data and loading the template for the settings page.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function do_settings_page(): void {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( empty( $_GET['subpage'] ) ) {
|
||||
$tab = 'welcome';
|
||||
} else {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$tab = \sanitize_key( $_GET['subpage'] );
|
||||
}
|
||||
|
||||
// Fallback to always re-scan active event plugins, when user visits admin area of this plugin.
|
||||
$plugin_setup = Setup::get_instance();
|
||||
$plugin_setup->redetect_active_event_plugins();
|
||||
$event_plugins = $plugin_setup->get_active_event_plugins();
|
||||
|
||||
switch ( $tab ) {
|
||||
case 'settings':
|
||||
$event_terms = array();
|
||||
|
||||
foreach ( $event_plugins as $event_plugin_integration ) {
|
||||
$event_terms = array_merge( $event_terms, self::get_event_terms( $event_plugin_integration ) );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'slug' => self::SETTINGS_SLUG,
|
||||
'event_terms' => $event_terms,
|
||||
);
|
||||
|
||||
\load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/settings.php', true, $args );
|
||||
break;
|
||||
case 'event-sources':
|
||||
$supports_event_sources = array();
|
||||
|
||||
foreach ( $event_plugins as $event_plugin_integration ) {
|
||||
if ( is_a( $event_plugin_integration, Feature_Event_Sources::class ) ) {
|
||||
$class_name = get_class( $event_plugin_integration );
|
||||
$supports_event_sources[ $class_name ] = $event_plugin_integration::get_plugin_name();
|
||||
}
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'supports_event_sources' => $supports_event_sources,
|
||||
);
|
||||
|
||||
\wp_enqueue_script( 'thickbox' );
|
||||
\wp_enqueue_style( 'thickbox' );
|
||||
\load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/event-sources.php', true, $args );
|
||||
break;
|
||||
case 'welcome':
|
||||
default:
|
||||
\wp_enqueue_script( 'plugin-install' );
|
||||
\add_thickbox();
|
||||
\wp_enqueue_script( 'updates' );
|
||||
|
||||
\load_template( EVENT_BRIDGE_FOR_ACTIVITYPUB_PLUGIN_DIR . 'templates/settings/subpages/welcome.php', true );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
<?php
|
||||
/**
|
||||
* Class responsible for User Interface additions in the Admin UI.
|
||||
*
|
||||
* @package Event_Bridge_For_ActivityPub
|
||||
* @since 1.0.0
|
||||
* @license AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace Event_Bridge_For_ActivityPub\Admin;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore
|
||||
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Model\Event_Source;
|
||||
use Event_Bridge_For_ActivityPub\ActivityPub\Collection\Event_Sources as Event_Sources_Collection;
|
||||
use Event_Bridge_For_ActivityPub\Event_Sources;
|
||||
|
||||
/**
|
||||
* Class responsible for Event Plugin related admin notices.
|
||||
*
|
||||
* Notices for guiding to proper configuration of ActivityPub with event plugins.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class User_Interface {
|
||||
/**
|
||||
* Init.
|
||||
*/
|
||||
public static function init() {
|
||||
\add_filter( 'page_row_actions', array( self::class, 'row_actions' ), 10, 2 );
|
||||
\add_filter( 'post_row_actions', array( self::class, 'row_actions' ), 10, 2 );
|
||||
\add_filter( 'map_meta_cap', array( self::class, 'disable_editing_for_external_events' ), 10, 4 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an column that shows the origin of an external event.
|
||||
*
|
||||
* @param array $columns The current columns.
|
||||
* @return array
|
||||
*/
|
||||
public static function add_origin_column( $columns ) {
|
||||
// Add a new column after the title column.
|
||||
$columns['activitypub_origin'] = __( 'ActivityPub origin', 'event-bridge-for-activitypub' );
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a "⁂ Preview" link to the row actions.
|
||||
*
|
||||
* @param array $actions The existing actions.
|
||||
* @param \WP_Post $post The post object.
|
||||
*
|
||||
* @return array The modified actions.
|
||||
*/
|
||||
public static function row_actions( $actions, $post ): array {
|
||||
// check if the post is enabled for ActivityPub.
|
||||
if ( ! Event_Sources::is_cached_external_post( $post ) ) {
|
||||
return $actions;
|
||||
}
|
||||
|
||||
$url = $post->guid;
|
||||
|
||||
$parent = get_post_parent();
|
||||
|
||||
if ( $parent && Event_Sources_Collection::POST_TYPE === $parent->post_type ) {
|
||||
$url = \get_post_meta( $parent->ID, '_activitypub_actor_id', true );
|
||||
}
|
||||
|
||||
$actions['view_origin'] = sprintf(
|
||||
'<a href="%s" target="_blank">⁂ %s</a>',
|
||||
\esc_url( $url ),
|
||||
\esc_html__( 'Open original page', 'event-bridge-for-activitypub' )
|
||||
);
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify the user capabilities so that nobody can edit external events.
|
||||
*
|
||||
* @param array $caps Concerned user's capabilities.
|
||||
* @param mixed $cap Required primitive capabilities for the requested capability.
|
||||
* @param array $user_id The WordPress user ID.
|
||||
* @param array $args Additional args.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function disable_editing_for_external_events( $caps, $cap, $user_id, $args ) {
|
||||
if ( 'edit_post' === $cap && isset( $args[0] ) ) {
|
||||
$post_id = $args[0];
|
||||
$post = get_post( $post_id );
|
||||
if ( $post && Event_Sources::is_cached_external_post( $post ) ) {
|
||||
// Deny editing by returning 'do_not_allow'.
|
||||
return array( 'do_not_allow' );
|
||||
}
|
||||
}
|
||||
return $caps;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user