]> git.mxchange.org Git - friendica.git/commitdiff
Rename Depository to Repository
authorPhilipp <admin@philipp.info>
Thu, 21 Oct 2021 21:18:08 +0000 (23:18 +0200)
committerHypolite Petovan <hypolite@mrpetovan.com>
Sun, 24 Oct 2021 01:45:36 +0000 (21:45 -0400)
26 files changed:
src/BaseDepository.php [deleted file]
src/BaseRepository.php [new file with mode: 0644]
src/Contact/FriendSuggest/Depository/FriendSuggest.php [deleted file]
src/Contact/FriendSuggest/Repository/FriendSuggest.php [new file with mode: 0644]
src/Contact/Introduction/Depository/Introduction.php [deleted file]
src/Contact/Introduction/Repository/Introduction.php [new file with mode: 0644]
src/Core/UserImport.php
src/DI.php
src/Factory/Api/Mastodon/Account.php
src/Module/Api/Friendica/Profile/Show.php
src/Navigation/Notifications/Depository/Notification.php [deleted file]
src/Navigation/Notifications/Depository/Notify.php [deleted file]
src/Navigation/Notifications/Factory/FormattedNotification.php
src/Navigation/Notifications/Repository/Notification.php [new file with mode: 0644]
src/Navigation/Notifications/Repository/Notify.php [new file with mode: 0644]
src/Profile/ProfileField/Depository/ProfileField.php [deleted file]
src/Profile/ProfileField/Repository/ProfileField.php [new file with mode: 0644]
src/Security/PermissionSet/Depository/PermissionSet.php [deleted file]
src/Security/PermissionSet/Entity/PermissionSet.php
src/Security/PermissionSet/Repository/PermissionSet.php [new file with mode: 0644]
tests/src/Profile/ProfileField/Depository/ProfileFieldTest.php [deleted file]
tests/src/Profile/ProfileField/Entity/ProfileFieldTest.php
tests/src/Profile/ProfileField/Repository/ProfileFieldTest.php [new file with mode: 0644]
tests/src/Security/PermissionSet/Depository/PermissionSetTest.php [deleted file]
tests/src/Security/PermissionSet/Repository/PermissionSetTest.php [new file with mode: 0644]
update.php

