+++ /dev/null
-<?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);
- }
-}
--- /dev/null
+<?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);
+ }
+}
+++ /dev/null
-<?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);
- }
- }
-}
--- /dev/null
+<?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);
+ }
+ }
+}
+++ /dev/null
-<?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);
- }
- }
-}
--- /dev/null
+<?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);
+ }
+ }
+}
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;
//
/**
- * @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);
}
/**
}
/**
- * @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);
}
/**
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
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
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
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
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;
{
/** @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;
}
$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();
{
$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);
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
+++ /dev/null
-<?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;
- }
-}
+++ /dev/null
-<?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);
- }
-}
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;
{
/** @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);
--- /dev/null
+<?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;
+ }
+}
--- /dev/null
+<?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);
+ }
+}
+++ /dev/null
-<?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;
- }
-}
--- /dev/null
+<?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;
+ }
+}
+++ /dev/null
-<?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;
- }
-}
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
*/
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) &&
--- /dev/null
+<?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;
+ }
+}
+++ /dev/null
-<?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);
- }
-}
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;
class ProfileFieldTest extends MockedTest
{
- /** @var MockInterface|PermissionSetDepository */
- protected $permissionSetDepository;
+ /** @var MockInterface|PermissionSetRepository */
+ protected $permissionSetRepository;
/** @var ProfileFieldFactory */
protected $profileFieldFactory;
/** @var MockInterface|PermissionSetFactory */
{
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);
}
$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);
}
--- /dev/null
+<?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);
+ }
+}
+++ /dev/null
-<?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);
- }
-}
--- /dev/null
+<?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);
+ }
+}
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