From cc78b216a2c989475dd6377cd30a62a388bee35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Thu, 19 Dec 2024 16:06:25 +0100 Subject: [PATCH 1/2] Fix healthcheck when no supported event plugin is installed (#88) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://code.event-federation.eu/Event-Federation/wordpress-event-bridge-for-activitypub/pulls/88 Co-authored-by: André Menrath Co-committed-by: André Menrath --- CHANGELOG.md | 8 +------- README.md | 4 ++-- event-bridge-for-activitypub.php | 2 +- includes/admin/class-general-admin-notices.php | 11 ++++++----- includes/admin/class-health-check.php | 5 ++++- readme.txt | 4 ++-- templates/welcome.php | 7 +++++++ tests/test-class-plugin-gatherpress.php | 4 ++-- 8 files changed, 25 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e4577..f1b3e56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,13 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## Unreleased - -### Added - -* Add custom summary via shortcodes - -## [0.3.2] - 2024-12-12 +## [0.3.3] - 2024-12-19 * Initial release on WordPress.org diff --git a/README.md b/README.md index 83c871f..9543da5 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **Tags:** events, fediverse, activitypub, calendar **Requires at least:** 6.5 **Tested up to:** 6.7 -**Stable tag:** 0.3.2 +**Stable tag:** 0.3.3 **Requires PHP:** 7.4 **License:** AGPL-3.0-or-later **License URI:** https://www.gnu.org/licenses/agpl-3.0.html @@ -102,7 +102,7 @@ We're always interested in your feedback. Feel free to reach out to us via [E-Ma ## Changelog ## -### [0.3.2] 2024-12-12 ### +### [0.3.3] 2024-12-19 ### * Initial release on https://wordpress.org/ diff --git a/event-bridge-for-activitypub.php b/event-bridge-for-activitypub.php index ec9cfad..f1ce6b3 100644 --- a/event-bridge-for-activitypub.php +++ b/event-bridge-for-activitypub.php @@ -3,7 +3,7 @@ * Plugin Name: Event Bridge for ActivityPub * Description: Integrating popular event plugins with the ActivityPub plugin. * Plugin URI: https://event-federation.eu/ - * Version: 0.3.2 + * Version: 0.3.3 * Author: André Menrath * Author URI: https://graz.social/@linos * Text Domain: event-bridge-for-activitypub diff --git a/includes/admin/class-general-admin-notices.php b/includes/admin/class-general-admin-notices.php index a58c2c4..ee7f886 100644 --- a/includes/admin/class-general-admin-notices.php +++ b/includes/admin/class-general-admin-notices.php @@ -29,7 +29,7 @@ class General_Admin_Notices { */ const ACTIVITYPUB_PLUGIN_URL = 'https://wordpress.org/plugins/activitypub'; - const EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL = 'https://code.event-federation.eu/Event-Federation/wordpress-event-bridge-for-activitypub#events-plugin-that-will-be-supported-at-first'; + const EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL = 'https://code.event-federation.eu/Event-Federation/wordpress-event-bridge-for-activitypub#supported-event-plugins'; /** * Allowed HTML for admin notices. @@ -38,8 +38,9 @@ class General_Admin_Notices { */ const ALLOWED_HTML = array( 'a' => array( - 'href' => true, - 'title' => true, + 'href' => true, + 'title' => true, + 'target' => true, ), 'br', 'i', @@ -90,11 +91,11 @@ class General_Admin_Notices { /* translators: 1: An URL to the list of supported event plugins. */ _x( 'The Plugin Event Bridge for ActivityPub is of no use, because you do not have installed and activated a supported Event Plugin. -
For a list of supported Event Plugins see here.', +
For a list of supported Event Plugins see here.', 'admin notice', 'event-bridge-for-activitypub' ), - esc_html( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL ) + esc_url( self::EVENT_BRIDGE_FOR_ACTIVITYPUB_SUPPORTED_EVENT_PLUGINS_URL ) ); } diff --git a/includes/admin/class-health-check.php b/includes/admin/class-health-check.php index 45d4ea0..07c0a95 100644 --- a/includes/admin/class-health-check.php +++ b/includes/admin/class-health-check.php @@ -116,7 +116,10 @@ class Health_Check { if ( ! $event_post_type ) { $active_event_plugins = Setup::get_instance()->get_active_event_plugins(); $active_event_plugin = reset( $active_event_plugins ); - $event_post_type = $active_event_plugin->get_post_type(); + if ( ! $active_event_plugin ) { + return false; + } + $event_post_type = $active_event_plugin->get_post_type(); } $args = array( diff --git a/readme.txt b/readme.txt index 35b33d0..fb93cf9 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: andremenrath Tags: events, fediverse, activitypub, calendar Requires at least: 6.5 Tested up to: 6.7 -Stable tag: 0.3.2 +Stable tag: 0.3.3 Requires PHP: 7.4 License: AGPL-3.0-or-later License URI: https://www.gnu.org/licenses/agpl-3.0.html @@ -96,6 +96,6 @@ We're always interested in your feedback. Feel free to reach out to us via [E-Ma == Changelog == -= [0.3.2] 2024-12-12 = += [0.3.3] 2024-12-19 = * Initial release on https://wordpress.org/ diff --git a/templates/welcome.php b/templates/welcome.php index 503df4f..c6c3567 100644 --- a/templates/welcome.php +++ b/templates/welcome.php @@ -9,6 +9,7 @@ defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore use Event_Bridge_For_ActivityPub\Setup; +use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\Settings_Page; use Event_Bridge_For_ActivityPub\Admin\Health_Check; @@ -41,6 +42,12 @@ WP_Filesystem();

+ ⚠' . \wp_kses( $notice, General_Admin_Notices::ALLOWED_HTML ) . '

'; + ?>

get_plugin_name() ); ?>:

    diff --git a/tests/test-class-plugin-gatherpress.php b/tests/test-class-plugin-gatherpress.php index 9a7a076..a3fb55e 100644 --- a/tests/test-class-plugin-gatherpress.php +++ b/tests/test-class-plugin-gatherpress.php @@ -56,7 +56,7 @@ class Test_GatherPress extends WP_UnitTestCase { $params = array( 'datetime_start' => '+10 days 15:00:00', 'datetime_end' => '+10 days 16:00:00', - 'timezone' => 'America/New_York', + 'timezone' => \wp_timezone_string(), ); $event->save_datetimes( $params ); @@ -85,7 +85,7 @@ class Test_GatherPress extends WP_UnitTestCase { $params = array( 'datetime_start' => '+10 days 15:00:00', 'datetime_end' => '+10 days 16:00:00', - 'timezone' => 'America/New_York', + 'timezone' => \wp_timezone_string(), ); $event->save_datetimes( $params ); From c5578776d92f6c0345c9b47cef93e4d075f3b7e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Thu, 19 Dec 2024 17:00:30 +0100 Subject: [PATCH 2/2] Temporarily remove EventPrime integration because of security issues. (#89) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://code.event-federation.eu/Event-Federation/wordpress-event-bridge-for-activitypub/pulls/89 Co-authored-by: André Menrath Co-committed-by: André Menrath --- .forgejo/workflows/phpunit.yml | 5 - README.md | 1 - .../transformer/class-eventprime.php | 78 ------- includes/class-setup.php | 1 - includes/integrations/class-eventprime.php | 221 ------------------ readme.txt | 1 - tests/test-class-plugin-eventprime.php | 186 --------------- 7 files changed, 493 deletions(-) delete mode 100644 includes/activitypub/transformer/class-eventprime.php delete mode 100644 includes/integrations/class-eventprime.php delete mode 100644 tests/test-class-plugin-eventprime.php diff --git a/.forgejo/workflows/phpunit.yml b/.forgejo/workflows/phpunit.yml index 5f300c7..afb653e 100644 --- a/.forgejo/workflows/phpunit.yml +++ b/.forgejo/workflows/phpunit.yml @@ -115,11 +115,6 @@ jobs: env: PHP_VERSION: ${{ matrix.php-version }} - - name: Run Integration tests for EventPrime - run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=eventprime - env: - PHP_VERSION: ${{ matrix.php-version }} - - name: Run Integration tests for Event Organiser run: cd /workspace/Event-Federation/wordpress-event-bridge-for-activitypub/ && ./vendor/bin/phpunit --filter=event_organiser env: diff --git a/README.md b/README.md index 9543da5..2f7a674 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/ac * [Eventin](https://de.wordpress.org/plugins/wp-event-solution/) * [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/) * [GatherPress](https://gatherpress.org/) -* [EventPrime – Events Calendar, Bookings and Tickets](https://wordpress.org/plugins/eventprime-event-calendar-management/) * [Event Organiser](https://wordpress.org/plugins/event-organiser/) ## Configuration ## diff --git a/includes/activitypub/transformer/class-eventprime.php b/includes/activitypub/transformer/class-eventprime.php deleted file mode 100644 index c85548e..0000000 --- a/includes/activitypub/transformer/class-eventprime.php +++ /dev/null @@ -1,78 +0,0 @@ -wp_object->ID, 'em_end_date', true ); - if ( $timestamp ) { - return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); - } else { - return null; - } - } - - /** - * Get the end time from the event object. - */ - public function get_start_time(): string { - $timestamp = get_post_meta( $this->wp_object->ID, 'em_start_date', true ); - if ( $timestamp ) { - return \gmdate( 'Y-m-d\TH:i:s\Z', $timestamp ); - } else { - return ''; - } - } - - /** - * Get location from the event object. - */ - public function get_location(): ?Place { - $venue_term_id = get_post_meta( $this->wp_object->ID, 'em_venue', true ); - if ( ! $venue_term_id ) { - return null; - } - - $venue = wp_get_post_terms( $this->wp_object->ID, 'em_venue' ); - - if ( empty( $venue ) ) { - return null; - } else { - $venue = $venue[0]; - } - - $place = new Place(); - - $place->set_name( $venue->name ); - $place->set_content( $venue->description ); - - $address = get_term_meta( $venue->term_id, 'em_address', true ); - $display_address = get_term_meta( $venue->term_id, 'em_display_address_on_frontend', true ); - - if ( $address && $display_address ) { - $place->set_address( get_term_meta( $venue->term_id, 'em_address', true ) ); - } - - return $place; - } -} diff --git a/includes/class-setup.php b/includes/class-setup.php index f75721f..f3d72f6 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -130,7 +130,6 @@ class Setup { '\Event_Bridge_For_ActivityPub\Integrations\WP_Event_Manager', '\Event_Bridge_For_ActivityPub\Integrations\Eventin', '\Event_Bridge_For_ActivityPub\Integrations\Modern_Events_Calendar_Lite', - '\Event_Bridge_For_ActivityPub\Integrations\EventPrime', '\Event_Bridge_For_ActivityPub\Integrations\Event_Organiser', ); diff --git a/includes/integrations/class-eventprime.php b/includes/integrations/class-eventprime.php deleted file mode 100644 index a50f7ff..0000000 --- a/includes/integrations/class-eventprime.php +++ /dev/null @@ -1,221 +0,0 @@ -post_content && '[em_events]' !== $queried_object->post_content ) { - return false; - } - } - - // Check if header already sent. - if ( ! \headers_sent() && ACTIVITYPUB_SEND_VARY_HEADER ) { - // Send Vary header for Accept header. - \header( 'Vary: Accept' ); - } - - // One can trigger an ActivityPub request by adding ?activitypub to the URL. - if ( isset( $wp_query->query_vars['activitypub'] ) ) { - return true; - } - - /* - * The other (more common) option to make an ActivityPub request - * is to send an Accept header. - */ - if ( isset( $_SERVER['HTTP_ACCEPT'] ) ) { - $accept = sanitize_text_field( wp_unslash( $_SERVER['HTTP_ACCEPT'] ) ); - - /* - * $accept can be a single value, or a comma separated list of values. - * We want to support both scenarios, - * and return true when the header includes at least one of the following: - * - application/activity+json - * - application/ld+json - * - application/json - */ - if ( preg_match( '/(application\/(ld\+json|activity\+json|json))/i', $accept ) ) { - return true; - } - } - - return false; - } - - /** - * Extract the post id of the event for an EventPrime event query. - * - * @return bool|int The post ID if an event could be identified, false otherwise. - */ - private static function get_eventprime_post_id() { - $event = get_query_var( 'event' ); - if ( ! $event ) { - if ( ! empty( filter_input( INPUT_GET, 'event', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ) ) { - $event = rtrim( filter_input( INPUT_GET, 'event', FILTER_SANITIZE_FULL_SPECIAL_CHARS ), '/\\' ); - } - } - - if ( $event ) { - $ep_basic_functions = new Eventprime_Basic_Functions(); - return $ep_basic_functions->ep_get_id_by_slug( $event, 'em_event' ); - } - - return false; - } - - /** - * Add the ActivityPub template for EventPrime. - * - * @param string $template The path to the template object. - * @return string The new path to the JSON template. - */ - public static function render_activitypub_template( $template ) { - if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) { - return $template; - } - - // Check if the request is a page with (solely) the eventprime shortcode in it. - if ( ! self::is_eventprime_activitypub_request() ) { - return $template; - } - - if ( ! \is_singular() ) { - return $template; - } - - $post_id = self::get_eventprime_post_id(); - - if ( $post_id ) { - $preview = \get_query_var( 'preview' ); - if ( $preview ) { - $activitypub_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-preview.php'; - } else { - $activitypub_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php'; - } - } - - /* - * Check if the request is authorized. - * - * @see https://www.w3.org/wiki/SocialCG/ActivityPub/Primer/Authentication_Authorization#Authorized_fetch - * @see https://swicg.github.io/activitypub-http-signature/#authorized-fetch - */ - if ( $activitypub_template && defined( 'ACTIVITYPUB_AUTHORIZED_FETCH' ) && constant( 'ACTIVITYPUB_AUTHORIZED_FETCH' ) ) { - $verification = Signature::verify_http_signature( $_SERVER ); - if ( \is_wp_error( $verification ) ) { - header( 'HTTP/1.1 401 Unauthorized' ); - - // Fallback as template_loader can't return http headers. - return $template; - } - } - - if ( $activitypub_template ) { - global $post; - - $post = get_post( $post_id ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited - - // Ensure WordPress functions use the new post data. - setup_postdata( $post ); - // Return the default ActivityPub template. - return $activitypub_template; - } - - return $template; - } -} diff --git a/readme.txt b/readme.txt index fb93cf9..a2aa34b 100644 --- a/readme.txt +++ b/readme.txt @@ -57,7 +57,6 @@ This plugin depends on the [ActivityPub plugin](https://wordpress.org/plugins/ac * [Eventin](https://de.wordpress.org/plugins/wp-event-solution/) * [Modern Events Calendar Lite](https://webnus.net/modern-events-calendar/) * [GatherPress](https://gatherpress.org/) -* [EventPrime – Events Calendar, Bookings and Tickets](https://wordpress.org/plugins/eventprime-event-calendar-management/) * [Event Organiser](https://wordpress.org/plugins/event-organiser/) == Configuration == diff --git a/tests/test-class-plugin-eventprime.php b/tests/test-class-plugin-eventprime.php deleted file mode 100644 index e8c8ce3..0000000 --- a/tests/test-class-plugin-eventprime.php +++ /dev/null @@ -1,186 +0,0 @@ -activate_activitypub_support_for_active_event_plugins(); - - // Delete all posts afterwards. - _delete_all_posts(); - - $this->setup_mockup_data(); - } - - /** - * Setup mockup events. - */ - private function setup_mockup_data() { - $this->mockup_events = array( - 'minimal_event' => array( - 'name' => 'EventPrime Event title', - 'description' => 'EventPrime event description', - 'status' => 'Publish', - 'em_event_type' => '', - 'em_venue' => '', - 'em_organizer' => '', - 'em_performer' => '', - 'em_start_date' => strtotime( '+10 days 15:00:00' ), - 'em_end_date' => strtotime( '+10 days 16:00:00' ), - 'em_enable_booking' => 'bookings_off', - 'em_ticket_price' => 0, - ), - ); - - $this->mockup_venue = array( - 'name' => 'Test Venue', - 'address' => 'Fediverse-street 1337, 1234 Fediverse-town', - ); - } - - /** - * Test that the right transformer gets applied. - */ - public function test_the_events_calendar_transformer_class() { - // We only test for one event plugin being active at the same time, - // even though we support multiple onces in theory. - // But testing all combinations is beyond scope. - $active_event_plugins = \Event_Bridge_For_ActivityPub\Setup::get_instance()->get_active_event_plugins(); - $this->assertEquals( 1, count( $active_event_plugins ) ); - - // Enable ActivityPub support for the event plugin. - $this->assertContains( 'em_event', get_option( 'activitypub_support_post_types' ) ); - - // Create an EventPrime Event without content. - $ep_functions = new Eventprime_Basic_Functions(); - - $post_id = $ep_functions->insert_event_post_data( $this->mockup_events['minimal_event'] ); - - $wp_object = get_post( $post_id ); - - // Call the transformer Factory. - $transformer = \Activitypub\Transformer\Factory::get_transformer( $wp_object ); - - // Check that we got the right transformer. - $this->assertInstanceOf( \Event_Bridge_For_ActivityPub\Activitypub\Transformer\EventPrime::class, $transformer ); - } - - /** - * Test transformation of minimal event. - */ - public function test_transformation_of_minimal_event() { - // Create an EventPrime Event without content. - $ep_functions = new Eventprime_Basic_Functions(); - - $post_id = $ep_functions->insert_event_post_data( $this->mockup_events['minimal_event'] ); - - $wp_object = get_post( $post_id ); - - // Call the transformer Factory. - $event_array = \Activitypub\Transformer\Factory::get_transformer( $wp_object )->to_object()->to_array(); - - // Check that the event ActivityStreams representation contains everything as expected. - $this->assertEquals( 'Event', $event_array['type'] ); - $this->assertEquals( 'EventPrime Event title', $event_array['name'] ); - $this->assertEquals( 'EventPrime event description', wp_strip_all_tags( $event_array['content'] ) ); - $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 15:00:00' ) ) . 'T15:00:00Z', $event_array['startTime'] ); - $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 16:00:00' ) ) . 'T16:00:00Z', $event_array['endTime'] ); - $this->assertTrue( $event_array['commentsEnabled'] ); - $this->assertEquals( 'allow_all', $event_array['repliesModerationOption'] ); - $this->assertEquals( 'external', $event_array['joinMode'] ); - $this->assertArrayNotHasKey( 'location', $event_array ); - $this->assertEquals( 'MEETING', $event_array['category'] ); - } - - /** - * Test transformation of minimal event. - */ - public function test_transformation_of_minimal_event_with_venue() { - // Create an EventPrime Event without content. - $ep_functions = new Eventprime_Basic_Functions(); - - $venue_term_id = wp_insert_term( $this->mockup_venue['name'], 'em_venue' )['term_id']; - add_term_meta( $venue_term_id, 'em_address', $this->mockup_venue['address'], true ); - add_term_meta( $venue_term_id, 'em_display_address_on_frontend', true, true ); - - $event_data = $this->mockup_events['minimal_event']; - $event_data['em_venue'] = $venue_term_id; - - $post_id = $ep_functions->insert_event_post_data( $event_data ); - - $wp_object = get_post( $post_id ); - - // Call the transformer Factory. - $event_array = \Activitypub\Transformer\Factory::get_transformer( $wp_object )->to_object()->to_array(); - - // Check that the event ActivityStreams representation contains everything as expected. - $this->assertEquals( 'Event', $event_array['type'] ); - $this->assertEquals( 'EventPrime Event title', $event_array['name'] ); - $this->assertEquals( 'EventPrime event description', wp_strip_all_tags( $event_array['content'] ) ); - $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 15:00:00' ) ) . 'T15:00:00Z', $event_array['startTime'] ); - $this->assertEquals( gmdate( 'Y-m-d', strtotime( '+10 days 16:00:00' ) ) . 'T16:00:00Z', $event_array['endTime'] ); - $this->assertTrue( $event_array['commentsEnabled'] ); - $this->assertEquals( 'allow_all', $event_array['repliesModerationOption'] ); - $this->assertEquals( 'external', $event_array['joinMode'] ); - $this->assertEquals( $this->mockup_venue['name'], $event_array['location']['name'] ); - $this->assertEquals( $this->mockup_venue['address'], $event_array['location']['address'] ); - - $this->assertEquals( 'MEETING', $event_array['category'] ); - } - - /** - * Test transformation of minimal event with venue which has a hidden address. - */ - public function test_transformation_of_minimal_event_with_venue_with_hidden_address() { - // Create an EventPrime Event without content. - $ep_functions = new Eventprime_Basic_Functions(); - - $venue_term_id = wp_insert_term( $this->mockup_venue['name'], 'em_venue' )['term_id']; - add_term_meta( $venue_term_id, 'em_address', $this->mockup_venue['address'], true ); - add_term_meta( $venue_term_id, 'em_display_address_on_frontend', false, true ); - - $event_data = $this->mockup_events['minimal_event']; - $event_data['em_venue'] = $venue_term_id; - - $post_id = $ep_functions->insert_event_post_data( $event_data ); - - $wp_object = get_post( $post_id ); - - // Call the transformer Factory. - $event_array = \Activitypub\Transformer\Factory::get_transformer( $wp_object )->to_object()->to_array(); - - // Check that the event ActivityStreams representation contains everything as expected. - $this->assertArrayNotHasKey( 'address', $event_array['location'] ); - } -}