]> git.mxchange.org Git - friendica.git/commitdiff
Move Introduction to new depository paradigm
authorPhilipp <admin@philipp.info>
Mon, 18 Oct 2021 20:12:49 +0000 (22:12 +0200)
committerPhilipp <admin@philipp.info>
Thu, 21 Oct 2021 19:49:20 +0000 (21:49 +0200)
16 files changed:
doc/Developer-Domain-Driven-Design.md
src/Collection/Introductions.php [deleted file]
src/Contact/Introduction/Collection/Introductions.php [new file with mode: 0644]
src/Contact/Introduction/Depository/Introduction.php [new file with mode: 0644]
src/Contact/Introduction/Entity/Introduction.php [new file with mode: 0644]
src/Contact/Introduction/Exception/IntroductionNotFoundException.php [new file with mode: 0644]
src/Contact/Introduction/Exception/IntroductionPersistenceException.php [new file with mode: 0644]
src/Contact/Introduction/Factory/Introduction.php [new file with mode: 0644]
src/DI.php
src/Factory/Api/Mastodon/FollowRequest.php
src/Model/Contact/Introduction.php [new file with mode: 0644]
src/Model/Introduction.php [deleted file]
src/Module/Api/Mastodon/FollowRequests.php
src/Module/FollowConfirm.php
src/Module/Notifications/Notification.php
src/Repository/Introduction.php [deleted file]

index b8d886aa0db3da91852d4bd3a4cee53d96e21d15..1e77dd2f0b65f3cafbe7c58731d33303386166e4 100644 (file)
@@ -36,17 +36,18 @@ doSomething($intros);
 ```
 
 After:
+
 ```php
-function doSomething(\Friendica\Collection\Introductions $intros)
+function doSomething(\Friendica\Contact\Introductions\Collection\Introductions $intros)
 {
     foreach ($intros as $intro) {
-        /** @var $intro \Friendica\Model\Introduction */
+        /** @var $intro \Friendica\Contact\Introductions\Entity\Introduction */
         $introId = $intro->id;
     }
 }
 
