From 8fb92bfc10221afc5b0e0f38bf06ffd03f9fafaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Menrath?= Date: Sun, 13 Oct 2024 09:44:00 +0200 Subject: [PATCH] Add Transformer for Eventin (WP Event Solution) (#62) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://wordpress.org/plugins/wp-event-solution/ Reviewed-on: https://code.event-federation.eu/Event-Federation/wordpress-activitypub-event-bridge/pulls/62 Co-authored-by: André Menrath Co-committed-by: André Menrath --- .forgejo/workflows/phpunit.yml | 7 +- bin/install-wp-tests.sh | 1 + composer.json | 10 +- .../activitypub/transformer/class-eventin.php | 164 ++++++++++++++++ includes/class-setup.php | 1 + includes/plugins/class-eventin.php | 60 ++++++ tests/bootstrap.php | 8 + tests/test-class-plugin-eventin.php | 175 ++++++++++++++++++ 8 files changed, 422 insertions(+), 4 deletions(-) create mode 100644 includes/activitypub/transformer/class-eventin.php create mode 100644 includes/plugins/class-eventin.php create mode 100644 tests/test-class-plugin-eventin.php diff --git a/.forgejo/workflows/phpunit.yml b/.forgejo/workflows/phpunit.yml index b67d8e9..3cb7904 100644 --- a/.forgejo/workflows/phpunit.yml +++ b/.forgejo/workflows/phpunit.yml @@ -37,7 +37,7 @@ jobs: path: | ${{ env.WP_CORE_DIR }} ${{ env.WP_TESTS_DIR }} - key: cache-wordpress-5 + key: cache-wordpress-8 - name: Cache Composer id: cache-composer-phpunit @@ -96,5 +96,10 @@ jobs: - name: Run Integration tests for WP Event Manager run: cd /workspace/Event-Federation/wordpress-activitypub-event-bridge/ && ./vendor/bin/phpunit --filter=wp_event_manager + env: + PHP_VERSION: ${{ matrix.php-version }} + + - name: Run Integration tests for Eventin (WP Event Solution) + run: cd /workspace/Event-Federation/wordpress-activitypub-event-bridge/ && ./vendor/bin/phpunit --filter=eventin env: PHP_VERSION: ${{ matrix.php-version }} \ No newline at end of file diff --git a/bin/install-wp-tests.sh b/bin/install-wp-tests.sh index 0e0e4ad..759ad25 100755 --- a/bin/install-wp-tests.sh +++ b/bin/install-wp-tests.sh @@ -239,6 +239,7 @@ install_wp_plugins() { install_wp_plugin gatherpress install_wp_plugin events-manager install_wp_plugin wp-event-manager + install_wp_plugin wp-event-solution } install_wp diff --git a/composer.json b/composer.json index 1b3bb36..940dff0 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,6 @@ { "name": "menrath/wordpress-activitypub-event-bridge", + "version": "1.0.0", "description": "The ActivityPub Event Bridge help for event custom post types to federate properly.", "type": "wordpress-plugin", "require": { @@ -51,16 +52,19 @@ "@test-the-events-calendar", "@test-gatherpress", "@test-events-manager", - "@test-wp-event-manager" + "@test-wp-event-manager", + "@test-eventin" ], "test-debug": [ "@prepare-test", - "@test-wp-event-manager" + "@test-eventin" ], "test-vs-event-list": "phpunit --filter=vs_event_list", "test-the-events-calendar": "phpunit --filter=the_events_calendar", "test-gatherpress": "phpunit --filter=gatherpress", "test-events-manager": "phpunit --filter=events_manager", - "test-wp-event-manager": "phpunit --filter=wp_event_manager" + "test-wp-event-manager": "phpunit --filter=wp_event_manager", + "test-eventin": "phpunit --filter=eventin", + "test-all": "phpunit" } } diff --git a/includes/activitypub/transformer/class-eventin.php b/includes/activitypub/transformer/class-eventin.php new file mode 100644 index 0000000..b47d93e --- /dev/null +++ b/includes/activitypub/transformer/class-eventin.php @@ -0,0 +1,164 @@ +event_model = new Event_Model( $this->wp_object->ID ); + } + + /** + * Get the end time from the event object. + */ + public function get_start_time(): string { + return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_start_datetime() ) ); + } + + /** + * Get the end time from the event object. + */ + public function get_end_time(): string { + return \gmdate( 'Y-m-d\TH:i:s\Z', strtotime( $this->event_model->get_end_datetime() ) ); + } + + /** + * Get the timezone of the event. + */ + public function get_timezone(): string { + return $this->event_model->get_timezone(); + } + + /** + * Get whether the event is online. + * + * @return bool + */ + public function get_is_online(): bool { + return 'online' === $this->event_model->__get( 'event_type' ) ? true : false; + } + + /** + * Maybe add online link to attachments. + * + * @return array + */ + public function get_attachment(): array { + $attachment = parent::get_attachment(); + + $location = (array) $this->event_model->__get( 'location' ); + if ( array_key_exists( 'integration', $location ) && array_key_exists( $location['integration'], $location ) ) { + $online_link = array( + 'type' => 'Link', + 'mediaType' => 'text/html', + 'name' => $location[ $location['integration'] ], + 'href' => $location[ $location['integration'] ], + ); + $attachment[] = $online_link; + } + return $attachment; + } + + /** + * Compose the events tags. + */ + public function get_tag() { + // The parent tag function also fetches the mentions. + $tags = parent::get_tag(); + + $post_tags = \wp_get_post_terms( $this->wp_object->ID, 'etn_tags' ); + $post_categories = \wp_get_post_terms( $this->wp_object->ID, 'etn_category' ); + + if ( ! is_wp_error( $post_tags ) && $post_tags ) { + foreach ( $post_tags as $term ) { + $tag = array( + 'type' => 'Hashtag', + 'href' => \esc_url( \get_tag_link( $term->term_id ) ), + 'name' => esc_hashtag( $term->name ), + ); + $tags[] = $tag; + } + } + + if ( ! is_wp_error( $post_categories ) && $post_categories ) { + foreach ( $post_categories as $term ) { + $tag = array( + 'type' => 'Hashtag', + 'href' => \esc_url( \get_tag_link( $term->term_id ) ), + 'name' => esc_hashtag( $term->name ), + ); + $tags[] = $tag; + } + } + + if ( empty( $tags ) ) { + return null; + } + + return $tags; + } + + /** + * Get the location. + * + * @return ?Place + */ + public function get_location(): ?Place { + $location = (array) $this->event_model->__get( 'location' ); + + if ( ! array_key_exists( 'address', $location ) ) { + return null; + } + + $place = new Place(); + + $address = $location['address']; + + $place->set_name( $address ); + $place->set_address( $address ); + $place->set_sensitive( null ); + + return $place; + } +} diff --git a/includes/class-setup.php b/includes/class-setup.php index bafe050..e03c7d0 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -129,6 +129,7 @@ class Setup { '\ActivityPub_Event_Bridge\Plugins\The_Events_Calendar', '\ActivityPub_Event_Bridge\Plugins\VS_Event_List', '\ActivityPub_Event_Bridge\Plugins\WP_Event_Manager', + '\ActivityPub_Event_Bridge\Plugins\Eventin', ); /** diff --git a/includes/plugins/class-eventin.php b/includes/plugins/class-eventin.php new file mode 100644 index 0000000..fcab7c8 --- /dev/null +++ b/includes/plugins/class-eventin.php @@ -0,0 +1,60 @@ + 'publish', + 'post_title' => 'Eventin Test Event Title', + 'post_content' => 'Eventin Test Event Description', + 'etn_start_date' => \gmdate( 'Y-m-d', strtotime( '+10 days 15:00:00' ) ), + 'etn_end_date' => \gmdate( 'Y-m-d', strtotime( '+10 days 16:00:00' ) ), + 'etn_start_time' => \gmdate( 'H:i', strtotime( '+10 days 15:00:00' ) ), + 'etn_end_time' => \gmdate( 'H:i', strtotime( '+10 days 16:00:00' ) ), + 'event_timezone' => 'Europe/Vienna', + ); + } + + /** + * Override the setup function, so that tests don't run if the Events Calendar is not active. + */ + public function set_up() { + parent::set_up(); + + if ( ! class_exists( '\Wpeventin' ) ) { + self::markTestSkipped( 'Eventin plugin is not active.' ); + } + + // Make sure that ActivityPub support is enabled for The Events Calendar. + $aec = \ActivityPub_Event_Bridge\Setup::get_instance(); + $aec->activate_activitypub_support_for_active_event_plugins(); + + // Delete all posts afterwards. + _delete_all_posts(); + } + + /** + * Test that the right transformer gets applied. + */ + public function test_eventin_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 = \ActivityPub_Event_Bridge\Setup::get_instance()->get_active_event_plugins(); + $this->assertEquals( 1, count( $active_event_plugins ) ); + + // Enable ActivityPub support for the event plugin. + $this->assertContains( 'etn', get_option( 'activitypub_support_post_types' ) ); + + // Create a Eventin Event without content. + $event = new \Etn\Core\Event\Event_Model(); + $event->create( $this->get_mockup_event() ); + + // Call the transformer Factory. + $transformer = \Activitypub\Transformer\Factory::get_transformer( get_post( $event->id ) ); + + // Check that we got the right transformer. + $this->assertInstanceOf( \ActivityPub_Event_Bridge\Activitypub\Transformer\Eventin::class, $transformer ); + } + + /** + * Test that the right transformer gets applied. + */ + public function test_eventin_test_minimal_event() { + // Create a Eventin Event without content. + $event = new \Etn\Core\Event\Event_Model(); + $event->create( $this->get_mockup_event() ); + + // Call the transformer Factory. + $event_array = \Activitypub\Transformer\Factory::get_transformer( get_post( $event->id ) )->to_object()->to_array(); + + $this->assertEquals( 'Event', $event_array['type'] ); + $this->assertEquals( 'Eventin Test Event Title', $event_array['name'] ); + $this->assertEquals( 'Eventin Test Event Description', wp_strip_all_tags( $event_array['content'] ) ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 15:00:00' ) ), $event_array['startTime'] ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 16:00:00' ) ), $event_array['endTime'] ); + $this->assertEquals( 'Europe/Vienna', $event_array['timezone'] ); + $this->assertEquals( comments_open( $event->id ), $event_array['commentsEnabled'] ); + $this->assertEquals( comments_open( $event->id ) ? 'allow_all' : 'closed', $event_array['repliesModerationOption'] ); + $this->assertEquals( 'external', $event_array['joinMode'] ); + $this->assertArrayNotHasKey( 'location', $event_array ); + $this->assertEquals( 'MEETING', $event_array['category'] ); + $this->assertEquals( false, $event_array['isOnline'] ); + } + + /** + * Test that the right transformer gets applied. + */ + public function test_eventin_test_online_event_with_custom_link() { + // Create a Eventin Event without content. + $event = new \Etn\Core\Event\Event_Model(); + $args = array_merge( + $this->get_mockup_event(), + array( + 'event_type' => 'online', + 'location' => array( + 'integration' => 'custom_url', + 'custom_url' => 'https://jit.si/eventmeeting', + ), + ) + ); + $event->create( $args ); + + // Call the transformer Factory. + $event_array = \Activitypub\Transformer\Factory::get_transformer( get_post( $event->id ) )->to_object()->to_array(); + + $this->assertEquals( 'Event', $event_array['type'] ); + $this->assertEquals( 'Eventin Test Event Title', $event_array['name'] ); + $this->assertEquals( 'Eventin Test Event Description', wp_strip_all_tags( $event_array['content'] ) ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 15:00:00' ) ), $event_array['startTime'] ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 16:00:00' ) ), $event_array['endTime'] ); + $this->assertEquals( 'Europe/Vienna', $event_array['timezone'] ); + $this->assertEquals( comments_open( $event->id ), $event_array['commentsEnabled'] ); + $this->assertEquals( comments_open( $event->id ) ? 'allow_all' : 'closed', $event_array['repliesModerationOption'] ); + $this->assertEquals( 'external', $event_array['joinMode'] ); + $this->assertArrayNotHasKey( 'location', $event_array ); + $this->assertEquals( 'MEETING', $event_array['category'] ); + $this->assertEquals( true, $event_array['isOnline'] ); + $this->assertContains( + array( + 'type' => 'Link', + 'mediaType' => 'text/html', + 'name' => 'https://jit.si/eventmeeting', + 'href' => 'https://jit.si/eventmeeting', + ), + $event_array['attachment'] + ); + } + + + /** + * Test that the right transformer gets applied. + */ + public function test_eventin_test_online_event_with_physical_location() { + // Create a Eventin Event without content. + $event = new \Etn\Core\Event\Event_Model(); + $args = array_merge( + $this->get_mockup_event(), + array( + 'event_type' => 'offline', + 'location' => array( + 'address' => 'The NlNet center', + ), + ) + ); + $event->create( $args ); + + // Call the transformer Factory. + $event_array = \Activitypub\Transformer\Factory::get_transformer( get_post( $event->id ) )->to_object()->to_array(); + + $this->assertEquals( 'Event', $event_array['type'] ); + $this->assertEquals( 'Eventin Test Event Title', $event_array['name'] ); + $this->assertEquals( 'Eventin Test Event Description', wp_strip_all_tags( $event_array['content'] ) ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 15:00:00' ) ), $event_array['startTime'] ); + $this->assertEquals( gmdate( 'Y-m-d\TH:i:s\Z', strtotime( '+10 days 16:00:00' ) ), $event_array['endTime'] ); + $this->assertEquals( 'Europe/Vienna', $event_array['timezone'] ); + $this->assertEquals( comments_open( $event->id ), $event_array['commentsEnabled'] ); + $this->assertEquals( comments_open( $event->id ) ? 'allow_all' : 'closed', $event_array['repliesModerationOption'] ); + $this->assertEquals( 'external', $event_array['joinMode'] ); + $this->assertArrayHasKey( 'location', $event_array ); + $this->assertEquals( 'MEETING', $event_array['category'] ); + $this->assertEquals( false, $event_array['isOnline'] ); + $this->assertEquals( 'The NlNet center', $event_array['location']['address'] ); + $this->assertEquals( 'The NlNet center', $event_array['location']['name'] ); + } +}