kopia lustrzana https://github.com/nextcloud/social
				
				
				
			
		
			
	
	
		
			526 wiersze
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
		
		
			
		
	
	
			526 wiersze
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
|   | <?php | ||
|  | 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\Service; | ||
|  | 
 | ||
|  | 
 | ||
|   | use daita\MySmallPhpTools\Exceptions\MalformedArrayException; | ||
|   | use Exception; | ||
|   | use OCA\Social\Db\StreamRequest; | ||
|   | use OCA\Social\Exceptions\InvalidOriginException; | ||
|   | use OCA\Social\Exceptions\InvalidResourceException; | ||
|  | use OCA\Social\Exceptions\ItemUnknownException; | ||
|   | use OCA\Social\Exceptions\StreamNotFoundException; | ||
|   | use OCA\Social\Exceptions\RedundancyLimitException; | ||
|   | use OCA\Social\Exceptions\RequestContentException; | ||
|  | use OCA\Social\Exceptions\RequestNetworkException; | ||
|   | use OCA\Social\Exceptions\RequestResultNotJsonException; | ||
|   | use OCA\Social\Exceptions\RequestResultSizeException; | ||
|  | use OCA\Social\Exceptions\RequestServerException; | ||
|   | use OCA\Social\Exceptions\SocialAppConfigException; | ||
|   | use OCA\Social\Exceptions\UnauthorizedFediverseException; | ||
|   | use OCA\Social\Model\ActivityPub\ACore; | ||
|   | use OCA\Social\Model\ActivityPub\Actor\Person; | ||
|  | use OCA\Social\Model\ActivityPub\Object\Note; | ||
|   | use OCA\Social\Model\ActivityPub\Stream; | ||
|   | use OCA\Social\Model\InstancePath; | ||
|  | 
 | ||
|   | 
 | ||
