aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Digitigrade/Model/Actor.php58
-rw-r--r--Digitigrade/Model/ActorEndpoints.php2
-rw-r--r--migrations/20241220_123220_add_actor_accept_reject_endpoints.php13
-rw-r--r--routes/actor.php24
4 files changed, 75 insertions, 22 deletions
diff --git a/Digitigrade/Model/Actor.php b/Digitigrade/Model/Actor.php
index 89f4d50..07f24ec 100644
--- a/Digitigrade/Model/Actor.php
+++ b/Digitigrade/Model/Actor.php
@@ -97,38 +97,42 @@ class Actor extends PushableModel implements RpcReceiver {
}
public function rpcCall(string $method, array $args) {
+ // $args = [Actor $actingAs]
+ if (!$this->isLocal) {
+ // trigger the same action on the remote server
+ $endpoint = $this->endpoints->{$method} ?? null;
+ if (!isset($endpoint)) {
+ throw new RpcException("Actor `$this->uri` has no $method endpoint");
+ }
+ $result = send_request_authenticated($endpoint, method: 'POST', actingAs: $args[0]);
+ if (!str_contains($result->headers[0], ' 20')) {
+ throw new RpcException('remote call did not indicate success: ' . $result->headers[0]);
+ }
+ }
+
+ // the actual logic
switch ($method) {
- case 'follow': // $this is the target, $args[0] is the initiator
+ case 'follow':
$status = $this->requestToFollow ? FollowRelationStatus::PENDING : FollowRelationStatus::ACTIVE;
- if (!$this->isLocal) {
- $endpoint = $this->endpoints->follow ?? null;
- if (!isset($endpoint, $this->endpoints->unfollow)) {
- throw new RpcException("Actor `$this->uri` has no (un)follow endpoint");
- }
- $result = send_request_authenticated($endpoint, method: 'POST', actingAs: $args[0]);
- if (!str_contains($result->headers[0], ' 20')) {
- throw new RpcException('remote call did not indicate success: ' . $result->headers[0]);
- }
- }
FollowRelation::create($args[0], $this, $status);
return $status;
case 'unfollow':
- if (!$this->isLocal) {
- $endpoint = $this->endpoints->unfollow ?? null;
- if (!isset($endpoint, $this->endpoints->follow)) {
- throw new RpcException("Actor `$this->uri` has no (un)follow endpoint");
- }
- $result = send_request_authenticated($endpoint, method: 'POST', actingAs: $args[0]);
- if (!str_contains($result->headers[0], ' 20')) {
- throw new RpcException('remote call did not indicate success: ' . $result->headers[0]);
- }
- }
FollowRelation::findByActors($args[0], $this)->remove();
return;
+ case 'acceptedFollow':
+ $rel = FollowRelation::findByActors($this, $args[0]);
+ $rel->status = FollowRelationStatus::ACTIVE;
+ $rel->save();
+ return;
+
+ case 'rejectedFollow':
+ FollowRelation::findByActors($this, $args[0])->remove();
+ return;
+
default:
- throw new \RuntimeException("Actor rpc method $method not (yet?) implemented");
+ throw new \RuntimeException("behaviour for actor rpc method $method not (yet?) implemented");
}
}
@@ -145,6 +149,14 @@ class Actor extends PushableModel implements RpcReceiver {
$target->rpcCall('unfollow', [$this]);
}
+ public function acceptPendingFollowFrom(self $initiator) {
+ $initiator->rpcCall('acceptedFollow', [$this]);
+ }
+
+ public function rejectPendingFollowFrom(self $initiator) {
+ $initiator->rpcCall('rejectedFollow', [$this]);
+ }
+
/**
* @return Actor[] a list of actors that follow this actor (does not include pending follows)
*/
@@ -203,6 +215,8 @@ class Actor extends PushableModel implements RpcReceiver {
'fullFeed' => path_to_uri("/user/$this->handle/fullFeed"),
'follow' => path_to_uri("/user/$this->handle/follow"),
'unfollow' => path_to_uri("/user/$this->handle/unfollow"),
+ 'acceptedFollow' => path_to_uri("/user/$this->handle/acceptedFollow"),
+ 'rejectedFollow' => path_to_uri("/user/$this->handle/rejectedFollow"),
]
];
}
diff --git a/Digitigrade/Model/ActorEndpoints.php b/Digitigrade/Model/ActorEndpoints.php
index 2278e19..f2bc85a 100644
--- a/Digitigrade/Model/ActorEndpoints.php
+++ b/Digitigrade/Model/ActorEndpoints.php
@@ -9,6 +9,8 @@ class ActorEndpoints extends Model {
public ?string $fullFeed;
public ?string $follow;
public ?string $unfollow;
+ public ?string $acceptedFollow;
+ public ?string $rejectedFollow;
public ?string $block;
public ?string $unblock;
diff --git a/migrations/20241220_123220_add_actor_accept_reject_endpoints.php b/migrations/20241220_123220_add_actor_accept_reject_endpoints.php
new file mode 100644
index 0000000..4cf2226
--- /dev/null
+++ b/migrations/20241220_123220_add_actor_accept_reject_endpoints.php
@@ -0,0 +1,13 @@
+<?php
+
+use \Digitigrade\Db\Migrator;
+
+Migrator::getInstance()->register(20241220_123220, function (PDO $db) {
+ // accept/reject follow request endpoints
+ $db->beginTransaction();
+ $db->exec(<<<END
+ ALTER TABLE actor_endpoints ADD COLUMN accepted_follow text;
+ ALTER TABLE actor_endpoints ADD COLUMN rejected_follow text;
+ END);
+ $db->commit();
+});
diff --git a/routes/actor.php b/routes/actor.php
index 98e8f4e..65a3837 100644
--- a/routes/actor.php
+++ b/routes/actor.php
@@ -68,4 +68,28 @@ Router::getInstance()->mount('/user/:handle/unfollow', function (array $args) {
throw new Unauthorized('please authenticate yourself on behalf of the initiating actor');
}
$initiator->unfollow($target);
+});
+
+Router::getInstance()->mount('/user/:handle/acceptedFollow', function (array $args) {
+ $initiator = Actor::findLocalByHandle($args['handle']);
+ if ($initiator == null) {
+ throw new NotFound();
+ }
+ $target = Actor::findByRequestHeaders();
+ if ($target == null) {
+ throw new Unauthorized('please authenticate yourself on behalf of the followed actor');
+ }
+ $target->acceptPendingFollowFrom($initiator);
+});
+
+Router::getInstance()->mount('/user/:handle/rejectedFollow', function (array $args) {
+ $initiator = Actor::findLocalByHandle($args['handle']);
+ if ($initiator == null) {
+ throw new NotFound();
+ }
+ $target = Actor::findByRequestHeaders();
+ if ($target == null) {
+ throw new Unauthorized('please authenticate yourself on behalf of the followed actor');
+ }
+ $target->rejectPendingFollowFrom($initiator);
}); \ No newline at end of file