a follower is now a valid ActivityPub Actor
this helps with API handling
This commit is contained in:
parent
d47a048329
commit
5478be1355
14 changed files with 914 additions and 318 deletions
562
includes/activity/class-activity-object.php
Normal file
562
includes/activity/class-activity-object.php
Normal file
|
@ -0,0 +1,562 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Inspired by the PHP ActivityPub Library by @Landrok
|
||||||
|
*
|
||||||
|
* @link https://github.com/landrok/activitypub
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Activitypub\Activity;
|
||||||
|
|
||||||
|
use WP_Error;
|
||||||
|
|
||||||
|
use function Activitypub\camel_to_snake_case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ObjectType is an implementation of one of the
|
||||||
|
* Activity Streams Core Types.
|
||||||
|
*
|
||||||
|
* The Object is the primary base type for the Activity Streams
|
||||||
|
* vocabulary.
|
||||||
|
*
|
||||||
|
* Note: Object is a reserved keyword in PHP. It has been suffixed with
|
||||||
|
* 'Type' for this reason.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-core/#object
|
||||||
|
*/
|
||||||
|
class Activity_Object {
|
||||||
|
/**
|
||||||
|
* The object's unique global identifier
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#obj-id
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type = 'Object';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A resource attached or related to an object that potentially
|
||||||
|
* requires special handling.
|
||||||
|
* The intent is to provide a model that is at least semantically
|
||||||
|
* similar to attachments in email.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attachment
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $attachment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more entities to which this object is attributed.
|
||||||
|
* The attributed entities might not be Actors. For instance, an
|
||||||
|
* object might be attributed to the completion of another activity.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-attributedto
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $attributed_to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more entities that represent the total population of
|
||||||
|
* entities for which the object can considered to be relevant.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-audience
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $audience;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content or textual representation of the Object encoded as a
|
||||||
|
* JSON string. By default, the value of content is HTML.
|
||||||
|
* The mediaType property can be used in the object to indicate a
|
||||||
|
* different content type.
|
||||||
|
*
|
||||||
|
* The content MAY be expressed using multiple language-tagged
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The context within which the object exists or an activity was
|
||||||
|
* performed.
|
||||||
|
* The notion of "context" used is intentionally vague.
|
||||||
|
* The intended function is to serve as a means of grouping objects
|
||||||
|
* and activities that share a common originating context or
|
||||||
|
* purpose. An example could be all activities relating to a common
|
||||||
|
* project or event.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-context
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content MAY be expressed using multiple language-tagged
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-content
|
||||||
|
*
|
||||||
|
* @var array|null
|
||||||
|
*/
|
||||||
|
protected $content_map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple, human-readable, plain-text name for the object.
|
||||||
|
* HTML markup MUST NOT be included.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name
|
||||||
|
*
|
||||||
|
* @var string|null xsd:string
|
||||||
|
*/
|
||||||
|
protected $name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name MAY be expressed using multiple language-tagged values.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-name
|
||||||
|
*
|
||||||
|
* @var array|null rdf:langString
|
||||||
|
*/
|
||||||
|
protected $name_map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time describing the actual or expected ending time
|
||||||
|
* of the object.
|
||||||
|
* When used with an Activity object, for instance, the endTime
|
||||||
|
* property specifies the moment the activity concluded or
|
||||||
|
* is expected to conclude.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-endtime
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $end_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The entity (e.g. an application) that generated the object.
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that describes an icon for this object.
|
||||||
|
* The image should have an aspect ratio of one (horizontal)
|
||||||
|
* to one (vertical) and should be suitable for presentation
|
||||||
|
* at a small size.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-icon
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | Image
|
||||||
|
* | Link
|
||||||
|
* | array<Image>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $icon;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that describes an image for this object.
|
||||||
|
* Unlike the icon property, there are no aspect ratio
|
||||||
|
* or display size limitations assumed.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-image-term
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | Image
|
||||||
|
* | Link
|
||||||
|
* | array<Image>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more entities for which this object is considered a
|
||||||
|
* response.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-inreplyto
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $in_reply_to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more physical or logical locations associated with the
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-location
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $location;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity that provides a preview of this object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-preview
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $preview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time at which the object was published
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-published
|
||||||
|
*
|
||||||
|
* @var string|null xsd:dateTime
|
||||||
|
*/
|
||||||
|
protected $published;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Collection containing objects considered to be responses to
|
||||||
|
* this object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-replies
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | Collection
|
||||||
|
* | Link
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $replies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time describing the actual or expected starting time
|
||||||
|
* of the object.
|
||||||
|
* When used with an Activity object, for instance, the startTime
|
||||||
|
* property specifies the moment the activity began
|
||||||
|
* or is scheduled to begin.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-starttime
|
||||||
|
*
|
||||||
|
* @var string|null xsd:dateTime
|
||||||
|
*/
|
||||||
|
protected $start_time;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A natural language summarization of the object encoded as HTML.
|
||||||
|
* Multiple language tagged summaries MAY be provided.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $summary;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The content MAY be expressed using multiple language-tagged
|
||||||
|
* values.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-summary
|
||||||
|
*
|
||||||
|
* @var array<string>|null
|
||||||
|
*/
|
||||||
|
protected $summary_map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more "tags" that have been associated with an objects.
|
||||||
|
* A tag can be any kind of Object.
|
||||||
|
* The key difference between attachment and tag is that the former
|
||||||
|
* implies association by inclusion, while the latter implies
|
||||||
|
* associated by reference.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-tag
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $tag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The date and time at which the object was updated
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-updated
|
||||||
|
*
|
||||||
|
* @var string|null xsd:dateTime
|
||||||
|
*/
|
||||||
|
protected $updated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more links to representations of the object.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | array<string>
|
||||||
|
* | Link
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An entity considered to be part of the public primary audience
|
||||||
|
* of an Object
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-to
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $to;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Object that is part of the private primary audience of this
|
||||||
|
* Object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bto
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $bto;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An Object that is part of the public secondary audience of this
|
||||||
|
* Object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-cc
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $cc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One or more Objects that are part of the private secondary
|
||||||
|
* audience of this Object.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-bcc
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | ObjectType
|
||||||
|
* | Link
|
||||||
|
* | array<ObjectType>
|
||||||
|
* | array<Link>
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $bcc;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The MIME media type of the value of the content property.
|
||||||
|
* If not specified, the content property is assumed to contain
|
||||||
|
* text/html content.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-mediatype
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $media_type;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the object describes a time-bound resource, such as an audio
|
||||||
|
* or video, a meeting, etc, the duration property indicates the
|
||||||
|
* object's approximate duration.
|
||||||
|
* The value MUST be expressed as an xsd:duration as defined by
|
||||||
|
* xmlschema11-2, section 3.3.6 (e.g. a period of 5 seconds is
|
||||||
|
* represented as "PT5S").
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $duration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intended to convey some sort of source from which the content
|
||||||
|
* markup was derived, as a form of provenance, or to support
|
||||||
|
* future editing by clients.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#source-property
|
||||||
|
*
|
||||||
|
* @var ObjectType
|
||||||
|
*/
|
||||||
|
protected $source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Magic function to implement getter and setter
|
||||||
|
*
|
||||||
|
* @param string $method The method name.
|
||||||
|
* @param string $params The method params.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function __call( $method, $params ) {
|
||||||
|
$var = \strtolower( \substr( $method, 4 ) );
|
||||||
|
|
||||||
|
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
|
||||||
|
if ( $this->has( $var ) ) {
|
||||||
|
return $this->get( $var );
|
||||||
|
}
|
||||||
|
return $this->$var;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
|
||||||
|
$this->set( $var, $params[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( \strncasecmp( $method, 'add', 3 ) === 0 ) {
|
||||||
|
$this->add( $var, $params[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic getter.
|
||||||
|
*
|
||||||
|
* @param string $key The key to get.
|
||||||
|
*
|
||||||
|
* @return mixed The value.
|
||||||
|
*/
|
||||||
|
public function get( $key ) {
|
||||||
|
if ( ! $this->has( $key ) ) {
|
||||||
|
return new WP_Error( 'invalid_key', 'Invalid key' );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the object has a key
|
||||||
|
*
|
||||||
|
* @param string $key The key to check.
|
||||||
|
*
|
||||||
|
* @return boolean True if the object has the key.
|
||||||
|
*/
|
||||||
|
public function has( $key ) {
|
||||||
|
return property_exists( $this, $key );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic setter.
|
||||||
|
*
|
||||||
|
* @param string $key The key to set.
|
||||||
|
* @param string $value The value to set.
|
||||||
|
*
|
||||||
|
* @return mixed The value.
|
||||||
|
*/
|
||||||
|
public function set( $key, $value ) {
|
||||||
|
if ( ! $this->has( $key ) ) {
|
||||||
|
return new WP_Error( 'invalid_key', 'Invalid key' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$key = $value;
|
||||||
|
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generic adder.
|
||||||
|
*
|
||||||
|
* @param string $key The key to set.
|
||||||
|
* @param mixed $value The value to add.
|
||||||
|
*
|
||||||
|
* @return mixed The value.
|
||||||
|
*/
|
||||||
|
public function add( $key, $value ) {
|
||||||
|
if ( ! $this->has( $key ) ) {
|
||||||
|
return new WP_Error( 'invalid_key', 'Invalid key' );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! isset( $this->$key ) ) {
|
||||||
|
$this->$key = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->$key[] = $value;
|
||||||
|
|
||||||
|
return $this->$key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert JSON input to an array.
|
||||||
|
*
|
||||||
|
* @return string The JSON string.
|
||||||
|
*
|
||||||
|
* @return array An Object built from the JSON string.
|
||||||
|
*/
|
||||||
|
public static function from_json( $json ) {
|
||||||
|
$array = wp_json_decode( $json, true );
|
||||||
|
|
||||||
|
return self::from_array( $array );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert JSON input to an array.
|
||||||
|
*
|
||||||
|
* @return string The object array.
|
||||||
|
*
|
||||||
|
* @return array An Object built from the JSON string.
|
||||||
|
*/
|
||||||
|
public static function from_array( $array ) {
|
||||||
|
$object = new static();
|
||||||
|
|
||||||
|
foreach ( $array as $key => $value ) {
|
||||||
|
$key = camel_to_snake_case( $key );
|
||||||
|
$object->set( $key, $value );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
}
|
117
includes/activity/class-actor.php
Normal file
117
includes/activity/class-actor.php
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Inspired by the PHP ActivityPub Library by @Landrok
|
||||||
|
*
|
||||||
|
* @link https://github.com/landrok/activitypub
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Activitypub\Activity;
|
||||||
|
|
||||||
|
class Actor extends Activity_Object {
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type = 'Object';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to an ActivityStreams OrderedCollection comprised of
|
||||||
|
* all the messages received by the actor.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#inbox
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $inbox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to an ActivityStreams OrderedCollection comprised of
|
||||||
|
* all the messages produced by the actor.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#outbox
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
* | null
|
||||||
|
*/
|
||||||
|
protected $outbox;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A link to an ActivityStreams collection of the actors that this
|
||||||
|
* actor is following.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#following
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $following;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A link to an ActivityStreams collection of the actors that
|
||||||
|
* follow this actor.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#followers
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $followers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A link to an ActivityStreams collection of objects this actor has
|
||||||
|
* liked.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#liked
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $liked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of supplementary Collections which may be of interest.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#streams-property
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $streams = array();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short username which may be used to refer to the actor, with no
|
||||||
|
* uniqueness guarantees.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#preferredUsername
|
||||||
|
*
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
protected $preferred_username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A JSON object which maps additional typically server/domain-wide
|
||||||
|
* endpoints which may be useful either for this actor or someone
|
||||||
|
* referencing this actor. This mapping may be nested inside the
|
||||||
|
* actor document as the value or may be a link to a JSON-LD
|
||||||
|
* document with these properties.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitypub/#endpoints
|
||||||
|
*
|
||||||
|
* @var string|array|null
|
||||||
|
*/
|
||||||
|
protected $endpoints;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* It's not part of the ActivityPub protocol but it's a quite common
|
||||||
|
* practice to handle an actor public key with a publicKey array:
|
||||||
|
* [
|
||||||
|
* 'id' => 'https://my-example.com/actor#main-key'
|
||||||
|
* 'owner' => 'https://my-example.com/actor',
|
||||||
|
* 'publicKeyPem' => '-----BEGIN PUBLIC KEY-----
|
||||||
|
* MIIBI [...]
|
||||||
|
* DQIDAQAB
|
||||||
|
* -----END PUBLIC KEY-----'
|
||||||
|
* ]
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/wiki/SocialCG/ActivityPub/Authentication_Authorization#Signing_requests_using_HTTP_Signatures
|
||||||
|
*
|
||||||
|
* @var string|array|null
|
||||||
|
*/
|
||||||
|
protected $public_key;
|
||||||
|
}
|
20
includes/activity/class-person.php
Normal file
20
includes/activity/class-person.php
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Inspired by the PHP ActivityPub Library by @Landrok
|
||||||
|
*
|
||||||
|
* @link https://github.com/landrok/activitypub
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Activitypub\Activity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an individual person.
|
||||||
|
*
|
||||||
|
* @see https://www.w3.org/TR/activitystreams-vocabulary/#dfn-person
|
||||||
|
*/
|
||||||
|
class Person extends Activity_Object {
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $type = 'Person';
|
||||||
|
}
|
|
@ -22,7 +22,8 @@ class Migration {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function get_version() {
|
public static function get_version() {
|
||||||
return get_option( 'activitypub_db_version', 0 );
|
return 0;
|
||||||
|
//return get_option( 'activitypub_db_version', 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,19 +72,19 @@ class Migration {
|
||||||
foreach ( $followers as $actor ) {
|
foreach ( $followers as $actor ) {
|
||||||
$meta = get_remote_metadata_by_actor( $actor );
|
$meta = get_remote_metadata_by_actor( $actor );
|
||||||
|
|
||||||
$follower = new Follower( $actor );
|
|
||||||
|
|
||||||
if ( is_tombstone( $meta ) ) {
|
if ( is_tombstone( $meta ) ) {
|
||||||
continue;
|
continue;
|
||||||
} if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
}
|
||||||
|
|
||||||
|
$follower = Follower::from_array( $meta );
|
||||||
|
|
||||||
|
if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
||||||
$follower->set_error( $meta );
|
$follower->set_error( $meta );
|
||||||
} else {
|
|
||||||
$follower->from_meta( $meta );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower->upsert();
|
$follower->upsert();
|
||||||
|
|
||||||
add_post_meta( $follower->get_id(), 'user_id', $user_id );
|
add_post_meta( $follower->get__id(), '_user_id', $user_id );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ class Scheduler {
|
||||||
$followers = Followers::get_outdated_followers();
|
$followers = Followers::get_outdated_followers();
|
||||||
|
|
||||||
foreach ( $followers as $follower ) {
|
foreach ( $followers as $follower ) {
|
||||||
$meta = get_remote_metadata_by_actor( $follower->get_actor(), true );
|
$meta = get_remote_metadata_by_actor( $follower->get_url(), true );
|
||||||
|
|
||||||
if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
if ( empty( $meta ) || ! is_array( $meta ) || is_wp_error( $meta ) ) {
|
||||||
$follower->set_error( $meta );
|
$follower->set_error( $meta );
|
||||||
|
@ -121,7 +121,7 @@ class Scheduler {
|
||||||
$followers = Followers::get_faulty_followers();
|
$followers = Followers::get_faulty_followers();
|
||||||
|
|
||||||
foreach ( $followers as $follower ) {
|
foreach ( $followers as $follower ) {
|
||||||
$meta = get_remote_metadata_by_actor( $follower->get_actor(), true );
|
$meta = get_remote_metadata_by_actor( $follower->get_url(), true );
|
||||||
|
|
||||||
if ( is_tombstone( $meta ) ) {
|
if ( is_tombstone( $meta ) ) {
|
||||||
$follower->delete();
|
$follower->delete();
|
||||||
|
|
|
@ -62,19 +62,7 @@ class Followers {
|
||||||
|
|
||||||
register_post_meta(
|
register_post_meta(
|
||||||
self::POST_TYPE,
|
self::POST_TYPE,
|
||||||
'name',
|
'preferred_username',
|
||||||
array(
|
|
||||||
'type' => 'string',
|
|
||||||
'single' => true,
|
|
||||||
'sanitize_callback' => function( $value ) {
|
|
||||||
return sanitize_user( $value );
|
|
||||||
},
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
register_post_meta(
|
|
||||||
self::POST_TYPE,
|
|
||||||
'username',
|
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
|
@ -86,11 +74,11 @@ class Followers {
|
||||||
|
|
||||||
register_post_meta(
|
register_post_meta(
|
||||||
self::POST_TYPE,
|
self::POST_TYPE,
|
||||||
'avatar',
|
'icon',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
//'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
'sanitize_callback' => array( self::class, 'sanitize_url' ),
|
//'sanitize_callback' => array( self::class, 'sanitize_url' ),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -116,7 +104,7 @@ class Followers {
|
||||||
|
|
||||||
register_post_meta(
|
register_post_meta(
|
||||||
self::POST_TYPE,
|
self::POST_TYPE,
|
||||||
'shared_inbox',
|
'_shared_inbox',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
|
@ -126,7 +114,7 @@ class Followers {
|
||||||
|
|
||||||
register_post_meta(
|
register_post_meta(
|
||||||
self::POST_TYPE,
|
self::POST_TYPE,
|
||||||
'updated_at',
|
'updated',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => true,
|
'single' => true,
|
||||||
|
@ -142,7 +130,7 @@ class Followers {
|
||||||
|
|
||||||
register_post_meta(
|
register_post_meta(
|
||||||
self::POST_TYPE,
|
self::POST_TYPE,
|
||||||
'errors',
|
'_errors',
|
||||||
array(
|
array(
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'single' => false,
|
'single' => false,
|
||||||
|
@ -156,6 +144,18 @@ class Followers {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
register_post_meta(
|
||||||
|
self::POST_TYPE,
|
||||||
|
'_actor',
|
||||||
|
array(
|
||||||
|
'type' => 'string',
|
||||||
|
'single' => false,
|
||||||
|
'sanitize_callback' => function( $value ) {
|
||||||
|
return esc_sql( $value );
|
||||||
|
},
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
do_action( 'activitypub_after_register_post_type' );
|
do_action( 'activitypub_after_register_post_type' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,14 +213,13 @@ class Followers {
|
||||||
return $meta;
|
return $meta;
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = new Follower( $actor );
|
$follower = Follower::from_array( $meta );
|
||||||
$follower->from_meta( $meta );
|
|
||||||
$follower->upsert();
|
$follower->upsert();
|
||||||
|
|
||||||
$meta = get_post_meta( $follower->get_id(), 'user_id' );
|
$meta = get_post_meta( $follower->get__id(), '_user_id' );
|
||||||
|
|
||||||
if ( is_array( $meta ) && ! in_array( $user_id, $meta, true ) ) {
|
if ( is_array( $meta ) && ! in_array( $user_id, $meta, true ) ) {
|
||||||
add_post_meta( $follower->get_id(), 'user_id', $user_id );
|
add_post_meta( $follower->get__id(), '_user_id', $user_id );
|
||||||
wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' );
|
wp_cache_delete( sprintf( self::CACHE_KEY_INBOXES, $user_id ), 'activitypub' );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,7 +243,7 @@ class Followers {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return delete_post_meta( $follower->get_id(), 'user_id', $user_id );
|
return delete_post_meta( $follower->get__id(), '_user_id', $user_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -260,7 +259,7 @@ class Followers {
|
||||||
|
|
||||||
$post_id = $wpdb->get_var(
|
$post_id = $wpdb->get_var(
|
||||||
$wpdb->prepare(
|
$wpdb->prepare(
|
||||||
"SELECT p.ID FROM $wpdb->posts p INNER JOIN $wpdb->postmeta pm ON p.ID = pm.post_id WHERE p.post_type = %s AND pm.meta_key = 'user_id' AND pm.meta_value = %d AND p.guid = %s",
|
"SELECT p.ID FROM $wpdb->posts p INNER JOIN $wpdb->postmeta pm ON p.ID = pm.post_id WHERE p.post_type = %s AND pm.meta_key = '_user_id' AND pm.meta_value = %d AND p.guid = %s",
|
||||||
array(
|
array(
|
||||||
esc_sql( self::POST_TYPE ),
|
esc_sql( self::POST_TYPE ),
|
||||||
esc_sql( $user_id ),
|
esc_sql( $user_id ),
|
||||||
|
@ -271,7 +270,7 @@ class Followers {
|
||||||
|
|
||||||
if ( $post_id ) {
|
if ( $post_id ) {
|
||||||
$post = get_post( $post_id );
|
$post = get_post( $post_id );
|
||||||
return new Follower( $post );
|
return Follower::from_custom_post_type( $post );
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -295,7 +294,7 @@ class Followers {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset( $object['user_id'] ) ) {
|
if ( isset( $object['user_id'] ) ) {
|
||||||
unset( $object['user_id'] );
|
unset( $object['_user_id'] );
|
||||||
unset( $object['@context'] );
|
unset( $object['@context'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +303,7 @@ class Followers {
|
||||||
|
|
||||||
// send "Accept" activity
|
// send "Accept" activity
|
||||||
$activity = new Activity( 'Accept' );
|
$activity = new Activity( 'Accept' );
|
||||||
$activity->set_object( $object );
|
$activity->set_activity_object( $object );
|
||||||
$activity->set_actor( \get_author_posts_url( $user_id ) );
|
$activity->set_actor( \get_author_posts_url( $user_id ) );
|
||||||
$activity->set_to( $actor );
|
$activity->set_to( $actor );
|
||||||
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $actor ) );
|
$activity->set_id( \get_author_posts_url( $user_id ) . '#follow-' . \preg_replace( '~^https?://~', '', $actor ) );
|
||||||
|
@ -332,7 +331,7 @@ class Followers {
|
||||||
'order' => 'DESC',
|
'order' => 'DESC',
|
||||||
'meta_query' => array(
|
'meta_query' => array(
|
||||||
array(
|
array(
|
||||||
'key' => 'user_id',
|
'key' => '_user_id',
|
||||||
'value' => $user_id,
|
'value' => $user_id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -343,7 +342,7 @@ class Followers {
|
||||||
$items = array();
|
$items = array();
|
||||||
|
|
||||||
foreach ( $query->get_posts() as $post ) {
|
foreach ( $query->get_posts() as $post ) {
|
||||||
$items[] = new Follower( $post ); // phpcs:ignore
|
$items[] = Follower::from_custom_post_type( $post ); // phpcs:ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return $items;
|
return $items;
|
||||||
|
@ -377,7 +376,7 @@ class Followers {
|
||||||
'fields' => 'ids',
|
'fields' => 'ids',
|
||||||
'meta_query' => array(
|
'meta_query' => array(
|
||||||
array(
|
array(
|
||||||
'key' => 'user_id',
|
'key' => '_user_id',
|
||||||
'value' => $user_id,
|
'value' => $user_id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -409,11 +408,11 @@ class Followers {
|
||||||
'fields' => 'ids',
|
'fields' => 'ids',
|
||||||
'meta_query' => array(
|
'meta_query' => array(
|
||||||
array(
|
array(
|
||||||
'key' => 'inbox',
|
'key' => '_shared_inbox',
|
||||||
'compare' => 'EXISTS',
|
'compare' => 'EXISTS',
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
'key' => 'user_id',
|
'key' => '_user_id',
|
||||||
'value' => $user_id,
|
'value' => $user_id,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -431,7 +430,7 @@ class Followers {
|
||||||
$wpdb->prepare(
|
$wpdb->prepare(
|
||||||
"SELECT DISTINCT meta_value FROM {$wpdb->postmeta}
|
"SELECT DISTINCT meta_value FROM {$wpdb->postmeta}
|
||||||
WHERE post_id IN (" . implode( ', ', array_fill( 0, count( $posts ), '%d' ) ) . ")
|
WHERE post_id IN (" . implode( ', ', array_fill( 0, count( $posts ), '%d' ) ) . ")
|
||||||
AND meta_key = 'shared_inbox'
|
AND meta_key = '_shared_inbox'
|
||||||
AND meta_value IS NOT NULL",
|
AND meta_value IS NOT NULL",
|
||||||
$posts
|
$posts
|
||||||
)
|
)
|
||||||
|
@ -471,7 +470,7 @@ class Followers {
|
||||||
$items = array();
|
$items = array();
|
||||||
|
|
||||||
foreach ( $posts->get_posts() as $follower ) {
|
foreach ( $posts->get_posts() as $follower ) {
|
||||||
$items[] = new Follower( $follower ); // phpcs:ignore
|
$items[] = Follower::from_custom_post_type( $follower ); // phpcs:ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return $items;
|
return $items;
|
||||||
|
@ -501,7 +500,7 @@ class Followers {
|
||||||
$items = array();
|
$items = array();
|
||||||
|
|
||||||
foreach ( $posts->get_posts() as $follower ) {
|
foreach ( $posts->get_posts() as $follower ) {
|
||||||
$items[] = new Follower( $follower ); // phpcs:ignore
|
$items[] = Follower::from_custom_post_type( $follower ); // phpcs:ignore
|
||||||
}
|
}
|
||||||
|
|
||||||
return $items;
|
return $items;
|
||||||
|
|
|
@ -237,6 +237,17 @@ function get_rest_url_by_path( $path = '' ) {
|
||||||
return \get_rest_url( null, $namespaced_path );
|
return \get_rest_url( null, $namespaced_path );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a string from camelCase to snake_case.
|
||||||
|
*
|
||||||
|
* @param string $string The string to convert.
|
||||||
|
*
|
||||||
|
* @return string The converted string.
|
||||||
|
*/
|
||||||
|
function camel_to_snake_case( $string ) {
|
||||||
|
return strtolower( preg_replace( '/(?<!^)[A-Z]/', '_$0', $string ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a request is for an ActivityPub request.
|
* Check if a request is for an ActivityPub request.
|
||||||
*
|
*
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
namespace Activitypub\Model;
|
namespace Activitypub\Model;
|
||||||
|
|
||||||
use WP_Query;
|
use WP_Query;
|
||||||
|
use Activitypub\Activity\Actor;
|
||||||
use Activitypub\Collection\Followers;
|
use Activitypub\Collection\Followers;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,81 +16,27 @@ use Activitypub\Collection\Followers;
|
||||||
*
|
*
|
||||||
* @see https://www.w3.org/TR/activitypub/#follow-activity-inbox
|
* @see https://www.w3.org/TR/activitypub/#follow-activity-inbox
|
||||||
*/
|
*/
|
||||||
class Follower {
|
class Follower extends Actor {
|
||||||
/**
|
/**
|
||||||
* The Object ID
|
* The complete Remote-Profile of the Follower
|
||||||
*
|
*
|
||||||
* @var int
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $id;
|
protected $_id; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
||||||
|
|
||||||
/**
|
|
||||||
* The Actor-URL of the Follower
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $actor;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Object Name
|
|
||||||
*
|
|
||||||
* This is the same as the Actor-URL
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Username
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $username;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The User-Summary
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $summary;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The Avatar URL
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $avatar;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL to the Followers Inbox
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $inbox;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The URL to the Servers Shared-Inbox
|
|
||||||
*
|
|
||||||
* If the Server does not support Shared-Inboxes,
|
|
||||||
* the Inbox will be stored.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $shared_inbox;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The date, the Follower was updated
|
|
||||||
*
|
|
||||||
* @var string untixtimestamp
|
|
||||||
*/
|
|
||||||
private $updated_at;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The complete Remote-Profile of the Follower
|
* The complete Remote-Profile of the Follower
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $meta;
|
protected $_shared_inbox; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The complete Remote-Profile of the Follower
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $_actor; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The latest received error.
|
* The latest received error.
|
||||||
|
@ -98,89 +45,14 @@ class Follower {
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $error;
|
protected $_error; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of errors
|
* A list of errors
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $errors;
|
protected $_errors; // phpcs:ignore PSR2.Classes.PropertyDeclaration.Underscore
|
||||||
|
|
||||||
/**
|
|
||||||
* The WordPress User ID, or 0 for whole site.
|
|
||||||
* @var int
|
|
||||||
*/
|
|
||||||
private $user_id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps the meta fields to the local db fields
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $map_meta = array(
|
|
||||||
'name' => 'name',
|
|
||||||
'preferredUsername' => 'username',
|
|
||||||
'inbox' => 'inbox',
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor
|
|
||||||
*
|
|
||||||
* @param string|WP_Post $actor The Actor-URL or WP_Post Object.
|
|
||||||
* @param int $user_id The WordPress User ID. 0 Represents the whole site.
|
|
||||||
*/
|
|
||||||
public function __construct( $actor ) {
|
|
||||||
$post = null;
|
|
||||||
|
|
||||||
if ( \is_a( $actor, 'WP_Post' ) ) {
|
|
||||||
$post = $actor;
|
|
||||||
} else {
|
|
||||||
global $wpdb;
|
|
||||||
|
|
||||||
$post_id = $wpdb->get_var(
|
|
||||||
$wpdb->prepare(
|
|
||||||
"SELECT ID FROM $wpdb->posts WHERE guid=%s",
|
|
||||||
esc_sql( $actor )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( $post_id ) {
|
|
||||||
$post = get_post( $post_id );
|
|
||||||
} else {
|
|
||||||
$this->actor = $actor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $post ) {
|
|
||||||
$this->id = $post->ID;
|
|
||||||
$this->actor = $post->guid;
|
|
||||||
$this->updated_at = $post->post_modified;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Magic function to implement getter and setter
|
|
||||||
*
|
|
||||||
* @param string $method The method name.
|
|
||||||
* @param string $params The method params.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __call( $method, $params ) {
|
|
||||||
$var = \strtolower( \substr( $method, 4 ) );
|
|
||||||
|
|
||||||
if ( \strncasecmp( $method, 'get', 3 ) === 0 ) {
|
|
||||||
if ( empty( $this->$var ) ) {
|
|
||||||
return $this->get( $var );
|
|
||||||
}
|
|
||||||
return $this->$var;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( \strncasecmp( $method, 'set', 3 ) === 0 ) {
|
|
||||||
$this->$var = $params[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Magic function to return the Actor-URL when the Object is used as a string
|
* Magic function to return the Actor-URL when the Object is used as a string
|
||||||
|
@ -188,64 +60,7 @@ class Follower {
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function __toString() {
|
public function __toString() {
|
||||||
return $this->get_actor();
|
return $this->get_url();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prefill the Object with the meta data.
|
|
||||||
*
|
|
||||||
* @param array $meta The meta data.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function from_meta( $meta ) {
|
|
||||||
$this->meta = $meta;
|
|
||||||
|
|
||||||
foreach ( $this->map_meta as $remote => $internal ) {
|
|
||||||
if ( ! empty( $meta[ $remote ] ) ) {
|
|
||||||
$this->$internal = $meta[ $remote ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty( $meta['icon']['url'] ) ) {
|
|
||||||
$this->avatar = $meta['icon']['url'];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! empty( $meta['endpoints']['sharedInbox'] ) ) {
|
|
||||||
$this->shared_inbox = $meta['endpoints']['sharedInbox'];
|
|
||||||
} elseif ( ! empty( $meta['inbox'] ) ) {
|
|
||||||
$this->shared_inbox = $meta['inbox'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->updated_at = \time();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data by the given attribute
|
|
||||||
*
|
|
||||||
* @param string $attribute The attribute name.
|
|
||||||
*
|
|
||||||
* @return mixed The attribute value.
|
|
||||||
*/
|
|
||||||
public function get( $attribute ) {
|
|
||||||
if ( ! is_null( $this->$attribute ) ) {
|
|
||||||
return $this->$attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
$attribute_value = get_post_meta( $this->id, $attribute, true );
|
|
||||||
|
|
||||||
if ( $attribute_value ) {
|
|
||||||
$this->$attribute = $attribute_value;
|
|
||||||
return $attribute_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
$attribute_value = $this->get_meta_by( $attribute );
|
|
||||||
if ( $attribute_value ) {
|
|
||||||
$this->$attribute = $attribute_value;
|
|
||||||
return $attribute_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -256,8 +71,8 @@ class Follower {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function set_error( $error ) {
|
public function set_error( $error ) {
|
||||||
$this->errors = array();
|
$this->_errors = array();
|
||||||
$this->error = $error;
|
$this->_error = $error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -266,12 +81,12 @@ class Follower {
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function get_errors() {
|
public function get_errors() {
|
||||||
if ( $this->errors ) {
|
if ( $this->_errors ) {
|
||||||
return $this->errors;
|
return $this->_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->errors = get_post_meta( $this->id, 'errors' );
|
$this->_errors = get_post_meta( $this->_id, 'errors' );
|
||||||
return $this->errors;
|
return $this->_errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -280,7 +95,7 @@ class Follower {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function reset_errors() {
|
public function reset_errors() {
|
||||||
delete_post_meta( $this->id, 'errors' );
|
delete_post_meta( $this->_id, 'errors' );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -289,7 +104,7 @@ class Follower {
|
||||||
* @return int The number of errors.
|
* @return int The number of errors.
|
||||||
*/
|
*/
|
||||||
public function count_errors() {
|
public function count_errors() {
|
||||||
$errors = $this->get_errors();
|
$errors = $this->get__errors();
|
||||||
|
|
||||||
if ( is_array( $errors ) && ! empty( $errors ) ) {
|
if ( is_array( $errors ) && ! empty( $errors ) ) {
|
||||||
return count( $errors );
|
return count( $errors );
|
||||||
|
@ -298,13 +113,21 @@ class Follower {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_url() {
|
||||||
|
if ( ! $this->url ) {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->url;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the latest error message.
|
* Return the latest error message.
|
||||||
*
|
*
|
||||||
* @return string The error message.
|
* @return string The error message.
|
||||||
*/
|
*/
|
||||||
public function get_latest_error_message() {
|
public function get_latest_error_message() {
|
||||||
$errors = $this->get_errors();
|
$errors = $this->get__errors();
|
||||||
|
|
||||||
if ( is_array( $errors ) && ! empty( $errors ) ) {
|
if ( is_array( $errors ) && ! empty( $errors ) ) {
|
||||||
return reset( $errors );
|
return reset( $errors );
|
||||||
|
@ -313,35 +136,12 @@ class Follower {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the meta data by the given attribute.
|
|
||||||
*
|
|
||||||
* @param string $attribute The attribute name.
|
|
||||||
*
|
|
||||||
* @return mixed $attribute The attribute value.
|
|
||||||
*/
|
|
||||||
public function get_meta_by( $attribute ) {
|
|
||||||
$meta = $this->get_meta();
|
|
||||||
if ( ! is_array( $meta ) ) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
// try mapped data (see $this->map_meta)
|
|
||||||
foreach ( $this->map_meta as $remote => $local ) {
|
|
||||||
if ( $attribute === $local && isset( $meta[ $remote ] ) ) {
|
|
||||||
return $meta[ $remote ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the current Follower-Object.
|
* Update the current Follower-Object.
|
||||||
*
|
*
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function update() {
|
public function update() {
|
||||||
$this->updated_at = \time();
|
|
||||||
$this->save();
|
$this->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,18 +152,18 @@ class Follower {
|
||||||
*/
|
*/
|
||||||
public function save() {
|
public function save() {
|
||||||
$args = array(
|
$args = array(
|
||||||
'ID' => $this->id,
|
'ID' => $this->get__id(),
|
||||||
'guid' => $this->actor,
|
'guid' => $this->get_id(),
|
||||||
'post_title' => $this->get_name(),
|
'post_title' => $this->get_name(),
|
||||||
'post_author' => 0,
|
'post_author' => 0,
|
||||||
'post_type' => Followers::POST_TYPE,
|
'post_type' => Followers::POST_TYPE,
|
||||||
'post_content' => $this->get_summary(),
|
'post_content' => $this->get_summary(),
|
||||||
'post_status' => 'publish',
|
'post_status' => 'publish',
|
||||||
'post_modified' => gmdate( 'Y-m-d H:i:s', $this->updated_at ),
|
|
||||||
'meta_input' => $this->get_post_meta_input(),
|
'meta_input' => $this->get_post_meta_input(),
|
||||||
);
|
);
|
||||||
|
|
||||||
$post_id = wp_insert_post( $args );
|
$post_id = wp_insert_post( $args );
|
||||||
$this->id = $post_id;
|
$this->_id = $post_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -372,7 +172,7 @@ class Follower {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function upsert() {
|
public function upsert() {
|
||||||
if ( $this->id ) {
|
if ( $this->_id ) {
|
||||||
$this->update();
|
$this->update();
|
||||||
} else {
|
} else {
|
||||||
$this->save();
|
$this->save();
|
||||||
|
@ -385,7 +185,7 @@ class Follower {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function delete() {
|
public function delete() {
|
||||||
wp_delete_post( $this->id );
|
wp_delete_post( $this->_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -394,7 +194,7 @@ class Follower {
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function get_post_meta_input() {
|
protected function get_post_meta_input() {
|
||||||
$attributes = array( 'inbox', 'shared_inbox', 'avatar', 'name', 'username', 'meta' );
|
$attributes = array( 'inbox', '_shared_inbox', 'icon', 'preferred_username', '_actor', 'url' );
|
||||||
|
|
||||||
$meta_input = array();
|
$meta_input = array();
|
||||||
|
|
||||||
|
@ -404,18 +204,94 @@ class Follower {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $this->error ) {
|
if ( $this->_error ) {
|
||||||
if ( is_string( $this->error ) ) {
|
if ( is_string( $this->_error ) ) {
|
||||||
$error = $this->error;
|
$_error = $this->_error;
|
||||||
} elseif ( is_wp_error( $this->error ) ) {
|
} elseif ( is_wp_error( $this->_error ) ) {
|
||||||
$error = $this->error->get_error_message();
|
$_error = $this->_error->get_error_message();
|
||||||
} else {
|
} else {
|
||||||
$error = __( 'Unknown Error or misconfigured Error-Message', 'activitypub' );
|
$_error = __( 'Unknown Error or misconfigured Error-Message', 'activitypub' );
|
||||||
}
|
}
|
||||||
|
|
||||||
$meta_input['errors'] = array( $error );
|
$meta_input['_errors'] = $_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $meta_input;
|
return $meta_input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the Icon URL (Avatar)
|
||||||
|
*
|
||||||
|
* @return string The URL to the Avatar.
|
||||||
|
*/
|
||||||
|
public function get_icon_url() {
|
||||||
|
$icon = $this->get_icon();
|
||||||
|
|
||||||
|
if ( ! $icon ) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_array( $icon ) ) {
|
||||||
|
return $icon['url'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an ActivityPub Array to an Follower Object.
|
||||||
|
*
|
||||||
|
* @param array $array The ActivityPub Array.
|
||||||
|
*
|
||||||
|
* @return Activitypub\Model\Follower The Follower Object.
|
||||||
|
*/
|
||||||
|
public static function from_array( $array ) {
|
||||||
|
$object = parent::from_array( $array );
|
||||||
|
$object->set__actor( $array );
|
||||||
|
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$post_id = $wpdb->get_var(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT ID FROM $wpdb->posts WHERE guid=%s",
|
||||||
|
esc_sql( $object->get_id() )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( $post_id ) {
|
||||||
|
$post = get_post( $post_id );
|
||||||
|
$object->set__id( $post->ID );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ! empty( $object->get_endpoints()['sharedInbox'] ) ) {
|
||||||
|
$object->_shared_inbox = $object->get_endpoints()['sharedInbox'];
|
||||||
|
} elseif ( ! empty( $object->get_inbox() ) ) {
|
||||||
|
$object->_shared_inbox = $object->get_inbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a Custom-Post-Type input to an Activitypub\Model\Follower.
|
||||||
|
*
|
||||||
|
* @return string The JSON string.
|
||||||
|
*
|
||||||
|
* @return array Activitypub\Model\Follower
|
||||||
|
*/
|
||||||
|
public static function from_custom_post_type( $post ) {
|
||||||
|
$object = new static();
|
||||||
|
|
||||||
|
$object->set__id( $post->ID );
|
||||||
|
$object->set_id( $post->guid );
|
||||||
|
$object->set_name( $post->post_title );
|
||||||
|
$object->set_summary( $post->post_content );
|
||||||
|
$object->set_url( get_post_meta( $post->ID, 'url', true ) );
|
||||||
|
$object->set_icon( get_post_meta( $post->ID, 'icon', true ) );
|
||||||
|
$object->set_preferred_username( get_post_meta( $post->ID, 'preferred_username', true ) );
|
||||||
|
$object->set_published( gmdate( 'Y-m-d H:i:s', strtotime( $post->post_published ) ) );
|
||||||
|
$object->set_updated( gmdate( 'Y-m-d H:i:s', strtotime( $post->post_modified ) ) );
|
||||||
|
|
||||||
|
return $object;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,7 +86,7 @@ class Followers {
|
||||||
// phpcs:ignore
|
// phpcs:ignore
|
||||||
$json->orderedItems = array_map(
|
$json->orderedItems = array_map(
|
||||||
function( $item ) {
|
function( $item ) {
|
||||||
return $item->get_actor();
|
return $item->get_url();
|
||||||
},
|
},
|
||||||
FollowerCollection::get_followers( $user_id )
|
FollowerCollection::get_followers( $user_id )
|
||||||
);
|
);
|
||||||
|
|
|
@ -16,9 +16,9 @@ class Followers extends WP_List_Table {
|
||||||
'name' => \__( 'Name', 'activitypub' ),
|
'name' => \__( 'Name', 'activitypub' ),
|
||||||
'username' => \__( 'Username', 'activitypub' ),
|
'username' => \__( 'Username', 'activitypub' ),
|
||||||
'identifier' => \__( 'Identifier', 'activitypub' ),
|
'identifier' => \__( 'Identifier', 'activitypub' ),
|
||||||
'updated_at' => \__( 'Last updated', 'activitypub' ),
|
'updated' => \__( 'Last updated', 'activitypub' ),
|
||||||
'errors' => \__( 'Errors', 'activitypub' ),
|
//'errors' => \__( 'Errors', 'activitypub' ),
|
||||||
'latest-error' => \__( 'Latest Error Message', 'activitypub' ),
|
//'latest-error' => \__( 'Latest Error Message', 'activitypub' ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,11 +50,11 @@ class Followers extends WP_List_Table {
|
||||||
|
|
||||||
foreach ( $followers as $follower ) {
|
foreach ( $followers as $follower ) {
|
||||||
$item = array(
|
$item = array(
|
||||||
'avatar' => esc_attr( $follower->get_avatar() ),
|
'icon' => esc_attr( $follower->get_icon_url() ),
|
||||||
'name' => esc_attr( $follower->get_name() ),
|
'name' => esc_attr( $follower->get_name() ),
|
||||||
'username' => esc_attr( $follower->get_username() ),
|
'username' => esc_attr( $follower->get_preferred_username() ),
|
||||||
'identifier' => esc_attr( $follower->get_actor() ),
|
'identifier' => esc_attr( $follower->get_url() ),
|
||||||
'updated_at' => esc_attr( $follower->get_updated_at() ),
|
'updated' => esc_attr( $follower->get_updated() ),
|
||||||
'errors' => $follower->count_errors(),
|
'errors' => $follower->count_errors(),
|
||||||
'latest-error' => $follower->get_latest_error_message(),
|
'latest-error' => $follower->get_latest_error_message(),
|
||||||
);
|
);
|
||||||
|
@ -79,7 +79,7 @@ class Followers extends WP_List_Table {
|
||||||
public function column_avatar( $item ) {
|
public function column_avatar( $item ) {
|
||||||
return sprintf(
|
return sprintf(
|
||||||
'<img src="%s" width="25px;" />',
|
'<img src="%s" width="25px;" />',
|
||||||
$item['avatar']
|
$item['icon']
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
<div class="wrap">
|
<div class="wrap">
|
||||||
<h1><?php \esc_html_e( 'Followers', 'activitypub' ); ?></h1>
|
<h1><?php \esc_html_e( 'Followers', 'activitypub' ); ?></h1>
|
||||||
|
<?php Activitypub\Migration::maybe_migrate(); ?>
|
||||||
<?php // translators: ?>
|
<?php // translators: ?>
|
||||||
<p><?php \printf( \esc_html__( 'You currently have %s followers.', 'activitypub' ), \esc_attr( \Activitypub\Collection\Followers::count_followers( \get_current_user_id() ) ) ); ?></p>
|
<p><?php \printf( \esc_html__( 'You currently have %s followers.', 'activitypub' ), \esc_attr( \Activitypub\Collection\Followers::count_followers( \get_current_user_id() ) ) ); ?></p>
|
||||||
|
|
||||||
<?php $token_table = new \Activitypub\Table\Followers(); ?>
|
<?php $table = new \Activitypub\Table\Followers(); ?>
|
||||||
|
|
||||||
<form method="get">
|
<form method="get">
|
||||||
<input type="hidden" name="page" value="activitypub-followers-list" />
|
<input type="hidden" name="page" value="activitypub-followers-list" />
|
||||||
<?php
|
<?php
|
||||||
$token_table->prepare_items();
|
$table->prepare_items();
|
||||||
$token_table->display();
|
$table->display();
|
||||||
?>
|
?>
|
||||||
<?php wp_nonce_field( 'activitypub-followers-list', '_apnonce' ); ?>
|
<?php wp_nonce_field( 'activitypub-followers-list', '_apnonce' ); ?>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HTTP {
|
class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HTTP {
|
||||||
public static $users = array(
|
public static $users = array(
|
||||||
'username@example.org' => array(
|
'username@example.org' => array(
|
||||||
|
'id' => 'https://example.org/users/username',
|
||||||
'url' => 'https://example.org/users/username',
|
'url' => 'https://example.org/users/username',
|
||||||
'inbox' => 'https://example.org/users/username/inbox',
|
'inbox' => 'https://example.org/users/username/inbox',
|
||||||
'name' => 'username',
|
'name' => 'username',
|
||||||
'prefferedUsername' => 'username',
|
'prefferedUsername' => 'username',
|
||||||
),
|
),
|
||||||
'jon@example.com' => array(
|
'jon@example.com' => array(
|
||||||
|
'id' => 'https://example.com/author/jon',
|
||||||
'url' => 'https://example.com/author/jon',
|
'url' => 'https://example.com/author/jon',
|
||||||
'inbox' => 'https://example.com/author/jon/inbox',
|
'inbox' => 'https://example.com/author/jon/inbox',
|
||||||
'name' => 'jon',
|
'name' => 'jon',
|
||||||
|
@ -56,6 +58,7 @@ class Test_Activitypub_Activity_Dispatcher extends ActivityPub_TestCase_Cache_HT
|
||||||
);
|
);
|
||||||
|
|
||||||
self::$users['https://example.com/alex'] = array(
|
self::$users['https://example.com/alex'] = array(
|
||||||
|
'id' => 'https://example.com/alex',
|
||||||
'url' => 'https://example.com/alex',
|
'url' => 'https://example.com/alex',
|
||||||
'inbox' => 'https://example.com/alex/inbox',
|
'inbox' => 'https://example.com/alex/inbox',
|
||||||
'name' => 'alex',
|
'name' => 'alex',
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
class Test_Activitypub_Mention extends ActivityPub_TestCase_Cache_HTTP {
|
class Test_Activitypub_Mention extends ActivityPub_TestCase_Cache_HTTP {
|
||||||
public static $users = array(
|
public static $users = array(
|
||||||
'username@example.org' => array(
|
'username@example.org' => array(
|
||||||
|
'id' => 'https://example.org/users/username',
|
||||||
'url' => 'https://example.org/users/username',
|
'url' => 'https://example.org/users/username',
|
||||||
'name' => 'username',
|
'name' => 'username',
|
||||||
),
|
),
|
||||||
|
|
|
@ -2,36 +2,42 @@
|
||||||
class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
public static $users = array(
|
public static $users = array(
|
||||||
'username@example.org' => array(
|
'username@example.org' => array(
|
||||||
|
'id' => 'https://example.org/users/username',
|
||||||
'url' => 'https://example.org/users/username',
|
'url' => 'https://example.org/users/username',
|
||||||
'inbox' => 'https://example.org/users/username/inbox',
|
'inbox' => 'https://example.org/users/username/inbox',
|
||||||
'name' => 'username',
|
'name' => 'username',
|
||||||
'prefferedUsername' => 'username',
|
'prefferedUsername' => 'username',
|
||||||
),
|
),
|
||||||
'jon@example.com' => array(
|
'jon@example.com' => array(
|
||||||
|
'id' => 'https://example.com/author/jon',
|
||||||
'url' => 'https://example.com/author/jon',
|
'url' => 'https://example.com/author/jon',
|
||||||
'inbox' => 'https://example.com/author/jon/inbox',
|
'inbox' => 'https://example.com/author/jon/inbox',
|
||||||
'name' => 'jon',
|
'name' => 'jon',
|
||||||
'prefferedUsername' => 'jon',
|
'prefferedUsername' => 'jon',
|
||||||
),
|
),
|
||||||
'doe@example.org' => array(
|
'doe@example.org' => array(
|
||||||
|
'id' => 'https://example.org/author/doe',
|
||||||
'url' => 'https://example.org/author/doe',
|
'url' => 'https://example.org/author/doe',
|
||||||
'inbox' => 'https://example.org/author/doe/inbox',
|
'inbox' => 'https://example.org/author/doe/inbox',
|
||||||
'name' => 'doe',
|
'name' => 'doe',
|
||||||
'prefferedUsername' => 'doe',
|
'prefferedUsername' => 'doe',
|
||||||
),
|
),
|
||||||
'sally@example.org' => array(
|
'sally@example.org' => array(
|
||||||
|
'id' => 'http://sally.example.org',
|
||||||
'url' => 'http://sally.example.org',
|
'url' => 'http://sally.example.org',
|
||||||
'inbox' => 'http://sally.example.org/inbox',
|
'inbox' => 'http://sally.example.org/inbox',
|
||||||
'name' => 'jon',
|
'name' => 'jon',
|
||||||
'prefferedUsername' => 'jon',
|
'prefferedUsername' => 'jon',
|
||||||
),
|
),
|
||||||
'12345@example.com' => array(
|
'12345@example.com' => array(
|
||||||
|
'id' => 'https://12345.example.com',
|
||||||
'url' => 'https://12345.example.com',
|
'url' => 'https://12345.example.com',
|
||||||
'inbox' => 'https://12345.example.com/inbox',
|
'inbox' => 'https://12345.example.com/inbox',
|
||||||
'name' => '12345',
|
'name' => '12345',
|
||||||
'prefferedUsername' => '12345',
|
'prefferedUsername' => '12345',
|
||||||
),
|
),
|
||||||
'user2@example.com' => array(
|
'user2@example.com' => array(
|
||||||
|
'id' => 'https://user2.example.com',
|
||||||
'url' => 'https://user2.example.com',
|
'url' => 'https://user2.example.com',
|
||||||
'inbox' => 'https://user2.example.com/inbox',
|
'inbox' => 'https://user2.example.com/inbox',
|
||||||
'name' => 'user2',
|
'name' => 'user2',
|
||||||
|
@ -66,7 +72,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
|
|
||||||
$db_followers = array_map(
|
$db_followers = array_map(
|
||||||
function( $item ) {
|
function( $item ) {
|
||||||
return $item->get_actor();
|
return $item->get_url();
|
||||||
},
|
},
|
||||||
$db_followers
|
$db_followers
|
||||||
);
|
);
|
||||||
|
@ -107,7 +113,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
||||||
$this->assertEquals( 'https://example.com/author/jon', $follower->get_actor() );
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
||||||
|
|
||||||
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
||||||
$this->assertNull( $follower );
|
$this->assertNull( $follower );
|
||||||
|
@ -116,10 +122,10 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
$this->assertNull( $follower );
|
$this->assertNull( $follower );
|
||||||
|
|
||||||
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
||||||
$this->assertEquals( 'https://example.com/author/jon', $follower->get_actor() );
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
||||||
|
|
||||||
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://user2.example.com' );
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://user2.example.com' );
|
||||||
$this->assertEquals( 'https://user2.example.com', $follower2->get_actor() );
|
$this->assertEquals( 'https://user2.example.com', $follower2->get_url() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function test_delete_follower() {
|
public function test_delete_follower() {
|
||||||
|
@ -144,13 +150,13 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
||||||
$this->assertEquals( 'https://example.com/author/jon', $follower->get_actor() );
|
$this->assertEquals( 'https://example.com/author/jon', $follower->get_url() );
|
||||||
|
|
||||||
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
||||||
$this->assertEquals( 2, count( $followers ) );
|
$this->assertEquals( 2, count( $followers ) );
|
||||||
|
|
||||||
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
||||||
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_actor() );
|
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_url() );
|
||||||
|
|
||||||
\Activitypub\Collection\Followers::remove_follower( 1, 'https://example.com/author/jon' );
|
\Activitypub\Collection\Followers::remove_follower( 1, 'https://example.com/author/jon' );
|
||||||
|
|
||||||
|
@ -158,7 +164,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
$this->assertNull( $follower );
|
$this->assertNull( $follower );
|
||||||
|
|
||||||
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
$follower2 = \Activitypub\Collection\Followers::get_follower( 2, 'https://example.com/author/jon' );
|
||||||
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_actor() );
|
$this->assertEquals( 'https://example.com/author/jon', $follower2->get_url() );
|
||||||
|
|
||||||
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
$followers = \Activitypub\Collection\Followers::get_followers( 1 );
|
||||||
$this->assertEquals( 1, count( $followers ) );
|
$this->assertEquals( 1, count( $followers ) );
|
||||||
|
@ -174,7 +180,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = new \Activitypub\Model\Follower( 'https://example.com/author/jon' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'https://example.com/author/jon' );
|
||||||
|
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
|
@ -184,7 +190,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
|
|
||||||
$post_modified = gmdate( $mysql_time_format, $time );
|
$post_modified = gmdate( $mysql_time_format, $time );
|
||||||
$post_modified_gmt = gmdate( $mysql_time_format, ( $time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
|
$post_modified_gmt = gmdate( $mysql_time_format, ( $time + get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
|
||||||
$post_id = $follower->get_id();
|
$post_id = $follower->get__id();
|
||||||
|
|
||||||
$wpdb->query(
|
$wpdb->query(
|
||||||
$wpdb->prepare(
|
$wpdb->prepare(
|
||||||
|
@ -214,13 +220,13 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
\Activitypub\Collection\Followers::add_follower( 1, $follower );
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = new \Activitypub\Model\Follower( 'http://sally.example.org' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
||||||
|
|
||||||
for ( $i = 1; $i <= 15; $i++ ) {
|
for ( $i = 1; $i <= 15; $i++ ) {
|
||||||
add_post_meta( $follower->get_id(), 'errors', 'error ' . $i );
|
add_post_meta( $follower->get__id(), 'errors', 'error ' . $i );
|
||||||
}
|
}
|
||||||
|
|
||||||
$follower = new \Activitypub\Model\Follower( 'http://sally.example.org' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
||||||
$count = $follower->count_errors();
|
$count = $follower->count_errors();
|
||||||
|
|
||||||
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
||||||
|
@ -230,7 +236,7 @@ class Test_Db_Activitypub_Followers extends WP_UnitTestCase {
|
||||||
|
|
||||||
$follower->reset_errors();
|
$follower->reset_errors();
|
||||||
|
|
||||||
$follower = new \Activitypub\Model\Follower( 'http://sally.example.org' );
|
$follower = \Activitypub\Collection\Followers::get_follower( 1, 'http://sally.example.org' );
|
||||||
$count = $follower->count_errors();
|
$count = $follower->count_errors();
|
||||||
|
|
||||||
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
$followers = \Activitypub\Collection\Followers::get_faulty_followers();
|
||||||
|
|
Loading…
Reference in a new issue