wordpress-activitypub/includes/model/class-blog.php

534 lines
10 KiB
PHP
Raw Normal View History

<?php
/**
* Blog model file.
*
* @package Activitypub
*/
namespace Activitypub\Model;
use WP_Query;
Add/event objects (#629) * remove redundant property definitions * Add redused context for actors. * Add classes to construct Moblizon compatible events * Bind the context to the activitypub object - change the propertyname which stores the json-ld context from context to _context, because context is already reserved in the ActivityStreams vocabulary. - cleanup currently unused code * fix phpcs * Remove PostalAddress object: it's enough (at least atm) to directly write the array in transformers. * Remove _context property from ActivityPub objects in favour of getter function get_json_ld_context() * fix unit tests: ActivityPub Activity objects have a custom getter for the JsonLD context * fix phpcs * fix unit-tests to also support php5.6 * fix phpcs * add param include_json_ld_context to to_array function This allows to not set the @context in the resulting array. * propagate the param include_json_ld_context to nested calls of to_array. * fix phpcs * Nested AcitivityPub objects: never build context in inner items in to_array function * fix: param of set_address may also be an array * fix typo in comment * always prefix json-ld context with json-ld and move event class to sub-namespace * fix usage of reserved object keyword seems it should not be used as a namespace either * Merge commit 'b2271cda6b857f879e0abd4f3c6683642d725267' into add/event-objects * Fix calling non-static function as static Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com> * Partly fix Json-LD contexts in collections * Update includes/activity/class-base-object.php * this is implicit We already set the correct user with `$transformer->change_wp_user_id( $user_id );` so the Actor will be generated properly. We can change the behaviour, but we should not use both. * this change prevents the Activity to re-use Object vars this should stay as is, because it pre-fills the Activity with data (for example cc and to) and it will no longer be done with your change. It is on purpose that it first sets the object and then replaces it with the URI. See: https://github.com/Automattic/wordpress-activitypub/blob/master/includes/activity/class-activity.php#L195 * add `$include_json_ld_context` support to `to_json` * disable some more contexts * remove whitespace * Add php-comment for 7ed17c042a2651e08afc790adbdfc5ccf46c2708 * Fix JSON-LD context for ActivityPub objects: child classes may override it. * coding standards * call folder/namespace `Extended_Object` to be consistent with folder names in singular * fix: unnessesary nesting of extended-objects * remove license I hope this is fine, to have the complete plugin under the MIT @Menrath ?!? --------- Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com>
2024-01-18 15:35:52 +00:00
use Activitypub\Signature;
use Activitypub\Activity\Actor;
2023-07-03 09:20:44 +00:00
use Activitypub\Collection\Users;
use Activitypub\Collection\Extra_Fields;
use function Activitypub\esc_hashtag;
use function Activitypub\is_single_user;
2024-09-12 14:55:14 +00:00
use function Activitypub\is_blog_public;
use function Activitypub\get_rest_url_by_path;
2023-06-28 14:43:41 +00:00
/**
* Blog class.
*/
class Blog extends Actor {
/**
* The Featured-Posts.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#featured
*
* @context {
* "@id": "http://joinmastodon.org/ns#featured",
* "@type": "@id"
* }
*
* @var string
*/
protected $featured;
/**
* Moderators endpoint.
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var string
*/
protected $moderators;
/**
* The User-ID
*
* @var int
*/
2023-07-03 09:20:44 +00:00
protected $_id = Users::BLOG_USER_ID; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
/**
* If the User is indexable.
*
* @context http://joinmastodon.org/ns#indexable
*
* @var boolean
*/
protected $indexable;
/**
* The WebFinger Resource.
*
* @var string
*/
protected $webfinger;
/**
* Whether the User is discoverable.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#discoverable
*
* @context http://joinmastodon.org/ns#discoverable
*
* @var boolean
*/
protected $discoverable;
/**
* Restrict posting to mods.
*
* @see https://join-lemmy.org/docs/contributors/05-federation.html
*
* @var boolean
*/
protected $posting_restricted_to_mods;
/**
* Whether the User manually approves followers.
*
* @return false
*/
Add/event objects (#629) * remove redundant property definitions * Add redused context for actors. * Add classes to construct Moblizon compatible events * Bind the context to the activitypub object - change the propertyname which stores the json-ld context from context to _context, because context is already reserved in the ActivityStreams vocabulary. - cleanup currently unused code * fix phpcs * Remove PostalAddress object: it's enough (at least atm) to directly write the array in transformers. * Remove _context property from ActivityPub objects in favour of getter function get_json_ld_context() * fix unit tests: ActivityPub Activity objects have a custom getter for the JsonLD context * fix phpcs * fix unit-tests to also support php5.6 * fix phpcs * add param include_json_ld_context to to_array function This allows to not set the @context in the resulting array. * propagate the param include_json_ld_context to nested calls of to_array. * fix phpcs * Nested AcitivityPub objects: never build context in inner items in to_array function * fix: param of set_address may also be an array * fix typo in comment * always prefix json-ld context with json-ld and move event class to sub-namespace * fix usage of reserved object keyword seems it should not be used as a namespace either * Merge commit 'b2271cda6b857f879e0abd4f3c6683642d725267' into add/event-objects * Fix calling non-static function as static Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com> * Partly fix Json-LD contexts in collections * Update includes/activity/class-base-object.php * this is implicit We already set the correct user with `$transformer->change_wp_user_id( $user_id );` so the Actor will be generated properly. We can change the behaviour, but we should not use both. * this change prevents the Activity to re-use Object vars this should stay as is, because it pre-fills the Activity with data (for example cc and to) and it will no longer be done with your change. It is on purpose that it first sets the object and then replaces it with the URI. See: https://github.com/Automattic/wordpress-activitypub/blob/master/includes/activity/class-activity.php#L195 * add `$include_json_ld_context` support to `to_json` * disable some more contexts * remove whitespace * Add php-comment for 7ed17c042a2651e08afc790adbdfc5ccf46c2708 * Fix JSON-LD context for ActivityPub objects: child classes may override it. * coding standards * call folder/namespace `Extended_Object` to be consistent with folder names in singular * fix: unnessesary nesting of extended-objects * remove license I hope this is fine, to have the complete plugin under the MIT @Menrath ?!? --------- Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com>
2024-01-18 15:35:52 +00:00
public function get_manually_approves_followers() {
return false;
}
/**
* Whether the User is discoverable.
*
* @return boolean
*/
Add/event objects (#629) * remove redundant property definitions * Add redused context for actors. * Add classes to construct Moblizon compatible events * Bind the context to the activitypub object - change the propertyname which stores the json-ld context from context to _context, because context is already reserved in the ActivityStreams vocabulary. - cleanup currently unused code * fix phpcs * Remove PostalAddress object: it's enough (at least atm) to directly write the array in transformers. * Remove _context property from ActivityPub objects in favour of getter function get_json_ld_context() * fix unit tests: ActivityPub Activity objects have a custom getter for the JsonLD context * fix phpcs * fix unit-tests to also support php5.6 * fix phpcs * add param include_json_ld_context to to_array function This allows to not set the @context in the resulting array. * propagate the param include_json_ld_context to nested calls of to_array. * fix phpcs * Nested AcitivityPub objects: never build context in inner items in to_array function * fix: param of set_address may also be an array * fix typo in comment * always prefix json-ld context with json-ld and move event class to sub-namespace * fix usage of reserved object keyword seems it should not be used as a namespace either * Merge commit 'b2271cda6b857f879e0abd4f3c6683642d725267' into add/event-objects * Fix calling non-static function as static Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com> * Partly fix Json-LD contexts in collections * Update includes/activity/class-base-object.php * this is implicit We already set the correct user with `$transformer->change_wp_user_id( $user_id );` so the Actor will be generated properly. We can change the behaviour, but we should not use both. * this change prevents the Activity to re-use Object vars this should stay as is, because it pre-fills the Activity with data (for example cc and to) and it will no longer be done with your change. It is on purpose that it first sets the object and then replaces it with the URI. See: https://github.com/Automattic/wordpress-activitypub/blob/master/includes/activity/class-activity.php#L195 * add `$include_json_ld_context` support to `to_json` * disable some more contexts * remove whitespace * Add php-comment for 7ed17c042a2651e08afc790adbdfc5ccf46c2708 * Fix JSON-LD context for ActivityPub objects: child classes may override it. * coding standards * call folder/namespace `Extended_Object` to be consistent with folder names in singular * fix: unnessesary nesting of extended-objects * remove license I hope this is fine, to have the complete plugin under the MIT @Menrath ?!? --------- Co-authored-by: Matthias Pfefferle <pfefferle@users.noreply.github.com>
2024-01-18 15:35:52 +00:00
public function get_discoverable() {
return true;
}
/**
* Get the User ID.
*
* @return string The User ID.
*/
public function get_id() {
return $this->get_url();
}
/**
* Get the type of the object.
*
* If the Blog is in "single user" mode, return "Person" insted of "Group".
*
* @return string The type of the object.
*/
public function get_type() {
if ( is_single_user() ) {
return 'Person';
} else {
return 'Group';
}
}
/**
* Get the Username.
*
* @return string The Username.
*/
public function get_name() {
return \wp_strip_all_tags(
\html_entity_decode(
\get_bloginfo( 'name' ),
\ENT_QUOTES,
'UTF-8'
)
);
}
/**
* Get the User description.
*
* @return string The User description.
*/
public function get_summary() {
2024-07-22 09:16:38 +00:00
$summary = \get_option( 'activitypub_blog_description', null );
if ( ! $summary ) {
$summary = \get_bloginfo( 'description' );
}
2023-06-14 13:02:45 +00:00
return \wpautop(
\wp_kses(
$summary,
2023-06-14 13:02:45 +00:00
'default'
)
);
}
/**
* Get the User url.
*
* @return string The User url.
*/
public function get_url() {
return \esc_url( \trailingslashit( get_home_url() ) . '@' . $this->get_preferred_username() );
}
/**
* Get blog's homepage URL.
*
* @return string The User-Url.
*/
public function get_alternate_url() {
return \esc_url( \trailingslashit( get_home_url() ) );
}
2023-05-30 09:22:20 +00:00
/**
2023-07-11 12:34:11 +00:00
* Generate a default Username.
2023-05-30 09:22:20 +00:00
*
* @return string The auto-generated Username.
*/
public static function get_default_username() {
// Check if domain host has a subdomain.
$host = \wp_parse_url( \get_home_url(), \PHP_URL_HOST );
$host = \preg_replace( '/^www\./i', '', $host );
2023-05-30 09:22:20 +00:00
2023-07-11 12:34:11 +00:00
/**
* Filters the default blog username.
2023-07-11 12:34:11 +00:00
*
2023-07-14 09:29:03 +00:00
* @param string $host The default username.
2023-07-11 12:34:11 +00:00
*/
2023-07-14 09:29:03 +00:00
return apply_filters( 'activitypub_default_blog_username', $host );
2023-05-30 09:22:20 +00:00
}
2023-07-11 12:34:11 +00:00
/**
* Get the preferred Username.
2023-07-11 12:34:11 +00:00
*
* @return string The Username.
2023-07-11 12:34:11 +00:00
*/
2023-07-05 13:32:26 +00:00
public function get_preferred_username() {
2024-07-22 09:16:38 +00:00
$username = \get_option( 'activitypub_blog_identifier' );
2023-07-11 07:21:16 +00:00
if ( $username ) {
return $username;
}
2023-05-30 09:22:20 +00:00
return self::get_default_username();
}
2023-07-11 12:34:11 +00:00
/**
* Get the User icon.
2023-07-11 12:34:11 +00:00
*
* @return array The User icon.
2023-07-11 12:34:11 +00:00
*/
2023-07-05 13:32:26 +00:00
public function get_icon() {
// Try site_logo, falling back to site_icon, first.
$icon_id = get_option( 'site_icon' );
// Try custom logo second.
if ( ! $icon_id ) {
$icon_id = get_theme_mod( 'custom_logo' );
}
$icon_url = false;
if ( $icon_id ) {
$icon = wp_get_attachment_image_src( $icon_id, 'full' );
if ( $icon ) {
$icon_url = $icon[0];
}
}
if ( ! $icon_url ) {
// Fallback to default icon.
$icon_url = plugins_url( '/assets/img/wp-logo.png', ACTIVITYPUB_PLUGIN_FILE );
2023-07-05 13:32:26 +00:00
}
return array(
'type' => 'Image',
'url' => esc_url( $icon_url ),
);
}
2023-07-11 12:34:11 +00:00
/**
* Get the User-Header-Image.
*
* @return array|null The User-Header-Image.
*/
2024-07-15 21:20:09 +00:00
public function get_image() {
$header_image = get_option( 'activitypub_header_image' );
2024-07-24 13:21:46 +00:00
$image_url = null;
if ( $header_image ) {
$image_url = \wp_get_attachment_url( $header_image );
}
if ( ! $image_url && \has_header_image() ) {
$image_url = \get_header_image();
}
if ( $image_url ) {
2023-07-05 13:32:26 +00:00
return array(
'type' => 'Image',
'url' => esc_url( $image_url ),
2023-07-05 13:32:26 +00:00
);
}
return null;
}
/**
* Get the published date.
*
* @return string The published date.
*/
public function get_published() {
$first_post = new WP_Query(
array(
'orderby' => 'date',
'order' => 'ASC',
'number' => 1,
)
);
if ( ! empty( $first_post->posts[0] ) ) {
$time = \strtotime( $first_post->posts[0]->post_date_gmt );
} else {
$time = \time();
}
return \gmdate( 'Y-m-d\TH:i:s\Z', $time );
}
2023-05-24 15:27:46 +00:00
/**
* Get the canonical URL.
*
* @return string|null The canonical URL.
*/
public function get_canonical_url() {
return \home_url();
}
/**
* Get the Moderators endpoint.
*
* @return string|null The Moderators endpoint.
*/
public function get_moderators() {
if ( is_single_user() || 'Group' !== $this->get_type() ) {
return null;
}
return get_rest_url_by_path( 'collections/moderators' );
}
/**
* Get attributedTo value.
*
* @return string|null The attributedTo value.
*/
2023-09-27 09:08:55 +00:00
public function get_attributed_to() {
if ( is_single_user() || 'Group' !== $this->get_type() ) {
return null;
}
return get_rest_url_by_path( 'collections/moderators' );
}
/**
* Get the public key information.
*
* @return array The public key.
*/
public function get_public_key() {
return array(
'id' => $this->get_id() . '#main-key',
'owner' => $this->get_id(),
'publicKeyPem' => Signature::get_public_key_for( $this->get__id() ),
);
}
/**
* Returns whether posting is restricted to mods.
*
* @return bool|null True if posting is restricted to mods, null if not applicable.
*/
public function get_posting_restricted_to_mods() {
if ( 'Group' === $this->get_type() ) {
return true;
}
return null;
}
/**
* Returns the Inbox-API-Endpoint.
*
* @return string The Inbox-Endpoint.
*/
public function get_inbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/inbox', $this->get__id() ) );
}
/**
* Returns the Outbox-API-Endpoint.
*
* @return string The Outbox-Endpoint.
*/
public function get_outbox() {
return get_rest_url_by_path( sprintf( 'actors/%d/outbox', $this->get__id() ) );
}
/**
* Returns the Followers-API-Endpoint.
*
* @return string The Followers-Endpoint.
*/
public function get_followers() {
return get_rest_url_by_path( sprintf( 'actors/%d/followers', $this->get__id() ) );
}
/**
* Returns the Following-API-Endpoint.
*
* @return string The Following-Endpoint.
*/
public function get_following() {
return get_rest_url_by_path( sprintf( 'actors/%d/following', $this->get__id() ) );
}
/**
* Returns endpoints.
*
* @return array|null The endpoints.
*/
public function get_endpoints() {
$endpoints = null;
if ( ACTIVITYPUB_SHARED_INBOX_FEATURE ) {
$endpoints = array(
'sharedInbox' => get_rest_url_by_path( 'inbox' ),
);
}
return $endpoints;
}
/**
* Returns a user@domain type of identifier for the user.
*
* @return string The Webfinger-Identifier.
*/
public function get_webfinger() {
return $this->get_preferred_username() . '@' . \wp_parse_url( \home_url(), \PHP_URL_HOST );
}
/**
* Returns the Featured-API-Endpoint.
*
* @return string The Featured-Endpoint.
*/
public function get_featured() {
return get_rest_url_by_path( sprintf( 'actors/%d/collections/featured', $this->get__id() ) );
}
/**
* Returns whether the site is indexable.
*
* @return bool Whether the site is indexable.
*/
public function get_indexable() {
2024-09-12 14:55:14 +00:00
if ( is_blog_public() ) {
return true;
} else {
return false;
}
}
/**
* Update the Username.
*
* @param mixed $value The new value.
* @return bool True if the attribute was updated, false otherwise.
*/
public function update_name( $value ) {
return \update_option( 'blogname', $value );
}
/**
* Update the User description.
*
* @param mixed $value The new value.
* @return bool True if the attribute was updated, false otherwise.
*/
public function update_summary( $value ) {
return \update_option( 'blogdescription', $value );
}
/**
* Update the User icon.
*
* @param mixed $value The new value.
* @return bool True if the attribute was updated, false otherwise.
*/
public function update_icon( $value ) {
if ( ! wp_attachment_is_image( $value ) ) {
return false;
}
return \update_option( 'site_icon', $value );
}
/**
* Update the User-Header-Image.
*
* @param mixed $value The new value.
* @return bool True if the attribute was updated, false otherwise.
*/
public function update_header( $value ) {
if ( ! wp_attachment_is_image( $value ) ) {
return false;
}
return \update_option( 'activitypub_header_image', $value );
}
/**
* Get the User - Hashtags.
*
* @see https://docs.joinmastodon.org/spec/activitypub/#Hashtag
*
* @return array The User - Hashtags.
*/
public function get_tag() {
$hashtags = array();
$args = array(
'orderby' => 'count',
'order' => 'DESC',
2024-07-26 14:03:58 +00:00
'number' => 10,
);
$tags = get_tags( $args );
foreach ( $tags as $tag ) {
$hashtags[] = array(
'type' => 'Hashtag',
'href' => \get_tag_link( $tag->term_id ),
'name' => esc_hashtag( $tag->name ),
);
}
return $hashtags;
}
/**
* Extend the User-Output with Attachments.
*
* @return array The extended User-Output.
*/
public function get_attachment() {
$extra_fields = Extra_Fields::get_actor_fields( $this->_id );
return Extra_Fields::fields_to_attachments( $extra_fields );
}
}