diff --git a/src/BaseDepository.php b/src/BaseDepository.php
deleted file mode 100644 (file)
index 75118dd..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-<?php
-
-namespace Friendica;
-
-use Exception;
-use Friendica\Capabilities\ICanCreateFromTableRow;
-use Friendica\Database\Database;
-use Friendica\Database\DBA;
-use Friendica\Network\HTTPException\NotFoundException;
-use Psr\Log\LoggerInterface;
-
-/**
- * Depositories are meant to store and retrieve Entities from the database.
- *
- * The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
- * which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
- * class for example)
- *
- * Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
- * is less pressing.
- */
-abstract class BaseDepository
-{
-       const LIMIT = 30;
-
-       /**
-        * @var string This should be set to the main database table name the depository is using
-        */
-       protected static $table_name;
-
-       /** @var Database */
-       protected $db;
-
-       /** @var LoggerInterface */
-       protected $logger;
-
-       /** @var ICanCreateFromTableRow */
-       protected $factory;
-
-       public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
-       {
-               $this->db      = $database;
-               $this->logger  = $logger;
-               $this->factory = $factory;
-       }
-
-       /**
-        * Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
-        * boundaries and the limit. The total count of rows matching the condition is stored in the collection.
-        *
-        * Depends on the corresponding table featuring a numerical auto incremented column called `id`.
-        *
-        * max_id and min_id are susceptible to the query order:
-        * - min_id alone only reliably works with ASC order
-        * - max_id alone only reliably works with DESC order
-        * If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
-        *
-        * Chainable.
-        *
-        * @param array    $condition
-        * @param array    $params
-        * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
-        * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
-        * @param int      $limit
-        * @return BaseCollection
-        * @throws \Exception
-        */
-       protected function _selectByBoundaries(
-               array $condition = [],
-               array $params = [],
-               int $min_id = null,
-               int $max_id = null,
-               int $limit = self::LIMIT
-       ): BaseCollection {
-               $totalCount = $this->count($condition);
-
-               $boundCondition = $condition;
-
-               $reverseOrder = false;
-
-               if (isset($min_id)) {
-                       $boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
-                       if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
-                               $reverseOrder = true;
-
-                               $params['order']['id'] = 'ASC';
-                       }
-               }
-
-               if (isset($max_id) && $max_id > 0) {
-                       $boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
-                       if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
-                               $reverseOrder = true;
-
-                               $params['order']['id'] = 'DESC';
-                       }
-               }
-
-               $params['limit'] = $limit;
-
-               $Entities = $this->_select($boundCondition, $params);
-               if ($reverseOrder) {
-                       $Entities->reverse();
-               }
-
-               return new BaseCollection($Entities->getArrayCopy(), $totalCount);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return BaseCollection
-        * @throws Exception
-        */
-       protected function _select(array $condition, array $params = []): BaseCollection
-       {
-               $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
-
-               $Entities = new BaseCollection();
-               foreach ($rows as $fields) {
-                       $Entities[] = $this->factory->createFromTableRow($fields);
-               }
-
-               return $Entities;
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return BaseEntity
-        * @throws NotFoundException
-        */
-       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();
-               }
-
-               return $this->factory->createFromTableRow($fields);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return int
-        * @throws Exception
-        */
-       public function count(array $condition, array $params = []): int
-       {
-               return $this->db->count(static::$table_name, $condition, $params);
-       }
-
-       /**
-        * @param array $condition
-        * @return bool
-        * @throws Exception
-        */
-       public function exists(array $condition): bool
-       {
-               return $this->db->exists(static::$table_name, $condition);
-       }
-}
diff --git a/src/BaseRepository.php b/src/BaseRepository.php
new file mode 100644 (file)
index 0000000..dccfe7f
--- /dev/null
@@ -0,0 +1,163 @@
+<?php
+
+namespace Friendica;
+
+use Exception;
+use Friendica\Capabilities\ICanCreateFromTableRow;
+use Friendica\Database\Database;
+use Friendica\Database\DBA;
+use Friendica\Network\HTTPException\NotFoundException;
+use Psr\Log\LoggerInterface;
+
+/**
+ * Repositories are meant to store and retrieve Entities from the database.
+ *
+ * The reason why there are methods prefixed with an underscore is because PHP doesn't support generic polymorphism
+ * which means we can't directly overload base methods and make parameters more strict (from a parent class to a child
+ * class for example)
+ *
+ * Similarly, we can't make an overloaded method return type more strict until we only support PHP version 7.4 but this
+ * is less pressing.
+ */
+abstract class BaseRepository
+{
+       const LIMIT = 30;
+
+       /**
+        * @var string This should be set to the main database table name the depository is using
+        */
+       protected static $table_name;
+
+       /** @var Database */
+       protected $db;
+
+       /** @var LoggerInterface */
+       protected $logger;
+
+       /** @var ICanCreateFromTableRow */
+       protected $factory;
+
+       public function __construct(Database $database, LoggerInterface $logger, ICanCreateFromTableRow $factory)
+       {
+               $this->db      = $database;
+               $this->logger  = $logger;
+               $this->factory = $factory;
+       }
+
+       /**
+        * Populates the collection according to the condition. Retrieves a limited subset of entities depending on the
+        * boundaries and the limit. The total count of rows matching the condition is stored in the collection.
+        *
+        * Depends on the corresponding table featuring a numerical auto incremented column called `id`.
+        *
+        * max_id and min_id are susceptible to the query order:
+        * - min_id alone only reliably works with ASC order
+        * - max_id alone only reliably works with DESC order
+        * If the wrong order is detected in either case, we reverse the query order and the entity list order after the query
+        *
+        * Chainable.
+        *
+        * @param array    $condition
+        * @param array    $params
+        * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
+        * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
+        * @param int      $limit
+        * @return BaseCollection
+        * @throws \Exception
+        */
+       protected function _selectByBoundaries(
+               array $condition = [],
+               array $params = [],
+               int $min_id = null,
+               int $max_id = null,
+               int $limit = self::LIMIT
+       ): BaseCollection {
+               $totalCount = $this->count($condition);
+
+               $boundCondition = $condition;
+
+               $reverseOrder = false;
+
+               if (isset($min_id)) {
+                       $boundCondition = DBA::mergeConditions($boundCondition, ['`id` > ?', $min_id]);
+                       if (!isset($max_id) && isset($params['order']['id']) && ($params['order']['id'] === true || $params['order']['id'] === 'DESC')) {
+                               $reverseOrder = true;
+
+                               $params['order']['id'] = 'ASC';
+                       }
+               }
+
+               if (isset($max_id) && $max_id > 0) {
+                       $boundCondition = DBA::mergeConditions($boundCondition, ['`id` < ?', $max_id]);
+                       if (!isset($min_id) && (!isset($params['order']['id']) || $params['order']['id'] === false || $params['order']['id'] === 'ASC')) {
+                               $reverseOrder = true;
+
+                               $params['order']['id'] = 'DESC';
+                       }
+               }
+
+               $params['limit'] = $limit;
+
+               $Entities = $this->_select($boundCondition, $params);
+               if ($reverseOrder) {
+                       $Entities->reverse();
+               }
+
+               return new BaseCollection($Entities->getArrayCopy(), $totalCount);
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        * @return BaseCollection
+        * @throws Exception
+        */
+       protected function _select(array $condition, array $params = []): BaseCollection
+       {
+               $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params);
+
+               $Entities = new BaseCollection();
+               foreach ($rows as $fields) {
+                       $Entities[] = $this->factory->createFromTableRow($fields);
+               }
+
+               return $Entities;
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        * @return BaseEntity
+        * @throws NotFoundException
+        */
+       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();
+               }
+
+               return $this->factory->createFromTableRow($fields);
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        * @return int
+        * @throws Exception
+        */
+       public function count(array $condition, array $params = []): int
+       {
+               return $this->db->count(static::$table_name, $condition, $params);
+       }
+
+       /**
+        * @param array $condition
+        * @return bool
+        * @throws Exception
+        */
+       public function exists(array $condition): bool
+       {
+               return $this->db->exists(static::$table_name, $condition);
+       }
+}
diff --git a/src/Contact/FriendSuggest/Depository/FriendSuggest.php b/src/Contact/FriendSuggest/Depository/FriendSuggest.php
deleted file mode 100644 (file)
index 76f96bd..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-<?php
-
-namespace Friendica\Contact\FriendSuggest\Depository;
-
-use Friendica\BaseCollection;
-use Friendica\BaseDepository;
-use Friendica\Contact\FriendSuggest\Collection;
-use Friendica\Contact\FriendSuggest\Entity;
-use Friendica\Contact\FriendSuggest\Exception\FriendSuggestNotFoundException;
-use Friendica\Contact\FriendSuggest\Exception\FriendSuggestPersistenceException;
-use Friendica\Contact\FriendSuggest\Factory;
-use Friendica\Database\Database;
-use Friendica\Network\HTTPException\NotFoundException;
-use Psr\Log\LoggerInterface;
-
-class FriendSuggest extends BaseDepository
-{
-       /** @var Factory\FriendSuggest */
-       protected $factory;
-
-       protected static $table_name = 'fsuggest';
-
-       public function __construct(Database $database, LoggerInterface $logger, Factory\FriendSuggest $factory)
-       {
-               parent::__construct($database, $logger, $factory);
-       }
-
-       private function convertToTableRow(Entity\FriendSuggest $fsuggest): array
-       {
-               return [
-                       'uid'     => $fsuggest->uid,
-                       'cid'     => $fsuggest->cid,
-                       'name'    => $fsuggest->name,
-                       'url'     => $fsuggest->url,
-                       'request' => $fsuggest->request,
-                       'photo'   => $fsuggest->photo,
-                       'note'    => $fsuggest->note,
-               ];
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Entity\FriendSuggest
-        *
-        * @throws NotFoundException The underlying exception if there's no FriendSuggest with the given conditions
-        */
-       private function selectOne(array $condition, array $params = []): Entity\FriendSuggest
-       {
-               return parent::_selectOne($condition, $params);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Collection\FriendSuggests
-        *
-        * @throws \Exception
-        */
-       private function select(array $condition, array $params = []): Collection\FriendSuggests
-       {
-               return parent::_select($condition, $params);
-       }
-
-       /**
-        * @param int $id
-        *
-        * @return Entity\FriendSuggest
-        *
-        * @throws FriendSuggestNotFoundException in case there's no suggestion for this id
-        */
-       public function selectOneById(int $id): Entity\FriendSuggest
-       {
-               try {
-                       return $this->selectOne(['id' => $id]);
-               } catch (NotFoundException $e) {
-                       throw new FriendSuggestNotFoundException(sprintf('No FriendSuggest found for id %d', $id));
-               }
-       }
-
-       /**
-        * @param int $cid
-        *
-        * @return Collection\FriendSuggests
-        *
-        * @throws FriendSuggestPersistenceException In case the underlying storage cannot select the suggestion
-        */
-       public function selectForContact(int $cid): Collection\FriendSuggests
-       {
-               try {
-                       return $this->select(['cid' => $cid]);
-               } catch (\Exception $e) {
-                       throw new FriendSuggestPersistenceException(sprintf('Cannot select FriendSuggestion for contact %d', $cid));
-               }
-       }
-
-       /**
-        * @param Entity\FriendSuggest $fsuggest
-        *
-        * @return Entity\FriendSuggest
-        *
-        * @throws FriendSuggestNotFoundException in case the underlying storage cannot save the suggestion
-        */
-       public function save(Entity\FriendSuggest $fsuggest): Entity\FriendSuggest
-       {
-               try {
-                       $fields = $this->convertToTableRow($fsuggest);
-
-                       if ($fsuggest->id) {
-                               $this->db->update(self::$table_name, $fields, ['id' => $fsuggest->id]);
-                               return $this->factory->createFromTableRow($fields);
-                       } else {
-                               $this->db->insert(self::$table_name, $fields);
-                               return $this->selectOneById($this->db->lastInsertId());
-                       }
-               } catch (\Exception $exception) {
-                       throw new FriendSuggestNotFoundException(sprintf('Cannot insert/update the FriendSuggestion %d for user %d', $fsuggest->id, $fsuggest->uid), $exception);
-               }
-       }
-
-       /**
-        * @param Collection\FriendSuggest $fsuggests
-        *
-        * @return bool
-        *
-        * @throws FriendSuggestNotFoundException in case the underlying storage cannot delete the suggestion
-        */
-       public function delete(Collection\FriendSuggests $fsuggests): bool
-       {
-               try {
-                       $ids = $fsuggests->column('id');
-                       return $this->db->delete(self::$table_name, ['id' => $ids]);
-               } catch (\Exception $exception) {
-                       throw new FriendSuggestNotFoundException('Cannot delete the FriendSuggestions', $exception);
-               }
-       }
-}
diff --git a/src/Contact/FriendSuggest/Repository/FriendSuggest.php b/src/Contact/FriendSuggest/Repository/FriendSuggest.php
new file mode 100644 (file)
index 0000000..77abd73
--- /dev/null
@@ -0,0 +1,138 @@
+<?php
+
+namespace Friendica\Contact\FriendSuggest\Repository;
+
+use Friendica\BaseRepository;
+use Friendica\Contact\FriendSuggest\Collection;
+use Friendica\Contact\FriendSuggest\Entity;
+use Friendica\Contact\FriendSuggest\Exception\FriendSuggestNotFoundException;
+use Friendica\Contact\FriendSuggest\Exception\FriendSuggestPersistenceException;
+use Friendica\Contact\FriendSuggest\Factory;
+use Friendica\Database\Database;
+use Friendica\Network\HTTPException\NotFoundException;
+use Psr\Log\LoggerInterface;
+
+class FriendSuggest extends BaseRepository
+{
+       /** @var Factory\FriendSuggest */
+       protected $factory;
+
+       protected static $table_name = 'fsuggest';
+
+       public function __construct(Database $database, LoggerInterface $logger, Factory\FriendSuggest $factory)
+       {
+               parent::__construct($database, $logger, $factory);
+       }
+
+       private function convertToTableRow(Entity\FriendSuggest $fsuggest): array
+       {
+               return [
+                       'uid'     => $fsuggest->uid,
+                       'cid'     => $fsuggest->cid,
+                       'name'    => $fsuggest->name,
+                       'url'     => $fsuggest->url,
+                       'request' => $fsuggest->request,
+                       'photo'   => $fsuggest->photo,
+                       'note'    => $fsuggest->note,
+               ];
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Entity\FriendSuggest
+        *
+        * @throws NotFoundException The underlying exception if there's no FriendSuggest with the given conditions
+        */
+       private function selectOne(array $condition, array $params = []): Entity\FriendSuggest
+       {
+               return parent::_selectOne($condition, $params);
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Collection\FriendSuggests
+        *
+        * @throws \Exception
+        */
+       private function select(array $condition, array $params = []): Collection\FriendSuggests
+       {
+               return parent::_select($condition, $params);
+       }
+
+       /**
+        * @param int $id
+        *
+        * @return Entity\FriendSuggest
+        *
+        * @throws FriendSuggestNotFoundException in case there's no suggestion for this id
+        */
+       public function selectOneById(int $id): Entity\FriendSuggest
+       {
+               try {
+                       return $this->selectOne(['id' => $id]);
+               } catch (NotFoundException $e) {
+                       throw new FriendSuggestNotFoundException(sprintf('No FriendSuggest found for id %d', $id));
+               }
+       }
+
+       /**
+        * @param int $cid
+        *
+        * @return Collection\FriendSuggests
+        *
+        * @throws FriendSuggestPersistenceException In case the underlying storage cannot select the suggestion
+        */
+       public function selectForContact(int $cid): Collection\FriendSuggests
+       {
+               try {
+                       return $this->select(['cid' => $cid]);
+               } catch (\Exception $e) {
+                       throw new FriendSuggestPersistenceException(sprintf('Cannot select FriendSuggestion for contact %d', $cid));
+               }
+       }
+
+       /**
+        * @param Entity\FriendSuggest $fsuggest
+        *
+        * @return Entity\FriendSuggest
+        *
+        * @throws FriendSuggestNotFoundException in case the underlying storage cannot save the suggestion
+        */
+       public function save(Entity\FriendSuggest $fsuggest): Entity\FriendSuggest
+       {
+               try {
+                       $fields = $this->convertToTableRow($fsuggest);
+
+                       if ($fsuggest->id) {
+                               $this->db->update(self::$table_name, $fields, ['id' => $fsuggest->id]);
+                               return $this->factory->createFromTableRow($fields);
+                       } else {
+                               $this->db->insert(self::$table_name, $fields);
+                               return $this->selectOneById($this->db->lastInsertId());
+                       }
+               } catch (\Exception $exception) {
+                       throw new FriendSuggestNotFoundException(sprintf('Cannot insert/update the FriendSuggestion %d for user %d', $fsuggest->id, $fsuggest->uid), $exception);
+               }
+       }
+
+       /**
+        * @param Collection\FriendSuggest $fsuggests
+        *
+        * @return bool
+        *
+        * @throws FriendSuggestNotFoundException in case the underlying storage cannot delete the suggestion
+        */
+       public function delete(Collection\FriendSuggests $fsuggests): bool
+       {
+               try {
+                       $ids = $fsuggests->column('id');
+                       return $this->db->delete(self::$table_name, ['id' => $ids]);
+               } catch (\Exception $exception) {
+                       throw new FriendSuggestNotFoundException('Cannot delete the FriendSuggestions', $exception);
+               }
+       }
+}
diff --git a/src/Contact/Introduction/Depository/Introduction.php b/src/Contact/Introduction/Depository/Introduction.php
deleted file mode 100644 (file)
index 792673f..0000000
+++ /dev/null
@@ -1,209 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Contact\Introduction\Depository;
-
-use Friendica\BaseDepository;
-use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException;
-use Friendica\Contact\Introduction\Exception\IntroductionPersistenceException;
-use Friendica\Contact\Introduction\Collection;
-use Friendica\Contact\Introduction\Entity;
-use Friendica\Contact\Introduction\Factory;
-use Friendica\Database\Database;
-use Friendica\Network\HTTPException\NotFoundException;
-use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
-
-class Introduction extends BaseDepository
-{
-       /** @var Factory\Introduction */
-       protected $factory;
-
-       protected static $table_name = 'intro';
-
-       public function __construct(Database $database, LoggerInterface $logger, Factory\Introduction $factory)
-       {
-               parent::__construct($database, $logger, $factory);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Entity\Introduction
-        *
-        * @throws NotFoundException the underlying exception if there's no Introduction with the given conditions
-        */
-       private function selectOne(array $condition, array $params = []): Entity\Introduction
-       {
-               return parent::_selectOne($condition, $params);
-       }
-
-       /**
-        * Converts a given Introduction into a DB compatible row array
-        *
-        * @param Entity\Introduction $introduction
-        *
-        * @return array
-        */
-       protected function convertToTableRow(Entity\Introduction $introduction): array
-       {
-               return [
-                       'uid'         => $introduction->uid,
-                       'contact-id'  => $introduction->cid,
-                       'suggest-cid' => $introduction->sid,
-                       'knowyou'     => $introduction->knowyou ? 1 : 0,
-                       'note'        => $introduction->note,
-                       'hash'        => $introduction->hash,
-                       'ignore'      => $introduction->ignore ? 1 : 0,
-                       'datetime'    => $introduction->datetime->format(DateTimeFormat::MYSQL),
-               ];
-       }
-
-       /**
-        * @param int $id
-        * @param int $uid
-        *
-        * @return Entity\Introduction
-        *
-        * @throws IntroductionNotFoundException in case there is no Introduction with this id
-        */
-       public function selectOneById(int $id, int $uid): Entity\Introduction
-       {
-               try {
-                       return $this->selectOne(['id' => $id, 'uid' => $uid]);
-               } catch (NotFoundException $exception) {
-                       throw new IntroductionNotFoundException(sprintf('There is no Introduction with the ID %d for the user %d', $id, $uid), $exception);
-               }
-       }
-
-       /**
-        * Selects introductions for a given user
-        *
-        * @param int      $uid
-        * @param int|null $min_id
-        * @param int|null $max_id
-        * @param int      $limit
-        *
-        * @return Collection\Introductions
-        */
-       public function selectForUser(int $uid, int $min_id = null, int $max_id = null, int $limit = self::LIMIT): Collection\Introductions
-       {
-               try {
-                       $BaseCollection = parent::_selectByBoundaries(
-                               ['`uid = ?` AND NOT `ignore`',$uid],
-                               ['order' => ['id' => 'DESC']],
-                               $min_id, $max_id, $limit);
-               } catch (\Exception $e) {
-                       throw new IntroductionPersistenceException(sprintf('Cannot select Introductions for used %d', $uid), $e);
-               }
-
-               return new Collection\Introductions($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount());
-       }
-
-       /**
-        * Selects the introduction for a given contact
-        *
-        * @param int $cid
-        *
-        * @return Entity\Introduction
-        *
-        * @throws IntroductionNotFoundException in case there is not Introduction for this contact
-        */
-       public function selectForContact(int $cid): Entity\Introduction
-       {
-               try {
-                       return $this->selectOne(['contact-id' => $cid]);
-               } catch (NotFoundException $exception) {
-                       throw new IntroductionNotFoundException(sprintf('There is no Introduction for the contact %d', $cid), $exception);
-               }
-       }
-
-       public function countActiveForUser($uid, array $params = []): int
-       {
-               try {
-                       return $this->count(['ignore' => false, 'uid' => $uid], $params);
-               } catch (\Exception $e) {
-                       throw new IntroductionPersistenceException(sprintf('Cannot count Introductions for used %d', $uid), $e);
-               }
-       }
-
-       /**
-        * Checks, if the suggested contact already exists for the user
-        *
-        * @param int $sid
-        * @param int $uid
-        *
-        * @return bool
-        */
-       public function suggestionExistsForUser(int $sid, int $uid): bool
-       {
-               try {
-                       return $this->exists(['uid' => $uid, 'suggest-cid' => $sid]);
-               } catch (\Exception $e) {
-                       throw new IntroductionPersistenceException(sprintf('Cannot check suggested Introduction for contact %d and user %d', $sid, $uid), $e);
-               }
-       }
-
-       /**
-        * @param Entity\Introduction $introduction
-        *
-        * @return bool
-        *
-        * @throws IntroductionPersistenceException in case the underlying storage cannot delete the Introduction
-        */
-       public function delete(Entity\Introduction $introduction): bool
-       {
-               if (!$introduction->id) {
-                       return false;
-               }
-
-               try {
-                       return $this->db->delete(self::$table_name, ['id' => $introduction->id]);
-               } catch (\Exception $e) {
-                       throw new IntroductionPersistenceException(sprintf('Cannot delete Introduction with id %d', $introduction->id), $e);
-               }
-       }
-
-       /**
-        * @param Entity\Introduction $introduction
-        *
-        * @return Entity\Introduction
-        *
-        * @throws IntroductionPersistenceException In case the underlying storage cannot save the Introduction
-        */
-       public function save(Entity\Introduction $introduction): Entity\Introduction
-       {
-               try {
-                       $fields = $this->convertToTableRow($introduction);
-
-                       if ($introduction->id) {
-                               $this->db->update(self::$table_name, $fields, ['id' => $introduction->id]);
-                               return $this->factory->createFromTableRow($fields);
-                       } else {
-                               $this->db->insert(self::$table_name, $fields);
-                               return $this->selectOneById($this->db->lastInsertId(), $introduction->uid);
-                       }
-               } catch (\Exception $exception) {
-                       throw new IntroductionPersistenceException(sprintf('Cannot insert/update the Introduction %d for user %d', $introduction->id, $introduction->uid), $exception);
-               }
-       }
-}
diff --git a/src/Contact/Introduction/Repository/Introduction.php b/src/Contact/Introduction/Repository/Introduction.php
new file mode 100644 (file)
index 0000000..6121d3a
--- /dev/null
@@ -0,0 +1,209 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Contact\Introduction\Repository;
+
+use Friendica\BaseRepository;
+use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException;
+use Friendica\Contact\Introduction\Exception\IntroductionPersistenceException;
+use Friendica\Contact\Introduction\Collection;
+use Friendica\Contact\Introduction\Entity;
+use Friendica\Contact\Introduction\Factory;
+use Friendica\Database\Database;
+use Friendica\Network\HTTPException\NotFoundException;
+use Friendica\Util\DateTimeFormat;
+use Psr\Log\LoggerInterface;
+
+class Introduction extends BaseRepository
+{
+       /** @var Factory\Introduction */
+       protected $factory;
+
+       protected static $table_name = 'intro';
+
+       public function __construct(Database $database, LoggerInterface $logger, Factory\Introduction $factory)
+       {
+               parent::__construct($database, $logger, $factory);
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Entity\Introduction
+        *
+        * @throws NotFoundException the underlying exception if there's no Introduction with the given conditions
+        */
+       private function selectOne(array $condition, array $params = []): Entity\Introduction
+       {
+               return parent::_selectOne($condition, $params);
+       }
+
+       /**
+        * Converts a given Introduction into a DB compatible row array
+        *
+        * @param Entity\Introduction $introduction
+        *
+        * @return array
+        */
+       protected function convertToTableRow(Entity\Introduction $introduction): array
+       {
+               return [
+                       'uid'         => $introduction->uid,
+                       'contact-id'  => $introduction->cid,
+                       'suggest-cid' => $introduction->sid,
+                       'knowyou'     => $introduction->knowyou ? 1 : 0,
+                       'note'        => $introduction->note,
+                       'hash'        => $introduction->hash,
+                       'ignore'      => $introduction->ignore ? 1 : 0,
+                       'datetime'    => $introduction->datetime->format(DateTimeFormat::MYSQL),
+               ];
+       }
+
+       /**
+        * @param int $id
+        * @param int $uid
+        *
+        * @return Entity\Introduction
+        *
+        * @throws IntroductionNotFoundException in case there is no Introduction with this id
+        */
+       public function selectOneById(int $id, int $uid): Entity\Introduction
+       {
+               try {
+                       return $this->selectOne(['id' => $id, 'uid' => $uid]);
+               } catch (NotFoundException $exception) {
+                       throw new IntroductionNotFoundException(sprintf('There is no Introduction with the ID %d for the user %d', $id, $uid), $exception);
+               }
+       }
+
+       /**
+        * Selects introductions for a given user
+        *
+        * @param int      $uid
+        * @param int|null $min_id
+        * @param int|null $max_id
+        * @param int      $limit
+        *
+        * @return Collection\Introductions
+        */
+       public function selectForUser(int $uid, int $min_id = null, int $max_id = null, int $limit = self::LIMIT): Collection\Introductions
+       {
+               try {
+                       $BaseCollection = parent::_selectByBoundaries(
+                               ['`uid = ?` AND NOT `ignore`',$uid],
+                               ['order' => ['id' => 'DESC']],
+                               $min_id, $max_id, $limit);
+               } catch (\Exception $e) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot select Introductions for used %d', $uid), $e);
+               }
+
+               return new Collection\Introductions($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount());
+       }
+
+       /**
+        * Selects the introduction for a given contact
+        *
+        * @param int $cid
+        *
+        * @return Entity\Introduction
+        *
+        * @throws IntroductionNotFoundException in case there is not Introduction for this contact
+        */
+       public function selectForContact(int $cid): Entity\Introduction
+       {
+               try {
+                       return $this->selectOne(['contact-id' => $cid]);
+               } catch (NotFoundException $exception) {
+                       throw new IntroductionNotFoundException(sprintf('There is no Introduction for the contact %d', $cid), $exception);
+               }
+       }
+
+       public function countActiveForUser($uid, array $params = []): int
+       {
+               try {
+                       return $this->count(['ignore' => false, 'uid' => $uid], $params);
+               } catch (\Exception $e) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot count Introductions for used %d', $uid), $e);
+               }
+       }
+
+       /**
+        * Checks, if the suggested contact already exists for the user
+        *
+        * @param int $sid
+        * @param int $uid
+        *
+        * @return bool
+        */
+       public function suggestionExistsForUser(int $sid, int $uid): bool
+       {
+               try {
+                       return $this->exists(['uid' => $uid, 'suggest-cid' => $sid]);
+               } catch (\Exception $e) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot check suggested Introduction for contact %d and user %d', $sid, $uid), $e);
+               }
+       }
+
+       /**
+        * @param Entity\Introduction $introduction
+        *
+        * @return bool
+        *
+        * @throws IntroductionPersistenceException in case the underlying storage cannot delete the Introduction
+        */
+       public function delete(Entity\Introduction $introduction): bool
+       {
+               if (!$introduction->id) {
+                       return false;
+               }
+
+               try {
+                       return $this->db->delete(self::$table_name, ['id' => $introduction->id]);
+               } catch (\Exception $e) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot delete Introduction with id %d', $introduction->id), $e);
+               }
+       }
+
+       /**
+        * @param Entity\Introduction $introduction
+        *
+        * @return Entity\Introduction
+        *
+        * @throws IntroductionPersistenceException In case the underlying storage cannot save the Introduction
+        */
+       public function save(Entity\Introduction $introduction): Entity\Introduction
+       {
+               try {
+                       $fields = $this->convertToTableRow($introduction);
+
+                       if ($introduction->id) {
+                               $this->db->update(self::$table_name, $fields, ['id' => $introduction->id]);
+                               return $this->factory->createFromTableRow($fields);
+                       } else {
+                               $this->db->insert(self::$table_name, $fields);
+                               return $this->selectOneById($this->db->lastInsertId(), $introduction->uid);
+                       }
+               } catch (\Exception $exception) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot insert/update the Introduction %d for user %d', $introduction->id, $introduction->uid), $exception);
+               }
+       }
+}
index 4ac59d14cb94bb38599f7f07ffc3fefd78692119..67960fabda41edaaaeeaa2125741dd6ff2fcfa09 100644 (file)
@@ -27,7 +27,7 @@ use Friendica\DI;
 use Friendica\Model\Photo;
 use Friendica\Model\Profile;
 use Friendica\Object\Image;
-use Friendica\Security\PermissionSet\Depository\PermissionSet;
+use Friendica\Security\PermissionSet\Repository\PermissionSet;
 use Friendica\Util\Strings;
 use Friendica\Worker\Delivery;
 
index eea219bd226d5a459d2d7584008bc709632a7c41..7e5f309b33b2f368c0c6f81f6972be55bb5ee5e9 100644 (file)
@@ -427,11 +427,11 @@ abstract class DI
        //
 
        /**
-        * @return Contact\FriendSuggest\Depository\FriendSuggest;
+        * @return Contact\FriendSuggest\Repository\FriendSuggest;
         */
        public static function fsuggest()
        {
-               return self::$dice->create(Contact\FriendSuggest\Depository\FriendSuggest::class);
+               return self::$dice->create(Contact\FriendSuggest\Repository\FriendSuggest::class);
        }
 
        /**
@@ -443,11 +443,11 @@ abstract class DI
        }
 
        /**
-        * @return Contact\Introduction\Depository\Introduction
+        * @return Contact\Introduction\Repository\Introduction
         */
        public static function intro()
        {
-               return self::$dice->create(Contact\Introduction\Depository\Introduction::class);
+               return self::$dice->create(Contact\Introduction\Repository\Introduction::class);
        }
 
        /**
@@ -458,9 +458,9 @@ abstract class DI
                return self::$dice->create(Contact\Introduction\Factory\Introduction::class);
        }
 
-       public static function permissionSet(): Security\PermissionSet\Depository\PermissionSet
+       public static function permissionSet(): Security\PermissionSet\Repository\PermissionSet
        {
-               return self::$dice->create(Security\PermissionSet\Depository\PermissionSet::class);
+               return self::$dice->create(Security\PermissionSet\Repository\PermissionSet::class);
        }
 
        public static function permissionSetFactory(): Security\PermissionSet\Factory\PermissionSet
@@ -468,9 +468,9 @@ abstract class DI
                return self::$dice->create(Security\PermissionSet\Factory\PermissionSet::class);
        }
 
-       public static function profileField(): Profile\ProfileField\Depository\ProfileField
+       public static function profileField(): Profile\ProfileField\Repository\ProfileField
        {
-               return self::$dice->create(Profile\ProfileField\Depository\ProfileField::class);
+               return self::$dice->create(Profile\ProfileField\Repository\ProfileField::class);
        }
 
        public static function profileFieldFactory(): Profile\ProfileField\Factory\ProfileField
@@ -478,9 +478,9 @@ abstract class DI
                return self::$dice->create(Profile\ProfileField\Factory\ProfileField::class);
        }
 
-       public static function notification(): Navigation\Notifications\Depository\Notification
+       public static function notification(): Navigation\Notifications\Repository\Notification
        {
-               return self::$dice->create(Navigation\Notifications\Depository\Notification::class);
+               return self::$dice->create(Navigation\Notifications\Repository\Notification::class);
        }
 
        public static function notificationFactory(): Navigation\Notifications\Factory\Notification
@@ -488,9 +488,9 @@ abstract class DI
                return self::$dice->create(Navigation\Notifications\Factory\Notification::class);
        }
 
-       public static function notify(): Navigation\Notifications\Depository\Notify
+       public static function notify(): Navigation\Notifications\Repository\Notify
        {
-               return self::$dice->create(Navigation\Notifications\Depository\Notify::class);
+               return self::$dice->create(Navigation\Notifications\Repository\Notify::class);
        }
 
        public static function notifyFactory(): Navigation\Notifications\Factory\Notify
index a987e6874c1ab83a6f8251268da019a6196ececa..7b7eba0ed5b539547e254a13ea6f113a109baebd 100644 (file)
@@ -27,7 +27,7 @@ use Friendica\Collection\Api\Mastodon\Fields;
 use Friendica\Model\APContact;
 use Friendica\Model\Contact;
 use Friendica\Network\HTTPException;
-use Friendica\Profile\ProfileField\Depository\ProfileField as ProfileFieldDepository;
+use Friendica\Profile\ProfileField\Repository\ProfileField as ProfileFieldRepository;
 use ImagickException;
 use Psr\Log\LoggerInterface;
 
@@ -35,17 +35,17 @@ class Account extends BaseFactory
 {
        /** @var BaseURL */
        private $baseUrl;
-       /** @var ProfileFieldDepository */
-       private $profileFieldDepo;
+       /** @var ProfileFieldRepository */
+       private $profileFieldRepo;
        /** @var Field */
        private $mstdnFieldFactory;
 
-       public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileFieldDepository $profileFieldDepo, Field $mstdnFieldFactory)
+       public function __construct(LoggerInterface $logger, BaseURL $baseURL, ProfileFieldRepository $profileFieldRepo, Field $mstdnFieldFactory)
        {
                parent::__construct($logger);
 
                $this->baseUrl           = $baseURL;
-               $this->profileFieldDepo  = $profileFieldDepo;
+               $this->profileFieldRepo  = $profileFieldRepo;
                $this->mstdnFieldFactory = $mstdnFieldFactory;
        }
 
