. // }}} /** * ActivityPub implementation for GNU social * * @package GNUsocial * @category ActivityPub * * @author Diogo Peralta Cordeiro <@diogo.site> * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ namespace Plugin\ActivityPub\Util; use ActivityPhp\Type; use ActivityPhp\Type\TypeConfiguration; use ActivityPhp\Type\TypeResolver; use App\Core\Entity; use App\Core\Event; use App\Util\Exception\ClientException; use Exception; use InvalidArgumentException; use Plugin\ActivityPub\Util\Model\Activity; use Plugin\ActivityPub\Util\Model\Note; /** * This class handles translation between JSON and GS Entities * * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later */ abstract class Model { /** * Create a Type from an ActivityStreams 2.0 JSON string * * @throws Exception */ public static function jsonToType(string|array $data): Type\AbstractObject { if (\is_string($data)) { $attributes = json_decode($data, true); if (json_last_error() !== \JSON_ERROR_NONE || !\is_array($attributes) ) { throw new Exception( sprintf( "An error occurred during the JSON decoding.\n '%s'", $data, ), ); } } else { $attributes = $data; } if (!\array_key_exists('type', $attributes)) { throw new InvalidArgumentException('Missing "type" attribute in $data: ' . var_export($data, true)); } unset($data); try { $type = TypeResolver::getClass($attributes['type']); } catch (Exception $e) { $message = json_encode($attributes, \JSON_PRETTY_PRINT); throw new Exception( $e->getMessage() . "\n{$message}", ); } if (\is_string($type)) { $type = new $type(); } // Add our own extensions $validators = []; if (Event::handle('ActivityPubValidateActivityStreamsTwoData', [$attributes['type'], &$validators]) === Event::next) { foreach ($validators as $name => $class) { Type::addValidator($name, $class); $type->extend($name); } } TypeConfiguration::set('undefined_properties', 'include'); foreach ($attributes as $name => $value) { $type->set($name, $value); } return $type; } /** * Create an Entity from an ActivityStreams 2.0 JSON string */ abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity; /** * Get a JSON * * @param ?int $options PHP JSON options * * @throws ClientException */ public static function toJson(mixed $object, ?int $options = null): string { switch ($object::class) { case 'App\Entity\Activity': return Activity::toJson($object, $options); case 'App\Entity\Note': return Note::toJson($object, $options); default: $type = self::jsonToType($object); Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); return $type->toJson($options); } } }