PluginProbe
Friends / 4.3.2
Friends v4.3.2
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
friends / integrations / class-enable-mastodon-apps.php

class-enable-mastodon-apps.php in Friends 4.3.2, at integrations/class-enable-mastodon-apps.php

373 lines 12.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Friends;
3
4 /**
5 * Class Enable_Mastodon_Apps
6 *
7 * This class is used to enable Mastodon Apps to work with Friends.
8 *
9 * @see https://github.com/akirk/enable-mastodon-apps
10 */
11 class Enable_Mastodon_Apps {
12 /**
13 * Initialize the class, registering WordPress hooks
14 */
15 public static function init() {
16 add_filter( 'mastodon_api_account', array( 'Friends\User', 'mastodon_api_account' ), 10, 4 );
17 add_filter( 'mastodon_api_account_id', array( 'Friends\User', 'mastodon_api_account_id' ), 8, 2 );
18 add_filter( 'mastodon_api_get_posts_query_args', array( 'Friends\User', 'mastodon_api_get_posts_query_args' ) );
19 add_filter( 'mastodon_entity_relationship', array( 'Friends\User', 'mastodon_entity_relationship' ), 10, 2 );
20 add_filter( 'mastodon_api_account_follow', array( get_called_class(), 'mastodon_api_account_follow' ), 10, 1 );
21 add_action( 'mastodon_api_account_unfollow', array( get_called_class(), 'mastodon_api_account_unfollow' ), 10, 1 );
22 add_filter( 'mastodon_api_view_post_types', array( get_called_class(), 'mastodon_api_view_post_types' ) );
23 add_filter( 'mastodon_api_favourites_args', array( get_called_class(), 'mastodon_api_favourites_args' ), 10, 2 );
24 add_filter( 'mastodon_api_bookmarks_args', array( get_called_class(), 'mastodon_api_bookmarks_args' ), 10, 2 );
25 add_filter( 'mastodon_api_status', array( get_called_class(), 'mastodon_api_status' ), 60, 2 );
26 add_filter( 'mastodon_api_submit_post_data', array( get_called_class(), 'mastodon_api_submit_post_data' ), 20, 9 );
27 add_filter( 'mastodon_api_get_notifications_query_args', array( get_called_class(), 'mastodon_api_get_notifications_query_args' ), 10, 2 );
28 add_filter( 'mastodon_api_get_notifications_queries', array( get_called_class(), 'mastodon_api_get_notifications_queries' ), 10, 2 );
29 add_filter( 'mastodon_api_account_statuses_excluded_post_types', array( get_called_class(), 'mastodon_api_account_statuses_excluded_post_types' ) );
30 add_filter( 'mastodon_api_account_statuses', array( get_called_class(), 'mastodon_api_account_statuses' ), 10, 3 );
31 }
32
33 public static function mastodon_api_account_follow( $user_id ) {
34 $user = User::get_user_by_id( $user_id );
35 if ( ! $user ) {
36 return apply_filters( 'friends_create_and_follow', null, $user_id );
37 }
38 foreach ( $user->get_feeds() as $feed ) {
39 if ( $feed->is_active() ) {
40 continue;
41 }
42 if ( class_exists( 'Friends\Feed_Parser_ActivityPub' ) && Feed_Parser_ActivityPub::SLUG === $feed->get_parser() ) {
43 $feed->activate();
44 }
45 }
46 return $user_id;
47 }
48
49 public static function mastodon_api_account_unfollow( $user_id ) {
50 $user = User::get_user_by_id( $user_id );
51 if ( ! $user ) {
52 return;
53 }
54 foreach ( $user->get_active_feeds() as $feed ) {
55 $feed->deactivate();
56 }
57 }
58
59 public static function mastodon_api_view_post_types( $view_post_types ) {
60 $view_post_types[] = Friends::CPT;
61 return $view_post_types;
62 }
63
64 public static function mastodon_api_account_statuses_excluded_post_types( $excluded_post_types ) {
65 $excluded_post_types[] = Friends::CPT;
66 return $excluded_post_types;
67 }
68
69 public static function mastodon_api_favourites_args( $args, $user_id ) {
70 return self::mastodon_api_reaction_args(
71 self::get_mastodon_api_reaction( 'favourite' ),
72 $args,
73 $user_id
74 );
75 }
76 public static function mastodon_api_bookmarks_args( $args, $user_id ) {
77 return self::mastodon_api_reaction_args(
78 self::get_mastodon_api_reaction( 'bookmark' ),
79 $args,
80 $user_id
81 );
82 }
83
84 protected static function mastodon_api_reaction_args( $reaction, $args, $user_id ) {
85 $tax_query = array();
86 if ( isset( $args['tax_query'] ) ) {
87 $tax_query = $args['tax_query'];
88 }
89
90 if ( ! empty( $tax_query ) ) {
91 $tax_query['relation'] = 'AND';
92 }
93 Reactions::register_user_taxonomy( $user_id );
94
95 $reaction_query = array(
96 'taxonomy' => 'friend-reaction-' . $user_id,
97 'field' => 'slug',
98 'terms' => array( strval( $reaction ) ),
99 );
100
101 if ( ! empty( $tax_query ) ) {
102 $tax_query[] = $reaction_query;
103 } else {
104 $tax_query = array( $reaction_query );
105 }
106
107 $args['tax_query'] = $tax_query; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
108
109 return $args;
110 }
111
112 protected static function get_mastodon_api_reaction( $type ) {
113 if ( 'bookmark' === $type ) {
114 return apply_filters( 'mastodon_api_bookmark_reaction', apply_filters( 'friends_bookmarks_emoji', '2b50' ), null );
115 }
116
117 return apply_filters( 'mastodon_api_favourite_reaction', apply_filters( 'friends_favourites_emoji', '2764' ), null );
118 }
119
120 public static function mastodon_api_status( $status, $post_id ) {
121 if ( ! $status ) {
122 return $status;
123 }
124
125 if ( self::get_activitypub_quiet_public_visibility() === get_post_meta( $post_id, 'activitypub_content_visibility', true ) ) {
126 $status->visibility = 'unlisted';
127 }
128
129 $reaction_post_id = $post_id;
130 $paired_post_id = get_post_meta( $post_id, 'mastodon_reblog_id', true );
131 if ( Friends::CPT !== get_post_type( $reaction_post_id ) ) {
132 if ( ! $paired_post_id || Friends::CPT !== get_post_type( $paired_post_id ) ) {
133 return $status;
134 }
135 $reaction_post_id = $paired_post_id;
136 }
137
138 $reactions = Reactions::get_post_reactions( $reaction_post_id );
139 if ( ! is_array( $reactions ) ) {
140 return $status;
141 }
142
143 $favourite_reaction = self::get_mastodon_api_reaction( 'favourite' );
144 $bookmark_reaction = self::get_mastodon_api_reaction( 'bookmark' );
145 $remapped_reactions = array();
146 if ( $paired_post_id && intval( $paired_post_id ) !== intval( $reaction_post_id ) ) {
147 $remapped_reactions = Reactions::get_post_reactions( $paired_post_id );
148 if ( ! is_array( $remapped_reactions ) ) {
149 $remapped_reactions = array();
150 }
151 }
152
153 $favourite = $reactions[ $favourite_reaction ] ?? $remapped_reactions[ $favourite_reaction ] ?? null;
154 $bookmark = $reactions[ $bookmark_reaction ] ?? $remapped_reactions[ $bookmark_reaction ] ?? null;
155
156 if ( $favourite ) {
157 $status->favourited = (bool) $favourite->user_reacted;
158 $status->favourites_count = intval( $favourite->count );
159 }
160 if ( $bookmark ) {
161 $status->bookmarked = (bool) $bookmark->user_reacted;
162 }
163
164 if ( isset( $status->reblog ) ) {
165 $status->reblog->favourited = $status->favourited;
166 $status->reblog->bookmarked = $status->bookmarked;
167 $status->reblog->favourites_count = $status->favourites_count;
168 }
169
170 return $status;
171 }
172
173 public static function mastodon_api_submit_post_data( $post_data, $status_text, $in_reply_to_id, $media_ids, $post_format, $visibility, $scheduled_at, $post_id, $app ) {
174 unset( $status_text, $in_reply_to_id, $media_ids, $post_format, $post_id, $app );
175
176 if ( 'unlisted' !== $visibility ) {
177 return $post_data;
178 }
179
180 if ( empty( $scheduled_at ) ) {
181 $post_data['post_status'] = 'publish';
182 }
183
184 if ( ! isset( $post_data['meta_input'] ) || ! is_array( $post_data['meta_input'] ) ) {
185 $post_data['meta_input'] = array();
186 }
187
188 $post_data['meta_input']['activitypub_content_visibility'] = self::get_activitypub_quiet_public_visibility();
189
190 return $post_data;
191 }
192
193 private static function get_activitypub_quiet_public_visibility() {
194 return defined( 'ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC' ) ? ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC : 'quiet_public';
195 }
196
197 public static function mastodon_api_account_statuses( $statuses, $request, $user_id ) {
198 if ( $request->get_param( 'exclude_reblogs' ) ) {
199 return $statuses;
200 }
201
202 if ( is_wp_error( $statuses ) ) {
203 return $statuses;
204 }
205
206 $response = null;
207 if ( $statuses instanceof \WP_REST_Response ) {
208 $response = $statuses;
209 $statuses = $response->get_data();
210 }
211
212 if ( ! is_array( $statuses ) ) {
213 return $response ? $response : $statuses;
214 }
215
216 $boosted_posts = self::get_mastodon_api_boosted_posts( $request, $user_id );
217 if ( empty( $boosted_posts ) ) {
218 return $response ? $response : $statuses;
219 }
220
221 $account = apply_filters( 'mastodon_api_account', null, $user_id, $request, null );
222 if ( ! is_object( $account ) ) {
223 return $response ? $response : $statuses;
224 }
225
226 foreach ( $boosted_posts as $post ) {
227 $reblog = apply_filters( 'mastodon_api_status', null, $post->ID, array() );
228 if ( ! is_object( $reblog ) || empty( $reblog->id ) ) {
229 continue;
230 }
231
232 $status = clone $reblog;
233 $status->account = $account;
234 $status->reblog = $reblog;
235 $status->content = '';
236 $status->url = null;
237 $status->created_at = self::get_mastodon_api_boosted_at( $post );
238 $status->reblogged = true;
239 $statuses[] = $status;
240 }
241
242 usort(
243 $statuses,
244 function ( $a, $b ) {
245 return $b->created_at->getTimestamp() - $a->created_at->getTimestamp();
246 }
247 );
248
249 $limit = $request->get_param( 'limit' );
250 if ( $limit > 0 ) {
251 $statuses = array_slice( $statuses, 0, $limit );
252 }
253
254 if ( $response ) {
255 $response->set_data( $statuses );
256 return $response;
257 }
258
259 return $statuses;
260 }
261
262 protected static function get_mastodon_api_boosted_posts( $request, $user_id ) {
263 $args = array(
264 'post_type' => Friends::CPT,
265 'post_status' => array( 'publish', 'private' ),
266 'posts_per_page' => $request->get_param( 'limit' ),
267 'suppress_filters' => false,
268 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
269 array(
270 'key' => 'boosted',
271 'value' => strval( $user_id ),
272 ),
273 ),
274 );
275
276 return get_posts( $args );
277 }
278
279 protected static function get_mastodon_api_boosted_at( \WP_Post $post ) {
280 $boosted_at = get_post_meta( $post->ID, 'boosted_at', true );
281 if ( $boosted_at ) {
282 return new \DateTime( $boosted_at, new \DateTimeZone( 'UTC' ) );
283 }
284
285 return new \DateTime( $post->post_modified_gmt, new \DateTimeZone( 'UTC' ) );
286 }
287
288 /**
289 * Add the received messages as their own notification source.
290 *
291 * Enable Mastodon Apps queries every entry of this filter separately, so the mention
292 * tag query that mastodon_api_get_notifications_query_args() needs for the cached
293 * posts doesn't apply to the messages, which don't carry that tag.
294 *
295 * @param array $queries The notification queries.
296 * @param string $type The type of notifications.
297 * @return array The notification queries.
298 */
299 public static function mastodon_api_get_notifications_queries( $queries, $type ) {
300 if ( 'mention' !== $type ) {
301 return $queries;
302 }
303
304 $queries[] = array(
305 'post_type' => Messages::CPT,
306 'post_status' => array( 'friends_read', 'friends_unread' ),
307 );
308
309 return $queries;
310 }
311
312 public static function mastodon_api_get_notifications_query_args( $args, $type ) {
313 if ( 'mention' !== $type ) {
314 return $args;
315 }
316
317 if ( ! isset( $args['post_type'] ) ) {
318 $args['post_type'] = array();
319 } elseif ( ! is_array( $args['post_type'] ) ) {
320 $args['post_type'] = array( $args['post_type'] );
321 }
322
323 // Include public Friends posts for public mentions.
324 if ( ! in_array( Friends::CPT, $args['post_type'] ) ) {
325 $args['post_type'][] = Friends::CPT;
326 }
327
328 if ( ! isset( $args['post_status'] ) ) {
329 $args['post_status'] = array();
330 } elseif ( ! is_array( $args['post_status'] ) ) {
331 $args['post_status'] = array( $args['post_status'] );
332 }
333
334 // Add public post statuses for mentions.
335 if ( ! in_array( 'publish', $args['post_status'] ) ) {
336 $args['post_status'][] = 'publish';
337 }
338 if ( ! in_array( 'private', $args['post_status'] ) ) {
339 $args['post_status'][] = 'private';
340 }
341
342 // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
343
344 // Add tax_query to filter for mention tags for the current user.
345 $current_user = wp_get_current_user();
346 if ( $current_user && $current_user->ID ) {
347 $mention_tag = Friend_Tag::mention_tag( $current_user->user_login );
348
349 $mention_query = array(
350 'taxonomy' => Friends::TAG_TAXONOMY,
351 'field' => 'name',
352 'terms' => $mention_tag,
353 );
354
355 if ( ! isset( $args['tax_query'] ) ) {
356 $args['tax_query'] = array( $mention_query );
357 } elseif ( ! empty( $args['tax_query'] ) ) {
358 $args['tax_query'] = array(
359 'relation' => 'OR',
360 $args['tax_query'],
361 $mention_query,
362 );
363 } else {
364 $args['tax_query'] = array( $mention_query );
365 }
366 }
367
368 // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_tax_query
369
370 return $args;
371 }
372 }
373