InstancePath and Delete

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
pull/48/head
Maxence Lange 2018-11-21 18:22:46 -01:00
rodzic b48d962164
commit 16d42a9e53
10 zmienionych plików z 204 dodań i 41 usunięć

Wyświetl plik

@ -43,6 +43,7 @@ use OCA\Social\Service\ActorService;
use OCA\Social\Service\MiscService;
use OCA\Social\Service\PostService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\IRequest;
@ -162,7 +163,7 @@ class LocalController extends Controller {
throw new InvalidResourceException('user have no rights');
}
$this->noteService->delete($note);
$this->noteService->deleteLocalNote($note);
return $this->success();
} catch (Exception $e) {
@ -183,9 +184,6 @@ class LocalController extends Controller {
* @return DataResponse
*/
public function timeline($since = 0, $limit = 5): DataResponse {
// $this->miscService->log('timeline: ' . json_encode($data));
try {
$posts = $this->noteService->getTimeline((int)$since, (int)$limit);

Wyświetl plik

@ -94,6 +94,11 @@ class NotesRequest extends NotesRequestBuilder {
->setValue('attributed_to', $qb->createNamedParameter($note->getAttributedTo()))
->setValue('in_reply_to', $qb->createNamedParameter($note->getInReplyTo()))
->setValue('source', $qb->createNamedParameter($note->getSource()))
->setValue(
'instances', $qb->createNamedParameter(
json_encode($note->getInstancePaths(), JSON_UNESCAPED_SLASHES)
)
)
->setValue('local', $qb->createNamedParameter(($note->isLocal()) ? '1' : '0'))
->setValue(
'creation',

Wyświetl plik

@ -34,6 +34,7 @@ use daita\MySmallPhpTools\Traits\TArrayTools;
use DateTime;
use OCA\Social\Exceptions\InvalidResourceException;
use OCA\Social\Model\ActivityPub\Note;
use OCA\Social\Model\InstancePath;
use OCP\DB\QueryBuilder\IQueryBuilder;
class NotesRequestBuilder extends CoreRequestBuilder {
@ -80,7 +81,7 @@ class NotesRequestBuilder extends CoreRequestBuilder {
$qb->select(
'sn.id', 'sn.to', 'sn.to_array', 'sn.cc', 'sn.bcc', 'sn.content', 'sn.summary',
'sn.published', 'sn.published_time', 'sn.attributed_to', 'sn.in_reply_to', 'sn.source',
'sn.creation'
'sn.local', 'sn.instances', 'sn.creation'
)
->from(self::TABLE_SERVER_NOTES, 'sn');
@ -117,12 +118,18 @@ class NotesRequestBuilder extends CoreRequestBuilder {
->setToArray(json_decode($data['to_array'], true))
->setCcArray(json_decode($data['cc'], true))
->setBccArray(json_decode($data['bcc']))
->setLocal(($data['local'] === '1') ? true : false)
->setPublished($data['published']);
$note->setContent($data['content'])
->setPublishedTime($dTime->getTimestamp())
->setAttributedTo($data['attributed_to'])
->setInReplyTo($data['in_reply_to']);
$instances = json_decode($data['instances'], true);
foreach ($instances as $instance) {
$note->addInstancePath(new InstancePath($instance['uri'], $instance['type']));
}
try {
$actor = $this->parseCacheActorsLeftJoin($data);
$note->setCompleteDetails(true);

Wyświetl plik

@ -234,7 +234,9 @@ abstract class ACore implements JsonSerializable {
* @return ACore
*/
public function addInstancePath(InstancePath $instancePath): ACore {
$this->instancePaths[] = $instancePath;
if ($instancePath->getUri() !== '') {
$this->instancePaths[] = $instancePath;
}
return $this;
}

Wyświetl plik

@ -44,13 +44,28 @@ class InstancePath implements JsonSerializable {
use TArrayTools;
const TYPE_PUBLIC = 0;
const TYPE_INBOX = 1;
const TYPE_GLOBAL = 2;
const TYPE_FOLLOWERS = 3;
/** @var string */
private $uri = '';
/** @var int */
private $type = 0;
public function __construct(string $uri) {
/**
* InstancePath constructor.
*
* @param string $uri
* @param int $type
*/
public function __construct(string $uri = '', int $type = 0) {
$this->uri = $uri;
$this->type = $type;
}
@ -62,6 +77,24 @@ class InstancePath implements JsonSerializable {
}
/**
* @return int
*/
public function getType(): int {
return $this->type;
}
/**
* @return string
*/
public function getAddress(): string {
$info = parse_url($this->uri);
return $this->get('host', $info, '');
}
/**
* @return string
*/
@ -71,12 +104,20 @@ class InstancePath implements JsonSerializable {
return $this->get('path', $info, '');
}
public function import(array $data) {
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'uri' => $this->getUri()
'uri' => $this->getUri(),
'type' => $this->getType()
];
}

Wyświetl plik

@ -61,6 +61,9 @@ class NoteService implements ICoreService {
/** @var NotesRequest */
private $notesRequest;
/** @var ActivityService */
private $activityService;
/** @var ActorService */
private $actorService;
@ -81,6 +84,7 @@ class NoteService implements ICoreService {
* NoteService constructor.
*
* @param NotesRequest $notesRequest
* @param ActivityService $activityService
* @param ActorService $actorService
* @param PersonService $personService
* @param CurlService $curlService
@ -88,10 +92,13 @@ class NoteService implements ICoreService {
* @param MiscService $miscService
*/
public function __construct(
NotesRequest $notesRequest, ActorService $actorService, PersonService $personService,
CurlService $curlService, ConfigService $configService, MiscService $miscService
NotesRequest $notesRequest, ActivityService $activityService, ActorService $actorService,
PersonService $personService,
CurlService $curlService, ConfigService $configService,
MiscService $miscService
) {
$this->notesRequest = $notesRequest;
$this->activityService = $activityService;
$this->actorService = $actorService;
$this->personService = $personService;
$this->curlService = $curlService;
@ -141,11 +148,17 @@ class NoteService implements ICoreService {
switch ($type) {
case self::TYPE_UNLISTED:
$note->setTo($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
);
$note->addCc(ActivityService::TO_PUBLIC);
break;
case self::TYPE_FOLLOWERS:
$note->setTo($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
);
break;
case self::TYPE_DIRECT:
@ -154,9 +167,10 @@ class NoteService implements ICoreService {
default:
$note->setTo(ActivityService::TO_PUBLIC);
$note->addCc($actor->getFollowers());
$note->addInstancePath(
new InstancePath($actor->getFollowers(), InstancePath::TYPE_FOLLOWERS)
);
break;
}
}
@ -188,7 +202,7 @@ class NoteService implements ICoreService {
]
);
$note->addInstancePath(new InstancePath($actor->getInbox()));
$note->addInstancePath(new InstancePath($actor->getInbox(), InstancePath::TYPE_INBOX));
}
@ -253,6 +267,35 @@ class NoteService implements ICoreService {
}
/**
* @param Note $note
*/
public function deleteLocalNote(Note $note) {
if (!$note->isLocal()) {
return;
}
// $this->notesRequest->deleteNoteById($note->getId());
// $this->miscService->log('___' . json_encode($note->getInstancePaths()));
$this->activityService->deleteActivity($note);
// $this->deleteService->deleteItem($note);
}
// /**
// * @param Note $note
// */
// private function assignInstances(Note $note) {
// $note->addInstancePath(new InstancePath($note->getTo()));
// $all = array_merge($note->getToArray(), $note->getCcArray(), $note->getBccArray());
// foreach ($all as $uri) {
// $note->addInstancePath(new InstancePath($uri));
// }
// $note->addInstancePath(new InstancePath($note->getInReplyTo()));
// }
/**
* @param ACore $item
*/

Wyświetl plik

@ -36,6 +36,7 @@ use daita\MySmallPhpTools\Traits\TArrayTools;
use DateTime;
use Exception;
use OCA\Social\Db\ActorsRequest;
use OCA\Social\Db\FollowsRequest;
use OCA\Social\Db\NotesRequest;
use OCA\Social\Exceptions\ActorDoesNotExistException;
use OCA\Social\Exceptions\InvalidResourceException;
@ -44,6 +45,8 @@ use OCA\Social\Exceptions\SignatureException;
use OCA\Social\Exceptions\SocialAppConfigException;
use OCA\Social\Model\ActivityPub\ACore;
use OCA\Social\Model\ActivityPub\Activity\Create;
use OCA\Social\Model\ActivityPub\Activity\Delete;
use OCA\Social\Model\ActivityPub\Activity\Tombstone;
use OCA\Social\Model\ActivityPub\Person;
use OCA\Social\Model\InstancePath;
use OCA\Social\Service\ActivityPub\PersonService;
@ -71,6 +74,9 @@ class ActivityService {
/** @var NotesRequest */
private $notesRequest;
/** @var FollowsRequest */
private $followsRequest;
/** @var ActorService */
private $actorService;
@ -95,6 +101,7 @@ class ActivityService {
*
* @param ActorsRequest $actorsRequest
* @param NotesRequest $notesRequest
* @param FollowsRequest $followsRequest
* @param CurlService $curlService
* @param ActorService $actorService
* @param PersonService $personService
@ -103,8 +110,8 @@ class ActivityService {
* @param MiscService $miscService
*/
public function __construct(
ActorsRequest $actorsRequest, NotesRequest $notesRequest, CurlService $curlService,
ActorService $actorService,
ActorsRequest $actorsRequest, NotesRequest $notesRequest, FollowsRequest $followsRequest,
CurlService $curlService, ActorService $actorService,
PersonService $personService, InstanceService $instanceService,
ConfigService $configService,
MiscService $miscService
@ -112,6 +119,7 @@ class ActivityService {
$this->curlService = $curlService;
$this->actorsRequest = $actorsRequest;
$this->notesRequest = $notesRequest;
$this->followsRequest = $followsRequest;
$this->actorService = $actorService;
$this->personService = $personService;
$this->instanceService = $instanceService;
@ -131,7 +139,7 @@ class ActivityService {
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
*/
public function createActivity(Person $actor, ACore $item, int $type, ACore &$activity = null
public function createActivity(Person $actor, ACore $item, ACore &$activity = null
): array {
$activity = new Create();
@ -151,12 +159,34 @@ class ActivityService {
$activity->setActor($actor);
$result = $this->request($activity, $type);
$result = $this->request($activity);
return $result;
}
/**
* @param ACore $item
*
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
*/
public function deleteActivity(ACore $item) {
$delete = new Delete();
$delete->setId($item->getId() . '#delete');
$delete->setActorId($item->getActorId());
$tombstone = new Tombstone($delete);
$tombstone->setId($item->getId());
$delete->setObject($tombstone);
$delete->addInstancePaths($item->getInstancePaths());
$this->request($delete);
}
/**
* @param string $id
*
@ -174,7 +204,7 @@ class ActivityService {
foreach ($requests as $request) {
try {
$toDelete = $request->getFromId($id);
$toDelete = $request->getNoteById($id);
return $toDelete;
} catch (Exception $e) {
@ -187,14 +217,13 @@ class ActivityService {
/**
* @param ACore $activity
* @param int $type
*
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
*/
public function manageRequest(ACore $activity, int $type) {
$result = $this->request($activity, $type);
public function manageRequest(ACore $activity) {
$result = $this->request($activity);
$this->miscService->log('Activity: ' . json_encode($activity));
$this->miscService->log('Result: ' . json_encode($result));
}
@ -203,48 +232,86 @@ class ActivityService {
/**
* @param ACore $activity
*
* @param int $type
*
* @return array
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
*/
public function request(ACore &$activity, int $type) {
public function request(ACore &$activity) {
$this->setupCore($activity);
$hosts = $this->instanceService->getInstancesFromActivity($activity);
// $hosts = $this->instanceService->getInstancesFromActivity($activity);
$result = [];
foreach ($hosts as $host) {
foreach ($host->getInstancePaths() as $path) {
$result[] = $this->generateRequest($host->getAddress(), $path, $type, $activity);
// foreach ($hosts as $host) {
// foreach ($host->getInstancePaths() as $path) {
foreach ($activity->getInstancePaths() as $instancePath) {
if ($instancePath->getType() === InstancePath::TYPE_FOLLOWERS) {
$result = array_merge($result, $this->requestToFollowers($activity, $instancePath));
} else {
$result[] = $this->generateRequest($instancePath, $activity);
}
}
// }
return $result;
}
/**
* @param ACore $activity
* @param InstancePath $instancePath
*
* @return array
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
*/
private function requestToFollowers(ACore &$activity, InstancePath $instancePath): array {
$result = [];
$sharedInboxes = [];
$follows = $this->followsRequest->getByFollowId($instancePath->getUri());
foreach ($follows as $follow) {
if (!$follow->gotActor()) {
// TODO - check if cache can be empty at this point ?
continue;
}
$sharedInbox = $follow->getActor()
->getSharedInbox();
if (in_array($sharedInbox, $sharedInboxes)) {
continue;
}
$sharedInboxes[] = $sharedInbox;
$result[] = $this->generateRequest(
new InstancePath($sharedInbox, InstancePath::TYPE_GLOBAL), $activity
);
}
return $result;
}
/**
* @param string $address
* @param InstancePath $path
* @param int $type
* @param ACore $activity
*
* @return Request[]
* @throws ActorDoesNotExistException
* @throws RequestException
* @throws SocialAppConfigException
* @throws ActorDoesNotExistException
*/
public function generateRequest(string $address, InstancePath $path, int $type, ACore $activity
): array {
public function generateRequest(InstancePath $path, ACore $activity): array {
$document = json_encode($activity);
$date = gmdate(self::DATE_FORMAT);
$localActor = $this->getActorFromItem($activity);
$localActorLink =
$this->configService->getUrlRoot() . '@' . $localActor->getPreferredUsername();
$signature = "(request-target): post " . $path->getPath() . "\nhost: " . $address
$signature = "(request-target): post " . $path->getPath() . "\nhost: " . $path->getAddress()
. "\ndate: " . $date;
openssl_sign($signature, $signed, $localActor->getPrivateKey(), OPENSSL_ALGO_SHA256);
@ -255,18 +322,19 @@ class ActivityService {
. $signed . '"';
$requestType = Request::TYPE_GET;
if ($type === self::REQUEST_INBOX) {
if ($path->getType() === InstancePath::TYPE_INBOX
|| $path->getType() === InstancePath::TYPE_GLOBAL
|| $path->getType() === InstancePath::TYPE_FOLLOWERS) {
$requestType = Request::TYPE_POST;
}
$request = new Request($path->getPath(), $requestType);
$request->addHeader('Host: ' . $address);
$request->addHeader('Host: ' . $path->getAddress());
$request->addHeader('Date: ' . $date);
$request->addHeader('Signature: ' . $header);
$request->setDataJson($document);
$request->setAddress($address);
$request->setAddress($path->getAddress());
return $this->curlService->request($request);
}
@ -317,6 +385,7 @@ class ActivityService {
* @throws RequestException
* @throws SignatureException
* @throws MalformedArrayException
* @throws Exception
*/
private function checkSignature(IRequest $request) {
$signatureHeader = $request->getHeader('Signature');

Wyświetl plik

@ -79,6 +79,7 @@ class CurlService {
}
$ret['_address'] = $request->getAddress();
$ret['_path'] = $request->getUrl();
$ret['_code'] = $code;
return $ret;

Wyświetl plik

@ -116,7 +116,6 @@ class ImportService {
*/
private function createItem(array $data, $root = null): ACore {
// $isTopLevel = ($root === null);
switch ($this->get('type', $data)) {
case Create::TYPE:
$item = new Create($root);

Wyświetl plik

@ -94,9 +94,7 @@ class PostService {
$actor = $this->actorService->getActorFromUserId($post->getUserId());
return $this->activityService->createActivity(
$actor, $note, ActivityService::REQUEST_INBOX, $activity
);
return $this->activityService->createActivity($actor, $note, $activity);
}