Skip to content

Commit

Permalink
Include @mentions in the JSON representation of the reply (#1086)
Browse files Browse the repository at this point in the history
* Include @mentions in the JSON representation of the reply

See #844

* add tests

* added changelog

* PHPCS fixes

* PHPCS fixes

* remove unused WP_HTML_Tag_Processor class

props @obenland

* update tests

* add escaping

* Use factories and make callback removable

---------

Co-authored-by: Konstantin Obenland <obenland@gmx.de>
  • Loading branch information
pfefferle and obenland authored Dec 19, 2024
1 parent b2e14e9 commit 56308cd
Show file tree
Hide file tree
Showing 4 changed files with 237 additions and 19 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

* `@mentions` in the JSON representation of the reply

### Improved

* Direct Messages: Improve HTML to e-mail text conversion
Expand Down
94 changes: 75 additions & 19 deletions includes/transformer/class-comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,31 +53,30 @@ public function change_wp_user_id( $user_id ) {
* @return \Activitypub\Activity\Base_Object The ActivityPub Object.
*/
public function to_object() {
$comment = $this->wp_object;
$object = parent::to_object();

$object->set_url( $this->get_id() );
$object->set_type( 'Note' );
$object = parent::to_object();

$content = $this->get_content();
$at_replies = '';
$reply_context = $this->extract_reply_context( array() );

foreach ( $reply_context as $acct => $url ) {
$at_replies .= sprintf(
'<a class="u-mention mention" href="%s">%s</a> ',
esc_url( $url ),
esc_html( $acct )
);
}

$published = \strtotime( $comment->comment_date_gmt );
$object->set_published( \gmdate( 'Y-m-d\TH:i:s\Z', $published ) );
$at_replies = trim( $at_replies );

$updated = \get_comment_meta( $comment->comment_ID, 'activitypub_comment_modified', true );
if ( $updated > $published ) {
$object->set_updated( \gmdate( 'Y-m-d\TH:i:s\Z', $updated ) );
if ( $at_replies ) {
$content = sprintf( '<p>%s</p>%s', $at_replies, $content );
}

$object->set_content( $content );
$object->set_content_map(
array(
$this->get_locale() => $this->get_content(),
)
);
$path = sprintf( 'actors/%d/followers', intval( $comment->comment_author ) );

$object->set_to(
array(
'https://www.w3.org/ns/activitystreams#Public',
get_rest_url_by_path( $path ),
$this->get_locale() => $content,
)
);

Expand Down Expand Up @@ -308,4 +307,61 @@ public function get_locale() {
*/
return apply_filters( 'activitypub_comment_locale', $lang, $comment_id, $this->wp_object );
}

/**
* Returns the updated date of the comment.
*
* @return string|null The updated date of the comment.
*/
public function get_updated() {
$updated = \get_comment_meta( $this->wp_object->comment_ID, 'activitypub_comment_modified', true );
$published = \get_comment_meta( $this->wp_object->comment_ID, 'activitypub_comment_published', true );

if ( $updated > $published ) {
return \gmdate( 'Y-m-d\TH:i:s\Z', $updated );
}

return null;
}

/**
* Returns the published date of the comment.
*
* @return string The published date of the comment.
*/
public function get_published() {
return \gmdate( 'Y-m-d\TH:i:s\Z', \strtotime( $this->wp_object->comment_date_gmt ) );
}

/**
* Returns the URL of the comment.
*
* @return string The URL of the comment.
*/
public function get_url() {
return $this->get_id();
}

/**
* Returns the type of the comment.
*
* @return string The type of the comment.
*/
public function get_type() {
return 'Note';
}

/**
* Returns the to of the comment.
*
* @return array The to of the comment.
*/
public function get_to() {
$path = sprintf( 'actors/%d/followers', intval( $this->wp_object->comment_author ) );

return array(
'https://www.w3.org/ns/activitystreams#Public',
get_rest_url_by_path( $path ),
);
}
}
1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ For reasons of data protection, it is not possible to see the followers of other

= 4.5.1 =

* Added: `@mentions` in the JSON representation of the reply
* Improved: Reactions block: Remove the `wp-block-editor` dependency for frontend views
* Fixed: Direct Messages: Don't send notification for received public activities

Expand Down
157 changes: 157 additions & 0 deletions tests/includes/transformer/class-test-comment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php
/**
* Test file for Comment transformer.
*
* @package ActivityPub
*/

namespace Activitypub\Tests\Transformer;

use Activitypub\Transformer\Comment;

/**
* Test class for Comment Transformer.
*
* @coversDefaultClass \Activitypub\Transformer\Comment
*/
class Test_Comment extends \WP_UnitTestCase {
/**
* Test post ID.
*
* @var int
*/
protected static $post_id;

/**
* Create fake data before tests run.
*
* @param \WP_UnitTest_Factory $factory Helper that creates fake data.
*/
public static function wpSetUpBeforeClass( $factory ) {
self::$post_id = $factory->post->create();

// Mock the WebFinger wp_safe_remote_get.
add_filter( 'pre_http_request', array( self::class, 'pre_http_request' ), 10, 3 );
}

/**
* Clean up after tests.
*/
public static function wpTearDownAfterClass() {
wp_delete_post( self::$post_id, true );
remove_filter( 'pre_http_request', array( self::class, 'pre_http_request' ) );
}

/**
* Test content generation with reply context.
*
* @covers ::to_object
*/
public function test_content_with_reply_context() {
// Create a parent ActivityPub comment.
$parent_comment_id = self::factory()->comment->create(
array(
'comment_post_ID' => self::$post_id,
'comment_author_url' => 'https://remote.example/@author',
'comment_meta' => array(
'protocol' => 'activitypub',
),
)
);

// Create a reply comment.
$reply_comment_id = self::factory()->comment->create(
array(
'comment_post_ID' => self::$post_id,
'comment_parent' => $parent_comment_id,
'comment_author_url' => 'https://example.net/@remote',
'comment_meta' => array(
'protocol' => 'activitypub',
),
)
);

// Create a reply comment.
$test_comment_id = self::factory()->comment->create(
array(
'comment_post_ID' => self::$post_id,
'comment_parent' => $reply_comment_id,
'comment_author_url' => 'https://example.com/@test',
)
);

// Transform comment to ActivityPub object.
$comment = get_comment( $test_comment_id );
$transformer = new Comment( $comment );
$object = $transformer->to_object();

// Get the content.
$content = $object->get_content();

// Test that reply context is added.
$this->assertEquals( '<p><a class="u-mention mention" href="https://example.net/@remote">@remote@example.net</a> <a class="u-mention mention" href="https://remote.example/@author">@author@remote.example</a></p><p>This is a comment</p>', $content );

// Clean up.
wp_delete_comment( $reply_comment_id, true );
wp_delete_comment( $parent_comment_id, true );
wp_delete_comment( $test_comment_id, true );
}

/**
* Test content generation with reply context.
*
* @param mixed $data The response data.
* @param array $parsed_args The request arguments.
* @param string $url The request URL.
* @return mixed The response data.
*/
public static function pre_http_request( $data, $parsed_args, $url ) {
if ( str_starts_with( $url, 'https://remote.example' ) ) {
return self::dummy_response(
wp_json_encode(
array(
'subject' => 'acct:author@remote.example',
'links' => array(
'self' => array( 'href' => 'https://remote.example/@author' ),
),
)
)
);
}

if ( str_starts_with( $url, 'https://example.net/' ) ) {
return self::dummy_response(
wp_json_encode(
array(
'subject' => 'https://example.net/@remote',
'aliases' => array(
'acct:remote@example.net',
),
'links' => array(
'self' => array( 'href' => 'https://example.net/@remote' ),
),
)
)
);
}

return $data;
}

/**
* Create a dummy response.
*
* @param string $body The body of the response.
*
* @return array The dummy response.
*/
private static function dummy_response( $body ) {
return array(
'headers' => array(),
'body' => $body,
'response' => array( 'code' => 200 ),
'cookies' => array(),
'filename' => null,
);
}
}

0 comments on commit 56308cd

Please sign in to comment.