From dea5f385613b67fa03498699785806c62c854320 Mon Sep 17 00:00:00 2001 From: Matthias Pfefferle Date: Tue, 2 May 2023 14:39:25 +0200 Subject: [PATCH] better error handling --- includes/collection/class-followers.php | 69 +++++++++++++++++++------ includes/functions.php | 21 ++++++++ includes/model/class-follower.php | 62 +++++++++++++++++++++- includes/table/class-followers.php | 22 ++++---- 4 files changed, 146 insertions(+), 28 deletions(-) diff --git a/includes/collection/class-followers.php b/includes/collection/class-followers.php index 0bd8d03..e21ce2d 100644 --- a/includes/collection/class-followers.php +++ b/includes/collection/class-followers.php @@ -9,8 +9,7 @@ use Activitypub\Webfinger; use Activitypub\Model\Activity; use Activitypub\Model\Follower; -use function Activitypub\safe_remote_get; -use function Activitypub\safe_remote_post; +use function Activitypub\is_tombstone; use function Activitypub\get_remote_metadata_by_actor; /** @@ -152,6 +151,22 @@ class Followers { ) ); + register_term_meta( + self::TAXONOMY, + 'errors', + array( + 'type' => 'string', + 'single' => false, + 'sanitize_callback' => function( $value ) { + if ( ! is_string( $value ) ) { + throw new Exception( 'Error message is no valid string' ); + } + + return esc_sql( $value ); + }, + ) + ); + do_action( 'activitypub_after_register_taxonomy' ); } @@ -197,12 +212,16 @@ class Followers { public static function add_follower( $user_id, $actor ) { $meta = get_remote_metadata_by_actor( $actor ); - if ( ! $meta || is_wp_error( $meta ) || ! is_array( $meta ) ) { - return $meta; + $follower = new Follower( $actor ); + + if ( is_tombstone( $meta ) ) { + return; + } if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) { + $follower->set_error( $meta ); + } else { + $follower->from_meta( $meta ); } - $follower = new Follower( $actor ); - $follower->from_meta( $meta ); $follower->upsert(); $result = wp_set_object_terms( $user_id, $follower->get_actor(), self::TAXONOMY, true ); @@ -299,19 +318,29 @@ class Followers { * * @return array The Term list of Followers, the format depends on $output */ - public static function get_followers( $user_id, $output = ARRAY_N, $number = null, $offset = null ) { - $terms = new WP_Term_Query( - array( - 'taxonomy' => self::TAXONOMY, - 'hide_empty' => false, - 'object_ids' => $user_id, - 'number' => $number, - 'offset' => $offset, - 'orderby' => 'id', - 'order' => 'ASC', - ) + public static function get_followers( $user_id, $output = ARRAY_N, $number = null, $offset = null, $hide_errors = false, $args = array() ) { + $defaults = array( + 'taxonomy' => self::TAXONOMY, + 'hide_empty' => false, + 'object_ids' => $user_id, + 'number' => $number, + 'offset' => $offset, + 'orderby' => 'id', + 'order' => 'ASC', ); + if ( true === $hide_errors ) { + $defaults['meta_query'] = array( + array( + 'key' => 'errors', + 'compare' => 'NOT EXISTS', + ), + ); + } + + $args = wp_parse_args( $args, $defaults ); + $terms = new WP_Term_Query( $args ); + $items = array(); // change output format @@ -358,6 +387,12 @@ class Followers { 'hide_empty' => false, 'object_ids' => $user_id, 'fields' => 'ids', + 'meta_query' => array( + array( + 'key' => 'inbox', + 'compare' => 'EXISTS', + ), + ), ) ); diff --git a/includes/functions.php b/includes/functions.php index b88f8a8..5fa7ab3 100644 --- a/includes/functions.php +++ b/includes/functions.php @@ -211,3 +211,24 @@ function get_author_description( $user_id ) { } return $description; } + +/** + * Check for Tombstone Objects + * + * @see https://www.w3.org/TR/activitypub/#delete-activity-outbox + * + * @param WP_Error $wp_error A WP_Error-Response of an HTTP-Request + * + * @return boolean true if HTTP-Code is 410 or 404 + */ +function is_tombstone( $wp_error ) { + if ( ! is_wp_error( $wp_error ) ) { + return false; + } + + if ( in_array( (int) $wp_error->get_error_code(), array( 404, 410 ), true ) ) { + return true; + } + + return false; +} diff --git a/includes/model/class-follower.php b/includes/model/class-follower.php index d4fc70f..694489d 100644 --- a/includes/model/class-follower.php +++ b/includes/model/class-follower.php @@ -92,6 +92,22 @@ class Follower { */ private $meta; + /** + * The latest received error. + * + * This will only temporary and will saved to $this->errors + * + * @var string + */ + private $error; + + /** + * A list of errors + * + * @var array + */ + private $errors; + /** * Maps the meta fields to the local db fields * @@ -185,10 +201,39 @@ class Follower { return null; } + public function get_errors() { + if ( $this->errors ) { + return $this->errors; + } + + $this->errors = get_term_meta( $this->id, 'errors' ); + return $this->errors; + } + + public function count_errors() { + $errors = $this->get_errors(); + + if ( is_array( $errors ) && ! empty( $errors ) ) { + return count( $errors ); + } + + return 0; + } + + public function get_latest_error_message() { + $errors = $this->get_errors(); + + if ( is_array( $errors ) && ! empty( $errors ) ) { + return reset( $errors ); + } + + return ''; + } + public function get_meta_by( $attribute ) { $meta = $this->get_meta(); - // try mapped data ($this->map_meta) + // try mapped data (see $this->map_meta) foreach ( $this->map_meta as $remote => $local ) { if ( $attribute === $local && isset( $meta[ $remote ] ) ) { return $meta[ $remote ]; @@ -251,8 +296,21 @@ class Follower { foreach ( $attributes as $attribute ) { if ( $this->get( $attribute ) ) { - update_term_meta( $this->id, $attribute, $this->get( $attribute ), true ); + update_term_meta( $this->id, $attribute, $this->get( $attribute ) ); } } + + if ( $this->error ) { + if ( is_string( $this->error ) ) { + $error = $this->error; + } elseif ( is_wp_error( $this->error ) ) { + $error = $this->error->get_error_message(); + } else { + $error = __( 'Unknown Error or misconfigured Error-Message', 'activitypub' ); + } + + add_term_meta( $this->id, 'errors', $error ); + } + } } diff --git a/includes/table/class-followers.php b/includes/table/class-followers.php index c39b45f..c9b5948 100644 --- a/includes/table/class-followers.php +++ b/includes/table/class-followers.php @@ -11,11 +11,13 @@ if ( ! \class_exists( '\WP_List_Table' ) ) { class Followers extends WP_List_Table { public function get_columns() { return array( - 'cb' => '', - 'avatar' => \__( 'Avatar', 'activitypub' ), - 'name' => \__( 'Name', 'activitypub' ), - 'username' => \__( 'Username', 'activitypub' ), - 'identifier' => \__( 'Identifier', 'activitypub' ), + 'cb' => '', + 'avatar' => \__( 'Avatar', 'activitypub' ), + 'name' => \__( 'Name', 'activitypub' ), + 'username' => \__( 'Username', 'activitypub' ), + 'identifier' => \__( 'Identifier', 'activitypub' ), + 'errors' => \__( 'Errors', 'activitypub' ), + 'latest-error' => \__( 'Latest Error Message', 'activitypub' ), ); } @@ -47,10 +49,12 @@ class Followers extends WP_List_Table { foreach ( $follower as $follower ) { $item = array( - 'avatar' => esc_attr( $follower->get_avatar() ), - 'name' => esc_attr( $follower->get_name() ), - 'username' => esc_attr( $follower->get_username() ), - 'identifier' => esc_attr( $follower->get_actor() ), + 'avatar' => esc_attr( $follower->get_avatar() ), + 'name' => esc_attr( $follower->get_name() ), + 'username' => esc_attr( $follower->get_username() ), + 'identifier' => esc_attr( $follower->get_actor() ), + 'errors' => $follower->count_errors(), + 'latest-error' => $follower->get_latest_error_message(), ); $this->items[] = $item;