diff --git a/DOCUMENTATION/DEVELOPERS/EVENTS.txt b/DOCUMENTATION/DEVELOPERS/EVENTS.txt index 7433395f7c..7ab80afc94 100644 --- a/DOCUMENTATION/DEVELOPERS/EVENTS.txt +++ b/DOCUMENTATION/DEVELOPERS/EVENTS.txt @@ -1496,3 +1496,16 @@ StartDocNav: Before outputting the docs Nav EndDocNav: After outputting the docs Nav - $nav: The DoclNav widget + +StartNoticeSearch: Before finding notices that match the given query +- string $query: The text query + +StartNoticeSearchShowResults: Before displaying notices matching the query +- $out: HTMLOutputter used to output +- $query: The text query +- $notices: Array of DB notice objects + +EndNoticeSearchShowResults: After displaying notices matching the query +- $out: HTMLOutputter used to output +- $query: The text query +- $notices: Array of DB notice objects diff --git a/actions/noticesearch.php b/actions/noticesearch.php index 6dcd29bde7..ddc4bd477c 100644 --- a/actions/noticesearch.php +++ b/actions/noticesearch.php @@ -65,6 +65,8 @@ class NoticesearchAction extends SearchAction if (!empty($this->q)) { + Event::handle('StartNoticeSearch', [$this->q]); + $stream = new SearchNoticeStream($this->q, $this->scoped); $page = $this->trimmed('page'); diff --git a/plugins/ActivityPub/ActivityPubPlugin.php b/plugins/ActivityPub/ActivityPubPlugin.php index 89ded8855c..057b10afeb 100644 --- a/plugins/ActivityPub/ActivityPubPlugin.php +++ b/plugins/ActivityPub/ActivityPubPlugin.php @@ -50,7 +50,7 @@ const ACTIVITYPUB_PUBLIC_TO = ['https://www.w3.org/ns/activitystreams#Public', */ class ActivityPubPlugin extends Plugin { - const PLUGIN_VERSION = '0.3.0alpha0'; + const PLUGIN_VERSION = '0.4.0alpha0'; /** * Returns a Actor's URI from its local $profile @@ -119,7 +119,7 @@ class ActivityPubPlugin extends Plugin $client = new HTTPClient(); $headers = []; $headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; - $headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social'; + $headers[] = 'User-Agent: GNUSocialBot ' . GNUSOCIAL_VERSION . ' - https://gnu.io/social'; $response = $client->get($url, $headers); $object = json_decode($response->getBody(), true); Activitypub_notice::validate_note($object); @@ -398,6 +398,68 @@ class ActivityPubPlugin extends Plugin return true; } + /** + * Hack the notice search-box and try to grab remote profiles or notices. + * + * Note that, on successful grabbing, this function will redirect to the + * new profile/notice, so URL searching is directly affected. A good solution + * for this is to store the URLs in the notice text without the https/http + * prefixes. This would change the queries for URL searching and therefore we + * could do both search and grab. + * + * @param string $query search query + * @return void + */ + public function onStartNoticeSearch(string $query): void + { + if (!common_logged_in()) { + // early return, search-only for non-logged sessions + return; + } + + if (!filter_var($query, FILTER_VALIDATE_URL) && + !preg_match('!^((?:\w+\.)*\w+@(?:\w+\.)*\w+(?:\w+\-\w+)*\.\w+)$!', $query)) { + // early return, not an url or webfinger ID + return; + } + + // someone we know about ? + try { + $explorer = new Activitypub_explorer(); + $profile = $explorer->lookup($query, false)[0]; + if ($profile instanceof Profile) { + return; + } + } catch (Exception $e) { + // nope + } + + // some notice we know about ? + try { + $notice = self::grab_notice_from_url($query, false); + if ($notice instanceof Notice) { + return; + } + } catch (Exception $e) { + // nope + } + + // try to grab profile + $aprofile = self::pull_remote_profile($query); + if ($aprofile instanceof Activitypub_profile) { + $url = common_local_url('userbyid', ['id' => $aprofile->getID()], null, null, false); + common_redirect($url, 303); + return; + } + + // try to grab notice + $notice = self::grab_notice_from_url($query); + if ($notice instanceof Notice) { + $url = common_local_url('shownotice', ['notice' => $notice->getID()]); + common_redirect($url, 303); + } + } + /** * Make sure necessary tables are filled out. * diff --git a/plugins/ActivityPub/lib/explorer.php b/plugins/ActivityPub/lib/explorer.php index f0e75baecc..1b39137c80 100644 --- a/plugins/ActivityPub/lib/explorer.php +++ b/plugins/ActivityPub/lib/explorer.php @@ -65,13 +65,14 @@ class Activitypub_explorer * so that there is no erroneous data * * @param string $url User's url + * @param bool $remote remote lookup? * @return array of Profile objects * @throws HTTP_Request2_Exception * @throws NoProfileException * @throws ServerException * @author Diogo Cordeiro */ - public function lookup($url) + public function lookup(string $url, bool $remote = true) { if (in_array($url, ACTIVITYPUB_PUBLIC_TO)) { return []; @@ -80,7 +81,7 @@ class Activitypub_explorer common_debug('ActivityPub Explorer: Started now looking for '.$url); $this->discovered_actor_profiles = []; - return $this->_lookup($url); + return $this->_lookup($url, $remote); } /** @@ -89,6 +90,7 @@ class Activitypub_explorer * $discovered_actor_profiles array * * @param string $url User's url + * @param bool $remote remote lookup? * @return array of Profile objects * @throws HTTP_Request2_Exception * @throws NoProfileException @@ -96,11 +98,13 @@ class Activitypub_explorer * @throws Exception * @author Diogo Cordeiro */ - private function _lookup($url) + private function _lookup(string $url, bool $remote) { - // First check if we already have it locally and, if so, return it - // If the local fetch fails: grab it remotely, store locally and return - if (! ($this->grab_local_user($url) || $this->grab_remote_user($url))) { + $grab_local = $this->grab_local_user($url); + + // First check if we already have it locally and, if so, return it. + // If the local fetch fails and remote grab is required: store locally and return. + if (!$grab_local && (!$remote || !$this->grab_remote_user($url))) { throw new Exception('User not found.'); } @@ -403,7 +407,7 @@ class Activitypub_explorer $client = new HTTPClient(); $headers = []; $headers[] = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; - $headers[] = 'User-Agent: GNUSocialBot v0.1 - https://gnu.io/social'; + $headers[] = 'User-Agent: GNUSocialBot ' . GNUSOCIAL_VERSION . ' - https://gnu.io/social'; $response = $client->get($url, $headers); if (!$response->isOk()) { throw new Exception('Invalid Actor URL.');