PluginProbe
ActivityPub / 1.3.0
ActivityPub v1.3.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 / collection / class-interactions.php

class-interactions.php in ActivityPub 1.3.0, at includes/collection/class-interactions.php

236 lines 6.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Activitypub\Collection;
3
4 use WP_Error;
5 use WP_Comment_Query;
6
7 use function Activitypub\url_to_commentid;
8 use function Activitypub\object_id_to_comment;
9 use function Activitypub\get_remote_metadata_by_actor;
10
11 /**
12 * ActivityPub Interactions Collection
13 */
14 class Interactions {
15 /**
16 * Add a comment to a post
17 *
18 * @param array $activity The activity-object
19 *
20 * @return array|false The commentdata or false on failure
21 */
22 public static function add_comment( $activity ) {
23 if (
24 ! isset( $activity['object'] ) ||
25 ! isset( $activity['object']['id'] )
26 ) {
27 return false;
28 }
29
30 if ( ! isset( $activity['object']['inReplyTo'] ) ) {
31 return false;
32 }
33
34 $in_reply_to = \esc_url_raw( $activity['object']['inReplyTo'] );
35 $comment_post_id = \url_to_postid( $in_reply_to );
36 $parent_comment = object_id_to_comment( $in_reply_to );
37
38 // save only replys and reactions
39 if ( ! $comment_post_id && $parent_comment ) {
40 $comment_post_id = $parent_comment->comment_post_ID;
41 }
42
43 // not a reply to a post or comment
44 if ( ! $comment_post_id ) {
45 return false;
46 }
47
48 $meta = get_remote_metadata_by_actor( $activity['actor'] );
49
50 if ( ! $meta || \is_wp_error( $meta ) ) {
51 return false;
52 }
53
54 $commentdata = array(
55 'comment_post_ID' => $comment_post_id,
56 'comment_author' => \esc_attr( $meta['name'] ),
57 'comment_author_url' => \esc_url_raw( $meta['url'] ),
58 'comment_content' => \addslashes( $activity['object']['content'] ),
59 'comment_type' => 'comment',
60 'comment_author_email' => '',
61 'comment_parent' => $parent_comment ? $parent_comment->comment_ID : 0,
62 'comment_meta' => array(
63 'source_id' => \esc_url_raw( $activity['object']['id'] ),
64 'source_url' => \esc_url_raw( $activity['object']['url'] ),
65 'protocol' => 'activitypub',
66 ),
67 );
68
69 if ( isset( $meta['icon']['url'] ) ) {
70 $commentdata['comment_meta']['avatar_url'] = \esc_url_raw( $meta['icon']['url'] );
71 }
72
73 // disable flood control
74 \remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
75 // do not require email for AP entries
76 \add_filter( 'pre_option_require_name_email', '__return_false' );
77 // No nonce possible for this submission route
78 \add_filter(
79 'akismet_comment_nonce',
80 function() {
81 return 'inactive';
82 }
83 );
84 \add_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10, 2 );
85
86 $comment = \wp_new_comment( $commentdata, true );
87
88 \remove_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10 );
89 \remove_filter( 'pre_option_require_name_email', '__return_false' );
90 // re-add flood control
91 \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
92
93 return $comment;
94 }
95
96 /**
97 * Update a comment
98 *
99 * @param array $activity The activity-object
100 *
101 * @return array|false The commentdata or false on failure
102 */
103 public static function update_comment( $activity ) {
104 $meta = get_remote_metadata_by_actor( $activity['actor'] );
105
106 //Determine comment_ID
107 $object_comment_id = url_to_commentid( \esc_url_raw( $activity['object']['id'] ) );
108
109 if ( ! $object_comment_id ) {
110 return false;
111 }
112
113 //found a local comment id
114 $commentdata = \get_comment( $object_comment_id, ARRAY_A );
115 $commentdata['comment_author'] = \esc_attr( $meta['name'] ? $meta['name'] : $meta['preferredUsername'] );
116 $commentdata['comment_content'] = \addslashes( $activity['object']['content'] );
117 if ( isset( $meta['icon']['url'] ) ) {
118 $commentdata['comment_meta']['avatar_url'] = \esc_url_raw( $meta['icon']['url'] );
119 }
120
121 // disable flood control
122 \remove_action( 'check_comment_flood', 'check_comment_flood_db', 10 );
123 // do not require email for AP entries
124 \add_filter( 'pre_option_require_name_email', '__return_false' );
125 // No nonce possible for this submission route
126 \add_filter(
127 'akismet_comment_nonce',
128 function() {
129 return 'inactive';
130 }
131 );
132 \add_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10, 2 );
133
134 $comment = \wp_update_comment( $commentdata, true );
135
136 \remove_filter( 'wp_kses_allowed_html', array( self::class, 'allowed_comment_html' ), 10 );
137 \remove_filter( 'pre_option_require_name_email', '__return_false' );
138 // re-add flood control
139 \add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 );
140
141 return $comment;
142 }
143
144 /**
145 * Get interaction(s) for a given URL/ID.
146 *
147 * @param strin $url The URL/ID to get interactions for.
148 *
149 * @return array The interactions as WP_Comment objects.
150 */
151 public static function get_interaction_by_id( $url ) {
152 $args = array(
153 'nopaging' => true,
154 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
155 'meta_query' => array(
156 'relation' => 'AND',
157 array(
158 'key' => 'protocol',
159 'value' => 'activitypub',
160 ),
161 array(
162 'relation' => 'OR',
163 array(
164 'key' => 'source_url',
165 'value' => $url,
166 ),
167 array(
168 'key' => 'source_id',
169 'value' => $url,
170 ),
171 ),
172 ),
173 );
174
175 $query = new WP_Comment_Query( $args );
176 return $query->comments;
177 }
178
179 /**
180 * Get interaction(s) for a given actor.
181 *
182 * @param string $actor The Actor-URL.
183 *
184 * @return array The interactions as WP_Comment objects.
185 */
186 public static function get_interactions_by_actor( $actor ) {
187 $meta = get_remote_metadata_by_actor( $actor );
188
189 // get URL, because $actor seems to be the ID
190 if ( $meta && ! is_wp_error( $meta ) && isset( $meta['url'] ) ) {
191 $actor = $meta['url'];
192 }
193
194 $args = array(
195 'nopaging' => true,
196 'author_url' => $actor,
197 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
198 'meta_query' => array(
199 array(
200 'key' => 'protocol',
201 'value' => 'activitypub',
202 'compare' => '=',
203 ),
204 ),
205 );
206 $comment_query = new WP_Comment_Query( $args );
207 return $comment_query->comments;
208 }
209
210 /**
211 * Adds line breaks to the list of allowed comment tags.
212 *
213 * @param array $allowed_tags Allowed HTML tags.
214 * @param string $context Context.
215 *
216 * @return array Filtered tag list.
217 */
218 public static function allowed_comment_html( $allowed_tags, $context = '' ) {
219 if ( 'pre_comment_content' !== $context ) {
220 // Do nothing.
221 return $allowed_tags;
222 }
223
224 // Add `p` and `br` to the list of allowed tags.
225 if ( ! array_key_exists( 'br', $allowed_tags ) ) {
226 $allowed_tags['br'] = array();
227 }
228
229 if ( ! array_key_exists( 'p', $allowed_tags ) ) {
230 $allowed_tags['p'] = array();
231 }
232
233 return $allowed_tags;
234 }
235 }
236