Skip to content

Commit

Permalink
Add "visibility" feature (#931)
Browse files Browse the repository at this point in the history
  • Loading branch information
pfefferle authored Oct 16, 2024
1 parent 4b488cf commit 7ca9a58
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 51 deletions.
6 changes: 6 additions & 0 deletions activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@
\defined( 'ACTIVITYPUB_SEND_VARY_HEADER' ) || \define( 'ACTIVITYPUB_SEND_VARY_HEADER', false );
\defined( 'ACTIVITYPUB_DEFAULT_OBJECT_TYPE' ) || \define( 'ACTIVITYPUB_DEFAULT_OBJECT_TYPE', 'note' );

// Post visibility constants.
\define( 'ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC', '' );
\define( 'ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC', 'quiet_public' );
\define( 'ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL', 'local' );

// Plugin related constants.
\define( 'ACTIVITYPUB_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
\define( 'ACTIVITYPUB_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
\define( 'ACTIVITYPUB_PLUGIN_FILE', plugin_dir_path( __FILE__ ) . '/' . basename( __FILE__ ) );
Expand Down
2 changes: 1 addition & 1 deletion build/editor-plugin/plugin.asset.php
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('react', 'wp-components', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-i18n', 'wp-plugins'), 'version' => '88603987940fec29730d');
<?php return array('dependencies' => array('react', 'wp-components', 'wp-core-data', 'wp-data', 'wp-editor', 'wp-element', 'wp-i18n', 'wp-plugins', 'wp-primitives'), 'version' => '92b35e5bbecef58deaf6');
2 changes: 1 addition & 1 deletion build/editor-plugin/plugin.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions includes/class-activity-dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,20 @@ public static function add_inboxes_of_follower( $inboxes, $user_id ) {
*/
public static function add_inboxes_by_mentioned_actors( $inboxes, $user_id, $activity ) {
$cc = $activity->get_cc();
if ( $cc ) {
$mentioned_inboxes = Mention::get_inboxes( $cc );
$to = $activity->get_to();

$audience = array_merge( $cc, $to );

// Remove "public placeholder" and "same domain" from the audience.
$audience = array_filter(
$audience,
function ( $actor ) {
return 'https://www.w3.org/ns/activitystreams#Public' !== $actor && ! is_same_domain( $actor );
}
);

if ( $audience ) {
$mentioned_inboxes = Mention::get_inboxes( $audience );

return array_merge( $inboxes, $mentioned_inboxes );
}
Expand Down
2 changes: 1 addition & 1 deletion includes/class-activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static function render_json_template( $template ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/user-json.php';
} elseif ( is_comment() ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/comment-json.php';
} elseif ( \is_singular() ) {
} elseif ( \is_singular() && ! is_post_disabled( \get_the_ID() ) ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/post-json.php';
} elseif ( \is_home() && ! is_user_type_disabled( 'blog' ) ) {
$json_template = ACTIVITYPUB_PLUGIN_DIR . '/templates/blog-json.php';
Expand Down
29 changes: 28 additions & 1 deletion includes/class-blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,34 @@ public static function register_postmeta() {
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
'sanitize_callback' => function ( $warning ) {
if ( $warning ) {
return \sanitize_text_field( $warning );
}

return null;
},
)
);
\register_post_meta(
$post_type,
'activitypub_content_visibility',
array(
'show_in_rest' => true,
'single' => true,
'type' => 'string',
'sanitize_callback' => function ( $visibility ) {
$options = array(
ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC,
ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL,
);

if ( in_array( $visibility, $options, true ) ) {
return $visibility;
}

return null;
},
)
);
}
Expand Down
2 changes: 1 addition & 1 deletion includes/class-scheduler.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public static function deregister_schedules() {
public static function schedule_post_activity( $new_status, $old_status, $post ) {
$post = get_post( $post );

if ( ! $post ) {
if ( ! $post || is_post_disabled( $post ) ) {
return;
}

Expand Down
119 changes: 96 additions & 23 deletions includes/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,31 @@ function is_activitypub_request() {
return false;
}

/**
* Check if a post is disabled for ActivityPub.
*
* @param mixed $post The post object or ID.
*
* @return boolean True if the post is disabled, false otherwise.
*/
function is_post_disabled( $post ) {
$post = \get_post( $post );
$disabled = false;
$visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true );

if ( ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL === $visibility ) {
$disabled = true;
}

/*
* Allow plugins to disable posts for ActivityPub.
*
* @param boolean $disabled True if the post is disabled, false otherwise.
* @param \WP_Post $post The post object.
*/
return \apply_filters( 'activitypub_is_post_disabled', $disabled, $post );
}

/**
* This function checks if a user is disabled for ActivityPub.
*
Expand All @@ -408,50 +433,50 @@ function is_activitypub_request() {
* @return boolean True if the user is disabled, false otherwise.
*/
function is_user_disabled( $user_id ) {
$return = false;
$disabled = false;

switch ( $user_id ) {
// if the user is the application user, it's always enabled.
case \Activitypub\Collection\Users::APPLICATION_USER_ID:
$return = false;
$disabled = false;
break;
// if the user is the blog user, it's only enabled in single-user mode.
case \Activitypub\Collection\Users::BLOG_USER_ID:
if ( is_user_type_disabled( 'blog' ) ) {
$return = true;
$disabled = true;
break;
}

$return = false;
$disabled = false;
break;
// if the user is any other user, it's enabled if it can publish posts.
default:
if ( ! \get_user_by( 'id', $user_id ) ) {
$return = true;
$disabled = true;
break;
}

if ( is_user_type_disabled( 'user' ) ) {
$return = true;
$disabled = true;
break;
}

if ( ! \user_can( $user_id, 'activitypub' ) ) {
$return = true;
$disabled = true;
break;
}

$return = false;
$disabled = false;
break;
}

/**
* Allow plugins to disable users for ActivityPub.
*
* @param boolean $return True if the user is disabled, false otherwise.
* @param int $user_id The User-ID.
* @param boolean $disabled True if the user is disabled, false otherwise.
* @param int $user_id The User-ID.
*/
return apply_filters( 'activitypub_is_user_disabled', $return, $user_id );
return apply_filters( 'activitypub_is_user_disabled', $disabled, $user_id );
}

/**
Expand All @@ -469,45 +494,45 @@ function is_user_type_disabled( $type ) {
case 'blog':
if ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) ) {
if ( ACTIVITYPUB_SINGLE_USER_MODE ) {
$return = false;
$disabled = false;
break;
}
}

if ( \defined( 'ACTIVITYPUB_DISABLE_BLOG_USER' ) ) {
$return = ACTIVITYPUB_DISABLE_BLOG_USER;
$disabled = ACTIVITYPUB_DISABLE_BLOG_USER;
break;
}

if ( '1' !== \get_option( 'activitypub_enable_blog_user', '0' ) ) {
$return = true;
$disabled = true;
break;
}

$return = false;
$disabled = false;
break;
case 'user':
if ( \defined( 'ACTIVITYPUB_SINGLE_USER_MODE' ) ) {
if ( ACTIVITYPUB_SINGLE_USER_MODE ) {
$return = true;
$disabled = true;
break;
}
}

if ( \defined( 'ACTIVITYPUB_DISABLE_USER' ) ) {
$return = ACTIVITYPUB_DISABLE_USER;
$disabled = ACTIVITYPUB_DISABLE_USER;
break;
}

if ( '1' !== \get_option( 'activitypub_enable_users', '1' ) ) {
$return = true;
$disabled = true;
break;
}

$return = false;
$disabled = false;
break;
default:
$return = new WP_Error(
$disabled = new WP_Error(
'activitypub_wrong_user_type',
__( 'Wrong user type', 'activitypub' ),
array( 'status' => 400 )
Expand All @@ -518,10 +543,10 @@ function is_user_type_disabled( $type ) {
/**
* Allow plugins to disable user types for ActivityPub.
*
* @param boolean $return True if the user type is disabled, false otherwise.
* @param string $type The User-Type.
* @param boolean $disabled True if the user type is disabled, false otherwise.
* @param string $type The User-Type.
*/
return apply_filters( 'activitypub_is_user_type_disabled', $return, $type );
return apply_filters( 'activitypub_is_user_type_disabled', $disabled, $type );
}

/**
Expand Down Expand Up @@ -1334,3 +1359,51 @@ function get_content_warning( $post_id ) {

return $warning;
}

/**
* Check if a URL is from the same domain as the site.
*
* @param string $url The URL to check.
*
* @return boolean True if the URL is from the same domain, false otherwise.
*/
function is_same_domain( $url ) {
$remote = \wp_parse_url( $url, PHP_URL_HOST );

if ( ! $remote ) {
return false;
}

$remote = normalize_host( $remote );
$self = \wp_parse_url( \home_url(), PHP_URL_HOST );
$self = normalize_host( $self );

return $remote === $self;
}

/**
* Get the visibility of a post.
*
* @param int $post_id The post ID.
*
* @return string|false The visibility of the post or false if not found.
*/
function get_content_visibility( $post_id ) {
$post = get_post( $post_id );
if ( ! $post ) {
return false;
}

$visibility = get_post_meta( $post->ID, 'activitypub_content_visibility', true );
$_visibility = ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC;
$options = array(
ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC,
ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL,
);

if ( in_array( $visibility, $options, true ) ) {
$_visibility = $visibility;
}

return \apply_filters( 'activitypub_content_visibility', $_visibility, $post );
}
40 changes: 24 additions & 16 deletions includes/transformer/class-post.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
use function Activitypub\esc_hashtag;
use function Activitypub\is_single_user;
use function Activitypub\get_enclosures;
use function Activitypub\get_content_warning;
use function Activitypub\site_supports_blocks;
use function Activitypub\generate_post_summary;
use function Activitypub\get_content_warning;
use function Activitypub\get_content_visibility;

/**
* WordPress Post Transformer.
Expand Down Expand Up @@ -77,6 +78,12 @@ public function to_object() {
$object->set_summary_map( null );
}

// Change order if visibility is "Quiet public".
if ( ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC === get_content_visibility( $post ) ) {
$object->set_to( $this->get_cc() );
$object->set_cc( $this->get_to() );
}

return $object;
}

Expand Down Expand Up @@ -686,6 +693,19 @@ protected function get_type() {
return $object_type;
}

/**
* Returns the recipient of the post.
*
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-to
*
* @return array The recipient URLs of the post.
*/
public function get_to() {
return array(
'https://www.w3.org/ns/activitystreams#Public',
);
}

/**
* Returns a list of Mentions, used in the Post.
*
Expand All @@ -694,7 +714,9 @@ protected function get_type() {
* @return array The list of Mentions.
*/
protected function get_cc() {
$cc = array();
$cc = array(
$this->get_actor_object()->get_followers(),
);

$mentions = $this->get_mentions();
if ( $mentions ) {
Expand Down Expand Up @@ -952,20 +974,6 @@ public function get_in_reply_to() {
return null;
}

/**
* Returns the recipient of the post.
*
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-to
*
* @return array The recipient URLs of the post.
*/
public function get_to() {
return array(
'https://www.w3.org/ns/activitystreams#Public',
$this->get_actor_object()->get_followers(),
);
}

/**
* Returns the published date of the post.
*
Expand Down
2 changes: 1 addition & 1 deletion src/editor-plugin/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
"keywords": [
],
"editorScript": "file:./plugin.js"
}
}
Loading

0 comments on commit 7ca9a58

Please sign in to comment.