Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/1626/head
Maxence Lange 2023-03-07 09:09:41 -01:00
rodzic d251806d55
commit 1c12b522e5
14 zmienionych plików z 275 dodań i 23 usunięć

Wyświetl plik

@ -18,7 +18,7 @@
**🕸 Open standards:** We use the established ActivityPub standard!
]]></description>
<version>0.6.0-beta2</version>
<version>0.6.0-beta3</version>
<licence>agpl</licence>
<author mail="maxence@artificial-owl.com" homepage="https://artificial-owl.com/">Maxence Lange</author>
<author mail="jus@bitgrid.net">Julius Härtl</author>

Wyświetl plik

@ -90,6 +90,8 @@ return [
['name' => 'Api#statusNew', 'url' => '/api/v1/statuses', 'verb' => 'POST'],
['name' => 'Api#statusGet', 'url' => '/api/v1/statuses/{nid}', 'verb' => 'GET'],
['name' => 'Api#statusContext', 'url' => '/api/v1/statuses/{nid}/context', 'verb' => 'GET'],
['name' => 'Api#statusAction', 'url' => '/api/v1/statuses/{nid}/{act}', 'verb' => 'POST'],
['name' => 'Api#accountStatuses', 'url' => '/api/v1/accounts/{account}/statuses', 'verb' => 'GET'],
// Api for local front-end

Wyświetl plik

@ -35,7 +35,6 @@ use Exception;
use OC\Core\Command\Base;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\BoostService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\StreamService;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
@ -51,18 +50,17 @@ class NoteBoost extends Base {
private StreamService $streamService;
private AccountService $accountService;
private BoostService $boostService;
private MiscService $miscService;
public function __construct(
AccountService $accountService, StreamService $streamService, BoostService $boostService,
MiscService $miscService
AccountService $accountService,
StreamService $streamService,
BoostService $boostService
) {
parent::__construct();
$this->streamService = $streamService;
$this->boostService = $boostService;
$this->accountService = $accountService;
$this->miscService = $miscService;
}

Wyświetl plik

@ -46,6 +46,7 @@ use OCA\Social\Model\Client\SocialClient;
use OCA\Social\Model\Client\Status;
use OCA\Social\Model\Post;
use OCA\Social\Service\AccountService;
use OCA\Social\Service\ActionService;
use OCA\Social\Service\CacheActorService;
use OCA\Social\Service\CacheDocumentService;
use OCA\Social\Service\ClientService;
@ -85,6 +86,7 @@ class ApiController extends Controller {
private DocumentService $documentService;
private FollowService $followService;
private StreamService $streamService;
private ActionService $actionService;
private PostService $postService;
private ConfigService $configService;
@ -105,6 +107,7 @@ class ApiController extends Controller {
DocumentService $documentService,
FollowService $followService,
StreamService $streamService,
ActionService $actionService,
PostService $postService,
ConfigService $configService
) {
@ -121,6 +124,7 @@ class ApiController extends Controller {
$this->documentService = $documentService;
$this->followService = $followService;
$this->streamService = $streamService;
$this->actionService = $actionService;
$this->postService = $postService;
$this->configService = $configService;
@ -256,9 +260,14 @@ class ApiController extends Controller {
}
$activity = $this->postService->createPost($post);
$activity->setExportFormat(ACore::FORMAT_LOCAL);
return new DataResponse($activity, Http::STATUS_OK);
$item = $this->streamService->getStreamById(
$activity->getObjectId(),
true,
ACore::FORMAT_LOCAL
);
return new DataResponse($item, Http::STATUS_OK);
} catch (Exception $e) {
$this->logger->warning('issues while statusNew', ['exception' => $e]);
@ -461,6 +470,31 @@ class ApiController extends Controller {
}
}
/**
* @NoCSRFRequired
* @PublicPage
*
* @param int $nid
* @param string $action
*
* @return DataResponse
*/
public function statusAction(int $nid, string $act): DataResponse {
try {
$this->initViewer(true);
$item = $this->actionService->action($this->viewer->getId(), $nid, $act);
if ($item === null) {
$item = $this->streamService->getStreamByNid($nid);
}
return new DataResponse($item, Http::STATUS_OK);
} catch (Exception $e) {
return $this->error($e->getMessage());
}
}
/**
* @NoCSRFRequired
* @PublicPage
@ -469,6 +503,7 @@ class ApiController extends Controller {
* @param int $limit
* @param int $max_id
* @param int $min_id
* @param int $since
*
* @return DataResponse
*/

Wyświetl plik

@ -202,6 +202,7 @@ class CoreRequestBuilder {
'nid',
'id',
'id_prim',
'visibility',
'type',
'subtype',
'to',

Wyświetl plik

@ -891,6 +891,7 @@ class StreamRequest extends StreamRequestBuilder {
$qb = $this->getStreamInsertSql();
$qb->setValue('nid', $qb->createNamedParameter($stream->getNid()))
->setValue('id', $qb->createNamedParameter($stream->getId()))
->setValue('visibility', $qb->createNamedParameter($stream->getVisibility()))
->setValue('type', $qb->createNamedParameter($stream->getType()))
->setValue('subtype', $qb->createNamedParameter($stream->getSubType()))
->setValue('to', $qb->createNamedParameter($stream->getTo()))

Wyświetl plik

@ -31,9 +31,6 @@ declare(strict_types=1);
namespace OCA\Social\Db;
use OCA\Social\Tools\Exceptions\CacheItemNotFoundException;
use OCA\Social\Tools\Exceptions\RowNotFoundException;
use OCA\Social\Tools\Traits\TArrayTools;
use OCA\Social\AP;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Exceptions\ItemUnknownException;
@ -42,6 +39,9 @@ use OCA\Social\Exceptions\StreamNotFoundException;
use OCA\Social\Model\ActivityPub\Object\Announce;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Model\InstancePath;
use OCA\Social\Tools\Exceptions\CacheItemNotFoundException;
use OCA\Social\Tools\Exceptions\RowNotFoundException;
use OCA\Social\Tools\Traits\TArrayTools;
/**
* Class StreamRequestBuilder
@ -92,9 +92,9 @@ class StreamRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->selectDistinct('s.id')
->addSelect(
's.nid', 's.type', 's.subtype', 's.to', 's.to_array', 's.cc', 's.bcc', 's.content',
's.summary', 's.attachments', 's.published', 's.published_time', 's.cache',
's.object_id', 's.attributed_to', 's.in_reply_to', 's.source', 's.local',
's.nid', 's.type', 's.subtype', 's.visibility', 's.to', 's.to_array', 's.cc',
's.bcc', 's.content', 's.summary', 's.attachments', 's.published', 's.published_time',
's.cache', 's.object_id', 's.attributed_to', 's.in_reply_to', 's.source', 's.local',
's.instances', 's.creation', 's.filter_duplicate', 's.details', 's.hashtags'
)
->from(self::TABLE_STREAM, 's');

Wyświetl plik

@ -0,0 +1,35 @@
<?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 2023, 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\Exceptions;
use Exception;
class InvalidActionException extends Exception {
}

Wyświetl plik

@ -537,6 +537,14 @@ class Version1000Date20221118000001 extends SimpleMigrationStep {
'default' => ''
]
);
$table->addColumn(
'visibility', Types::STRING,
[
'notnull' => false,
'length' => 31,
'default' => ''
]
);
$table->addColumn(
'to', Types::TEXT,
[

Wyświetl plik

@ -40,6 +40,21 @@ class Version1000Date20230217000002 extends SimpleMigrationStep {
/** @var ISchemaWrapper $schema */
$schema = $schemaClosure();
if ($schema->hasTable('social_stream')) {
$table = $schema->getTable('social_stream');
if (!$table->hasColumn('visibility')) {
$table->addColumn(
'visibility', Types::STRING,
[
'notnull' => false,
'length' => 31,
'default' => ''
]
);
}
}
if ($schema->hasTable('social_cache_doc')) {
$table = $schema->getTable('social_cache_doc');

Wyświetl plik

@ -33,15 +33,10 @@ namespace OCA\Social\Model\ActivityPub;
use DateTime;
use Exception;
use JsonSerializable;
use OCA\Social\AP;
use OCA\Social\Exceptions\InvalidResourceEntryException;
use OCA\Social\Exceptions\ItemAlreadyExistsException;
use OCA\Social\Exceptions\ItemUnknownException;
use OCA\Social\Model\ActivityPub\Actor\Person;
use OCA\Social\Model\ActivityPub\Object\Announce;
use OCA\Social\Model\ActivityPub\Object\Document;
use OCA\Social\Model\ActivityPub\Object\Follow;
use OCA\Social\Model\ActivityPub\Object\Image;
use OCA\Social\Model\ActivityPub\Object\Like;
use OCA\Social\Model\Client\MediaAttachment;
use OCA\Social\Model\StreamAction;
@ -70,6 +65,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
private string $activityId = '';
private string $content = '';
private string $visibility = '';
private string $spoilerText = '';
private string $language = 'en';
private string $attributedTo = '';
@ -130,6 +126,24 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
return $this;
}
/**
* @param string $visibility
*
* @return Stream
*/
public function setVisibility(string $visibility): self {
$this->visibility = $visibility;
return $this;
}
/**
* @return string
*/
public function getVisibility(): string {
return $this->visibility;
}
/**
* @return string
@ -470,6 +484,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
$this->setDetailsAll($this->getArray('details', $data, []));
$this->setFilterDuplicate($this->getBool('filter_duplicate', $data, false));
$this->setAttachments($this->getArray('attachments', $data, []));
$this->setVisibility($this->get('visibility', $data));
$cache = new Cache();
$cache->import($this->getArray('cache', $data, []));
@ -545,7 +560,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
"content" => $this->getContent(),
"sensitive" => $this->isSensitive(),
"spoiler_text" => $this->getSpoilerText(),
"visibility" => 'unlisted',
"visibility" => $this->getVisibility(),
"language" => $this->getLanguage(),
"in_reply_to_id" => null,
"in_reply_to_account_id" => null,
@ -560,7 +575,8 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
'url' => $this->getId(),
"reblog" => null,
'media_attachments' => $this->getAttachments(),
"created_at" => date('Y-m-d\TH:i:s', $this->getPublishedTime()) . '.000Z'
"created_at" => date('Y-m-d\TH:i:s', $this->getPublishedTime()) . '.000Z',
'noindex' => false
];
// TODO - store created_at full string with milliseconds ?
@ -592,7 +608,7 @@ class Stream extends ACore implements IQueryRow, JsonSerializable {
'id' => $this->getId(),
'type' => $type,
'created_at' => $this->getOriginCreationTime(),
'status' => $this->getDetails('post')
'status' => $this->getDetails('post'),
];
if ($this->hasActor()) {

Wyświetl plik

@ -0,0 +1,140 @@
<?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 2023, 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\InvalidActionException;
use OCA\Social\Exceptions\StreamNotFoundException;
use OCA\Social\Model\ActivityPub\Stream;
use OCA\Social\Model\StreamAction;
use OCA\Social\Tools\Traits\TStringTools;
class ActionService {
use TStringTools;
private StreamService $streamService;
private StreamActionService $streamActionService;
private const TRANSLATE = 'translate';
private const FAVOURITE = 'favourite';
private const UNFAVOURITE = 'unfavourite';
private const REBLOG = 'reblog';
private const UNREBLOG = 'unreblog';
private const BOOKMARK = 'bookmark';
private const UNBOOKMARK = 'unbookmark';
private const MUTE = 'mute';
private const UNMUTE = 'unmute';
private const PIN = 'pin';
private const UNPIN = 'unpin';
private static array $availableStatusAction = [
self::TRANSLATE,
self::FAVOURITE,
self::UNFAVOURITE,
self::REBLOG,
self::UNREBLOG,
self::BOOKMARK,
self::UNBOOKMARK,
self::MUTE,
self::UNMUTE,
self::PIN,
self::UNPIN
];
public function __construct(
StreamService $streamService,
StreamActionService $streamActionService
) {
$this->streamService = $streamService;
$this->streamActionService = $streamActionService;
}
/**
* should return null
* will return Stream only with translate action
*
* @param int $nid
* @param string $action
*
* @return Stream|null
* @throws InvalidActionException
*/
public function action(string $actorId, int $nid, string $action): ?Stream {
if (!in_array($action, self::$availableStatusAction)) {
throw new InvalidActionException();
}
$post = $this->streamService->getStreamByNid($nid);
switch ($action) {
case self::TRANSLATE:
return $this->translate($nid);
case self::FAVOURITE:
$this->favourite($actorId, $post->getId());
break;
case self::UNFAVOURITE:
$this->favourite($actorId, $post->getId(), false);
break;
case self::REBLOG:
$this->reblog($actorId, $post->getId());
break;
case self::UNREBLOG:
$this->reblog($actorId, $post->getId(), false);
break;
}
return null;
}
/**
* TODO: returns a translated version of the Status
*
* @param int $nid
*
* @return Stream
* @throws StreamNotFoundException
*/
private function translate(int $nid): Stream {
return $this->streamService->getStreamByNid($nid);
}
private function favourite(string $actorId, string $postId, bool $enabled = true): void {
$this->streamActionService->setActionBool($actorId, $postId, StreamAction::LIKED, $enabled);
}
private function reblog(string $actorId, string $postId, bool $enabled = true): void {
$this->streamActionService->setActionBool($actorId, $postId, StreamAction::BOOSTED, $enabled);
}
}

Wyświetl plik

@ -107,6 +107,7 @@ class PostService {
$note->setAttributedTo($actor->getId());
$note->setContent(htmlentities($post->getContent(), ENT_QUOTES));
$note->setAttachments($post->getMedias());
$note->setVisibility($post->getType());
// $this->generateDocumentsFromAttachments($note, $post);

Wyświetl plik

@ -90,7 +90,7 @@ class StreamActionService {
* @param string $key
* @param bool $value
*/
public function setActionBool(string $actorId, string $streamId, string $key, bool $value) {
public function setActionBool(string $actorId, string $streamId, string $key, bool $value): void {
$action = $this->loadAction($actorId, $streamId);
$action->updateValueBool($key, $value);
$this->saveAction($action);