PluginProbe
ActivityPub / 5.7.0
ActivityPub v5.7.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / rest / class-outbox-controller.php

class-outbox-controller.php in ActivityPub 5.7.0, at includes/rest/class-outbox-controller.php

258 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Outbox Controller file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Activity\Base_Object;
11 use Activitypub\Collection\Actors;
12 use Activitypub\Collection\Outbox;
13 use function Activitypub\get_masked_wp_version;
14 use function ActivityPub\get_rest_url_by_path;
15
16 /**
17 * ActivityPub Outbox Controller.
18 *
19 * @author Matthias Pfefferle
20 *
21 * @see https://www.w3.org/TR/activitypub/#outbox
22 */
23 class Outbox_Controller extends \WP_REST_Controller {
24 use Collection;
25
26 /**
27 * The namespace of this controller's route.
28 *
29 * @var string
30 */
31 protected $namespace = ACTIVITYPUB_REST_NAMESPACE;
32
33 /**
34 * The base of this controller's route.
35 *
36 * @var string
37 */
38 protected $rest_base = '(?:users|actors)/(?P<user_id>[\w\-\.]+)/outbox';
39
40 /**
41 * Register routes.
42 */
43 public function register_routes() {
44 \register_rest_route(
45 $this->namespace,
46 '/' . $this->rest_base,
47 array(
48 'args' => array(
49 'user_id' => array(
50 'description' => 'The ID of the user or actor.',
51 'type' => 'string',
52 'validate_callback' => array( $this, 'validate_user_id' ),
53 ),
54 ),
55 array(
56 'methods' => \WP_REST_Server::READABLE,
57 'callback' => array( $this, 'get_items' ),
58 'permission_callback' => array( 'Activitypub\Rest\Server', 'verify_signature' ),
59 'args' => array(
60 'page' => array(
61 'description' => 'Current page of the collection.',
62 'type' => 'integer',
63 'minimum' => 1,
64 // No default so we can differentiate between Collection and CollectionPage requests.
65 ),
66 'per_page' => array(
67 'description' => 'Maximum number of items to be returned in result set.',
68 'type' => 'integer',
69 'default' => 20,
70 'minimum' => 1,
71 'maximum' => 100,
72 ),
73 ),
74 ),
75 'schema' => array( $this, 'get_item_schema' ),
76 )
77 );
78 }
79
80 /**
81 * Validates the user_id parameter.
82 *
83 * @param mixed $user_id The user_id parameter.
84 * @return bool|\WP_Error True if the user_id is valid, WP_Error otherwise.
85 */
86 public function validate_user_id( $user_id ) {
87 $user = Actors::get_by_various( $user_id );
88 if ( \is_wp_error( $user ) ) {
89 return $user;
90 }
91
92 return true;
93 }
94
95 /**
96 * Retrieves a collection of outbox items.
97 *
98 * @param \WP_REST_Request $request Full details about the request.
99 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
100 */
101 public function get_items( $request ) {
102 $page = $request->get_param( 'page' ) ?? 1;
103 $user = Actors::get_by_various( $request->get_param( 'user_id' ) );
104 $user_id = $user->get__id();
105
106 /**
107 * Action triggered prior to the ActivityPub profile being created and sent to the client.
108 *
109 * @param \WP_REST_Request $request The request object.
110 */
111 \do_action( 'activitypub_rest_outbox_pre', $request );
112
113 /**
114 * Filters the list of activity types to include in the outbox.
115 *
116 * @param string[] $activity_types The list of activity types.
117 */
118 $activity_types = apply_filters( 'rest_activitypub_outbox_activity_types', array( 'Announce', 'Create', 'Like', 'Update' ) );
119
120 $args = array(
121 'posts_per_page' => $request->get_param( 'per_page' ),
122 'author' => $user_id > 0 ? $user_id : null,
123 'paged' => $page,
124 'post_type' => Outbox::POST_TYPE,
125 'post_status' => 'any',
126
127 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
128 'meta_query' => array(
129 array(
130 'key' => '_activitypub_activity_actor',
131 'value' => Actors::get_type_by_id( $user_id ),
132 ),
133 ),
134 );
135
136 if ( get_current_user_id() !== $user_id && ! current_user_can( 'activitypub' ) ) {
137 $args['meta_query'][] = array(
138 'key' => '_activitypub_activity_type',
139 'value' => $activity_types,
140 'compare' => 'IN',
141 );
142
143 $args['meta_query'][] = array(
144 'relation' => 'OR',
145 array(
146 'key' => 'activitypub_content_visibility',
147 'compare' => 'NOT EXISTS',
148 ),
149 array(
150 'key' => 'activitypub_content_visibility',
151 'value' => ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC,
152 ),
153 );
154 }
155
156 /**
157 * Filters WP_Query arguments when querying Outbox items via the REST API.
158 *
159 * Enables adding extra arguments or setting defaults for an outbox collection request.
160 *
161 * @param array $args Array of arguments for WP_Query.
162 * @param \WP_REST_Request $request The REST API request.
163 */
164 $args = apply_filters( 'rest_activitypub_outbox_query', $args, $request );
165
166 $outbox_query = new \WP_Query();
167 $query_result = $outbox_query->query( $args );
168
169 $response = array(
170 '@context' => Base_Object::JSON_LD_CONTEXT,
171 'id' => get_rest_url_by_path( sprintf( 'actors/%d/outbox', $user_id ) ),
172 'generator' => 'https://wordpress.org/?v=' . get_masked_wp_version(),
173 'actor' => $user->get_id(),
174 'type' => 'OrderedCollection',
175 'totalItems' => $outbox_query->found_posts,
176 'orderedItems' => array(),
177 );
178
179 \update_postmeta_cache( \wp_list_pluck( $query_result, 'ID' ) );
180 foreach ( $query_result as $outbox_item ) {
181 $response['orderedItems'][] = $this->prepare_item_for_response( $outbox_item, $request );
182 }
183
184 $response = $this->prepare_collection_response( $response, $request );
185 if ( is_wp_error( $response ) ) {
186 return $response;
187 }
188
189 /**
190 * Filter the ActivityPub outbox array.
191 *
192 * @param array $response The ActivityPub outbox array.
193 * @param \WP_REST_Request $request The request object.
194 */
195 $response = \apply_filters( 'activitypub_rest_outbox_array', $response, $request );
196
197 /**
198 * Action triggered after the ActivityPub profile has been created and sent to the client.
199 *
200 * @param \WP_REST_Request $request The request object.
201 */
202 \do_action( 'activitypub_outbox_post', $request );
203
204 $response = \rest_ensure_response( $response );
205 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
206
207 return $response;
208 }
209
210 /**
211 * Prepares the item for the REST response.
212 *
213 * @param mixed $item WordPress representation of the item.
214 * @param \WP_REST_Request $request Request object.
215 * @return array Response object on success, or WP_Error object on failure.
216 */
217 public function prepare_item_for_response( $item, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
218 $activity = Outbox::get_activity( $item->ID );
219
220 return $activity->to_array( false );
221 }
222
223 /**
224 * Retrieves the outbox schema, conforming to JSON Schema.
225 *
226 * @return array Collection schema data.
227 */
228 public function get_item_schema() {
229 if ( $this->schema ) {
230 return $this->add_additional_fields_schema( $this->schema );
231 }
232
233 $item_schema = array(
234 'type' => 'object',
235 );
236
237 $schema = $this->get_collection_schema( $item_schema );
238
239 // Add outbox-specific properties.
240 $schema['title'] = 'outbox';
241 $schema['properties']['actor'] = array(
242 'description' => 'The actor who owns this outbox.',
243 'type' => 'string',
244 'format' => 'uri',
245 'required' => true,
246 );
247 $schema['properties']['generator'] = array(
248 'description' => 'The software used to generate the collection.',
249 'type' => 'string',
250 'format' => 'uri',
251 );
252
253 $this->schema = $schema;
254
255 return $this->add_additional_fields_schema( $this->schema );
256 }
257 }
258