diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php index 7a437ce5..16a1c32a 100644 --- a/lib/Db/CoreRequestBuilder.php +++ b/lib/Db/CoreRequestBuilder.php @@ -90,6 +90,7 @@ class CoreRequestBuilder { self::TABLE_STREAM_ACTIONS ]; + /** @var ILogger */ protected $logger; /** @var IDBConnection */ @@ -137,6 +138,10 @@ class CoreRequestBuilder { $this->logger ); + if ($this->viewer !== null) { + $qb->setViewer($this->viewer); + } + return $qb; } @@ -161,6 +166,7 @@ class CoreRequestBuilder { * @param string $id * * @return string + * @deprecated */ public function prim(string $id): string { if ($id === '') { @@ -184,7 +190,7 @@ class CoreRequestBuilder { /** * Limit the request to the Id - * + * @deprecated * @param IQueryBuilder $qb * @param int $id */ @@ -195,6 +201,7 @@ class CoreRequestBuilder { /** * Limit the request to the Id (string) + * @deprecated * * @param IQueryBuilder $qb * @param string $id @@ -206,6 +213,7 @@ class CoreRequestBuilder { /** * Limit the request to the UserId + * @deprecated * * @param IQueryBuilder $qb * @param string $userId @@ -533,6 +541,7 @@ class CoreRequestBuilder { * @param int $limit * * @throws DateTimeException + * @deprecated */ protected function limitPaginate(IQueryBuilder &$qb, int $since = 0, int $limit = 5) { try { @@ -763,6 +772,7 @@ class CoreRequestBuilder { /** + * @deprecated * @param IQueryBuilder $qb * @param string $alias */ @@ -958,6 +968,8 @@ class CoreRequestBuilder { /** * @param IQueryBuilder $qb + * + * @deprecated */ protected function leftJoinStreamAction(IQueryBuilder &$qb) { if ($qb->getType() !== QueryBuilder::SELECT || $this->viewer === null) { diff --git a/lib/Db/SocialCoreQueryBuilder.php b/lib/Db/SocialCoreQueryBuilder.php new file mode 100644 index 00000000..917a2b1c --- /dev/null +++ b/lib/Db/SocialCoreQueryBuilder.php @@ -0,0 +1,86 @@ + + * @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\Db\ExtendedQueryBuilder; +use OCA\Social\Model\ActivityPub\Actor\Person; + + +/** + * Class SocialCoreQueryBuilder + * + * @package OCA\Social\Db + */ +class SocialCoreQueryBuilder extends ExtendedQueryBuilder { + + + /** @var Person */ + private $viewer = null; + + + /** + * @return bool + */ + public function hasViewer(): bool { + return ($this->viewer !== null); + } + + /** + * @param Person $viewer + */ + public function setViewer(Person $viewer): void { + $this->viewer = $viewer; + } + + /** + * @return Person + */ + public function getViewer(): Person { + return $this->viewer; + } + + + /** + * @param string $id + * + * @return string + */ + public function prim(string $id): string { + if ($id === '') { + return ''; + } + + return hash('sha512', $id); + } + +} + diff --git a/lib/Db/SocialCrossQueryBuilder.php b/lib/Db/SocialCrossQueryBuilder.php new file mode 100644 index 00000000..525c3778 --- /dev/null +++ b/lib/Db/SocialCrossQueryBuilder.php @@ -0,0 +1,174 @@ + + * @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 Doctrine\DBAL\Query\QueryBuilder; + + +/** + * Class SocialCrossQueryBuilder + * + * @package OCA\Social\Db + */ +class SocialCrossQueryBuilder extends SocialCoreQueryBuilder { + + + /** + * @param string $aliasDest + * @param string $aliasFollowing + */ + public function selectDestFollowing(string $aliasDest = 'sd', string $aliasFollowing = 'f') { + if ($this->getType() !== QueryBuilder::SELECT) { + return; + } + + if ($aliasDest !== '') { + $this->from(CoreRequestBuilder::TABLE_STREAM_DEST, $aliasDest); + } + if ($aliasFollowing !== '') { + $this->from(CoreRequestBuilder::TABLE_FOLLOWS, $aliasFollowing); + } + } + + + /** + * @param string $alias + */ + public function selectCacheActors(string $alias = 'ca') { + if ($this->getType() !== QueryBuilder::SELECT) { + return; + } + + $pf = (($alias === '') ? $this->getDefaultSelectAlias() : $alias); + $this->from(CoreRequestBuilder::TABLE_CACHE_ACTORS, $pf); + $this->selectAlias($pf . '.id', 'cacheactor_id') + ->selectAlias($pf . '.type', 'cacheactor_type') + ->selectAlias($pf . '.account', 'cacheactor_account') + ->selectAlias($pf . '.following', 'cacheactor_following') + ->selectAlias($pf . '.followers', 'cacheactor_followers') + ->selectAlias($pf . '.inbox', 'cacheactor_inbox') + ->selectAlias($pf . '.shared_inbox', 'cacheactor_shared_inbox') + ->selectAlias($pf . '.outbox', 'cacheactor_outbox') + ->selectAlias($pf . '.featured', 'cacheactor_featured') + ->selectAlias($pf . '.url', 'cacheactor_url') + ->selectAlias($pf . '.preferred_username', 'cacheactor_preferred_username') + ->selectAlias($pf . '.name', 'cacheactor_name') + ->selectAlias($pf . '.summary', 'cacheactor_summary') + ->selectAlias($pf . '.public_key', 'cacheactor_public_key') + ->selectAlias($pf . '.source', 'cacheactor_source') + ->selectAlias($pf . '.creation', 'cacheactor_creation') + ->selectAlias($pf . '.local', 'cacheactor_local'); + } + + + /** + * @param string $alias + */ + public function leftJoinFollowStatus(string $alias = 'fs') { + if ($this->getType() !== QueryBuilder::SELECT || !$this->hasViewer()) { + return; + } + + $expr = $this->expr(); + $actor = $this->getViewer(); + $pf = $this->getDefaultSelectAlias() . '.'; + + $idPrim = $this->prim($actor->getId()); + + $on = $expr->andX(); + $on->add($this->exprLimitToDBFieldInt('accepted', 1, $alias)); + $on->add($this->exprLimitToDBField('actor_id_prim', $idPrim, true, true, $alias)); + $on->add($expr->eq($pf . 'attributed_to_prim', $alias . '.object_id_prim')); + + $this->leftJoin($this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_FOLLOWS, $alias, $on); + } + + + /** + * @param string $alias + */ + public function leftJoinStreamAction(string $alias = 'sa') { + if ($this->getType() !== QueryBuilder::SELECT || !$this->hasViewer()) { + return; + } + + $pf = $this->getDefaultSelectAlias(); + $expr = $this->expr(); + + $this->selectAlias($alias . '.id', 'streamaction_id') + ->selectAlias($alias . '.actor_id', 'streamaction_actor_id') + ->selectAlias($alias . '.stream_id', 'streamaction_stream_id') + ->selectAlias($alias . '.values', 'streamaction_values'); + + $orX = $expr->orX(); + $orX->add($expr->eq($alias . '.stream_id_prim', $pf . '.id_prim')); + $orX->add($expr->eq($alias . '.stream_id_prim', $pf . '.object_id_prim')); + + $on = $expr->andX(); + $viewer = $this->getViewer(); + $idPrim = $this->prim($viewer->getId()); + + $on->add($expr->eq($alias . '.actor_id_prim', $this->createNamedParameter($idPrim))); + $on->add($orX); + + $this->leftJoin($this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_STREAM_ACTIONS, 'sa', $on); + } + + + /** + * @param string $actorId + * @param string $type + * @param string $field + * @param string $aliasDest + * @param string $aliasFollowing + * @param string $alias + */ + public function innerJoinDestFollowing( + string $actorId, string $type, string $field = 'id_prim', string $aliasDest = 'sd', + string $aliasFollowing = 'f', string $alias = '' + ) { + $expr = $this->expr(); + $andX = $expr->andX(); + $pf = (($alias === '') ? $this->getdefaultSelectAlias() : $alias) . '.'; + + $idPrim = $this->prim($actorId); + $andX->add($this->exprLimitToDBField('actor_id_prim', $idPrim, true, true, $aliasFollowing)); + $andX->add($this->exprLimitToDBFieldInt('accepted', 1, $aliasFollowing)); + $andX->add($expr->eq($aliasFollowing . '.follow_id_prim', $aliasDest . '.actor_id')); + $andX->add($expr->eq($aliasDest . '.stream_id', $pf . $field)); + $andX->add($expr->eq($aliasDest . '.type', $this->createNamedParameter($type))); + + $this->andWhere($andX); + } + +} + diff --git a/lib/Db/SocialFiltersQueryBuilder.php b/lib/Db/SocialFiltersQueryBuilder.php new file mode 100644 index 00000000..e0d2e7c2 --- /dev/null +++ b/lib/Db/SocialFiltersQueryBuilder.php @@ -0,0 +1,69 @@ + + * @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 OCP\DB\QueryBuilder\IQueryBuilder; + + +/** + * Class SocialFiltersQueryBuilder + * + * @package OCA\Social\Db + */ +class SocialFiltersQueryBuilder extends SocialLimitsQueryBuilder { + + + /** + * @param IQueryBuilder $qb + */ + public function filterDuplicate() { + if (!$this->hasViewer()) { + return; + } + + $viewer = $this->getViewer(); + $this->leftJoinFollowStatus('fs'); + + $expr = $this->expr(); + $filter = $expr->orX(); + $filter->add($this->exprLimitToDBFieldInt('hidden_on_timeline', 0, 's')); + + $follower = $expr->andX(); + $follower->add($this->exprLimitToDBField('attributed_to_prim', $this->prim($viewer->getId()), false)); + $follower->add($expr->isNull('fs.id_prim')); + $filter->add($follower); + + $this->andWhere($filter); + } + +} + diff --git a/lib/Db/SocialLimitsQueryBuilder.php b/lib/Db/SocialLimitsQueryBuilder.php new file mode 100644 index 00000000..afdee38f --- /dev/null +++ b/lib/Db/SocialLimitsQueryBuilder.php @@ -0,0 +1,338 @@ + + * @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 DateInterval; +use DateTime; +use Exception; +use OCA\Social\Exceptions\DateTimeException; +use OCA\Social\Model\ActivityPub\ACore; + + +/** + * Class SocialLimitsQueryBuilder + * + * @package OCA\Social\Db + */ +class SocialLimitsQueryBuilder extends SocialCrossQueryBuilder { + + /** + * Limit the request to the Type + * + * @param string $type + * + * @return SocialQueryBuilder + */ + public function limitToType(string $type): self { + $this->limitToDBField('type', $type, false); + + return $this; + } + + + /** + * Limit the request to the ActivityId + * + * @param string $activityId + */ + public function limitToActivityId(string $activityId) { + $this->limitToDBField('activity_id', $activityId, false); + } + + + /** + * Limit the request to the Id (string) + * + * @param string $id + */ + public function limitToInReplyTo(string $id) { + $this->limitToDBField('in_reply_to', $id, false); + } + + + /** + * Limit the request to the sub-type + * + * @param string $subType + */ + public function limitToSubType(string $subType) { + $this->limitToDBField('subtype', $subType); + } + + + /** + * @param string $type + */ + public function filterType(string $type) { + $this->filterDBField('type', $type); + } + + + /** + * Limit the request to the Preferred Username + * + * @param string $username + */ + public function limitToPreferredUsername(string $username) { + $this->limitToDBField('preferred_username', $username, false); + } + + + /** + * Limit the request to the ActorId + */ + public function limitToPublic() { + $this->limitToDBFieldInt('public', 1); + } + + + /** + * Limit the request to the ActorId + */ + public function limitToIdPrim(string $id) { + $this->limitToDBField('id_prim', $id); + } + + + /** + * Limit the request to the token + * + * @param string $token + */ + public function limitToToken(string $token) { + $this->limitToDBField('token', $token); + } + + /** + * Limit the results to a given number + * + * @param int $limit + */ + public function limitResults(int $limit) { + $this->setMaxResults($limit); + } + + + /** + * Limit the request to the ActorId + * + * @param string $hashtag + */ + public function limitToHashtag(string $hashtag) { + $this->limitToDBField('hashtag', $hashtag, false); + } + + + /** + * Limit the request to the ActorId + * + * @param string $actorId + * @param string $alias + */ + public function limitToActorId(string $actorId, string $alias = '') { + $this->limitToDBField('actor_id', $actorId, false, $alias); + } + + + /** + * Limit the request to the FollowId + * + * @param string $followId + */ + public function limitToFollowId(string $followId) { + $this->limitToDBField('follow_id', $followId, false); + } + + + /** + * Limit the request to the FollowId + * + * @param bool $accepted + * @param string $alias + */ + public function limitToAccepted(bool $accepted, string $alias = '') { + $this->limitToDBField('accepted', ($accepted) ? '1' : '0', true, $alias); + } + + + /** + * Limit the request to the ServiceId + * + * @param string $objectId + */ + public function limitToObjectId(string $objectId) { + $this->limitToDBField('object_id', $objectId, false); + } + + + /** + * Limit the request to the account + * + * @param string $account + */ + public function limitToAccount(string $account) { + $this->limitToDBField('account', $account, false); + } + + + /** + * Limit the request to the creation + * + * @param int $delay + * + * @throws Exception + */ + public function limitToCaching(int $delay = 0) { + $date = new DateTime('now'); + $date->sub(new DateInterval('PT' . $delay . 'M')); + + $this->limitToDBFieldDateTime('caching', $date, true); + } + + + /** + * Limit the request to the url + * + * @param string $url + */ + public function limitToUrl(string $url) { + $this->limitToDBField('url', $url); + } + + + /** + * Limit the request to the url + * + * @param string $actorId + */ + public function limitToAttributedTo(string $actorId) { + $this->limitToDBField('attributed_to', $actorId, false); + } + + + /** + * Limit the request to the status + * + * @param int $status + */ + public function limitToStatus(int $status) { + $this->limitToDBFieldInt('status', $status); + } + + + /** + * Limit the request to the instance + * + * @param string $address + */ + public function limitToAddress(string $address) { + $this->limitToDBField('address', $address); + } + + + /** + * Limit the request to the instance + * + * @param bool $local + */ + public function limitToLocal(bool $local) { + $this->limitToDBField('local', ($local) ? '1' : '0'); + } + + + /** + * Limit the request to the parent_id + * + * @param string $parentId + */ + public function limitToParentId(string $parentId) { + $this->limitToDBField('parent_id', $parentId); + } + + + /** + * @param int $since + * @param int $limit + * + * @throws DateTimeException + */ + public function limitPaginate(int $since = 0, int $limit = 5) { + try { + if ($since > 0) { + $dTime = new DateTime(); + $dTime->setTimestamp($since); + $this->limitToDBFieldDateTime('published_time', $dTime); + } + } catch (Exception $e) { + throw new DateTimeException(); + } + + $this->setMaxResults($limit); + $pf = $this->getDefaultSelectAlias(); + $this->orderBy($pf . '.published_time', 'desc'); + } + + + /** + * @param string $actorId + * @param string $type + * @param string $subType + * @param string $alias + */ + public function limitToDest(string $actorId, string $type, string $subType = '', string $alias = 'sd') { + $this->limitToDBField('actor_id', $this->prim($actorId), true, $alias); + $this->limitToDBField('type', $type, true, $alias); + + if ($subType !== '') { + $this->limitToDBField('subtype', $subType, true, $alias); + } + } + + + /** + * @param string $aliasDest + * @param string $aliasFollowing + */ + public function limitToViewer(string $aliasDest = 'sd', string $aliasFollowing = 'f') { + if (!$this->hasViewer()) { + $this->selectDestFollowing($aliasDest); + $this->limitToDest(ACore::CONTEXT_PUBLIC, 'recipient', '', $aliasDest); + + return; + } + + $actor = $this->getViewer(); + $this->selectDestFollowing($aliasDest, $aliasFollowing); + $this->innerJoinDestFollowing($actor->getId(), 'recipient', 'id_prim', $aliasDest, $aliasFollowing); + } +} + diff --git a/lib/Db/SocialQueryBuilder.php b/lib/Db/SocialQueryBuilder.php index b1e01a8a..872ed14c 100644 --- a/lib/Db/SocialQueryBuilder.php +++ b/lib/Db/SocialQueryBuilder.php @@ -31,313 +31,59 @@ declare(strict_types=1); namespace OCA\Social\Db; -use daita\MySmallPhpTools\Db\ExtendedQueryBuilder; -use DateInterval; -use DateTime; -use Exception; -use OCA\Social\Model\ActivityPub\Actor\Person; - - /** * Class SocialQueryBuilder * - * @package OCA\Push\Db + * @package OCA\Social\Db */ -class SocialQueryBuilder extends ExtendedQueryBuilder { - - - /** @var Person */ - private $viewer = null; - - - /** - * @return bool - */ - public function hasViewer(): bool { - return ($this->viewer !== null); - } - - /** - * @param Person $viewer - */ - public function setViewer(Person $viewer): void { - $this->viewer = $viewer; - } - - /** - * @return Person - */ - public function getViewer(): Person { - return $this->viewer; - } +class SocialQueryBuilder extends SocialFiltersQueryBuilder { /** * @param string $id + * @param string $field */ - public function generatePrimaryKey(string $id) { - $this->setValue('id_prim', $this->createNamedParameter(hash('sha512', $id))); + public function generatePrimaryKey(string $id, string $field = 'id_prim') { + if ($id === '') { + return; + } + + $this->setValue($field, $this->createNamedParameter($this->prim($id))); } - /** - * Limit the request to the Type - * - * @param string $type - * - * @return SocialQueryBuilder - */ - public function limitToType(string $type): self { - $this->limitToDBField('type', $type, false); - - return $this; - } - - - /** - * Limit the request to the ActivityId - * - * @param string $activityId - */ - protected function limitToActivityId(string $activityId) { - $this->limitToDBField('activity_id', $activityId, false); - } - - - /** - * Limit the request to the Id (string) - * - * @param string $id - */ - protected function limitToInReplyTo(string $id) { - $this->limitToDBField('in_reply_to', $id, false); - } - - - /** - * Limit the request to the sub-type - * - * @param string $subType - */ - protected function limitToSubType(string $subType) { - $this->limitToDBField('subtype', $subType); - } - - - /** - * @param string $type - */ - protected function filterType(string $type) { - $this->filterDBField('type', $type); - } - - - /** - * Limit the request to the Preferred Username - * - * @param string $username - */ - protected function limitToPreferredUsername(string $username) { - $this->limitToDBField('preferred_username', $username, false); - } - /** * search using username * * @param string $username */ - protected function searchInPreferredUsername(string $username) { + public function searchInPreferredUsername(string $username) { $dbConn = $this->getConnection(); $this->searchInDBField('preferred_username', $dbConn->escapeLikeParameter($username) . '%'); } - - /** - * Limit the request to the ActorId - */ - protected function limitToPublic() { - $this->limitToDBFieldInt('public', 1); - } - - - /** - * Limit the request to the token - * - * @param string $token - */ - protected function limitToToken(string $token) { - $this->limitToDBField('token', $token); - } - - /** - * Limit the results to a given number - * - * @param int $limit - */ - protected function limitResults(int $limit) { - $this->setMaxResults($limit); - } - - - /** - * Limit the request to the ActorId - * - * @param string $hashtag - */ - protected function limitToHashtag(string $hashtag) { - $this->limitToDBField('hashtag', $hashtag, false); - } - - /** * Limit the request to the ActorId * * @param string $hashtag * @param bool $all */ - protected function searchInHashtag(string $hashtag, bool $all = false) { + public function searchInHashtag(string $hashtag, bool $all = false) { $dbConn = $this->getConnection(); $this->searchInDBField('hashtag', (($all) ? '%' : '') . $dbConn->escapeLikeParameter($hashtag) . '%'); } - /** - * Limit the request to the ActorId - * - * @param string $actorId - * @param string $alias - */ - protected function limitToActorId(string $actorId, string $alias = '') { - $this->limitToDBField('actor_id', $actorId, false, $alias); - } - - - /** - * Limit the request to the FollowId - * - * @param string $followId - */ - protected function limitToFollowId(string $followId) { - $this->limitToDBField('follow_id', $followId, false); - } - - - /** - * Limit the request to the FollowId - * - * @param bool $accepted - * @param string $alias - */ - protected function limitToAccepted(bool $accepted, string $alias = '') { - $this->limitToDBField('accepted', ($accepted) ? '1' : '0', true, $alias); - } - - - /** - * Limit the request to the ServiceId - * - * @param string $objectId - */ - protected function limitToObjectId(string $objectId) { - $this->limitToDBField('object_id', $objectId, false); - } - - /** * Limit the request to the account * * @param string $account */ - protected function limitToAccount(string $account) { - $this->limitToDBField('account', $account, false); - } - - - /** - * Limit the request to the account - * - * @param string $account - */ - protected function searchInAccount(string $account) { + public function searchInAccount(string $account) { $dbConn = $this->getConnection(); $this->searchInDBField('account', $dbConn->escapeLikeParameter($account) . '%'); } - /** - * Limit the request to the creation - * - * @param int $delay - * - * @throws Exception - */ - protected function limitToCaching(int $delay = 0) { - $date = new DateTime('now'); - $date->sub(new DateInterval('PT' . $delay . 'M')); - - $this->limitToDBFieldDateTime('caching', $date, true); - } - - - /** - * Limit the request to the url - * - * @param string $url - */ - protected function limitToUrl(string $url) { - $this->limitToDBField('url', $url); - } - - - /** - * Limit the request to the url - * - * @param string $actorId - */ - protected function limitToAttributedTo(string $actorId) { - $this->limitToDBField('attributed_to', $actorId, false); - } - - - /** - * Limit the request to the status - * - * @param int $status - */ - protected function limitToStatus(int $status) { - $this->limitToDBFieldInt('status', $status); - } - - - /** - * Limit the request to the instance - * - * @param string $address - */ - protected function limitToAddress(string $address) { - $this->limitToDBField('address', $address); - } - - - /** - * Limit the request to the instance - * - * @param bool $local - */ - protected function limitToLocal(bool $local) { - $this->limitToDBField('local', ($local) ? '1' : '0'); - } - - - /** - * Limit the request to the parent_id - * - * @param string $parentId - */ - protected function limitToParentId(string $parentId) { - $this->limitToDBField('parent_id', $parentId); - } - - } diff --git a/lib/Db/StreamRequest.php b/lib/Db/StreamRequest.php index b4b49c23..ac172c83 100644 --- a/lib/Db/StreamRequest.php +++ b/lib/Db/StreamRequest.php @@ -38,7 +38,6 @@ use Doctrine\DBAL\Query\QueryBuilder; use Exception; use OCA\Social\Exceptions\DateTimeException; use OCA\Social\Exceptions\ItemUnknownException; -use OCA\Social\Exceptions\SocialAppConfigException; use OCA\Social\Exceptions\StreamNotFoundException; use OCA\Social\Model\ActivityPub\ACore; use OCA\Social\Model\ActivityPub\Actor\Person; @@ -122,8 +121,9 @@ class StreamRequest extends StreamRequestBuilder { json_encode($stream->getCcArray(), JSON_UNESCAPED_SLASHES) ) ); - $this->limitToIdString($qb, $stream->getId()); + $qb->limitToIdPrim($qb->prim($stream->getId())); + // TODO - update StreamDest !??? return $qb->execute(); } @@ -136,7 +136,7 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamUpdateSql(); $qb->set('cache', $qb->createNamedParameter(json_encode($cache, JSON_UNESCAPED_SLASHES))); - $this->limitToIdString($qb, $stream->getId()); + $qb->limitToIdPrim($qb->prim($stream->getId())); $qb->execute(); } @@ -147,7 +147,7 @@ class StreamRequest extends StreamRequestBuilder { */ public function updateAttachments(Document $document) { $qb = $this->getStreamSelectSql(); - $this->limitToIdString($qb, $document->getParentId()); + $qb->limitToIdPrim($qb->prim($document->getParentId())); $cursor = $qb->execute(); $data = $cursor->fetch(); @@ -158,12 +158,11 @@ class StreamRequest extends StreamRequestBuilder { } $new = $this->updateAttachmentInList($document, $this->getArray('attachments', $data, [])); - $qb = $this->getStreamUpdateSql(); $qb->set( 'attachments', $qb->createNamedParameter(json_encode($new, JSON_UNESCAPED_SLASHES)) ); - $this->limitToIdString($qb, $document->getParentId()); + $qb->limitToIdPrim($qb->prim($document->getParentId())); $qb->execute(); } @@ -197,9 +196,9 @@ class StreamRequest extends StreamRequestBuilder { public function updateAttributedTo(string $itemId, string $to) { $qb = $this->getStreamUpdateSql(); $qb->set('attributed_to', $qb->createNamedParameter($to)); - $qb->set('attributed_to_prim', $qb->createNamedParameter($this->prim($to))); + $qb->set('attributed_to_prim', $qb->createNamedParameter($qb->prim($to))); - $this->limitToIdString($qb, $itemId); + $qb->limitToIdPrim($qb->prim($itemId)); $qb->execute(); } @@ -214,7 +213,7 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); if ($type !== '') { - $this->limitToType($qb, $type); + $qb->limitToType($type); } return $this->getStreamsFromRequest($qb); @@ -236,15 +235,13 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); $expr = $qb->expr(); - $this->limitToIdString($qb, $id); - $this->selectCacheActors($qb, 'ca'); + $qb->limitToIdPrim($qb->prim($id)); + $qb->selectCacheActors('ca'); $qb->andWhere($expr->eq('s.attributed_to_prim', 'ca.id_prim')); if ($asViewer) { - $this->limitToViewer($qb); - if ($this->viewer !== null) { - $this->leftJoinStreamAction($qb); - } + $qb->limitToViewer('sd', 'f'); + $qb->leftJoinStreamAction('sa'); } try { @@ -314,8 +311,6 @@ class StreamRequest extends StreamRequestBuilder { * @param string $subType * * @return Stream - * @throws ItemUnknownException - * @throws SocialAppConfigException * @throws StreamNotFoundException */ public function getStreamByObjectId(string $objectId, string $type, string $subType = '' @@ -326,7 +321,7 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); $this->limitToObjectId($qb, $objectId); - $this->limitToType($qb, $type); + $qb->limitToType($type); $this->limitToSubType($qb, $subType); return $this->getStreamFromRequest($qb); @@ -341,7 +336,7 @@ class StreamRequest extends StreamRequestBuilder { public function countNotesFromActorId(string $actorId): int { $qb = $this->countNotesSelectSql(); $this->limitToAttributedTo($qb, $actorId); - $this->limitToType($qb, Note::TYPE); + $qb->limitToType(Note::TYPE); $this->limitToRecipient($qb, ACore::CONTEXT_PUBLIC); $cursor = $qb->execute(); @@ -368,16 +363,20 @@ class StreamRequest extends StreamRequestBuilder { $qb = $this->getStreamSelectSql(); $expr = $qb->expr(); - $this->selectCacheActors($qb, 'ca'); - $this->selectDestFollowing($qb, 'sd', 'f'); - $this->limitPaginate($qb, $since, $limit); + $qb->selectCacheActors('ca'); + $qb->limitPaginate($since, $limit); + + $qb->andWhere($qb->exprLimitToDBField('type', SocialAppNotification::TYPE, false)); + + $qb->limitToViewer('sd', 'f'); +// $qb->selectDestFollowing('sd', 'f'); +// $qb->andWhere($qb->exprInnerJoinDestFollowing($actor, 'recipient', 'id_prim', 'sd', 'f')); + // - $qb->andWhere($this->exprLimitToDBField($qb, 'type', SocialAppNotification::TYPE, false)); - $qb->andWhere($this->exprInnerJoinDestFollowing($qb, $actor, 'id_prim', 'sd', 'f')); $qb->andWhere($expr->eq('f.object_id_prim', 'ca.id_prim')); - $this->leftJoinStreamAction($qb); - $this->filterDuplicate($qb); + $qb->leftJoinStreamAction('sa'); + $qb->filterDuplicate(); return $this->getStreamsFromRequest($qb); } @@ -403,7 +402,7 @@ class StreamRequest extends StreamRequestBuilder { $this->limitPaginate($qb, $since, $limit); $this->limitToRecipient($qb, $actor->getId(), false); - $this->limitToType($qb, SocialAppNotification::TYPE); + $qb->limitToType(SocialAppNotification::TYPE); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); @@ -483,12 +482,13 @@ class StreamRequest extends StreamRequestBuilder { $this->limitPaginate($qb, $since, $limit); $this->limitToLocal($qb, $localOnly); - $this->limitToType($qb, Note::TYPE); + $qb->limitToType(Note::TYPE); $this->leftJoinCacheActors($qb, 'attributed_to'); $this->leftJoinStreamAction($qb); // TODO: to: = real public, cc: = unlisted !? + // DO NOT USE stream_dest.type = 'recipient' on this one ! $this->limitToRecipient($qb, ACore::CONTEXT_PUBLIC, true, ['to']); return $this->getStreamsFromRequest($qb); @@ -513,7 +513,7 @@ class StreamRequest extends StreamRequestBuilder { $actorId = $this->viewer->getId(); $qb = $this->getStreamSelectSql(); - $this->limitToType($qb, Note::TYPE); + $qb->limitToType(Note::TYPE); $this->limitPaginate($qb, $since, $limit); $expr = $qb->expr(); @@ -573,7 +573,7 @@ class StreamRequest extends StreamRequestBuilder { public function getNoteSince(int $since): array { $qb = $this->getStreamSelectSql(); $this->limitToSince($qb, $since, 'published_time'); - $this->limitToType($qb, Note::TYPE); + $qb->limitToType(Note::TYPE); $this->leftJoinStreamAction($qb); return $this->getStreamsFromRequest($qb); @@ -586,10 +586,10 @@ class StreamRequest extends StreamRequestBuilder { */ public function deleteById(string $id, string $type = '') { $qb = $this->getStreamDeleteSql(); - $this->limitToIdString($qb, $id); + $qb->limitToIdPrim($qb->prim($id)); if ($type !== '') { - $this->limitToType($qb, $type); + $qb->limitToType($type); } $qb->execute(); @@ -657,12 +657,12 @@ class StreamRequest extends StreamRequestBuilder { ->setValue('summary', $qb->createNamedParameter($stream->getSummary())) ->setValue('published', $qb->createNamedParameter($stream->getPublished())) ->setValue('attributed_to', $qb->createNamedParameter($attributedTo)) - ->setValue('attributed_to_prim', $qb->createNamedParameter($this->prim($attributedTo))) + ->setValue('attributed_to_prim', $qb->createNamedParameter($qb->prim($attributedTo))) ->setValue('in_reply_to', $qb->createNamedParameter($stream->getInReplyTo())) ->setValue('source', $qb->createNamedParameter($stream->getSource())) ->setValue('activity_id', $qb->createNamedParameter($stream->getActivityId())) ->setValue('object_id', $qb->createNamedParameter($stream->getObjectId())) - ->setValue('object_id_prim', $qb->createNamedParameter($this->prim($stream->getObjectId()))) + ->setValue('object_id_prim', $qb->createNamedParameter($qb->prim($stream->getObjectId()))) ->setValue('details', $qb->createNamedParameter(json_encode($stream->getDetailsAll()))) ->setValue('cache', $qb->createNamedParameter($cache)) ->setValue( @@ -689,7 +689,7 @@ class StreamRequest extends StreamRequestBuilder { } catch (Exception $e) { } - $this->generatePrimaryKey($qb, $stream->getId()); + $qb->generatePrimaryKey($stream->getId(), 'id_prim'); return $qb; } @@ -698,6 +698,8 @@ class StreamRequest extends StreamRequestBuilder { /** * @param IQueryBuilder $qb * @param Person $actor + * + * @deprecated */ private function leftJoinFollowStatus(IQueryBuilder $qb, Person $actor) { if ($qb->getType() !== QueryBuilder::SELECT) { @@ -720,6 +722,8 @@ class StreamRequest extends StreamRequestBuilder { /** * @param IQueryBuilder $qb + * + * @deprecated */ private function filterDuplicate(IQueryBuilder $qb) { $actor = $this->viewer; diff --git a/lib/Db/StreamRequestBuilder.php b/lib/Db/StreamRequestBuilder.php index 55934151..54dce9a4 100644 --- a/lib/Db/StreamRequestBuilder.php +++ b/lib/Db/StreamRequestBuilder.php @@ -103,7 +103,7 @@ class StreamRequestBuilder extends CoreRequestBuilder { ) ->from(self::TABLE_STREAM, 's'); - $this->defaultSelectAlias = 's'; + $qb->setDefaultSelectAlias('s'); return $qb; } @@ -197,56 +197,6 @@ class StreamRequestBuilder extends CoreRequestBuilder { } - /** - * @param IQueryBuilder $qb - * @param string $aliasDest - * @param string $aliasFollowing - */ - protected function selectDestFollowing( - IQueryBuilder $qb, string $aliasDest = 'sd', string $aliasFollowing = 'f' - ) { - if ($qb->getType() !== QueryBuilder::SELECT) { - return; - } - - $qb->from(self::TABLE_STREAM_DEST, $aliasDest); - $qb->from(self::TABLE_FOLLOWS, $aliasFollowing); - } - - - /** - * @param IQueryBuilder $qb - * @param Person $actor - * @param string $field - * @param string $aliasDest - * @param string $aliasFollowing - * - * @param string $alias - * - * @return ICompositeExpression - */ - protected function exprInnerJoinDestFollowing( - IQueryBuilder $qb, Person $actor, string $field = 'id_prim', string $aliasDest = 'sd', - string $aliasFollowing = 'f', string $alias = '' - ): ICompositeExpression { - - $expr = $qb->expr(); - $andX = $expr->andX(); - - $pf = (($alias === '') ? $this->defaultSelectAlias : $alias) . '.'; - $andX->add( - $this->exprLimitToDBField( - $qb, 'actor_id_prim', $this->prim($actor->getId()), true, true, $aliasFollowing - ) - ); - $andX->add($this->exprLimitToDBFieldInt($qb, 'accepted', 1, $aliasFollowing)); - $andX->add($expr->eq($aliasFollowing . '.follow_id_prim', $aliasDest . '.actor_id')); - $andX->add($expr->eq($aliasDest . '.stream_id', $pf . $field)); - - return $andX; - } - - /** * @param IQueryBuilder $qb * @param Person $actor @@ -380,7 +330,7 @@ class StreamRequestBuilder extends CoreRequestBuilder { * @param string $recipient * @param bool $asAuthor * @param array $type - * + * @deprecated * @return ICompositeExpression */ protected function exprLimitToRecipient( diff --git a/lib/Migration/Version0002Date20190916000001.php b/lib/Migration/Version0002Date20190916000001.php index 07ea1b6a..9de43f5d 100644 --- a/lib/Migration/Version0002Date20190916000001.php +++ b/lib/Migration/Version0002Date20190916000001.php @@ -127,10 +127,17 @@ class Version0002Date20190916000001 extends SimpleMigrationStep { 'length' => 15, ] ); + $table->addColumn( + 'subtype', 'string', + [ + 'notnull' => false, + 'length' => 7, + ] + ); if (!$table->hasIndex('sat')) { $table->addUniqueIndex(['stream_id', 'actor_id', 'type'], 'sat'); - $table->addUniqueIndex(['stream_id', 'actor_id'], 'sa'); + $table->addIndex(['type', 'subtype'], 'ts'); } } @@ -361,12 +368,11 @@ class Version0002Date20190916000001 extends SimpleMigrationStep { private function insertStreamDest($data) { $recipients = []; $recipients['to'] = array_merge(json_decode($data['to_array'], true), [$data['to']]); - $recipients['cc'] = json_decode($data['cc'], true); - $recipients['bcc'] = json_decode($data['bcc'], true); + $recipients['cc'] = array_merge(json_decode($data['cc'], true), json_decode($data['bcc'], true)); $streamId = $data['id_prim']; foreach (array_keys($recipients) as $dest) { - $type = $dest; + $subtype = $dest; foreach ($recipients[$dest] as $actorId) { if ($actorId === '') { continue; @@ -377,6 +383,7 @@ class Version0002Date20190916000001 extends SimpleMigrationStep { $insert->setValue('stream_id', $insert->createNamedParameter($streamId)); $insert->setValue('actor_id', $insert->createNamedParameter(hash('sha512', $actorId))); $insert->setValue('type', $insert->createNamedParameter('recipient')); + $insert->setValue('subtype', $insert->createNamedParameter($subtype)); try { $insert->execute(); diff --git a/lib/Migration/Version0002Date20190916000002.php b/lib/Migration/Version0002Date20190916000002.php index bd18c1fa..c2d87f9f 100644 --- a/lib/Migration/Version0002Date20190916000002.php +++ b/lib/Migration/Version0002Date20190916000002.php @@ -112,10 +112,10 @@ class Version0002Date20190916000002 extends SimpleMigrationStep { $table->addUniqueIndex(['id_prim'], 'i'); } - $table = $schema->getTable('social_a2_stream_action'); - if (!$table->hasIndex('sa')) { - $table->addUniqueIndex(['stream_id_prim', 'actor_id_prim'], 'sa'); - } +// $table = $schema->getTable('social_a2_stream_action'); +// if (!$table->hasIndex('sa')) { +// $table->addUniqueIndex(['stream_id_prim', 'actor_id_prim'], 'sa'); +// } return $schema; }