|  | class StreamService { | ||
|   | 
 | ||
|  | 
 | ||
|   | 	/** @var StreamRequest */ | ||
|  | 	private $streamRequest; | ||
|   | 
 | ||
|  | 	/** @var ActivityService */ | ||
|  | 	private $activityService; | ||
|  | 
 | ||
|  | 	/** @var AccountService */ | ||
|  | 	private $accountService; | ||
|  | 
 | ||
|   | 	/** @var SignatureService */ | ||
|  | 	private $signatureService; | ||
|  | 
 | ||
|   | 	/** @var StreamQueueService */ | ||
|  | 	private $streamQueueService; | ||
|  | 
 | ||
|   | 	/** @var CacheActorService */ | ||
|  | 	private $cacheActorService; | ||
|  | 
 | ||
|  | 	/** @var ConfigService */ | ||
|  | 	private $configService; | ||
|  | 
 | ||
|  | 	/** @var MiscService */ | ||
|  | 	private $miscService; | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** @var Person */ | ||
|  | 	private $viewer = null; | ||
|   | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * NoteService constructor. | ||
|  | 	 * | ||
|   | 	 * @param StreamRequest $streamRequest | ||
|   | 	 * @param ActivityService $activityService | ||
|  | 	 * @param AccountService $accountService | ||
|   | 	 * @param SignatureService $signatureService | ||
|   | 	 * @param StreamQueueService $streamQueueService | ||
|   | 	 * @param CacheActorService $cacheActorService | ||
|  | 	 * @param ConfigService $configService | ||
|  | 	 * @param MiscService $miscService | ||
|  | 	 */ | ||
|  | 	public function __construct( | ||
|   | 		StreamRequest $streamRequest, ActivityService $activityService, | ||
|   | 		AccountService $accountService, SignatureService $signatureService, | ||
|   | 		StreamQueueService $streamQueueService, CacheActorService $cacheActorService, | ||
|  | 		ConfigService $configService, MiscService $miscService | ||
|   | 	) { | ||
|   | 		$this->streamRequest = $streamRequest; | ||
|   | 		$this->activityService = $activityService; | ||
|  | 		$this->accountService = $accountService; | ||
|   | 		$this->signatureService = $signatureService; | ||
|   | 		$this->streamQueueService = $streamQueueService; | ||
|   | 		$this->cacheActorService = $cacheActorService; | ||
|  | 		$this->configService = $configService; | ||
|  | 		$this->miscService = $miscService; | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|   | 	 * @param Person $viewer | ||
|   | 	 */ | ||
|   | 	public function setViewer(Person $viewer) { | ||
|  | 		$this->viewer = $viewer; | ||
|   | 		$this->streamRequest->setViewer($viewer); | ||
|   | 	} | ||
|  | 
 | ||
|   | 
 | ||
|  | 	/** | ||
|   | 	 * @param ACore $stream | ||
|   | 	 * @param Person $actor | ||
|   | 	 * @param string $type | ||
|   | 	 * | ||
|  | 	 * @throws SocialAppConfigException | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|   | 	public function assignItem(Acore &$stream, Person $actor, string $type) { | ||
|  | 		$stream->setId($this->configService->generateId('@' . $actor->getPreferredUsername())); | ||
|  | 		$stream->setPublished(date("c")); | ||
|   | 
 | ||
|   | 		$this->setRecipient($stream, $actor, $type); | ||
|  | 		$stream->setLocal(true); | ||
|   | 
 | ||
|   | 		if ($stream instanceof Stream) { | ||
|  | 			$this->assignStream($stream); | ||
|   | 		} | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|   | 	 * @param Stream $stream | ||
|   | 	 * | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|   | 	public function assignStream(Stream &$stream) { | ||
|   | 		$stream->convertPublished(); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|   | 	 * @param ACore $stream | ||
|   | 	 * @param Person $actor | ||
|  | 	 * @param string $type | ||
|  | 	 */ | ||
|   | 	private function setRecipient(ACore $stream, Person $actor, string $type) { | ||
|   | 		switch ($type) { | ||
|   | 			case Stream::TYPE_UNLISTED: | ||
|   | 				$stream->setTo($actor->getFollowers()); | ||
|  | 				$stream->addInstancePath( | ||
|   | 					new InstancePath( | ||
|  | 						$actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, | ||
|  | 						InstancePath::PRIORITY_LOW | ||
|  | 					) | ||
|  | 				); | ||
|   | 				$stream->addCc(ACore::CONTEXT_PUBLIC); | ||
|   | 				break; | ||
|  | 
 | ||
|   | 			case Stream::TYPE_FOLLOWERS: | ||
|   | 				$stream->setTo($actor->getFollowers()); | ||
|  | 				$stream->addInstancePath( | ||
|   | 					new InstancePath( | ||
|  | 						$actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, | ||
|  | 						InstancePath::PRIORITY_LOW | ||
|  | 					) | ||
|  | 				); | ||
|  | 				break; | ||
|  | 
 | ||
|   | 			case Stream::TYPE_ANNOUNCE: | ||
|  | 				$stream->addInstancePath( | ||
|  | 					new InstancePath( | ||
|  | 						$actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, | ||
|  | 						InstancePath::PRIORITY_LOW | ||
|  | 					) | ||
|  | 				); | ||
|  | 				$stream->addCc($actor->getFollowers()); | ||
|  | 				break; | ||
|  | 
 | ||
|  | 			case Stream::TYPE_DIRECT: | ||
|   | 				break; | ||
|  | 
 | ||
|  | 			default: | ||
|   | 				$stream->setTo(ACore::CONTEXT_PUBLIC); | ||
|  | 				$stream->addCc($actor->getFollowers()); | ||
|  | 				$stream->addInstancePath( | ||
|   | 					new InstancePath( | ||
|  | 						$actor->getFollowers(), InstancePath::TYPE_FOLLOWERS, | ||
|  | 						InstancePath::PRIORITY_LOW | ||
|  | 					) | ||
|  | 				); | ||
|  | 				break; | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param $stream | ||
|  | 	 */ | ||
|  | 	public function detectType(Stream $stream) { | ||
|  | 		if (in_array(ACore::CONTEXT_PUBLIC, $stream->getToAll())) { | ||
|  | 			$stream->setType(Stream::TYPE_PUBLIC); | ||
|  | 
 | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (in_array(ACore::CONTEXT_PUBLIC, $stream->getCcArray())) { | ||
|  | 			$stream->setType(Stream::TYPE_UNLISTED); | ||
|  | 
 | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		try { | ||
|  | 			$actor = $this->cacheActorService->getFromId($stream->getAttributedTo()); | ||
|  | 			echo json_encode($actor) . "\n"; | ||
|  | 		} catch (Exception $e) { | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|   | 	 * @param Stream $stream | ||
|   | 	 * @param string $type | ||
|  | 	 * @param string $account | ||
|  | 	 */ | ||
|   | 	public function addRecipient(Stream $stream, string $type, string $account) { | ||
|   | 		if ($account === '') { | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		try { | ||
|  | 			$actor = $this->cacheActorService->getFromAccount($account); | ||
|  | 		} catch (Exception $e) { | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		$instancePath = new InstancePath( | ||
|  | 			$actor->getInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_MEDIUM | ||
|  | 		); | ||
|   | 		if ($type === Stream::TYPE_DIRECT) { | ||
|   | 			$instancePath->setPriority(InstancePath::PRIORITY_HIGH); | ||
|   | 			$stream->addToArray($actor->getId()); | ||
|   | 		} else { | ||
|   | 			$stream->addCc($actor->getId()); | ||
|   | 		} | ||
|  | 
 | ||
|   | 		$stream->addTag( | ||
|   | 			[ | ||
|  | 				'type' => 'Mention', | ||
|   | 				'href' => $actor->getId(), | ||
|  | 				'name' => '@' . $account | ||
|   | 			] | ||
|  | 		); | ||
|  | 
 | ||
|   | 		$stream->addInstancePath($instancePath); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param Note $note | ||
|  | 	 * @param string $hashtag | ||
|  | 	 */ | ||
|  | 	public function addHashtag(Note $note, string $hashtag) { | ||
|  | 		try { | ||
|  | 			$note->addTag( | ||
|  | 				[ | ||
|  | 					'type' => 'Hashtag', | ||
|   | 					'href' => $this->configService->getSocialUrl() . 'tag/' . strtolower( | ||
|   | 							$hashtag | ||
|  | 						), | ||
|  | 					'name' => '#' . $hashtag | ||
|  | 				] | ||
|  | 			); | ||
|  | 		} catch (SocialAppConfigException $e) { | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|   | 	 * @param Stream $stream | ||
|   | 	 * @param string $type | ||
|  | 	 * @param array $accounts | ||
|  | 	 */ | ||
|   | 	public function addRecipients(Stream $stream, string $type, array $accounts) { | ||
|   | 		foreach ($accounts as $account) { | ||
|   | 			$this->addRecipient($stream, $type, $account); | ||
|   | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param Note $note | ||
|  | 	 * @param array $hashtags | ||
|  | 	 */ | ||
|  | 	public function addHashtags(Note $note, array $hashtags) { | ||
|   | 		$note->setHashtags($hashtags); | ||
|   | 		foreach ($hashtags as $hashtag) { | ||
|  | 			$this->addHashtag($note, $hashtag); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param Note $note | ||
|  | 	 * @param string $replyTo | ||
|   | 	 * | ||
|  | 	 * @throws InvalidOriginException | ||
|  | 	 * @throws InvalidResourceException | ||
|   | 	 * @throws ItemUnknownException | ||
|   | 	 * @throws MalformedArrayException | ||
|  | 	 * @throws RedundancyLimitException | ||
|   | 	 * @throws RequestContentException | ||
|  | 	 * @throws RequestNetworkException | ||
|   | 	 * @throws RequestResultNotJsonException | ||
|   | 	 * @throws RequestResultSizeException | ||
|  | 	 * @throws RequestServerException | ||
|   | 	 * @throws SocialAppConfigException | ||
|   | 	 * @throws StreamNotFoundException | ||
|  | 	 * @throws UnauthorizedFediverseException | ||
|   | 	 */ | ||
|  | 	public function replyTo(Note $note, string $replyTo) { | ||
|  | 		if ($replyTo === '') { | ||
|  | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|   | 		$author = $this->getAuthorFromPostId($replyTo); | ||
|   | 		$note->setInReplyTo($replyTo); | ||
|  | 		// TODO - type can be NOT public !
 | ||
|  | 		$note->addInstancePath( | ||
|   | 			new InstancePath( | ||
|  | 				$author->getSharedInbox(), InstancePath::TYPE_INBOX, InstancePath::PRIORITY_HIGH | ||
|  | 			) | ||
|   | 		); | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|   | 	 * @param Stream $item | ||
|   | 	 * @param string $type | ||
|   | 	 * | ||
|  | 	 * @throws Exception | ||
|  | 	 */ | ||
|   | 	public function deleteLocalItem(Stream $item, string $type = '') { | ||
|   | 		if (!$item->isLocal()) { | ||
|   | 			return; | ||
|  | 		} | ||
|  | 
 | ||
|   | 		$item->setActorId($item->getAttributedTo()); | ||
|  | 		$this->activityService->deleteActivity($item); | ||
|   | 		$this->streamRequest->deleteStreamById($item->getId(), $type); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param string $id | ||
|   | 	 * @param bool $asViewer | ||
|   | 	 * | ||
|   | 	 * @return Stream | ||
|   | 	 * @throws StreamNotFoundException | ||
|   | 	 */ | ||
|   | 	public function getStreamById(string $id, bool $asViewer = false): Stream { | ||
|   | 		return $this->streamRequest->getStreamById($id, $asViewer); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param Person $actor | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamHome(Person $actor, int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineHome($actor, $since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param Person $actor | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamNotifications(Person $actor, int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineNotifications($actor, $since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param string $actorId | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamAccount(string $actorId, int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineAccount($actorId, $since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param Person $actor | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamDirect(Person $actor, int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineDirect($actor, $since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|  | 	/** | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamLocalTimeline(int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineGlobal($since, $limit, true); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|   | 	 * @param Person $actor | ||
|   | 	 * @param string $hashtag | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|   | 	public function getStreamLocalTag(Person $actor, string $hashtag, int $since = 0, int $limit = 5 | ||
|  | 	): array { | ||
|   | 		return $this->streamRequest->getTimelineTag($actor, $hashtag, $since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|  | 	 */ | ||
|  | 	public function getStreamInternalTimeline(int $since = 0, int $limit = 5): array { | ||
|  | 		// TODO - admin should be able to provide a list of 'friendly/internal' instance of ActivityPub
 | ||
|  | 		return []; | ||
|  | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|   | 	 * | ||
|   | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|   | 	 * @throws Exception | ||
|   | 	 */ | ||
|  | 	public function getStreamGlobalTimeline(int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineGlobal($since, $limit, false); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * | ||
|  | 	 * @param int $since | ||
|  | 	 * @param int $limit | ||
|  | 	 * | ||
|  | 	 * @return Note[] | ||
|  | 	 * @throws Exception | ||
|  | 	 */ | ||
|  | 	public function getStreamLiked(int $since = 0, int $limit = 5): array { | ||
|   | 		return $this->streamRequest->getTimelineLiked($since, $limit); | ||
|   | 	} | ||
|  | 
 | ||
|  | 
 | ||
|   | 	/** | ||
|  | 	 * @param $noteId | ||
|  | 	 * | ||
|  | 	 * @return Person | ||
|   | 	 * @throws InvalidOriginException | ||
|   | 	 * @throws InvalidResourceException | ||
|  | 	 * @throws MalformedArrayException | ||
|   | 	 * @throws StreamNotFoundException | ||
|   | 	 * @throws RedundancyLimitException | ||
|   | 	 * @throws SocialAppConfigException | ||
|  | 	 * @throws ItemUnknownException | ||
|  | 	 * @throws RequestContentException | ||
|  | 	 * @throws RequestNetworkException | ||
|  | 	 * @throws RequestResultSizeException | ||
|  | 	 * @throws RequestServerException | ||
|   | 	 * @throws RequestResultNotJsonException | ||
|   | 	 * @throws UnauthorizedFediverseException | ||
|   | 	 */ | ||
|  | 	public function getAuthorFromPostId($noteId) { | ||
|   | 		$note = $this->streamRequest->getStreamById($noteId); | ||
|   | 
 | ||
|  | 		return $this->cacheActorService->getFromId($note->getAttributedTo()); | ||
|  | 	} | ||
|  | 
 | ||
|   | 
 | ||
|   | } | ||
|  | 
 |