diff --git a/src/Moderation/Entity/Report.php b/src/Moderation/Entity/Report.php new file mode 100644 index 0000000000..93d42b94ef --- /dev/null +++ b/src/Moderation/Entity/Report.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Moderation\Entity; + +/** + * @property-read int $id + * @property-read int $uid + * @property-read int $cid + * @property-read string $comment + * @property-read bool $forward + * @property-read array $postUriIds + * @property-read \DateTime|null $created + */ +class Report extends \Friendica\BaseEntity +{ + /** @var int|null */ + protected $id; + /** @var int ID of the user making a moderation report*/ + protected $uid; + /** @var int ID of the contact being reported*/ + protected $cid; + /** @var string Optional comment */ + protected $comment; + /** @var bool Whether this report should be forwarded to the remote server */ + protected $forward; + /** @var \DateTime|null When the report was created */ + protected $created; + /** @var array Optional list of URI IDs of posts supporting the report*/ + protected $postUriIds; + + public function __construct(int $uid, int $cid, \DateTime $created, string $comment = '', bool $forward = false, array $postUriIds = [], int $id = null) + { + $this->uid = $uid; + $this->cid = $cid; + $this->created = $created; + $this->comment = $comment; + $this->forward = $forward; + $this->postUriIds = $postUriIds; + $this->id = $id; + } +} diff --git a/src/Moderation/Factory/Report.php b/src/Moderation/Factory/Report.php new file mode 100644 index 0000000000..17203d3078 --- /dev/null +++ b/src/Moderation/Factory/Report.php @@ -0,0 +1,72 @@ +. + * + */ + +namespace Friendica\Moderation\Factory; + +use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Moderation\Entity; + +class Report extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + /** + * @param array $row `report` table row + * @param array $postUriIds List of post URI ids from the `report-post` table + * @return Entity\Report + * @throws \Exception + */ + public function createFromTableRow(array $row, array $postUriIds = []): Entity\Report + { + return new Entity\Report( + $row['uid'], + $row['cid'], + new \DateTime($row['created'] ?? 'now', new \DateTimeZone('UTC')), + $row['comment'], + $row['forward'], + $postUriIds, + $row['id'], + ); + } + + /** + * Creates a Report entity from a Mastodon API /reports request + * + * @see \Friendica\Module\Api\Mastodon\Reports::post() + * + * @param int $uid + * @param int $cid + * @param string $comment + * @param bool $forward + * @param array $postUriIds + * @return Entity\Report + * @throws \Exception + */ + public function createFromReportsRequest(int $uid, int $cid, string $comment = '', bool $forward = false, array $postUriIds = []): Entity\Report + { + return new Entity\Report( + $uid, + $cid, + new \DateTime('now', new \DateTimeZone('UTC')), + $comment, + $forward, + $postUriIds, + ); + } +} diff --git a/src/Moderation/Repository/Report.php b/src/Moderation/Repository/Report.php new file mode 100644 index 0000000000..3ffc0de8af --- /dev/null +++ b/src/Moderation/Repository/Report.php @@ -0,0 +1,95 @@ +. + * + */ + +namespace Friendica\Moderation\Repository; + +use Friendica\BaseEntity; +use Friendica\Core\Logger; +use Friendica\Database\Database; +use Friendica\Model\Post; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\Util\DateTimeFormat; +use Psr\Log\LoggerInterface; + +class Report extends \Friendica\BaseRepository +{ + protected static $table_name = 'report'; + + /** + * @var \Friendica\Moderation\Factory\Report + */ + protected $factory; + + public function __construct(Database $database, LoggerInterface $logger, \Friendica\Moderation\Factory\Report $factory) + { + parent::__construct($database, $logger, $factory); + + $this->factory = $factory; + } + + public function selectOneById(int $lastInsertId): \Friendica\Moderation\Factory\Report + { + return $this->_selectOne(['id' => $lastInsertId]); + } + + public function save(\Friendica\Moderation\Entity\Report $Report) + { + $fields = [ + 'uid' => $Report->uid, + 'cid' => $Report->cid, + 'comment' => $Report->comment, + 'forward' => $Report->forward, + ]; + + if ($Report->id) { + $this->db->update(self::$table_name, $fields, ['id' => $Report->id]); + } else { + $fields['created'] = DateTimeFormat::utcNow(); + $this->db->insert(self::$table_name, $fields, Database::INSERT_IGNORE); + + $Report = $this->selectOneById($this->db->lastInsertId()); + } + + $this->db->delete('report-post', ['rid' => $Report->id]); + + foreach ($Report->postUriIds as $uriId) { + if (Post::exists(['uri-id' => $uriId])) { + $this->db->insert('report-post', ['rid' => $Report->id, 'uri-id' => $uriId]); + } else { + Logger::notice('Post does not exist', ['uri-id' => $uriId, 'report' => $Report]); + } + } + + return $Report; + } + + protected function _selectOne(array $condition, array $params = []): BaseEntity + { + $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + if (!$this->db->isResult($fields)) { + throw new NotFoundException(); + } + + $postUriIds = array_column($this->db->selectToArray('report-post', ['uri-id'], ['rid' => $condition['id'] ?? 0]), 'uri-id'); + + return $this->factory->createFromTableRow($fields, $postUriIds); + } +} diff --git a/tests/src/Moderation/Factory/ReportTest.php b/tests/src/Moderation/Factory/ReportTest.php new file mode 100644 index 0000000000..0f29709100 --- /dev/null +++ b/tests/src/Moderation/Factory/ReportTest.php @@ -0,0 +1,149 @@ +. + * + */ + +namespace Friendica\Test\src\Moderation\Factory; + +use Friendica\Moderation\Factory; +use Friendica\Moderation\Entity; +use Friendica\Test\MockedTest; +use Psr\Log\NullLogger; + +class ReportTest extends MockedTest +{ + public function dataCreateFromTableRow(): array + { + return [ + 'default' => [ + 'row' => [ + 'id' => 11, + 'uid' => 12, + 'cid' => 13, + 'comment' => '', + 'forward' => false, + 'created' => null + ], + 'postUriIds' => [], + 'assertion' => new Entity\Report( + 12, + 13, + new \DateTime('now', new \DateTimeZone('UTC')), + '', + false, + [], + 11, + ), + ], + 'full' => [ + 'row' => [ + 'id' => 11, + 'uid' => 12, + 'cid' => 13, + 'comment' => 'Report', + 'forward' => true, + 'created' => '2021-10-12 12:23:00' + ], + 'postUriIds' => [89, 90], + 'assertion' => new Entity\Report( + 12, + 13, + new \DateTime('2021-10-12 12:23:00', new \DateTimeZone('UTC')), + 'Report', + true, + [89, 90], + 11 + ), + ], + ]; + } + + public function assertReport(Entity\Report $assertion, Entity\Report $report) + { + self::assertEquals( + $assertion->id, + $report->id + ); + self::assertEquals($assertion->uid, $report->uid); + self::assertEquals($assertion->cid, $report->cid); + self::assertEquals($assertion->comment, $report->comment); + self::assertEquals($assertion->forward, $report->forward); + // No way to test "now" at the moment + //self::assertEquals($assertion->created, $report->created); + self::assertEquals($assertion->postUriIds, $report->postUriIds); + } + + /** + * @dataProvider dataCreateFromTableRow + */ + public function testCreateFromTableRow(array $row, array $postUriIds, Entity\Report $assertion) + { + $factory = new Factory\Report(new NullLogger()); + + $this->assertReport($factory->createFromTableRow($row, $postUriIds), $assertion); + } + + public function dataCreateFromReportsRequest(): array + { + return [ + 'default' => [ + 'uid' => 12, + 'cid' => 13, + 'comment' => '', + 'forward' => false, + 'postUriIds' => [], + 'assertion' => new Entity\Report( + 12, + 13, + new \DateTime('now', new \DateTimeZone('UTC')), + '', + false, + [], + null + ), + ], + 'full' => [ + 'uid' => 12, + 'cid' => 13, + 'comment' => 'Report', + 'forward' => true, + 'postUriIds' => [89, 90], + 'assertion' => new Entity\Report( + 12, + 13, + new \DateTime('now', new \DateTimeZone('UTC')), + 'Report', + true, + [89, 90], + null + ), + ], + ]; + } + + /** + * @dataProvider dataCreateFromReportsRequest + */ + public function testCreateFromReportsRequest(int $uid, int $cid, string $comment, bool $forward, array $postUriIds, Entity\Report $assertion) + { + $factory = new Factory\Report(new NullLogger()); + + $this->assertReport($factory->createFromReportsRequest($uid, $cid, $comment, $forward, $postUriIds), $assertion); + } +}