diff --git a/appinfo/database.xml b/appinfo/database.xml index 5d750abb..7c99fbc5 100644 --- a/appinfo/database.xml +++ b/appinfo/database.xml @@ -5,59 +5,16 @@ false utf8 - - *dbprefix*social_accounts - - - - id - integer - 7 - true - true - true - true - - - - user_id - text - 63 - - - - account - text - 63 - - - - creation - timestamp - - - -
- *dbprefix*social_server_actors id - integer - 7 - true - true - true - true - - - - type text - 15 + 127 true + true @@ -74,6 +31,20 @@ true + + name + text + 127 + true + + + + summary + text + 500 + true + + public_key text @@ -94,6 +65,40 @@
+ + *dbprefix*social_server_follows + + + + id + text + 127 + true + true + + + + actor_id + text + 127 + true + + + + object_id + text + 127 + true + + + + creation + timestamp + + + +
+ *dbprefix*social_server_activities @@ -131,6 +136,7 @@ text 127 true + true @@ -215,11 +221,9 @@ id - integer - 8 - true + string + 127 true - true true @@ -230,6 +234,48 @@ true + + following + text + 127 + true + + + + followers + text + 127 + true + + + + inbox + text + 127 + true + + + + shared_inbox + text + 127 + true + + + + outbox + text + 127 + true + + + + featured + text + 127 + true + + url text @@ -238,9 +284,30 @@ - actor + preferred_username text - 8000 + 127 + true + + + + name + text + 127 + true + + + + summary + text + 500 + true + + + + public_key + text + 500 true diff --git a/lib/Db/ActorsRequest.php b/lib/Db/ActorsRequest.php index 46e30187..9cfdc578 100644 --- a/lib/Db/ActorsRequest.php +++ b/lib/Db/ActorsRequest.php @@ -31,7 +31,7 @@ namespace OCA\Social\Db; use OCA\Social\Exceptions\ActorDoesNotExistException; -use OCA\Social\Model\ActivityPub\Actor; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; use OCP\IDBConnection; @@ -54,19 +54,25 @@ class ActorsRequest extends ActorsRequestBuilder { /** - * create a new Actor in the database. + * create a new Person in the database. * - * @param Actor $actor + * @param Person $actor * * @return int * @throws \Exception */ - public function create(Actor $actor): int { + public function create(Person $actor) { + + $id = $this->configService->getRoot() . '@' . $actor->getPreferredUsername(); try { $qb = $this->getActorsInsertSql(); - $qb->setValue('type', $qb->createNamedParameter($actor->getType())) + + $qb->setValue('id', $qb->createNamedParameter($id)) +// ->setValue('type', $qb->createNamedParameter($actor->getType())) ->setValue('user_id', $qb->createNamedParameter($actor->getUserId())) + ->setValue('name', $qb->createNamedParameter($actor->getName())) + ->setValue('summary', $qb->createNamedParameter($actor->getSummary())) ->setValue( 'preferred_username', $qb->createNamedParameter($actor->getPreferredUsername()) ) @@ -74,8 +80,6 @@ class ActorsRequest extends ActorsRequestBuilder { ->setValue('private_key', $qb->createNamedParameter($actor->getPrivateKey())); $qb->execute(); - - return $qb->getLastInsertId(); } catch (\Exception $e) { throw $e; } @@ -87,10 +91,10 @@ class ActorsRequest extends ActorsRequestBuilder { * * @param string $username * - * @return Actor + * @return Person * @throws ActorDoesNotExistException */ - public function getFromUsername(string $username): Actor { + public function getFromUsername(string $username): Person { $qb = $this->getActorsSelectSql(); $this->limitToPreferredUsername($qb, $username); @@ -111,10 +115,10 @@ class ActorsRequest extends ActorsRequestBuilder { * * @param string $userId * - * @return Actor + * @return Person * @throws ActorDoesNotExistException */ - public function getFromUserId(string $userId): Actor { + public function getFromUserId(string $userId): Person { $qb = $this->getActorsSelectSql(); $this->limitToUserId($qb, $userId); diff --git a/lib/Db/ActorsRequestBuilder.php b/lib/Db/ActorsRequestBuilder.php index 4f480817..f19b44f5 100644 --- a/lib/Db/ActorsRequestBuilder.php +++ b/lib/Db/ActorsRequestBuilder.php @@ -31,7 +31,7 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; -use OCA\Social\Model\ActivityPub\Actor; +use OCA\Social\Model\ActivityPub\Person; use OCP\DB\QueryBuilder\IQueryBuilder; class ActorsRequestBuilder extends CoreRequestBuilder { @@ -76,7 +76,7 @@ class ActorsRequestBuilder extends CoreRequestBuilder { /** @noinspection PhpMethodParametersCountMismatchInspection */ $qb->select( - 'sa.id', 'sa.type', 'sa.user_id', 'sa.preferred_username', 'sa.public_key', + 'sa.id', 'sa.user_id', 'sa.preferred_username', 'sa.name', 'sa.summary', 'sa.public_key', 'sa.private_key', 'sa.creation' ) ->from(self::TABLE_SERVER_ACTORS, 'sa'); @@ -103,24 +103,18 @@ class ActorsRequestBuilder extends CoreRequestBuilder { /** * @param array $data * - * @return Actor + * @return Person */ - protected function parseActorsSelectSql($data): Actor { - $id = $this->configService->getRoot() . '@' . $data['preferred_username']; - $actor = new Actor(); - $actor->setId($id) - ->setType($this->get('type', $data, '')) - ->setRoot($this->configService->getRoot()); - $actor->setUserId($data['user_id']) - ->setPreferredUsername($data['preferred_username']) - ->setPublicKey($data['public_key']) - ->setPrivateKey($data['private_key']) - ->setInbox($id . '/inbox') - ->setOutbox($id . '/outbox') - ->setFollowers($id . '/followers') - ->setFollowing($id . '/following') - ->setSharedInbox($this->configService->getRoot() . 'inbox') - ->setCreation($this->getInt('creation', $data, 0)); + protected function parseActorsSelectSql($data): Person { + $root = $this->configService->getRoot(); + + $actor = new Person(); + $actor->import($data); + $actor->setInbox($actor->getId() . '/inbox') + ->setOutbox($actor->getId() . '/outbox') + ->setFollowers($actor->getId() . '/followers') + ->setFollowing($actor->getId() . '/following') + ->setSharedInbox($root . 'inbox'); return $actor; } diff --git a/lib/Db/CacheActorsRequest.php b/lib/Db/CacheActorsRequest.php index afb60261..0c730160 100644 --- a/lib/Db/CacheActorsRequest.php +++ b/lib/Db/CacheActorsRequest.php @@ -31,8 +31,8 @@ namespace OCA\Social\Db; use OCA\Social\Exceptions\CacheActorDoesNotExistException; -use OCA\Social\Model\ActivityPub\Actor; use OCA\Social\Model\ActivityPub\Cache\CacheActor; +use OCA\Social\Model\ActivityPub\Person; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; use OCP\IDBConnection; @@ -57,19 +57,30 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { /** * insert cache about an Actor in database. * - * @param Actor $actor - * @param array $object + * @param Person $actor * * @return int * @throws \Exception */ - public function create(Actor $actor, array $object): int { + public function save(Person $actor): int { try { $qb = $this->getCacheActorsInsertSql(); - $qb->setValue('account', $qb->createNamedParameter($actor->getAccount())) - ->setValue('url', $qb->createNamedParameter($actor->getId())) - ->setValue('actor', $qb->createNamedParameter(json_encode($object))); + $qb->setValue('id', $qb->createNamedParameter($actor->getId())) + ->setValue('account', $qb->createNamedParameter($actor->getAccount())) + ->setValue('following', $qb->createNamedParameter($actor->getFollowing())) + ->setValue('followers', $qb->createNamedParameter($actor->getFollowers())) + ->setValue('inbox', $qb->createNamedParameter($actor->getInbox())) + ->setValue('shared_inbox', $qb->createNamedParameter($actor->getSharedInbox())) + ->setValue('outbox', $qb->createNamedParameter($actor->getOutbox())) + ->setValue('featured', $qb->createNamedParameter($actor->getFeatured())) + ->setValue('url', $qb->createNamedParameter($actor->getUrl())) + ->setValue( + 'preferred_username', $qb->createNamedParameter($actor->getPreferredUsername()) + ) + ->setValue('name', $qb->createNamedParameter($actor->getName())) + ->setValue('summary', $qb->createNamedParameter($actor->getSummary())) + ->setValue('public_key', $qb->createNamedParameter($actor->getPublicKey())); $qb->execute(); @@ -80,15 +91,39 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { } +// /** +// * get Cached value about an Actor, based on the account. +// * +// * @param string $account +// * +// * @return CacheActor +// * @throws CacheActorDoesNotExistException +// */ +// public function getFromAccount(string $account): CacheActor { +// $qb = $this->getCacheActorsSelectSql(); +// $this->limitToAccount($qb, $account); +// +// $cursor = $qb->execute(); +// $data = $cursor->fetch(); +// $cursor->closeCursor(); +// +// if ($data === false) { +// throw new CacheActorDoesNotExistException(); +// } +// +// return $this->parseCacheActorsSelectSql($data); +// } + + /** - * get Cached value about an Actor, based on the account. + * get Cached version of an Actor, based on the UriId * * @param string $account * - * @return CacheActor + * @return Person * @throws CacheActorDoesNotExistException */ - public function getFromAccount(string $account): CacheActor { + public function getFromAccount(string $account): Person { $qb = $this->getCacheActorsSelectSql(); $this->limitToAccount($qb, $account); @@ -104,29 +139,5 @@ class CacheActorsRequest extends CacheActorsRequestBuilder { } - /** - * get Cached version of an Actor, based on the UriId - * - * @param string $url - * - * @return CacheActor - * @throws CacheActorDoesNotExistException - */ - public function getFromUrl(string $url): CacheActor { - $qb = $this->getCacheActorsSelectSql(); - $this->limitToUrl($qb, $url); - - $cursor = $qb->execute(); - $data = $cursor->fetch(); - $cursor->closeCursor(); - - if ($data === false) { - throw new CacheActorDoesNotExistException(); - } - - return $this->parseCacheActorsSelectSql($data); - } - - } diff --git a/lib/Db/CacheActorsRequestBuilder.php b/lib/Db/CacheActorsRequestBuilder.php index 29e7b80b..69fe2e47 100644 --- a/lib/Db/CacheActorsRequestBuilder.php +++ b/lib/Db/CacheActorsRequestBuilder.php @@ -32,6 +32,7 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; use OCA\Social\Model\ActivityPub\Cache\CacheActor; +use OCA\Social\Model\ActivityPub\Person; use OCP\DB\QueryBuilder\IQueryBuilder; class CacheActorsRequestBuilder extends CoreRequestBuilder { @@ -76,7 +77,10 @@ class CacheActorsRequestBuilder extends CoreRequestBuilder { /** @noinspection PhpMethodParametersCountMismatchInspection */ $qb->select( - 'ca.id', 'ca.account', 'ca.url', 'ca.actor', 'ca.creation' + 'ca.id', 'ca.account', 'ca.following', 'ca.followers', 'ca.inbox', + 'ca.shared_inbox', 'ca.outbox', 'ca.featured', 'ca.url', + 'ca.preferred_username', 'ca.name', 'ca.summary', + 'ca.public_key', 'ca.creation' ) ->from(self::TABLE_CACHE_ACTORS, 'ca'); @@ -102,15 +106,11 @@ class CacheActorsRequestBuilder extends CoreRequestBuilder { /** * @param array $data * - * @return CacheActor + * @return Person */ - protected function parseCacheActorsSelectSql($data): CacheActor { - $actor = new CacheActor(); - $actor->setId($this->getInt('id', $data)) - ->setAccount($data['account']) - ->setUrl($data['url']) - ->setActor(json_decode($data['actor'], true)) - ->setCreation($this->getInt('creation', $data, 0)); + protected function parseCacheActorsSelectSql(array $data): Person { + $actor = new Person(); + $actor->import($data); return $actor; } diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 7f389cbd..d9f13693 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -40,6 +40,7 @@ class CoreRequestBuilder { const TABLE_SERVER_ACTORS = 'social_server_actors'; const TABLE_SERVER_NOTES = 'social_server_notes'; + const TABLE_SERVER_FOLLOWS = 'social_server_follows'; const TABLE_CACHE_ACTORS = 'social_cache_actors'; @@ -80,7 +81,18 @@ class CoreRequestBuilder { * @param IQueryBuilder $qb * @param int $id */ - protected function limitToId(IQueryBuilder &$qb, $id) { + protected function limitToId(IQueryBuilder &$qb, int $id) { + $this->limitToDBField($qb, 'id', $id); + } + + + /** + * Limit the request to the Id + * + * @param IQueryBuilder $qb + * @param string $id + */ + protected function limitToIdString(IQueryBuilder &$qb, string $id) { $this->limitToDBField($qb, 'id', $id); } @@ -173,6 +185,22 @@ class CoreRequestBuilder { } + /** + * @param IQueryBuilder $qb + * @param string $recipient + */ + protected function limitToRecipient(IQueryBuilder &$qb, string $recipient) { + $expr = $qb->expr(); + $orX = $expr->orX(); + + $orX->add($expr->eq('to', $qb->createNamedParameter($recipient))); + $orX->add($expr->like('to_array', $qb->createNamedParameter('%"' . $recipient . '"%'))); + $orX->add($expr->like('cc', $qb->createNamedParameter('%"' . $recipient . '"%'))); + $orX->add($expr->like('bcc', $qb->createNamedParameter('%"' . $recipient . '"%'))); + + $qb->andWhere($orX); + } + /** * @param IQueryBuilder $qb * @param string $field diff --git a/lib/Db/FollowsRequest.php b/lib/Db/FollowsRequest.php new file mode 100644 index 00000000..994fd2ed --- /dev/null +++ b/lib/Db/FollowsRequest.php @@ -0,0 +1,93 @@ + + * @copyright 2018, Maxence Lange + * @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 . + * + */ + + +namespace OCA\Social\Db; + + +use Exception; +use OCA\Social\Model\ActivityPub\Follow; + + +/** + * Class FollowsRequest + * + * @package OCA\Social\Db + */ +class FollowsRequest extends FollowsRequestBuilder { + + + /** + * Insert a new Note in the database. + * + * @param Follow $follow + * + * @return int + * @throws Exception + */ + public function save(Follow $follow): int { + + try { + $qb = $this->getFollowsInsertSql(); + $qb->setValue('id', $qb->createNamedParameter($follow->getId())) + ->setValue('actor_id', $qb->createNamedParameter($follow->getActorId())) + ->setValue('object_id', $qb->createNamedParameter($follow->getObjectId())); + + $qb->execute(); + + return $qb->getLastInsertId(); + } catch (Exception $e) { + throw $e; + } + } + + + /** + * Insert a new Note in the database. + * + * @param Follow $follow + * + * @return int + * @throws Exception + */ + public function delete(Follow $follow) { + + try { + $qb = $this->getFollowsDeleteSql(); + $this->limitToIdString($qb, $follow->getId()); + + $qb->execute(); + } catch (Exception $e) { + throw $e; + } + } + + +} + diff --git a/lib/Db/FollowsRequestBuilder.php b/lib/Db/FollowsRequestBuilder.php new file mode 100644 index 00000000..b50e5e9c --- /dev/null +++ b/lib/Db/FollowsRequestBuilder.php @@ -0,0 +1,122 @@ + + * @copyright 2018, Maxence Lange + * @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 . + * + */ + + +namespace OCA\Social\Db; + + +use daita\MySmallPhpTools\Traits\TArrayTools; +use OCA\Social\Model\ActivityPub\Follow; +use OCP\DB\QueryBuilder\IQueryBuilder; + + +/** + * Class FollowsRequestBuilder + * + * @package OCA\Social\Db + */ +class FollowsRequestBuilder extends CoreRequestBuilder { + + + use TArrayTools; + + + /** + * Base of the Sql Insert request + * + * @return IQueryBuilder + */ + protected function getFollowsInsertSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->insert(self::TABLE_SERVER_FOLLOWS); + + return $qb; + } + + + /** + * Base of the Sql Update request + * + * @return IQueryBuilder + */ + protected function getFollowsUpdateSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->update(self::TABLE_SERVER_FOLLOWS); + + return $qb; + } + + + /** + * Base of the Sql Select request for Shares + * + * @return IQueryBuilder + */ + protected function getFollowsSelectSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + + /** @noinspection PhpMethodParametersCountMismatchInspection */ + $qb->select('f.id', 'f.actor_id', 'f.object_id', 'f.creation') + ->from(self::TABLE_SERVER_FOLLOWS, 'f'); + + $this->defaultSelectAlias = 'f'; + + return $qb; + } + + + /** + * Base of the Sql Delete request + * + * @return IQueryBuilder + */ + protected function getFollowsDeleteSql(): IQueryBuilder { + $qb = $this->dbConnection->getQueryBuilder(); + $qb->delete(self::TABLE_SERVER_FOLLOWS); + + return $qb; + } + + + /** + * @param array $data + * + * @return Follow + */ + protected function parseFollowsSelectSql($data): Follow { + $follow = new Follow(); + $follow->setId($data['id']) + ->setActorId($data['actor_id']) + ->setObjectId($data['object_id']); + + return $follow; + } + +} + diff --git a/lib/Db/NotesRequest.php b/lib/Db/NotesRequest.php index 2b9ed2bd..1a55a270 100644 --- a/lib/Db/NotesRequest.php +++ b/lib/Db/NotesRequest.php @@ -31,6 +31,7 @@ namespace OCA\Social\Db; use OCA\Social\Model\ActivityPub\Note; +use OCA\Social\Service\ActivityService; use OCA\Social\Service\ConfigService; use OCA\Social\Service\MiscService; use OCP\IDBConnection; @@ -60,15 +61,27 @@ class NotesRequest extends NotesRequestBuilder { * @return int * @throws \Exception */ - public function create(Note $note): int { + public function save(Note $note): int { try { $qb = $this->getNotesInsertSql(); $qb->setValue('id', $qb->createNamedParameter($note->getId())) ->setValue('to', $qb->createNamedParameter($note->getTo())) - ->setValue('to_array', $qb->createNamedParameter(json_encode($note->getToArray()))) - ->setValue('cc', $qb->createNamedParameter(json_encode($note->getCc()))) - ->setValue('bcc', $qb->createNamedParameter(json_encode($note->getBcc()))) + ->setValue( + 'to_array', $qb->createNamedParameter( + json_encode($note->getToArray(), JSON_UNESCAPED_SLASHES) + ) + ) + ->setValue( + 'cc', $qb->createNamedParameter( + json_encode($note->getCcArray(), JSON_UNESCAPED_SLASHES) + ) + ) + ->setValue( + 'bcc', $qb->createNamedParameter( + json_encode($note->getBccArray()), JSON_UNESCAPED_SLASHES + ) + ) ->setValue('content', $qb->createNamedParameter($note->getContent())) ->setValue('summary', $qb->createNamedParameter($note->getSummary())) ->setValue('published', $qb->createNamedParameter($note->getPublished())) @@ -83,4 +96,44 @@ class NotesRequest extends NotesRequestBuilder { } } + + /** + * @param string $actorId + * + * @return array + */ + public function getPublicNotes(): array { + $qb = $this->getNotesSelectSql(); + $this->limitToRecipient($qb, ActivityService::TO_PUBLIC); + + $notes = []; + $cursor = $qb->execute(); + while ($data = $cursor->fetch()) { + $notes[] = $this->parseNotesSelectSql($data); + } + $cursor->closeCursor(); + + return $notes; + } + + /** + * @param string $actorId + * + * @return array + */ + public function getNotesForActorId(string $actorId): array { + $qb = $this->getNotesSelectSql(); + $this->limitToRecipient($qb, $actorId); + + $notes = []; + $cursor = $qb->execute(); + while ($data = $cursor->fetch()) { + $notes[] = $this->parseNotesSelectSql($data); + } + $cursor->closeCursor(); + + return $notes; + } + + } diff --git a/lib/Db/NotesRequestBuilder.php b/lib/Db/NotesRequestBuilder.php index a4de22a6..26bfb0ad 100644 --- a/lib/Db/NotesRequestBuilder.php +++ b/lib/Db/NotesRequestBuilder.php @@ -32,6 +32,7 @@ namespace OCA\Social\Db; use daita\MySmallPhpTools\Traits\TArrayTools; use OCA\Social\Model\ActivityPub\Note; +use OCA\Social\Model\Post; use OCP\DB\QueryBuilder\IQueryBuilder; class NotesRequestBuilder extends CoreRequestBuilder { @@ -76,7 +77,7 @@ class NotesRequestBuilder extends CoreRequestBuilder { /** @noinspection PhpMethodParametersCountMismatchInspection */ $qb->select( - 'sn.id', 'sn.to', 'sn.to_array', 'sn.cc', 'sn.bcc', 'sn.content', 'sn_summary', + 'sn.id', 'sn.to', 'sn.to_array', 'sn.cc', 'sn.bcc', 'sn.content', 'sn.summary', 'sn.published', 'sn.attributed_to', 'sn.in_reply_to', 'sn.creation' ) ->from(self::TABLE_SERVER_NOTES, 'sn'); @@ -110,15 +111,39 @@ class NotesRequestBuilder extends CoreRequestBuilder { $note->setId($data['id']) ->setTo($data['to']) ->setToArray(json_decode($data['to_array'], true)) - ->setCc(json_decode($data['cc'], true)) - ->setBcc(json_decode($data['bcc'])); + ->setCcArray(json_decode($data['cc'], true)) + ->setBccArray(json_decode($data['bcc'])) + ->setPublished($data['published']); $note->setContent($data['content']) - ->setPublished($data['published']) ->setAttributedTo($data['attributed_to']) ->setInReplyTo($data['in_reply_to']); return $note; } + + /** + * @param array $data + * + * @return Post + */ + protected function parsePostsSelectSql($userId, $data): Note { + $post = new Post($userId); + + $post->setContent($data['content']); + +// $note->setId($data['id']) +// ->setTo($data['to']) +// ->setToArray(json_decode($data['to_array'], true)) +// ->setCc(json_decode($data['cc'], true)) +// ->setBcc(json_decode($data['bcc'])); +// $note->setContent($data['content']) +// ->setPublished($data['published']) +// ->setAttributedTo($data['attributed_to']) +// ->setInReplyTo($data['in_reply_to']); + + return $post; + } + }