-/** @var $intros \Friendica\Collection\Introductions */
-$intros = \Friendica\DI::intro()->select(['uid' => local_user()]);
+/** @var $intros \Friendica\Contact\Introductions\Collection\Introductions */
+$intros = \Friendica\DI::intro()->selecForUser(local_user());
 
 doSomething($intros);
 ```
diff --git a/src/Collection/Introductions.php b/src/Collection/Introductions.php
deleted file mode 100644 (file)
index e954331..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Collection;
-
-use Friendica\BaseCollection;
-
-class Introductions extends BaseCollection
-{
-
-}
diff --git a/src/Contact/Introduction/Collection/Introductions.php b/src/Contact/Introduction/Collection/Introductions.php
new file mode 100644 (file)
index 0000000..4df89ce
--- /dev/null
@@ -0,0 +1,9 @@
+<?php
+
+namespace Friendica\Contact\Introduction\Collection;
+
+use Friendica\BaseCollection;
+
+class Introductions extends BaseCollection
+{
+}
diff --git a/src/Contact/Introduction/Depository/Introduction.php b/src/Contact/Introduction/Depository/Introduction.php
new file mode 100644 (file)
index 0000000..f697c99
--- /dev/null
@@ -0,0 +1,168 @@
+<?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,
+                       'fid'         => $introduction->fid,
+                       'contact-id'  => $introduction->cid,
+                       'suggest-cid' => $introduction->sid,
+                       'knowyou'     => $introduction->knowyou ? 1 : 0,
+                       'duplex'      => $introduction->duplex ? 1 : 0,
+                       'note'        => $introduction->note,
+                       'hash'        => $introduction->hash,
+                       'blocked'     => $introduction->blocked ? 1 : 0,
+                       'ignore'      => $introduction->ignore ? 1 : 0
+               ];
+       }
+
+       /**
+        * @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());
+       }
+
+       /**
+        * @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);
+                       $fields['datetime'] = DateTimeFormat::utcNow();
+
+                       if ($introduction->id) {
+                               $this->db->update(self::$table_name, $fields, ['id' => $introduction->id]);
+                               return $this->factory->createFromTableRow($fields);
+                       } else {
+                               $this->db->insert(self::$table_name, $fields);
+                               return $this->selectOneById($this->db->lastInsertId(), $introduction->uid);
+                       }
+               } catch (\Exception $exception) {
+                       throw new IntroductionPersistenceException(sprintf('Cannot insert/update the Introduction %d for user %d', $introduction->id, $introduction->uid), $exception);
+               }
+       }
+}
diff --git a/src/Contact/Introduction/Entity/Introduction.php b/src/Contact/Introduction/Entity/Introduction.php
new file mode 100644 (file)
index 0000000..b9842a8
--- /dev/null
@@ -0,0 +1,98 @@
+<?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\Entity;
+
+use Friendica\BaseEntity;
+
+/**
+ * @property-read int $uid
+ * @property-read int $fid
+ * @property-read int $cid
+ * @property-read int $sid
+ * @property-read bool $knowyou
+ * @property-read bool $duplex
+ * @property-read string $note
+ * @property-read string $hash
+ * @property-read \DateTime $datetime
+ * @property-read bool $blocked
+ * @property-read bool $ignore
+ * @property-read int|null $id
+ */
+class Introduction extends BaseEntity
+{
+       /** @var int */
+       protected $uid;
+       /** @var int */
+       protected $fid;
+       /** @var int */
+       protected $cid;
+       /** @var int */
+       protected $sid;
+       /** @var bool */
+       protected $knowyou;
+       /** @var bool */
+       protected $duplex;
+       /** @var string */
+       protected $note;
+       /** @var string */
+       protected $hash;
+       /** @var \DateTime */
+       protected $datetime;
+       /** @var bool */
+       protected $blocked;
+       /** @var bool */
+       protected $ignore;
+       /** @var int|null */
+       protected $id;
+
+       /**
+        * @param int      $uid
+        * @param int      $fid
+        * @param int      $cid
+        * @param bool     $knowyou
+        * @param bool     $duplex
+        * @param string   $note
+        * @param string   $hash
+        * @param bool     $blocked
+        * @param bool     $ignore
+        * @param int|null $id
+        */
+       public function __construct(int $uid, int $fid, int $cid, int $sid, bool $knowyou, bool $duplex, string $note, string $hash, \DateTime $datetime, bool $blocked, bool $ignore, ?int $id)
+       {
+               $this->uid     = $uid;
+               $this->fid     = $fid;
+               $this->cid     = $cid;
+               $this->sid     = $sid;
+               $this->knowyou = $knowyou;
+               $this->duplex  = $duplex;
+               $this->note    = $note;
+               $this->hash    = $hash;
+               $this->blocked = $blocked;
+               $this->ignore  = $ignore;
+               $this->id      = $id;
+       }
+
+       public function setIgnore()
+       {
+               $this->ignore = true;
+       }
+}
diff --git a/src/Contact/Introduction/Exception/IntroductionNotFoundException.php b/src/Contact/Introduction/Exception/IntroductionNotFoundException.php
new file mode 100644 (file)
index 0000000..f48c9ea
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+
+namespace Friendica\Contact\Introduction\Exception;
+
+class IntroductionNotFoundException extends \OutOfBoundsException
+{
+       public function __construct($message = "", \Throwable $previous = null)
+       {
+               parent::__construct($message, 404, $previous);
+       }
+}
diff --git a/src/Contact/Introduction/Exception/IntroductionPersistenceException.php b/src/Contact/Introduction/Exception/IntroductionPersistenceException.php
new file mode 100644 (file)
index 0000000..99fb919
--- /dev/null
@@ -0,0 +1,11 @@
+<?php
+
+namespace Friendica\Contact\Introduction\Exception;
+
+class IntroductionPersistenceException extends \RuntimeException
+{
+       public function __construct($message = "", \Throwable $previous = null)
+       {
+               parent::__construct($message, 500, $previous);
+       }
+}
diff --git a/src/Contact/Introduction/Factory/Introduction.php b/src/Contact/Introduction/Factory/Introduction.php
new file mode 100644 (file)
index 0000000..5f9d837
--- /dev/null
@@ -0,0 +1,50 @@
+<?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\Factory;
+
+use Friendica\BaseFactory;
+use Friendica\Contact\Introduction\Entity;
+use Friendica\Capabilities\ICanCreateFromTableRow;
+
+class Introduction extends BaseFactory implements ICanCreateFromTableRow
+{
+       /**
+        * @inheritDoc
+        */
+       public function createFromTableRow(array $row): Entity\Introduction
+       {
+               return new Entity\Introduction(
+                       $row['uid'],
+                       $row['fid'],
+                       $row['contact-id'],
+                       $row['suggested-cid'],
+                       !empty($row['knowyou']),
+                       !empty($row['dupley']),
+                       $row['note'],
+                       $row['hash'],
+                       new \DateTime($row['datetime'], new \DateTimeZone('UTC')),
+                       !empty($row['blocked']),
+                       !empty($row['ignore']),
+                       $row['id'] ?? null
+               );
+       }
+}
index 31542e3d52dd30bebd34c47c8b8e10501fac0c8f..c00fb82c1d7a8d8956dd3c56e6c75e9f3b97080f 100644 (file)
@@ -435,11 +435,11 @@ abstract class DI
        }
 
        /**
-        * @return Repository\Introduction
+        * @return Contact\Introduction\Depository\Introduction
         */
        public static function intro()
        {
-               return self::$dice->create(Repository\Introduction::class);
+               return self::$dice->create(Contact\Introduction\Depository\Introduction::class);
        }
 
        public static function permissionSet(): Security\PermissionSet\Depository\PermissionSet
index f2be0e589aff5a40d0cfbfbdf61825deb71b4ef3..1d90c55f04d8b310d22a915bf66d557e8169f7dd 100644 (file)
@@ -23,9 +23,9 @@ namespace Friendica\Factory\Api\Mastodon;
 
 use Friendica\App\BaseURL;
 use Friendica\BaseFactory;
+use Friendica\Contact\Introduction\Entity\Introduction;
 use Friendica\Model\APContact;
 use Friendica\Model\Contact;
-use Friendica\Model\Introduction;
 use Friendica\Network\HTTPException;
 use ImagickException;
 use Psr\Log\LoggerInterface;
@@ -49,7 +49,7 @@ class FollowRequest extends BaseFactory
         */
        public function createFromIntroduction(Introduction $introduction): \Friendica\Object\Api\Mastodon\FollowRequest
        {
-               $cdata = Contact::getPublicAndUserContactID($introduction->{'contact-id'}, $introduction->uid);
+               $cdata = Contact::getPublicAndUserContactID($introduction->cid, $introduction->uid);
 
                if (empty($cdata)) {
                        $this->logger->warning('Wrong introduction data', ['Introduction' => $introduction]);
diff --git a/src/Model/Contact/Introduction.php b/src/Model/Contact/Introduction.php
new file mode 100644 (file)
index 0000000..692ba7b
--- /dev/null
@@ -0,0 +1,144 @@
+<?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\Model\Contact;
+
+use Friendica\Contact\Introduction\Entity;
+use Friendica\Core\Protocol;
+use Friendica\DI;
+use Friendica\Network\HTTPException;
+use Friendica\Model\Contact;
+use Friendica\Model\User;
+use Friendica\Protocol\ActivityPub;
+use Friendica\Protocol\Diaspora;
+use Friendica\Util\DateTimeFormat;
+
+class Introduction
+{
+       /**
+        * Confirms a follow request and sends a notice to the remote contact.
+        *
+        * @param Entity\Introduction $introduction
+        *
+        * @throws HTTPException\InternalServerErrorException
+        * @throws HTTPException\NotFoundException
+        * @throws \ImagickException
+        */
+       public static function confirm(Entity\Introduction $introduction): void
+       {
+               DI::logger()->info('Confirming follower', ['cid' => $introduction->cid]);
+
+               $contact = Contact::selectFirst([], ['id' => $introduction->cid, 'uid' => $introduction->uid]);
+
+               if (!$contact) {
+                       throw new HTTPException\NotFoundException('Contact record not found.');
+               }
+
+               $newRelation = $contact['rel'];
+               $writable    = $contact['writable'];
+
+               if (!empty($contact['protocol'])) {
+                       $protocol = $contact['protocol'];
+               } else {
+                       $protocol = $contact['network'];
+               }
+
+               if ($protocol == Protocol::ACTIVITYPUB) {
+                       ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $contact['uid']);
+               }
+
+               if (in_array($protocol, [Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
+                       if ($introduction->duplex) {
+                               $newRelation = Contact::FRIEND;
+                       } else {
+                               $newRelation = Contact::FOLLOWER;
+                       }
+
+                       if ($newRelation != Contact::FOLLOWER) {
+                               $writable = 1;
+                       }
+               }
+
+               $fields = [
+                       'name-date' => DateTimeFormat::utcNow(),
+                       'uri-date'  => DateTimeFormat::utcNow(),
+                       'blocked'   => false,
+                       'pending'   => false,
+                       'protocol'  => $protocol,
+                       'writable'  => $writable,
+                       'hidden'    => $hidden ?? $contact['hidden'],
+                       'rel'       => $newRelation,
+               ];
+               Contact::update($fields, ['id' => $contact['id']]);
+
+               array_merge($contact, $fields);
+
+               if ($newRelation == Contact::FRIEND) {
+                       if ($protocol == Protocol::DIASPORA) {
+                               $ret = Diaspora::sendShare(User::getById($contact['uid']), $contact);
+                               DI::logger()->info('share returns', ['return' => $ret]);
+                       } elseif ($protocol == Protocol::ACTIVITYPUB) {
+                               ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $contact['uid']);
+                       }
+               }
+       }
+
+       /**
+        * Discards the introduction and sends a rejection message to AP contacts.
+        *
+        * @param Entity\Introduction $introduction
+        *
+        * @throws HTTPException\InternalServerErrorException
+        * @throws \ImagickException
+        */
+       public static function discard(Entity\Introduction $introduction): void
+       {
+               // If it is a friend suggestion, the contact is not a new friend but an existing friend
+               // that should not be deleted.
+               if (!$introduction->fid) {
+                       // When the contact entry had been created just for that intro, we want to get rid of it now
+                       $condition = [
+                               'id'      => $introduction->cid,
+                               'uid'     => $introduction->uid,
+                               'self'    => false,
+                               'pending' => true,
+                               'rel'     => [0, Contact::FOLLOWER]];
+                       if (DI::dba()->exists('contact', $condition)) {
+                               Contact::remove($introduction->cid);
+                       } else {
+                               Contact::update(['pending' => false], ['id' => $introduction->cid]);
+                       }
+               }
+
+               $contact = Contact::selectFirst([], ['id' => $introduction->cid, 'uid' => $introduction->uid]);
+               if (!empty($contact)) {
+                       if (!empty($contact['protocol'])) {
+                               $protocol = $contact['protocol'];
+                       } else {
+                               $protocol = $contact['network'];
+                       }
+
+                       if ($protocol == Protocol::ACTIVITYPUB) {
+                               ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']);
+                       }
+               }
+       }
+}
diff --git a/src/Model/Introduction.php b/src/Model/Introduction.php
deleted file mode 100644 (file)
index aa71891..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Model;
-
-use Friendica\BaseModel;
-use Friendica\Core\Protocol;
-use Friendica\Database\Database;
-use Friendica\Network\HTTPException;
-use Friendica\Protocol\ActivityPub;
-use Friendica\Protocol\Diaspora;
-use Friendica\Repository;
-use Friendica\Util\DateTimeFormat;
-use Psr\Log\LoggerInterface;
-
-/**
- * @property int    uid
- * @property int    fid
- * @property int    contact-id
- * @property bool   knowyou
- * @property bool   duplex
- * @property string note
- * @property string hash
- * @property string datetime
- * @property bool   blocked
- * @property bool   ignore
- */
-class Introduction extends BaseModel
-{
-       /** @var Repository\Introduction */
-       protected $intro;
-
-       public function __construct(Database $dba, LoggerInterface $logger, Repository\Introduction $intro, array $data = [])
-       {
-               parent::__construct($dba, $logger, $data);
-
-               $this->intro = $intro;
-       }
-
-       /**
-        * Confirms a follow request and sends a notice to the remote contact.
-        *
-        * @param bool               $duplex       Is it a follow back?
-        * @param bool|null          $hidden       Should this contact be hidden? null = no change
-        * @return bool
-        * @throws HTTPException\InternalServerErrorException
-        * @throws HTTPException\NotFoundException
-        * @throws \ImagickException
-        */
-       public function confirm(bool $duplex = false, bool $hidden = null)
-       {
-               $this->logger->info('Confirming follower', ['cid' => $this->{'contact-id'}]);
-
-               $contact = Contact::selectFirst([], ['id' => $this->{'contact-id'}, 'uid' => $this->uid]);
-
-               if (!$contact) {
-                       throw new HTTPException\NotFoundException('Contact record not found.');
-               }
-
-               $newRelation = $contact['rel'];
-               $writable = $contact['writable'];
-
-               if (!empty($contact['protocol'])) {
-                       $protocol = $contact['protocol'];
-               } else {
-                       $protocol = $contact['network'];
-               }
-
-               if ($protocol == Protocol::ACTIVITYPUB) {
-                       ActivityPub\Transmitter::sendContactAccept($contact['url'], $contact['hub-verify'], $contact['uid']);
-               }
-
-               if (in_array($protocol, [Protocol::DIASPORA, Protocol::ACTIVITYPUB])) {
-                       if ($duplex) {
-                               $newRelation = Contact::FRIEND;
-                       } else {
-                               $newRelation = Contact::FOLLOWER;
-                       }
-
-                       if ($newRelation != Contact::FOLLOWER) {
-                               $writable = 1;
-                       }
-               }
-
-               $fields = [
-                       'name-date' => DateTimeFormat::utcNow(),
-                       'uri-date'  => DateTimeFormat::utcNow(),
-                       'blocked'   => false,
-                       'pending'   => false,
-                       'protocol'  => $protocol,
-                       'writable'  => $writable,
-                       'hidden'    => $hidden ?? $contact['hidden'],
-                       'rel'       => $newRelation,
-               ];
-               Contact::update($fields, ['id' => $contact['id']]);
-
-               array_merge($contact, $fields);
-
-               if ($newRelation == Contact::FRIEND) {
-                       if ($protocol == Protocol::DIASPORA) {
-                               $ret = Diaspora::sendShare(User::getById($contact['uid']), $contact);
-                               $this->logger->info('share returns', ['return' => $ret]);
-                       } elseif ($protocol == Protocol::ACTIVITYPUB) {
-                               ActivityPub\Transmitter::sendActivity('Follow', $contact['url'], $contact['uid']);
-                       }
-               }
-
-               return $this->intro->delete($this);
-       }
-
-       /**
-        * Silently ignores the introduction, hides it from notifications and prevents the remote contact from submitting
-        * additional follow requests.
-        *
-        * @return bool
-        * @throws \Exception
-        */
-       public function ignore()
-       {
-               $this->ignore = true;
-
-               return $this->intro->update($this);
-       }
-
-       /**
-        * Discards the introduction and sends a rejection message to AP contacts.
-        *
-        * @return bool
-        * @throws HTTPException\InternalServerErrorException
-        * @throws HTTPException\NotFoundException
-        * @throws \ImagickException
-        */
-       public function discard()
-       {
-               // If it is a friend suggestion, the contact is not a new friend but an existing friend
-               // that should not be deleted.
-               if (!$this->fid) {
-                       // When the contact entry had been created just for that intro, we want to get rid of it now
-                       $condition = ['id' => $this->{'contact-id'}, 'uid' => $this->uid,
-                               'self' => false, 'pending' => true, 'rel' => [0, Contact::FOLLOWER]];
-                       if ($this->dba->exists('contact', $condition)) {
-                               Contact::remove($this->{'contact-id'});
-                       } else {
-                               Contact::update(['pending' => false], ['id' => $this->{'contact-id'}]);
-                       }
-               }
-
-               $contact = Contact::selectFirst([], ['id' => $this->{'contact-id'}, 'uid' => $this->uid]);
-               if (!empty($contact)) {
-                       if (!empty($contact['protocol'])) {
-                               $protocol = $contact['protocol'];
-                       } else {
-                               $protocol = $contact['network'];
-                       }
-
-                       if ($protocol == Protocol::ACTIVITYPUB) {
-                               ActivityPub\Transmitter::sendContactReject($contact['url'], $contact['hub-verify'], $contact['uid']);
-                       }
-               }
-
-               return $this->intro->delete($this);
-       }
-}
index cb7d5da220cda51039fced22ee8269d534ae2181..dc6f336d6db13fe13a7f03899c985a3fc957da52 100644 (file)
@@ -23,6 +23,7 @@ namespace Friendica\Module\Api\Mastodon;
 
 use Friendica\Core\System;
 use Friendica\DI;
+use Friendica\Model\Contact;
 use Friendica\Module\BaseApi;
 use Friendica\Network\HTTPException;
 
@@ -34,7 +35,6 @@ class FollowRequests extends BaseApi
        /**
         * @param array $parameters
         * @throws HTTPException\BadRequestException
-        * @throws HTTPException\ForbiddenException
         * @throws HTTPException\InternalServerErrorException
         * @throws HTTPException\NotFoundException
         * @throws HTTPException\UnauthorizedException
@@ -48,25 +48,28 @@ class FollowRequests extends BaseApi
                self::checkAllowedScope(self::SCOPE_FOLLOW);
                $uid = self::getCurrentUserID();
 
-               $introduction = DI::intro()->selectFirst(['id' => $parameters['id'], 'uid' => $uid]);
+               $introduction = DI::intro()->selectOneById($parameters['id'], $uid);
 
-               $contactId = $introduction->{'contact-id'};
+               $contactId = $introduction->cid;
 
                switch ($parameters['action']) {
                        case 'authorize':
-                               $introduction->confirm();
-
+                               Contact\Introduction::confirm($introduction);
                                $relationship = DI::mstdnRelationship()->createFromContactId($contactId, $uid);
+
+                               DI::intro()->delete($introduction);
                                break;
                        case 'ignore':
-                               $introduction->ignore();
-
+                               $introduction->setIgnore();
                                $relationship = DI::mstdnRelationship()->createFromContactId($contactId, $uid);
+
+                               DI::intro()->save($introduction);
                                break;
                        case 'reject':
-                               $introduction->discard();
-
+                               Contact\Introduction::discard($introduction);
                                $relationship = DI::mstdnRelationship()->createFromContactId($contactId, $uid);
+
+                               DI::intro()->delete($introduction);
                                break;
                        default:
                                throw new HTTPException\BadRequestException('Unexpected action parameter, expecting "authorize", "ignore" or "reject"');
@@ -92,13 +95,7 @@ class FollowRequests extends BaseApi
                        'limit'  => 40, // Maximum number of results to return. Defaults to 40. Paginate using the HTTP Link header.
                ]);
 
-               $introductions = DI::intro()->selectByBoundaries(
-                       ['`uid` = ? AND NOT `ignore`', $uid],
-                       ['order' => ['id' => 'DESC']],
-                       $request['min_id'],
-                       $request['max_id'],
-                       $request['limit']
-               );
+               $introductions = DI::intro()->selectForUser($uid, $request['min_id'], $request['max_id'], $request['limit']);
 
                $return = [];
 
index f4e4c5ebf9725282ba45317ad37c02d4620f09f2..f028a3d3888fd9a7c90d5c431dcb1cf6a331b8d3 100644 (file)
@@ -21,12 +21,10 @@ class FollowConfirm extends BaseModule
                $duplex   = intval($_POST['duplex']     ?? 0);
                $hidden   = intval($_POST['hidden']     ?? 0);
 
-               $intro = DI::intro()->selectFirst(['id' => $intro_id, 'uid' => local_user()]);
-
-               $cid = $intro->{'contact-id'};
+               $intro = DI::intro()->selectOneById($intro_id, local_user());
 
                $intro->confirm($duplex, $hidden);
 
-               DI::baseUrl()->redirect('contact/' . intval($cid));
+               DI::baseUrl()->redirect('contact/' .  $intro->cid);
        }
 }
index 19ee410d2825c06cc4a77e9ef0edaa97b695b0b9..403b43781c02da0e815d09b64922a554dba47780 100644 (file)
@@ -24,6 +24,7 @@ namespace Friendica\Module\Notifications;
 use Friendica\BaseModule;
 use Friendica\Core\System;
 use Friendica\DI;
+use Friendica\Model\Contact;
 use Friendica\Module\Security\Login;
 use Friendica\Network\HTTPException;
 
@@ -50,14 +51,16 @@ class Notification extends BaseModule
                $request_id = $parameters['id'] ?? false;
 
                if ($request_id) {
-                       $intro = DI::intro()->selectFirst(['id' => $request_id, 'uid' => local_user()]);
+                       $intro = DI::intro()->selectOneById($request_id, local_user());
 
                        switch ($_POST['submit']) {
                                case DI::l10n()->t('Discard'):
-                                       $intro->discard();
+                                       Contact\Introduction::discard($intro);
+                                       DI::intro()->delete($intro);
                                        break;
                                case DI::l10n()->t('Ignore'):
-                                       $intro->ignore();
+                                       $intro->setIgnore();
+                                       DI::intro()->save($intro);
                                        break;
                        }
 
diff --git a/src/Repository/Introduction.php b/src/Repository/Introduction.php
deleted file mode 100644 (file)
index de95229..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php
-/**
- * @copyright Copyright (C) 2010-2021, the Friendica project
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- *
- */
-
-namespace Friendica\Repository;
-
-use Friendica\BaseRepository;
-use Friendica\Collection;
-use Friendica\Model;
-
-class Introduction extends BaseRepository
-{
-       protected static $table_name = 'intro';
-
-       protected static $model_class = Model\Introduction::class;
-
-       protected static $collection_class = Collection\Introductions::class;
-
-       /**
-        * @param array $data
-        * @return Model\Introduction
-        */
-       protected function create(array $data)
-       {
-               return new Model\Introduction($this->dba, $this->logger, $this, $data);
-       }
-
-       /**
-        * @param array $condition
-        * @return Model\Introduction
-        * @throws \Friendica\Network\HTTPException\NotFoundException
-        */
-       public function selectFirst(array $condition)
-       {
-               return parent::selectFirst($condition);
-       }
-
-       /**
-        * @param array $condition
-        * @param array $params
-        * @return Collection\Introductions
-        * @throws \Exception
-        */
-       public function select(array $condition = [], array $params = [])
-       {
-               return parent::select($condition, $params);
-       }
-
-       /**
-        * @param array    $condition
-        * @param array    $params
-        * @param int|null $min_id
-        * @param int|null $max_id
-        * @param int      $limit
-        * @return Collection\Introductions
-        * @throws \Exception
-        */
-       public function selectByBoundaries(array $condition = [], array $params = [], int $min_id = null, int $max_id = null, int $limit = self::LIMIT)
-       {
-               return parent::selectByBoundaries($condition, $params, $min_id, $max_id, $limit);
-       }
-}