PluginProbe
ActivityPub / 8.0.2
ActivityPub v8.0.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 8.0.2, at includes/rest/class-following-controller.php

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