| @@ -17,11 +17,8 @@ | ||
| 17 | 17 | use Activitypub\Collection\Remote_Posts; |
| 18 | 18 | use Activitypub\OAuth\Client; |
| 19 | 19 | use Activitypub\OAuth\Scope; |
| 20 | 20 | use Activitypub\OAuth\Token; |
| 21 | -use Activitypub\Rest\Reader_Terms_Controller; | |
| 22 | -use Activitypub\Rest\Remote_Actors_Controller; | |
| 23 | -use Activitypub\Rest\Remote_Posts_Controller; | |
| 24 | 21 | |
| 25 | 22 | /** |
| 26 | 23 | * Post Types class. |
| 27 | 24 | */ |
| @@ -44,11 +41,9 @@ | ||
| 44 | 41 | \add_action( 'rest_api_init', array( self::class, 'register_ap_post_rest_params' ) ); |
| 45 | 42 | |
| 46 | 43 | \add_filter( 'rest_ap_post_query', array( self::class, 'filter_ap_post_by_user' ), 10, 2 ); |
| 47 | 44 | \add_filter( 'rest_ap_object_type_query', array( self::class, 'filter_object_type_by_user' ), 10, 2 ); |
| 48 | - \add_filter( 'rest_ap_tag_query', array( self::class, 'filter_tag_by_user' ), 10, 2 ); | |
| 49 | 45 | \add_filter( 'rest_ap_object_type_collection_params', array( self::class, 'register_object_type_user_param' ) ); |
| 50 | - \add_filter( 'rest_ap_tag_collection_params', array( self::class, 'register_object_type_user_param' ) ); | |
| 51 | 46 | |
| 52 | 47 | \add_filter( 'activitypub_get_actor_extra_fields', array( Extra_Fields::class, 'default_actor_extra_fields' ), 10, 2 ); |
| 53 | 48 | |
| 54 | 49 | \add_filter( 'add_post_metadata', array( self::class, 'prevent_empty_post_meta' ), 10, 4 ); |
| @@ -66,24 +61,20 @@ | ||
| 66 | 61 | public static function register_remote_actors_post_type() { |
| 67 | 62 | \register_post_type( |
| 68 | 63 | Remote_Actors::POST_TYPE, |
| 69 | 64 | array( |
| 70 | - 'labels' => array( | |
| 65 | + 'labels' => array( | |
| 71 | 66 | 'name' => \_x( 'Followers', 'post_type plural name', 'activitypub' ), |
| 72 | 67 | 'singular_name' => \_x( 'Follower', 'post_type single name', 'activitypub' ), |
| 73 | 68 | ), |
| 74 | - 'public' => false, | |
| 75 | - 'capabilities' => array( | |
| 76 | - 'create_posts' => false, | |
| 77 | - ), | |
| 78 | - 'show_in_rest' => true, | |
| 79 | - 'rest_controller_class' => Remote_Actors_Controller::class, | |
| 80 | - 'hierarchical' => false, | |
| 81 | - 'rewrite' => false, | |
| 82 | - 'query_var' => false, | |
| 83 | - 'delete_with_user' => false, | |
| 84 | - 'can_export' => true, | |
| 85 | - 'supports' => array( 'custom-fields' ), | |
| 69 | + 'public' => false, | |
| 70 | + 'show_in_rest' => true, | |
| 71 | + 'hierarchical' => false, | |
| 72 | + 'rewrite' => false, | |
| 73 | + 'query_var' => false, | |
| 74 | + 'delete_with_user' => false, | |
| 75 | + 'can_export' => true, | |
| 76 | + 'supports' => array( 'custom-fields' ), | |
| 86 | 77 | ) |
| 87 | 78 | ); |
| 88 | 79 | |
| 89 | 80 | // Register meta for Remote Actors post type. |
| @@ -112,8 +103,9 @@ | ||
| 112 | 103 | Followers::FOLLOWER_META_KEY, |
| 113 | 104 | array( |
| 114 | 105 | 'type' => 'string', |
| 115 | 106 | 'single' => false, |
| 107 | + 'show_in_rest' => true, | |
| 116 | 108 | 'sanitize_callback' => 'sanitize_text_field', |
| 117 | 109 | ) |
| 118 | 110 | ); |
| 119 | 111 | } |
| @@ -359,26 +351,25 @@ | ||
| 359 | 351 | public static function register_post_post_type() { |
| 360 | 352 | \register_post_type( |
| 361 | 353 | Remote_Posts::POST_TYPE, |
| 362 | 354 | array( |
| 363 | - 'labels' => array( | |
| 355 | + 'labels' => array( | |
| 364 | 356 | 'name' => \_x( 'Posts', 'post_type plural name', 'activitypub' ), |
| 365 | 357 | 'singular_name' => \_x( 'Post', 'post_type single name', 'activitypub' ), |
| 366 | 358 | ), |
| 367 | - 'map_meta_cap' => true, | |
| 368 | - 'public' => false, | |
| 369 | - 'capabilities' => array( | |
| 370 | - 'create_posts' => false, | |
| 359 | + 'capabilities' => array( | |
| 360 | + 'activitypub' => true, | |
| 371 | 361 | ), |
| 372 | - 'show_in_rest' => true, | |
| 373 | - 'rest_controller_class' => Remote_Posts_Controller::class, | |
| 374 | - 'rewrite' => false, | |
| 375 | - 'query_var' => false, | |
| 376 | - 'supports' => array( 'title', 'editor', 'author', 'custom-fields', 'excerpt', 'comments' ), | |
| 377 | - 'delete_with_user' => true, | |
| 378 | - 'can_export' => true, | |
| 379 | - 'exclude_from_search' => true, | |
| 380 | - 'taxonomies' => array( 'ap_tag', 'ap_object_type' ), | |
| 362 | + 'map_meta_cap' => true, | |
| 363 | + 'public' => false, | |
| 364 | + 'show_in_rest' => true, | |
| 365 | + 'rewrite' => false, | |
| 366 | + 'query_var' => false, | |
| 367 | + 'supports' => array( 'title', 'editor', 'author', 'custom-fields', 'excerpt', 'comments' ), | |
| 368 | + 'delete_with_user' => true, | |
| 369 | + 'can_export' => true, | |
| 370 | + 'exclude_from_search' => true, | |
| 371 | + 'taxonomies' => array( 'ap_tag', 'ap_object_type' ), | |
| 381 | 372 | ) |
| 382 | 373 | ); |
| 383 | 374 | |
| 384 | 375 | \register_taxonomy( |
| @@ -384,12 +375,11 @@ | ||
| 384 | 375 | \register_taxonomy( |
| 385 | 376 | 'ap_tag', |
| 386 | 377 | array( Remote_Posts::POST_TYPE ), |
| 387 | 378 | array( |
| 388 | - 'public' => false, | |
| 389 | - 'query_var' => true, | |
| 390 | - 'show_in_rest' => true, | |
| 391 | - 'rest_controller_class' => Reader_Terms_Controller::class, | |
| 379 | + 'public' => false, | |
| 380 | + 'query_var' => true, | |
| 381 | + 'show_in_rest' => true, | |
| 392 | 382 | ) |
| 393 | 383 | ); |
| 394 | 384 | |
| 395 | 385 | \register_taxonomy( |
| @@ -395,12 +385,11 @@ | ||
| 395 | 385 | \register_taxonomy( |
| 396 | 386 | 'ap_object_type', |
| 397 | 387 | array( Remote_Posts::POST_TYPE ), |
| 398 | 388 | array( |
| 399 | - 'public' => false, | |
| 400 | - 'query_var' => true, | |
| 401 | - 'show_in_rest' => true, | |
| 402 | - 'rest_controller_class' => Reader_Terms_Controller::class, | |
| 389 | + 'public' => false, | |
| 390 | + 'query_var' => true, | |
| 391 | + 'show_in_rest' => true, | |
| 403 | 392 | ) |
| 404 | 393 | ); |
| 405 | 394 | |
| 406 | 395 | \register_post_meta( |
| @@ -803,29 +792,20 @@ | ||
| 803 | 792 | * @param \WP_REST_Request $request The REST API request. |
| 804 | 793 | * @return array Modified query arguments. |
| 805 | 794 | */ |
| 806 | 795 | public static function filter_ap_actor_query_by_follower( $args, $request ) { |
| 807 | - $follower_of = isset( $request['follower_of'] ) ? (int) $request['follower_of'] : null; | |
| 796 | + if ( ! empty( $request['follower_of'] ) ) { | |
| 797 | + // Add meta_query to filter by _activitypub_following. | |
| 798 | + if ( ! isset( $args['meta_query'] ) ) { | |
| 799 | + $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query | |
| 800 | + } | |
| 808 | 801 | |
| 809 | - // Users who cannot list users may only ever see their own followers. | |
| 810 | - if ( ! \current_user_can( 'list_users' ) ) { | |
| 811 | - $follower_of = \get_current_user_id(); | |
| 802 | + $args['meta_query'][] = array( | |
| 803 | + 'key' => Followers::FOLLOWER_META_KEY, | |
| 804 | + 'value' => $request['follower_of'], | |
| 805 | + ); | |
| 812 | 806 | } |
| 813 | 807 | |
| 814 | - if ( null === $follower_of ) { | |
| 815 | - return $args; | |
| 816 | - } | |
| 817 | - | |
| 818 | - // Add meta_query to filter by _activitypub_following. | |
| 819 | - if ( ! isset( $args['meta_query'] ) ) { | |
| 820 | - $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query | |
| 821 | - } | |
| 822 | - | |
| 823 | - $args['meta_query'][] = array( | |
| 824 | - 'key' => Followers::FOLLOWER_META_KEY, | |
| 825 | - 'value' => $follower_of, | |
| 826 | - ); | |
| 827 | - | |
| 828 | 808 | return $args; |
| 829 | 809 | } |
| 830 | 810 | |
| 831 | 811 | /** |
| @@ -912,25 +892,8 @@ | ||
| 912 | 892 | * |
| 913 | 893 | * @return array Modified query arguments. |
| 914 | 894 | */ |
| 915 | 895 | public static function filter_ap_post_by_user( $args, $request ) { |
| 916 | - /* | |
| 917 | - * Scope to one actor's feed. `scope_user_id()` pins the value to the current user unless | |
| 918 | - * the caller can `list_users`, so only a privileged caller can ask for another actor or | |
| 919 | - * for 0, the site/blog actor. This runs for every request, whatever else is being | |
| 920 | - * filtered on, or a tag or object type filter would match the whole cache. | |
| 921 | - */ | |
| 922 | - if ( ! isset( $args['meta_query'] ) ) { | |
| 923 | - $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query | |
| 924 | - } | |
| 925 | - | |
| 926 | - $args['meta_query'][] = array( | |
| 927 | - 'key' => '_activitypub_user_id', | |
| 928 | - 'value' => self::scope_user_id( isset( $request['user_id'] ) ? $request['user_id'] : null ), | |
| 929 | - 'compare' => '=', | |
| 930 | - ); | |
| 931 | - | |
| 932 | - // Filter by tag if provided. | |
| 933 | 896 | $ap_tag = $request->get_param( 'ap_tag' ); |
| 934 | 897 | if ( ! empty( $ap_tag ) ) { |
| 935 | 898 | if ( ! isset( $args['tax_query'] ) ) { |
| 936 | 899 | $args['tax_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query |
| @@ -940,10 +903,25 @@ | ||
| 940 | 903 | 'taxonomy' => 'ap_tag', |
| 941 | 904 | 'field' => 'term_id', |
| 942 | 905 | 'terms' => $ap_tag, |
| 943 | 906 | ); |
| 907 | + | |
| 908 | + return $args; | |
| 944 | 909 | } |
| 945 | 910 | |
| 911 | + // Filter by user_id (defaults to current user, use 0 for site/blog actor). | |
| 912 | + $user_id = isset( $request['user_id'] ) ? (int) $request['user_id'] : \get_current_user_id(); | |
| 913 | + | |
| 914 | + if ( ! isset( $args['meta_query'] ) ) { | |
| 915 | + $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query | |
| 916 | + } | |
| 917 | + | |
| 918 | + $args['meta_query'][] = array( | |
| 919 | + 'key' => '_activitypub_user_id', | |
| 920 | + 'value' => $user_id, | |
| 921 | + 'compare' => '=', | |
| 922 | + ); | |
| 923 | + | |
| 946 | 924 | // Filter by object type if provided. |
| 947 | 925 | if ( ! empty( $request['ap_object_type'] ) ) { |
| 948 | 926 | if ( ! isset( $args['tax_query'] ) ) { |
| 949 | 927 | $args['tax_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query |
| @@ -959,35 +937,8 @@ | ||
| 959 | 937 | return $args; |
| 960 | 938 | } |
| 961 | 939 | |
| 962 | 940 | /** |
| 963 | - * Clamp a requested user ID to a feed the current user is allowed to read. | |
| 964 | - * | |
| 965 | - * Users who can list users may read any actor's reader data, everybody else is | |
| 966 | - * limited to their own. | |
| 967 | - * | |
| 968 | - * @since 9.3.0 | |
| 969 | - * | |
| 970 | - * @param int|null $requested_user_id The requested user ID, or null when none was given. | |
| 971 | - * @return int The user ID to scope the query to. | |
| 972 | - */ | |
| 973 | - private static function scope_user_id( $requested_user_id ) { | |
| 974 | - $current_user_id = \get_current_user_id(); | |
| 975 | - | |
| 976 | - if ( null === $requested_user_id ) { | |
| 977 | - return $current_user_id; | |
| 978 | - } | |
| 979 | - | |
| 980 | - $requested_user_id = (int) $requested_user_id; | |
| 981 | - | |
| 982 | - if ( $requested_user_id !== $current_user_id && ! \current_user_can( 'list_users' ) ) { | |
| 983 | - return $current_user_id; | |
| 984 | - } | |
| 985 | - | |
| 986 | - return $requested_user_id; | |
| 987 | - } | |
| 988 | - | |
| 989 | - /** | |
| 990 | 941 | * Register user_id parameter for ap_object_type taxonomy REST API. |
| 991 | 942 | * |
| 992 | 943 | * @param array $params Existing collection parameters. |
| 993 | 944 | * |
| @@ -1013,40 +964,9 @@ | ||
| 1013 | 964 | * |
| 1014 | 965 | * @return array Modified query arguments. |
| 1015 | 966 | */ |
| 1016 | 967 | public static function filter_object_type_by_user( $args, $request ) { |
| 1017 | - return self::filter_terms_by_user( $args, $request, 'ap_object_type' ); | |
| 1018 | - } | |
| 1019 | - | |
| 1020 | - /** | |
| 1021 | - * Filter the ap_tag REST query to terms that have posts for the given user. | |
| 1022 | - * | |
| 1023 | - * @param array $args Query arguments. | |
| 1024 | - * @param \WP_REST_Request $request The REST API request. | |
| 1025 | - * | |
| 1026 | - * @return array Modified query arguments. | |
| 1027 | - */ | |
| 1028 | - public static function filter_tag_by_user( $args, $request ) { | |
| 1029 | - return self::filter_terms_by_user( $args, $request, 'ap_tag' ); | |
| 1030 | - } | |
| 1031 | - | |
| 1032 | - /** | |
| 1033 | - * Filter a reader taxonomy REST query to terms that have posts for the given user. | |
| 1034 | - * | |
| 1035 | - * @param array $args Query arguments. | |
| 1036 | - * @param \WP_REST_Request $request The REST API request. | |
| 1037 | - * @param string $taxonomy The taxonomy to scope. | |
| 1038 | - * | |
| 1039 | - * @return array Modified query arguments. | |
| 1040 | - */ | |
| 1041 | - private static function filter_terms_by_user( $args, $request, $taxonomy ) { | |
| 1042 | 968 | $user_id = $request->get_param( 'user_id' ); |
| 1043 | - | |
| 1044 | - // Users who cannot list users may only ever see terms from their own feed. | |
| 1045 | - if ( ! \current_user_can( 'list_users' ) ) { | |
| 1046 | - $user_id = \get_current_user_id(); | |
| 1047 | - } | |
| 1048 | - | |
| 1049 | 969 | if ( null === $user_id ) { |
| 1050 | 970 | return $args; |
| 1051 | 971 | } |
| 1052 | 972 | |
| @@ -1059,25 +979,19 @@ | ||
| 1059 | 979 | FROM {$wpdb->term_taxonomy} tt |
| 1060 | 980 | INNER JOIN {$wpdb->term_relationships} tr ON tt.term_taxonomy_id = tr.term_taxonomy_id |
| 1061 | 981 | INNER JOIN {$wpdb->posts} p ON tr.object_id = p.ID |
| 1062 | 982 | INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id |
| 1063 | - WHERE tt.taxonomy = %s | |
| 1064 | - AND p.post_type = %s | |
| 983 | + WHERE tt.taxonomy = 'ap_object_type' | |
| 984 | + AND p.post_type = 'ap_post' | |
| 1065 | 985 | AND pm.meta_key = '_activitypub_user_id' |
| 1066 | 986 | AND pm.meta_value = %s", |
| 1067 | - $taxonomy, | |
| 1068 | - Remote_Posts::POST_TYPE, | |
| 1069 | 987 | $user_id |
| 1070 | 988 | ) |
| 1071 | 989 | ); |
| 1072 | 990 | |
| 1073 | - /* | |
| 1074 | - * `include => array( 0 )` does not restrict anything: `WP_Term_Query` adds the `IN` clause | |
| 1075 | - * only when the imploded id list is truthy, and the string "0" is not, so the clause is | |
| 1076 | - * dropped and every term comes back. An id that cannot exist forces the empty result. | |
| 1077 | - */ | |
| 1078 | 991 | if ( empty( $term_ids ) ) { |
| 1079 | - $term_ids = array( PHP_INT_MAX ); | |
| 992 | + // Force empty result. | |
| 993 | + $term_ids = array( 0 ); | |
| 1080 | 994 | } |
| 1081 | 995 | |
| 1082 | 996 | $args['include'] = \array_map( 'intval', $term_ids ); |
| 1083 | 997 | |