[TOOLS] Run CS-fixer on all files

This commit is contained in:
Hugo Sales 2021-12-26 09:48:16 +00:00 committed by Diogo Peralta Cordeiro
parent 5e42723624
commit ec28f23025
Signed by: diogo
GPG Key ID: 18D2D35001FBFAB0
66 changed files with 494 additions and 579 deletions

View File

@ -30,12 +30,12 @@ use App\Core\GSFile;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router\Router;
use Component\Attachment\Entity\AttachmentThumbnail;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NoSuchFileException; use App\Util\Exception\NoSuchFileException;
use App\Util\Exception\NotFoundException; use App\Util\Exception\NotFoundException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use Component\Attachment\Entity\AttachmentThumbnail;
use Symfony\Component\HttpFoundation\HeaderUtils; use Symfony\Component\HttpFoundation\HeaderUtils;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -39,7 +41,7 @@ class ActorToAttachment extends Entity
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
private int $attachment_id; private int $attachment_id;
private int $actor_id; private int $actor_id;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setAttachmentId(int $attachment_id): self public function setAttachmentId(int $attachment_id): self
{ {
@ -77,10 +79,6 @@ class ActorToAttachment extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
/**
* @param int $attachment_id
* @return mixed
*/
public static function removeWhereAttachmentId(int $attachment_id): mixed public static function removeWhereAttachmentId(int $attachment_id): mixed
{ {
return DB::dql( return DB::dql(
@ -92,11 +90,6 @@ class ActorToAttachment extends Entity
); );
} }
/**
* @param int $actor_id
* @param int $attachment_id
* @return mixed
*/
public static function removeWhere(int $attachment_id, int $actor_id): mixed public static function removeWhere(int $attachment_id, int $actor_id): mixed
{ {
return DB::dql( return DB::dql(
@ -109,10 +102,6 @@ class ActorToAttachment extends Entity
); );
} }
/**
* @param int $actor_id
* @return mixed
*/
public static function removeWhereActorId(int $actor_id): mixed public static function removeWhereActorId(int $actor_id): mixed
{ {
return DB::dql( return DB::dql(

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -26,10 +28,10 @@ use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Entity\Note;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router\Router;
use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\DuplicateFoundException; use App\Util\Exception\DuplicateFoundException;
@ -77,17 +79,11 @@ class Attachment extends Entity
return $this->id; return $this->id;
} }
/**
* @return int
*/
public function getLives(): int public function getLives(): int
{ {
return $this->lives; return $this->lives;
} }
/**
* @param int $lives
*/
public function setLives(int $lives): void public function setLives(int $lives): void
{ {
$this->lives = $lives; $this->lives = $lives;
@ -176,39 +172,31 @@ class Attachment extends Entity
public function getMimetypeMajor(): ?string public function getMimetypeMajor(): ?string
{ {
$mime = $this->getMimetype(); $mime = $this->getMimetype();
return is_null($mime) ? $mime : GSFile::mimetypeMajor($mime); return \is_null($mime) ? $mime : GSFile::mimetypeMajor($mime);
} }
public function getMimetypeMinor(): ?string public function getMimetypeMinor(): ?string
{ {
$mime = $this->getMimetype(); $mime = $this->getMimetype();
return is_null($mime) ? $mime : GSFile::mimetypeMinor($mime); return \is_null($mime) ? $mime : GSFile::mimetypeMinor($mime);
} }
/**
* @return int
*/
public function livesIncrementAndGet(): int public function livesIncrementAndGet(): int
{ {
++$this->lives; ++$this->lives;
return $this->lives; return $this->lives;
} }
/**
* @return int
*/
public function livesDecrementAndGet(): int public function livesDecrementAndGet(): int
{ {
--$this->lives; --$this->lives;
return $this->lives; return $this->lives;
} }
const FILEHASH_ALGO = 'sha256'; public const FILEHASH_ALGO = 'sha256';
/** /**
* Delete a file if safe, removes dependencies, cleanups and flushes * Delete a file if safe, removes dependencies, cleanups and flushes
*
* @return bool
*/ */
public function kill(): bool public function kill(): bool
{ {
@ -223,7 +211,7 @@ class Attachment extends Entity
*/ */
public function deleteStorage(): bool public function deleteStorage(): bool
{ {
if (!is_null($filepath = $this->getPath())) { if (!\is_null($filepath = $this->getPath())) {
if (file_exists($filepath)) { if (file_exists($filepath)) {
if (@unlink($filepath) === false) { if (@unlink($filepath) === false) {
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
@ -248,6 +236,7 @@ class Attachment extends Entity
/** /**
* Attachment delete always removes dependencies, cleanups and flushes * Attachment delete always removes dependencies, cleanups and flushes
*
* @see kill() It's more likely that you want to use that rather than call delete directly * @see kill() It's more likely that you want to use that rather than call delete directly
*/ */
protected function delete(): bool protected function delete(): bool
@ -261,7 +250,7 @@ class Attachment extends Entity
// Collect files starting with the one associated with this attachment // Collect files starting with the one associated with this attachment
$files = []; $files = [];
if (!is_null($filepath = $this->getPath())) { if (!\is_null($filepath = $this->getPath())) {
$files[] = $filepath; $files[] = $filepath;
} }
@ -306,25 +295,21 @@ class Attachment extends Entity
/** /**
* TODO: Maybe this isn't the best way of handling titles * TODO: Maybe this isn't the best way of handling titles
* *
* @param null|Note $note
*
* @throws DuplicateFoundException * @throws DuplicateFoundException
* @throws NotFoundException * @throws NotFoundException
* @throws ServerException * @throws ServerException
*
* @return string
*/ */
public function getBestTitle(?Note $note = null): string public function getBestTitle(?Note $note = null): string
{ {
// If we have a note, then the best title is the title itself // If we have a note, then the best title is the title itself
if (!is_null(($note))) { if (!\is_null(($note))) {
$title = Cache::get('attachment-title-' . $this->getId() . '-' . $note->getId(), function () use ($note) { $title = Cache::get('attachment-title-' . $this->getId() . '-' . $note->getId(), function () use ($note) {
try { try {
$attachment_to_note = DB::findOneBy('attachment_to_note', [ $attachment_to_note = DB::findOneBy('attachment_to_note', [
'attachment_id' => $this->getId(), 'attachment_id' => $this->getId(),
'note_id' => $note->getId(), 'note_id' => $note->getId(),
]); ]);
if (!is_null($attachment_to_note->getTitle())) { if (!\is_null($attachment_to_note->getTitle())) {
return $attachment_to_note->getTitle(); return $attachment_to_note->getTitle();
} }
} catch (NotFoundException) { } catch (NotFoundException) {
@ -332,14 +317,14 @@ class Attachment extends Entity
Event::handle('AttachmentGetBestTitle', [$this, $note, &$title]); Event::handle('AttachmentGetBestTitle', [$this, $note, &$title]);
return $title; return $title;
} }
return null;
}); });
if ($title != null) { if ($title != null) {
return $title; return $title;
} }
} }
// Else // Else
if (!is_null($filename = $this->getFilename())) { if (!\is_null($filename = $this->getFilename())) {
// A filename would do just as well // A filename would do just as well
return $filename; return $filename;
} else { } else {
@ -359,7 +344,7 @@ class Attachment extends Entity
public function getPath() public function getPath()
{ {
$filename = $this->getFilename(); $filename = $this->getFilename();
return is_null($filename) ? null : Common::config('attachments', 'dir') . DIRECTORY_SEPARATOR . $filename; return \is_null($filename) ? null : Common::config('attachments', 'dir') . \DIRECTORY_SEPARATOR . $filename;
} }
public function getUrl(int $type = Router::ABSOLUTE_URL): string public function getUrl(int $type = Router::ABSOLUTE_URL): string
@ -368,9 +353,6 @@ class Attachment extends Entity
} }
/** /**
* @param null|string $size
* @param bool $crop
*
* @throws ClientException * @throws ClientException
* @throws NotFoundException * @throws NotFoundException
* @throws ServerException * @throws ServerException

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -39,7 +41,7 @@ class AttachmentToLink extends Entity
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
private int $attachment_id; private int $attachment_id;
private int $link_id; private int $link_id;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setAttachmentId(int $attachment_id): self public function setAttachmentId(int $attachment_id): self
{ {
@ -77,10 +79,6 @@ class AttachmentToLink extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
/**
* @param int $attachment_id
* @return mixed
*/
public static function removeWhereAttachmentId(int $attachment_id): mixed public static function removeWhereAttachmentId(int $attachment_id): mixed
{ {
return DB::dql( return DB::dql(
@ -92,11 +90,6 @@ class AttachmentToLink extends Entity
); );
} }
/**
* @param int $link_id
* @param int $attachment_id
* @return mixed
*/
public static function removeWhere(int $link_id, int $attachment_id): mixed public static function removeWhere(int $link_id, int $attachment_id): mixed
{ {
return DB::dql( return DB::dql(
@ -109,10 +102,6 @@ class AttachmentToLink extends Entity
); );
} }
/**
* @param int $link_id
* @return mixed
*/
public static function removeWhereLinkId(int $link_id): mixed public static function removeWhereLinkId(int $link_id): mixed
{ {
return DB::dql( return DB::dql(

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -19,7 +21,6 @@
namespace Component\Attachment\Entity; namespace Component\Attachment\Entity;
use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use DateTimeInterface; use DateTimeInterface;
@ -45,7 +46,7 @@ class AttachmentToNote extends Entity
private int $attachment_id; private int $attachment_id;
private int $note_id; private int $note_id;
private ?string $title; private ?string $title;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setAttachmentId(int $attachment_id): self public function setAttachmentId(int $attachment_id): self
{ {
@ -94,11 +95,6 @@ class AttachmentToNote extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
/**
* @param int $note_id
* @param int $attachment_id
* @return mixed
*/
public static function removeWhere(int $note_id, int $attachment_id): mixed public static function removeWhere(int $note_id, int $attachment_id): mixed
{ {
return DB::dql( return DB::dql(
@ -111,10 +107,6 @@ class AttachmentToNote extends Entity
); );
} }
/**
* @param int $note_id
* @return mixed
*/
public static function removeWhereNoteId(int $note_id): mixed public static function removeWhereNoteId(int $note_id): mixed
{ {
return DB::dql( return DB::dql(
@ -126,10 +118,6 @@ class AttachmentToNote extends Entity
); );
} }
/**
* @param int $attachment_id
* @return mixed
*/
public static function removeWhereAttachmentId(int $attachment_id): mixed public static function removeWhereAttachmentId(int $attachment_id): mixed
{ {
return DB::dql( return DB::dql(

View File

@ -27,8 +27,8 @@ use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use App\Core\Router\Router; use App\Core\Router\Router;
use Component\Attachment\Entity\Attachment;
use App\Util\Common; use App\Util\Common;
use Component\Attachment\Entity\Attachment;
use DateTimeInterface; use DateTimeInterface;
/** /**

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
/** /**
* @author James Walker <james@status.net> * @author James Walker <james@status.net>
* @author Craig Andrews <candrews@integralblue.com> * @author Craig Andrews <candrews@integralblue.com>
@ -8,13 +10,9 @@
namespace Component\FreeNetwork\Controller; namespace Component\FreeNetwork\Controller;
use App\Core\Controller;
use App\Core\Event; use App\Core\Event;
use Component\FreeNetwork\Util\Discovery; use Component\FreeNetwork\Util\Discovery;
use Component\FreeNetwork\Util\XrdController; use Component\FreeNetwork\Util\XrdController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use XML_XRD;
class HostMeta extends XrdController class HostMeta extends XrdController
{ {

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types = 1);
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
// GNU social is free software: you can redistribute it and/or modify // GNU social is free software: you can redistribute it and/or modify
@ -30,7 +32,6 @@ use App\Util\Common;
use Component\FreeNetwork\Util\Discovery; use Component\FreeNetwork\Util\Discovery;
use Component\FreeNetwork\Util\XrdController; use Component\FreeNetwork\Util\XrdController;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class OwnerXrd extends XrdController class OwnerXrd extends XrdController
{ {

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types = 1);
/* /*
* StatusNet - the distributed open-source microblogging tool * StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc. * Copyright (C) 2010, StatusNet, Inc.
@ -69,7 +71,7 @@ class Webfinger extends XrdController
$this->xrd->subject = $this->resource; $this->xrd->subject = $this->resource;
foreach ($this->target->getAliases() as $alias) { foreach ($this->target->getAliases() as $alias) {
if ($alias != $this->xrd->subject && !in_array($alias, $this->xrd->aliases)) { if ($alias != $this->xrd->subject && !\in_array($alias, $this->xrd->aliases)) {
$this->xrd->aliases[] = $alias; $this->xrd->aliases[] = $alias;
} }
} }

View File

@ -32,17 +32,11 @@ declare(strict_types = 1);
namespace Component\FreeNetwork\Entity; namespace Component\FreeNetwork\Entity;
use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use function App\Core\I18n\_m;
use App\Core\Log;
use App\Entity\Actor; use App\Entity\Actor;
use Component\FreeNetwork\Util\Discovery; use Component\FreeNetwork\Util\Discovery;
use DateTimeInterface; use DateTimeInterface;
use Exception;
use Plugin\ActivityPub\Util\DiscoveryHints;
use Plugin\ActivityPub\Util\Explorer;
/** /**
* Table Definition for free_network_actor_protocol * Table Definition for free_network_actor_protocol
@ -119,9 +113,9 @@ class FreeNetworkActorProtocol extends Entity
public static function protocolSucceeded(string $protocol, int|Actor $actor_id, string $addr): void public static function protocolSucceeded(string $protocol, int|Actor $actor_id, string $addr): void
{ {
$actor_id = is_int($actor_id) ? $actor_id : $actor_id->getId(); $actor_id = \is_int($actor_id) ? $actor_id : $actor_id->getId();
$attributed_protocol = self::getByPK(['actor_id' => $actor_id]); $attributed_protocol = self::getByPK(['actor_id' => $actor_id]);
if (is_null($attributed_protocol)) { if (\is_null($attributed_protocol)) {
$attributed_protocol = self::create([ $attributed_protocol = self::create([
'actor_id' => $actor_id, 'actor_id' => $actor_id,
'protocol' => $protocol, 'protocol' => $protocol,
@ -130,14 +124,14 @@ class FreeNetworkActorProtocol extends Entity
} else { } else {
$attributed_protocol->setProtocol($protocol); $attributed_protocol->setProtocol($protocol);
} }
DB::wrapInTransaction(fn() => DB::persist($attributed_protocol)); DB::wrapInTransaction(fn () => DB::persist($attributed_protocol));
} }
public static function canIActor(string $protocol, int|Actor $actor_id): bool public static function canIActor(string $protocol, int|Actor $actor_id): bool
{ {
$actor_id = is_int($actor_id) ? $actor_id : $actor_id->getId(); $actor_id = \is_int($actor_id) ? $actor_id : $actor_id->getId();
$attributed_protocol = self::getByPK(['actor_id' => $actor_id])?->getProtocol(); $attributed_protocol = self::getByPK(['actor_id' => $actor_id])?->getProtocol();
if (is_null($attributed_protocol)) { if (\is_null($attributed_protocol)) {
// If it is not attributed, you can go ahead. // If it is not attributed, you can go ahead.
return true; return true;
} else { } else {
@ -149,9 +143,9 @@ class FreeNetworkActorProtocol extends Entity
public static function canIAddr(string $protocol, string $target): bool public static function canIAddr(string $protocol, string $target): bool
{ {
// Normalize $addr, i.e. add 'acct:' if missing // Normalize $addr, i.e. add 'acct:' if missing
$addr = Discovery::normalize($target); $addr = Discovery::normalize($target);
$attributed_protocol = self::getByPK(['addr' => $addr])?->getProtocol(); $attributed_protocol = self::getByPK(['addr' => $addr])?->getProtocol();
if (is_null($attributed_protocol)) { if (\is_null($attributed_protocol)) {
// If it is not attributed, you can go ahead. // If it is not attributed, you can go ahead.
return true; return true;
} else { } else {
@ -167,7 +161,7 @@ class FreeNetworkActorProtocol extends Entity
'fields' => [ 'fields' => [
'actor_id' => ['type' => 'int', 'not null' => true], 'actor_id' => ['type' => 'int', 'not null' => true],
'protocol' => ['type' => 'varchar', 'length' => 32, 'description' => 'the protocol plugin that should handle federation of this actor'], 'protocol' => ['type' => 'varchar', 'length' => 32, 'description' => 'the protocol plugin that should handle federation of this actor'],
'addr' => ['type' => 'text', 'not null' => true, 'description' => 'webfinger acct'], 'addr' => ['type' => 'text', 'not null' => true, 'description' => 'webfinger acct'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
], ],

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types = 1);
/** /**
* StatusNet, the distributed open-source microblogging tool * StatusNet, the distributed open-source microblogging tool
* *
@ -50,7 +52,7 @@ use Throwable;
*/ */
class WebfingerReconstructionException extends ServerException class WebfingerReconstructionException extends ServerException
{ {
public function __construct(string $message = '', int $code = 500, Throwable $previous = null) public function __construct(string $message = '', int $code = 500, ?Throwable $previous = null)
{ {
// We could log an entry here with the search parameters // We could log an entry here with the search parameters
parent::__construct(_m('WebFinger URI generation failed.')); parent::__construct(_m('WebFinger URI generation failed.'));

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types = 1);
/** /**
* StatusNet - the distributed open-source microblogging tool * StatusNet - the distributed open-source microblogging tool
* Copyright (C) 2010, StatusNet, Inc. * Copyright (C) 2010, StatusNet, Inc.
@ -69,7 +71,7 @@ class LinkHeader
$this->type = null; $this->type = null;
// remove uri-reference from header // remove uri-reference from header
$str = substr($str, strlen($uri_reference[0])); $str = mb_substr($str, \mb_strlen($uri_reference[0]));
// parse link-params // parse link-params
$params = explode(';', $str); $params = explode(';', $str);
@ -78,7 +80,7 @@ class LinkHeader
if (empty($param)) { if (empty($param)) {
continue; continue;
} }
list($param_name, $param_value) = explode('=', $param, 2); [$param_name, $param_value] = explode('=', $param, 2);
$param_name = trim($param_name); $param_name = trim($param_name);
$param_value = preg_replace('(^"|"$)', '', trim($param_value)); $param_value = preg_replace('(^"|"$)', '', trim($param_value));
@ -110,18 +112,18 @@ class LinkHeader
$headers = $response->getHeader('Link'); $headers = $response->getHeader('Link');
if ($headers) { if ($headers) {
// Can get an array or string, so try to simplify the path // Can get an array or string, so try to simplify the path
if (!is_array($headers)) { if (!\is_array($headers)) {
$headers = [$headers]; $headers = [$headers];
} }
foreach ($headers as $header) { foreach ($headers as $header) {
$lh = new self($header); $lh = new self($header);
if ((is_null($rel) || $lh->rel == $rel) && (is_null($type) || $lh->type == $type)) { if ((\is_null($rel) || $lh->rel == $rel) && (\is_null($type) || $lh->type == $type)) {
return $lh->href; return $lh->href;
} }
} }
} }
return null;
} }
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util\LrddMethod; namespace Component\FreeNetwork\Util\LrddMethod;
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -39,29 +41,27 @@ class LrddMethodHostMeta extends LRDDMethod
/** /**
* For RFC6415 and HTTP URIs, fetch the host-meta file * For RFC6415 and HTTP URIs, fetch the host-meta file
* and look for LRDD templates * and look for LRDD templates
*
* @param mixed $uri
*/ */
public function discover($uri) public function discover($uri)
{ {
// This is allowed for RFC6415 but not the 'WebFinger' RFC7033. // This is allowed for RFC6415 but not the 'WebFinger' RFC7033.
$try_schemes = ['https', 'http']; $try_schemes = ['https', 'http'];
$scheme = mb_strtolower(parse_url($uri, PHP_URL_SCHEME)); $scheme = mb_strtolower(parse_url($uri, \PHP_URL_SCHEME));
switch ($scheme) { switch ($scheme) {
case 'acct': case 'acct':
// We can't use parse_url data for this, since the 'host' // We can't use parse_url data for this, since the 'host'
// entry is only set if the scheme has '://' after it. // entry is only set if the scheme has '://' after it.
$parts = explode('@', parse_url($uri, PHP_URL_PATH), 2); $parts = explode('@', parse_url($uri, \PHP_URL_PATH), 2);
if (!Discovery::isAcct($uri) || count($parts) != 2) { if (!Discovery::isAcct($uri) || \count($parts) != 2) {
throw new Exception('Bad resource URI: ' . $uri); throw new Exception('Bad resource URI: ' . $uri);
} }
[, $domain] = $parts; [, $domain] = $parts;
break; break;
case 'http': case 'http':
case 'https': case 'https':
$domain = mb_strtolower(parse_url($uri, PHP_URL_HOST)); $domain = mb_strtolower(parse_url($uri, \PHP_URL_HOST));
$try_schemes = [$scheme]; $try_schemes = [$scheme];
break; break;
default: default:

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util\LrddMethod; namespace Component\FreeNetwork\Util\LrddMethod;
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -38,10 +40,7 @@ class LrddMethodLinkHtml extends LRDDMethod
* For HTTP IDs, fetch the URL and look for <link> elements * For HTTP IDs, fetch the URL and look for <link> elements
* in the HTML response. * in the HTML response.
* *
* @param mixed $uri
*
* @todo fail out of WebFinger URIs faster * @todo fail out of WebFinger URIs faster
*
*/ */
public function discover($uri) public function discover($uri)
{ {
@ -65,7 +64,7 @@ class LrddMethodLinkHtml extends LRDDMethod
preg_match('/<head(\s[^>]*)?>(.*?)<\/head>/is', $html, $head_matches); preg_match('/<head(\s[^>]*)?>(.*?)<\/head>/is', $html, $head_matches);
if (count($head_matches) != 3) { if (\count($head_matches) != 3) {
return []; return [];
} }
[, , $head_html] = $head_matches; [, , $head_html] = $head_matches;
@ -78,23 +77,23 @@ class LrddMethodLinkHtml extends LRDDMethod
$link_type = null; $link_type = null;
preg_match('/\srel=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $rel_matches); preg_match('/\srel=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $rel_matches);
if (count($rel_matches) > 3) { if (\count($rel_matches) > 3) {
$link_rel = $rel_matches[3]; $link_rel = $rel_matches[3];
} elseif (count($rel_matches) > 1) { } elseif (\count($rel_matches) > 1) {
$link_rel = $rel_matches[1]; $link_rel = $rel_matches[1];
} }
preg_match('/\shref=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $href_matches); preg_match('/\shref=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $href_matches);
if (count($href_matches) > 3) { if (\count($href_matches) > 3) {
$link_uri = $href_matches[3]; $link_uri = $href_matches[3];
} elseif (count($href_matches) > 1) { } elseif (\count($href_matches) > 1) {
$link_uri = $href_matches[1]; $link_uri = $href_matches[1];
} }
preg_match('/\stype=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $type_matches); preg_match('/\stype=(("|\')([^\\2]*?)\\2|[^"\'\s]+)/i', $link_html, $type_matches);
if (count($type_matches) > 3) { if (\count($type_matches) > 3) {
$link_type = $type_matches[3]; $link_type = $type_matches[3];
} elseif (count($type_matches) > 1) { } elseif (\count($type_matches) > 1) {
$link_type = $type_matches[1]; $link_type = $type_matches[1];
} }

View File

@ -1,4 +1,6 @@
<?php <?php
declare(strict_types = 1);
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
// GNU social is free software: you can redistribute it and/or modify // GNU social is free software: you can redistribute it and/or modify
@ -36,19 +38,17 @@ class LrddMethodWebfinger extends LRDDMethod
/** /**
* Simply returns the WebFinger URL over HTTPS at the uri's domain: * Simply returns the WebFinger URL over HTTPS at the uri's domain:
* https://{domain}/.well-known/webfinger?resource={uri} * https://{domain}/.well-known/webfinger?resource={uri}
*
* @param mixed $uri
*/ */
public function discover($uri) public function discover($uri)
{ {
$parts = explode('@', parse_url($uri, PHP_URL_PATH), 2); $parts = explode('@', parse_url($uri, \PHP_URL_PATH), 2);
if (!Discovery::isAcct($uri) || count($parts) != 2) { if (!Discovery::isAcct($uri) || \count($parts) != 2) {
throw new Exception('Bad resource URI: ' . $uri); throw new Exception('Bad resource URI: ' . $uri);
} }
[, $domain] = $parts; [, $domain] = $parts;
if (!filter_var($domain, FILTER_VALIDATE_IP) if (!filter_var($domain, \FILTER_VALIDATE_IP)
&& !filter_var(gethostbyname($domain), FILTER_VALIDATE_IP)) { && !filter_var(gethostbyname($domain), \FILTER_VALIDATE_IP)) {
throw new Exception('Bad resource host.'); throw new Exception('Bad resource host.');
} }
@ -56,7 +56,7 @@ class LrddMethodWebfinger extends LRDDMethod
Discovery::LRDD_REL, Discovery::LRDD_REL,
'https://' . $domain . '/.well-known/webfinger?resource={uri}', 'https://' . $domain . '/.well-known/webfinger?resource={uri}',
Discovery::JRD_MIMETYPE, Discovery::JRD_MIMETYPE,
true // isTemplate true, // isTemplate
); );
return [$link]; return [$link];

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util; namespace Component\FreeNetwork\Util;
use App\Core\Entity; use App\Core\Entity;
@ -40,8 +42,6 @@ abstract class WebfingerResource
/** /**
* List of alternative IDs of a certain Actor * List of alternative IDs of a certain Actor
*
* @return array
*/ */
public function getAliases(): array public function getAliases(): array
{ {
@ -53,7 +53,7 @@ abstract class WebfingerResource
// you've run HTTPS all the time! // you've run HTTPS all the time!
if (Common::config('fix', 'legacy_http')) { if (Common::config('fix', 'legacy_http')) {
foreach ($aliases as $alias => $id) { foreach ($aliases as $alias => $id) {
if (!strtolower(parse_url($alias, PHP_URL_SCHEME)) === 'https') { if (!mb_strtolower(parse_url($alias, \PHP_URL_SCHEME)) === 'https') {
continue; continue;
} }
$aliases[preg_replace('/^https:/i', 'http:', $alias, 1)] = $id; $aliases[preg_replace('/^https:/i', 'http:', $alias, 1)] = $id;

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util\WebfingerResource; namespace Component\FreeNetwork\Util\WebfingerResource;
use App\Core\Event; use App\Core\Event;
@ -24,9 +26,9 @@ use XML_XRD_Element_Link;
*/ */
class WebfingerResourceActor extends WebFingerResource class WebfingerResourceActor extends WebFingerResource
{ {
const PROFILEPAGE = 'http://webfinger.net/rel/profile-page'; public const PROFILEPAGE = 'http://webfinger.net/rel/profile-page';
public function __construct(Actor $object = null) public function __construct(?Actor $object = null)
{ {
// The type argument above verifies that it's our class // The type argument above verifies that it's our class
parent::__construct($object); parent::__construct($object);
@ -49,8 +51,9 @@ class WebfingerResourceActor extends WebFingerResource
/** /**
* Reconstruct WebFinger acct: from object * Reconstruct WebFinger acct: from object
* *
* @return array|false|mixed|string|string[]|null
* @throws WebfingerReconstructionException * @throws WebfingerReconstructionException
*
* @return null|array|false|mixed|string|string[]
*/ */
public function reconstructAcct() public function reconstructAcct()
{ {
@ -58,7 +61,7 @@ class WebfingerResourceActor extends WebFingerResource
if (Event::handle('StartWebFingerReconstruction', [$this->object, &$acct])) { if (Event::handle('StartWebFingerReconstruction', [$this->object, &$acct])) {
// TODO: getUri may not always give us the correct host on remote users? // TODO: getUri may not always give us the correct host on remote users?
$host = parse_url($this->object->getUri(Router::ABSOLUTE_URL), PHP_URL_HOST); $host = parse_url($this->object->getUri(Router::ABSOLUTE_URL), \PHP_URL_HOST);
if (empty($this->object->getNickname()) || empty($host)) { if (empty($this->object->getNickname()) || empty($host)) {
throw new WebFingerReconstructionException(print_r($this->object, true)); throw new WebFingerReconstructionException(print_r($this->object, true));
} }
@ -75,8 +78,11 @@ class WebfingerResourceActor extends WebFingerResource
if (Event::handle('StartWebFingerProfileLinks', [$xrd, $this->object])) { if (Event::handle('StartWebFingerProfileLinks', [$xrd, $this->object])) {
// Profile page, can give more metadata from Link header or HTML parsing // Profile page, can give more metadata from Link header or HTML parsing
$xrd->links[] = new XML_XRD_Element_Link(self::PROFILEPAGE, $xrd->links[] = new XML_XRD_Element_Link(
$this->object->getUrl(Router::ABSOLUTE_URL), 'text/html'); self::PROFILEPAGE,
$this->object->getUrl(Router::ABSOLUTE_URL),
'text/html',
);
// // XFN // // XFN
// $xrd->links[] = new XML_XRD_Element_Link('http://gmpg.org/xfn/11', // $xrd->links[] = new XML_XRD_Element_Link('http://gmpg.org/xfn/11',

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util\WebfingerResource; namespace Component\FreeNetwork\Util\WebfingerResource;
use App\Core\Event; use App\Core\Event;
@ -22,7 +24,7 @@ use XML_XRD_Element_Link;
*/ */
class WebfingerResourceNote extends WebfingerResource class WebfingerResourceNote extends WebfingerResource
{ {
public function __construct(Note $object = null) public function __construct(?Note $object = null)
{ {
// The type argument above verifies that it's our class // The type argument above verifies that it's our class
parent::__construct($object); parent::__construct($object);
@ -30,29 +32,37 @@ class WebfingerResourceNote extends WebfingerResource
/** /**
* Update given XRD with self's data * Update given XRD with self's data
*
* @param XML_XRD $xrd
*/ */
public function updateXRD(XML_XRD $xrd) public function updateXRD(XML_XRD $xrd)
{ {
if (Event::handle('StartWebFingerNoticeLinks', [$xrd, $this->object])) { if (Event::handle('StartWebFingerNoticeLinks', [$xrd, $this->object])) {
if ($this->object->isLocal()) { if ($this->object->isLocal()) {
$xrd->links[] = new XML_XRD_Element_Link('alternate', $xrd->links[] = new XML_XRD_Element_Link(
common_local_url('ApiStatusesShow', 'alternate',
common_local_url(
'ApiStatusesShow',
['id' => $this->object->id, ['id' => $this->object->id,
'format' => 'atom', ]), 'format' => 'atom', ],
'application/atom+xml'); ),
'application/atom+xml',
);
$xrd->links[] = new XML_XRD_Element_Link('alternate', $xrd->links[] = new XML_XRD_Element_Link(
common_local_url('ApiStatusesShow', 'alternate',
common_local_url(
'ApiStatusesShow',
['id' => $this->object->id, ['id' => $this->object->id,
'format' => 'json', ]), 'format' => 'json', ],
'application/json'); ),
'application/json',
);
} else { } else {
try { try {
$xrd->links[] = new XML_XRD_Element_Link('alternate', $xrd->links[] = new XML_XRD_Element_Link(
'alternate',
$this->object->getUrl(), $this->object->getUrl(),
'text/html'); 'text/html',
);
} catch (InvalidUrlException $e) { } catch (InvalidUrlException $e) {
// don't do a fallback in webfinger // don't do a fallback in webfinger
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
namespace Component\FreeNetwork\Util; namespace Component\FreeNetwork\Util;
use App\Core\Controller; use App\Core\Controller;
@ -35,4 +37,4 @@ abstract class XrdController extends Controller
$this->setXRD(); $this->setXRD();
return ['xrd' => $this->xrd, 'default_mimetype' => $this->default_mimetype]; return ['xrd' => $this->xrd, 'default_mimetype' => $this->default_mimetype];
} }
} }

View File

@ -28,13 +28,13 @@ use App\Core\Controller;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use Component\Language\Entity\ActorLanguage;
use Component\Language\Entity\Language as LangEntity;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\NoLoggedInUser; use App\Util\Exception\NoLoggedInUser;
use App\Util\Exception\RedirectException; use App\Util\Exception\RedirectException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use App\Util\Form\FormFields; use App\Util\Form\FormFields;
use Component\Language\Entity\ActorLanguage;
use Component\Language\Entity\Language as LangEntity;
use Functional as F; use Functional as F;
use Symfony\Component\Form\Extension\Core\Type\IntegerType; use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
@ -26,13 +26,12 @@ namespace Component\Language\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use function App\Core\I18n\_m;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use DateTimeInterface; use DateTimeInterface;
use Functional as F; use Functional as F;
use function App\Core\I18n\_m;
use function is_null;
/** /**
* Entity for languages * Entity for languages
@ -115,8 +114,8 @@ class Language extends Entity
{ {
return Cache::getHashMapKey( return Cache::getHashMapKey(
map_key: 'languages-id', map_key: 'languages-id',
key: (string)$id, key: (string) $id,
calculate_map: fn() => F\reindex(DB::dql('select l from language l'), fn(self $l) => (string)$l->getId()), calculate_map: fn () => F\reindex(DB::dql('select l from language l'), fn (self $l) => (string) $l->getId()),
); );
} }
@ -125,7 +124,7 @@ class Language extends Entity
return Cache::getHashMapKey( return Cache::getHashMapKey(
'languages', 'languages',
$locale, $locale,
calculate_map: fn() => F\reindex(DB::dql('select l from language l'), fn(self $l) => $l->getLocale()), calculate_map: fn () => F\reindex(DB::dql('select l from language l'), fn (self $l) => $l->getLocale()),
); );
} }
@ -138,10 +137,10 @@ class Language extends Entity
{ {
$langs = Cache::getHashMap( $langs = Cache::getHashMap(
'languages', 'languages',
fn() => F\reindex(DB::dql('select l from language l'), fn(self $l) => $l->getLocale()), fn () => F\reindex(DB::dql('select l from language l'), fn (self $l) => $l->getLocale()),
); );
return array_merge(...F\map(array_values($langs), fn($l) => $l->toChoiceFormat())); return array_merge(...F\map(array_values($langs), fn ($l) => $l->toChoiceFormat()));
} }
public function toChoiceFormat(): array public function toChoiceFormat(): array
@ -156,18 +155,18 @@ class Language extends Entity
public static function getSortedLanguageChoices(?Actor $actor, ?Actor $context_actor, ?bool $use_short_display): array public static function getSortedLanguageChoices(?Actor $actor, ?Actor $context_actor, ?bool $use_short_display): array
{ {
$language_choices = self::getLanguageChoices(); $language_choices = self::getLanguageChoices();
if (is_null($actor)) { if (\is_null($actor)) {
return [$language_choices, []]; return [$language_choices, []];
} }
$preferred_language_choices = $actor->getPreferredLanguageChoices($context_actor); $preferred_language_choices = $actor->getPreferredLanguageChoices($context_actor);
ksort($language_choices); ksort($language_choices);
if ($use_short_display ?? Common::config('posting', 'use_short_language_display')) { if ($use_short_display ?? Common::config('posting', 'use_short_language_display')) {
$key = array_key_first($preferred_language_choices); $key = array_key_first($preferred_language_choices);
$language = $preferred_language_choices[$key]; $language = $preferred_language_choices[$key];
unset($preferred_language_choices[$key], $language_choices[$key]); unset($preferred_language_choices[$key], $language_choices[$key]);
$short_display = $language->getShortDisplay(); $short_display = $language->getShortDisplay();
$preferred_language_choices[$short_display] = ($locale = $language->getLocale()); $preferred_language_choices[$short_display] = ($locale = $language->getLocale());
$language_choices[$short_display] = $locale; $language_choices[$short_display] = $locale;
} }
return [$language_choices, $preferred_language_choices]; return [$language_choices, $preferred_language_choices];
} }
@ -175,14 +174,14 @@ class Language extends Entity
public static function schemaDef(): array public static function schemaDef(): array
{ {
return [ return [
'name' => 'language', 'name' => 'language',
'description' => 'all known languages', 'description' => 'all known languages',
'fields' => [ 'fields' => [
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], 'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'locale' => ['type' => 'varchar', 'length' => 64, 'description' => 'The locale identifier for the language of a note. 2-leter-iso-language-code_4-leter-script-code_2-leter-iso-country-code, but kept longer in case we get a different format'], 'locale' => ['type' => 'varchar', 'length' => 64, 'description' => 'The locale identifier for the language of a note. 2-leter-iso-language-code_4-leter-script-code_2-leter-iso-country-code, but kept longer in case we get a different format'],
'long_display' => ['type' => 'varchar', 'length' => 64, 'description' => 'The long display string for the language, in english (translated later)'], 'long_display' => ['type' => 'varchar', 'length' => 64, 'description' => 'The long display string for the language, in english (translated later)'],
'short_display' => ['type' => 'varchar', 'length' => 12, 'description' => 'The short display string for the language (used for the first option)'], 'short_display' => ['type' => 'varchar', 'length' => 12, 'description' => 'The short display string for the language (used for the first option)'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
], ],
'primary key' => ['id'], 'primary key' => ['id'],
'unique keys' => [ 'unique keys' => [

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -40,7 +42,7 @@ class NoteToLink extends Entity
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
private int $link_id; private int $link_id;
private int $note_id; private int $note_id;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setLinkId(int $link_id): self public function setLinkId(int $link_id): self
{ {
@ -93,10 +95,6 @@ class NoteToLink extends Entity
return parent::create($args, $obj); return parent::create($args, $obj);
} }
/**
* @param int $note_id
* @return mixed
*/
public static function removeWhereNoteId(int $note_id): mixed public static function removeWhereNoteId(int $note_id): mixed
{ {
return DB::dql( return DB::dql(
@ -108,11 +106,6 @@ class NoteToLink extends Entity
); );
} }
/**
* @param int $link_id
* @param int $note_id
* @return mixed
*/
public static function removeWhere(int $link_id, int $note_id): mixed public static function removeWhere(int $link_id, int $note_id): mixed
{ {
return DB::dql( return DB::dql(
@ -125,10 +118,6 @@ class NoteToLink extends Entity
); );
} }
/**
* @param int $link_id
* @return mixed
*/
public static function removeWhereLinkId(int $link_id): mixed public static function removeWhereLinkId(int $link_id): mixed
{ {
return DB::dql( return DB::dql(

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -46,8 +48,8 @@ class Notification extends Entity
private int $activity_id; private int $activity_id;
private int $target_id; private int $target_id;
private ?string $reason; private ?string $reason;
private \DateTimeInterface $created; private DateTimeInterface $created;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setActivityId(int $activity_id): self public function setActivityId(int $activity_id): self
{ {
@ -107,9 +109,6 @@ class Notification extends Entity
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
/**
* @return Actor
*/
public function getTarget(): Actor public function getTarget(): Actor
{ {
return Actor::getById($this->getTargetId()); return Actor::getById($this->getTargetId());
@ -122,18 +121,14 @@ class Notification extends Entity
*/ */
public static function getNotificationTargetIdsByActivity(int|Activity $activity_id): array public static function getNotificationTargetIdsByActivity(int|Activity $activity_id): array
{ {
$notifications = DB::findBy('notification', ['activity_id' => is_int($activity_id) ? $activity_id : $activity_id->getId()]); $notifications = DB::findBy('notification', ['activity_id' => \is_int($activity_id) ? $activity_id : $activity_id->getId()]);
$targets = []; $targets = [];
foreach ($notifications as $notification) { foreach ($notifications as $notification) {
$targets[] = $notification->getTargetId(); $targets[] = $notification->getTargetId();
} }
return $targets; return $targets;
} }
/**
* @param int|Activity $activity_id
* @return array
*/
public function getNotificationTargetsByActivity(int|Activity $activity_id): array public function getNotificationTargetsByActivity(int|Activity $activity_id): array
{ {
return DB::findBy('actor', ['id' => $this->getNotificationTargetIdsByActivity($activity_id)]); return DB::findBy('actor', ['id' => $this->getNotificationTargetIdsByActivity($activity_id)]);
@ -154,7 +149,7 @@ class Notification extends Entity
'primary key' => ['activity_id', 'target_id'], 'primary key' => ['activity_id', 'target_id'],
'indexes' => [ 'indexes' => [
'attention_activity_id_idx' => ['activity_id'], 'attention_activity_id_idx' => ['activity_id'],
'attention_target_id_idx' => ['target_id'], 'attention_target_id_idx' => ['target_id'],
], ],
]; ];
} }

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -48,8 +50,8 @@ class UserNotificationPrefs extends Entity
private bool $dm = true; private bool $dm = true;
private bool $post_on_status_change = false; private bool $post_on_status_change = false;
private ?bool $enable_posting; private ?bool $enable_posting;
private \DateTimeInterface $created; private DateTimeInterface $created;
private \DateTimeInterface $modified; private DateTimeInterface $modified;
public function setUserId(int $user_id): self public function setUserId(int $user_id): self
{ {

View File

@ -37,7 +37,6 @@ use App\Core\Security;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\GroupInbox; use App\Entity\GroupInbox;
use Component\Language\Entity\Language;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
@ -49,6 +48,7 @@ use App\Util\Formatting;
use Component\Attachment\Entity\ActorToAttachment; use Component\Attachment\Entity\ActorToAttachment;
use Component\Attachment\Entity\AttachmentToNote; use Component\Attachment\Entity\AttachmentToNote;
use Component\Conversation\Conversation; use Component\Conversation\Conversation;
use Component\Language\Entity\Language;
use Functional as F; use Functional as F;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\FileType; use Symfony\Component\Form\Extension\Core\Type\FileType;

View File

@ -26,7 +26,6 @@ namespace Component\Tag;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use Component\Language\Entity\Language;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Modules\Component; use App\Core\Modules\Component;
use App\Core\Router\Router; use App\Core\Router\Router;
@ -38,6 +37,7 @@ use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Formatting; use App\Util\Formatting;
use App\Util\HTML; use App\Util\HTML;
use Component\Language\Entity\Language;
use Component\Tag\Controller as C; use Component\Tag\Controller as C;
use Doctrine\Common\Collections\ExpressionBuilder; use Doctrine\Common\Collections\ExpressionBuilder;
use Doctrine\ORM\Query\Expr; use Doctrine\ORM\Query\Expr;

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -106,15 +107,15 @@ class ActivitypubActivity extends Entity
public static function schemaDef(): array public static function schemaDef(): array
{ {
return [ return [
'name' => 'activitypub_activity', 'name' => 'activitypub_activity',
'fields' => [ 'fields' => [
'activity_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Activity.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'activity_id to give attention'], 'activity_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Activity.id', 'multiplicity' => 'one to one', 'not null' => true, 'description' => 'activity_id to give attention'],
'activity_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Activity\'s URI'], 'activity_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Activity\'s URI'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
], ],
'primary key' => ['activity_uri'], 'primary key' => ['activity_uri'],
'indexes' => [ 'indexes' => [
'activity_activity_uri_idx' => ['activity_uri'], 'activity_activity_uri_idx' => ['activity_uri'],
], ],
]; ];

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -33,6 +34,7 @@ namespace Plugin\ActivityPub\Entity;
use App\Core\Cache; use App\Core\Cache;
use App\Core\Entity; use App\Core\Entity;
use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Entity\Actor; use App\Entity\Actor;
use Component\FreeNetwork\Util\Discovery; use Component\FreeNetwork\Util\Discovery;
@ -41,9 +43,6 @@ use Exception;
use Plugin\ActivityPub\Util\DiscoveryHints; use Plugin\ActivityPub\Util\DiscoveryHints;
use Plugin\ActivityPub\Util\Explorer; use Plugin\ActivityPub\Util\Explorer;
use XML_XRD; use XML_XRD;
use function App\Core\I18n\_m;
use function array_key_exists;
use function is_null;
/** /**
* Table Definition for activitypub_actor * Table Definition for activitypub_actor
@ -158,10 +157,10 @@ class ActivitypubActor extends Entity
$addr = Discovery::normalize($addr); $addr = Discovery::normalize($addr);
// Try the cache // Try the cache
$uri = Cache::get(sprintf('ActivitypubActor-webfinger-%s', urlencode($addr)), fn() => false); $uri = Cache::get(sprintf('ActivitypubActor-webfinger-%s', urlencode($addr)), fn () => false);
if ($uri !== false) { if ($uri !== false) {
if (is_null($uri)) { if (\is_null($uri)) {
// TRANS: Exception. // TRANS: Exception.
throw new Exception(_m('Not a valid WebFinger address (via cache).')); throw new Exception(_m('Not a valid WebFinger address (via cache).'));
} }
@ -197,7 +196,7 @@ class ActivitypubActor extends Entity
DiscoveryHints::fromXRD($xrd), DiscoveryHints::fromXRD($xrd),
); );
if (array_key_exists('activitypub', $hints)) { if (\array_key_exists('activitypub', $hints)) {
$uri = $hints['activitypub']; $uri = $hints['activitypub'];
try { try {
LOG::info("Discovery on acct:{$addr} with URI:{$uri}"); LOG::info("Discovery on acct:{$addr} with URI:{$uri}");
@ -240,9 +239,7 @@ class ActivitypubActor extends Entity
/** /**
* @param ActivitypubActor $ap_actor * @param ActivitypubActor $ap_actor
* @param Actor $actor *
* @param ActivitypubRsa $activitypub_rsa
* @param string $res
* @throws Exception * @throws Exception
*/ */
public static function update_profile(self &$ap_actor, Actor &$actor, ActivitypubRsa &$activitypub_rsa, string $res): void public static function update_profile(self &$ap_actor, Actor &$actor, ActivitypubRsa &$activitypub_rsa, string $res): void
@ -253,17 +250,17 @@ class ActivitypubActor extends Entity
public static function schemaDef(): array public static function schemaDef(): array
{ {
return [ return [
'name' => 'activitypub_actor', 'name' => 'activitypub_actor',
'fields' => [ 'fields' => [
'uri' => ['type' => 'text', 'not null' => true], 'uri' => ['type' => 'text', 'not null' => true],
'actor_id' => ['type' => 'int', 'not null' => true], 'actor_id' => ['type' => 'int', 'not null' => true],
'inbox_uri' => ['type' => 'text', 'not null' => true], 'inbox_uri' => ['type' => 'text', 'not null' => true],
'inbox_shared_uri' => ['type' => 'text'], 'inbox_shared_uri' => ['type' => 'text'],
'url' => ['type' => 'text'], 'url' => ['type' => 'text'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
], ],
'primary key' => ['actor_id'], 'primary key' => ['actor_id'],
'foreign keys' => [ 'foreign keys' => [
'activitypub_actor_actor_id_fkey' => ['actor', ['actor_id' => 'id']], 'activitypub_actor_actor_id_fkey' => ['actor', ['actor_id' => 'id']],
], ],

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -117,16 +118,16 @@ class ActivitypubObject extends Entity
public static function schemaDef(): array public static function schemaDef(): array
{ {
return [ return [
'name' => 'activitypub_object', 'name' => 'activitypub_object',
'fields' => [ 'fields' => [
'object_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Object\'s URI'], 'object_uri' => ['type' => 'text', 'not null' => true, 'description' => 'Object\'s URI'],
'object_type' => ['type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'the name of the table this object refers to'], 'object_type' => ['type' => 'varchar', 'length' => 32, 'not null' => true, 'description' => 'the name of the table this object refers to'],
'object_id' => ['type' => 'int', 'not null' => true, 'description' => 'id in the referenced table'], 'object_id' => ['type' => 'int', 'not null' => true, 'description' => 'id in the referenced table'],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
], ],
'primary key' => ['object_uri'], 'primary key' => ['object_uri'],
'indexes' => [ 'indexes' => [
'activity_object_uri_idx' => ['object_uri'], 'activity_object_uri_idx' => ['object_uri'],
], ],
]; ];

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -119,15 +120,15 @@ class ActivitypubRsa extends Entity
public static function schemaDef(): array public static function schemaDef(): array
{ {
return [ return [
'name' => 'activitypub_rsa', 'name' => 'activitypub_rsa',
'fields' => [ 'fields' => [
'actor_id' => ['type' => 'int', 'not null' => true], 'actor_id' => ['type' => 'int', 'not null' => true],
'private_key' => ['type' => 'text'], 'private_key' => ['type' => 'text'],
'public_key' => ['type' => 'text', 'not null' => true], 'public_key' => ['type' => 'text', 'not null' => true],
'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'], 'created' => ['type' => 'datetime', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was created'],
'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'], 'modified' => ['type' => 'timestamp', 'not null' => true, 'default' => 'CURRENT_TIMESTAMP', 'description' => 'date this record was modified'],
], ],
'primary key' => ['actor_id'], 'primary key' => ['actor_id'],
'foreign keys' => [ 'foreign keys' => [
'activitypub_rsa_actor_id_fkey' => ['actor', ['actor_id' => 'id']], 'activitypub_rsa_actor_id_fkey' => ['actor', ['actor_id' => 'id']],
], ],
@ -137,27 +138,28 @@ class ActivitypubRsa extends Entity
/** /**
* Guarantees RSA keys for a given actor. * Guarantees RSA keys for a given actor.
* *
* @param Actor $gsactor
* @param bool $fetch =true Should attempt to fetch keys from a remote profile? * @param bool $fetch =true Should attempt to fetch keys from a remote profile?
* @return ActivitypubRsa The keys (private key is null for remote actors) *
* @throws ServerException It should never occur, but if so, we break everything! * @throws ServerException It should never occur, but if so, we break everything!
*
* @return ActivitypubRsa The keys (private key is null for remote actors)
*/ */
public static function getByActor(Actor $gsactor, bool $fetch = true): self public static function getByActor(Actor $gsactor, bool $fetch = true): self
{ {
$apRSA = self::getByPK(['actor_id' => ($actor_id = $gsactor->getId())]); $apRSA = self::getByPK(['actor_id' => ($actor_id = $gsactor->getId())]);
if (is_null($apRSA)) { if (\is_null($apRSA)) {
// Nonexistent key pair for this profile // Nonexistent key pair for this profile
if ($gsactor->getIsLocal()) { if ($gsactor->getIsLocal()) {
self::generateKeys($private_key, $public_key); self::generateKeys($private_key, $public_key);
$apRSA = self::create([ $apRSA = self::create([
'actor_id' => $actor_id, 'actor_id' => $actor_id,
'private_key' => $private_key, 'private_key' => $private_key,
'public_key' => $public_key, 'public_key' => $public_key,
]); ]);
DB::wrapInTransaction(fn() => DB::persist($apRSA)); DB::wrapInTransaction(fn () => DB::persist($apRSA));
} else { } else {
// ASSERT: This should never happen, but try to recover! // ASSERT: This should never happen, but try to recover!
Log::error("Activitypub_rsa: An impossible thing has happened... Please let the devs know."); Log::error('Activitypub_rsa: An impossible thing has happened... Please let the devs know.');
if ($fetch) { if ($fetch) {
//$res = Activitypub_explorer::get_remote_user_activity($profile->getUri()); //$res = Activitypub_explorer::get_remote_user_activity($profile->getUri());
//Activitypub_rsa::update_public_key($profile, $res['publicKey']['publicKeyPem']); //Activitypub_rsa::update_public_key($profile, $res['publicKey']['publicKeyPem']);
@ -173,16 +175,17 @@ class ActivitypubRsa extends Entity
/** /**
* Generates a pair of RSA keys. * Generates a pair of RSA keys.
* *
* @param string|null $private_key out * @param null|string $private_key out
* @param string|null $public_key out * @param null|string $public_key out
*
* @author PHP Manual Contributed Notes <dirt@awoms.com> * @author PHP Manual Contributed Notes <dirt@awoms.com>
*/ */
private static function generateKeys(?string &$private_key, ?string &$public_key): void private static function generateKeys(?string &$private_key, ?string &$public_key): void
{ {
$config = [ $config = [
'digest_alg' => 'sha512', 'digest_alg' => 'sha512',
'private_key_bits' => 2048, 'private_key_bits' => 2048,
'private_key_type' => OPENSSL_KEYTYPE_RSA, 'private_key_type' => \OPENSSL_KEYTYPE_RSA,
]; ];
// Create the private and public key // Create the private and public key
@ -192,8 +195,8 @@ class ActivitypubRsa extends Entity
openssl_pkey_export($res, $private_key); openssl_pkey_export($res, $private_key);
// Extract the public key from $res to $pubKey // Extract the public key from $res to $pubKey
$pubKey = openssl_pkey_get_details($res); $pubKey = openssl_pkey_get_details($res);
$public_key = $pubKey["key"]; $public_key = $pubKey['key'];
unset($pubKey); unset($pubKey);
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -51,7 +52,6 @@ use XML_XRD;
/** /**
* DiscoveryHints implementation for GNU social * DiscoveryHints implementation for GNU social
* *
*
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
*/ */
@ -59,9 +59,6 @@ class DiscoveryHints
{ {
/** /**
* Search the WebFinger XRD after an ActivityPub URI * Search the WebFinger XRD after an ActivityPub URI
*
* @param XML_XRD $xrd
* @return array
*/ */
public static function fromXRD(XML_XRD $xrd): array public static function fromXRD(XML_XRD $xrd): array
{ {
@ -79,4 +76,4 @@ class DiscoveryHints
return $hints; return $hints;
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2018-2019, 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -35,15 +36,13 @@ use App\Core\HTTPClient;
use App\Core\Log; use App\Core\Log;
use App\Util\Exception\NoSuchActorException; use App\Util\Exception\NoSuchActorException;
use Exception; use Exception;
use const JSON_UNESCAPED_SLASHES;
use Plugin\ActivityPub\ActivityPub; use Plugin\ActivityPub\ActivityPub;
use Plugin\ActivityPub\Entity\ActivitypubActor; use Plugin\ActivityPub\Entity\ActivitypubActor;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use function in_array;
use function is_null;
use const JSON_UNESCAPED_SLASHES;
/** /**
* ActivityPub's own Explorer * ActivityPub's own Explorer
@ -60,10 +59,8 @@ class Explorer
/** /**
* Shortcut function to get a single profile from its URL. * Shortcut function to get a single profile from its URL.
* *
* @param string $url
* @param bool $grab_online whether to try online grabbing, defaults to true * @param bool $grab_online whether to try online grabbing, defaults to true
* *
* @return ActivitypubActor
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws NoSuchActorException * @throws NoSuchActorException
* @throws RedirectionExceptionInterface * @throws RedirectionExceptionInterface
@ -86,8 +83,8 @@ class Explorer
* This function cleans the $this->discovered_actor_profiles array * This function cleans the $this->discovered_actor_profiles array
* so that there is no erroneous data * so that there is no erroneous data
* *
* @param string $url User's url * @param string $url User's url
* @param bool $grab_online whether to try online grabbing, defaults to true * @param bool $grab_online whether to try online grabbing, defaults to true
* *
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws NoSuchActorException * @throws NoSuchActorException
@ -99,7 +96,7 @@ class Explorer
*/ */
public function lookup(string $url, bool $grab_online = true) public function lookup(string $url, bool $grab_online = true)
{ {
if (in_array($url, ActivityPub::PUBLIC_TO)) { if (\in_array($url, ActivityPub::PUBLIC_TO)) {
return []; return [];
} }
@ -114,8 +111,8 @@ class Explorer
* This is a recursive function that will accumulate the results on * This is a recursive function that will accumulate the results on
* $discovered_actor_profiles array * $discovered_actor_profiles array
* *
* @param string $url User's url * @param string $url User's url
* @param bool $grab_online whether to try online grabbing, defaults to true * @param bool $grab_online whether to try online grabbing, defaults to true
* *
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws NoSuchActorException * @throws NoSuchActorException
@ -187,13 +184,13 @@ class Explorer
{ {
Log::debug('ActivityPub Explorer: Trying to grab a remote actor for ' . $url); Log::debug('ActivityPub Explorer: Trying to grab a remote actor for ' . $url);
$response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]); $response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]);
$res = json_decode($response->getContent(), true); $res = json_decode($response->getContent(), true);
if ($response->getStatusCode() == 410) { // If it was deleted if ($response->getStatusCode() == 410) { // If it was deleted
return true; // Nothing to add. return true; // Nothing to add.
} elseif (!HTTPClient::statusCodeIsOkay($response)) { // If it is unavailable } elseif (!HTTPClient::statusCodeIsOkay($response)) { // If it is unavailable
return false; // Try to add at another time. return false; // Try to add at another time.
} }
if (is_null($res)) { if (\is_null($res)) {
Log::debug('ActivityPub Explorer: Invalid response returned from given Actor URL: ' . $res); Log::debug('ActivityPub Explorer: Invalid response returned from given Actor URL: ' . $res);
return true; // Nothing to add. return true; // Nothing to add.
} }
@ -210,7 +207,7 @@ class Explorer
Log::debug( Log::debug(
'ActivityPub Explorer: Invalid potential remote actor while grabbing remotely: ' . $url 'ActivityPub Explorer: Invalid potential remote actor while grabbing remotely: ' . $url
. '. He returned the following: ' . json_encode($res, JSON_UNESCAPED_SLASHES) . '. He returned the following: ' . json_encode($res, JSON_UNESCAPED_SLASHES)
. ' and the following exception: ' . $e->getMessage() . ' and the following exception: ' . $e->getMessage(),
); );
return false; return false;
} }
@ -229,14 +226,12 @@ class Explorer
public static function get_aprofile_by_url(string $v): ActivitypubActor|bool public static function get_aprofile_by_url(string $v): ActivitypubActor|bool
{ {
$aprofile = ActivitypubActor::getByPK(['uri' => $v]); $aprofile = ActivitypubActor::getByPK(['uri' => $v]);
return is_null($aprofile) ? false : ActivitypubActor::getByPK(['uri' => $v]); return \is_null($aprofile) ? false : ActivitypubActor::getByPK(['uri' => $v]);
} }
/** /**
* Allows the Explorer to transverse a collection of persons. * Allows the Explorer to transverse a collection of persons.
* *
* @param string $url
* @return bool
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws NoSuchActorException * @throws NoSuchActorException
* @throws RedirectionExceptionInterface * @throws RedirectionExceptionInterface
@ -246,7 +241,7 @@ class Explorer
private function travel_collection(string $url): bool private function travel_collection(string $url): bool
{ {
$response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]); $response = HTTPClient::get($url, ['headers' => ACTIVITYPUB::HTTP_CLIENT_HEADERS]);
$res = json_decode($response->getContent(), true); $res = json_decode($response->getContent(), true);
if (!isset($res['orderedItems'])) { if (!isset($res['orderedItems'])) {
return false; return false;
@ -258,7 +253,7 @@ class Explorer
} }
} }
// Go through entire collection // Go through entire collection
if (!is_null($res['next'])) { if (!\is_null($res['next'])) {
$this->travel_collection($res['next']); $this->travel_collection($res['next']);
} }
@ -272,12 +267,12 @@ class Explorer
* @param string $url User's url * @param string $url User's url
* *
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws Exception
* @throws RedirectionExceptionInterface * @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface * @throws ServerExceptionInterface
* @throws TransportExceptionInterface * @throws TransportExceptionInterface
* @throws Exception
* *
* @return string|null If it is able to fetch, false if it's gone * @return null|string If it is able to fetch, false if it's gone
* // Exceptions when network issues or unsupported Activity format * // Exceptions when network issues or unsupported Activity format
*/ */
public static function get_remote_user_activity(string $url): string|null public static function get_remote_user_activity(string $url): string|null

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
/** /**
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -17,9 +17,11 @@ declare(strict_types=1);
* *
* @category Network * @category Network
* @package Nautilus * @package Nautilus
*
* @author Aaron Parecki <aaron@parecki.com> * @author Aaron Parecki <aaron@parecki.com>
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
* @link https://github.com/aaronpk/Nautilus/blob/master/app/ActivityPub/HTTPSignature.php *
* @see https://github.com/aaronpk/Nautilus/blob/master/app/ActivityPub/HTTPSignature.php
*/ */
namespace Plugin\ActivityPub\Util; namespace Plugin\ActivityPub\Util;
@ -34,12 +36,14 @@ class HTTPSignature
/** /**
* Sign a message with an Actor * Sign a message with an Actor
* *
* @param Actor $user Actor signing * @param Actor $user Actor signing
* @param string $url Inbox url * @param string $url Inbox url
* @param string|bool $body Data to sign (optional) * @param bool|string $body Data to sign (optional)
* @param array $addlHeaders Additional headers (optional) * @param array $addlHeaders Additional headers (optional)
* @return array Headers to be used in request *
* @throws Exception Attempted to sign something that belongs to an Actor we don't own * @throws Exception Attempted to sign something that belongs to an Actor we don't own
*
* @return array Headers to be used in request
*/ */
public static function sign(Actor $user, string $url, string|bool $body = false, array $addlHeaders = []): array public static function sign(Actor $user, string $url, string|bool $body = false, array $addlHeaders = []): array
{ {
@ -47,15 +51,15 @@ class HTTPSignature
if ($body) { if ($body) {
$digest = self::_digest($body); $digest = self::_digest($body);
} }
$headers = self::_headersToSign($url, $digest); $headers = self::_headersToSign($url, $digest);
$headers = array_merge($headers, $addlHeaders); $headers = array_merge($headers, $addlHeaders);
$stringToSign = self::_headersToSigningString($headers); $stringToSign = self::_headersToSigningString($headers);
$signedHeaders = implode(' ', array_map('strtolower', array_keys($headers))); $signedHeaders = implode(' ', array_map('strtolower', array_keys($headers)));
$actor_private_key = ActivitypubRsa::getByActor($user)->getPrivateKey(); $actor_private_key = ActivitypubRsa::getByActor($user)->getPrivateKey();
// Intentionally unhandled exception, we want this to explode if that happens as it would be a bug // Intentionally unhandled exception, we want this to explode if that happens as it would be a bug
$key = openssl_pkey_get_private($actor_private_key); $key = openssl_pkey_get_private($actor_private_key);
openssl_sign($stringToSign, $signature, $key, OPENSSL_ALGO_SHA256); openssl_sign($stringToSign, $signature, $key, \OPENSSL_ALGO_SHA256);
$signature = base64_encode($signature); $signature = base64_encode($signature);
$signatureHeader = 'keyId="' . $user->getUri() . '#public-key' . '",headers="' . $signedHeaders . '",algorithm="rsa-sha256",signature="' . $signature . '"'; $signatureHeader = 'keyId="' . $user->getUri() . '#public-key' . '",headers="' . $signedHeaders . '",algorithm="rsa-sha256",signature="' . $signature . '"';
unset($headers['(request-target)']); unset($headers['(request-target)']);
$headers['Signature'] = $signatureHeader; $headers['Signature'] = $signatureHeader;
@ -65,20 +69,16 @@ class HTTPSignature
/** /**
* @param array|string $body array or json string $body * @param array|string $body array or json string $body
* @return string
*/ */
private static function _digest(array|string $body): string private static function _digest(array|string $body): string
{ {
if (is_array($body)) { if (\is_array($body)) {
$body = json_encode($body); $body = json_encode($body);
} }
return base64_encode(hash('sha256', $body, true)); return base64_encode(hash('sha256', $body, true));
} }
/** /**
* @param string $url
* @param string|bool $digest
* @return array
* @throws Exception * @throws Exception
*/ */
protected static function _headersToSign(string $url, string|bool $digest = false): array protected static function _headersToSign(string $url, string|bool $digest = false): array
@ -86,12 +86,12 @@ class HTTPSignature
$date = new DateTime('UTC'); $date = new DateTime('UTC');
$headers = [ $headers = [
'(request-target)' => 'post ' . parse_url($url, PHP_URL_PATH), '(request-target)' => 'post ' . parse_url($url, \PHP_URL_PATH),
'Date' => $date->format('D, d M Y H:i:s \G\M\T'), 'Date' => $date->format('D, d M Y H:i:s \G\M\T'),
'Host' => parse_url($url, PHP_URL_HOST), 'Host' => parse_url($url, \PHP_URL_HOST),
'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json, application/json', 'Accept' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json, application/json',
'User-Agent' => 'GNU social ActivityPub Plugin - ' . GNUSOCIAL_ENGINE_URL, 'User-Agent' => 'GNU social ActivityPub Plugin - ' . GNUSOCIAL_ENGINE_URL,
'Content-Type' => 'application/activity+json' 'Content-Type' => 'application/activity+json',
]; ];
if ($digest) { if ($digest) {
@ -101,24 +101,14 @@ class HTTPSignature
return $headers; return $headers;
} }
/**
* @param array $headers
* @return string
*/
private static function _headersToSigningString(array $headers): string private static function _headersToSigningString(array $headers): string
{ {
return implode("\n", array_map(function ($k, $v) { return implode("\n", array_map(fn ($k, $v) => mb_strtolower($k) . ': ' . $v, array_keys($headers), $headers));
return strtolower($k) . ': ' . $v;
}, array_keys($headers), $headers));
} }
/**
* @param string $signature
* @return array
*/
public static function parseSignatureHeader(string $signature): array public static function parseSignatureHeader(string $signature): array
{ {
$parts = explode(',', $signature); $parts = explode(',', $signature);
$signatureData = []; $signatureData = [];
foreach ($parts as $part) { foreach ($parts as $part) {
@ -129,51 +119,43 @@ class HTTPSignature
if (!isset($signatureData['keyId'])) { if (!isset($signatureData['keyId'])) {
return [ return [
'error' => 'No keyId was found in the signature header. Found: ' . implode(', ', array_keys($signatureData)) 'error' => 'No keyId was found in the signature header. Found: ' . implode(', ', array_keys($signatureData)),
]; ];
} }
if (!filter_var($signatureData['keyId'], FILTER_VALIDATE_URL)) { if (!filter_var($signatureData['keyId'], \FILTER_VALIDATE_URL)) {
return [ return [
'error' => 'keyId is not a URL: ' . $signatureData['keyId'] 'error' => 'keyId is not a URL: ' . $signatureData['keyId'],
]; ];
} }
if (!isset($signatureData['headers']) || !isset($signatureData['signature'])) { if (!isset($signatureData['headers']) || !isset($signatureData['signature'])) {
return [ return [
'error' => 'Signature is missing headers or signature parts' 'error' => 'Signature is missing headers or signature parts',
]; ];
} }
return $signatureData; return $signatureData;
} }
/**
* @param string $publicKey
* @param array $signatureData
* @param array $inputHeaders
* @param string $path
* @param string $body
* @return array
*/
public static function verify(string $publicKey, array $signatureData, array $inputHeaders, string $path, string $body): array public static function verify(string $publicKey, array $signatureData, array $inputHeaders, string $path, string $body): array
{ {
// We need this because the used Request headers fields specified by Signature are in lower case. // We need this because the used Request headers fields specified by Signature are in lower case.
$headersContent = array_change_key_case($inputHeaders, CASE_LOWER); $headersContent = array_change_key_case($inputHeaders, \CASE_LOWER);
$digest = 'SHA-256=' . base64_encode(hash('sha256', $body, true)); $digest = 'SHA-256=' . base64_encode(hash('sha256', $body, true));
$headersToSign = []; $headersToSign = [];
foreach (explode(' ', $signatureData['headers']) as $h) { foreach (explode(' ', $signatureData['headers']) as $h) {
if ($h == '(request-target)') { if ($h == '(request-target)') {
$headersToSign[$h] = 'post ' . $path; $headersToSign[$h] = 'post ' . $path;
} elseif ($h == 'digest') { } elseif ($h == 'digest') {
$headersToSign[$h] = $digest; $headersToSign[$h] = $digest;
} elseif (array_key_exists($h, $headersContent)) { } elseif (\array_key_exists($h, $headersContent)) {
$headersToSign[$h] = $headersContent[$h]; $headersToSign[$h] = $headersContent[$h];
} }
} }
$signingString = self::_headersToSigningString($headersToSign); $signingString = self::_headersToSigningString($headersToSign);
$verified = openssl_verify($signingString, base64_decode($signatureData['signature']), $publicKey, OPENSSL_ALGO_SHA256); $verified = openssl_verify($signingString, base64_decode($signatureData['signature']), $publicKey, \OPENSSL_ALGO_SHA256);
return [$verified, $signingString]; return [$verified, $signingString];
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -53,29 +54,27 @@ abstract class Model
/** /**
* Create a Type from an ActivityStreams 2.0 JSON string * Create a Type from an ActivityStreams 2.0 JSON string
* *
* @param string|array $data
* @return Type\AbstractObject
* @throws Exception * @throws Exception
*/ */
public static function jsonToType(string|array $data): Type\AbstractObject public static function jsonToType(string|array $data): Type\AbstractObject
{ {
if (is_string($data)) { if (\is_string($data)) {
$attributes = json_decode($data, true); $attributes = json_decode($data, true);
if (json_last_error() !== JSON_ERROR_NONE if (json_last_error() !== \JSON_ERROR_NONE
|| !is_array($attributes) || !\is_array($attributes)
) { ) {
throw new Exception( throw new Exception(
sprintf( sprintf(
"An error occurred during the JSON decoding.\n '%s'", "An error occurred during the JSON decoding.\n '%s'",
$data $data,
) ),
); );
} }
} else { } else {
$attributes = $data; $attributes = $data;
} }
if (!array_key_exists('type', $attributes)) { if (!\array_key_exists('type', $attributes)) {
throw new InvalidArgumentException('Missing "type" attribute in $data: ' . var_export($data, true)); throw new InvalidArgumentException('Missing "type" attribute in $data: ' . var_export($data, true));
} }
unset($data); unset($data);
@ -83,13 +82,13 @@ abstract class Model
try { try {
$type = TypeResolver::getClass($attributes['type']); $type = TypeResolver::getClass($attributes['type']);
} catch (Exception $e) { } catch (Exception $e) {
$message = json_encode($attributes, JSON_PRETTY_PRINT); $message = json_encode($attributes, \JSON_PRETTY_PRINT);
throw new Exception( throw new Exception(
$e->getMessage() . "\n$message" $e->getMessage() . "\n{$message}",
); );
} }
if (is_string($type)) { if (\is_string($type)) {
$type = new $type(); $type = new $type();
} }
@ -112,22 +111,17 @@ abstract class Model
/** /**
* Create an Entity from an ActivityStreams 2.0 JSON string * Create an Entity from an ActivityStreams 2.0 JSON string
*
* @param string|Type\AbstractObject $json
* @param array $options
* @return Entity
*/ */
abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity; abstract public static function fromJson(string|Type\AbstractObject $json, array $options = []): Entity;
/** /**
* Get a JSON * Get a JSON
* *
* @param mixed $object * @param ?int $options PHP JSON options
* @param ?int $options PHP JSON options *
* @return string
* @throws ClientException * @throws ClientException
*/ */
public static function toJson(mixed $object, int $options = null): string public static function toJson(mixed $object, ?int $options = null): string
{ {
switch ($object::class) { switch ($object::class) {
case 'App\Entity\Activity': case 'App\Entity\Activity':
@ -140,4 +134,4 @@ abstract class Model
return $type->toJson($options); return $type->toJson($options);
} }
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -63,29 +64,26 @@ class Activity extends Model
* Create an Entity from an ActivityStreams 2.0 JSON string * Create an Entity from an ActivityStreams 2.0 JSON string
* This will persist new GSActivities, GSObjects, and APActivity * This will persist new GSActivities, GSObjects, and APActivity
* *
* @param string|AbstractObject $json
* @param array $options
* @return ActivitypubActivity
* @throws NoSuchActorException
* @throws ClientExceptionInterface * @throws ClientExceptionInterface
* @throws NoSuchActorException
* @throws RedirectionExceptionInterface * @throws RedirectionExceptionInterface
* @throws ServerExceptionInterface * @throws ServerExceptionInterface
* @throws TransportExceptionInterface * @throws TransportExceptionInterface
*/ */
public static function fromJson(string|AbstractObject $json, array $options = []): ActivitypubActivity public static function fromJson(string|AbstractObject $json, array $options = []): ActivitypubActivity
{ {
$type_activity = is_string($json) ? self::jsonToType($json) : $json; $type_activity = \is_string($json) ? self::jsonToType($json) : $json;
// Ditch known activities // Ditch known activities
$ap_act = ActivitypubActivity::getByPK(['activity_uri' => $type_activity->get('id')]); $ap_act = ActivitypubActivity::getByPK(['activity_uri' => $type_activity->get('id')]);
if (!is_null($ap_act)) { if (!\is_null($ap_act)) {
return $ap_act; return $ap_act;
} }
// Find Actor and Object // Find Actor and Object
$actor = ActivityPub::getActorByUri($type_activity->get('actor')); $actor = ActivityPub::getActorByUri($type_activity->get('actor'));
$type_object = $type_activity->get('object'); $type_object = $type_activity->get('object');
if (is_string($type_object)) { // Retrieve it if (\is_string($type_object)) { // Retrieve it
$type_object = ActivityPub::getObjectByUri($type_object, try_online: true); $type_object = ActivityPub::getObjectByUri($type_object, try_online: true);
} else { // Encapsulated, if we have it locally, prefer it } else { // Encapsulated, if we have it locally, prefer it
$type_object = ActivityPub::getObjectByUri($type_object->get('id'), try_online: false) ?? $type_object; $type_object = ActivityPub::getObjectByUri($type_object->get('id'), try_online: false) ?? $type_object;
@ -118,20 +116,20 @@ class Activity extends Model
} }
// Store Activity // Store Activity
$act = GSActivity::create([ $act = GSActivity::create([
'actor_id' => $actor->getId(), 'actor_id' => $actor->getId(),
'verb' => 'create', 'verb' => 'create',
'object_type' => 'note', 'object_type' => 'note',
'object_id' => $note->getId(), 'object_id' => $note->getId(),
'created' => new DateTime($type_activity->get('published') ?? 'now'), 'created' => new DateTime($type_activity->get('published') ?? 'now'),
'source' => 'ActivityPub', 'source' => 'ActivityPub',
]); ]);
DB::persist($act); DB::persist($act);
// Store ActivityPub Activity // Store ActivityPub Activity
$ap_act = ActivitypubActivity::create([ $ap_act = ActivitypubActivity::create([
'activity_id' => $act->getId(), 'activity_id' => $act->getId(),
'activity_uri' => $type_activity->get('id'), 'activity_uri' => $type_activity->get('id'),
'created' => new DateTime($type_activity->get('published') ?? 'now'), 'created' => new DateTime($type_activity->get('published') ?? 'now'),
'modified' => new DateTime(), 'modified' => new DateTime(),
]); ]);
DB::persist($ap_act); DB::persist($ap_act);
} }
@ -141,9 +139,6 @@ class Activity extends Model
/** /**
* Get a JSON * Get a JSON
* *
* @param mixed $object
* @param int|null $options
* @return string
* @throws ClientException * @throws ClientException
*/ */
public static function toJson(mixed $object, ?int $options = null): string public static function toJson(mixed $object, ?int $options = null): string
@ -151,24 +146,24 @@ class Activity extends Model
if ($object::class !== 'App\Entity\Activity') { if ($object::class !== 'App\Entity\Activity') {
throw new InvalidArgumentException('First argument type is Activity'); throw new InvalidArgumentException('First argument type is Activity');
} }
$gs_verb_to_activity_stream_two_verb = null; $gs_verb_to_activity_stream_two_verb = null;
if (Event::handle('GSVerbToActivityStreamsTwoActivityType', [($verb = $object->getVerb()), &$gs_verb_to_activity_stream_two_verb]) === Event::next) { if (Event::handle('GSVerbToActivityStreamsTwoActivityType', [($verb = $object->getVerb()), &$gs_verb_to_activity_stream_two_verb]) === Event::next) {
$gs_verb_to_activity_stream_two_verb = match ($verb) { $gs_verb_to_activity_stream_two_verb = match ($verb) {
'create' => 'Create', 'create' => 'Create',
'undo' => 'Undo', 'undo' => 'Undo',
default => throw new ClientException('Invalid verb'), default => throw new ClientException('Invalid verb'),
}; };
} }
$attr = [ $attr = [
'type' => $gs_verb_to_activity_stream_two_verb, 'type' => $gs_verb_to_activity_stream_two_verb,
'@context' => 'https://www.w3.org/ns/activitystreams', '@context' => 'https://www.w3.org/ns/activitystreams',
'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'id' => Router::url('activity_view', ['id' => $object->getId()], Router::ABSOLUTE_URL),
'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339),
'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL), 'actor' => $object->getActor()->getUri(Router::ABSOLUTE_URL),
'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address 'to' => ['https://www.w3.org/ns/activitystreams#Public'], // TODO: implement proper scope address
'cc' => ['https://www.w3.org/ns/activitystreams#Public'], 'cc' => ['https://www.w3.org/ns/activitystreams#Public'],
]; ];
$attr['object'] = ($attr['type'] === 'Create') ? self::jsonToType(Model::toJson($object->getObject())) : ActivityPub::getUriByObject($object->getObject()); $attr['object'] = ($attr['type'] === 'Create') ? self::jsonToType(Model::toJson($object->getObject())) : ActivityPub::getUriByObject($object->getObject());

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -60,29 +61,25 @@ use Plugin\ActivityPub\Util\Model;
*/ */
class Actor extends Model class Actor extends Model
{ {
/** /**
* Create an Entity from an ActivityStreams 2.0 JSON string * Create an Entity from an ActivityStreams 2.0 JSON string
* This will persist a new GSActor, ActivityPubRSA, and ActivityPubActor * This will persist a new GSActor, ActivityPubRSA, and ActivityPubActor
* *
* @param string|AbstractObject $json
* @param array $options
* @return ActivitypubActor
* @throws Exception * @throws Exception
*/ */
public static function fromJson(string|AbstractObject $json, array $options = []): ActivitypubActor public static function fromJson(string|AbstractObject $json, array $options = []): ActivitypubActor
{ {
$person = is_string($json) ? self::jsonToType($json) : $json; $person = \is_string($json) ? self::jsonToType($json) : $json;
// Actor // Actor
$actor_map = [ $actor_map = [
'nickname' => $person->get('preferredUsername'), 'nickname' => $person->get('preferredUsername'),
'fullname' => !empty($person->get('name')) ? $person->get('name') : null, 'fullname' => !empty($person->get('name')) ? $person->get('name') : null,
'created' => new DateTime($person->get('published') ?? 'now'), 'created' => new DateTime($person->get('published') ?? 'now'),
'bio' => $person->get('summary'), 'bio' => $person->get('summary'),
'is_local' => false, 'is_local' => false,
'type' => GSActor::PERSON, 'type' => GSActor::PERSON,
'roles' => UserRoles::USER, 'roles' => UserRoles::USER,
'modified' => new DateTime(), 'modified' => new DateTime(),
]; ];
@ -99,11 +96,11 @@ class Actor extends Model
// ActivityPub Actor // ActivityPub Actor
$ap_actor = ActivitypubActor::create([ $ap_actor = ActivitypubActor::create([
'inbox_uri' => $person->get('inbox'), 'inbox_uri' => $person->get('inbox'),
'inbox_shared_uri' => ($person->has('endpoints') && isset($person->get('endpoints')['sharedInbox'])) ? $person->get('endpoints')['sharedInbox'] : null, 'inbox_shared_uri' => ($person->has('endpoints') && isset($person->get('endpoints')['sharedInbox'])) ? $person->get('endpoints')['sharedInbox'] : null,
'uri' => $person->get('id'), 'uri' => $person->get('id'),
'actor_id' => $actor->getId(), 'actor_id' => $actor->getId(),
'url' => $person->get('url') ?? null, 'url' => $person->get('url') ?? null,
], $options['objects']['ActivitypubActor'] ?? null); ], $options['objects']['ActivitypubActor'] ?? null);
if (!isset($options['objects']['ActivitypubActor'])) { if (!isset($options['objects']['ActivitypubActor'])) {
@ -112,7 +109,7 @@ class Actor extends Model
// Public Key // Public Key
$apRSA = ActivitypubRsa::create([ $apRSA = ActivitypubRsa::create([
'actor_id' => $actor->getID(), 'actor_id' => $actor->getID(),
'public_key' => ($person->has('publicKey') && isset($person->get('publicKey')['publicKeyPem'])) ? $person->get('publicKey')['publicKeyPem'] : null, 'public_key' => ($person->has('publicKey') && isset($person->get('publicKey')['publicKeyPem'])) ? $person->get('publicKey')['publicKeyPem'] : null,
], $options['objects']['ActivitypubRsa'] ?? null); ], $options['objects']['ActivitypubRsa'] ?? null);
@ -125,8 +122,8 @@ class Actor extends Model
try { try {
// Retrieve media // Retrieve media
$get_response = HTTPClient::get($person->get('icon')->get('url')); $get_response = HTTPClient::get($person->get('icon')->get('url'));
$media = $get_response->getContent(); $media = $get_response->getContent();
$mimetype = $get_response->getHeaders()['content-type'][0] ?? null; $mimetype = $get_response->getHeaders()['content-type'][0] ?? null;
unset($get_response); unset($get_response);
// Only handle if it is an image // Only handle if it is an image
@ -168,9 +165,8 @@ class Actor extends Model
/** /**
* Get a JSON * Get a JSON
* *
* @param mixed $object * @param null|int $options PHP JSON options
* @param int|null $options PHP JSON options *
* @return string
* @throws ServerException * @throws ServerException
*/ */
public static function toJson(mixed $object, ?int $options = null): string public static function toJson(mixed $object, ?int $options = null): string
@ -178,41 +174,41 @@ class Actor extends Model
if ($object::class !== 'App\Entity\Actor') { if ($object::class !== 'App\Entity\Actor') {
throw new InvalidArgumentException('First argument type is Actor'); throw new InvalidArgumentException('First argument type is Actor');
} }
$rsa = ActivitypubRsa::getByActor($object); $rsa = ActivitypubRsa::getByActor($object);
$public_key = $rsa->getPublicKey(); $public_key = $rsa->getPublicKey();
$uri = null; $uri = null;
$attr = [ $attr = [
'@context' => 'https://www.w3.org/ns/activitystreams', '@context' => 'https://www.w3.org/ns/activitystreams',
'type' => 'Person', 'type' => 'Person',
'id' => $object->getUri(Router::ABSOLUTE_URL), 'id' => $object->getUri(Router::ABSOLUTE_URL),
'inbox' => Router::url('activitypub_actor_inbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL), 'inbox' => Router::url('activitypub_actor_inbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL),
'outbox' => Router::url('activitypub_actor_outbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL), 'outbox' => Router::url('activitypub_actor_outbox', ['gsactor_id' => $object->getId()], Router::ABSOLUTE_URL),
'following' => Router::url('actor_subscriptions_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'following' => Router::url('actor_subscriptions_id', ['id' => $object->getId()], Router::ABSOLUTE_URL),
'followers' => Router::url('actor_subscribers_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'followers' => Router::url('actor_subscribers_id', ['id' => $object->getId()], Router::ABSOLUTE_URL),
'liked' => Router::url('favourites_view_by_actor_id', ['id' => $object->getId()], Router::ABSOLUTE_URL), 'liked' => Router::url('favourites_view_by_actor_id', ['id' => $object->getId()], Router::ABSOLUTE_URL),
//'streams' => //'streams' =>
'preferredUsername' => $object->getNickname(), 'preferredUsername' => $object->getNickname(),
'publicKey' => [ 'publicKey' => [
'id' => $uri . "#public-key", 'id' => $uri . '#public-key',
'owner' => $uri, 'owner' => $uri,
'publicKeyPem' => $public_key 'publicKeyPem' => $public_key,
], ],
'name' => $object->getFullname(), 'name' => $object->getFullname(),
'location' => $object->getLocation(), 'location' => $object->getLocation(),
'published' => $object->getCreated()->format(DateTimeInterface::RFC3339), 'published' => $object->getCreated()->format(DateTimeInterface::RFC3339),
'summary' => $object->getBio(), 'summary' => $object->getBio(),
//'tag' => $object->getSelfTags(), //'tag' => $object->getSelfTags(),
'updated' => $object->getModified()->format(DateTimeInterface::RFC3339), 'updated' => $object->getModified()->format(DateTimeInterface::RFC3339),
'url' => $object->getUrl(Router::ABSOLUTE_URL), 'url' => $object->getUrl(Router::ABSOLUTE_URL),
]; ];
// Avatar // Avatar
try { try {
$avatar = Avatar::getAvatar($object->getId()); $avatar = Avatar::getAvatar($object->getId());
$attr['icon'] = $attr['image'] = [ $attr['icon'] = $attr['image'] = [
'type' => 'Image', 'type' => 'Image',
'mediaType' => $avatar->getAttachment()->getMimetype(), 'mediaType' => $avatar->getAttachment()->getMimetype(),
'url' => $avatar->getUrl(type: Router::ABSOLUTE_URL), 'url' => $avatar->getUrl(type: Router::ABSOLUTE_URL),
]; ];
} catch (Exception) { } catch (Exception) {
// No icon for this actor // No icon for this actor
@ -222,4 +218,4 @@ class Actor extends Model
Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]); Event::handle('ActivityPubAddActivityStreamsTwoData', [$type->get('type'), &$type]);
return $type->toJson($options); return $type->toJson($options);
} }
} }

View File

@ -39,11 +39,10 @@ use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use App\Core\HTTPClient; use App\Core\HTTPClient;
use App\Core\VisibilityScope;
use Component\Language\Entity\Language;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Log; use App\Core\Log;
use App\Core\Router\Router; use App\Core\Router\Router;
use App\Core\VisibilityScope;
use App\Entity\Note as GSNote; use App\Entity\Note as GSNote;
use App\Entity\NoteTag; use App\Entity\NoteTag;
use App\Util\Common; use App\Util\Common;
@ -56,11 +55,13 @@ use App\Util\TemporaryFile;
use Component\Attachment\Entity\ActorToAttachment; use Component\Attachment\Entity\ActorToAttachment;
use Component\Attachment\Entity\AttachmentToNote; use Component\Attachment\Entity\AttachmentToNote;
use Component\Conversation\Conversation; use Component\Conversation\Conversation;
use Component\Language\Entity\Language;
use Component\Tag\Tag; use Component\Tag\Tag;
use DateTime; use DateTime;
use DateTimeInterface; use DateTimeInterface;
use Exception; use Exception;
use InvalidArgumentException; use InvalidArgumentException;
use const PHP_URL_HOST;
use Plugin\ActivityPub\ActivityPub; use Plugin\ActivityPub\ActivityPub;
use Plugin\ActivityPub\Entity\ActivitypubObject; use Plugin\ActivityPub\Entity\ActivitypubObject;
use Plugin\ActivityPub\Util\Model; use Plugin\ActivityPub\Util\Model;
@ -68,10 +69,6 @@ use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface; use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface; use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface; use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use function array_key_exists;
use function is_null;
use function is_string;
use const PHP_URL_HOST;
/** /**
* This class handles translation between JSON and GSNotes * This class handles translation between JSON and GSNotes
@ -98,7 +95,7 @@ class Note extends Model
{ {
$handleInReplyTo = function (AbstractObject|string $type_note): ?int { $handleInReplyTo = function (AbstractObject|string $type_note): ?int {
try { try {
$parent_note = is_null($type_note->get('inReplyTo')) ? null : ActivityPub::getObjectByUri($type_note->get('inReplyTo'), try_online: true); $parent_note = \is_null($type_note->get('inReplyTo')) ? null : ActivityPub::getObjectByUri($type_note->get('inReplyTo'), try_online: true);
if ($parent_note instanceof GSNote) { if ($parent_note instanceof GSNote) {
return $parent_note->getId(); return $parent_note->getId();
} elseif ($parent_note instanceof Type\AbstractObject && $parent_note->get('type') === 'Note') { } elseif ($parent_note instanceof Type\AbstractObject && $parent_note->get('type') === 'Note') {
@ -116,13 +113,13 @@ class Note extends Model
}; };
$source = $options['source'] ?? 'ActivityPub'; $source = $options['source'] ?? 'ActivityPub';
$type_note = is_string($json) ? self::jsonToType($json) : $json; $type_note = \is_string($json) ? self::jsonToType($json) : $json;
$actor = null; $actor = null;
$actor_id = null; $actor_id = null;
if ($json instanceof AbstractObject if ($json instanceof AbstractObject
&& array_key_exists('test_authority', $options) && \array_key_exists('test_authority', $options)
&& $options['test_authority'] && $options['test_authority']
&& array_key_exists('actor_uri', $options) && \array_key_exists('actor_uri', $options)
) { ) {
$actor_uri = $options['actor_uri']; $actor_uri = $options['actor_uri'];
if ($actor_uri !== $type_note->get('attributedTo')) { if ($actor_uri !== $type_note->get('attributedTo')) {
@ -135,7 +132,7 @@ class Note extends Model
} }
} }
if (is_null($actor_id)) { if (\is_null($actor_id)) {
$actor = ActivityPub::getActorByUri($type_note->get('attributedTo')); $actor = ActivityPub::getActorByUri($type_note->get('attributedTo'));
$actor_id = $actor->getId(); $actor_id = $actor->getId();
} }
@ -164,14 +161,14 @@ class Note extends Model
]); ]);
} }
if (!is_null($map['language_id'])) { if (!\is_null($map['language_id'])) {
$map['language_id'] = Language::getByLocale($map['language_id'])->getId(); $map['language_id'] = Language::getByLocale($map['language_id'])->getId();
} else { } else {
$map['language_id'] = null; $map['language_id'] = null;
} }
// Scope // Scope
if (in_array('https://www.w3.org/ns/activitystreams#Public', $type_note->get('to'))) { if (\in_array('https://www.w3.org/ns/activitystreams#Public', $type_note->get('to'))) {
// Public: Visible for all, shown in public feeds // Public: Visible for all, shown in public feeds
$map['scope'] = VisibilityScope::PUBLIC; $map['scope'] = VisibilityScope::PUBLIC;
} elseif (\in_array('https://www.w3.org/ns/activitystreams#Public', $type_note->get('cc'))) { } elseif (\in_array('https://www.w3.org/ns/activitystreams#Public', $type_note->get('cc'))) {
@ -258,7 +255,7 @@ class Note extends Model
case 'Hashtag': case 'Hashtag':
$match = ltrim($ap_tag->get('name'), '#'); $match = ltrim($ap_tag->get('name'), '#');
$tag = Tag::ensureValid($match); $tag = Tag::ensureValid($match);
$canonical_tag = $ap_tag->get('canonical') ?? Tag::canonicalTag($tag, is_null($lang_id = $obj->getLanguageId()) ? null : Language::getById($lang_id)->getLocale()); $canonical_tag = $ap_tag->get('canonical') ?? Tag::canonicalTag($tag, \is_null($lang_id = $obj->getLanguageId()) ? null : Language::getById($lang_id)->getLocale());
DB::persist(NoteTag::create([ DB::persist(NoteTag::create([
'tag' => $tag, 'tag' => $tag,
'canonical' => $canonical_tag, 'canonical' => $canonical_tag,
@ -323,7 +320,7 @@ class Note extends Model
'content' => $object->getRendered(), 'content' => $object->getRendered(),
'attachment' => [], 'attachment' => [],
'tag' => [], 'tag' => [],
'inReplyTo' => is_null($object->getReplyTo()) ? null : ActivityPub::getUriByObject(GSNote::getById($object->getReplyTo())), 'inReplyTo' => \is_null($object->getReplyTo()) ? null : ActivityPub::getUriByObject(GSNote::getById($object->getReplyTo())),
'inConversation' => $object->getConversationUri(), 'inConversation' => $object->getConversationUri(),
'directMessage' => $object->getScope() === VisibilityScope::MESSAGE, 'directMessage' => $object->getScope() === VisibilityScope::MESSAGE,
]; ];

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -43,8 +44,7 @@ abstract class ModelResponse
* Provides a response in application/ld+json for ActivityStreams 2.0 Types * Provides a response in application/ld+json for ActivityStreams 2.0 Types
* *
* @param mixed $object (Entity) * @param mixed $object (Entity)
* @param int $status The response status code * @param int $status The response status code
* @return TypeResponse
*/ */
public static function handle(mixed $object, int $status = 200): TypeResponse public static function handle(mixed $object, int $status = 200): TypeResponse
{ {

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -47,9 +48,8 @@ abstract class ActivityResponse
/** /**
* Provides a response in application/ld+json to GSActivity * Provides a response in application/ld+json to GSActivity
* *
* @param GSActivity $activity
* @param int $status The response status code * @param int $status The response status code
* @return TypeResponse *
* @throws ClientException * @throws ClientException
*/ */
public static function handle(GSActivity $activity, int $status = 200): TypeResponse public static function handle(GSActivity $activity, int $status = 200): TypeResponse

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -47,9 +48,8 @@ abstract class ActorResponse
/** /**
* Provides a response in application/ld+json to GSActors * Provides a response in application/ld+json to GSActors
* *
* @param GSActor $gsactor
* @param int $status The response status code * @param int $status The response status code
* @return TypeResponse *
* @throws ClientException * @throws ClientException
*/ */
public static function handle(GSActor $gsactor, int $status = 200): TypeResponse public static function handle(GSActor $gsactor, int $status = 200): TypeResponse

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -46,9 +47,7 @@ abstract class NoteResponse
/** /**
* Provides a response in application/ld+json to GSNotes * Provides a response in application/ld+json to GSNotes
* *
* @param GSNote $note
* @param int $status The response status code * @param int $status The response status code
* @return TypeResponse
*/ */
public static function handle(GSNote $note, int $status = 200): TypeResponse public static function handle(GSNote $note, int $status = 200): TypeResponse
{ {

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -45,13 +46,13 @@ class TypeResponse extends JsonResponse
/** /**
* Provides a response in application/ld+json for ActivityStreams 2.0 Types * Provides a response in application/ld+json for ActivityStreams 2.0 Types
* *
* @param string|AbstractObject|null $json * @param null|AbstractObject|string $json
* @param int $status The response status code * @param int $status The response status code
*/ */
public function __construct(string|AbstractObject|null $json = null, int $status = 202) public function __construct(string|AbstractObject|null $json = null, int $status = 202)
{ {
parent::__construct( parent::__construct(
data: is_object($json) ? $json->toJson() : $json, data: \is_object($json) ? $json->toJson() : $json,
status: $status, status: $status,
headers: ['content-type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'], headers: ['content-type' => 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'],
json: true, json: true,

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -49,8 +50,8 @@ class contentLangModelValidator extends ModelValidator
* Validate manuallyApprovesFollowers value * Validate manuallyApprovesFollowers value
* *
* @param string $value * @param string $value
* @param mixed $container A Note * @param mixed $container A Note
* @return bool *
* @throws Exception * @throws Exception
*/ */
public function validate($value, $container): bool public function validate($value, $container): bool

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
@ -24,6 +24,7 @@ declare(strict_types=1);
* *
* @package GNUsocial * @package GNUsocial
* @category ActivityPub * @category ActivityPub
*
* @author Diogo Peralta Cordeiro <@diogo.site> * @author Diogo Peralta Cordeiro <@diogo.site>
* @copyright 2021 Free Software Foundation, Inc http://www.fsf.org * @copyright 2021 Free Software Foundation, Inc http://www.fsf.org
* @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later * @license https://www.gnu.org/licenses/agpl.html GNU AGPL v3 or later
@ -49,8 +50,8 @@ class manuallyApprovesFollowersModelValidator extends ModelValidator
* Validate manuallyApprovesFollowers value * Validate manuallyApprovesFollowers value
* *
* @param string $value * @param string $value
* @param mixed $container A Person * @param mixed $container A Person
* @return bool *
* @throws Exception * @throws Exception
*/ */
public function validate($value, $container): bool public function validate($value, $container): bool

View File

@ -23,16 +23,16 @@ declare(strict_types = 1);
namespace Plugin\AttachmentCollections\Controller; namespace Plugin\AttachmentCollections\Controller;
use App\Core\Form;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Util\Common; use App\Core\Form;
use App\Core\Router\Router;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Core\Router\Router;
use App\Util\Common;
use Component\Feed\Util\FeedController; use Component\Feed\Util\FeedController;
use Symfony\Component\HttpFoundation\Request;
use Plugin\AttachmentCollections\Entity\Collection; use Plugin\AttachmentCollections\Entity\Collection;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType; use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
class Controller extends FeedController class Controller extends FeedController
{ {
@ -47,16 +47,18 @@ class Controller extends FeedController
} }
/** /**
* Generate Collections page * Generate Collections page
*
* @param int $id actor id * @param int $id actor id
* @param ?string $nickname actor nickname * @param ?string $nickname actor nickname
* @return array twig template options *
* @return array twig template options
*/ */
public function collectionsView(Request $request, int $id, ?string $nickname): array public function collectionsView(Request $request, int $id, ?string $nickname): array
{ {
$collections = DB::dql( $collections = DB::dql(
'select collection from Plugin\AttachmentCollections\Entity\Collection collection ' 'select collection from Plugin\AttachmentCollections\Entity\Collection collection '
. 'where collection.actor_id = :id', . 'where collection.actor_id = :id',
['id' => $id] ['id' => $id],
); );
// create collection form // create collection form
$create = null; $create = null;
@ -64,9 +66,9 @@ class Controller extends FeedController
$create = Form::create([ $create = Form::create([
['name', TextType::class, [ ['name', TextType::class, [
'label' => _m('Create collection'), 'label' => _m('Create collection'),
'attr' => [ 'attr' => [
'placeholder' => _m('Name'), 'placeholder' => _m('Name'),
'required' => 'required' 'required' => 'required',
], ],
'data' => '', 'data' => '',
]], ]],
@ -80,7 +82,7 @@ class Controller extends FeedController
$create->handleRequest($request); $create->handleRequest($request);
if ($create->isSubmitted() && $create->isValid()) { if ($create->isSubmitted() && $create->isValid()) {
DB::persist(Collection::create([ DB::persist(Collection::create([
'name' => $create->getData()['name'], 'name' => $create->getData()['name'],
'actor_id' => $id, 'actor_id' => $id,
])); ]));
DB::flush(); DB::flush();
@ -94,15 +96,14 @@ class Controller extends FeedController
// Instead, I'm using an anonymous class to encapsulate // Instead, I'm using an anonymous class to encapsulate
// the functions and passing how the class to the template. // the functions and passing how the class to the template.
// It's suggested at https://stackoverflow.com/a/50364502. // It's suggested at https://stackoverflow.com/a/50364502.
$fn = new class ($id, $nickname, $request) $fn = new class($id, $nickname, $request) {
{
private $id; private $id;
private $nick; private $nick;
private $request; private $request;
public function __construct($id, $nickname, $request) public function __construct($id, $nickname, $request)
{ {
$this->id = $id; $this->id = $id;
$this->nick = $nickname; $this->nick = $nickname;
$this->request = $request; $this->request = $request;
} }
// there's already a injected function called path, // there's already a injected function called path,
@ -114,12 +115,12 @@ class Controller extends FeedController
if (\is_null($this->nick)) { if (\is_null($this->nick)) {
return Router::url( return Router::url(
'collection_notes_view_by_actor_id', 'collection_notes_view_by_actor_id',
['id' => $this->id, 'cid' => $cid] ['id' => $this->id, 'cid' => $cid],
); );
} }
return Router::url( return Router::url(
'collection_notes_view_by_nickname', 'collection_notes_view_by_nickname',
['nickname' => $this->nick, 'cid' => $cid] ['nickname' => $this->nick, 'cid' => $cid],
); );
} }
// There are many collections in this page and we need two // There are many collections in this page and we need two
@ -133,11 +134,11 @@ class Controller extends FeedController
['name', TextType::class, [ ['name', TextType::class, [
'attr' => [ 'attr' => [
'placeholder' => 'New name', 'placeholder' => 'New name',
'required' => 'required' 'required' => 'required',
], ],
'data' => '', 'data' => '',
]], ]],
['update_'.$collection->getId(), SubmitType::class, [ ['update_' . $collection->getId(), SubmitType::class, [
'label' => _m('Save'), 'label' => _m('Save'),
'attr' => [ 'attr' => [
'title' => _m('Save'), 'title' => _m('Save'),
@ -156,7 +157,7 @@ class Controller extends FeedController
public function rmForm($collection) public function rmForm($collection)
{ {
$rm = Form::create([ $rm = Form::create([
['remove_'.$collection->getId(), SubmitType::class, [ ['remove_' . $collection->getId(), SubmitType::class, [
'label' => _m('Delete collection'), 'label' => _m('Delete collection'),
'attr' => [ 'attr' => [
'title' => _m('Delete collection'), 'title' => _m('Delete collection'),
@ -190,12 +191,12 @@ class Controller extends FeedController
public function collectionNotesByActorId(Request $request, int $id, int $cid): array public function collectionNotesByActorId(Request $request, int $id, int $cid): array
{ {
$collection = DB::findOneBy('attachment_collection', ['id' => $cid]); $collection = DB::findOneBy('attachment_collection', ['id' => $cid]);
$attchs = DB::dql( $attchs = DB::dql(
'select attch from attachment_album_entry entry ' 'select attch from attachment_album_entry entry '
. 'left join Component\Attachment\Entity\Attachment attch ' . 'left join Component\Attachment\Entity\Attachment attch '
. 'with entry.attachment_id = attch.id ' . 'with entry.attachment_id = attch.id '
. 'where entry.collection_id = :cid', . 'where entry.collection_id = :cid',
['cid' => $cid] ['cid' => $cid],
); );
return [ return [
'_template' => 'AttachmentCollections/collection.html.twig', '_template' => 'AttachmentCollections/collection.html.twig',

View File

@ -1,7 +1,11 @@
<?php <?php
declare(strict_types = 1);
namespace Plugin\AttachmentCollections\Entity; namespace Plugin\AttachmentCollections\Entity;
use App\Core\Entity; use App\Core\Entity;
class Collection extends Entity class Collection extends Entity
{ {
// These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields` // These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields`
@ -44,22 +48,19 @@ class Collection extends Entity
return $this->actor_id; return $this->actor_id;
} }
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function schemaDef() public static function schemaDef()
{ {
return [ return [
'name' => 'attachment_collection', 'name' => 'attachment_collection',
'fields' => [ 'fields' => [
'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'], 'id' => ['type' => 'serial', 'not null' => true, 'description' => 'unique identifier'],
'name' => ['type' => 'varchar', 'length' => 255, 'description' => 'collection\'s name'], 'name' => ['type' => 'varchar', 'length' => 255, 'description' => 'collection\'s name'],
'actor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to many', 'not null' => true, 'description' => 'foreign key to actor table'], 'actor_id' => ['type' => 'int', 'foreign key' => true, 'target' => 'Actor.id', 'multiplicity' => 'one to many', 'not null' => true, 'description' => 'foreign key to actor table'],
], ],
'primary key' => ['id'], 'primary key' => ['id'],
]; ];
} }
} }

View File

@ -1,7 +1,11 @@
<?php <?php
declare(strict_types = 1);
namespace Plugin\AttachmentCollections\Entity; namespace Plugin\AttachmentCollections\Entity;
use App\Core\Entity; use App\Core\Entity;
class CollectionEntry extends Entity class CollectionEntry extends Entity
{ {
// These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields` // These tags are meant to be literally included and will be populated with the appropriate fields, setters and getters by `bin/generate_entity_fields`
@ -44,11 +48,9 @@ class CollectionEntry extends Entity
return $this->collection_id; return $this->collection_id;
} }
// @codeCoverageIgnoreEnd // @codeCoverageIgnoreEnd
// }}} Autocode // }}} Autocode
public static function schemaDef() public static function schemaDef()
{ {
return [ return [
@ -62,4 +64,3 @@ class CollectionEntry extends Entity
]; ];
} }
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social
// //
@ -34,12 +34,12 @@ namespace Plugin\AudioEncoder;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use function App\Core\I18n\_m;
use App\Core\Modules\Plugin; use App\Core\Modules\Plugin;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use App\Util\Formatting; use App\Util\Formatting;
use FFMpeg\FFProbe as ffprobe; use FFMpeg\FFProbe as ffprobe;
use SplFileInfo; use SplFileInfo;
use function App\Core\I18n\_m;
class AudioEncoder extends Plugin class AudioEncoder extends Plugin
{ {
@ -66,7 +66,7 @@ class AudioEncoder extends Plugin
* Adds duration metadata to audios * Adds duration metadata to audios
* *
* @param null|string $mimetype in/out * @param null|string $mimetype in/out
* @param null|int $width out audio duration * @param null|int $width out audio duration
* *
* @return bool true if metadata filled * @return bool true if metadata filled
*/ */
@ -75,14 +75,14 @@ class AudioEncoder extends Plugin
// Create FFProbe instance // Create FFProbe instance
// Need to explicitly tell the drivers' location, or it won't find them // Need to explicitly tell the drivers' location, or it won't find them
$ffprobe = ffprobe::create([ $ffprobe = ffprobe::create([
'ffmpeg.binaries' => exec('which ffmpeg'), 'ffmpeg.binaries' => exec('which ffmpeg'),
'ffprobe.binaries' => exec('which ffprobe'), 'ffprobe.binaries' => exec('which ffprobe'),
]); ]);
$metadata = $ffprobe->streams($file->getRealPath()) // extracts streams informations $metadata = $ffprobe->streams($file->getRealPath()) // extracts streams informations
->audios() // filters audios streams ->audios() // filters audios streams
->first(); // returns the first audio stream ->first(); // returns the first audio stream
$width = (int)ceil((float)$metadata->get('duration')); $width = (int) ceil((float) $metadata->get('duration'));
return true; return true;
} }
@ -100,7 +100,7 @@ class AudioEncoder extends Plugin
'audioEncoder/audioEncoderView.html.twig', 'audioEncoder/audioEncoderView.html.twig',
[ [
'attachment' => $vars['attachment'], 'attachment' => $vars['attachment'],
'note' => $vars['note'], 'note' => $vars['note'],
], ],
); );
return Event::stop; return Event::stop;
@ -112,9 +112,9 @@ class AudioEncoder extends Plugin
public function onPluginVersion(array &$versions): bool public function onPluginVersion(array &$versions): bool
{ {
$versions[] = [ $versions[] = [
'name' => 'AudioEncoder', 'name' => 'AudioEncoder',
'version' => self::version(), 'version' => self::version(),
'author' => 'Diogo Peralta Cordeiro', 'author' => 'Diogo Peralta Cordeiro',
'rawdescription' => _m('Use PHP-FFMpeg for some more audio support.'), 'rawdescription' => _m('Use PHP-FFMpeg for some more audio support.'),
]; ];
return Event::next; return Event::next;

View File

@ -25,8 +25,8 @@ namespace Plugin\Cover\Entity;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Entity; use App\Core\Entity;
use Component\Attachment\Entity\Attachment;
use App\Util\Common; use App\Util\Common;
use Component\Attachment\Entity\Attachment;
use DateTimeInterface; use DateTimeInterface;
/** /**

View File

@ -187,8 +187,8 @@ class AttachmentEmbed extends Entity
$attr['has_attachment'] = false; $attr['has_attachment'] = false;
} elseif (!\is_null($thumbnail)) { } elseif (!\is_null($thumbnail)) {
$attr['has_attachment'] = true; $attr['has_attachment'] = true;
$attr['width'] = $thumbnail->getWidth(); $attr['width'] = $thumbnail->getWidth();
$attr['height'] = $thumbnail->getHeight(); $attr['height'] = $thumbnail->getHeight();
} }
return $attr; return $attr;
} }

View File

@ -55,7 +55,8 @@ class ImageEncoder extends Plugin
return '3.0.0'; return '3.0.0';
} }
public static function shouldHandle (string $mimetype): bool { public static function shouldHandle(string $mimetype): bool
{
return GSFile::mimetypeMajor($mimetype) === 'image'; return GSFile::mimetypeMajor($mimetype) === 'image';
} }

View File

@ -1,6 +1,6 @@
<?php <?php
declare(strict_types=1); declare(strict_types = 1);
// {{{ License // {{{ License
@ -26,6 +26,7 @@ namespace Plugin\Oomox\Controller;
use App\Core\Cache; use App\Core\Cache;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Form; use App\Core\Form;
use function App\Core\I18n\_m;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\ClientException; use App\Util\Exception\ClientException;
use App\Util\Exception\NoLoggedInUser; use App\Util\Exception\NoLoggedInUser;
@ -41,8 +42,6 @@ use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\SubmitButton; use Symfony\Component\Form\SubmitButton;
use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use function App\Core\I18n\_m;
use function is_null;
/** /**
* Oomox controller * Oomox controller
@ -64,67 +63,67 @@ class Oomox
*/ */
public function getOomoxForm(?EntityOomox $current_oomox_settings, bool $is_light): FormInterface public function getOomoxForm(?EntityOomox $current_oomox_settings, bool $is_light): FormInterface
{ {
$theme = $is_light ? 'light' : 'dark'; $theme = $is_light ? 'light' : 'dark';
$foreground = 'colour_foreground_' . $theme; $foreground = 'colour_foreground_' . $theme;
$background_hard = 'colour_background_hard_' . $theme; $background_hard = 'colour_background_hard_' . $theme;
$background_card = 'colour_background_card_' . $theme; $background_card = 'colour_background_card_' . $theme;
$border = 'colour_border_' . $theme; $border = 'colour_border_' . $theme;
$accent = 'colour_accent_' . $theme; $accent = 'colour_accent_' . $theme;
$reset = 'colour_reset_' . $theme; $reset = 'colour_reset_' . $theme;
$save = 'save_oomox_colours_' . $theme; $save = 'save_oomox_colours_' . $theme;
if (isset($current_oomox_settings)) { if (isset($current_oomox_settings)) {
if ($is_light) { if ($is_light) {
$current_foreground = $current_oomox_settings->getColourForegroundLight() ?: '#09090d'; $current_foreground = $current_oomox_settings->getColourForegroundLight() ?: '#09090d';
$current_background_hard = $current_oomox_settings->getColourBackgroundHardLight() ?: '#ebebeb'; $current_background_hard = $current_oomox_settings->getColourBackgroundHardLight() ?: '#ebebeb';
$current_background_card = $current_oomox_settings->getColourBackgroundCardLight() ?: '#f0f0f0'; $current_background_card = $current_oomox_settings->getColourBackgroundCardLight() ?: '#f0f0f0';
$current_border = $current_oomox_settings->getColourBorderLight() ?: '#d5d5d5'; $current_border = $current_oomox_settings->getColourBorderLight() ?: '#d5d5d5';
$current_accent = $current_oomox_settings->getColourAccentLight() ?: '#a22430'; $current_accent = $current_oomox_settings->getColourAccentLight() ?: '#a22430';
} else { } else {
$current_foreground = $current_oomox_settings->getColourForegroundDark() ?: '#f0f6f6'; $current_foreground = $current_oomox_settings->getColourForegroundDark() ?: '#f0f6f6';
$current_background_hard = $current_oomox_settings->getColourBackgroundHardDark() ?: '#141216'; $current_background_hard = $current_oomox_settings->getColourBackgroundHardDark() ?: '#141216';
$current_background_card = $current_oomox_settings->getColourBackgroundCardDark() ?: '#131217'; $current_background_card = $current_oomox_settings->getColourBackgroundCardDark() ?: '#131217';
$current_border = $current_oomox_settings->getColourBorderDark() ?: '#201f25'; $current_border = $current_oomox_settings->getColourBorderDark() ?: '#201f25';
$current_accent = $current_oomox_settings->getColourAccentDark() ?: '#5ddbcf'; $current_accent = $current_oomox_settings->getColourAccentDark() ?: '#5ddbcf';
} }
} else { } else {
$current_foreground = $is_light ? '#09090d' : '#f0f6f6'; $current_foreground = $is_light ? '#09090d' : '#f0f6f6';
$current_background_hard = $is_light ? '#ebebeb' : '#141216'; $current_background_hard = $is_light ? '#ebebeb' : '#141216';
$current_background_card = $is_light ? '#f0f0f0' : '#131217'; $current_background_card = $is_light ? '#f0f0f0' : '#131217';
$current_border = $is_light ? '#d5d5d5' : '#201f25'; $current_border = $is_light ? '#d5d5d5' : '#201f25';
$current_accent = $is_light ? '#a22430' : '#5ddbcf'; $current_accent = $is_light ? '#a22430' : '#5ddbcf';
} }
return Form::create([ return Form::create([
[$foreground, ColorType::class, [ [$foreground, ColorType::class, [
'html5' => true, 'html5' => true,
'data' => $current_foreground, 'data' => $current_foreground,
'label' => _m('Foreground colour'), 'label' => _m('Foreground colour'),
'help' => _m('Choose the foreground colour'),], 'help' => _m('Choose the foreground colour'), ],
], ],
[$background_hard, ColorType::class, [ [$background_hard, ColorType::class, [
'html5' => true, 'html5' => true,
'data' => $current_background_hard, 'data' => $current_background_hard,
'label' => _m('Background colour'), 'label' => _m('Background colour'),
'help' => _m('Choose the background colour'),], 'help' => _m('Choose the background colour'), ],
], ],
[$background_card, ColorType::class, [ [$background_card, ColorType::class, [
'html5' => true, 'html5' => true,
'data' => $current_background_card, 'data' => $current_background_card,
'label' => _m('Card background colour'), 'label' => _m('Card background colour'),
'help' => _m('Choose the card background colour'),], 'help' => _m('Choose the card background colour'), ],
], ],
[$border, ColorType::class, [ [$border, ColorType::class, [
'html5' => true, 'html5' => true,
'data' => $current_border, 'data' => $current_border,
'label' => _m('Border colour'), 'label' => _m('Border colour'),
'help' => _m('Choose the borders accents'),], 'help' => _m('Choose the borders accents'), ],
], ],
[$accent, ColorType::class, [ [$accent, ColorType::class, [
'html5' => true, 'html5' => true,
'data' => $current_accent, 'data' => $current_accent,
'label' => _m('Accent colour'), 'label' => _m('Accent colour'),
'help' => _m('Choose the accent colour'),], 'help' => _m('Choose the accent colour'), ],
], ],
['hidden', HiddenType::class, []], ['hidden', HiddenType::class, []],
[$reset, SubmitType::class, ['label' => _m('Reset colours to default')]], [$reset, SubmitType::class, ['label' => _m('Reset colours to default')]],
@ -141,11 +140,11 @@ class Oomox
*/ */
public static function oomoxSettingsLight(Request $request): array public static function oomoxSettingsLight(Request $request): array
{ {
$user = Common::ensureLoggedIn(); $user = Common::ensureLoggedIn();
$actor_id = $user->getId(); $actor_id = $user->getId();
$current_oomox_settings = PluginOomox::getEntity($user); $current_oomox_settings = PluginOomox::getEntity($user);
$form_light = (new self)->getOomoxForm($current_oomox_settings, true); $form_light = (new self)->getOomoxForm($current_oomox_settings, true);
$form_light->handleRequest($request); $form_light->handleRequest($request);
if ($form_light->isSubmitted() && $form_light->isValid()) { if ($form_light->isSubmitted() && $form_light->isValid()) {
@ -156,15 +155,15 @@ class Oomox
$current_oomox_settings?->resetTheme(true); $current_oomox_settings?->resetTheme(true);
} }
} else { } else {
$data = $form_light->getData(); $data = $form_light->getData();
$current_oomox_settings = EntityOomox::create( $current_oomox_settings = EntityOomox::create(
[ [
'actor_id' => $actor_id, 'actor_id' => $actor_id,
'colour_foreground_light' => $data['colour_foreground_light'], 'colour_foreground_light' => $data['colour_foreground_light'],
'colour_background_hard_light' => $data['colour_background_hard_light'], 'colour_background_hard_light' => $data['colour_background_hard_light'],
'colour_background_card_light' => $data['colour_background_card_light'], 'colour_background_card_light' => $data['colour_background_card_light'],
'colour_border_light' => $data['colour_border_light'], 'colour_border_light' => $data['colour_border_light'],
'colour_accent_light' => $data['colour_accent_light'], 'colour_accent_light' => $data['colour_accent_light'],
], ],
); );
} }
@ -187,11 +186,11 @@ class Oomox
*/ */
public static function oomoxSettingsDark(Request $request): array public static function oomoxSettingsDark(Request $request): array
{ {
$user = Common::ensureLoggedIn(); $user = Common::ensureLoggedIn();
$actor_id = $user->getId(); $actor_id = $user->getId();
$current_oomox_settings = PluginOomox::getEntity($user); $current_oomox_settings = PluginOomox::getEntity($user);
$form_dark = (new self)->getOomoxForm($current_oomox_settings, false); $form_dark = (new self)->getOomoxForm($current_oomox_settings, false);
$form_dark->handleRequest($request); $form_dark->handleRequest($request);
if ($form_dark->isSubmitted() && $form_dark->isValid()) { if ($form_dark->isSubmitted() && $form_dark->isValid()) {
@ -200,15 +199,15 @@ class Oomox
if ($reset_button->isClicked()) { if ($reset_button->isClicked()) {
$current_oomox_settings?->resetTheme(false); $current_oomox_settings?->resetTheme(false);
} else { } else {
$data = $form_dark->getData(); $data = $form_dark->getData();
$current_oomox_settings = EntityOomox::create( $current_oomox_settings = EntityOomox::create(
[ [
'actor_id' => $actor_id, 'actor_id' => $actor_id,
'colour_foreground_dark' => $data['colour_foreground_dark'], 'colour_foreground_dark' => $data['colour_foreground_dark'],
'colour_background_hard_dark' => $data['colour_background_hard_dark'], 'colour_background_hard_dark' => $data['colour_background_hard_dark'],
'colour_background_card_dark' => $data['colour_background_card_dark'], 'colour_background_card_dark' => $data['colour_background_card_dark'],
'colour_border_dark' => $data['colour_border_dark'], 'colour_border_dark' => $data['colour_border_dark'],
'colour_accent_dark' => $data['colour_accent_dark'], 'colour_accent_dark' => $data['colour_accent_dark'],
], ],
); );
} }
@ -225,18 +224,16 @@ class Oomox
/** /**
* Renders the resulting CSS file from user options, serves that file as a response * Renders the resulting CSS file from user options, serves that file as a response
* *
* @return Response * @throws ClientException
* @throws NoLoggedInUser * @throws NoLoggedInUser
* @throws ServerException * @throws ServerException
*
* @throws ClientException
*/ */
public function oomoxCSS(): Response public function oomoxCSS(): Response
{ {
$user = Common::ensureLoggedIn(); $user = Common::ensureLoggedIn();
$oomox_table = PluginOomox::getEntity($user); $oomox_table = PluginOomox::getEntity($user);
if (is_null($oomox_table)) { if (\is_null($oomox_table)) {
throw new ClientException(_m('No custom colours defined', 404)); throw new ClientException(_m('No custom colours defined', 404));
} }

View File

@ -197,20 +197,20 @@ class Oomox extends Entity
return $this->modified; return $this->modified;
} }
public function resetTheme(bool $is_light) { public function resetTheme(bool $is_light)
{
if ($is_light) { if ($is_light) {
$this->colour_background_hard_light = '#09090d'; $this->colour_background_hard_light = '#09090d';
$this->colour_background_card_light = '#ebebeb'; $this->colour_background_card_light = '#ebebeb';
$this->colour_foreground_light = '#f0f0f0'; $this->colour_foreground_light = '#f0f0f0';
$this->colour_border_light = '#d5d5d5'; $this->colour_border_light = '#d5d5d5';
$this->colour_accent_light = '#a22430'; $this->colour_accent_light = '#a22430';
} else { } else {
$this->colour_background_hard_dark = '#141216'; $this->colour_background_hard_dark = '#141216';
$this->colour_background_card_dark = '#131217'; $this->colour_background_card_dark = '#131217';
$this->colour_foreground_dark = '#f0f6f6'; $this->colour_foreground_dark = '#f0f6f6';
$this->colour_border_dark = '#201f25'; $this->colour_border_dark = '#201f25';
$this->colour_accent_dark = '#5ddbcf'; $this->colour_accent_dark = '#5ddbcf';
} }
} }

View File

@ -29,13 +29,13 @@ use App\Core\Router\RouteLoader;
use App\Core\Router\Router; use App\Core\Router\Router;
use App\Entity\Activity; use App\Entity\Activity;
use App\Entity\Actor; use App\Entity\Actor;
use Component\Language\Entity\Language;
use App\Entity\Note; use App\Entity\Note;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\DuplicateFoundException; use App\Util\Exception\DuplicateFoundException;
use App\Util\Exception\NotFoundException; use App\Util\Exception\NotFoundException;
use App\Util\Exception\ServerException; use App\Util\Exception\ServerException;
use App\Util\Formatting; use App\Util\Formatting;
use Component\Language\Entity\Language;
use Component\Posting\Posting; use Component\Posting\Posting;
use DateTime; use DateTime;
use Plugin\RepeatNote\Entity\NoteRepeat; use Plugin\RepeatNote\Entity\NoteRepeat;
@ -53,11 +53,11 @@ class RepeatNote extends NoteHandlerPlugin
if (!\is_null($repeat_entity)) { if (!\is_null($repeat_entity)) {
return DB::findBy('activity', [ return DB::findBy('activity', [
'actor_id' => $actor_id, 'actor_id' => $actor_id,
'verb' => 'repeat', 'verb' => 'repeat',
'object_type' => 'note', 'object_type' => 'note',
'object_id' => $note->getId() 'object_id' => $note->getId(),
], order_by: ['created' => 'DESC'])[0]; ], order_by: ['created' => 'DESC'])[0];
} }
// Create a new note with the same content as the original // Create a new note with the same content as the original

View File

@ -31,12 +31,12 @@ use function App\Core\I18n\_m;
use App\Entity\Actor; use App\Entity\Actor;
use App\Entity\ActorTag; use App\Entity\ActorTag;
use App\Entity\ActorTagBlock; use App\Entity\ActorTagBlock;
use Component\Language\Entity\Language;
use App\Entity\Note; use App\Entity\Note;
use App\Entity\NoteTag; use App\Entity\NoteTag;
use App\Entity\NoteTagBlock; use App\Entity\NoteTagBlock;
use App\Util\Common; use App\Util\Common;
use App\Util\Exception\RedirectException; use App\Util\Exception\RedirectException;
use Component\Language\Entity\Language;
use Component\Tag\Tag; use Component\Tag\Tag;
use Functional as F; use Functional as F;
use Plugin\TagBasedFiltering\TagBasedFiltering as TagFilerPlugin; use Plugin\TagBasedFiltering\TagBasedFiltering as TagFilerPlugin;

View File

@ -31,7 +31,7 @@ class TreeNotes extends Plugin
*/ */
public function onFormatNoteList(array $notes_in, ?array &$notes_out) public function onFormatNoteList(array $notes_in, ?array &$notes_out)
{ {
$roots = array_filter($notes_in, static fn (Note $note) => is_null($note->getReplyTo())); $roots = array_filter($notes_in, static fn (Note $note) => \is_null($note->getReplyTo()));
$notes_out = $this->build_tree($roots, $notes_in); $notes_out = $this->build_tree($roots, $notes_in);
} }

View File

@ -151,7 +151,7 @@ abstract class Entity
public function getNotificationTargetIds(array $ids_already_known = [], ?int $sender_id = null, bool $include_additional = true): array public function getNotificationTargetIds(array $ids_already_known = [], ?int $sender_id = null, bool $include_additional = true): array
{ {
// Additional actors that should know about this // Additional actors that should know about this
if (array_key_exists('additional', $ids_already_known)) { if (\array_key_exists('additional', $ids_already_known)) {
return $ids_already_known['additional']; return $ids_already_known['additional'];
} }
return []; return [];

View File

@ -44,7 +44,7 @@ class BugFoundException extends ServerException
{ {
parent::__construct($message, $code, $previous); parent::__construct($message, $code, $previous);
$frame = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, limit: 2)[1]; $frame = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, limit: 2)[1];
$file = mb_substr($frame['file'], \mb_strlen(INSTALLDIR) + 1); $file = mb_substr($frame['file'], mb_strlen(INSTALLDIR) + 1);
Log::critical("{$log_message} in {$file}:{$frame['line']}"); Log::critical("{$log_message} in {$file}:{$frame['line']}");
} }
} }

View File

@ -21,7 +21,9 @@ declare(strict_types = 1);
namespace App\Util\Exception; namespace App\Util\Exception;
class FileNotAllowedException extends \InvalidArgumentException use InvalidArgumentException;
class FileNotAllowedException extends InvalidArgumentException
{ {
public function __construct(string $mimetype) public function __construct(string $mimetype)
{ {

View File

@ -1,5 +1,7 @@
<?php <?php
declare(strict_types = 1);
// {{{ License // {{{ License
// This file is part of GNU social - https://www.gnu.org/software/social // This file is part of GNU social - https://www.gnu.org/software/social

View File

@ -6,8 +6,8 @@ namespace App\Util\Form;
use function App\Core\I18n\_m; use function App\Core\I18n\_m;
use App\Entity\Actor; use App\Entity\Actor;
use Component\Language\Entity\Language;
use App\Util\Common; use App\Util\Common;
use Component\Language\Entity\Language;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType; use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType; use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType; use Symfony\Component\Form\Extension\Core\Type\RepeatedType;

View File

@ -263,7 +263,7 @@ abstract class Formatting
// php-intl is highly recommended... // php-intl is highly recommended...
if (!\function_exists('transliterator_transliterate')) { if (!\function_exists('transliterator_transliterate')) {
$str = preg_replace('/[^\pL\pN]/u', '', $str); $str = preg_replace('/[^\pL\pN]/u', '', $str);
$str = mb_convert_case($str, MB_CASE_LOWER, 'UTF-8'); $str = mb_convert_case($str, \MB_CASE_LOWER, 'UTF-8');
return mb_substr($str, 0, $length); return mb_substr($str, 0, $length);
} }
$str = transliterator_transliterate('Any-Latin;' // any charset to latin compatible $str = transliterator_transliterate('Any-Latin;' // any charset to latin compatible

View File

@ -39,7 +39,7 @@ class Notification
public const NOTICE_BY_SUBSCRIBED = 1; public const NOTICE_BY_SUBSCRIBED = 1;
public const MENTION = 2; public const MENTION = 2;
public const REPLY = 3; public const REPLY = 3;
public const SUBSCRIPTION = 4; public const SUBSCRIPTION = 4;
public const FAVORITE = 5; public const FAVORITE = 5;
public const NUDGE = 6; public const NUDGE = 6;
public const DM = 7; public const DM = 7;

View File

@ -24,10 +24,10 @@ namespace App\Tests\Entity;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use App\Core\GSFile; use App\Core\GSFile;
use Component\Attachment\Entity\AttachmentToNote;
use App\Entity\Note; use App\Entity\Note;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use App\Util\TemporaryFile; use App\Util\TemporaryFile;
use Component\Attachment\Entity\AttachmentToNote;
use Jchook\AssertThrows\AssertThrows; use Jchook\AssertThrows\AssertThrows;
use SplFileInfo; use SplFileInfo;
use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\File;

View File

@ -23,9 +23,9 @@ namespace App\Tests\Entity;
use App\Core\DB\DB; use App\Core\DB\DB;
use App\Core\Event; use App\Core\Event;
use Component\Attachment\Entity\AttachmentThumbnail;
use App\Util\Exception\NotStoredLocallyException; use App\Util\Exception\NotStoredLocallyException;
use App\Util\GNUsocialTestCase; use App\Util\GNUsocialTestCase;
use Component\Attachment\Entity\AttachmentThumbnail;
use Functional as F; use Functional as F;
use Jchook\AssertThrows\AssertThrows; use Jchook\AssertThrows\AssertThrows;
use SplFileInfo; use SplFileInfo;