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-post-controller.php

class-post-controller.php in ActivityPub 8.0.2, at includes/rest/class-post-controller.php

263 lines 6.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ActivityPub Post REST Endpoints
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Rest;
9
10 use Activitypub\Activity\Base_Object;
11 use Activitypub\Collection\Replies;
12 use Activitypub\Comment;
13 use Activitypub\Sanitize;
14 use Activitypub\Webfinger;
15
16 use function Activitypub\get_post_id;
17 use function Activitypub\get_rest_url_by_path;
18
19 /**
20 * Class Post_Controller
21 *
22 * @package Activitypub\Rest
23 */
24 class Post_Controller extends \WP_REST_Controller {
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 = 'posts/(?P<id>[-]?\d+)';
39
40 /**
41 * Register routes.
42 */
43 public function register_routes() {
44 \register_rest_route(
45 $this->namespace,
46 '/' . $this->rest_base . '/reactions',
47 array(
48 'args' => array(
49 'id' => array(
50 'required' => true,
51 'type' => 'integer',
52 ),
53 ),
54 array(
55 'methods' => \WP_REST_Server::READABLE,
56 'callback' => array( $this, 'get_reactions' ),
57 'permission_callback' => '__return_true',
58 ),
59 )
60 );
61
62 \register_rest_route(
63 $this->namespace,
64 '/' . $this->rest_base . '/context',
65 array(
66 'args' => array(
67 'id' => array(
68 'required' => true,
69 'type' => 'integer',
70 ),
71 ),
72 array(
73 'methods' => \WP_REST_Server::READABLE,
74 'callback' => array( $this, 'get_context' ),
75 'permission_callback' => '__return_true',
76 ),
77 )
78 );
79
80 \register_rest_route(
81 $this->namespace,
82 '/' . $this->rest_base . '/remote-intent',
83 array(
84 'args' => array(
85 'id' => array(
86 'description' => 'Unique identifier for the post.',
87 'type' => 'integer',
88 'required' => true,
89 ),
90 ),
91 array(
92 'methods' => \WP_REST_Server::READABLE,
93 'callback' => array( $this, 'get_remote_intent_template' ),
94 'permission_callback' => '__return_true',
95 'args' => array(
96 'resource' => array(
97 'description' => 'The Fediverse profile handle or URL.',
98 'type' => 'string',
99 'required' => true,
100 'sanitize_callback' => array( Sanitize::class, 'webfinger' ),
101 ),
102 'intent' => array(
103 'description' => 'The intent type.',
104 'type' => 'string',
105 'default' => 'like',
106 'enum' => array( 'like', 'announce', 'create' ),
107 'sanitize_callback' => 'sanitize_text_field',
108 ),
109 ),
110 ),
111 )
112 );
113 }
114
115 /**
116 * Get reactions for a post.
117 *
118 * @param \WP_REST_Request $request The request.
119 *
120 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
121 */
122 public function get_reactions( $request ) {
123 $post_id = $request->get_param( 'id' );
124 $post = \get_post( $post_id );
125
126 if ( ! $post ) {
127 return new \WP_Error( 'activitypub_post_not_found', 'Post not found', array( 'status' => 404 ) );
128 }
129
130 $reactions = array();
131
132 foreach ( Comment::get_comment_types() as $type_object ) {
133 $comments = \get_comments(
134 array(
135 'post_id' => $post_id,
136 'type' => $type_object['type'],
137 'status' => 'approve',
138 'parent' => 0,
139 )
140 );
141
142 if ( empty( $comments ) ) {
143 continue;
144 }
145
146 $count = \count( $comments );
147 // phpcs:disable WordPress.WP.I18n
148 $label = \sprintf(
149 \_n(
150 $type_object['count_single'],
151 $type_object['count_plural'],
152 $count,
153 'activitypub'
154 ),
155 \number_format_i18n( $count )
156 );
157 // phpcs:enable WordPress.WP.I18n
158
159 $reactions[ $type_object['collection'] ] = array(
160 'label' => $label,
161 'items' => \array_map(
162 static function ( $comment ) {
163 return array(
164 'name' => html_entity_decode( $comment->comment_author ),
165 'url' => $comment->comment_author_url,
166 'avatar' => \get_avatar_url( $comment ),
167 );
168 },
169 $comments
170 ),
171 );
172 }
173
174 return new \WP_REST_Response( $reactions );
175 }
176
177 /**
178 * Get the context for a post.
179 *
180 * @param \WP_REST_Request $request The request.
181 *
182 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
183 */
184 public function get_context( $request ) {
185 $post_id = $request->get_param( 'id' );
186
187 $collection = Replies::get_context_collection( $post_id );
188
189 if ( false === $collection ) {
190 return new \WP_Error( 'activitypub_post_not_found', 'Post not found', array( 'status' => 404 ) );
191 }
192
193 $response = array_merge(
194 array(
195 '@context' => Base_Object::JSON_LD_CONTEXT,
196 'id' => get_rest_url_by_path( \sprintf( 'posts/%d/context', $post_id ) ),
197 ),
198 $collection
199 );
200
201 $response = \rest_ensure_response( $response );
202 $response->header( 'Content-Type', 'application/activity+json; charset=' . \get_option( 'blog_charset' ) );
203
204 return $response;
205 }
206
207 /**
208 * Get the remote intent template for a post.
209 *
210 * @since 8.0.0
211 *
212 * @param \WP_REST_Request $request The request.
213 *
214 * @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
215 */
216 public function get_remote_intent_template( $request ) {
217 $post_id = $request->get_param( 'id' );
218 $resource = $request->get_param( 'resource' );
219 $intent = $request->get_param( 'intent' );
220 $post = \get_post( $post_id );
221
222 if ( ! $post || 'publish' !== \get_post_status( $post ) ) {
223 return new \WP_Error( 'activitypub_post_not_found', \__( 'Post not found.', 'activitypub' ), array( 'status' => 404 ) );
224 }
225
226 $template = Webfinger::get_intent_endpoint( $resource, $intent, true );
227
228 if ( \is_wp_error( $template ) ) {
229 return $template;
230 }
231
232 $id = get_post_id( $post_id );
233
234 $url = \str_replace(
235 array(
236 '{object}',
237 '{uri}',
238 '{inReplyTo}',
239 '{name}',
240 '{target}',
241 ),
242 array(
243 \rawurlencode( $id ),
244 \rawurlencode( $id ),
245 \rawurlencode( $id ),
246 \rawurlencode( $post->post_title ),
247 \rawurlencode( $resource ),
248 ),
249 $template
250 );
251
252 // Remove any other GET-Params with placeholders to avoid confusion.
253 $url = \preg_replace( '/([&?][^=]+=\{[^}]+\})/', '', $url );
254
255 return \rest_ensure_response(
256 array(
257 'url' => $url,
258 'template' => $template,
259 )
260 );
261 }
262 }
263