PluginProbe
ActivityPub / 9.2.2
ActivityPub v9.2.2
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-following-controller.php

class-following-controller.php in ActivityPub 9.2.2, at includes/rest/class-following-controller.php

235 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Following_Controller file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Activity\Base_Object;
11 use Activitypub\Collection\Following;
12 use Activitypub\Collection\Remote_Actors;
13
14 use function Activitypub\get_masked_wp_version;
15 use function Activitypub\get_rest_url_by_path;
16
17 /**
18 * Following_Controller class.
19 *
20 * @author Matthias Pfefferle
21 *
22 * @see https://www.w3.org/TR/activitypub/#following
23 */
24 class Following_Controller extends Actors_Controller {
25 use Collection;
26
27 /**
28 * Register routes.
29 */
30 public function register_routes() {
31 \register_rest_route(
32 $this->namespace,
33 '/' . $this->rest_base . '/following',
34 array(
35 'args' => array(
36 'user_id' => array(
37 'description' => 'The ID of the actor.',
38 'type' => 'integer',
39 'required' => true,
40 'validate_callback' => array( $this, 'validate_user_id' ),
41 ),
42 ),
43 array(
44 'methods' => \WP_REST_Server::READABLE,
45 'callback' => array( $this, 'get_items' ),
46 'permission_callback' => array( $this, 'verify_signature' ),
47 'args' => array(
48 'page' => array(
49 'description' => 'Current page of the collection.',
50 'type' => 'integer',
51 'minimum' => 1,
52 // No default so we can differentiate between Collection and CollectionPage requests.
53 ),
54 'per_page' => array(
55 'description' => 'Maximum number of items to be returned in result set.',
56 'type' => 'integer',
57 'default' => 10,
58 'minimum' => 1,
59 'maximum' => 100,
60 ),
61 'order' => array(
62 'description' => 'Order sort attribute ascending or descending.',
63 'type' => 'string',
64 'default' => 'desc',
65 'enum' => array( 'asc', 'desc' ),
66 ),
67 'context' => array(
68 'description' => 'The context in which the request is made.',
69 'type' => 'string',
70 'default' => 'simple',
71 'enum' => array( 'simple', 'full' ),
72 ),
73 ),
74 ),
75 'schema' => array( $this, 'get_public_item_schema' ),
76 )
77 );
78 }
79
80 /**
81 * Retrieves following list.
82 *
83 * @param \WP_REST_Request $request Full details about the request.
84 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
85 */
86 public function get_items( $request ) {
87 $user_id = $request->get_param( 'user_id' );
88
89 /**
90 * Action triggered prior to the ActivityPub profile being created and sent to the client.
91 */
92 \do_action( 'activitypub_rest_following_pre' );
93
94 $order = $request->get_param( 'order' );
95 $per_page = $request->get_param( 'per_page' );
96 $page = $request->get_param( 'page' ) ?? 1;
97 $context = $request->get_param( 'context' );
98
99 $data = Following::query( $user_id, $per_page, $page, array( 'order' => \ucwords( $order ) ) );
100
101 $response = array(
102 'id' => get_rest_url_by_path( \sprintf( 'actors/%d/following', $user_id ) ),
103 'generator' => 'https://wordpress.org/?v=' . get_masked_wp_version(),
104 'type' => 'OrderedCollection',
105 'totalItems' => $data['total'],
106 );
107
108 if ( 'full' === $context ) {
109 // Ensure the context is the first element in the response.
110 $response = array( '@context' => Base_Object::JSON_LD_CONTEXT ) + $response;
111 }
112
113 if ( $this->show_social_graph( $request ) ) {
114 $response['orderedItems'] = \array_filter(
115 \array_map(
116 static function ( $item ) use ( $context ) {
117 if ( 'full' === $context ) {
118 $actor = Remote_Actors::get_actor( $item );
119 if ( \is_wp_error( $actor ) ) {
120 return false;
121 }
122 return $actor->to_array( false );
123 }
124 return $item->guid;
125 },
126 $data['following']
127 )
128 );
129 }
130
131 $response = $this->prepare_collection_response( $response, $request );
132 if ( \is_wp_error( $response ) ) {
133 return $response;
134 }
135
136 $response = \rest_ensure_response( $response );
137 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
138
139 return $response;
140 }
141
142 /**
143 * Retrieves the following schema, conforming to JSON Schema.
144 *
145 * @return array Item schema data.
146 */
147 public function get_item_schema() {
148 if ( $this->schema ) {
149 return $this->add_additional_fields_schema( $this->schema );
150 }
151
152 // Define the schema for items in the following collection.
153 $item_schema = array(
154 'oneOf' => array(
155 array(
156 'type' => 'string',
157 'format' => 'uri',
158 ),
159 array(
160 'type' => 'object',
161 'properties' => array(
162 'id' => array(
163 'type' => 'string',
164 'format' => 'uri',
165 ),
166 'type' => array(
167 'type' => 'string',
168 ),
169 'name' => array(
170 'type' => 'string',
171 ),
172 'icon' => array(
173 'type' => 'object',
174 'properties' => array(
175 'type' => array(
176 'type' => 'string',
177 ),
178 'mediaType' => array(
179 'type' => 'string',
180 ),
181 'url' => array(
182 'type' => 'string',
183 'format' => 'uri',
184 ),
185 ),
186 ),
187 'published' => array(
188 'type' => 'string',
189 'format' => 'date-time',
190 ),
191 'summary' => array(
192 'type' => 'string',
193 ),
194 'updated' => array(
195 'type' => 'string',
196 'format' => 'date-time',
197 ),
198 'url' => array(
199 'type' => 'string',
200 'format' => 'uri',
201 ),
202 'streams' => array(
203 'type' => 'array',
204 ),
205 'preferredUsername' => array(
206 'type' => 'string',
207 ),
208 ),
209 ),
210 ),
211 );
212
213 $schema = $this->get_collection_schema( $item_schema );
214
215 // Add following-specific properties.
216 $schema['title'] = 'following';
217 $schema['properties']['actor'] = array(
218 'description' => 'The actor who owns the following collection.',
219 'type' => 'string',
220 'format' => 'uri',
221 'readonly' => true,
222 );
223 $schema['properties']['generator'] = array(
224 'description' => 'The generator of the following collection.',
225 'type' => 'string',
226 'format' => 'uri',
227 'readonly' => true,
228 );
229
230 $this->schema = $schema;
231
232 return $this->add_additional_fields_schema( $this->schema );
233 }
234 }
235