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
← All changes | includes/handler/class-create.php +146 -30 1.3.08.0.2 View file →
@@ -1,61 +1,177 @@
1 1 <?php
2 +/**
3 + * Create handler file.
4 + *
5 + * @package Activitypub
6 + */
7 +
2 8 namespace Activitypub\Handler;
3 9
4 -use WP_Error;
5 10 use Activitypub\Collection\Interactions;
11 +use Activitypub\Collection\Posts;
12 +use Activitypub\Tombstone;
6 13
7 -use function Activitypub\is_activity_public;
14 +use function Activitypub\get_activity_visibility;
15 +use function Activitypub\is_activity_reply;
16 +use function Activitypub\is_quote_activity;
17 +use function Activitypub\is_self_ping;
8 18 use function Activitypub\object_id_to_comment;
9 19
10 20 /**
11 - * Handle Create requests
21 + * Handle Create requests.
12 22 */
13 23 class Create {
14 24 /**
15 - * Initialize the class, registering WordPress hooks
25 + * Initialize the class, registering WordPress hooks.
16 26 */
17 27 public static function init() {
18 - \add_action( 'activitypub_inbox_create', array( self::class, 'handle_create' ), 10, 3 );
28 + \add_action( 'activitypub_handled_inbox_create', array( self::class, 'handle_create' ), 10, 3 );
29 + \add_filter( 'activitypub_validate_object', array( self::class, 'validate_object' ), 10, 3 );
30 + \add_action( 'post_activitypub_add_to_outbox', array( self::class, 'maybe_unbury' ), 10, 2 );
19 31 }
20 32
21 33 /**
22 - * Handles "Create" requests
34 + * Handles "Create" requests.
23 35 *
24 - * @param array $array The activity-object
25 - * @param int $user_id The id of the local blog-user
26 - * @param Activitypub\Activity $object The activity object
36 + * @param array $activity The activity-object.
37 + * @param int|int[] $user_ids The id(s) of the local blog-user(s).
38 + * @param \Activitypub\Activity\Activity $activity_object Optional. The activity object. Default null.
39 + */
40 + public static function handle_create( $activity, $user_ids, $activity_object = null ) {
41 + // Check for private and/or direct messages.
42 + if ( ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE === get_activity_visibility( $activity ) ) {
43 + $result = false;
44 + } elseif ( is_activity_reply( $activity ) || is_quote_activity( $activity ) ) { // Check for replies and quotes.
45 + $result = self::create_interaction( $activity, $user_ids, $activity_object );
46 + } else { // Handle non-interaction objects.
47 + $result = self::create_post( $activity, $user_ids, $activity_object );
48 + }
49 +
50 + if ( false === $result ) {
51 + return;
52 + }
53 +
54 + $success = ! \is_wp_error( $result );
55 +
56 + /**
57 + * Fires after an ActivityPub Create activity has been handled.
58 + *
59 + * @param array $activity The ActivityPub activity data.
60 + * @param int[] $user_ids The local user IDs.
61 + * @param bool $success True on success, false otherwise.
62 + * @param \WP_Comment|\WP_Post|\WP_Error $result The WP_Comment object of the created comment, or null if creation failed.
63 + */
64 + \do_action( 'activitypub_handled_create', $activity, (array) $user_ids, $success, $result );
65 + }
66 +
67 + /**
68 + * Handle interactions like replies.
27 69 *
28 - * @return void
70 + * @param array $activity The activity-object.
71 + * @param int[] $user_ids The ids of the local blog-users.
72 + * @param \Activitypub\Activity\Activity $activity_object Optional. The activity object. Default null.
73 + *
74 + * @return \WP_Comment|\WP_Error|false The created comment, WP_Error on failure, false if already exists or not processed.
29 75 */
30 - public static function handle_create( $array, $user_id, $object = null ) {
31 - if (
32 - ! isset( $array['object'] ) ||
33 - ! isset( $array['object']['id'] )
34 - ) {
35 - return;
76 + public static function create_interaction( $activity, $user_ids, $activity_object = null ) {
77 + $existing_comment = object_id_to_comment( $activity['object']['id'] );
78 +
79 + // If comment exists, call update action.
80 + if ( $existing_comment ) {
81 + Update::handle_update( $activity, (array) $user_ids, $activity_object );
82 +
83 + return false;
36 84 }
37 85
38 - // check if Activity is public or not
39 - if ( ! is_activity_public( $array ) ) {
40 - // @todo maybe send email
41 - return;
86 + if ( is_self_ping( $activity['object']['id'] ) ) {
87 + return false;
42 88 }
43 89
44 - $check_dupe = object_id_to_comment( $array['object']['id'] );
90 + $result = Interactions::add_comment( $activity );
45 91
46 - // if comment exists, call update action
47 - if ( $check_dupe ) {
48 - \do_action( 'activitypub_inbox_update', $array, $user_id, $object );
92 + if ( ! $result || \is_wp_error( $result ) ) {
93 + return $result;
94 + }
95 +
96 + return \get_comment( $result );
97 + }
98 +
99 + /**
100 + * Handle non-interaction posts like posts.
101 + *
102 + * @param array $activity The activity-object.
103 + * @param int[] $user_ids The ids of the local blog-users.
104 + * @param \Activitypub\Activity\Activity $activity_object Optional. The activity object. Default null.
105 + *
106 + * @return \WP_Post|\WP_Error|false The post on success, WP_Error on failure, false if already exists.
107 + */
108 + public static function create_post( $activity, $user_ids, $activity_object = null ) {
109 + if ( ! \get_option( 'activitypub_create_posts', false ) ) {
110 + return false;
111 + }
112 +
113 + $existing_post = Posts::get_by_guid( $activity['object']['id'] );
114 +
115 + // If post exists, call update action.
116 + if ( $existing_post instanceof \WP_Post ) {
117 + Update::handle_update( $activity, (array) $user_ids, $activity_object );
118 +
119 + return false;
120 + }
121 +
122 + return Posts::add( $activity, $user_ids );
123 + }
124 +
125 + /**
126 + * Validate the object.
127 + *
128 + * @param bool $valid The validation state.
129 + * @param string $param The object parameter.
130 + * @param \WP_REST_Request $request The request object.
131 + *
132 + * @return bool The validation state: true if valid, false if not.
133 + */
134 + public static function validate_object( $valid, $param, $request ) {
135 + $activity = $request->get_json_params();
136 +
137 + if ( empty( $activity['type'] ) ) {
138 + return false;
139 + }
140 +
141 + if ( 'Create' !== $activity['type'] ) {
142 + return $valid;
143 + }
144 +
145 + if ( ! isset( $activity['object'] ) || ! \is_array( $activity['object'] ) ) {
146 + return false;
147 + }
148 +
149 + if ( ! isset( $activity['object']['id'], $activity['object']['content'] ) ) {
150 + return false;
151 + }
152 +
153 + return $valid;
154 + }
155 +
156 + /**
157 + * Remove a URL from the tombstone registry when a Create or Update activity is sent.
158 + *
159 + * This handles the case where a post was soft-deleted (visibility changed to local/private)
160 + * and then later changed back to public. The Create/Update activity indicates the post is being
161 + * re-federated, so we remove it from the tombstone registry.
162 + *
163 + * @param int $outbox_id The ID of the outbox activity.
164 + * @param \Activitypub\Activity\Activity $activity The Activity object.
165 + */
166 + public static function maybe_unbury( $outbox_id, $activity ) {
167 + if ( ! in_array( $activity->get_type(), array( 'Create', 'Update' ), true ) ) {
49 168 return;
50 169 }
51 170
52 - $state = Interactions::add_comment( $array );
53 - $reaction = null;
171 + $object = $activity->get_object();
54 172
55 - if ( $state && ! \is_wp_error( $reaction ) ) {
56 - $reaction = \get_comment( $state );
173 + if ( $object ) {
174 + Tombstone::remove( $object->get_id(), $object->get_url() );
57 175 }
58 -
59 - \do_action( 'activitypub_handled_create', $array, $user_id, $state, $reaction );
60 176 }
61 177 }