@@ -76,7 +76,7 @@ class Account extends BaseFactory
 
                $self_contact = Contact::selectFirst(['uid'], ['nurl' => $publicContact['nurl'], 'self' => true]);
                if (!empty($self_contact['uid'])) {
-                       $profileFields = $this->profileFieldDepo->selectPublicFieldsByUserId($self_contact['uid']);
+                       $profileFields = $this->profileFieldRepo->selectPublicFieldsByUserId($self_contact['uid']);
                        $fields        = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
                } else {
                        $fields = new Fields();
@@ -94,7 +94,7 @@ class Account extends BaseFactory
        {
                $publicContact = Contact::selectFirst([], ['uid' => $userId, 'self' => true]);
 
-               $profileFields = $this->profileFieldDepo->selectPublicFieldsByUserId($userId);
+               $profileFields = $this->profileFieldRepo->selectPublicFieldsByUserId($userId);
                $fields        = $this->mstdnFieldFactory->createFromProfileFields($profileFields);
 
                $apContact = APContact::getByURL($publicContact['url'], false);
index 8102ac4bcc63f9454c691dfe7eadef21fcb33fd3..4167e6c61f8fcde1ea99f9191c4f889e8e63dd40 100644 (file)
@@ -28,7 +28,7 @@ use Friendica\Model\Contact;
 use Friendica\Model\Profile;
 use Friendica\Module\BaseApi;
 use Friendica\Network\HTTPException;
-use Friendica\Security\PermissionSet\Depository\PermissionSet;
+use Friendica\Security\PermissionSet\Repository\PermissionSet;
 
 /**
  * API endpoint: /api/friendica/profile/show
diff --git a/src/Navigation/Notifications/Depository/Notification.php b/src/Navigation/Notifications/Depository/Notification.php
deleted file mode 100644 (file)
index a93bce6..0000000
+++ /dev/null
@@ -1,141 +0,0 @@
-<?php
-
-namespace Friendica\Navigation\Notifications\Depository;
-
-use Exception;
-use Friendica\BaseCollection;
-use Friendica\BaseDepository;
-use Friendica\Database\Database;
-use Friendica\Database\DBA;
-use Friendica\Model\Verb;
-use Friendica\Navigation\Notifications\Collection;
-use Friendica\Navigation\Notifications\Entity;
-use Friendica\Navigation\Notifications\Factory;
-use Friendica\Network\HTTPException\NotFoundException;
-use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
-
-class Notification extends BaseDepository
-{
-       /** @var Factory\Notification  */
-       protected $factory;
-
-       protected static $table_name = 'notification';
-
-       public function __construct(Database $database, LoggerInterface $logger, Factory\Notification $factory = null)
-       {
-               parent::__construct($database, $logger, $factory ?? new Factory\Notification($logger));
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return Entity\Notification
-        * @throws NotFoundException
-        */
-       private function selectOne(array $condition, array $params = []): Entity\Notification
-       {
-               return parent::_selectOne($condition, $params);
-       }
-
-       private function select(array $condition, array $params = []): Collection\Notifications
-       {
-               return new Collection\Notifications(parent::_select($condition, $params)->getArrayCopy());
-       }
-
-       public function countForUser($uid, array $condition, array $params = []): int
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->count($condition, $params);
-       }
-
-       public function existsForUser($uid, array $condition): bool
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->exists($condition);
-       }
-
-       /**
-        * @param int $id
-        * @return Entity\Notification
-        * @throws NotFoundException
-        */
-       public function selectOneById(int $id): Entity\Notification
-       {
-               return $this->selectOne(['id' => $id]);
-       }
-
-       public function selectOneForUser(int $uid, array $condition, array $params = []): Entity\Notification
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->selectOne($condition, $params);
-       }
-
-       public function selectForUser(int $uid, array $condition = [], array $params = []): Collection\Notifications
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->select($condition, $params);
-       }
-
-       public function selectAllForUser(int $uid): Collection\Notifications
-       {
-               return $this->selectForUser($uid);
-       }
-
-       /**
-        * @param array    $condition
-        * @param array    $params
-        * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
-        * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
-        * @param int      $limit
-        * @return BaseCollection
-        * @throws Exception
-        * @see _selectByBoundaries
-        */
-       public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
-       {
-               $BaseCollection = parent::_selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
-
-               return new Collection\Notifications($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount());
-       }
-
-       public function setAllSeenForUser(int $uid, array $condition = []): bool
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->db->update(self::$table_name, ['seen' => true], $condition);
-       }
-
-       /**
-        * @param Entity\Notification $Notification
-        * @return Entity\Notification
-        * @throws Exception
-        */
-       public function save(Entity\Notification $Notification): Entity\Notification
-       {
-               $fields = [
-                       'uid'           => $Notification->uid,
-                       'vid'           => Verb::getID($Notification->verb),
-                       'type'          => $Notification->type,
-                       'actor-id'      => $Notification->actorId,
-                       'target-uri-id' => $Notification->targetUriId,
-                       'parent-uri-id' => $Notification->parentUriId,
-                       'seen'          => $Notification->seen,
-               ];
-
-               if ($Notification->id) {
-                       $this->db->update(self::$table_name, $fields, ['id' => $Notification->id]);
-               } else {
-                       $fields['created'] = DateTimeFormat::utcNow();
-                       $this->db->insert(self::$table_name, $fields);
-
-                       $Notification = $this->selectOneById($this->db->lastInsertId());
-               }
-
-               return $Notification;
-       }
-}
diff --git a/src/Navigation/Notifications/Depository/Notify.php b/src/Navigation/Notifications/Depository/Notify.php
deleted file mode 100644 (file)
index a380166..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-<?php
-
-namespace Friendica\Navigation\Notifications\Depository;
-
-use Friendica\App\BaseURL;
-use Friendica\BaseDepository;
-use Friendica\Content\Text\Plaintext;
-use Friendica\Core\Config\IConfig;
-use Friendica\Core\Hook;
-use Friendica\Core\L10n;
-use Friendica\Core\System;
-use Friendica\Database\Database;
-use Friendica\Database\DBA;
-use Friendica\Model;
-use Friendica\Navigation\Notifications\Collection;
-use Friendica\Navigation\Notifications\Entity;
-use Friendica\Navigation\Notifications\Exception;
-use Friendica\Navigation\Notifications\Factory;
-use Friendica\Network\HTTPException;
-use Friendica\Protocol\Activity;
-use Friendica\Util\DateTimeFormat;
-use Friendica\Util\Emailer;
-use Psr\Log\LoggerInterface;
-
-class Notify extends BaseDepository
-{
-       /** @var Factory\Notify  */
-       protected $factory;
-
-       /** @var L10n  */
-       protected $l10n;
-
-       /** @var BaseURL  */
-       protected $baseUrl;
-
-       /** @var IConfig */
-       protected $config;
-
-       /** @var Emailer */
-       protected $emailer;
-
-       /** @var Factory\Notification */
-       protected $notification;
-
-       protected static $table_name = 'notify';
-
-       public function __construct(Database $database, LoggerInterface $logger, L10n $l10n, BaseURL $baseUrl, IConfig $config, Emailer $emailer, Factory\Notification $notification, Factory\Notify $factory = null)
-       {
-               $this->l10n         = $l10n;
-               $this->baseUrl      = $baseUrl;
-               $this->config       = $config;
-               $this->emailer      = $emailer;
-               $this->notification = $notification;
-
-               parent::__construct($database, $logger, $factory ?? new Factory\Notify($logger));
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return Entity\Notify
-        * @throws HTTPException\NotFoundException
-        */
-       private function selectOne(array $condition, array $params = []): Entity\Notify
-       {
-               return parent::_selectOne($condition, $params);
-       }
-
-       private function select(array $condition, array $params = []): Collection\Notifies
-       {
-               return new Collection\Notifies(parent::_select($condition, $params)->getArrayCopy());
-       }
-
-       public function countForUser($uid, array $condition, array $params = []): int
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->count($condition, $params);
-       }
-
-       public function existsForUser($uid, array $condition): bool
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->exists($condition);
-       }
-
-       /**
-        * @param int $id
-        * @return Entity\Notify
-        * @throws HTTPException\NotFoundException
-        */
-       public function selectOneById(int $id): Entity\Notify
-       {
-               return $this->selectOne(['id' => $id]);
-       }
-
-       public function selectForUser(int $uid, array $condition, array $params): Collection\Notifies
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->select($condition, $params);
-       }
-
-       /**
-        * Returns notifications for the user, unread first, ordered in descending chronological order.
-        *
-        * @param int $uid
-        * @param int $limit
-        * @return Collection\Notifies
-        */
-       public function selectAllForUser(int $uid, int $limit): Collection\Notifies
-       {
-               return $this->selectForUser($uid, [], ['order' => ['seen' => 'ASC', 'date' => 'DESC'], 'limit' => $limit]);
-       }
-
-       public function setAllSeenForUser(int $uid, array $condition = []): bool
-       {
-               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
-
-               return $this->db->update(self::$table_name, ['seen' => true], $condition);
-       }
-
-       /**
-        * @param Entity\Notify $Notify
-        * @return Entity\Notify
-        * @throws HTTPException\NotFoundException
-        * @throws HTTPException\InternalServerErrorException
-        * @throws Exception\NotificationCreationInterceptedException
-        */
-       public function save(Entity\Notify $Notify): Entity\Notify
-       {
-               $fields = [
-                       'type'          => $Notify->type,
-                       'name'          => $Notify->name,
-                       'url'           => $Notify->url,
-                       'photo'         => $Notify->photo,
-                       'msg'           => $Notify->msg,
-                       'uid'           => $Notify->uid,
-                       'link'          => $Notify->link,
-                       'iid'           => $Notify->itemId,
-                       'parent'        => $Notify->parent,
-                       'seen'          => $Notify->seen,
-                       'verb'          => $Notify->verb,
-                       'otype'         => $Notify->otype,
-                       'name_cache'    => $Notify->name_cache,
-                       'msg_cache'     => $Notify->msg_cache,
-                       'uri-id'        => $Notify->uriId,
-                       'parent-uri-id' => $Notify->parentUriId,
-               ];
-
-               if ($Notify->id) {
-                       $this->db->update(self::$table_name, $fields, ['id' => $Notify->id]);
-               } else {
-                       $fields['date'] = DateTimeFormat::utcNow();
-                       Hook::callAll('enotify_store', $fields);
-
-                       $this->db->insert(self::$table_name, $fields);
-
-                       $Notify = $this->selectOneById($this->db->lastInsertId());
-               }
-
-               return $Notify;
-       }
-
-       public function setAllSeenForRelatedNotify(Entity\Notify $Notify): bool
-       {
-               $condition = [
-                       '(`link` = ? OR (`parent` != 0 AND `parent` = ? AND `otype` = ?)) AND `uid` = ?',
-                       $Notify->link,
-                       $Notify->parent,
-                       $Notify->otype,
-                       $Notify->uid
-               ];
-               return $this->db->update(self::$table_name, ['seen' => true], $condition);
-       }
-
-       /**
-        * Creates a notification entry and possibly sends a mail
-        *
-        * @param array $params Array with the elements:
-        *                      type, event, otype, activity, verb, uid, cid, item, link,
-        *                      source_name, source_mail, source_nick, source_link, source_photo,
-        *                      show_in_notification_page
-        *
-        * @return bool
-        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
-        */
-       function createFromArray($params)
-       {
-               /** @var string the common prefix of a notification subject */
-               $subjectPrefix = $this->l10n->t('[Friendica:Notify]');
-
-               // Temporary logging for finding the origin
-               if (!isset($params['uid'])) {
-                       $this->logger->notice('Missing parameters "uid".', ['params' => $params, 'callstack' => System::callstack()]);
-               }
-
-               // Ensure that the important fields are set at any time
-               $fields = ['nickname', 'page-flags', 'notify-flags', 'language', 'username', 'email'];
-               $user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
-
-               if (!DBA::isResult($user)) {
-                       $this->logger->error('Unknown user', ['uid' =>  $params['uid']]);
-                       return false;
-               }
-
-               // There is no need to create notifications for forum accounts
-               if (in_array($user['page-flags'], [Model\User::PAGE_FLAGS_COMMUNITY, Model\User::PAGE_FLAGS_PRVGROUP])) {
-                       return false;
-               }
-
-               $params['notify_flags'] = $user['notify-flags'];
-               $params['language']     = $user['language'];
-               $params['to_name']      = $user['username'];
-               $params['to_email']     = $user['email'];
-
-               // from here on everything is in the recipients language
-               $l10n = $this->l10n->withLang($params['language']);
-
-               if (!empty($params['cid'])) {
-                       $contact = Model\Contact::getById($params['cid'], ['url', 'name', 'photo']);
-                       if (DBA::isResult($contact)) {
-                               $params['source_link'] = $contact['url'];
-                               $params['source_name'] = $contact['name'];
-                               $params['source_photo'] = $contact['photo'];
-                       }
-               }
-
-               $siteurl = $this->baseUrl->get(true);
-               $sitename = $this->config->get('config', 'sitename');
-
-               // with $params['show_in_notification_page'] == false, the notification isn't inserted into
-               // the database, and an email is sent if applicable.
-               // default, if not specified: true
-               $show_in_notification_page = isset($params['show_in_notification_page']) ? $params['show_in_notification_page'] : true;
-
-               $title = $params['item']['title'] ?? '';
-               $body = $params['item']['body'] ?? '';
-
-               $parent_id = $params['item']['parent'] ?? 0;
-               $parent_uri_id = $params['item']['parent-uri-id'] ?? 0;
-
-               $epreamble = '';
-               $preamble  = '';
-               $subject   = '';
-               $sitelink  = '';
-               $tsitelink = '';
-               $hsitelink = '';
-               $itemlink  = '';
-
-               switch ($params['type']) {
-                       case Model\Notification\Type::MAIL:
-                               $itemlink = $params['link'];
-
-                               $subject = $l10n->t('%s New mail received at %s', $subjectPrefix, $sitename);
-
-                               $preamble = $l10n->t('%1$s sent you a new private message at %2$s.', $params['source_name'], $sitename);
-                               $epreamble = $l10n->t('%1$s sent you %2$s.', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', '[url=' . $itemlink . ']' . $l10n->t('a private message').'[/url]');
-
-                               $sitelink = $l10n->t('Please visit %s to view and/or reply to your private messages.');
-                               $tsitelink = sprintf($sitelink, $itemlink);
-                               $hsitelink = sprintf($sitelink, '<a href="' . $itemlink . '">' . $sitename . '</a>');
-
-                               // Mail notifications aren't using the "notify" table entry
-                               $show_in_notification_page = false;
-                               break;
-
-                       case Model\Notification\Type::COMMENT:
-                               if (Model\Post\ThreadUser::getIgnored($parent_uri_id, $params['uid'])) {
-                                       $this->logger->info('Thread is ignored', ['parent' => $parent_id, 'parent-uri-id' => $parent_uri_id]);
-                                       return false;
-                               }
-
-                               $item = Model\Post::selectFirstForUser($params['uid'], Model\Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
-                               if (empty($item)) {
-                                       return false;
-                               }
-
-                               $item_post_type = Model\Item::postType($item, $l10n);
-
-                               $content = Plaintext::getPost($item, 70);
-                               if (!empty($content['text'])) {
-                                       $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
-                               } else {
-                                       $title = '';
-                               }
-
-                               // First go for the general message
-
-                               // "George Bull's post"
-                               $message = $l10n->t('%1$s commented on %2$s\'s %3$s %4$s');
-                               $dest_str = sprintf($message, $params['source_name'], $item['author-name'], $item_post_type, $title);
-
-                               // "your post"
-                               if ($item['wall']) {
-                                       $message = $l10n->t('%1$s commented on your %2$s %3$s');
-                                       $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
-                               // "their post"
-                               } elseif ($item['author-link'] == $params['source_link']) {
-                                       $message = $l10n->t('%1$s commented on their %2$s %3$s');
-                                       $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
-                               }
-
-                               $subject = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $parent_id, $params['source_name']);
-
-                               $preamble = $l10n->t('%s commented on an item/conversation you have been following.', $params['source_name']);
-
-                               $epreamble = $dest_str;
-
-                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
-                               $tsitelink = sprintf($sitelink, $siteurl);
-                               $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
-                               $itemlink =  $params['link'];
-                               break;
-
-                       case Model\Notification\Type::WALL:
-                               $subject = $l10n->t('%s %s posted to your profile wall', $subjectPrefix, $params['source_name']);
-
-                               $preamble = $l10n->t('%1$s posted to your profile wall at %2$s', $params['source_name'], $sitename);
-                               $epreamble = $l10n->t('%1$s posted to [url=%2$s]your wall[/url]',
-                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
-                                       $params['link']
-                               );
-
-                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
-                               $tsitelink = sprintf($sitelink, $siteurl);
-                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-                               $itemlink =  $params['link'];
-                               break;
-
-                       case Model\Notification\Type::POKE:
-                               $subject = $l10n->t('%1$s %2$s poked you', $subjectPrefix, $params['source_name']);
-
-                               $preamble = $l10n->t('%1$s poked you at %2$s', $params['source_name'], $sitename);
-                               $epreamble = $l10n->t('%1$s [url=%2$s]poked you[/url].',
-                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
-                                       $params['link']
-                               );
-
-                               $subject = str_replace('poked', $l10n->t($params['activity']), $subject);
-                               $preamble = str_replace('poked', $l10n->t($params['activity']), $preamble);
-                               $epreamble = str_replace('poked', $l10n->t($params['activity']), $epreamble);
-
-                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
-                               $tsitelink = sprintf($sitelink, $siteurl);
-                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-                               $itemlink =  $params['link'];
-                               break;
-
-                       case Model\Notification\Type::INTRO:
-                               $itemlink = $params['link'];
-                               $subject = $l10n->t('%s Introduction received', $subjectPrefix);
-
-                               $preamble = $l10n->t('You\'ve received an introduction from \'%1$s\' at %2$s', $params['source_name'], $sitename);
-                               $epreamble = $l10n->t('You\'ve received [url=%1$s]an introduction[/url] from %2$s.',
-                                       $itemlink,
-                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
-                               );
-
-                               $body = $l10n->t('You may visit their profile at %s', $params['source_link']);
-
-                               $sitelink = $l10n->t('Please visit %s to approve or reject the introduction.');
-                               $tsitelink = sprintf($sitelink, $siteurl);
-                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-
-                               switch ($params['verb']) {
-                                       case Activity::FRIEND:
-                                               // someone started to share with user (mostly OStatus)
-                                               $subject = $l10n->t('%s A new person is sharing with you', $subjectPrefix);
-
-                                               $preamble = $l10n->t('%1$s is sharing with you at %2$s', $params['source_name'], $sitename);
-                                               $epreamble = $l10n->t('%1$s is sharing with you at %2$s',
-                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
-                                                       $sitename
-                                               );
-                                               break;
-                                       case Activity::FOLLOW:
-                                               // someone started to follow the user (mostly OStatus)
-                                               $subject = $l10n->t('%s You have a new follower', $subjectPrefix);
-
-                                               $preamble = $l10n->t('You have a new follower at %2$s : %1$s', $params['source_name'], $sitename);
-                                               $epreamble = $l10n->t('You have a new follower at %2$s : %1$s',
-                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
-                                                       $sitename
-                                               );
-                                               break;
-                                       default:
-                                               // ACTIVITY_REQ_FRIEND is default activity for notifications
-                                               break;
-                               }
-                               break;
-
-                       case Model\Notification\Type::SUGGEST:
-                               $itemlink =  $params['link'];
-                               $subject = $l10n->t('%s Friend suggestion received', $subjectPrefix);
-
-                               $preamble = $l10n->t('You\'ve received a friend suggestion from \'%1$s\' at %2$s', $params['source_name'], $sitename);
-                               $epreamble = $l10n->t('You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.',
-                                       $itemlink,
-                                       '[url='.$params['item']['url'].']'.$params['item']['name'].'[/url]',
-                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
-                               );
-
-                               $body = $l10n->t('Name:').' '.$params['item']['name']."\n";
-                               $body .= $l10n->t('Photo:').' '.$params['item']['photo']."\n";
-                               $body .= $l10n->t('You may visit their profile at %s', $params['item']['url']);
-
-                               $sitelink = $l10n->t('Please visit %s to approve or reject the suggestion.');
-                               $tsitelink = sprintf($sitelink, $siteurl);
-                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-                               break;
-
-                       case Model\Notification\Type::CONFIRM:
-                               if ($params['verb'] == Activity::FRIEND) { // mutual connection
-                                       $itemlink =  $params['link'];
-                                       $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
-
-                                       $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
-                                       $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
-                                               $itemlink,
-                                               '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
-                                       );
-
-                                       $body =  $l10n->t('You are now mutual friends and may exchange status updates, photos, and email without restriction.');
-
-                                       $sitelink = $l10n->t('Please visit %s if you wish to make any changes to this relationship.');
-                                       $tsitelink = sprintf($sitelink, $siteurl);
-                                       $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-                               } else { // ACTIVITY_FOLLOW
-                                       $itemlink =  $params['link'];
-                                       $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
-
-                                       $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
-                                       $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
-                                               $itemlink,
-                                               '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
-                                       );
-
-                                       $body =  $l10n->t('\'%1$s\' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically.', $params['source_name']);
-                                       $body .= "\n\n";
-                                       $body .= $l10n->t('\'%1$s\' may choose to extend this into a two-way or more permissive relationship in the future.', $params['source_name']);
-
-                                       $sitelink = $l10n->t('Please visit %s  if you wish to make any changes to this relationship.');
-                                       $tsitelink = sprintf($sitelink, $siteurl);
-                                       $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
-                               }
-                               break;
-
-                       case Model\Notification\Type::SYSTEM:
-                               switch($params['event']) {
-                                       case "SYSTEM_REGISTER_REQUEST":
-                                               $itemlink =  $params['link'];
-                                               $subject = $l10n->t('[Friendica System Notify]') . ' ' . $l10n->t('registration request');
-
-                                               $preamble = $l10n->t('You\'ve received a registration request from \'%1$s\' at %2$s', $params['source_name'], $sitename);
-                                               $epreamble = $l10n->t('You\'ve received a [url=%1$s]registration request[/url] from %2$s.',
-                                                       $itemlink,
-                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
-                                               );
-
-                                               $body = $l10n->t("Full Name:    %s\nSite Location:      %s\nLogin Name: %s (%s)",
-                                                       $params['source_name'],
-                                                       $siteurl, $params['source_mail'],
-                                                       $params['source_nick']
-                                               );
-
-                                               $sitelink = $l10n->t('Please visit %s to approve or reject the request.');
-                                               $tsitelink = sprintf($sitelink, $params['link']);
-                                               $hsitelink = sprintf($sitelink, '<a href="'.$params['link'].'">'.$sitename.'</a><br><br>');
-                                               break;
-                                       case "SYSTEM_DB_UPDATE_FAIL":
-                                               break;
-                               }
-                               break;
-
-                       default:
-                               $this->logger->notice('Unhandled type', ['type' => $params['type']]);
-                               return false;
-               }
-
-               return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page);
-       }
-
-       private function storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page)
-       {
-               $item_id = $params['item']['id'] ?? 0;
-               $uri_id = $params['item']['uri-id'] ?? null;
-               $parent_id = $params['item']['parent'] ?? 0;
-               $parent_uri_id = $params['item']['parent-uri-id'] ?? null;
-
-               // Ensure that the important fields are set at any time
-               $fields = ['nickname'];
-               $user = Model\User::getById($params['uid'], $fields);
-
-               $sitename = $this->config->get('config', 'sitename');
-
-               $nickname = $user['nickname'];
-
-               $hostname = $this->baseUrl->getHostname();
-               if (strpos($hostname, ':')) {
-                       $hostname = substr($hostname, 0, strpos($hostname, ':'));
-               }
-
-               // Creates a new email builder for the notification email
-               $emailBuilder = $this->emailer->newNotifyMail();
-
-               $emailBuilder->setHeader('X-Friendica-Account', '<' . $nickname . '@' . $hostname . '>');
-
-               $subject .= " (".$nickname."@".$hostname.")";
-
-               $h = [
-                       'params'    => $params,
-                       'subject'   => $subject,
-                       'preamble'  => $preamble,
-                       'epreamble' => $epreamble,
-                       'body'      => $body,
-                       'sitelink'  => $sitelink,
-                       'tsitelink' => $tsitelink,
-                       'hsitelink' => $hsitelink,
-                       'itemlink'  => $itemlink
-               ];
-
-               Hook::callAll('enotify', $h);
-
-               $subject   = $h['subject'];
-
-               $preamble  = $h['preamble'];
-               $epreamble = $h['epreamble'];
-
-               $body      = $h['body'];
-
-               $tsitelink = $h['tsitelink'];
-               $hsitelink = $h['hsitelink'];
-               $itemlink  = $h['itemlink'];
-
-               $notify_id = 0;
-
-               if ($show_in_notification_page) {
-                       $Notify = $this->factory->createFromParams($params, $itemlink, $item_id, $uri_id, $parent_id, $parent_uri_id);
-                       try {
-                               $Notify = $this->save($Notify);
-                       } catch (Exception\NotificationCreationInterceptedException $e) {
-                               // Notification insertion can be intercepted by an addon registering the 'enotify_store' hook
-                               return false;
-                       }
-
-                       $Notify->updateMsgFromPreamble($epreamble);
-                       $Notify = $this->save($Notify);
-
-                       $itemlink  = $this->baseUrl->get() . '/notification/' . $Notify->id;
-                       $notify_id = $Notify->id;
-               }
-
-               // send email notification if notification preferences permit
-               if ((intval($params['notify_flags']) & intval($params['type']))
-                       || $params['type'] == Model\Notification\Type::SYSTEM) {
-
-                       $this->logger->notice('sending notification email');
-
-                       if (isset($params['parent']) && (intval($params['parent']) != 0)) {
-                               $parent = Model\Post::selectFirst(['guid'], ['id' => $params['parent']]);
-                               $message_id = "<" . $parent['guid'] . "@" . gethostname() . ">";
-
-                               // Is this the first email notification for this parent item and user?
-                               if (!DBA::exists('notify-threads', ['master-parent-uri-id' => $parent_uri_id, 'receiver-uid' => $params['uid']])) {
-                                       $this->logger->info("notify_id:" . intval($notify_id) . ", parent: " . intval($params['parent']) . "uid: " . intval($params['uid']));
-
-                                       $fields = ['notify-id' => $notify_id, 'master-parent-uri-id' => $parent_uri_id,
-                                               'receiver-uid' => $params['uid'], 'parent-item' => 0];
-                                       DBA::insert('notify-threads', $fields);
-
-                                       $emailBuilder->setHeader('Message-ID', $message_id);
-                                       $log_msg = "include/enotify: No previous notification found for this parent:\n" .
-                                               "  parent: ${params['parent']}\n" . "  uid   : ${params['uid']}\n";
-                                       $this->logger->info($log_msg);
-                               } else {
-                                       // If not, just "follow" the thread.
-                                       $emailBuilder->setHeader('References', $message_id);
-                                       $emailBuilder->setHeader('In-Reply-To', $message_id);
-                                       $this->logger->info("There's already a notification for this parent.");
-                               }
-                       }
-
-                       $datarray = [
-                               'preamble'     => $preamble,
-                               'type'         => $params['type'],
-                               'parent'       => $parent_id,
-                               'source_name'  => $params['source_name'] ?? null,
-                               'source_link'  => $params['source_link'] ?? null,
-                               'source_photo' => $params['source_photo'] ?? null,
-                               'uid'          => $params['uid'],
-                               'hsitelink'    => $hsitelink,
-                               'tsitelink'    => $tsitelink,
-                               'itemlink'     => $itemlink,
-                               'title'        => $title,
-                               'body'         => $body,
-                               'subject'      => $subject,
-                               'headers'      => $emailBuilder->getHeaders(),
-                       ];
-
-                       Hook::callAll('enotify_mail', $datarray);
-
-                       $emailBuilder
-                               ->withHeaders($datarray['headers'])
-                               ->withRecipient($params['to_email'])
-                               ->forUser([
-                                       'uid' => $datarray['uid'],
-                                       'language' => $params['language'],
-                               ])
-                               ->withNotification($datarray['subject'], $datarray['preamble'], $datarray['title'], $datarray['body'])
-                               ->withSiteLink($datarray['tsitelink'], $datarray['hsitelink'])
-                               ->withItemLink($datarray['itemlink']);
-
-                       // If a photo is present, add it to the email
-                       if (!empty($datarray['source_photo'])) {
-                               $emailBuilder->withPhoto(
-                                       $datarray['source_photo'],
-                                       $datarray['source_link'] ?? $sitelink,
-                                       $datarray['source_name'] ?? $sitename);
-                       }
-
-                       $email = $emailBuilder->build();
-
-                       // use the Emailer class to send the message
-                       return $this->emailer->send($email);
-               }
-
-               return false;
-       }
-
-       public function createFromNotification(Entity\Notification $Notification)
-       {
-               $this->logger->info('Start', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
-
-               if ($Notification->type === Model\Post\UserNotification::TYPE_NONE) {
-                       $this->logger->info('Not an item based notification, quitting', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
-                       return false;
-               }
-
-               $params = [];
-               $params['verb']  = $Notification->verb;
-               $params['uid']   = $Notification->uid;
-               $params['otype'] = Model\Notification\ObjectType::ITEM;
-
-               $user = Model\User::getById($Notification->uid);
-
-               $params['notify_flags'] = $user['notify-flags'];
-               $params['language']     = $user['language'];
-               $params['to_name']      = $user['username'];
-               $params['to_email']     = $user['email'];
-
-               // from here on everything is in the recipients language
-               $l10n = $this->l10n->withLang($user['language']);
-
-               $contact = Model\Contact::getById($Notification->actorId, ['url', 'name', 'photo']);
-               if (DBA::isResult($contact)) {
-                       $params['source_link']  = $contact['url'];
-                       $params['source_name']  = $contact['name'];
-                       $params['source_photo'] = $contact['photo'];
-               }
-
-               $item = Model\Post::selectFirstForUser($Notification->uid, Model\Item::ITEM_FIELDLIST,
-                       ['uid' => [0, $Notification->uid], 'uri-id' => $Notification->targetUriId, 'deleted' => false],
-                       ['order' => ['uid' => true]]);
-               if (empty($item)) {
-                       $this->logger->info('Item not found', ['uri-id' => $Notification->targetUriId, 'type' => $Notification->type]);
-                       return false;
-               }
-
-               $params['item']   = $item;
-               $params['parent'] = $item['parent'];
-               $params['link']   = $this->baseUrl->get() . '/display/' . urlencode($item['guid']);
-
-               $subjectPrefix = $l10n->t('[Friendica:Notify]');
-
-               if (Model\Post\ThreadUser::getIgnored($Notification->parentUriId, $Notification->uid)) {
-                       $this->logger->info('Thread is ignored', ['parent-uri-id' => $Notification->parentUriId, 'type' => $Notification->type]);
-                       return false;
-               }
-
-               // Check to see if there was already a tag notify or comment notify for this post.
-               // If so don't create a second notification
-               $condition = ['type' => [Model\Notification\Type::TAG_SELF, Model\Notification\Type::COMMENT, Model\Notification\Type::SHARE],
-                       'link' => $params['link'], 'verb' => Activity::POST];
-               if ($this->existsForUser($Notification->uid, $condition)) {
-                       $this->logger->info('Duplicate found, quitting', $condition + ['uid' => $Notification->uid]);
-                       return false;
-               }
-
-               $content = Plaintext::getPost($item, 70);
-               if (!empty($content['text'])) {
-                       $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
-               } else {
-                       $title = $item['title'];
-               }
-
-               // Some mail software relies on subject field for threading.
-               // So, we cannot have different subjects for notifications of the same thread.
-               // Before this we have the name of the replier on the subject rendering
-               // different subjects for messages on the same thread.
-               if ($Notification->type === Model\Post\UserNotification::TYPE_EXPLICIT_TAGGED) {
-                       $params['type'] = Model\Notification\Type::TAG_SELF;
-                       $subject        = $l10n->t('%s %s tagged you', $subjectPrefix, $contact['name']);
-               } elseif ($Notification->type === Model\Post\UserNotification::TYPE_SHARED) {
-                       $params['type'] = Model\Notification\Type::SHARE;
-                       $subject        = $l10n->t('%s %s shared a new post', $subjectPrefix, $contact['name']);
-               } else {
-                       $params['type'] = Model\Notification\Type::COMMENT;
-                       $subject        = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $item['parent'], $contact['name']);
-               }
-
-               $msg = $this->notification->getMessageFromNotification($Notification, $this->baseUrl, $l10n);
-               if (empty($msg)) {
-                       $this->logger->info('No notification message, quitting', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
-                       return false;
-               }
-
-               $preamble  = $msg['plain'];
-               $epreamble = $msg['rich'];
-
-               $sitename = $this->config->get('config', 'sitename');
-               $siteurl  = $this->baseUrl->get(true);
-
-               $sitelink  = $l10n->t('Please visit %s to view and/or reply to the conversation.');
-               $tsitelink = sprintf($sitelink, $siteurl);
-               $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
-               $itemlink  = $params['link'];
-
-               $this->logger->info('Perform notification', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
-
-               return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $item['body'], $itemlink, true);
-       }
-}
index 4e8c1b846228851494f4c85e837b8ace1bfbe136..df0a779155ff0ca2fa1bf281d83e24ef985be183 100644 (file)
@@ -32,7 +32,7 @@ use Friendica\Model\Contact;
 use Friendica\Model\Post;
 use Friendica\Module\BaseNotifications;
 use Friendica\Navigation\Notifications\Collection\FormattedNotifications;
-use Friendica\Navigation\Notifications\Depository;
+use Friendica\Navigation\Notifications\Repository;
 use Friendica\Navigation\Notifications\ValueObject;
 use Friendica\Network\HTTPException\InternalServerErrorException;
 use Friendica\Protocol\Activity;
@@ -54,14 +54,14 @@ class FormattedNotification extends BaseFactory
 {
        /** @var Database */
        private $dba;
-       /** @var Depository\Notify */
+       /** @var Repository\Notify */
        private $notify;
        /** @var BaseURL */
        private $baseUrl;
        /** @var L10n */
        private $l10n;
 
-       public function __construct(LoggerInterface $logger, Database $dba, Depository\Notify $notify, BaseURL $baseUrl, L10n $l10n)
+       public function __construct(LoggerInterface $logger, Database $dba, Repository\Notify $notify, BaseURL $baseUrl, L10n $l10n)
        {
                parent::__construct($logger);
 
diff --git a/src/Navigation/Notifications/Repository/Notification.php b/src/Navigation/Notifications/Repository/Notification.php
new file mode 100644 (file)
index 0000000..154461e
--- /dev/null
@@ -0,0 +1,141 @@
+<?php
+
+namespace Friendica\Navigation\Notifications\Repository;
+
+use Exception;
+use Friendica\BaseCollection;
+use Friendica\BaseRepository;
+use Friendica\Database\Database;
+use Friendica\Database\DBA;
+use Friendica\Model\Verb;
+use Friendica\Navigation\Notifications\Collection;
+use Friendica\Navigation\Notifications\Entity;
+use Friendica\Navigation\Notifications\Factory;
+use Friendica\Network\HTTPException\NotFoundException;
+use Friendica\Util\DateTimeFormat;
+use Psr\Log\LoggerInterface;
+
+class Notification extends BaseRepository
+{
+       /** @var Factory\Notification  */
+       protected $factory;
+
+       protected static $table_name = 'notification';
+
+       public function __construct(Database $database, LoggerInterface $logger, Factory\Notification $factory = null)
+       {
+               parent::__construct($database, $logger, $factory ?? new Factory\Notification($logger));
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        * @return Entity\Notification
+        * @throws NotFoundException
+        */
+       private function selectOne(array $condition, array $params = []): Entity\Notification
+       {
+               return parent::_selectOne($condition, $params);
+       }
+
+       private function select(array $condition, array $params = []): Collection\Notifications
+       {
+               return new Collection\Notifications(parent::_select($condition, $params)->getArrayCopy());
+       }
+
+       public function countForUser($uid, array $condition, array $params = []): int
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->count($condition, $params);
+       }
+
+       public function existsForUser($uid, array $condition): bool
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->exists($condition);
+       }
+
+       /**
+        * @param int $id
+        * @return Entity\Notification
+        * @throws NotFoundException
+        */
+       public function selectOneById(int $id): Entity\Notification
+       {
+               return $this->selectOne(['id' => $id]);
+       }
+
+       public function selectOneForUser(int $uid, array $condition, array $params = []): Entity\Notification
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->selectOne($condition, $params);
+       }
+
+       public function selectForUser(int $uid, array $condition = [], array $params = []): Collection\Notifications
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->select($condition, $params);
+       }
+
+       public function selectAllForUser(int $uid): Collection\Notifications
+       {
+               return $this->selectForUser($uid);
+       }
+
+       /**
+        * @param array    $condition
+        * @param array    $params
+        * @param int|null $min_id Retrieve models with an id no fewer than this, as close to it as possible
+        * @param int|null $max_id Retrieve models with an id no greater than this, as close to it as possible
+        * @param int      $limit
+        * @return BaseCollection
+        * @throws Exception
+        * @see _selectByBoundaries
+        */
+       public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
+       {
+               $BaseCollection = parent::_selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
+
+               return new Collection\Notifications($BaseCollection->getArrayCopy(), $BaseCollection->getTotalCount());
+       }
+
+       public function setAllSeenForUser(int $uid, array $condition = []): bool
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->db->update(self::$table_name, ['seen' => true], $condition);
+       }
+
+       /**
+        * @param Entity\Notification $Notification
+        * @return Entity\Notification
+        * @throws Exception
+        */
+       public function save(Entity\Notification $Notification): Entity\Notification
+       {
+               $fields = [
+                       'uid'           => $Notification->uid,
+                       'vid'           => Verb::getID($Notification->verb),
+                       'type'          => $Notification->type,
+                       'actor-id'      => $Notification->actorId,
+                       'target-uri-id' => $Notification->targetUriId,
+                       'parent-uri-id' => $Notification->parentUriId,
+                       'seen'          => $Notification->seen,
+               ];
+
+               if ($Notification->id) {
+                       $this->db->update(self::$table_name, $fields, ['id' => $Notification->id]);
+               } else {
+                       $fields['created'] = DateTimeFormat::utcNow();
+                       $this->db->insert(self::$table_name, $fields);
+
+                       $Notification = $this->selectOneById($this->db->lastInsertId());
+               }
+
+               return $Notification;
+       }
+}
diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php
new file mode 100644 (file)
index 0000000..3a6a413
--- /dev/null
@@ -0,0 +1,734 @@
+<?php
+
+namespace Friendica\Navigation\Notifications\Repository;
+
+use Friendica\App\BaseURL;
+use Friendica\BaseRepository;
+use Friendica\Content\Text\Plaintext;
+use Friendica\Core\Config\IConfig;
+use Friendica\Core\Hook;
+use Friendica\Core\L10n;
+use Friendica\Core\System;
+use Friendica\Database\Database;
+use Friendica\Database\DBA;
+use Friendica\Model;
+use Friendica\Navigation\Notifications\Collection;
+use Friendica\Navigation\Notifications\Entity;
+use Friendica\Navigation\Notifications\Exception;
+use Friendica\Navigation\Notifications\Factory;
+use Friendica\Network\HTTPException;
+use Friendica\Protocol\Activity;
+use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Emailer;
+use Psr\Log\LoggerInterface;
+
+class Notify extends BaseRepository
+{
+       /** @var Factory\Notify  */
+       protected $factory;
+
+       /** @var L10n  */
+       protected $l10n;
+
+       /** @var BaseURL  */
+       protected $baseUrl;
+
+       /** @var IConfig */
+       protected $config;
+
+       /** @var Emailer */
+       protected $emailer;
+
+       /** @var Factory\Notification */
+       protected $notification;
+
+       protected static $table_name = 'notify';
+
+       public function __construct(Database $database, LoggerInterface $logger, L10n $l10n, BaseURL $baseUrl, IConfig $config, Emailer $emailer, Factory\Notification $notification, Factory\Notify $factory = null)
+       {
+               $this->l10n         = $l10n;
+               $this->baseUrl      = $baseUrl;
+               $this->config       = $config;
+               $this->emailer      = $emailer;
+               $this->notification = $notification;
+
+               parent::__construct($database, $logger, $factory ?? new Factory\Notify($logger));
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        * @return Entity\Notify
+        * @throws HTTPException\NotFoundException
+        */
+       private function selectOne(array $condition, array $params = []): Entity\Notify
+       {
+               return parent::_selectOne($condition, $params);
+       }
+
+       private function select(array $condition, array $params = []): Collection\Notifies
+       {
+               return new Collection\Notifies(parent::_select($condition, $params)->getArrayCopy());
+       }
+
+       public function countForUser($uid, array $condition, array $params = []): int
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->count($condition, $params);
+       }
+
+       public function existsForUser($uid, array $condition): bool
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->exists($condition);
+       }
+
+       /**
+        * @param int $id
+        * @return Entity\Notify
+        * @throws HTTPException\NotFoundException
+        */
+       public function selectOneById(int $id): Entity\Notify
+       {
+               return $this->selectOne(['id' => $id]);
+       }
+
+       public function selectForUser(int $uid, array $condition, array $params): Collection\Notifies
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->select($condition, $params);
+       }
+
+       /**
+        * Returns notifications for the user, unread first, ordered in descending chronological order.
+        *
+        * @param int $uid
+        * @param int $limit
+        * @return Collection\Notifies
+        */
+       public function selectAllForUser(int $uid, int $limit): Collection\Notifies
+       {
+               return $this->selectForUser($uid, [], ['order' => ['seen' => 'ASC', 'date' => 'DESC'], 'limit' => $limit]);
+       }
+
+       public function setAllSeenForUser(int $uid, array $condition = []): bool
+       {
+               $condition = DBA::mergeConditions($condition, ['uid' => $uid]);
+
+               return $this->db->update(self::$table_name, ['seen' => true], $condition);
+       }
+
+       /**
+        * @param Entity\Notify $Notify
+        * @return Entity\Notify
+        * @throws HTTPException\NotFoundException
+        * @throws HTTPException\InternalServerErrorException
+        * @throws Exception\NotificationCreationInterceptedException
+        */
+       public function save(Entity\Notify $Notify): Entity\Notify
+       {
+               $fields = [
+                       'type'          => $Notify->type,
+                       'name'          => $Notify->name,
+                       'url'           => $Notify->url,
+                       'photo'         => $Notify->photo,
+                       'msg'           => $Notify->msg,
+                       'uid'           => $Notify->uid,
+                       'link'          => $Notify->link,
+                       'iid'           => $Notify->itemId,
+                       'parent'        => $Notify->parent,
+                       'seen'          => $Notify->seen,
+                       'verb'          => $Notify->verb,
+                       'otype'         => $Notify->otype,
+                       'name_cache'    => $Notify->name_cache,
+                       'msg_cache'     => $Notify->msg_cache,
+                       'uri-id'        => $Notify->uriId,
+                       'parent-uri-id' => $Notify->parentUriId,
+               ];
+
+               if ($Notify->id) {
+                       $this->db->update(self::$table_name, $fields, ['id' => $Notify->id]);
+               } else {
+                       $fields['date'] = DateTimeFormat::utcNow();
+                       Hook::callAll('enotify_store', $fields);
+
+                       $this->db->insert(self::$table_name, $fields);
+
+                       $Notify = $this->selectOneById($this->db->lastInsertId());
+               }
+
+               return $Notify;
+       }
+
+       public function setAllSeenForRelatedNotify(Entity\Notify $Notify): bool
+       {
+               $condition = [
+                       '(`link` = ? OR (`parent` != 0 AND `parent` = ? AND `otype` = ?)) AND `uid` = ?',
+                       $Notify->link,
+                       $Notify->parent,
+                       $Notify->otype,
+                       $Notify->uid
+               ];
+               return $this->db->update(self::$table_name, ['seen' => true], $condition);
+       }
+
+       /**
+        * Creates a notification entry and possibly sends a mail
+        *
+        * @param array $params Array with the elements:
+        *                      type, event, otype, activity, verb, uid, cid, item, link,
+        *                      source_name, source_mail, source_nick, source_link, source_photo,
+        *                      show_in_notification_page
+        *
+        * @return bool
+        * @throws \Friendica\Network\HTTPException\InternalServerErrorException
+        */
+       function createFromArray($params)
+       {
+               /** @var string the common prefix of a notification subject */
+               $subjectPrefix = $this->l10n->t('[Friendica:Notify]');
+
+               // Temporary logging for finding the origin
+               if (!isset($params['uid'])) {
+                       $this->logger->notice('Missing parameters "uid".', ['params' => $params, 'callstack' => System::callstack()]);
+               }
+
+               // Ensure that the important fields are set at any time
+               $fields = ['nickname', 'page-flags', 'notify-flags', 'language', 'username', 'email'];
+               $user = DBA::selectFirst('user', $fields, ['uid' => $params['uid']]);
+
+               if (!DBA::isResult($user)) {
+                       $this->logger->error('Unknown user', ['uid' =>  $params['uid']]);
+                       return false;
+               }
+
+               // There is no need to create notifications for forum accounts
+               if (in_array($user['page-flags'], [Model\User::PAGE_FLAGS_COMMUNITY, Model\User::PAGE_FLAGS_PRVGROUP])) {
+                       return false;
+               }
+
+               $params['notify_flags'] = $user['notify-flags'];
+               $params['language']     = $user['language'];
+               $params['to_name']      = $user['username'];
+               $params['to_email']     = $user['email'];
+
+               // from here on everything is in the recipients language
+               $l10n = $this->l10n->withLang($params['language']);
+
+               if (!empty($params['cid'])) {
+                       $contact = Model\Contact::getById($params['cid'], ['url', 'name', 'photo']);
+                       if (DBA::isResult($contact)) {
+                               $params['source_link'] = $contact['url'];
+                               $params['source_name'] = $contact['name'];
+                               $params['source_photo'] = $contact['photo'];
+                       }
+               }
+
+               $siteurl = $this->baseUrl->get(true);
+               $sitename = $this->config->get('config', 'sitename');
+
+               // with $params['show_in_notification_page'] == false, the notification isn't inserted into
+               // the database, and an email is sent if applicable.
+               // default, if not specified: true
+               $show_in_notification_page = isset($params['show_in_notification_page']) ? $params['show_in_notification_page'] : true;
+
+               $title = $params['item']['title'] ?? '';
+               $body = $params['item']['body'] ?? '';
+
+               $parent_id = $params['item']['parent'] ?? 0;
+               $parent_uri_id = $params['item']['parent-uri-id'] ?? 0;
+
+               $epreamble = '';
+               $preamble  = '';
+               $subject   = '';
+               $sitelink  = '';
+               $tsitelink = '';
+               $hsitelink = '';
+               $itemlink  = '';
+
+               switch ($params['type']) {
+                       case Model\Notification\Type::MAIL:
+                               $itemlink = $params['link'];
+
+                               $subject = $l10n->t('%s New mail received at %s', $subjectPrefix, $sitename);
+
+                               $preamble = $l10n->t('%1$s sent you a new private message at %2$s.', $params['source_name'], $sitename);
+                               $epreamble = $l10n->t('%1$s sent you %2$s.', '[url='.$params['source_link'].']'.$params['source_name'].'[/url]', '[url=' . $itemlink . ']' . $l10n->t('a private message').'[/url]');
+
+                               $sitelink = $l10n->t('Please visit %s to view and/or reply to your private messages.');
+                               $tsitelink = sprintf($sitelink, $itemlink);
+                               $hsitelink = sprintf($sitelink, '<a href="' . $itemlink . '">' . $sitename . '</a>');
+
+                               // Mail notifications aren't using the "notify" table entry
+                               $show_in_notification_page = false;
+                               break;
+
+                       case Model\Notification\Type::COMMENT:
+                               if (Model\Post\ThreadUser::getIgnored($parent_uri_id, $params['uid'])) {
+                                       $this->logger->info('Thread is ignored', ['parent' => $parent_id, 'parent-uri-id' => $parent_uri_id]);
+                                       return false;
+                               }
+
+                               $item = Model\Post::selectFirstForUser($params['uid'], Model\Item::ITEM_FIELDLIST, ['id' => $parent_id, 'deleted' => false]);
+                               if (empty($item)) {
+                                       return false;
+                               }
+
+                               $item_post_type = Model\Item::postType($item, $l10n);
+
+                               $content = Plaintext::getPost($item, 70);
+                               if (!empty($content['text'])) {
+                                       $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
+                               } else {
+                                       $title = '';
+                               }
+
+                               // First go for the general message
+
+                               // "George Bull's post"
+                               $message = $l10n->t('%1$s commented on %2$s\'s %3$s %4$s');
+                               $dest_str = sprintf($message, $params['source_name'], $item['author-name'], $item_post_type, $title);
+
+                               // "your post"
+                               if ($item['wall']) {
+                                       $message = $l10n->t('%1$s commented on your %2$s %3$s');
+                                       $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
+                               // "their post"
+                               } elseif ($item['author-link'] == $params['source_link']) {
+                                       $message = $l10n->t('%1$s commented on their %2$s %3$s');
+                                       $dest_str = sprintf($message, $params['source_name'], $item_post_type, $title);
+                               }
+
+                               $subject = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $parent_id, $params['source_name']);
+
+                               $preamble = $l10n->t('%s commented on an item/conversation you have been following.', $params['source_name']);
+
+                               $epreamble = $dest_str;
+
+                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
+                               $tsitelink = sprintf($sitelink, $siteurl);
+                               $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
+                               $itemlink =  $params['link'];
+                               break;
+
+                       case Model\Notification\Type::WALL:
+                               $subject = $l10n->t('%s %s posted to your profile wall', $subjectPrefix, $params['source_name']);
+
+                               $preamble = $l10n->t('%1$s posted to your profile wall at %2$s', $params['source_name'], $sitename);
+                               $epreamble = $l10n->t('%1$s posted to [url=%2$s]your wall[/url]',
+                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
+                                       $params['link']
+                               );
+
+                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
+                               $tsitelink = sprintf($sitelink, $siteurl);
+                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+                               $itemlink =  $params['link'];
+                               break;
+
+                       case Model\Notification\Type::POKE:
+                               $subject = $l10n->t('%1$s %2$s poked you', $subjectPrefix, $params['source_name']);
+
+                               $preamble = $l10n->t('%1$s poked you at %2$s', $params['source_name'], $sitename);
+                               $epreamble = $l10n->t('%1$s [url=%2$s]poked you[/url].',
+                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
+                                       $params['link']
+                               );
+
+                               $subject = str_replace('poked', $l10n->t($params['activity']), $subject);
+                               $preamble = str_replace('poked', $l10n->t($params['activity']), $preamble);
+                               $epreamble = str_replace('poked', $l10n->t($params['activity']), $epreamble);
+
+                               $sitelink = $l10n->t('Please visit %s to view and/or reply to the conversation.');
+                               $tsitelink = sprintf($sitelink, $siteurl);
+                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+                               $itemlink =  $params['link'];
+                               break;
+
+                       case Model\Notification\Type::INTRO:
+                               $itemlink = $params['link'];
+                               $subject = $l10n->t('%s Introduction received', $subjectPrefix);
+
+                               $preamble = $l10n->t('You\'ve received an introduction from \'%1$s\' at %2$s', $params['source_name'], $sitename);
+                               $epreamble = $l10n->t('You\'ve received [url=%1$s]an introduction[/url] from %2$s.',
+                                       $itemlink,
+                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
+                               );
+
+                               $body = $l10n->t('You may visit their profile at %s', $params['source_link']);
+
+                               $sitelink = $l10n->t('Please visit %s to approve or reject the introduction.');
+                               $tsitelink = sprintf($sitelink, $siteurl);
+                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+
+                               switch ($params['verb']) {
+                                       case Activity::FRIEND:
+                                               // someone started to share with user (mostly OStatus)
+                                               $subject = $l10n->t('%s A new person is sharing with you', $subjectPrefix);
+
+                                               $preamble = $l10n->t('%1$s is sharing with you at %2$s', $params['source_name'], $sitename);
+                                               $epreamble = $l10n->t('%1$s is sharing with you at %2$s',
+                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
+                                                       $sitename
+                                               );
+                                               break;
+                                       case Activity::FOLLOW:
+                                               // someone started to follow the user (mostly OStatus)
+                                               $subject = $l10n->t('%s You have a new follower', $subjectPrefix);
+
+                                               $preamble = $l10n->t('You have a new follower at %2$s : %1$s', $params['source_name'], $sitename);
+                                               $epreamble = $l10n->t('You have a new follower at %2$s : %1$s',
+                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]',
+                                                       $sitename
+                                               );
+                                               break;
+                                       default:
+                                               // ACTIVITY_REQ_FRIEND is default activity for notifications
+                                               break;
+                               }
+                               break;
+
+                       case Model\Notification\Type::SUGGEST:
+                               $itemlink =  $params['link'];
+                               $subject = $l10n->t('%s Friend suggestion received', $subjectPrefix);
+
+                               $preamble = $l10n->t('You\'ve received a friend suggestion from \'%1$s\' at %2$s', $params['source_name'], $sitename);
+                               $epreamble = $l10n->t('You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.',
+                                       $itemlink,
+                                       '[url='.$params['item']['url'].']'.$params['item']['name'].'[/url]',
+                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
+                               );
+
+                               $body = $l10n->t('Name:').' '.$params['item']['name']."\n";
+                               $body .= $l10n->t('Photo:').' '.$params['item']['photo']."\n";
+                               $body .= $l10n->t('You may visit their profile at %s', $params['item']['url']);
+
+                               $sitelink = $l10n->t('Please visit %s to approve or reject the suggestion.');
+                               $tsitelink = sprintf($sitelink, $siteurl);
+                               $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+                               break;
+
+                       case Model\Notification\Type::CONFIRM:
+                               if ($params['verb'] == Activity::FRIEND) { // mutual connection
+                                       $itemlink =  $params['link'];
+                                       $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
+
+                                       $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
+                                       $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
+                                               $itemlink,
+                                               '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
+                                       );
+
+                                       $body =  $l10n->t('You are now mutual friends and may exchange status updates, photos, and email without restriction.');
+
+                                       $sitelink = $l10n->t('Please visit %s if you wish to make any changes to this relationship.');
+                                       $tsitelink = sprintf($sitelink, $siteurl);
+                                       $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+                               } else { // ACTIVITY_FOLLOW
+                                       $itemlink =  $params['link'];
+                                       $subject = $l10n->t('%s Connection accepted', $subjectPrefix);
+
+                                       $preamble = $l10n->t('\'%1$s\' has accepted your connection request at %2$s', $params['source_name'], $sitename);
+                                       $epreamble = $l10n->t('%2$s has accepted your [url=%1$s]connection request[/url].',
+                                               $itemlink,
+                                               '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
+                                       );
+
+                                       $body =  $l10n->t('\'%1$s\' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically.', $params['source_name']);
+                                       $body .= "\n\n";
+                                       $body .= $l10n->t('\'%1$s\' may choose to extend this into a two-way or more permissive relationship in the future.', $params['source_name']);
+
+                                       $sitelink = $l10n->t('Please visit %s  if you wish to make any changes to this relationship.');
+                                       $tsitelink = sprintf($sitelink, $siteurl);
+                                       $hsitelink = sprintf($sitelink, '<a href="'.$siteurl.'">'.$sitename.'</a>');
+                               }
+                               break;
+
+                       case Model\Notification\Type::SYSTEM:
+                               switch($params['event']) {
+                                       case "SYSTEM_REGISTER_REQUEST":
+                                               $itemlink =  $params['link'];
+                                               $subject = $l10n->t('[Friendica System Notify]') . ' ' . $l10n->t('registration request');
+
+                                               $preamble = $l10n->t('You\'ve received a registration request from \'%1$s\' at %2$s', $params['source_name'], $sitename);
+                                               $epreamble = $l10n->t('You\'ve received a [url=%1$s]registration request[/url] from %2$s.',
+                                                       $itemlink,
+                                                       '[url='.$params['source_link'].']'.$params['source_name'].'[/url]'
+                                               );
+
+                                               $body = $l10n->t("Full Name:    %s\nSite Location:      %s\nLogin Name: %s (%s)",
+                                                       $params['source_name'],
+                                                       $siteurl, $params['source_mail'],
+                                                       $params['source_nick']
+                                               );
+
+                                               $sitelink = $l10n->t('Please visit %s to approve or reject the request.');
+                                               $tsitelink = sprintf($sitelink, $params['link']);
+                                               $hsitelink = sprintf($sitelink, '<a href="'.$params['link'].'">'.$sitename.'</a><br><br>');
+                                               break;
+                                       case "SYSTEM_DB_UPDATE_FAIL":
+                                               break;
+                               }
+                               break;
+
+                       default:
+                               $this->logger->notice('Unhandled type', ['type' => $params['type']]);
+                               return false;
+               }
+
+               return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page);
+       }
+
+       private function storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $body, $itemlink, $show_in_notification_page)
+       {
+               $item_id = $params['item']['id'] ?? 0;
+               $uri_id = $params['item']['uri-id'] ?? null;
+               $parent_id = $params['item']['parent'] ?? 0;
+               $parent_uri_id = $params['item']['parent-uri-id'] ?? null;
+
+               // Ensure that the important fields are set at any time
+               $fields = ['nickname'];
+               $user = Model\User::getById($params['uid'], $fields);
+
+               $sitename = $this->config->get('config', 'sitename');
+
+               $nickname = $user['nickname'];
+
+               $hostname = $this->baseUrl->getHostname();
+               if (strpos($hostname, ':')) {
+                       $hostname = substr($hostname, 0, strpos($hostname, ':'));
+               }
+
+               // Creates a new email builder for the notification email
+               $emailBuilder = $this->emailer->newNotifyMail();
+
+               $emailBuilder->setHeader('X-Friendica-Account', '<' . $nickname . '@' . $hostname . '>');
+
+               $subject .= " (".$nickname."@".$hostname.")";
+
+               $h = [
+                       'params'    => $params,
+                       'subject'   => $subject,
+                       'preamble'  => $preamble,
+                       'epreamble' => $epreamble,
+                       'body'      => $body,
+                       'sitelink'  => $sitelink,
+                       'tsitelink' => $tsitelink,
+                       'hsitelink' => $hsitelink,
+                       'itemlink'  => $itemlink
+               ];
+
+               Hook::callAll('enotify', $h);
+
+               $subject   = $h['subject'];
+
+               $preamble  = $h['preamble'];
+               $epreamble = $h['epreamble'];
+
+               $body      = $h['body'];
+
+               $tsitelink = $h['tsitelink'];
+               $hsitelink = $h['hsitelink'];
+               $itemlink  = $h['itemlink'];
+
+               $notify_id = 0;
+
+               if ($show_in_notification_page) {
+                       $Notify = $this->factory->createFromParams($params, $itemlink, $item_id, $uri_id, $parent_id, $parent_uri_id);
+                       try {
+                               $Notify = $this->save($Notify);
+                       } catch (Exception\NotificationCreationInterceptedException $e) {
+                               // Notification insertion can be intercepted by an addon registering the 'enotify_store' hook
+                               return false;
+                       }
+
+                       $Notify->updateMsgFromPreamble($epreamble);
+                       $Notify = $this->save($Notify);
+
+                       $itemlink  = $this->baseUrl->get() . '/notification/' . $Notify->id;
+                       $notify_id = $Notify->id;
+               }
+
+               // send email notification if notification preferences permit
+               if ((intval($params['notify_flags']) & intval($params['type']))
+                       || $params['type'] == Model\Notification\Type::SYSTEM) {
+
+                       $this->logger->notice('sending notification email');
+
+                       if (isset($params['parent']) && (intval($params['parent']) != 0)) {
+                               $parent = Model\Post::selectFirst(['guid'], ['id' => $params['parent']]);
+                               $message_id = "<" . $parent['guid'] . "@" . gethostname() . ">";
+
+                               // Is this the first email notification for this parent item and user?
+                               if (!DBA::exists('notify-threads', ['master-parent-uri-id' => $parent_uri_id, 'receiver-uid' => $params['uid']])) {
+                                       $this->logger->info("notify_id:" . intval($notify_id) . ", parent: " . intval($params['parent']) . "uid: " . intval($params['uid']));
+
+                                       $fields = ['notify-id' => $notify_id, 'master-parent-uri-id' => $parent_uri_id,
+                                               'receiver-uid' => $params['uid'], 'parent-item' => 0];
+                                       DBA::insert('notify-threads', $fields);
+
+                                       $emailBuilder->setHeader('Message-ID', $message_id);
+                                       $log_msg = "include/enotify: No previous notification found for this parent:\n" .
+                                               "  parent: ${params['parent']}\n" . "  uid   : ${params['uid']}\n";
+                                       $this->logger->info($log_msg);
+                               } else {
+                                       // If not, just "follow" the thread.
+                                       $emailBuilder->setHeader('References', $message_id);
+                                       $emailBuilder->setHeader('In-Reply-To', $message_id);
+                                       $this->logger->info("There's already a notification for this parent.");
+                               }
+                       }
+
+                       $datarray = [
+                               'preamble'     => $preamble,
+                               'type'         => $params['type'],
+                               'parent'       => $parent_id,
+                               'source_name'  => $params['source_name'] ?? null,
+                               'source_link'  => $params['source_link'] ?? null,
+                               'source_photo' => $params['source_photo'] ?? null,
+                               'uid'          => $params['uid'],
+                               'hsitelink'    => $hsitelink,
+                               'tsitelink'    => $tsitelink,
+                               'itemlink'     => $itemlink,
+                               'title'        => $title,
+                               'body'         => $body,
+                               'subject'      => $subject,
+                               'headers'      => $emailBuilder->getHeaders(),
+                       ];
+
+                       Hook::callAll('enotify_mail', $datarray);
+
+                       $emailBuilder
+                               ->withHeaders($datarray['headers'])
+                               ->withRecipient($params['to_email'])
+                               ->forUser([
+                                       'uid' => $datarray['uid'],
+                                       'language' => $params['language'],
+                               ])
+                               ->withNotification($datarray['subject'], $datarray['preamble'], $datarray['title'], $datarray['body'])
+                               ->withSiteLink($datarray['tsitelink'], $datarray['hsitelink'])
+                               ->withItemLink($datarray['itemlink']);
+
+                       // If a photo is present, add it to the email
+                       if (!empty($datarray['source_photo'])) {
+                               $emailBuilder->withPhoto(
+                                       $datarray['source_photo'],
+                                       $datarray['source_link'] ?? $sitelink,
+                                       $datarray['source_name'] ?? $sitename);
+                       }
+
+                       $email = $emailBuilder->build();
+
+                       // use the Emailer class to send the message
+                       return $this->emailer->send($email);
+               }
+
+               return false;
+       }
+
+       public function createFromNotification(Entity\Notification $Notification)
+       {
+               $this->logger->info('Start', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
+
+               if ($Notification->type === Model\Post\UserNotification::TYPE_NONE) {
+                       $this->logger->info('Not an item based notification, quitting', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
+                       return false;
+               }
+
+               $params = [];
+               $params['verb']  = $Notification->verb;
+               $params['uid']   = $Notification->uid;
+               $params['otype'] = Model\Notification\ObjectType::ITEM;
+
+               $user = Model\User::getById($Notification->uid);
+
+               $params['notify_flags'] = $user['notify-flags'];
+               $params['language']     = $user['language'];
+               $params['to_name']      = $user['username'];
+               $params['to_email']     = $user['email'];
+
+               // from here on everything is in the recipients language
+               $l10n = $this->l10n->withLang($user['language']);
+
+               $contact = Model\Contact::getById($Notification->actorId, ['url', 'name', 'photo']);
+               if (DBA::isResult($contact)) {
+                       $params['source_link']  = $contact['url'];
+                       $params['source_name']  = $contact['name'];
+                       $params['source_photo'] = $contact['photo'];
+               }
+
+               $item = Model\Post::selectFirstForUser($Notification->uid, Model\Item::ITEM_FIELDLIST,
+                       ['uid' => [0, $Notification->uid], 'uri-id' => $Notification->targetUriId, 'deleted' => false],
+                       ['order' => ['uid' => true]]);
+               if (empty($item)) {
+                       $this->logger->info('Item not found', ['uri-id' => $Notification->targetUriId, 'type' => $Notification->type]);
+                       return false;
+               }
+
+               $params['item']   = $item;
+               $params['parent'] = $item['parent'];
+               $params['link']   = $this->baseUrl->get() . '/display/' . urlencode($item['guid']);
+
+               $subjectPrefix = $l10n->t('[Friendica:Notify]');
+
+               if (Model\Post\ThreadUser::getIgnored($Notification->parentUriId, $Notification->uid)) {
+                       $this->logger->info('Thread is ignored', ['parent-uri-id' => $Notification->parentUriId, 'type' => $Notification->type]);
+                       return false;
+               }
+
+               // Check to see if there was already a tag notify or comment notify for this post.
+               // If so don't create a second notification
+               $condition = ['type' => [Model\Notification\Type::TAG_SELF, Model\Notification\Type::COMMENT, Model\Notification\Type::SHARE],
+                       'link' => $params['link'], 'verb' => Activity::POST];
+               if ($this->existsForUser($Notification->uid, $condition)) {
+                       $this->logger->info('Duplicate found, quitting', $condition + ['uid' => $Notification->uid]);
+                       return false;
+               }
+
+               $content = Plaintext::getPost($item, 70);
+               if (!empty($content['text'])) {
+                       $title = '"' . trim(str_replace("\n", " ", $content['text'])) . '"';
+               } else {
+                       $title = $item['title'];
+               }
+
+               // Some mail software relies on subject field for threading.
+               // So, we cannot have different subjects for notifications of the same thread.
+               // Before this we have the name of the replier on the subject rendering
+               // different subjects for messages on the same thread.
+               if ($Notification->type === Model\Post\UserNotification::TYPE_EXPLICIT_TAGGED) {
+                       $params['type'] = Model\Notification\Type::TAG_SELF;
+                       $subject        = $l10n->t('%s %s tagged you', $subjectPrefix, $contact['name']);
+               } elseif ($Notification->type === Model\Post\UserNotification::TYPE_SHARED) {
+                       $params['type'] = Model\Notification\Type::SHARE;
+                       $subject        = $l10n->t('%s %s shared a new post', $subjectPrefix, $contact['name']);
+               } else {
+                       $params['type'] = Model\Notification\Type::COMMENT;
+                       $subject        = $l10n->t('%1$s Comment to conversation #%2$d by %3$s', $subjectPrefix, $item['parent'], $contact['name']);
+               }
+
+               $msg = $this->notification->getMessageFromNotification($Notification, $this->baseUrl, $l10n);
+               if (empty($msg)) {
+                       $this->logger->info('No notification message, quitting', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
+                       return false;
+               }
+
+               $preamble  = $msg['plain'];
+               $epreamble = $msg['rich'];
+
+               $sitename = $this->config->get('config', 'sitename');
+               $siteurl  = $this->baseUrl->get(true);
+
+               $sitelink  = $l10n->t('Please visit %s to view and/or reply to the conversation.');
+               $tsitelink = sprintf($sitelink, $siteurl);
+               $hsitelink = sprintf($sitelink, '<a href="' . $siteurl . '">' . $sitename . '</a>');
+               $itemlink  = $params['link'];
+
+               $this->logger->info('Perform notification', ['uid' => $Notification->uid, 'id' => $Notification->id, 'type' => $Notification->type]);
+
+               return $this->storeAndSend($params, $sitelink, $tsitelink, $hsitelink, $title, $subject, $preamble, $epreamble, $item['body'], $itemlink, true);
+       }
+}
diff --git a/src/Profile/ProfileField/Depository/ProfileField.php b/src/Profile/ProfileField/Depository/ProfileField.php
deleted file mode 100644 (file)
index a6e441f..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Profile\ProfileField\Depository;
-
-use Friendica\BaseDepository;
-use Friendica\Database\Database;
-use Friendica\Profile\ProfileField\Exception\ProfileFieldNotFoundException;
-use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
-use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException;
-use Friendica\Profile\ProfileField\Factory;
-use Friendica\Profile\ProfileField\Entity;
-use Friendica\Profile\ProfileField\Collection;
-use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
-use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
-
-class ProfileField extends BaseDepository
-{
-       /** @var  Factory\ProfileField */
-       protected $factory;
-
-       protected static $table_name = 'profile_field';
-
-       protected static $view_name = 'profile_field-view';
-
-       /** @var PermissionSetDepository */
-       protected $permissionSetDepository;
-
-       public function __construct(Database $database, LoggerInterface $logger, Factory\ProfileField $factory, PermissionSetDepository $permissionSetDepository)
-       {
-               parent::__construct($database, $logger, $factory);
-
-               $this->permissionSetDepository = $permissionSetDepository;
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Entity\ProfileField
-        *
-        * @throws ProfileFieldNotFoundException
-        * @throws UnexpectedPermissionSetException
-        */
-       private function selectOne(array $condition, array $params = []): Entity\ProfileField
-       {
-               $fields = $this->db->selectFirst(static::$view_name, [], $condition, $params);
-               if (!$this->db->isResult($fields)) {
-                       throw new ProfileFieldNotFoundException();
-               }
-
-               return $this->factory->createFromTableRow($fields);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Collection\ProfileFields
-        *
-        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
-        * @throws UnexpectedPermissionSetException
-        */
-       private function select(array $condition, array $params = []): Collection\ProfileFields
-       {
-               $rows = $this->db->selectToArray(static::$view_name, [], $condition, $params);
-
-               $Entities = new Collection\ProfileFields();
-               foreach ($rows as $fields) {
-                       $Entities[] = $this->factory->createFromTableRow($fields);
-               }
-
-               return $Entities;
-       }
-
-       /**
-        * Converts a given ProfileField into a DB compatible row array
-        *
-        * @param Entity\ProfileField $profileField
-        *
-        * @return array
-        */
-       protected function convertToTableRow(Entity\ProfileField $profileField): array
-       {
-               return [
-                       'uid'     => $profileField->uid,
-                       'label'   => $profileField->label,
-                       'value'   => $profileField->value,
-                       'order'   => $profileField->order,
-                       'created' => $profileField->created->format(DateTimeFormat::MYSQL),
-                       'edited'  => $profileField->edited->format(DateTimeFormat::MYSQL),
-                       'psid'    => $profileField->permissionSet->id
-               ];
-       }
-
-       /**
-        * Returns all public available ProfileFields for a specific user
-        *
-        * @param int $uid the user id
-        *
-        * @return Collection\ProfileFields
-        *
-        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
-        */
-       public function selectPublicFieldsByUserId(int $uid): Collection\ProfileFields
-       {
-               try {
-                       $publicPermissionSet = $this->permissionSetDepository->selectPublicForUser($uid);
-
-                       return $this->select([
-                               'uid'  => $uid,
-                               'psid' => $publicPermissionSet->id
-                       ]);
-               } catch (\Exception $exception) {
-                       throw new ProfileFieldPersistenceException(sprintf('Cannot select public ProfileField for user "%d"', $uid), $exception);
-               }
-       }
-
-       /**
-        * @param int $uid Field owner user Id
-        *
-        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
-        */
-       public function selectByUserId(int $uid): Collection\ProfileFields
-       {
-               try {
-                       return $this->select(
-                               ['uid' => $uid],
-                               ['order' => ['order']]
-                       );
-               } catch (\Exception $exception) {
-                       throw new ProfileFieldPersistenceException(sprintf('Cannot select ProfileField for user "%d"', $uid), $exception);
-               }
-       }
-
-       /**
-        * Retrieve all custom profile field a given contact is able to access to, including public profile fields.
-        *
-        * @param int $cid Private contact id, must be owned by $uid
-        * @param int $uid Field owner user id
-        *
-        * @throws \Exception
-        */
-       public function selectByContactId(int $cid, int $uid): Collection\ProfileFields
-       {
-               $permissionSets = $this->permissionSetDepository->selectByContactId($cid, $uid);
-
-               $permissionSetIds = $permissionSets->column('id');
-
-               // Includes public custom fields
-               $permissionSetIds[] = $this->permissionSetDepository->selectPublicForUser($uid)->id;
-
-               return $this->select(
-                       ['uid' => $uid, 'psid' => $permissionSetIds],
-                       ['order' => ['order']]
-               );
-       }
-
-       /**
-        * @param int $id
-        *
-        * @return Entity\ProfileField
-        *
-        * @ProfileFieldNotFoundException In case there is no ProfileField found
-        */
-       public function selectOneById(int $id): Entity\ProfileField
-       {
-               try {
-                       return $this->selectOne(['id' => $id]);
-               } catch (\Exception $exception) {
-                       throw new ProfileFieldNotFoundException(sprintf('Cannot find Profile "%s"', $id), $exception);
-               }
-       }
-
-       /**
-        * Delets a whole collection of ProfileFields
-        *
-        * @param Collection\ProfileFields $profileFields
-        *
-        * @return bool
-        * @throws ProfileFieldPersistenceException in case the persistence layer cannot delete the ProfileFields
-        */
-       public function deleteCollection(Collection\ProfileFields $profileFields): bool
-       {
-               try {
-                       return $this->db->delete(self::$table_name, ['id' => $profileFields->column('id')]);
-               } catch (\Exception $exception) {
-                       throw new ProfileFieldPersistenceException('Cannot delete ProfileFields', $exception);
-               }
-       }
-
-       /**
-        * @param Entity\ProfileField $profileField
-        *
-        * @return Entity\ProfileField
-        * @throws ProfileFieldPersistenceException in case the persistence layer cannot save the ProfileField
-        */
-       public function save(Entity\ProfileField $profileField): Entity\ProfileField
-       {
-               if ($profileField->permissionSet->id === null) {
-                       throw new ProfileFieldPersistenceException('PermissionSet needs to be saved first.');
-               }
-
-               $fields = $this->convertToTableRow($profileField);
-
-               try {
-                       if ($profileField->id) {
-                               $this->db->update(self::$table_name, $fields, ['id' => $profileField->id]);
-                       } else {
-                               $this->db->insert(self::$table_name, $fields);
-
-                               $profileField = $this->selectOneById($this->db->lastInsertId());
-                       }
-               } catch (\Exception $exception) {
-                       throw new ProfileFieldPersistenceException(sprintf('Cannot save ProfileField with id "%d" and label "%s"', $profileField->id, $profileField->label), $exception);
-               }
-
-               return $profileField;
-       }
-
-       public function saveCollectionForUser(int $uid, Collection\ProfileFields $profileFields): Collection\ProfileFields
-       {
-               $savedProfileFields = new Collection\ProfileFields();
-
-               $profileFieldsOld = $this->selectByUserId($uid);
-
-               // Prunes profile field whose label has been emptied
-               $labels                 = $profileFields->column('label');
-               $prunedProfileFieldsOld = $profileFieldsOld->filter(function (Entity\ProfileField $profileFieldOld) use ($labels) {
-                       return array_search($profileFieldOld->label, $labels) === false;
-               });
-               $this->deleteCollection($prunedProfileFieldsOld);
-
-               // Update the order based on the new Profile Field Collection
-               $order                 = 0;
-               $labelProfileFieldsOld = array_flip($profileFieldsOld->column('label'));
-
-               foreach ($profileFields as $profileField) {
-                       // Update existing field (preserve
-                       if (array_key_exists($profileField->label, $labelProfileFieldsOld)) {
-                               $profileFieldOldId = $labelProfileFieldsOld[$profileField->label];
-                               /** @var Entity\ProfileField $foundProfileFieldOld */
-                               $foundProfileFieldOld = $profileFieldsOld[$profileFieldOldId];
-                               $foundProfileFieldOld->update(
-                                       $profileField->value,
-                                       $order,
-                                       $profileField->permissionSet
-                               );
-
-                               $savedProfileFields->append($this->save($foundProfileFieldOld));
-                       } else {
-                               $profileField->setOrder($order);
-                               $savedProfileFields->append($this->save($profileField));
-                       }
-
-                       $order++;
-               }
-
-               return $savedProfileFields;
-       }
-}
diff --git a/src/Profile/ProfileField/Repository/ProfileField.php b/src/Profile/ProfileField/Repository/ProfileField.php
new file mode 100644 (file)
index 0000000..09959e4
--- /dev/null
@@ -0,0 +1,280 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Profile\ProfileField\Repository;
+
+use Friendica\BaseRepository;
+use Friendica\Database\Database;
+use Friendica\Profile\ProfileField\Exception\ProfileFieldNotFoundException;
+use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
+use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException;
+use Friendica\Profile\ProfileField\Factory;
+use Friendica\Profile\ProfileField\Entity;
+use Friendica\Profile\ProfileField\Collection;
+use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
+use Friendica\Util\DateTimeFormat;
+use Psr\Log\LoggerInterface;
+
+class ProfileField extends BaseRepository
+{
+       /** @var  Factory\ProfileField */
+       protected $factory;
+
+       protected static $table_name = 'profile_field';
+
+       protected static $view_name = 'profile_field-view';
+
+       /** @var PermissionSetRepository */
+       protected $permissionSetRepository;
+
+       public function __construct(Database $database, LoggerInterface $logger, Factory\ProfileField $factory, PermissionSetRepository $permissionSetRepository)
+       {
+               parent::__construct($database, $logger, $factory);
+
+               $this->permissionSetRepository = $permissionSetRepository;
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Entity\ProfileField
+        *
+        * @throws ProfileFieldNotFoundException
+        * @throws UnexpectedPermissionSetException
+        */
+       private function selectOne(array $condition, array $params = []): Entity\ProfileField
+       {
+               $fields = $this->db->selectFirst(static::$view_name, [], $condition, $params);
+               if (!$this->db->isResult($fields)) {
+                       throw new ProfileFieldNotFoundException();
+               }
+
+               return $this->factory->createFromTableRow($fields);
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Collection\ProfileFields
+        *
+        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
+        * @throws UnexpectedPermissionSetException
+        */
+       private function select(array $condition, array $params = []): Collection\ProfileFields
+       {
+               $rows = $this->db->selectToArray(static::$view_name, [], $condition, $params);
+
+               $Entities = new Collection\ProfileFields();
+               foreach ($rows as $fields) {
+                       $Entities[] = $this->factory->createFromTableRow($fields);
+               }
+
+               return $Entities;
+       }
+
+       /**
+        * Converts a given ProfileField into a DB compatible row array
+        *
+        * @param Entity\ProfileField $profileField
+        *
+        * @return array
+        */
+       protected function convertToTableRow(Entity\ProfileField $profileField): array
+       {
+               return [
+                       'uid'     => $profileField->uid,
+                       'label'   => $profileField->label,
+                       'value'   => $profileField->value,
+                       'order'   => $profileField->order,
+                       'created' => $profileField->created->format(DateTimeFormat::MYSQL),
+                       'edited'  => $profileField->edited->format(DateTimeFormat::MYSQL),
+                       'psid'    => $profileField->permissionSet->id
+               ];
+       }
+
+       /**
+        * Returns all public available ProfileFields for a specific user
+        *
+        * @param int $uid the user id
+        *
+        * @return Collection\ProfileFields
+        *
+        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
+        */
+       public function selectPublicFieldsByUserId(int $uid): Collection\ProfileFields
+       {
+               try {
+                       $publicPermissionSet = $this->permissionSetRepository->selectPublicForUser($uid);
+
+                       return $this->select([
+                               'uid'  => $uid,
+                               'psid' => $publicPermissionSet->id
+                       ]);
+               } catch (\Exception $exception) {
+                       throw new ProfileFieldPersistenceException(sprintf('Cannot select public ProfileField for user "%d"', $uid), $exception);
+               }
+       }
+
+       /**
+        * @param int $uid Field owner user Id
+        *
+        * @throws ProfileFieldPersistenceException In case of underlying persistence exceptions
+        */
+       public function selectByUserId(int $uid): Collection\ProfileFields
+       {
+               try {
+                       return $this->select(
+                               ['uid' => $uid],
+                               ['order' => ['order']]
+                       );
+               } catch (\Exception $exception) {
+                       throw new ProfileFieldPersistenceException(sprintf('Cannot select ProfileField for user "%d"', $uid), $exception);
+               }
+       }
+
+       /**
+        * Retrieve all custom profile field a given contact is able to access to, including public profile fields.
+        *
+        * @param int $cid Private contact id, must be owned by $uid
+        * @param int $uid Field owner user id
+        *
+        * @throws \Exception
+        */
+       public function selectByContactId(int $cid, int $uid): Collection\ProfileFields
+       {
+               $permissionSets = $this->permissionSetRepository->selectByContactId($cid, $uid);
+
+               $permissionSetIds = $permissionSets->column('id');
+
+               // Includes public custom fields
+               $permissionSetIds[] = $this->permissionSetRepository->selectPublicForUser($uid)->id;
+
+               return $this->select(
+                       ['uid' => $uid, 'psid' => $permissionSetIds],
+                       ['order' => ['order']]
+               );
+       }
+
+       /**
+        * @param int $id
+        *
+        * @return Entity\ProfileField
+        *
+        * @ProfileFieldNotFoundException In case there is no ProfileField found
+        */
+       public function selectOneById(int $id): Entity\ProfileField
+       {
+               try {
+                       return $this->selectOne(['id' => $id]);
+               } catch (\Exception $exception) {
+                       throw new ProfileFieldNotFoundException(sprintf('Cannot find Profile "%s"', $id), $exception);
+               }
+       }
+
+       /**
+        * Delets a whole collection of ProfileFields
+        *
+        * @param Collection\ProfileFields $profileFields
+        *
+        * @return bool
+        * @throws ProfileFieldPersistenceException in case the persistence layer cannot delete the ProfileFields
+        */
+       public function deleteCollection(Collection\ProfileFields $profileFields): bool
+       {
+               try {
+                       return $this->db->delete(self::$table_name, ['id' => $profileFields->column('id')]);
+               } catch (\Exception $exception) {
+                       throw new ProfileFieldPersistenceException('Cannot delete ProfileFields', $exception);
+               }
+       }
+
+       /**
+        * @param Entity\ProfileField $profileField
+        *
+        * @return Entity\ProfileField
+        * @throws ProfileFieldPersistenceException in case the persistence layer cannot save the ProfileField
+        */
+       public function save(Entity\ProfileField $profileField): Entity\ProfileField
+       {
+               if ($profileField->permissionSet->id === null) {
+                       throw new ProfileFieldPersistenceException('PermissionSet needs to be saved first.');
+               }
+
+               $fields = $this->convertToTableRow($profileField);
+
+               try {
+                       if ($profileField->id) {
+                               $this->db->update(self::$table_name, $fields, ['id' => $profileField->id]);
+                       } else {
+                               $this->db->insert(self::$table_name, $fields);
+
+                               $profileField = $this->selectOneById($this->db->lastInsertId());
+                       }
+               } catch (\Exception $exception) {
+                       throw new ProfileFieldPersistenceException(sprintf('Cannot save ProfileField with id "%d" and label "%s"', $profileField->id, $profileField->label), $exception);
+               }
+
+               return $profileField;
+       }
+
+       public function saveCollectionForUser(int $uid, Collection\ProfileFields $profileFields): Collection\ProfileFields
+       {
+               $savedProfileFields = new Collection\ProfileFields();
+
+               $profileFieldsOld = $this->selectByUserId($uid);
+
+               // Prunes profile field whose label has been emptied
+               $labels                 = $profileFields->column('label');
+               $prunedProfileFieldsOld = $profileFieldsOld->filter(function (Entity\ProfileField $profileFieldOld) use ($labels) {
+                       return array_search($profileFieldOld->label, $labels) === false;
+               });
+               $this->deleteCollection($prunedProfileFieldsOld);
+
+               // Update the order based on the new Profile Field Collection
+               $order                 = 0;
+               $labelProfileFieldsOld = array_flip($profileFieldsOld->column('label'));
+
+               foreach ($profileFields as $profileField) {
+                       // Update existing field (preserve
+                       if (array_key_exists($profileField->label, $labelProfileFieldsOld)) {
+                               $profileFieldOldId = $labelProfileFieldsOld[$profileField->label];
+                               /** @var Entity\ProfileField $foundProfileFieldOld */
+                               $foundProfileFieldOld = $profileFieldsOld[$profileFieldOldId];
+                               $foundProfileFieldOld->update(
+                                       $profileField->value,
+                                       $order,
+                                       $profileField->permissionSet
+                               );
+
+                               $savedProfileFields->append($this->save($foundProfileFieldOld));
+                       } else {
+                               $profileField->setOrder($order);
+                               $savedProfileFields->append($this->save($profileField));
+                       }
+
+                       $order++;
+               }
+
+               return $savedProfileFields;
+       }
+}
diff --git a/src/Security/PermissionSet/Depository/PermissionSet.php b/src/Security/PermissionSet/Depository/PermissionSet.php
deleted file mode 100644 (file)
index b91f452..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Security\PermissionSet\Depository;
-
-use Exception;
-use Friendica\BaseDepository;
-use Friendica\Database\Database;
-use Friendica\Model\Contact;
-use Friendica\Model\Group;
-use Friendica\Network\HTTPException\NotFoundException;
-use Friendica\Security\PermissionSet\Factory;
-use Friendica\Security\PermissionSet\Collection;
-use Friendica\Security\PermissionSet\Entity;
-use Friendica\Util\ACLFormatter;
-use Psr\Log\LoggerInterface;
-
-class PermissionSet extends BaseDepository
-{
-       /** @var int Virtual permission set id for public permission */
-       const PUBLIC = 0;
-
-       /** @var Factory\PermissionSet */
-       protected $factory;
-
-       protected static $table_name = 'permissionset';
-
-       /** @var ACLFormatter */
-       private $aclFormatter;
-
-       public function __construct(Database $database, LoggerInterface $logger, Factory\PermissionSet $factory, ACLFormatter $aclFormatter)
-       {
-               parent::__construct($database, $logger, $factory);
-
-               $this->aclFormatter = $aclFormatter;
-       }
-
-       /**
-        * replaces the PUBLIC id for the public permissionSet
-        * (no need to create the default permission set over and over again)
-        *
-        * @param $condition
-        */
-       private function checkPublicSelect(&$condition)
-       {
-               if (empty($condition['allow_cid']) &&
-                       empty($condition['allow_gid']) &&
-                       empty($condition['deny_cid']) &&
-                       empty($condition['deny_gid'])) {
-                       $condition['uid'] = self::PUBLIC;
-               }
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        *
-        * @return Entity\PermissionSet
-        * @throws NotFoundException
-        */
-       private function selectOne(array $condition, array $params = []): Entity\PermissionSet
-       {
-               return parent::_selectOne($condition, $params);
-       }
-
-       private function select(array $condition, array $params = []): Collection\PermissionSets
-       {
-               return new Collection\PermissionSets(parent::_select($condition, $params)->getArrayCopy());
-       }
-
-       /**
-        * Converts a given PermissionSet into a DB compatible row array
-        *
-        * @param Entity\PermissionSet $permissionSet
-        *
-        * @return array
-        */
-       protected function convertToTableRow(Entity\PermissionSet $permissionSet): array
-       {
-               return [
-                       'uid'       => $permissionSet->uid,
-                       'allow_cid' => $this->aclFormatter->toString($permissionSet->allow_cid),
-                       'allow_gid' => $this->aclFormatter->toString($permissionSet->allow_gid),
-                       'deny_cid'  => $this->aclFormatter->toString($permissionSet->deny_cid),
-                       'deny_gid'  => $this->aclFormatter->toString($permissionSet->deny_gid),
-               ];
-       }
-
-       /**
-        * @param int $id  A PermissionSet table row id or self::PUBLIC
-        * @param int $uid The owner of the PermissionSet
-        * @return Entity\PermissionSet
-        * @throws NotFoundException
-        */
-       public function selectOneById(int $id, int $uid): Entity\PermissionSet
-       {
-               if ($id === self::PUBLIC) {
-                       return $this->factory->createFromString($uid);
-               }
-
-               return $this->selectOne(['id' => $id, 'uid' => $uid]);
-       }
-
-       /**
-        * Returns a permission set collection for a given contact
-        *
-        * @param int $cid Contact id of the visitor
-        * @param int $uid User id whom the items belong, used for ownership check.
-        *
-        * @return Collection\PermissionSets
-        */
-       public function selectByContactId(int $cid, int $uid): Collection\PermissionSets
-       {
-               $cdata = Contact::getPublicAndUserContactID($cid, $uid);
-               if (!empty($cdata)) {
-                       $public_contact_str = $this->aclFormatter->toString($cdata['public']);
-                       $user_contact_str   = $this->aclFormatter->toString($cdata['user']);
-                       $cid                = $cdata['user'];
-               } else {
-                       $public_contact_str = $this->aclFormatter->toString($cid);
-                       $user_contact_str   = '';
-               }
-
-               $groups = [];
-               if (!empty($user_contact_str) && $this->db->exists('contact', [
-                       'id' => $cid,
-                       'uid' => $uid,
-                       'blocked' => false
-               ])) {
-                       $groups = Group::getIdsByContactId($cid);
-               }
-
-               $group_str = '<<>>'; // should be impossible to match
-               foreach ($groups as $group_id) {
-                       $group_str .= '|<' . preg_quote($group_id) . '>';
-               }
-
-               if (!empty($user_contact_str)) {
-                       $condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR `deny_cid` REGEXP ? OR deny_gid REGEXP ?)
-                               AND (allow_cid REGEXP ? OR allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
-                               $uid, $user_contact_str, $public_contact_str, $group_str,
-                               $user_contact_str, $public_contact_str, $group_str];
-               } else {
-                       $condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
-                               AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
-                               $uid, $public_contact_str, $group_str, $public_contact_str, $group_str];
-               }
-
-               return $this->select($condition);
-       }
-
-       /**
-        * Fetch the default PermissionSet for a given user, create it if it doesn't exist
-        *
-        * @param int $uid
-        *
-        * @return Entity\PermissionSet
-        * @throws Exception
-        */
-       public function selectDefaultForUser(int $uid): Entity\PermissionSet
-       {
-               $self_contact = Contact::selectFirst(['id'], ['uid' => $uid, 'self' => true]);
-
-               return $this->selectOrCreate($this->factory->createFromString(
-                       $uid,
-                       $this->aclFormatter->toString($self_contact['id'])
-               ));
-       }
-
-       /**
-        * Fetch the public PermissionSet
-        *
-        * @param int $uid
-        *
-        * @return Entity\PermissionSet
-        */
-       public function selectPublicForUser(int $uid): Entity\PermissionSet
-       {
-               return $this->factory->createFromString($uid, '', '', '', '', self::PUBLIC);
-       }
-
-       /**
-        * Selects or creates a PermissionSet based on it's fields
-        *
-        * @param Entity\PermissionSet $permissionSet
-        *
-        * @return Entity\PermissionSet
-        */
-       public function selectOrCreate(Entity\PermissionSet $permissionSet): Entity\PermissionSet
-       {
-               if ($permissionSet->id) {
-                       return $permissionSet;
-               }
-
-               // Don't select/update Public permission sets
-               if ($permissionSet->isPublic()) {
-                       return $this->selectPublicForUser($permissionSet->uid);
-               }
-
-               try {
-                       return $this->selectOne($this->convertToTableRow($permissionSet));
-               } catch (NotFoundException $exception) {
-                       return $this->save($permissionSet);
-               }
-       }
-
-       /**
-        * @param Entity\PermissionSet $permissionSet
-        *
-        * @return Entity\PermissionSet
-        * @throws NotFoundException
-        */
-       public function save(Entity\PermissionSet $permissionSet): Entity\PermissionSet
-       {
-               // Don't save/update the common public PermissionSet
-               if ($permissionSet->isPublic()) {
-                       return $this->selectPublicForUser($permissionSet->uid);
-               }
-
-               $fields = $this->convertToTableRow($permissionSet);
-
-               if ($permissionSet->id) {
-                       $this->db->update(self::$table_name, $fields, ['id' => $permissionSet->id]);
-               } else {
-                       $this->db->insert(self::$table_name, $fields);
-
-                       $permissionSet = $this->selectOneById($this->db->lastInsertId(), $permissionSet->uid);
-               }
-
-               return $permissionSet;
-       }
-}
index 6a04093315f20f3887b424832e8e0876b13fc7a8..830c631a4cb67104bfaa366f9fbb4c70d373593c 100644 (file)
@@ -3,7 +3,7 @@
 namespace Friendica\Security\PermissionSet\Entity;
 
 use Friendica\BaseEntity;
-use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
+use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
 
 /**
  * @property-read int|null $id
@@ -55,7 +55,7 @@ class PermissionSet extends BaseEntity
         */
        public function isPublic(): bool
        {
-               return (($this->id === PermissionSetDepository::PUBLIC) ||
+               return (($this->id === PermissionSetRepository::PUBLIC) ||
                                (is_null($this->id) &&
                                 empty($this->allow_cid) &&
                                 empty($this->allow_gid) &&
diff --git a/src/Security/PermissionSet/Repository/PermissionSet.php b/src/Security/PermissionSet/Repository/PermissionSet.php
new file mode 100644 (file)
index 0000000..af02646
--- /dev/null
@@ -0,0 +1,250 @@
+<?php
+/**
+ * @copyright Copyright (C) 2010-2021, the Friendica project
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace Friendica\Security\PermissionSet\Repository;
+
+use Exception;
+use Friendica\BaseRepository;
+use Friendica\Database\Database;
+use Friendica\Model\Contact;
+use Friendica\Model\Group;
+use Friendica\Network\HTTPException\NotFoundException;
+use Friendica\Security\PermissionSet\Factory;
+use Friendica\Security\PermissionSet\Collection;
+use Friendica\Security\PermissionSet\Entity;
+use Friendica\Util\ACLFormatter;
+use Psr\Log\LoggerInterface;
+
+class PermissionSet extends BaseRepository
+{
+       /** @var int Virtual permission set id for public permission */
+       const PUBLIC = 0;
+
+       /** @var Factory\PermissionSet */
+       protected $factory;
+
+       protected static $table_name = 'permissionset';
+
+       /** @var ACLFormatter */
+       private $aclFormatter;
+
+       public function __construct(Database $database, LoggerInterface $logger, Factory\PermissionSet $factory, ACLFormatter $aclFormatter)
+       {
+               parent::__construct($database, $logger, $factory);
+
+               $this->aclFormatter = $aclFormatter;
+       }
+
+       /**
+        * replaces the PUBLIC id for the public permissionSet
+        * (no need to create the default permission set over and over again)
+        *
+        * @param $condition
+        */
+       private function checkPublicSelect(&$condition)
+       {
+               if (empty($condition['allow_cid']) &&
+                       empty($condition['allow_gid']) &&
+                       empty($condition['deny_cid']) &&
+                       empty($condition['deny_gid'])) {
+                       $condition['uid'] = self::PUBLIC;
+               }
+       }
+
+       /**
+        * @param array $condition
+        * @param array $params
+        *
+        * @return Entity\PermissionSet
+        * @throws NotFoundException
+        */
+       private function selectOne(array $condition, array $params = []): Entity\PermissionSet
+       {
+               return parent::_selectOne($condition, $params);
+       }
+
+       private function select(array $condition, array $params = []): Collection\PermissionSets
+       {
+               return new Collection\PermissionSets(parent::_select($condition, $params)->getArrayCopy());
+       }
+
+       /**
+        * Converts a given PermissionSet into a DB compatible row array
+        *
+        * @param Entity\PermissionSet $permissionSet
+        *
+        * @return array
+        */
+       protected function convertToTableRow(Entity\PermissionSet $permissionSet): array
+       {
+               return [
+                       'uid'       => $permissionSet->uid,
+                       'allow_cid' => $this->aclFormatter->toString($permissionSet->allow_cid),
+                       'allow_gid' => $this->aclFormatter->toString($permissionSet->allow_gid),
+                       'deny_cid'  => $this->aclFormatter->toString($permissionSet->deny_cid),
+                       'deny_gid'  => $this->aclFormatter->toString($permissionSet->deny_gid),
+               ];
+       }
+
+       /**
+        * @param int $id  A PermissionSet table row id or self::PUBLIC
+        * @param int $uid The owner of the PermissionSet
+        * @return Entity\PermissionSet
+        * @throws NotFoundException
+        */
+       public function selectOneById(int $id, int $uid): Entity\PermissionSet
+       {
+               if ($id === self::PUBLIC) {
+                       return $this->factory->createFromString($uid);
+               }
+
+               return $this->selectOne(['id' => $id, 'uid' => $uid]);
+       }
+
+       /**
+        * Returns a permission set collection for a given contact
+        *
+        * @param int $cid Contact id of the visitor
+        * @param int $uid User id whom the items belong, used for ownership check.
+        *
+        * @return Collection\PermissionSets
+        */
+       public function selectByContactId(int $cid, int $uid): Collection\PermissionSets
+       {
+               $cdata = Contact::getPublicAndUserContactID($cid, $uid);
+               if (!empty($cdata)) {
+                       $public_contact_str = $this->aclFormatter->toString($cdata['public']);
+                       $user_contact_str   = $this->aclFormatter->toString($cdata['user']);
+                       $cid                = $cdata['user'];
+               } else {
+                       $public_contact_str = $this->aclFormatter->toString($cid);
+                       $user_contact_str   = '';
+               }
+
+               $groups = [];
+               if (!empty($user_contact_str) && $this->db->exists('contact', [
+                       'id' => $cid,
+                       'uid' => $uid,
+                       'blocked' => false
+               ])) {
+                       $groups = Group::getIdsByContactId($cid);
+               }
+
+               $group_str = '<<>>'; // should be impossible to match
+               foreach ($groups as $group_id) {
+                       $group_str .= '|<' . preg_quote($group_id) . '>';
+               }
+
+               if (!empty($user_contact_str)) {
+                       $condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR `deny_cid` REGEXP ? OR deny_gid REGEXP ?)
+                               AND (allow_cid REGEXP ? OR allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
+                               $uid, $user_contact_str, $public_contact_str, $group_str,
+                               $user_contact_str, $public_contact_str, $group_str];
+               } else {
+                       $condition = ["`uid` = ? AND (NOT (`deny_cid` REGEXP ? OR deny_gid REGEXP ?)
+                               AND (allow_cid REGEXP ? OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))",
+                               $uid, $public_contact_str, $group_str, $public_contact_str, $group_str];
+               }
+
+               return $this->select($condition);
+       }
+
+       /**
+        * Fetch the default PermissionSet for a given user, create it if it doesn't exist
+        *
+        * @param int $uid
+        *
+        * @return Entity\PermissionSet
+        * @throws Exception
+        */
+       public function selectDefaultForUser(int $uid): Entity\PermissionSet
+       {
+               $self_contact = Contact::selectFirst(['id'], ['uid' => $uid, 'self' => true]);
+
+               return $this->selectOrCreate($this->factory->createFromString(
+                       $uid,
+                       $this->aclFormatter->toString($self_contact['id'])
+               ));
+       }
+
+       /**
+        * Fetch the public PermissionSet
+        *
+        * @param int $uid
+        *
+        * @return Entity\PermissionSet
+        */
+       public function selectPublicForUser(int $uid): Entity\PermissionSet
+       {
+               return $this->factory->createFromString($uid, '', '', '', '', self::PUBLIC);
+       }
+
+       /**
+        * Selects or creates a PermissionSet based on it's fields
+        *
+        * @param Entity\PermissionSet $permissionSet
+        *
+        * @return Entity\PermissionSet
+        */
+       public function selectOrCreate(Entity\PermissionSet $permissionSet): Entity\PermissionSet
+       {
+               if ($permissionSet->id) {
+                       return $permissionSet;
+               }
+
+               // Don't select/update Public permission sets
+               if ($permissionSet->isPublic()) {
+                       return $this->selectPublicForUser($permissionSet->uid);
+               }
+
+               try {
+                       return $this->selectOne($this->convertToTableRow($permissionSet));
+               } catch (NotFoundException $exception) {
+                       return $this->save($permissionSet);
+               }
+       }
+
+       /**
+        * @param Entity\PermissionSet $permissionSet
+        *
+        * @return Entity\PermissionSet
+        * @throws NotFoundException
+        */
+       public function save(Entity\PermissionSet $permissionSet): Entity\PermissionSet
+       {
+               // Don't save/update the common public PermissionSet
+               if ($permissionSet->isPublic()) {
+                       return $this->selectPublicForUser($permissionSet->uid);
+               }
+
+               $fields = $this->convertToTableRow($permissionSet);
+
+               if ($permissionSet->id) {
+                       $this->db->update(self::$table_name, $fields, ['id' => $permissionSet->id]);
+               } else {
+                       $this->db->insert(self::$table_name, $fields);
+
+                       $permissionSet = $this->selectOneById($this->db->lastInsertId(), $permissionSet->uid);
+               }
+
+               return $permissionSet;
+       }
+}
diff --git a/tests/src/Profile/ProfileField/Depository/ProfileFieldTest.php b/tests/src/Profile/ProfileField/Depository/ProfileFieldTest.php
deleted file mode 100644 (file)
index 87ea6ca..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-<?php
-
-namespace Friendica\Test\src\Profile\ProfileField\Depository;
-
-use Friendica\Profile\ProfileField\Collection\ProfileFields;
-use Friendica\Profile\ProfileField\Depository\ProfileField as ProfileFieldDepository;
-use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
-use Friendica\Profile\ProfileField\Factory\ProfileField as ProfileFieldFactory;
-use Friendica\Security\PermissionSet\Depository\PermissionSet;
-use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
-use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
-use Friendica\Test\FixtureTest;
-use Friendica\DI;
-
-class ProfileFieldTest extends FixtureTest
-{
-       /** @var ProfileFieldDepository */
-       private $depository;
-       /** @var ProfileFieldFactory */
-       private $factory;
-       /** @var PermissionSetFactory */
-       private $permissionSetFactory;
-       /** @var PermissionSetDepository */
-       private $permissionSetDepository;
-
-       public function setUp(): void
-       {
-               parent::setUp();
-
-               $this->depository              = DI::profileField();
-               $this->factory                 = DI::profileFieldFactory();
-               $this->permissionSetFactory    = DI::permissionSetFactory();
-               $this->permissionSetDepository = DI::permissionSet();
-       }
-
-       /**
-        * Test create ProfileField without a valid PermissionSet
-        */
-       public function testSavingWithoutPermissionSet()
-       {
-               self::expectExceptionMessage('PermissionSet needs to be saved first.');
-               self::expectException(ProfileFieldPersistenceException::class);
-
-               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetFactory->createFromString(42, '', '<~>'));
-
-               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
-
-               $this->depository->save($profileField);
-       }
-
-       /**
-        * Test saving a new entity
-        */
-       public function testSaveNew()
-       {
-               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
-
-               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
-
-               $savedProfileField = $this->depository->save($profileField);
-
-               self::assertNotNull($savedProfileField->id);
-               self::assertNull($profileField->id);
-
-               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
-
-               self::assertEquals($savedProfileField, $selectedProfileField);
-
-               $profileFields = new ProfileFields([$selectedProfileField]);
-               $this->depository->deleteCollection($profileFields);
-       }
-
-       /**
-        * Test updating the order of a ProfileField
-        */
-       public function testUpdateOrder()
-       {
-               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
-
-               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
-
-               $savedProfileField = $this->depository->save($profileField);
-
-               self::assertNotNull($savedProfileField->id);
-               self::assertNull($profileField->id);
-
-               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
-
-               self::assertEquals($savedProfileField, $selectedProfileField);
-
-               $selectedProfileField->setOrder(66);
-
-               $updatedOrderProfileField = $this->depository->save($selectedProfileField);
-
-               self::assertEquals($selectedProfileField->id, $updatedOrderProfileField->id);
-               self::assertEquals(66, $updatedOrderProfileField->order);
-
-               // Even using the ID of the old, saved ProfileField returns the right instance
-               $updatedFromOldProfileField = $this->depository->selectOneById($savedProfileField->id);
-               self::assertEquals(66, $updatedFromOldProfileField->order);
-
-               $profileFields = new ProfileFields([$updatedFromOldProfileField]);
-               $this->depository->deleteCollection($profileFields);
-       }
-
-       /**
-        * Test updating a whole entity
-        */
-       public function testUpdate()
-       {
-               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetDepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
-
-               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
-
-               $savedProfileField = $this->depository->save($profileField);
-
-               self::assertNotNull($savedProfileField->id);
-               self::assertNull($profileField->id);
-
-               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
-
-               self::assertEquals($savedProfileField, $selectedProfileField);
-
-               $savedProfileField->update('another', 5, $this->permissionSetDepository->selectPublicForUser(42));
-               self::assertEquals(PermissionSet::PUBLIC, $savedProfileField->permissionSet->id);
-
-               $publicProfileField = $this->depository->save($savedProfileField);
-
-               self::assertEquals($this->permissionSetDepository->selectPublicForUser(42), $publicProfileField->permissionSet);
-               self::assertEquals('another', $publicProfileField->value);
-               self::assertEquals(5, $publicProfileField->order);
-
-               $profileFields = new ProfileFields([$publicProfileField]);
-               $this->depository->deleteCollection($profileFields);
-       }
-}
index 8acd1d94caffcc43b0793bf2a59356869ba29eef..275a1d59721f6f399d31a1e4846efa7ea8ebea18 100644 (file)
@@ -6,7 +6,7 @@ use Friendica\Profile\ProfileField\Entity\ProfileField;
 use Friendica\Profile\ProfileField\Exception\ProfileFieldNotFoundException;
 use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException;
 use Friendica\Profile\ProfileField\Factory\ProfileField as ProfileFieldFactory;
-use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
+use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
 use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
 use Friendica\Test\MockedTest;
 use Friendica\Util\ACLFormatter;
@@ -16,8 +16,8 @@ use Mockery\MockInterface;
 
 class ProfileFieldTest extends MockedTest
 {
-       /** @var MockInterface|PermissionSetDepository */
-       protected $permissionSetDepository;
+       /** @var MockInterface|PermissionSetRepository */
+       protected $permissionSetRepository;
        /** @var ProfileFieldFactory */
        protected $profileFieldFactory;
        /** @var MockInterface|PermissionSetFactory */
@@ -27,7 +27,7 @@ class ProfileFieldTest extends MockedTest
        {
                parent::setUp();
 
-               $this->permissionSetDepository = \Mockery::mock(PermissionSetDepository::class);
+               $this->permissionSetRepository = \Mockery::mock(PermissionSetRepository::class);
                $this->permissionSetFactory    = new PermissionSetFactory(new VoidLogger(), new ACLFormatter());
                $this->profileFieldFactory     = new ProfileFieldFactory(new VoidLogger(), $this->permissionSetFactory);
        }
@@ -180,7 +180,7 @@ class ProfileFieldTest extends MockedTest
 
                $permissionSet = $this->permissionSetFactory->createFromTableRow(['uid' => $uid, 'id' => $psid]);
 
-               $this->permissionSetDepository->shouldReceive('selectOneById')->with($psid, $uid)->andReturns($permissionSet);
+               $this->permissionSetRepository->shouldReceive('selectOneById')->with($psid, $uid)->andReturns($permissionSet);
 
                self::assertEquals($psid, $entity->permissionSet->id);
        }
diff --git a/tests/src/Profile/ProfileField/Repository/ProfileFieldTest.php b/tests/src/Profile/ProfileField/Repository/ProfileFieldTest.php
new file mode 100644 (file)
index 0000000..0da41f5
--- /dev/null
@@ -0,0 +1,136 @@
+<?php
+
+namespace Friendica\Test\src\Profile\ProfileField\Repository;
+
+use Friendica\Profile\ProfileField\Collection\ProfileFields;
+use Friendica\Profile\ProfileField\Repository\ProfileField as ProfileFieldRepository;
+use Friendica\Profile\ProfileField\Exception\ProfileFieldPersistenceException;
+use Friendica\Profile\ProfileField\Factory\ProfileField as ProfileFieldFactory;
+use Friendica\Security\PermissionSet\Repository\PermissionSet;
+use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
+use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
+use Friendica\Test\FixtureTest;
+use Friendica\DI;
+
+class ProfileFieldTest extends FixtureTest
+{
+       /** @var ProfileFieldRepository */
+       private $depository;
+       /** @var ProfileFieldFactory */
+       private $factory;
+       /** @var PermissionSetFactory */
+       private $permissionSetFactory;
+       /** @var PermissionSetRepository */
+       private $permissionSetRepository;
+
+       public function setUp(): void
+       {
+               parent::setUp();
+
+               $this->depository              = DI::profileField();
+               $this->factory                 = DI::profileFieldFactory();
+               $this->permissionSetFactory    = DI::permissionSetFactory();
+               $this->permissionSetRepository = DI::permissionSet();
+       }
+
+       /**
+        * Test create ProfileField without a valid PermissionSet
+        */
+       public function testSavingWithoutPermissionSet()
+       {
+               self::expectExceptionMessage('PermissionSet needs to be saved first.');
+               self::expectException(ProfileFieldPersistenceException::class);
+
+               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetFactory->createFromString(42, '', '<~>'));
+
+               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
+
+               $this->depository->save($profileField);
+       }
+
+       /**
+        * Test saving a new entity
+        */
+       public function testSaveNew()
+       {
+               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
+
+               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
+
+               $savedProfileField = $this->depository->save($profileField);
+
+               self::assertNotNull($savedProfileField->id);
+               self::assertNull($profileField->id);
+
+               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
+
+               self::assertEquals($savedProfileField, $selectedProfileField);
+
+               $profileFields = new ProfileFields([$selectedProfileField]);
+               $this->depository->deleteCollection($profileFields);
+       }
+
+       /**
+        * Test updating the order of a ProfileField
+        */
+       public function testUpdateOrder()
+       {
+               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
+
+               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
+
+               $savedProfileField = $this->depository->save($profileField);
+
+               self::assertNotNull($savedProfileField->id);
+               self::assertNull($profileField->id);
+
+               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
+
+               self::assertEquals($savedProfileField, $selectedProfileField);
+
+               $selectedProfileField->setOrder(66);
+
+               $updatedOrderProfileField = $this->depository->save($selectedProfileField);
+
+               self::assertEquals($selectedProfileField->id, $updatedOrderProfileField->id);
+               self::assertEquals(66, $updatedOrderProfileField->order);
+
+               // Even using the ID of the old, saved ProfileField returns the right instance
+               $updatedFromOldProfileField = $this->depository->selectOneById($savedProfileField->id);
+               self::assertEquals(66, $updatedFromOldProfileField->order);
+
+               $profileFields = new ProfileFields([$updatedFromOldProfileField]);
+               $this->depository->deleteCollection($profileFields);
+       }
+
+       /**
+        * Test updating a whole entity
+        */
+       public function testUpdate()
+       {
+               $profileField = $this->factory->createFromValues(42, 0, 'public', 'value', $this->permissionSetRepository->save($this->permissionSetFactory->createFromString(42, '', '<~>')));
+
+               self::assertEquals($profileField->uid, $profileField->permissionSet->uid);
+
+               $savedProfileField = $this->depository->save($profileField);
+
+               self::assertNotNull($savedProfileField->id);
+               self::assertNull($profileField->id);
+
+               $selectedProfileField = $this->depository->selectOneById($savedProfileField->id);
+
+               self::assertEquals($savedProfileField, $selectedProfileField);
+
+               $savedProfileField->update('another', 5, $this->permissionSetRepository->selectPublicForUser(42));
+               self::assertEquals(PermissionSet::PUBLIC, $savedProfileField->permissionSet->id);
+
+               $publicProfileField = $this->depository->save($savedProfileField);
+
+               self::assertEquals($this->permissionSetRepository->selectPublicForUser(42), $publicProfileField->permissionSet);
+               self::assertEquals('another', $publicProfileField->value);
+               self::assertEquals(5, $publicProfileField->order);
+
+               $profileFields = new ProfileFields([$publicProfileField]);
+               $this->depository->deleteCollection($profileFields);
+       }
+}
diff --git a/tests/src/Security/PermissionSet/Depository/PermissionSetTest.php b/tests/src/Security/PermissionSet/Depository/PermissionSetTest.php
deleted file mode 100644 (file)
index 596b1e6..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-<?php
-
-namespace Friendica\Test\src\Security\PermissionSet\Depository;
-
-use Friendica\Security\PermissionSet\Depository\PermissionSet as PermissionSetDepository;
-use Friendica\Security\PermissionSet\Entity\PermissionSet;
-use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
-use Friendica\Test\FixtureTest;
-use Friendica\DI;
-
-class PermissionSetTest extends FixtureTest
-{
-       /** @var PermissionSetDepository */
-       private $depository;
-       /** @var PermissionSetFactory */
-       private $factory;
-
-       public function setUp(): void
-       {
-               parent::setUp();
-
-               $this->depository = DI::permissionSet();
-               $this->factory    = DI::permissionSetFactory();
-       }
-
-       public function testSelectOneByIdPublic()
-       {
-               $permissionSet = $this->depository->selectPublicForUser(1);
-
-               $this->assertInstanceOf(PermissionSet::class, $permissionSet);
-               self::assertEmpty($permissionSet->allow_cid);
-               self::assertEmpty($permissionSet->allow_gid);
-               self::assertEmpty($permissionSet->deny_cid);
-               self::assertEmpty($permissionSet->deny_gid);
-               self::assertEmpty(PermissionSetDepository::PUBLIC, $permissionSet->id);
-               self::assertEquals(1, $permissionSet->uid);
-       }
-
-       /**
-        * Test create/update PermissionSets
-        */
-       public function testSaving()
-       {
-               $permissionSet = $this->factory->createFromString(42, '', '<~>');
-
-               $permissionSet = $this->depository->selectOrCreate($permissionSet);
-
-               self::assertNotNull($permissionSet->id);
-
-               $permissionSetSelected = $this->depository->selectOneById($permissionSet->id, 42);
-
-               self::assertEquals($permissionSet, $permissionSetSelected);
-
-               $newPermissionSet   = $permissionSet->withAllowedContacts(['1', '2']);
-               $savedPermissionSet = $this->depository->save($newPermissionSet);
-
-               self::assertNotNull($savedPermissionSet->id);
-               self::assertNull($newPermissionSet->id);
-
-               $permissionSetSavedSelected = $this->depository->selectOneById($savedPermissionSet->id, 42);
-
-               self::assertEquals($savedPermissionSet, $permissionSetSavedSelected);
-       }
-}
diff --git a/tests/src/Security/PermissionSet/Repository/PermissionSetTest.php b/tests/src/Security/PermissionSet/Repository/PermissionSetTest.php
new file mode 100644 (file)
index 0000000..697c588
--- /dev/null
@@ -0,0 +1,64 @@
+<?php
+
+namespace Friendica\Test\src\Security\PermissionSet\Repository;
+
+use Friendica\Security\PermissionSet\Repository\PermissionSet as PermissionSetRepository;
+use Friendica\Security\PermissionSet\Entity\PermissionSet;
+use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory;
+use Friendica\Test\FixtureTest;
+use Friendica\DI;
+
+class PermissionSetTest extends FixtureTest
+{
+       /** @var PermissionSetRepository */
+       private $repository;
+       /** @var PermissionSetFactory */
+       private $factory;
+
+       public function setUp(): void
+       {
+               parent::setUp();
+
+               $this->repository = DI::permissionSet();
+               $this->factory    = DI::permissionSetFactory();
+       }
+
+       public function testSelectOneByIdPublic()
+       {
+               $permissionSet = $this->repository->selectPublicForUser(1);
+
+               $this->assertInstanceOf(PermissionSet::class, $permissionSet);
+               self::assertEmpty($permissionSet->allow_cid);
+               self::assertEmpty($permissionSet->allow_gid);
+               self::assertEmpty($permissionSet->deny_cid);
+               self::assertEmpty($permissionSet->deny_gid);
+               self::assertEmpty(PermissionSetRepository::PUBLIC, $permissionSet->id);
+               self::assertEquals(1, $permissionSet->uid);
+       }
+
+       /**
+        * Test create/update PermissionSets
+        */
+       public function testSaving()
+       {
+               $permissionSet = $this->factory->createFromString(42, '', '<~>');
+
+               $permissionSet = $this->repository->selectOrCreate($permissionSet);
+
+               self::assertNotNull($permissionSet->id);
+
+               $permissionSetSelected = $this->repository->selectOneById($permissionSet->id, 42);
+
+               self::assertEquals($permissionSet, $permissionSetSelected);
+
+               $newPermissionSet   = $permissionSet->withAllowedContacts(['1', '2']);
+               $savedPermissionSet = $this->repository->save($newPermissionSet);
+
+               self::assertNotNull($savedPermissionSet->id);
+               self::assertNull($newPermissionSet->id);
+
+               $permissionSetSavedSelected = $this->repository->selectOneById($savedPermissionSet->id, 42);
+
+               self::assertEquals($savedPermissionSet, $permissionSetSavedSelected);
+       }
+}
index 85f407d36ce223e1a2d222f967bbf7a1918638ed..a2999ed5a566bcec3c98aac516930f71feb8eac5 100644 (file)
@@ -55,7 +55,7 @@ use Friendica\Model\Photo;
 use Friendica\Model\Post;
 use Friendica\Model\Profile;
 use Friendica\Model\Storage;
-use Friendica\Security\PermissionSet\Depository\PermissionSet;
+use Friendica\Security\PermissionSet\Repository\PermissionSet;
 use Friendica\Worker\Delivery;
 
 // Post-update script of PR 5751