Merge remote-tracking branch 'origin/master'

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/695/head
Maxence Lange 2019-08-22 13:16:53 -01:00
commit bf09c86a80
51 zmienionych plików z 3117 dodań i 1328 usunięć

Wyświetl plik

@ -56,6 +56,7 @@
<command>OCA\Social\Command\NoteCreate</command>
<command>OCA\Social\Command\NoteBoost</command>
<command>OCA\Social\Command\Reset</command>
<command>OCA\Social\Command\StreamDetails</command>
<command>OCA\Social\Command\Timeline</command>
<command>OCA\Social\Command\QueueStatus</command>
<command>OCA\Social\Command\QueueProcess</command>

Wyświetl plik

@ -1,7 +1,13 @@
@include icon-black-white('reply', 'social', 1);
@include icon-black-white('emoji', 'social', 1);
@include icon-black-white('boost', 'social', 1);
.icon-boosted {
@include icon-color('boost', 'social', '#0082c9', 1);
}
img.emoji {
margin: 3px;
width: 16px;
vertical-align: text-bottom;
}

Wyświetl plik

@ -3,6 +3,9 @@ OC.L10N.register(
{
"Social" : "Social",
"🎉 Nextcloud becomes part of the federated social networks!" : "¡🎉 Nextcloud pasa a ser parte de las redes sociales federadas!",
"** Disclaimer: this is an ALPHA version **\n\n**🎉 Nextcloud becomes part of the federated social networks!**\n\n**🙋 Find your friends:** No matter if they use Nextcloud, 🐘 Mastodon, 🇫 Friendica, and soon ✱ Diaspora, 👹 MediaGoblin and more – you can follow them!\n\n**📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.\n\n**👐 Own your posts:** Everything you post stays on your Nextcloud!\n\n**🕸 Open standards:** We use the established ActivityPub standard!" : "** AVISO: Esta es una versión ALFA **\n\n**¡🎉 Nextcloud pasa a ser parte de las redes sociales federadas!**\n\n**🙋 Encuentra a tus amigos:** No importa si usan Nextcloud, 🐘 Mastodon, 🇫 Friendica, y pronto ✱ Diaspora, 👹 MediaGoblin y más, ¡Puedes seguirlos a todos!\n\n**📜 Información de perfil:** Sin necesidad de rellenar más perfiles – se usará y extenderá la información de tu perfil de Nextcloud. \n\n**👐 Sé el dueño de tu material:** ¡Todo lo que cuelgues permanece en tu Nextcloud!\n\n**🕸 Estándares abiertos:** ¡Usamos el estándar establecido ActivityPub! ",
".well-known/webfinger isn't properly set up!" : ".well-known/webfinger no está bien configurado",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Social necesita que el descubrimiento automático de .well-known esté bien configurado. Si Nextcloud no está instalado en la raíz del dominio, a menudo se da el caso de que Nextcloud no puede configurarlo automáticamente. Para usar Social, el administrador de esta instancia de Netcloud debe configurar manualmente las redirecciones .well-known:",
"Open documentation" : "Abrir la documentación",
"Social app setup" : "Configuración de la app Social",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPub necesita una URL fija para hacer únicas las entradas. Nota: esto no puede cambiarse más tarde sin reiniciar la app Social.",
@ -37,6 +40,7 @@ OC.L10N.register(
"No results found" : "No se han encontrado resultados",
"There were no results for your search:" : "No ha habido resultados para tu búsqueda:",
"Searching for" : "Buscando",
"boosted" : "reforzado",
"No posts found" : "No se han encontrado entradas",
"Posts from people you follow will show up here" : "Las entradas de gente a la que sigues aparecerán aquí",
"No direct messages found" : "No se han encontrado mensajes directos",
@ -45,8 +49,10 @@ OC.L10N.register(
"Posts from other people on this instance will show up here" : "Las entradas de otras personas en esta instancia aparecerán aquí",
"No global posts found" : "No se han encontrado entradas globales",
"Posts from federated instances will show up here" : "Las entradas de instancias federadas aparecerán aquí",
"No liked posts found" : "No se han encontrado entradas con Me gusta",
"No posts found for this tag" : "No se han encontrado post para este tag",
"Reply" : "Responder",
"Boost" : "Refuerzo",
"Like" : "Me gusta",
"More actions" : "Más acciones",
"Delete post" : "Borrar post",

Wyświetl plik

@ -1,6 +1,9 @@
{ "translations": {
"Social" : "Social",
"🎉 Nextcloud becomes part of the federated social networks!" : "¡🎉 Nextcloud pasa a ser parte de las redes sociales federadas!",
"** Disclaimer: this is an ALPHA version **\n\n**🎉 Nextcloud becomes part of the federated social networks!**\n\n**🙋 Find your friends:** No matter if they use Nextcloud, 🐘 Mastodon, 🇫 Friendica, and soon ✱ Diaspora, 👹 MediaGoblin and more – you can follow them!\n\n**📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.\n\n**👐 Own your posts:** Everything you post stays on your Nextcloud!\n\n**🕸 Open standards:** We use the established ActivityPub standard!" : "** AVISO: Esta es una versión ALFA **\n\n**¡🎉 Nextcloud pasa a ser parte de las redes sociales federadas!**\n\n**🙋 Encuentra a tus amigos:** No importa si usan Nextcloud, 🐘 Mastodon, 🇫 Friendica, y pronto ✱ Diaspora, 👹 MediaGoblin y más, ¡Puedes seguirlos a todos!\n\n**📜 Información de perfil:** Sin necesidad de rellenar más perfiles – se usará y extenderá la información de tu perfil de Nextcloud. \n\n**👐 Sé el dueño de tu material:** ¡Todo lo que cuelgues permanece en tu Nextcloud!\n\n**🕸 Estándares abiertos:** ¡Usamos el estándar establecido ActivityPub! ",
".well-known/webfinger isn't properly set up!" : ".well-known/webfinger no está bien configurado",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Social necesita que el descubrimiento automático de .well-known esté bien configurado. Si Nextcloud no está instalado en la raíz del dominio, a menudo se da el caso de que Nextcloud no puede configurarlo automáticamente. Para usar Social, el administrador de esta instancia de Netcloud debe configurar manualmente las redirecciones .well-known:",
"Open documentation" : "Abrir la documentación",
"Social app setup" : "Configuración de la app Social",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPub necesita una URL fija para hacer únicas las entradas. Nota: esto no puede cambiarse más tarde sin reiniciar la app Social.",
@ -35,6 +38,7 @@
"No results found" : "No se han encontrado resultados",
"There were no results for your search:" : "No ha habido resultados para tu búsqueda:",
"Searching for" : "Buscando",
"boosted" : "reforzado",
"No posts found" : "No se han encontrado entradas",
"Posts from people you follow will show up here" : "Las entradas de gente a la que sigues aparecerán aquí",
"No direct messages found" : "No se han encontrado mensajes directos",
@ -43,8 +47,10 @@
"Posts from other people on this instance will show up here" : "Las entradas de otras personas en esta instancia aparecerán aquí",
"No global posts found" : "No se han encontrado entradas globales",
"Posts from federated instances will show up here" : "Las entradas de instancias federadas aparecerán aquí",
"No liked posts found" : "No se han encontrado entradas con Me gusta",
"No posts found for this tag" : "No se han encontrado post para este tag",
"Reply" : "Responder",
"Boost" : "Refuerzo",
"Like" : "Me gusta",
"More actions" : "Más acciones",
"Delete post" : "Borrar post",

Wyświetl plik

@ -3,11 +3,11 @@ OC.L10N.register(
{
"🎉 Nextcloud becomes part of the federated social networks!" : "🎉 Nextcloudは分散ソーシャルネットワークの一部になります",
"** Disclaimer: this is an ALPHA version **\n\n**🎉 Nextcloud becomes part of the federated social networks!**\n\n**🙋 Find your friends:** No matter if they use Nextcloud, 🐘 Mastodon, 🇫 Friendica, and soon ✱ Diaspora, 👹 MediaGoblin and more – you can follow them!\n\n**📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.\n\n**👐 Own your posts:** Everything you post stays on your Nextcloud!\n\n**🕸 Open standards:** We use the established ActivityPub standard!" : "** 免責事項:これはアルファ版です **\n\n** 🎉 Nextcloudは分散型ソーシャルネットワークの一部になります**\n\n**🙋友達を探す:** Nextcloud、Mastodon、Friendica、近日中にはDiaspora、MediaGoblinなどを使用していてもフォローすることができます\n\n** プロフィール情報:**これ以上プロフィールを記入する必要はありません - Nextcloudからのあなたの情報は使用され、広がってゆきます。\n\n**👐自分の投稿:**投稿したものはすべてNextcloudに残ります\n\n**オープンスタンダード:**確立されたActivityPub形式を使用しています",
".well-known/webfinger isn't properly set up!" : ".well-known / webfingerが正しく設定されていません",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Socialが適切に設定されるためには、well-knownの自動検出が必要です。 Nextcloudがドメインのルートにインストールされていない場合、Nextcloudがこれを自動的に設定できないことがよくあります。 Socialを使用するには、このNextcloudインスタンスの管理者は手動で.well-knownリダイレクトを設定する必要があります。",
".well-known/webfinger isn't properly set up!" : ".well-known/webfingerが正しく設定されていません",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Socialが適切に設定されるためには、.well-knownの自動検出が必要です。 Nextcloudがドメインのルートにインストールされていない場合、Nextcloudがこれを自動的に設定できないことがよくあります。 Socialを使用するには、このNextcloudインスタンスの管理者は手動で.well-knownリダイレクトを設定する必要があります。",
"Open documentation" : "ドキュメントを開く",
"Social app setup" : "Socialアプリのセットアップ",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPubでは、エントリを一意にするために固定のURLが必要です。 \nこれは、Socialアプリをリセットせずに後で変更することはできません。",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPubでは、エントリを一意にするために固定のURLが必要です。 これは、Socialアプリをリセットせずに後で変更することはできません。",
"ActivityPub URL base" : "ActivityPub URLベース",
"Finish setup" : "セットアップを終了",
"The Social app needs to be set up by the server administrator." : "Socialアプリはサーバー管理者が設定する必要があります。",

Wyświetl plik

@ -1,11 +1,11 @@
{ "translations": {
"🎉 Nextcloud becomes part of the federated social networks!" : "🎉 Nextcloudは分散ソーシャルネットワークの一部になります",
"** Disclaimer: this is an ALPHA version **\n\n**🎉 Nextcloud becomes part of the federated social networks!**\n\n**🙋 Find your friends:** No matter if they use Nextcloud, 🐘 Mastodon, 🇫 Friendica, and soon ✱ Diaspora, 👹 MediaGoblin and more – you can follow them!\n\n**📜 Profile info:** No need to fill out more profiles – your info from Nextcloud will be used and extended.\n\n**👐 Own your posts:** Everything you post stays on your Nextcloud!\n\n**🕸 Open standards:** We use the established ActivityPub standard!" : "** 免責事項:これはアルファ版です **\n\n** 🎉 Nextcloudは分散型ソーシャルネットワークの一部になります**\n\n**🙋友達を探す:** Nextcloud、Mastodon、Friendica、近日中にはDiaspora、MediaGoblinなどを使用していてもフォローすることができます\n\n** プロフィール情報:**これ以上プロフィールを記入する必要はありません - Nextcloudからのあなたの情報は使用され、広がってゆきます。\n\n**👐自分の投稿:**投稿したものはすべてNextcloudに残ります\n\n**オープンスタンダード:**確立されたActivityPub形式を使用しています",
".well-known/webfinger isn't properly set up!" : ".well-known / webfingerが正しく設定されていません",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Socialが適切に設定されるためには、well-knownの自動検出が必要です。 Nextcloudがドメインのルートにインストールされていない場合、Nextcloudがこれを自動的に設定できないことがよくあります。 Socialを使用するには、このNextcloudインスタンスの管理者は手動で.well-knownリダイレクトを設定する必要があります。",
".well-known/webfinger isn't properly set up!" : ".well-known/webfingerが正しく設定されていません",
"Social needs the .well-known automatic discovery to be properly set up. If Nextcloud is not installed in the root of the domain, it is often the case that Nextcloud can't configure this automatically. To use Social, the admin of this Nextcloud instance needs to manually configure the .well-known redirects: " : "Socialが適切に設定されるためには、.well-knownの自動検出が必要です。 Nextcloudがドメインのルートにインストールされていない場合、Nextcloudがこれを自動的に設定できないことがよくあります。 Socialを使用するには、このNextcloudインスタンスの管理者は手動で.well-knownリダイレクトを設定する必要があります。",
"Open documentation" : "ドキュメントを開く",
"Social app setup" : "Socialアプリのセットアップ",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPubでは、エントリを一意にするために固定のURLが必要です。 \nこれは、Socialアプリをリセットせずに後で変更することはできません。",
"ActivityPub requires a fixed URL to make entries unique. Note that this can not be changed later without resetting the Social app." : "ActivityPubでは、エントリを一意にするために固定のURLが必要です。 これは、Socialアプリをリセットせずに後で変更することはできません。",
"ActivityPub URL base" : "ActivityPub URLベース",
"Finish setup" : "セットアップを終了",
"The Social app needs to be set up by the server administrator." : "Socialアプリはサーバー管理者が設定する必要があります。",

Wyświetl plik

@ -35,13 +35,20 @@ use Exception;
use OC\Core\Command\Base;
use OCA\Social\Service\CheckService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\PushService;
use OCP\IUserManager;
use OCP\Push\Exceptions\PushInstallException;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class CheckInstall extends Base {
/** @var IUserManager */
private $userManager;
/** @var CheckService */
private $checkService;
@ -52,16 +59,25 @@ class CheckInstall extends Base {
/**
* CacheUpdate constructor.
*
* @param IUserManager $userManager
* @param CheckService $checkService
* @param MiscService $miscService
* @param PushService $pushService
*/
public function __construct(CheckService $checkService, MiscService $miscService) {
public function __construct(
IUserManager $userManager, CheckService $checkService, MiscService $miscService,
PushService $pushService
) {
parent::__construct();
$this->userManager = $userManager;
$this->checkService = $checkService;
$this->miscService = $miscService;
$this->pushService = $pushService;
}
/** @var PushService */
private $pushService;
/**
*
@ -69,6 +85,10 @@ class CheckInstall extends Base {
protected function configure() {
parent::configure();
$this->setName('social:check:install')
->addOption(
'push', '', InputOption::VALUE_REQUIRED, 'a local account used to test integration to Nextcloud Push',
''
)
->setDescription('Check the integrity of the installation');
}
@ -81,8 +101,30 @@ class CheckInstall extends Base {
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$this->checkService->checkInstallationStatus();
$this->checkPushApp($input, $output);
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws Exception
*/
private function checkPushApp(InputInterface $input, OutputInterface $output) {
$userId = $input->getOption('push');
if ($userId !== '') {
$user = $this->userManager->get($userId);
if ($user === null) {
throw new Exception('unknown user');
}
$wrapper = $this->pushService->testOnAccount($userId);
$output->writeln(json_encode($wrapper, JSON_PRETTY_PRINT));
}
}
}

Wyświetl plik

@ -0,0 +1,134 @@
<?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\Command;
use daita\MySmallPhpTools\Exceptions\CacheItemNotFoundException;
use OC\Core\Command\Base;
use OCA\Social\AP;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Exceptions\RedundancyLimitException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Stream;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Output\OutputInterface;
class ExtendedBase extends Base {
/** @var OutputInterface */
protected $output;
/** @var bool */
protected $asJson = false;
/**
* @param Person $actor
*/
protected function outputActor(Person $actor) {
if ($this->asJson) {
$this->output->writeln(json_encode($actor, JSON_PRETTY_PRINT));
}
$this->output->writeln('<info>Account</info>: ' . $actor->getAccount());
$this->output->writeln('<info>Id</info>: ' . $actor->getId());
$this->output->writeln('');
}
/**
* @param Stream[] $streams
*/
protected function outputStreams(array $streams) {
if ($this->asJson) {
$this->output->writeln(json_encode($streams, JSON_PRETTY_PRINT));
}
$table = new Table($this->output);
$table->setHeaders(['Id', 'Source', 'Type', 'Author', 'Content']);
$table->render();
$this->output->writeln('');
foreach ($streams as $item) {
$objectId = $item->getObjectId();
$cache = $item->getCache();
$content = '';
$author = '';
if ($objectId !== '' && $cache->hasItem($objectId)) {
try {
$cachedObject = $cache->getItem($objectId)
->getObject();
/** @var Stream $cachedItem */
$cachedItem = AP::$activityPub->getItemFromData($cachedObject);
$content = $cachedItem->getContent();
$author = $cachedItem->getActor()
->getAccount();
} catch (CacheItemNotFoundException $e) {
} catch (ItemUnknownException $e) {
} catch (RedundancyLimitException $e) {
} catch (SocialAppConfigException $e) {
}
} else {
$content = $item->getContent();
$author = $item->getActor()
->getAccount();
}
$table->appendRow(
[
'<comment>' . $item->getId() . '</comment>',
'<info>' . $item->getActor()
->getAccount() . '</info>',
$item->getType(),
'<info>' . $author . '</info>',
$content,
]
);
}
}
/**
* @param Stream $stream
*/
protected function outputStream(Stream $stream) {
$actor = $stream->getActor();
$this->output->writeln('id: <comment>' . $stream->getId() . '</comment>');
$this->output->writeln(
'author: <comment>' . $actor->getAccount() . '</comment>'
);
$this->output->writeln('type: <info>' . $stream->getType() . '</info>');
}
}

Wyświetl plik

@ -36,7 +36,7 @@ use OC\Core\Command\Base;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\BoostService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\NoteService;
use OCA\Social\Service\StreamService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -50,8 +50,8 @@ use Symfony\Component\Console\Output\OutputInterface;
*/
class NoteBoost extends Base {
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var AccountService */
private $accountService;
@ -67,17 +67,17 @@ class NoteBoost extends Base {
* NoteBoost constructor.
*
* @param AccountService $accountService
* @param NoteService $noteService
* @param StreamService $streamService
* @param BoostService $boostService
* @param MiscService $miscService
*/
public function __construct(
AccountService $accountService, NoteService $noteService, BoostService $boostService,
AccountService $accountService, StreamService $streamService, BoostService $boostService,
MiscService $miscService
) {
parent::__construct();
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->boostService = $boostService;
$this->accountService = $accountService;
$this->miscService = $miscService;
@ -108,7 +108,7 @@ class NoteBoost extends Base {
$noteId = $input->getArgument('note_id');
$actor = $this->accountService->getActorFromUserId($userId);
$this->noteService->setViewer($actor);
$this->streamService->setViewer($actor);
if (!$input->getOption('unboost')) {
$activity = $this->boostService->create($actor, $noteId, $token);

Wyświetl plik

@ -132,7 +132,7 @@ class NoteCreate extends Base {
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$userId = $input->getArgument('user_id');
$userId = $input->getArgument('userid');
$content = $input->getArgument('content');
$to = $input->getOption('to');
$hashtag = $input->getOption('hashtag');

Wyświetl plik

@ -36,7 +36,7 @@ use OC\Core\Command\Base;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\LikeService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\NoteService;
use OCA\Social\Service\StreamService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -51,8 +51,8 @@ use Symfony\Component\Console\Output\OutputInterface;
class NoteLike extends Base {
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var AccountService */
private $accountService;
@ -68,17 +68,17 @@ class NoteLike extends Base {
* NoteBoost constructor.
*
* @param AccountService $accountService
* @param NoteService $noteService
* @param StreamService $streamService
* @param LikeService $likeService
* @param MiscService $miscService
*/
public function __construct(
AccountService $accountService, NoteService $noteService, LikeService $likeService,
AccountService $accountService, StreamService $streamService, LikeService $likeService,
MiscService $miscService
) {
parent::__construct();
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->likeService = $likeService;
$this->accountService = $accountService;
$this->miscService = $miscService;
@ -109,7 +109,7 @@ class NoteLike extends Base {
$noteId = $input->getArgument('note_id');
$actor = $this->accountService->getActorFromUserId($userId);
$this->noteService->setViewer($actor);
$this->streamService->setViewer($actor);
if (!$input->getOption('unlike')) {
$activity = $this->likeService->create($actor, $noteId, $token);

Wyświetl plik

@ -0,0 +1,145 @@
<?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\Command;
use Exception;
use OCA\Social\Exceptions\StreamNotFoundException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Service\DetailsService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\StreamService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class StreamDetails
*
* @package OCA\Social\Command
*/
class StreamDetails extends ExtendedBase {
/** @var StreamService */
private $streamService;
/** @var DetailsService */
private $detailsService;
/** @var MiscService */
private $miscService;
/**
* StreamDetails constructor.
*
* @param StreamService $streamService
* @param DetailsService $detailsService
* @param MiscService $miscService
*/
public function __construct(
StreamService $streamService, DetailsService $detailsService, MiscService $miscService
) {
parent::__construct();
$this->streamService = $streamService;
$this->detailsService = $detailsService;
$this->miscService = $miscService;
}
/**
*
*/
protected function configure() {
parent::configure();
$this->setName('social:details')
->addArgument('streamId', InputArgument::REQUIRED, 'Id of the Stream item')
->addOption('json', '', InputOption::VALUE_NONE, 'return JSON format')
->setDescription('Get details about a Stream item');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @throws Exception
*/
protected function execute(InputInterface $input, OutputInterface $output) {
$output = new ConsoleOutput();
$this->output = $output->section();
$this->asJson = $input->getOption('json');
$streamId = $input->getArgument('streamId');
try {
$stream = $this->streamService->getStreamById($streamId);
} catch (StreamNotFoundException $e) {
throw new Exception('Unknown item');
}
$details = $this->detailsService->generateDetailsFromStream($stream);
if ($this->asJson) {
$this->output->writeln(json_encode($details, JSON_PRETTY_PRINT));
return;
}
$this->outputStream($stream);
$this->output->writeln('');
$this->output->writeln('<comment>Affected Timelines</comment>:');
$home = array_map(
function(Person $item): string {
return $item->getUserId();
}, $details->getHomeViewers()
);
$this->output->writeln('* <info>Home</info>: ' . json_encode($home, JSON_PRETTY_PRINT));
$direct = array_map(
function(Person $item): string {
return $item->getUserId();
}, $details->getDirectViewers()
);
$this->output->writeln('* <info>Direct</info>: ' . json_encode($direct, JSON_PRETTY_PRINT));
$this->output->writeln('* <info>Public</info>: ' . ($details->isPublic() ? 'true' : 'false'));
$this->output->writeln('* <info>Federated</info>: ' . ($details->isFederated() ? 'true' : 'true'));
}
}

Wyświetl plik

@ -31,22 +31,13 @@ declare(strict_types=1);
namespace OCA\Social\Command;
use daita\MySmallPhpTools\Exceptions\CacheItemNotFoundException;
use Exception;
use OC\Core\Command\Base;
use OCA\Social\AP;
use OCA\Social\Db\StreamRequest;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Exceptions\RedundancyLimitException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\CacheActorService;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\MiscService;
use OCP\IUserManager;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
@ -59,7 +50,7 @@ use Symfony\Component\Console\Output\OutputInterface;
*
* @package OCA\Social\Command
*/
class Timeline extends Base {
class Timeline extends ExtendedBase {
/** @var IUserManager */
private $userManager;
@ -77,18 +68,12 @@ class Timeline extends Base {
private $miscService;
/** @var OutputInterface */
private $output;
/** @var bool */
private $asJson;
/** @var int */
private $count;
/**
* Stream constructor.
* Timeline constructor.
*
* @param IUserManager $userManager
* @param StreamRequest $streamRequest
@ -147,25 +132,13 @@ class Timeline extends Base {
$actor = $this->accountService->getActor($userId);
$this->outputActor($actor);
if (!$this->asJson) {
$this->outputActor($actor);
}
$this->displayStream($actor, $timeline);
}
/**
* @param Person $actor
*/
private function outputActor(Person $actor) {
if ($this->asJson) {
return;
}
$this->output->writeln('<info>Account</info>: ' . $actor->getAccount());
$this->output->writeln('<info>Id</info>: ' . $actor->getId());
$this->output->writeln('');
}
/**
* @param Person $actor
@ -177,27 +150,27 @@ class Timeline extends Base {
switch ($timeline) {
case 'home':
$stream = $this->streamRequest->getTimelineHome($actor, 0, $this->count);
$this->outputStream($stream);
$this->outputStreams($stream);
break;
case 'direct':
$stream = $this->streamRequest->getTimelineDirect($actor, 0, $this->count);
$this->outputStream($stream);
$this->outputStreams($stream);
break;
case 'notifications':
$stream = $this->streamRequest->getTimelineNotifications($actor, 0, $this->count);
$this->outputStream($stream);
$this->outputStreams($stream);
break;
case 'local':
$stream = $this->streamRequest->getTimelineGlobal(0, $this->count, true);
$this->outputStream($stream);
$this->outputStreams($stream);
break;
case 'global':
$stream = $this->streamRequest->getTimelineGlobal(0, $this->count, false);
$this->outputStream($stream);
$this->outputStreams($stream);
break;
default:
@ -207,61 +180,5 @@ class Timeline extends Base {
}
}
/**
* @param Stream[] $stream
*/
private function outputStream(array $stream) {
if ($this->asJson) {
$this->output->writeln(json_encode($stream, JSON_PRETTY_PRINT));
}
$table = new Table($this->output);
$table->setHeaders(['Id', 'Source', 'Type', 'Author', 'Content']);
$table->render();
$this->output->writeln('');
foreach ($stream as $item) {
$objectId = $item->getObjectId();
$cache = $item->getCache();
$content = '';
$author = '';
if ($objectId !== '' && $cache->hasItem($objectId)) {
try {
$cachedObject = $cache->getItem($objectId)
->getObject();
/** @var Stream $cachedItem */
$cachedItem = AP::$activityPub->getItemFromData($cachedObject);
$content = $cachedItem->getContent();
$author = $cachedItem->getActor()
->getAccount();
} catch (CacheItemNotFoundException $e) {
} catch (ItemUnknownException $e) {
} catch (RedundancyLimitException $e) {
} catch (SocialAppConfigException $e) {
}
} else {
$content = $item->getContent();
$author = $item->getActor()
->getAccount();
}
$table->appendRow(
[
'<comment>' . $item->getId() . '</comment>',
'<info>' . $item->getActor()
->getAccount() . '</info>',
$item->getType(),
'<info>' . $author . '</info>',
$content,
]
);
}
}
}

Wyświetl plik

@ -48,7 +48,7 @@ use OCA\Social\Service\FollowService;
use OCA\Social\Service\HashtagService;
use OCA\Social\Service\LikeService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\NoteService;
use OCA\Social\Service\StreamService;
use OCA\Social\Service\PostService;
use OCA\Social\Service\SearchService;
use OCP\AppFramework\Controller;
@ -92,8 +92,8 @@ class LocalController extends Controller {
/** @var PostService */
private $postService;
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var SearchService */
private $searchService;
@ -122,7 +122,7 @@ class LocalController extends Controller {
* @param HashtagService $hashtagService
* @param FollowService $followService
* @param PostService $postService
* @param NoteService $noteService
* @param StreamService $streamService
* @param SearchService $searchService
* @param BoostService $boostService
* @param LikeService $likeService
@ -133,7 +133,7 @@ class LocalController extends Controller {
IRequest $request, $userId, AccountService $accountService,
CacheActorService $cacheActorService, HashtagService $hashtagService,
FollowService $followService,
PostService $postService, NoteService $noteService, SearchService $searchService,
PostService $postService, StreamService $streamService, SearchService $searchService,
BoostService $boostService, LikeService $likeService, DocumentService $documentService,
MiscService $miscService
) {
@ -143,7 +143,7 @@ class LocalController extends Controller {
$this->cacheActorService = $cacheActorService;
$this->hashtagService = $hashtagService;
$this->accountService = $accountService;
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->searchService = $searchService;
$this->postService = $postService;
$this->followService = $followService;
@ -202,7 +202,7 @@ class LocalController extends Controller {
try {
$this->initViewer(true);
return $this->directSuccess($this->noteService->getNoteById($id, true));
return $this->directSuccess($this->streamService->getStreamById($id, true));
} catch (Exception $e) {
return $this->fail($e);
}
@ -220,13 +220,13 @@ class LocalController extends Controller {
*/
public function postDelete(string $id): DataResponse {
try {
$note = $this->noteService->getNoteById($id);
$note = $this->streamService->getStreamById($id);
$actor = $this->accountService->getActorFromUserId($this->userId);
if ($note->getAttributedTo() !== $actor->getId()) {
throw new InvalidResourceException('user have no rights');
}
$this->noteService->deleteLocalItem($note, Note::TYPE);
$this->streamService->deleteLocalItem($note, Note::TYPE);
return $this->success();
} catch (Exception $e) {
@ -351,7 +351,7 @@ class LocalController extends Controller {
public function streamHome($since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamHome($this->viewer, $since, $limit);
$posts = $this->streamService->getStreamHome($this->viewer, $since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -372,7 +372,7 @@ class LocalController extends Controller {
public function streamNotifications($since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamNotifications($this->viewer, $since, $limit);
$posts = $this->streamService->getStreamNotifications($this->viewer, $since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -396,7 +396,7 @@ class LocalController extends Controller {
$this->initViewer();
$account = $this->cacheActorService->getFromLocalAccount($username);
$posts = $this->noteService->getStreamAccount($account->getId(), $since, $limit);
$posts = $this->streamService->getStreamAccount($account->getId(), $since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -417,7 +417,7 @@ class LocalController extends Controller {
public function streamDirect(int $since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamDirect($this->viewer, $since, $limit);
$posts = $this->streamService->getStreamDirect($this->viewer, $since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -440,7 +440,7 @@ class LocalController extends Controller {
public function streamTimeline(int $since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamLocalTimeline($since, $limit);
$posts = $this->streamService->getStreamLocalTimeline($since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -463,7 +463,7 @@ class LocalController extends Controller {
public function streamTag(string $hashtag, int $since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamLocalTag($this->viewer, $hashtag, $since, $limit);
$posts = $this->streamService->getStreamLocalTag($this->viewer, $hashtag, $since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -485,7 +485,7 @@ class LocalController extends Controller {
public function streamFederated(int $since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamGlobalTimeline($since, $limit);
$posts = $this->streamService->getStreamGlobalTimeline($since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -507,7 +507,7 @@ class LocalController extends Controller {
public function streamLiked(int $since = 0, int $limit = 5): DataResponse {
try {
$this->initViewer(true);
$posts = $this->noteService->getStreamLiked($since, $limit);
$posts = $this->streamService->getStreamLiked($since, $limit);
return $this->success($posts);
} catch (Exception $e) {
@ -886,7 +886,7 @@ class LocalController extends Controller {
try {
$this->viewer = $this->accountService->getActorFromUserId($this->userId, true);
$this->noteService->setViewer($this->viewer);
$this->streamService->setViewer($this->viewer);
$this->followService->setViewer($this->viewer);
$this->cacheActorService->setViewer($this->viewer);
} catch (Exception $e) {

Wyświetl plik

@ -767,7 +767,40 @@ class CoreRequestBuilder {
$qb->leftJoin(
$this->defaultSelectAlias, CoreRequestBuilder::TABLE_CACHE_ACTORS, 'ca', $orX
);
}
/**
* @param IQueryBuilder $qb
* @param string $fieldActorId
* @param string $alias
*/
protected function leftJoinAccounts(IQueryBuilder &$qb, string $fieldActorId, string $alias = ''
) {
if ($qb->getType() !== QueryBuilder::SELECT) {
return;
}
$expr = $qb->expr();
$func = $qb->func();
$pf = ($alias === '') ? $this->defaultSelectAlias : $alias;
$qb->selectAlias('lja.id', 'accounts_id')
->selectAlias('lja.user_id', 'accounts_user_id')
->selectAlias('lja.preferred_username', 'accounts_preferred_username')
->selectAlias('lja.name', 'accounts_name')
->selectAlias('lja.summary', 'accounts_summary')
->selectAlias('lja.public_key', 'accounts_public_key');
$on = $expr->eq(
$func->lower($pf . '.' . $fieldActorId),
$func->lower('lja.id')
);
$qb->leftJoin(
$this->defaultSelectAlias, CoreRequestBuilder::TABLE_ACTORS, 'lja', $on
);
}
@ -797,6 +830,31 @@ class CoreRequestBuilder {
}
/**
* @param array $data
*
* @return Person
* @throws InvalidResourceException
*/
protected function parseAccountsLeftJoin(array $data): Person {
$new = [];
foreach ($data as $k => $v) {
if (substr($k, 0, 9) === 'accounts_') {
$new[substr($k, 9)] = $v;
}
}
$actor = new Person();
$actor->importFromDatabase($new);
if (!$actor->getUserId()) {
throw new InvalidResourceException();
}
return $actor;
}
/**
* @param IQueryBuilder $qb
*/

Wyświetl plik

@ -235,6 +235,28 @@ class FollowsRequest extends FollowsRequestBuilder {
}
/**
* @param string $followId
*
* @return Follow[]
*/
public function getFollowersByFollowId(string $followId): array {
$qb = $this->getFollowsSelectSql();
$this->limitToFollowId($qb, $followId);
$this->limitToAccepted($qb, true);
$this->leftJoinAccounts($qb, 'actor_id');
$follows = [];
$cursor = $qb->execute();
while ($data = $cursor->fetch()) {
$follows[] = $this->parseFollowsSelectSql($data);
}
$cursor->closeCursor();
return $follows;
}
/**
* @param Follow $follow
*/

Wyświetl plik

@ -139,6 +139,14 @@ class FollowsRequestBuilder extends CoreRequestBuilder {
$follow->setCompleteDetails(true);
$follow->setActor($actor);
return $follow;
} catch (InvalidResourceException $e) {
}
try {
$actor = $this->parseAccountsLeftJoin($data);
$follow->setActor($actor);
} catch (InvalidResourceException $e) {
}

Wyświetl plik

@ -461,7 +461,6 @@ class StreamRequestBuilder extends CoreRequestBuilder {
}
$item->setAction($action);
if ($item->getType() === Announce::TYPE) {
$item->setAttributedTo($this->get('following_actor_id', $data, ''));
}

Wyświetl plik

@ -60,7 +60,7 @@ class AcceptInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -60,7 +60,7 @@ class AddInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -60,7 +60,7 @@ class BlockInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -60,7 +60,7 @@ class CreateInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -64,7 +64,7 @@ class DeleteInterface implements IActivityPubInterface {
public function processIncomingRequest(ACore $item) {
$item->checkOrigin($item->getId());
if (!$item->gotObject()) {
if (!$item->hasObject()) {
if ($item->getObjectId() !== '') {
$item->checkOrigin($item->getObjectId());

Wyświetl plik

@ -60,7 +60,7 @@ class RejectInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -60,7 +60,7 @@ class RemoveInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -60,7 +60,7 @@ class UndoInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}

Wyświetl plik

@ -60,7 +60,7 @@ class UpdateInterface implements IActivityPubInterface {
* @param ACore $item
*/
public function processIncomingRequest(ACore $item) {
if (!$item->gotObject()) {
if (!$item->hasObject()) {
return;
}
$object = $item->getObject();

Wyświetl plik

@ -42,6 +42,7 @@ use OCA\Social\Model\ActivityPub\Object\Note;
use OCA\Social\Service\ConfigService;
use OCA\Social\Service\CurlService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\PushService;
class NoteInterface implements IActivityPubInterface {
@ -53,6 +54,9 @@ class NoteInterface implements IActivityPubInterface {
/** @var CurlService */
private $curlService;
/** @var PushService */
private $pushService;
/** @var ConfigService */
private $configService;
@ -65,15 +69,17 @@ class NoteInterface implements IActivityPubInterface {
*
* @param StreamRequest $streamRequest
* @param CurlService $curlService
* @param PushService $pushService
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
StreamRequest $streamRequest, CurlService $curlService, ConfigService $configService,
MiscService $miscService
StreamRequest $streamRequest, CurlService $curlService, PushService $pushService,
ConfigService $configService, MiscService $miscService
) {
$this->streamRequest = $streamRequest;
$this->curlService = $curlService;
$this->pushService = $pushService;
$this->configService = $configService;
$this->miscService = $miscService;
}
@ -147,6 +153,7 @@ class NoteInterface implements IActivityPubInterface {
$this->streamRequest->getStreamById($note->getId());
} catch (StreamNotFoundException $e) {
$this->streamRequest->save($note);
$this->pushService->onNewStream($note->getId());
}
}

Wyświetl plik

@ -144,7 +144,7 @@ class ACore extends Item implements JsonSerializable {
/**
* @return bool
*/
public function gotObject(): bool {
public function hasObject(): bool {
if ($this->object === null) {
return false;
}
@ -172,6 +172,22 @@ class ACore extends Item implements JsonSerializable {
}
/**
* @param bool $filter - will remove general url like Public
*
* @return array
*/
public function getRecipients(bool $filter = false): array {
$recipients = array_merge($this->getToAll(), $this->getCcArray());
if (!$filter) {
return $recipients;
}
return array_diff($recipients, [self::CONTEXT_PUBLIC]);
}
/**
* @return bool
*/
@ -226,9 +242,7 @@ class ACore extends Item implements JsonSerializable {
* @return bool
*/
public function isPublic(): bool {
return ($this->getTo() === self::CONTEXT_PUBLIC
|| in_array(self::CONTEXT_PUBLIC, $this->getCcArray())
|| in_array(self::CONTEXT_PUBLIC, $this->getToArray()));
return in_array(self::CONTEXT_PUBLIC, $this->getRecipients());
}
@ -296,7 +310,9 @@ class ACore extends Item implements JsonSerializable {
return;
}
throw new InvalidOriginException('ACore::checkOrigin - id: ' . $id . ' - origin: ' . $origin);
throw new InvalidOriginException(
'ACore::checkOrigin - id: ' . $id . ' - origin: ' . $origin
);
}
@ -661,7 +677,7 @@ class ACore extends Item implements JsonSerializable {
$this->addEntry('published', $this->getPublished());
$this->addEntryArray('tag', $this->getTags());
if ($this->gotObject()) {
if ($this->hasObject()) {
$this->addEntryItem('object', $this->getObject());
} else {
$this->addEntry('object', $this->getObjectId());

Wyświetl plik

@ -421,6 +421,7 @@ class Person extends ACore implements JsonSerializable {
$this->setPreferredUsername(
$this->validate(self::AS_USERNAME, 'preferred_username', $data, '')
)
->setUserId($this->get('user_id', $data, ''))
->setName($this->validate(self::AS_USERNAME, 'name', $data, ''))
->setAccount($this->validate(self::AS_ACCOUNT, 'account', $data, ''))
->setPublicKey($this->get('public_key', $data, ''))

Wyświetl plik

@ -31,6 +31,7 @@ namespace OCA\Social\Model\ActivityPub;
use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\InstancePath;
@ -395,6 +396,16 @@ class Item {
return $this->toArray;
}
/**
* @return array
*/
public function getToAll(): array {
$arr = $this->toArray;
$arr[] = $this->to;
return $arr;
}
/**
* @param string $to
*

Wyświetl plik

@ -82,6 +82,9 @@ class Stream extends ACore implements JsonSerializable {
/** @var StreamAction */
private $action = null;
/** @var string */
private $timeline = '';
/** @var bool */
private $hiddenOnTimeline = false;
@ -304,6 +307,25 @@ class Stream extends ACore implements JsonSerializable {
}
/**
* @return string
*/
public function getTimeline(): string {
return $this->timeline;
}
/**
* @param string $timeline
*
* @return Stream
*/
public function setTimeline(string $timeline): self {
$this->timeline = $timeline;
return $this;
}
/**
* @return bool
*/

Wyświetl plik

@ -39,7 +39,7 @@ use OCA\Social\Service\SignatureService;
/**
* Class InstancePath
* Class LinkedDataSignature
*
* @package OCA\Social\Model
*/

Wyświetl plik

@ -0,0 +1,208 @@
<?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\Model;
use daita\MySmallPhpTools\Traits\TArrayTools;
use JsonSerializable;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Stream;
/**
* Class StreamDetails
*
* @package OCA\Social\Model
*/
class StreamDetails implements JsonSerializable {
use TArrayTools;
/** @var Stream */
private $stream;
/** @var Person[] */
private $homeViewers = [];
/** @var Person[] */
private $directViewers = [];
/** @var bool */
private $public = false;
/** @var bool */
private $federated = false;
/**
* StreamDetails constructor.
*
* @param Stream|null $stream
*/
public function __construct(Stream $stream = null) {
$this->stream = $stream;
}
/**
* @return Stream
*/
public function getStream(): Stream {
return $this->stream;
}
/**
* @param Stream $stream
*
* @return StreamDetails
*/
public function setStream(Stream $stream): self {
$this->stream = $stream;
return $this;
}
/**
* @return Person[]
*/
public function getHomeViewers(): array {
return $this->homeViewers;
}
/**
* @param Person[] $viewers
*
* @return StreamDetails
*/
public function setHomeViewers(array $viewers): self {
$this->homeViewers = $viewers;
return $this;
}
/**
* @param Person $viewer
*
* @return StreamDetails
*/
public function addHomeViewer(Person $viewer): self {
$this->homeViewers[] = $viewer;
return $this;
}
/**
* @return Person[]
*/
public function getDirectViewers(): array {
return $this->directViewers;
}
/**
* @param Person[] $viewers
*
* @return StreamDetails
*/
public function setDirectViewers(array $viewers): self {
$this->directViewers = $viewers;
return $this;
}
/**
* @param Person $viewer
*
* @return StreamDetails
*/
public function addDirectViewer(Person $viewer): self {
$this->directViewers[] = $viewer;
return $this;
}
/**
* @return bool
*/
public function isPublic(): bool {
return $this->public;
}
/**
* @param bool $public
*
* @return StreamDetails
*/
public function setPublic(bool $public): self {
$this->public = $public;
return $this;
}
/**
* @return bool
*/
public function isFederated(): bool {
return $this->federated;
}
/**
* @param bool $federated
*
* @return StreamDetails
*/
public function setFederated(bool $federated): self {
$this->federated = $federated;
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'stream' => $this->getStream(),
'homeViewers' => $this->getHomeViewers(),
'directViewers' => $this->getDirectViewers(),
'public' => $this->isPublic(),
'federated' => $this->isFederated()
];
}
}

Wyświetl plik

@ -430,7 +430,7 @@ class ActivityService {
private function saveActivity(ACore $activity) {
// TODO: save activity in DB ?
if ($activity->gotObject()) {
if ($activity->hasObject()) {
$this->saveObject($activity->getObject());
}
}
@ -441,7 +441,7 @@ class ActivityService {
*/
private function saveObject(ACore $activity) {
try {
if ($activity->gotObject()) {
if ($activity->hasObject()) {
$this->saveObject($activity->getObject());
}

Wyświetl plik

@ -60,8 +60,8 @@ class BoostService {
/** @var StreamRequest */
private $streamRequest;
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var SignatureService */
private $signatureService;
@ -83,7 +83,7 @@ class BoostService {
* BoostService constructor.
*
* @param StreamRequest $streamRequest
* @param NoteService $noteService
* @param StreamService $streamService
* @param SignatureService $signatureService
* @param ActivityService $activityService
* @param StreamActionService $streamActionService
@ -91,12 +91,12 @@ class BoostService {
* @param MiscService $miscService
*/
public function __construct(
StreamRequest $streamRequest, NoteService $noteService, SignatureService $signatureService,
StreamRequest $streamRequest, StreamService $streamService, SignatureService $signatureService,
ActivityService $activityService, StreamActionService $streamActionService,
StreamQueueService $streamQueueService, MiscService $miscService
) {
$this->streamRequest = $streamRequest;
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->signatureService = $signatureService;
$this->activityService = $activityService;
$this->streamActionService = $streamActionService;
@ -118,10 +118,10 @@ class BoostService {
public function create(Person $actor, string $postId, &$token = ''): ACore {
/** @var Announce $announce */
$announce = AP::$activityPub->getItemFromType(Announce::TYPE);
$this->noteService->assignItem($announce, $actor, Stream::TYPE_ANNOUNCE);
$this->streamService->assignItem($announce, $actor, Stream::TYPE_ANNOUNCE);
$announce->setActor($actor);
$note = $this->noteService->getNoteById($postId, true);
$note = $this->streamService->getStreamById($postId, true);
if ($note->getType() !== Note::TYPE) {
throw new StreamNotFoundException('Stream is not a Note');
}
@ -180,10 +180,10 @@ class BoostService {
*/
public function delete(Person $actor, string $postId, &$token = ''): ACore {
$undo = new Undo();
$this->noteService->assignItem($undo, $actor, Stream::TYPE_PUBLIC);
$this->streamService->assignItem($undo, $actor, Stream::TYPE_PUBLIC);
$undo->setActor($actor);
$note = $this->noteService->getNoteById($postId, true);
$note = $this->streamService->getStreamById($postId, true);
if ($note->getType() !== Note::TYPE) {
throw new StreamNotFoundException('Stream is not a Note');
}

Wyświetl plik

@ -51,6 +51,7 @@ class ConfigService {
use TPathTools;
use TArrayTools;
const CLOUD_URL = 'cloud_url';
const SOCIAL_URL = 'social_url';
const SOCIAL_ADDRESS = 'social_address';

Wyświetl plik

@ -0,0 +1,131 @@
<?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 OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Model\StreamDetails;
/**
* Class DetailsService
*
* @package OCA\Social\Service
*/
class DetailsService {
/** @var StreamService */
private $streamService;
/** @var AccountService */
private $accountService;
/** @var FollowService */
private $followService;
/** @var CacheActorService */
private $cacheActorService;
/**
* DetailsService constructor.
*
* @param StreamService $streamService
* @param AccountService $accountService
* @param FollowService $followService
* @param CacheActorService $cacheActorService
*/
public function __construct(
StreamService $streamService, AccountService $accountService,
FollowService $followService, CacheActorService $cacheActorService
) {
$this->streamService = $streamService;
$this->accountService = $accountService;
$this->followService = $followService;
$this->cacheActorService = $cacheActorService;
}
/**
* @param Stream $stream
*
* @return StreamDetails
* @throws SocialAppConfigException
*/
public function generateDetailsFromStream(Stream $stream): StreamDetails {
$this->streamService->detectType($stream);
$details = new StreamDetails($stream);
$this->setStreamViewers($details);
if ($stream->getTimeline() === Stream::TYPE_PUBLIC) {
if ($stream->isLocal()) {
$details->setPublic(true);
} else {
$details->setFederated(true);
}
}
return $details;
}
/**
* @param StreamDetails $details
*
* @throws SocialAppConfigException
*/
private function setStreamViewers(StreamDetails $details) {
$stream = $details->getStream();
foreach ($stream->getRecipients(true) as $recipient) {
try {
$actor = $this->accountService->getFromId($recipient);
$details->addDirectViewer($actor);
} catch (ActorDoesNotExistException $e) {
}
$followers = $this->followService->getFollowersFromFollowId($recipient);
foreach ($followers as $follower) {
if (!$follower->hasActor()) {
continue;
}
$actor = $follower->getActor();
$details->addHomeViewer($actor);
}
}
}
}

Wyświetl plik

@ -39,21 +39,20 @@ use OCA\Social\Exceptions\FollowDoesNotExistException;
use OCA\Social\Exceptions\FollowSameAccountException;
use OCA\Social\Exceptions\InvalidOriginException;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Exceptions\RedundancyLimitException;
use OCA\Social\Exceptions\RequestContentException;
use OCA\Social\Exceptions\RequestResultNotJsonException;
use OCA\Social\Exceptions\RetrieveAccountFormatException;
use OCA\Social\Exceptions\RequestNetworkException;
use OCA\Social\Exceptions\RequestResultNotJsonException;
use OCA\Social\Exceptions\RequestResultSizeException;
use OCA\Social\Exceptions\RequestServerException;
use OCA\Social\Exceptions\RetrieveAccountFormatException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Exceptions\UnauthorizedFediverseException;
use OCA\Social\Exceptions\UrlCloudException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Object\Follow;
use OCA\Social\Model\ActivityPub\Activity\Undo;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Object\Follow;
use OCA\Social\Model\ActivityPub\OrderedCollection;
use OCA\Social\Model\InstancePath;
@ -285,5 +284,15 @@ class FollowService {
return $collection;
}
/**
* @param string $recipient
*
* @return Follow[]
*/
public function getFollowersFromFollowId(string $recipient): array {
return $this->followsRequest->getFollowersByFollowId($recipient);
}
}

Wyświetl plik

@ -63,8 +63,8 @@ class LikeService {
/** @var StreamRequest */
private $streamRequest;
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var SignatureService */
private $signatureService;
@ -86,7 +86,7 @@ class LikeService {
* LikeService constructor.
*
* @param StreamRequest $streamRequest
* @param NoteService $noteService
* @param StreamService $streamService
* @param SignatureService $signatureService
* @param ActivityService $activityService
* @param StreamActionService $streamActionService
@ -94,12 +94,12 @@ class LikeService {
* @param MiscService $miscService
*/
public function __construct(
StreamRequest $streamRequest, NoteService $noteService, SignatureService $signatureService,
StreamRequest $streamRequest, StreamService $streamService, SignatureService $signatureService,
ActivityService $activityService, StreamActionService $streamActionService,
StreamQueueService $streamQueueService, MiscService $miscService
) {
$this->streamRequest = $streamRequest;
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->signatureService = $signatureService;
$this->activityService = $activityService;
$this->streamActionService = $streamActionService;
@ -124,7 +124,7 @@ class LikeService {
$like->setId($actor->getId() . '#like/' . $this->uuid(8));
$like->setActor($actor);
$note = $this->noteService->getNoteById($postId, true);
$note = $this->streamService->getStreamById($postId, true);
if ($note->getType() !== Note::TYPE) {
throw new StreamNotFoundException('Stream is not a Note');
}
@ -174,7 +174,7 @@ class LikeService {
$undo = new Undo();
$undo->setActor($actor);
$note = $this->noteService->getNoteById($postId, true);
$note = $this->streamService->getStreamById($postId, true);
if ($note->getType() !== Note::TYPE) {
throw new StreamNotFoundException('Stream is not a Note');
}

Wyświetl plik

@ -36,6 +36,7 @@ use OCA\Social\AppInfo\Application;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
use OCP\Util;
/**
@ -79,6 +80,16 @@ class MiscService {
}
/**
* @return int
*/
public function getNcVersion(): int {
$ver = Util::getVersion();
return $ver[0];
}
/**
* @param string $userId
*

Wyświetl plik

@ -49,8 +49,8 @@ use OCA\Social\Model\Post;
class PostService {
/** @var NoteService */
private $noteService;
/** @var StreamService */
private $streamService;
/** @var AccountService */
private $accountService;
@ -68,17 +68,17 @@ class PostService {
/**
* PostService constructor.
*
* @param NoteService $noteService
* @param StreamService $streamService
* @param AccountService $accountService
* @param ActivityService $activityService
* @param ConfigService $configService
* @param MiscService $miscService
*/
public function __construct(
NoteService $noteService, AccountService $accountService, ActivityService $activityService,
StreamService $streamService, AccountService $accountService, ActivityService $activityService,
ConfigService $configService, MiscService $miscService
) {
$this->noteService = $noteService;
$this->streamService = $streamService;
$this->accountService = $accountService;
$this->activityService = $activityService;
$this->configService = $configService;
@ -107,16 +107,16 @@ class PostService {
public function createPost(Post $post, &$token = ''): ACore {
$note = new Note();
$actor = $post->getActor();
$this->noteService->assignItem($note, $actor, $post->getType());
$this->streamService->assignItem($note, $actor, $post->getType());
$note->setAttributedTo($actor->getId());
// $this->configService->getSocialUrl() . '@' . $actor->getPreferredUsername()
$note->setContent(htmlentities($post->getContent(), ENT_QUOTES));
$this->noteService->replyTo($note, $post->getReplyTo());
$this->noteService->addRecipients($note, $post->getType(), $post->getTo());
$this->noteService->addHashtags($note, $post->getHashtags());
$this->streamService->replyTo($note, $post->getReplyTo());
$this->streamService->addRecipients($note, $post->getType(), $post->getTo());
$this->streamService->addHashtags($note, $post->getHashtags());
$token = $this->activityService->createActivity($actor, $note, $activity);
$this->accountService->cacheLocalActorDetailCount($actor);

Wyświetl plik

@ -0,0 +1,156 @@
<?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\Traits\TAsync;
use OC;
use OC\Push\Model\Helper\PushCallback;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Exceptions\StreamNotFoundException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCP\AppFramework\QueryException;
use OCP\Push\Exceptions\PushInstallException;
use OCP\Push\IPushManager;
use OCP\Push\Model\IPushWrapper;
/**
* Class PushService
*
* @package OCA\Social\Service
*/
class PushService {
use TAsync;
/** @var IPushManager */
private $pushManager;
/** @var DetailsService */
private $detailsService;
/** @var StreamService */
private $streamService;
/** @var MiscService */
private $miscService;
/**
* PushService constructor.
*
* @param DetailsService $detailsService
* @param StreamService $streamService
* @param MiscService $miscService
*/
public function __construct(
DetailsService $detailsService, StreamService $streamService, MiscService $miscService
) {
$this->detailsService = $detailsService;
$this->streamService = $streamService;
$this->miscService = $miscService;
// FIX ME: nc18/push
if ($this->miscService->getNcVersion() >= 18) {
try {
$this->pushManager = OC::$server->query(IPushManager::class);
} catch (QueryException $e) {
$miscService->log('QueryException while loading IPushManager - ' . $e->getMessage());
}
}
}
/**
* @param string $streamId
*
* @throws SocialAppConfigException
* @throws PushInstallException
*/
public function onNewStream(string $streamId) {
// FIXME: remove in nc18
if ($this->miscService->getNcVersion() < 18) {
return;
}
if (!$this->pushManager->isAvailable()) {
return;
}
try {
$stream = $this->streamService->getStreamById($streamId);
} catch (StreamNotFoundException $e) {
return;
}
$pushHelper = $this->pushManager->getPushHelper();
$details = $this->detailsService->generateDetailsFromStream($stream);
$home = array_map(
function(Person $item): string {
return $item->getUserId();
}, $details->getHomeViewers()
);
$callback = new PushCallback('social', 'timeline.home');
$callback->setPayloadSerializable($stream);
$callback->addUsers($home);
$pushHelper->toCallback($callback);
$direct = array_map(
function(Person $item): string {
return $item->getUserId();
}, $details->getDirectViewers()
);
$callback = new PushCallback('social', 'timeline.direct');
$callback->addUsers($direct);
$callback->setPayloadSerializable($stream);
$pushHelper->toCallback($callback);
}
/**
* @param $userId
*
* @return IPushWrapper
* @throws PushInstallException
*/
public function testOnAccount(string $userId): IPushWrapper {
$pushHelper = $this->pushManager->getPushHelper();
return $pushHelper->test($userId);
}
}

Wyświetl plik

@ -257,12 +257,11 @@ class SignatureService {
}
try {
$origin = $this->checkRequestSignature($request, $data);
return $this->checkRequestSignature($request, $data);
} catch (RequestContentException $e) {
throw new SignatureIsGoneException();
} catch (SignatureException $e) {
}
return $origin;
}
@ -360,9 +359,9 @@ class SignatureService {
* @throws RequestResultNotJsonException
* @throws RequestResultSizeException
* @throws RequestServerException
* @throws SignatureException
* @throws SocialAppConfigException
* @throws UnauthorizedFediverseException
* @throws SignatureException
*/
private function checkRequestSignature(IRequest $request, string $data): string {
$signatureHeader = $request->getHeader('Signature');
@ -381,7 +380,29 @@ class SignatureService {
// TODO: check digest
// $this->generateDigest($data);
$publicKey = $this->retrieveKey($keyId);
try {
$publicKey = $this->retrieveKey($keyId);
$this->checkRequestSignatureUsingPublicKey($publicKey, $sign, $estimated, $signed);
} catch (SignatureException $e) {
$publicKey = $this->retrieveKey($keyId, true);
$this->checkRequestSignatureUsingPublicKey($publicKey, $sign, $estimated, $signed);
}
return $origin;
}
/**
* @param string $publicKey
* @param array $sign
* @param string $estimated
* @param bool $signed
*
* @throws SignatureException
*/
private function checkRequestSignatureUsingPublicKey(
string $publicKey, array $sign, string $estimated, bool $signed
) {
$algorithm = $this->getAlgorithmFromSignature($sign);
if ($publicKey === ''
|| openssl_verify($estimated, $signed, $publicKey, $algorithm) !== 1) {
@ -390,8 +411,6 @@ class SignatureService {
. ' - algo: ' . $algorithm . ' - estimated: ' . $estimated
);
}
return $origin;
}

Wyświetl plik

@ -51,7 +51,8 @@ use OCA\Social\Model\ActivityPub\Object\Note;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Model\InstancePath;
class NoteService {
class StreamService {
/** @var StreamRequest */
@ -207,6 +208,32 @@ class NoteService {
}
/**
* @param $stream
*/
public function detectType(Stream $stream) {
if (in_array(ACore::CONTEXT_PUBLIC, $stream->getToAll())) {
$stream->setTimeline(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
@ -295,16 +322,17 @@ class NoteService {
*
* @throws InvalidOriginException
* @throws InvalidResourceException
* @throws ItemUnknownException
* @throws MalformedArrayException
* @throws StreamNotFoundException
* @throws RedundancyLimitException
* @throws RequestContentException
* @throws RequestNetworkException
* @throws RequestResultNotJsonException
* @throws RequestResultSizeException
* @throws RequestServerException
* @throws SocialAppConfigException
* @throws ItemUnknownException
* @throws RequestResultNotJsonException
* @throws StreamNotFoundException
* @throws UnauthorizedFediverseException
*/
public function replyTo(Note $note, string $replyTo) {
if ($replyTo === '') {
@ -346,7 +374,7 @@ class NoteService {
* @return Stream
* @throws StreamNotFoundException
*/
public function getNoteById(string $id, bool $asViewer = false): Stream {
public function getStreamById(string $id, bool $asViewer = false): Stream {
return $this->streamRequest->getStreamById($id, $asViewer);
}

3000
package-lock.json wygenerowano

Plik diff jest za duży Load Diff

Wyświetl plik

@ -31,7 +31,7 @@
"linkifyjs": "^2.1.8",
"nextcloud-axios": "^0.2.0",
"nextcloud-vue": "^0.11.4",
"tributejs": "^3.7.1",
"tributejs": "^3.7.2",
"twemoji": "^12.0.1",
"uuid": "^3.3.2",
"v-tooltip": "^3.0.0-alpha.11",
@ -40,7 +40,7 @@
"vue-contenteditable-directive": "^1.2.0",
"vue-emoji-picker": "^1.0.1",
"vue-infinite-loading": "^2.4.4",
"vue-router": "^3.0.7",
"vue-router": "^3.1.2",
"vue-tribute": "^1.0.3",
"vue-twemoji": "^1.0.1",
"vuex": "^3.1.1",
@ -59,11 +59,11 @@
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/preset-env": "^7.5.5",
"@vue/test-utils": "^1.0.0-beta.29",
"acorn": "^6.2.1",
"acorn": "^6.3.0",
"babel-eslint": "^10.0.2",
"babel-jest": "^24.8.0",
"babel-jest": "^24.9.0",
"babel-loader": "^8.0.6",
"css-loader": "^3.1.0",
"css-loader": "^3.2.0",
"eslint": "^5.16.0",
"eslint-config-standard": "^12.0.0",
"eslint-friendly-formatter": "^4.0.1",
@ -73,8 +73,8 @@
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.0",
"eslint-plugin-vue": "^5.2.3",
"file-loader": "^4.1.0",
"jest": "^24.8.0",
"file-loader": "^4.2.0",
"jest": "^24.9.0",
"jest-serializer-vue": "^2.0.2",
"node-sass": "^4.12.0",
"prettier-eslint": "^9.0.0",
@ -87,7 +87,7 @@
"vue-loader": "^15.7.1",
"vue-style-loader": "^4.1.1",
"vue-template-compiler": "^2.6.10",
"webpack": "^4.39.1",
"webpack": "^4.39.2",
"webpack-cli": "^3.3.6",
"webpack-merge": "^4.2.1"
},

Wyświetl plik

@ -210,6 +210,9 @@ export default {
this.$store.dispatch('fetchCurrentAccountInfo', this.cloudId)
}
if (OCA.Push && OCA.Push.isEnabled()) {
OCA.Push.addCallback(this.fromPushApp, 'social')
}
},
methods: {
hideInfo() {
@ -226,6 +229,22 @@ export default {
},
resetSearch() {
this.searchTerm = ''
},
fromPushApp: function(data) {
// FIXME: might be better to use Timeline.type() ?
let timeline = 'home'
if (this.$route.name === 'tags') {
timeline = 'tags'
} else if (this.$route.params.type) {
timeline = this.$route.params.type
}
if (data.source === 'timeline.home' && timeline === 'home') {
this.$store.dispatch('addToTimeline', [data.payload])
}
if (data.source === 'timeline.direct' && timeline === 'direct') {
this.$store.dispatch('addToTimeline', [data.payload])
}
}
}
}

Wyświetl plik

@ -323,11 +323,6 @@
vertical-align: middle;
margin-top: -1px;
}
img.emoji {
margin: 3px;
width: 16px;
vertical-align: text-bottom;
}
.hashtag {
text-decoration: underline;
}

Wyświetl plik

@ -7,20 +7,25 @@
:disable-tooltip="true" />
</div>
<div class="post-content">
<div class="post-author-wrapper">
<router-link v-if="item.actor_info" :to="{ name: 'profile', params: { account: item.local ? item.actor_info.preferredUsername : item.actor_info.account }}">
<span class="post-author">
{{ userDisplayName(item.actor_info) }}
</span>
<span class="post-author-id">
@{{ item.actor_info.account }}
</span>
</router-link>
<a v-else :href="item.attributedTo">
<span class="post-author-id">
{{ item.attributedTo }}
</span>
</a>
<div class="post-header">
<div class="post-author-wrapper">
<router-link v-if="item.actor_info" :to="{ name: 'profile', params: { account: item.local ? item.actor_info.preferredUsername : item.actor_info.account }}">
<span class="post-author">
{{ userDisplayName(item.actor_info) }}
</span>
<span class="post-author-id">
@{{ item.actor_info.account }}
</span>
</router-link>
<a v-else :href="item.attributedTo">
<span class="post-author-id">
{{ item.attributedTo }}
</span>
</a>
</div>
<div :data-timestamp="timestamp" class="post-timestamp live-relative-timestamp">
{{ relativeTimestamp }}
</div>
</div>
<!-- eslint-disable-next-line vue/no-v-html -->
<div class="post-message" v-html="formatedMessage" />
@ -41,11 +46,6 @@
</div>
</div>
</div>
<div>
<div :data-timestamp="timestamp" class="post-timestamp live-relative-timestamp">
{{ relativeTimestamp }}
</div>
</div>
</div>
</template>
@ -246,6 +246,12 @@ export default {
flex-grow: 1;
}
.post-header {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.post-timestamp {
opacity: .7;
}

Wyświetl plik

@ -199,6 +199,9 @@ const actions = {
context.commit('addToTimeline', response.data.result)
return response.data
})
},
addToTimeline(context, data) {
context.commit('addToTimeline', data)
}
}