diff --git a/includes/activitypub/collection/class-event-sources.php b/includes/activitypub/collection/class-event-sources.php index b641f53..feea7fb 100644 --- a/includes/activitypub/collection/class-event-sources.php +++ b/includes/activitypub/collection/class-event-sources.php @@ -34,6 +34,8 @@ class Event_Sources { \add_action( 'event_bridge_for_activitypub_unfollow', array( self::class, 'activitypub_unfollow_actor' ), 10, 2 ); } + + /** * Register the post type used to store the external event sources (i.e., followed ActivityPub actors). */ diff --git a/includes/activitypub/handler/class-create.php b/includes/activitypub/handler/class-create.php index d980551..0366259 100644 --- a/includes/activitypub/handler/class-create.php +++ b/includes/activitypub/handler/class-create.php @@ -41,7 +41,7 @@ class Create { * @param int $user_id The id of the local blog-user. */ public static function handle_create( $activity, $user_id ) { - // We only process activities that are target the application user. + // We only process activities that are target to the application user. if ( Actors::APPLICATION_USER_ID !== $user_id ) { return; } @@ -80,6 +80,8 @@ class Create { if ( isset( $json_params['object']['type'] ) && 'Event' === $json_params['object']['type'] ) { $valid = true; + } else { + return $valid; } if ( empty( $json_params['type'] ) ) { @@ -87,7 +89,7 @@ class Create { } if ( - 'Create' !== $json_params['type'] || + 'Create' !== $json_params['type'] || 'Update' !== $json_params['type'] || is_wp_error( $request ) ) { return $valid; @@ -103,10 +105,22 @@ class Create { 'id', ); + // Limit this as a safety measure. + add_filter( 'wp_revisions_to_keep', array( 'revisions_to_keep' ) ); + if ( array_intersect( $required, array_keys( $object ) ) !== $required ) { return false; } return $valid; } + + /** + * Return the number of revisions to keep. + * + * @return int The number of revisions to keep. + */ + public static function revisions_to_keep() { + return 3; + } } diff --git a/includes/activitypub/handler/class-update.php b/includes/activitypub/handler/class-update.php index 12e3c96..a4de6eb 100644 --- a/includes/activitypub/handler/class-update.php +++ b/includes/activitypub/handler/class-update.php @@ -10,6 +10,9 @@ namespace Event_Bridge_For_ActivityPub\ActivityPub\Handler; use Activitypub\Notification; use Activitypub\Collection\Actors; use Activitypub\Http; +use Event_Bridge_For_ActivityPub\Setup; + +use function Activitypub\is_activity_public; /** * Handle Update requests. @@ -21,30 +24,41 @@ class Update { public static function init() { \add_action( 'activitypub_inbox_update', - array( self::class, 'handle_update' ) + array( self::class, 'handle_update' ), + 15, + 2 ); } /** * Handle "Follow" requests. * - * @param array $activity The activity object. + * @param array $activity The activity-object. + * @param int $user_id The id of the local blog-user. */ - public static function handle_update( $activity ) { - if ( ! isset( $activity['object'] ) ) { + public static function handle_update( $activity, $user_id ) { + // We only process activities that are target the application user. + if ( Actors::APPLICATION_USER_ID !== $user_id ) { return; } - $object = Actors::get_by_resource( $activity['object'] ); - - if ( ! $object || is_wp_error( $object ) ) { - // If we can not find a actor, we handle the `Update` activity. + // Check if Activity is public or not. + if ( ! is_activity_public( $activity ) ) { return; } - // We only expect `Update` activities being answers to follow requests by the application actor. - if ( Actors::APPLICATION_USER_ID !== $object->get__id() ) { + // Check if an object is set. + if ( ! isset( $activity['object']['type'] ) || 'Event' !== $activity['object']['type'] ) { return; } + + $transmogrifier_class = Setup::get_transmogrifier(); + + if ( ! $transmogrifier_class ) { + return; + } + + $transmogrifier = new $transmogrifier_class( $activity['object'] ); + $transmogrifier->update(); } } diff --git a/includes/activitypub/transmogrifier/class-gatherpress.php b/includes/activitypub/transmogrifier/class-gatherpress.php index 06c196d..1255acd 100644 --- a/includes/activitypub/transmogrifier/class-gatherpress.php +++ b/includes/activitypub/transmogrifier/class-gatherpress.php @@ -52,6 +52,15 @@ class GatherPress { $this->activitypub_event = $activitypub_event; } + /** + * Get post. + */ + private function get_post_id_from_activitypub_id() { + global $wpdb; + $id = $this->activitypub_event->get_id(); + return $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid=%s AND post_type=%s", $id, 'gatherpress_event' ) ); + } + /** * Save the ActivityPub event object as GatherPress Event. */ @@ -64,6 +73,39 @@ class GatherPress { 'post_content' => $this->activitypub_event->get_content(), 'post_excerpt' => $this->activitypub_event->get_summary(), 'post_status' => 'publish', + 'guid' => $this->activitypub_event->get_id(), + ) + ); + + if ( ! $post_id || is_wp_error( $post_id ) ) { + return; + } + + $event = new \GatherPress\Core\Event( $post_id ); + $params = array( + 'datetime_start' => $this->activitypub_event->get_start_time(), + 'datetime_end' => $this->activitypub_event->get_end_time(), + 'timezone' => $this->activitypub_event->get_timezone(), + ); + $event->save_datetimes( $params ); + } + + /** + * Save the ActivityPub event object as GatherPress Event. + */ + public function update() { + $post_id = $this->get_post_id_from_activitypub_id(); + + // Insert new GatherPress Event post. + $post_id = wp_update_post( + array( + 'ID' => $post_id, + 'post_title' => $this->activitypub_event->get_name(), + 'post_type' => 'gatherpress_event', + 'post_content' => $this->activitypub_event->get_content(), + 'post_excerpt' => $this->activitypub_event->get_summary(), + 'post_status' => 'publish', + 'guid' => $this->activitypub_event->get_id(), ) ); diff --git a/includes/admin/class-user-interface.php b/includes/admin/class-user-interface.php new file mode 100644 index 0000000..b6a9c3e --- /dev/null +++ b/includes/admin/class-user-interface.php @@ -0,0 +1,111 @@ +%s', + \esc_url( $post->guid ), + \esc_html__( 'Open original page', 'event-bridge-for-activitypub' ) + ); + + return $actions; + } + + /** + * Check if a post is both an event post and external (from ActivityPub federation). + * + * @param WP_Post $post The post. + * @return bool + */ + private static function post_is_external_event_post( $post ) { + if ( 'gatherpress_event' !== $post->post_type ) { + return false; + } + return str_starts_with( $post->guid, 'https://ga.lan' ) ? true : false; + } + + /** + * Modify the user capabilities so that nobody can edit external events. + * + * @param array $caps Concerned user's capabilities. + * @param array $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 && self::post_is_external_event_post( $post ) ) { + // Deny editing by returning 'do_not_allow'. + return array( 'do_not_allow' ); + } + } + return $caps; + } +} \ No newline at end of file diff --git a/includes/class-setup.php b/includes/class-setup.php index b0fd90c..b204bd6 100644 --- a/includes/class-setup.php +++ b/includes/class-setup.php @@ -21,6 +21,7 @@ use Event_Bridge_For_ActivityPub\Admin\Event_Plugin_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\General_Admin_Notices; use Event_Bridge_For_ActivityPub\Admin\Health_Check; use Event_Bridge_For_ActivityPub\Admin\Settings_Page; +use Event_Bridge_For_ActivityPub\Admin\User_Interface; use Event_Bridge_For_ActivityPub\Integrations\Event_Plugin; require_once ABSPATH . 'wp-admin/includes/plugin.php'; @@ -212,7 +213,8 @@ class Setup { if ( get_option( 'event_bridge_for_activitypub_event_sources_active' ) ) { add_action( 'init', array( Event_Sources_Collection::class, 'init' ) ); - add_action( 'init', array( Handler::class, 'register_handlers' ) ); + add_action( 'activitypub_register_handlers', array( Handler::class, 'register_handlers' ) ); + add_action( 'admin_init', array( User_Interface::class, 'init' ) ); } add_filter( 'activitypub_transformer', array( $this, 'register_activitypub_event_transformer' ), 10, 3 );