@@ -27,32 +27,59 @@ class Inbox {
2727 */
2828 const POST_TYPE = 'ap_inbox ' ;
2929
30+ /**
31+ * Context for user inbox requests.
32+ *
33+ * @var string
34+ */
35+ const CONTEXT_INBOX = 'inbox ' ;
36+
37+ /**
38+ * Context for shared inbox requests.
39+ *
40+ * @var string
41+ */
42+ const CONTEXT_SHARED_INBOX = 'shared_inbox ' ;
43+
3044 /**
3145 * Add an activity to the inbox.
3246 *
33- * @param Activity|\WP_Error $activity The Activity object.
34- * @param int $user_id The id of the local blog-user.
47+ * @param Activity|\WP_Error $activity The Activity object.
48+ * @param int|array $recipients The id(s) of the local blog-user(s) .
3549 *
3650 * @return false|int|\WP_Error The added item or an error.
3751 */
38- public static function add ( $ activity , $ user_id ) {
52+ public static function add ( $ activity , $ recipients ) {
3953 if ( \is_wp_error ( $ activity ) ) {
4054 return $ activity ;
4155 }
4256
43- $ item = self ::get_by_guid ( $ activity ->get_id () );
57+ // Sanitize recipients.
58+ $ recipients = \array_map ( 'absint ' , (array ) $ recipients );
59+ $ recipients = \array_unique ( $ recipients );
60+ $ recipients = \array_values ( $ recipients );
61+
62+ if ( empty ( $ recipients ) ) {
63+ return new \WP_Error (
64+ 'activitypub_inbox_no_recipients ' ,
65+ 'No valid recipients provided ' ,
66+ array ( 'status ' => 400 )
67+ );
68+ }
69+
70+ // Check if activity already exists (by GUID).
71+ $ existing = self ::get_by_guid ( $ activity ->get_id () );
4472
45- // Check for duplicate activity.
46- if ( $ item instanceof \WP_Post ) {
47- // Ensure that it is added to the inbox of the user.
48- $ user_ids = \get_post_meta ( $ item ->ID , '_activitypub_user_id ' , false );
49- if ( ! \in_array ( (string ) $ user_id , $ user_ids , true ) ) {
50- \add_post_meta ( $ item ->ID , '_activitypub_user_id ' , $ user_id );
51- \clean_post_cache ( $ item ->ID );
73+ // If activity exists, add new recipients to it.
74+ if ( $ existing instanceof \WP_Post ) {
75+ foreach ( $ recipients as $ user_id ) {
76+ self ::add_recipient ( $ existing ->ID , $ user_id );
5277 }
53- return $ item ->ID ;
78+
79+ return $ existing ->ID ;
5480 }
5581
82+ // Activity doesn't exist, create new post.
5683 $ title = self ::get_object_title ( $ activity ->get_object () );
5784 $ visibility = is_activity_public ( $ activity ) ? ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC : ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE ;
5885
@@ -65,12 +92,12 @@ public static function add( $activity, $user_id ) {
6592 \wp_trim_words ( $ title , 5 )
6693 ),
6794 'post_content ' => wp_slash ( $ activity ->to_json () ),
95+ 'post_author ' => 0 , // No specific author, recipients stored in meta.
6896 'post_status ' => 'publish ' ,
6997 'guid ' => $ activity ->get_id (),
7098 'meta_input ' => array (
7199 '_activitypub_object_id ' => object_to_uri ( $ activity ->get_object () ),
72100 '_activitypub_activity_type ' => $ activity ->get_type (),
73- '_activitypub_user_id ' => $ user_id ,
74101 '_activitypub_activity_remote_actor ' => object_to_uri ( $ activity ->get_actor () ),
75102 'activitypub_content_visibility ' => $ visibility ,
76103 ),
@@ -88,6 +115,13 @@ public static function add( $activity, $user_id ) {
88115 \kses_init_filters ();
89116 }
90117
118+ // Add recipients as separate meta entries after post is created.
119+ if ( ! \is_wp_error ( $ id ) ) {
120+ foreach ( $ recipients as $ user_id ) {
121+ self ::add_recipient ( $ id , $ user_id );
122+ }
123+ }
124+
91125 return $ id ;
92126 }
93127
@@ -222,4 +256,106 @@ public static function undo( $id ) {
222256 );
223257 }
224258 }
259+
260+ /**
261+ * Get all recipients for an inbox activity.
262+ *
263+ * @param int $post_id The inbox post ID.
264+ *
265+ * @return array Array of user IDs who are recipients.
266+ */
267+ public static function get_recipients ( $ post_id ) {
268+ // Get all meta values with key '_activitypub_user_id' (single => false).
269+ $ recipients = \get_post_meta ( $ post_id , '_activitypub_user_id ' , false );
270+ $ recipients = \array_map ( 'intval ' , $ recipients );
271+
272+ return $ recipients ;
273+ }
274+
275+ /**
276+ * Check if a user is a recipient of an inbox activity.
277+ *
278+ * @param int $post_id The inbox post ID.
279+ * @param int $user_id The user ID to check.
280+ *
281+ * @return bool True if user is a recipient, false otherwise.
282+ */
283+ public static function has_recipient ( $ post_id , $ user_id ) {
284+ $ recipients = self ::get_recipients ( $ post_id );
285+
286+ return \in_array ( (int ) $ user_id , $ recipients , true );
287+ }
288+
289+ /**
290+ * Add a recipient to an existing inbox activity.
291+ *
292+ * @param int $post_id The inbox post ID.
293+ * @param int $user_id The user ID to add.
294+ *
295+ * @return bool True on success, false on failure.
296+ */
297+ public static function add_recipient ( $ post_id , $ user_id ) {
298+ $ user_id = (int ) $ user_id ;
299+ // Allow 0 for blog user, but reject negative values.
300+ if ( $ user_id < 0 ) {
301+ return false ;
302+ }
303+
304+ // Check if already a recipient.
305+ if ( self ::has_recipient ( $ post_id , $ user_id ) ) {
306+ return true ;
307+ }
308+
309+ // Add new recipient as separate meta entry.
310+ return (bool ) \add_post_meta ( $ post_id , '_activitypub_user_id ' , $ user_id , false );
311+ }
312+
313+ /**
314+ * Remove a recipient from an inbox activity.
315+ *
316+ * @param int $post_id The inbox post ID.
317+ * @param int $user_id The user ID to remove.
318+ *
319+ * @return bool True on success, false on failure.
320+ */
321+ public static function remove_recipient ( $ post_id , $ user_id ) {
322+ $ user_id = (int ) $ user_id ;
323+
324+ // Allow 0 for blog user, but reject negative values.
325+ if ( $ user_id < 0 ) {
326+ return false ;
327+ }
328+
329+ // Delete the specific meta entry with this value.
330+ return \delete_post_meta ( $ post_id , '_activitypub_user_id ' , $ user_id );
331+ }
332+
333+ /**
334+ * Get an inbox item by GUID for a specific recipient.
335+ *
336+ * This checks both that the activity exists and that the user is a valid recipient.
337+ *
338+ * @param string $guid The activity GUID.
339+ * @param int $user_id The user ID.
340+ *
341+ * @return \WP_Post|\WP_Error The inbox item or WP_Error.
342+ */
343+ public static function get_by_guid_and_recipient ( $ guid , $ user_id ) {
344+ $ post = self ::get_by_guid ( $ guid );
345+
346+ if ( \is_wp_error ( $ post ) ) {
347+ return $ post ;
348+ }
349+
350+ // Check if user is a recipient.
351+ if ( ! self ::has_recipient ( $ post ->ID , $ user_id ) ) {
352+ return new \WP_Error (
353+ 'activitypub_inbox_not_recipient ' ,
354+ 'User is not a recipient of this activity ' ,
355+ array ( 'status ' => 404 )
356+ );
357+ }
358+
359+ return $ post ;
360+ }
225361}
0 commit comments