2019-09-29 11:39:25 +00:00
|
|
|
<?php
|
2022-04-15 11:34:01 +00:00
|
|
|
|
2019-09-29 11:39:25 +00:00
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Nextcloud - Social Support
|
|
|
|
*
|
|
|
|
* This file is licensed under the Affero General Public License version 3 or
|
|
|
|
* later. See the COPYING file.
|
|
|
|
*
|
|
|
|
* @author Maxence Lange <maxence@artificial-owl.com>
|
|
|
|
* @copyright 2018, Maxence Lange <maxence@artificial-owl.com>
|
|
|
|
* @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 <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
namespace OCA\Social\Db;
|
|
|
|
|
|
|
|
use Doctrine\DBAL\Query\QueryBuilder;
|
2020-09-01 14:14:19 +00:00
|
|
|
use OCA\Social\AP;
|
2020-08-28 02:35:57 +00:00
|
|
|
use OCA\Social\Exceptions\InvalidResourceException;
|
2020-09-01 14:14:19 +00:00
|
|
|
use OCA\Social\Model\ActivityPub\Actor\Person;
|
|
|
|
use OCA\Social\Model\ActivityPub\Object\Document;
|
|
|
|
use OCA\Social\Model\ActivityPub\Object\Image;
|
2019-09-29 15:41:47 +00:00
|
|
|
use OCP\DB\QueryBuilder\ICompositeExpression;
|
2019-09-29 11:39:25 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2019-09-29 15:41:47 +00:00
|
|
|
* @param string $link
|
2019-09-29 11:39:25 +00:00
|
|
|
*/
|
2019-10-01 11:53:26 +00:00
|
|
|
public function linkToStreamTags(string $alias = 'st', string $link = '') {
|
|
|
|
if ($this->getType() !== QueryBuilder::SELECT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->from(CoreRequestBuilder::TABLE_STREAM_TAGS, $alias);
|
|
|
|
if ($link !== '') {
|
|
|
|
$expr = $this->expr();
|
|
|
|
$this->andWhere($expr->eq($alias . '.stream_id', $link));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $alias
|
|
|
|
* @param string $link
|
|
|
|
*/
|
2022-05-11 17:13:46 +00:00
|
|
|
public function linkToCacheActors(string $alias = 'ca', string $link = '', bool $innerJoin = true) {
|
2019-09-29 11:39:25 +00:00
|
|
|
if ($this->getType() !== QueryBuilder::SELECT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pf = (($alias === '') ? $this->getDefaultSelectAlias() : $alias);
|
2020-09-01 14:14:19 +00:00
|
|
|
|
|
|
|
$expr = $this->expr();
|
|
|
|
if ($link !== '') {
|
2022-05-11 17:13:46 +00:00
|
|
|
if ($innerJoin) {
|
|
|
|
$this->innerJoin(
|
|
|
|
$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_CACHE_ACTORS, $pf,
|
|
|
|
$expr->eq('ca.id_prim', $link)
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
$this->leftJoin(
|
|
|
|
$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_CACHE_ACTORS, $pf,
|
|
|
|
$expr->eq('ca.id_prim', $link)
|
|
|
|
);
|
|
|
|
}
|
2020-09-01 14:14:19 +00:00
|
|
|
} else {
|
|
|
|
$this->from(CoreRequestBuilder::TABLE_CACHE_ACTORS, $pf);
|
|
|
|
}
|
|
|
|
|
2022-11-18 15:31:53 +00:00
|
|
|
$this->selectAlias($pf . '.id', 'cacheactor_id')
|
2023-03-13 11:11:04 +00:00
|
|
|
->selectAlias($pf . '.nid', 'cacheactor_nid')
|
2019-09-29 11:39:25 +00:00
|
|
|
->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')
|
2020-09-01 14:14:19 +00:00
|
|
|
->selectAlias($pf . '.details', 'cacheactor_details')
|
2019-09-29 11:39:25 +00:00
|
|
|
->selectAlias($pf . '.creation', 'cacheactor_creation')
|
|
|
|
->selectAlias($pf . '.local', 'cacheactor_local');
|
2020-09-01 14:14:19 +00:00
|
|
|
}
|
2019-09-29 15:41:47 +00:00
|
|
|
|
2020-09-01 14:14:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @param array $data
|
|
|
|
*
|
|
|
|
* @return Person
|
|
|
|
* @throws InvalidResourceException
|
|
|
|
*/
|
|
|
|
public function parseLeftJoinCacheActors(array $data): Person {
|
|
|
|
$new = [];
|
|
|
|
|
|
|
|
foreach ($data as $k => $v) {
|
|
|
|
if (substr($k, 0, 11) === 'cacheactor_') {
|
|
|
|
$new[substr($k, 11)] = $v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$actor = new Person();
|
|
|
|
$actor->importFromDatabase($new);
|
2020-09-02 13:07:57 +00:00
|
|
|
$actor->setAvatar(
|
|
|
|
$this->urlGenerator->linkToRouteAbsolute('social.Local.globalActorAvatar') . '?id='
|
|
|
|
. $actor->getId()
|
|
|
|
);
|
|
|
|
|
2020-09-01 14:14:19 +00:00
|
|
|
if (!AP::$activityPub->isActor($actor)) {
|
|
|
|
throw new InvalidResourceException();
|
|
|
|
}
|
|
|
|
|
|
|
|
return $actor;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $fieldDocumentId
|
|
|
|
* @param string $alias
|
|
|
|
*/
|
|
|
|
public function leftJoinCacheDocuments(string $fieldDocumentId, string $alias = '') {
|
|
|
|
if ($this->getType() !== QueryBuilder::SELECT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$expr = $this->expr();
|
|
|
|
$pf = (($alias === '') ? $this->getDefaultSelectAlias() : $alias);
|
|
|
|
$this->selectAlias('cd.id', 'cachedocument_id')
|
|
|
|
->selectAlias('cd.type', 'cachedocument_type')
|
|
|
|
->selectAlias('cd.mime_type', 'cachedocument_mime_type')
|
|
|
|
->selectAlias('cd.media_type', 'cachedocument_media_type')
|
|
|
|
->selectAlias('cd.url', 'cachedocument_url')
|
|
|
|
->selectAlias('cd.local_copy', 'cachedocument_local_copy')
|
|
|
|
->selectAlias('cd.caching', 'cachedocument_caching')
|
|
|
|
->selectAlias('cd.public', 'cachedocument_public')
|
|
|
|
->selectAlias('cd.error', 'cachedocument_error')
|
|
|
|
->selectAlias('cd.creation', 'cachedocument_creation')
|
|
|
|
->leftJoin(
|
2022-11-21 20:03:59 +00:00
|
|
|
$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_CACHE_DOCUMENTS, 'cd',
|
2023-03-15 15:25:49 +00:00
|
|
|
$expr->eq($pf . '.' . $fieldDocumentId, 'cd.id_prim')
|
2020-09-01 14:14:19 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param array $data
|
|
|
|
*
|
|
|
|
* @return Document
|
|
|
|
* @throws InvalidResourceException
|
|
|
|
*/
|
|
|
|
public function parseLeftJoinCacheDocuments(array $data): Document {
|
|
|
|
$new = [];
|
|
|
|
foreach ($data as $k => $v) {
|
|
|
|
if (substr($k, 0, 14) === 'cachedocument_') {
|
|
|
|
$new[substr($k, 14)] = $v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$document = new Document();
|
|
|
|
$document->importFromDatabase($new);
|
|
|
|
|
|
|
|
if ($document->getType() !== Image::TYPE) {
|
|
|
|
throw new InvalidResourceException();
|
2019-09-29 15:41:47 +00:00
|
|
|
}
|
|
|
|
|
2020-09-01 14:14:19 +00:00
|
|
|
return $document;
|
2019-09-29 11:39:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @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);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-29 15:41:47 +00:00
|
|
|
/**
|
|
|
|
* @param string $alias
|
|
|
|
*/
|
2020-08-28 02:35:57 +00:00
|
|
|
public function selectStreamActions(string $alias = 'sa'): void {
|
2019-09-29 15:41:47 +00:00
|
|
|
if ($this->getType() !== QueryBuilder::SELECT) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$pf = (($alias === '') ? $this->getDefaultSelectAlias() : $alias);
|
|
|
|
$this->from(CoreRequestBuilder::TABLE_STREAM_ACTIONS, $pf);
|
|
|
|
$this->selectAlias('sa.id', 'streamaction_id')
|
|
|
|
->selectAlias('sa.actor_id', 'streamaction_actor_id')
|
|
|
|
->selectAlias('sa.stream_id', 'streamaction_stream_id')
|
|
|
|
->selectAlias('sa.values', 'streamaction_values');
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-29 11:39:25 +00:00
|
|
|
/**
|
|
|
|
* @param string $alias
|
|
|
|
*/
|
2020-08-28 02:35:57 +00:00
|
|
|
public function leftJoinStreamAction(string $alias = 'sa'): void {
|
2019-09-29 11:39:25 +00:00
|
|
|
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);
|
|
|
|
|
2020-07-31 13:21:59 +00:00
|
|
|
$this->leftJoin(
|
|
|
|
$this->getDefaultSelectAlias(), CoreRequestBuilder::TABLE_STREAM_ACTIONS, $alias, $on
|
|
|
|
);
|
2019-09-29 11:39:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-30 16:28:59 +00:00
|
|
|
/**
|
|
|
|
* @param string $type
|
|
|
|
* @param string $field
|
|
|
|
* @param string $aliasDest
|
|
|
|
* @param string $alias
|
|
|
|
*/
|
2022-12-07 00:14:12 +00:00
|
|
|
public function innerJoinStreamDest(
|
2019-09-30 16:28:59 +00:00
|
|
|
string $type, string $field = 'id_prim', string $aliasDest = 'sd', string $alias = ''
|
|
|
|
) {
|
2019-10-01 11:53:26 +00:00
|
|
|
$this->andWhere($this->exprInnerJoinStreamDest($type, $field, $aliasDest, $alias));
|
2019-09-30 16:28:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $type
|
|
|
|
* @param string $field
|
|
|
|
* @param string $aliasDest
|
|
|
|
* @param string $alias
|
|
|
|
*
|
|
|
|
* @return ICompositeExpression
|
|
|
|
*/
|
2019-10-01 11:53:26 +00:00
|
|
|
public function exprInnerJoinStreamDest(
|
2019-09-30 16:28:59 +00:00
|
|
|
string $type, string $field = 'id_prim', string $aliasDest = 'sd', string $alias = ''
|
|
|
|
): ICompositeExpression {
|
|
|
|
$expr = $this->expr();
|
|
|
|
$andX = $expr->andX();
|
|
|
|
$pf = (($alias === '') ? $this->getdefaultSelectAlias() : $alias) . '.';
|
|
|
|
$andX->add($expr->eq($aliasDest . '.stream_id', $pf . $field));
|
|
|
|
$andX->add($expr->eq($aliasDest . '.type', $this->createNamedParameter($type)));
|
|
|
|
|
|
|
|
return $andX;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-10-01 11:53:26 +00:00
|
|
|
/**
|
|
|
|
* @param string $actorId
|
|
|
|
* @param string $type
|
|
|
|
* @param string $field
|
|
|
|
* @param string $aliasDest
|
|
|
|
* @param string $aliasFollowing
|
|
|
|
* @param string $alias
|
|
|
|
*/
|
|
|
|
public function innerJoinStreamDestFollowing(
|
2019-09-30 16:28:59 +00:00
|
|
|
string $actorId, string $type, string $field = 'id_prim', string $aliasDest = 'sd',
|
|
|
|
string $aliasFollowing = 'f', string $alias = ''
|
|
|
|
) {
|
|
|
|
$this->andWhere(
|
2019-10-01 11:53:26 +00:00
|
|
|
$this->exprInnerJoinStreamDestFollowing(
|
|
|
|
$actorId, $type, $field, $aliasDest, $aliasFollowing, $alias
|
|
|
|
)
|
2019-09-30 16:28:59 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-09-29 11:39:25 +00:00
|
|
|
/**
|
|
|
|
* @param string $actorId
|
|
|
|
* @param string $type
|
|
|
|
* @param string $field
|
|
|
|
* @param string $aliasDest
|
|
|
|
* @param string $aliasFollowing
|
|
|
|
* @param string $alias
|
2019-09-29 15:41:47 +00:00
|
|
|
*
|
|
|
|
* @return ICompositeExpression
|
2019-09-29 11:39:25 +00:00
|
|
|
*/
|
2019-10-01 11:53:26 +00:00
|
|
|
public function exprInnerJoinStreamDestFollowing(
|
2019-09-29 11:39:25 +00:00
|
|
|
string $actorId, string $type, string $field = 'id_prim', string $aliasDest = 'sd',
|
|
|
|
string $aliasFollowing = 'f', string $alias = ''
|
2019-09-29 15:41:47 +00:00
|
|
|
): ICompositeExpression {
|
2019-09-29 11:39:25 +00:00
|
|
|
$expr = $this->expr();
|
|
|
|
$andX = $expr->andX();
|
2019-09-30 16:28:59 +00:00
|
|
|
|
2019-09-29 11:39:25 +00:00
|
|
|
$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)));
|
|
|
|
|
2019-09-29 15:41:47 +00:00
|
|
|
return $andX;
|
2019-09-29 11:39:25 +00:00
|
|
|
}
|
|
|
|
}
|