config = config(Fediverse::class); } public function _remap(string $method, string ...$params): mixed { if (($post = model('PostModel', false)->getPostById($params[0])) === null) { throw PageNotFoundException::forPageNotFound(); } $this->post = $post; unset($params[0]); return $this->{$method}(...$params); } public function index(): Response { $noteObjectClass = $this->config->noteObject; $noteObject = new $noteObjectClass($this->post); return $this->response ->setContentType('application/activity+json') ->setBody($noteObject->toJSON()); } public function replies(): Response { /** * get post replies */ $postReplies = model('PostModel', false) ->where('in_reply_to_id', service('uuid') ->fromString($this->post->id) ->getBytes()) ->where('`published_at` <= UTC_TIMESTAMP()', null, false) ->orderBy('published_at', 'ASC'); $pageNumber = (int) $this->request->getGet('page'); if ($pageNumber < 1) { $postReplies->paginate(12); $pager = $postReplies->pager; $collection = new OrderedCollectionObject(null, $pager); } else { $paginatedReplies = $postReplies->paginate(12, 'default', $pageNumber); $pager = $postReplies->pager; $orderedItems = []; $noteObjectClass = $this->config->noteObject; if ($paginatedReplies !== null) { foreach ($paginatedReplies as $reply) { $replyObject = new $noteObjectClass($reply); $orderedItems[] = $replyObject->toArray(); } } $collection = new OrderedCollectionPage($pager, $orderedItems); } return $this->response ->setContentType('application/activity+json') ->setBody($collection->toJSON()); } public function attemptCreate(): RedirectResponse { $rules = [ 'actor_id' => 'required|is_natural_no_zero', 'message' => 'required|max_length[500]', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } $newPost = new Post([ 'actor_id' => $this->request->getPost('actor_id'), 'message' => $this->request->getPost('message'), 'published_at' => Time::now(), ]); $postModel = model('PostModel', false); if (! $postModel->addPost($newPost)) { return redirect() ->back() ->withInput() // TODO: translate ->with('error', $postModel->errors()); } // Post without preview card has been successfully created return redirect()->back(); } public function attemptFavourite(): RedirectResponse { $rules = [ 'actor_id' => 'required|is_natural_no_zero', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } $actor = model('ActorModel', false) ->getActorById($this->request->getPost('actor_id')); model('FavouriteModel', false) ->toggleFavourite($actor, $this->post->id); return redirect()->back(); } public function attemptReblog(): RedirectResponse { $rules = [ 'actor_id' => 'required|is_natural_no_zero', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } $actor = model('ActorModel', false) ->getActorById($this->request->getPost('actor_id')); model('PostModel', false) ->toggleReblog($actor, $this->post); return redirect()->back(); } public function attemptReply(): RedirectResponse { $rules = [ 'actor_id' => 'required|is_natural_no_zero', 'message' => 'required|max_length[500]', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } $newReplyPost = new Post([ 'actor_id' => $this->request->getPost('actor_id'), 'in_reply_to_id' => $this->post->id, 'message' => $this->request->getPost('message'), 'published_at' => Time::now(), ]); if (! model('PostModel', false)->addReply($newReplyPost)) { return redirect() ->back() ->withInput() // TODO: translate ->with('error', "Couldn't create Reply"); } // Reply post without preview card has been successfully created return redirect()->back(); } public function attemptRemoteAction(string $action): RedirectResponse | ResponseInterface { $rules = [ 'handle' => 'regex_match[/^@?(?P[\w\.\-]+)@(?P[\w\.\-]+)(?P:[\d]+)?$/]', ]; if (! $this->validate($rules)) { return redirect() ->back() ->withInput() ->with('errors', $this->validator->getErrors()); } helper('text'); // get webfinger data from actor // parse actor id to get actor and domain // check if actor and domain exist if ( ! ($parts = split_handle($this->request->getPost('handle'))) || ! ($data = get_webfinger_data($parts['username'], $parts['domain'])) ) { return redirect() ->back() ->withInput() ->with('error', lang('Fediverse.follow.accountNotFound')); } $ostatusKey = array_search( 'http://ostatus.org/schema/1.0/subscribe', array_column($data->links, 'rel'), true, ); if (! $ostatusKey) { // TODO: error, couldn't remote favourite/share/reply to post // The instance doesn't allow its users remote actions on posts return $this->response->setJSON([]); } return redirect()->to( str_replace('{uri}', urlencode($this->post->uri), (string) $data->links[$ostatusKey]->template), ); } public function attemptBlockActor(): RedirectResponse { model('ActorModel', false)->blockActor($this->post->actor->id); return redirect()->back(); } public function attemptBlockDomain(): RedirectResponse { model('BlockedDomainModel', false)->blockDomain($this->post->actor->domain); return redirect()->back(); } public function attemptDelete(): RedirectResponse { model('PostModel', false)->removePost($this->post); return redirect()->back(); } }