]> git.mxchange.org Git - friendica.git/commitdiff
Merge pull request #12674 from nupplaphil/bug/config_typesafe
authorHypolite Petovan <hypolite@mrpetovan.com>
Sun, 15 Jan 2023 14:38:29 +0000 (09:38 -0500)
committerGitHub <noreply@github.com>
Sun, 15 Jan 2023 14:38:29 +0000 (09:38 -0500)
Config: Improve the node.config.php transformation

46 files changed:
doc/Addons.md
doc/de/Addons.md
mod/item.php
mod/notes.php
src/App/Page.php
src/Contact/Avatar.php
src/Content/Conversation.php
src/Core/Config/Capability/IManageConfigValues.php
src/Core/Config/Model/Config.php
src/Core/Config/Model/ConfigTransaction.php
src/Core/Config/ValueObject/Cache.php
src/Core/Hook.php
src/Factory/Api/Mastodon/Error.php
src/Model/Contact.php
src/Model/Item.php
src/Module/ActivityPub/Objects.php
src/Module/Api/Mastodon/Apps.php
src/Module/Calendar/Export.php
src/Module/Calendar/Show.php
src/Module/Conversation/Community.php
src/Module/Conversation/Network.php
src/Module/DFRN/Poll.php
src/Module/Feed.php
src/Module/Item/Display.php
src/Module/OAuth/Token.php
src/Module/Profile/Conversations.php
src/Module/Search/Filed.php
src/Module/Search/Index.php
src/Module/Settings/Addons.php
src/Module/Settings/Connectors.php
src/Module/Update/Community.php
src/Module/Update/Network.php
src/Module/Update/Profile.php
src/Util/Network.php
src/Util/Strings.php
src/Worker/Expire.php
src/Worker/ForkHook.php
static/defaults.config.php
tests/Util/SampleStorageBackendInstance.php
tests/Util/authtest/authtest.php
tests/src/Core/Config/Cache/CacheTest.php
tests/src/Core/Config/Cache/ConfigFileManagerTest.php
tests/src/Core/Config/ConfigTest.php
view/lang/C/messages.po
view/theme/frio/php/default.php
view/theme/frio/theme.php

index 171b5681a19f90de915514fea9dd19805b14ebe5..dbb2c501fe34d11b4de6b6d1a44eab385d4bdc52 100644 (file)
@@ -60,25 +60,14 @@ This *should* be 'addon/*addon_name*/*addon_name*.php' in most cases and can be
 `$function` is a string and is the name of the function which will be executed when the hook is called.
 
 ### Arguments
-Your hook callback functions will be called with at least one and possibly two arguments
+Your hook callback functions will be called with at most one argument
 
-    function <addon>_<hookname>(App $a, &$b) {
+    function <addon>_<hookname>(&$b) {
 
     }
 
 If you wish to make changes to the calling data, you must declare them as reference variables (with `&`) during function declaration.
 
-#### $a
-$a is the Friendica `App` class.
-It contains a wealth of information about the current state of Friendica:
-
-* which module has been called,
-* configuration information,
-* the page contents at the point the hook was invoked,
-* profile and user information, etc.
-
-It is recommeded you call this `$a` to match its usage elsewhere.
-
 #### $b
 $b can be called anything you like.
 This is information specific to the hook currently being processed, and generally contains information that is being immediately processed or acted on that you can use, display, or alter.
@@ -88,7 +77,7 @@ Remember to declare it with `&` if you wish to alter it.
 
 Your addon can provide user-specific settings via the `addon_settings` PHP hook, but it can also provide node-wide settings in the administration page of your addon.
 
-Simply declare a `<addon>_addon_admin(App $a)` function to display the form and a `<addon>_addon_admin_post(App $a)` function to process the data from the form.
+Simply declare a `<addon>_addon_admin()` function to display the form and a `<addon>_addon_admin_post()` function to process the data from the form.0
 
 ## Global stylesheets
 
@@ -102,7 +91,7 @@ function <addon>_install()
 }
 
 
-function <addon>_head(App $a)
+function <addon>_head()
 {
        \Friendica\DI::page()->registerStylesheet(__DIR__ . '/relative/path/to/addon/stylesheet.css');
 }
@@ -124,7 +113,7 @@ function <addon>_install()
        ...
 }
 
-function <addon>_footer(App $a)
+function <addon>_footer()
 {
        \Friendica\DI::page()->registerFooterScript(__DIR__ . '/relative/path/to/addon/script.js');
 }
@@ -167,9 +156,9 @@ DI::args()->get(1); // = 'arg1'
 DI::args()->get(2); // = 'arg2'
 ```
 
-To display a module page, you need to declare the function `<addon>_content(App $a)`, which defines and returns the page body content.
-They may also contain `<addon>_post(App $a)` which is called before the `<addon>_content` function and typically handles the results of POST forms.
-You may also have `<addon>_init(App $a)` which is called before `<addon>_content` and should include common logic to your module.
+To display a module page, you need to declare the function `<addon>_content()`, which defines and returns the page body content.
+They may also contain `<addon>_post()` which is called before the `<addon>_content` function and typically handles the results of POST forms.
+You may also have `<addon>_init()` which is called before `<addon>_content` and should include common logic to your module.
 
 ## Templates
 
@@ -209,7 +198,7 @@ Called when a user attempts to login.
 
 ### logged_in
 Called after a user has successfully logged in.
-`$b` contains the `$a->user` array.
+`$b` contains the `App->user` array.
 
 ### display_item
 Called when formatting a post for display.
@@ -360,7 +349,7 @@ Called prior to output of profile edit page.
 ### profile_advanced
 Called when the HTML is generated for the Advanced profile, corresponding to the Profile tab within a person's profile page.
 `$b` is the HTML string representation of the generated profile.
-The profile array details are in `$a->profile`.
+The profile array details are in `App->profile`.
 
 ### directory_item
 Called from the Directory page when formatting an item for display.
index 143e309cbba4059bbc26b589e4ea33a20957c698..73f2aeb45efb7e92530436a50e35507698dec9a1 100644 (file)
@@ -38,17 +38,14 @@ $function ist ein String und der Name der Funktion, die ausgeführt wird, wenn d
 Argumente
 ---
 
-Deine Hook-Callback-Funktion wird mit mindestens einem und bis zu zwei Argumenten aufgerufen
+Deine Hook-Callback-Funktion wird mit höchstens einem Argumenten aufgerufen
 
-    function myhook_function(App $a, &$b) {
+    function myhook_function(&$b) {
 
     }
 
 Wenn du Änderungen an den aufgerufenen Daten vornehmen willst, musst du diese als Referenzvariable (mit "&") während der Funktionsdeklaration deklarieren.
 
-$a ist die Friendica "App"-Klasse, die eine Menge an Informationen über den aktuellen Friendica-Status beinhaltet, u.a. welche Module genutzt werden, Konfigurationsinformationen, Inhalte der Seite zum Zeitpunkt des Hook-Aufrufs.
-Es ist empfohlen, diese Funktion "$a" zu nennen, um seine Nutzung an den Gebrauch an anderer Stelle anzugleichen.
-
 $b kann frei benannt werden.
 Diese Information ist speziell auf den Hook bezogen, der aktuell bearbeitet wird, und beinhaltet normalerweise Daten, die du sofort nutzen, anzeigen oder bearbeiten kannst.
 Achte darauf, diese mit "&" zu deklarieren, wenn du sie bearbeiten willst.
@@ -70,9 +67,9 @@ DI::args()->get(1); // = 'arg1'
 DI::args()->get(2); // = 'arg2'
 ```
 
-Deine Modulfunktionen umfassen oft die Funktion addon_name_content(App $a), welche den Seiteninhalt definiert und zurückgibt.
-Sie können auch addon_name_post(App $a) umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt.
-Du kannst ebenso addon_name_init(App $a) nutzen, was oft frühzeitig aufgerufen wird und das Modul initialisert.
+Deine Modulfunktionen umfassen oft die Funktion `addon_name_content()`, welche den Seiteninhalt definiert und zurückgibt.
+Sie können auch `addon_name_post()` umfassen, welches vor der content-Funktion aufgerufen wird und normalerweise die Resultate der POST-Formulare handhabt.
+Du kannst ebenso `addon_name_init()` nutzen, was oft frühzeitig aufgerufen wird und das Modul initialisert.
 
 
 Derzeitige Hooks
@@ -86,7 +83,7 @@ Derzeitige Hooks
         'user_record' => die erfolgreiche Authentifizierung muss auch einen gültigen Nutzereintrag aus der Datenbank zurückgeben
 
 **'logged_in'** - wird aufgerufen, sobald ein Nutzer sich erfolgreich angemeldet hat.
-    $b beinhaltet den $a->Nutzer-Array
+    $b beinhaltet den `App->user`
 
 
 **'display_item'** - wird aufgerufen, wenn ein Beitrag für die Anzeige formatiert wird.
@@ -122,7 +119,7 @@ Derzeitige Hooks
 
 **'profile_advanced'** - wird aufgerufen, wenn die HTML-Ausgabe für das "Advanced profile" generiert wird; stimmt mit dem "Profil"-Tab auf der Profilseite der Nutzer überein.
     $b ist die HTML-Ausgabe (String) des erstellten Profils
-    (Die Details des Profil-Arrays sind in $a->profile)
+    (Die Details des Profil-Arrays sind in `App->profile`)
 
 **'directory_item'** - wird von der Verzeichnisseite aufgerufen, wenn ein Item für die Anzeige formatiert wird.
     $b ist ein Array
index c1740c274f8d4b7e9f819cb7502ba70fbd013967..13ffe756833b6c391e52784a8f7af6b075535cf5 100644 (file)
@@ -29,6 +29,7 @@
  */
 
 use Friendica\App;
+use Friendica\Content\Conversation;
 use Friendica\Content\Text\BBCode;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
@@ -274,7 +275,7 @@ function item_process(array $post, array $request, bool $preview, string $return
                $post['body']           = BBCode::removeSharedData(Item::setHashtags($post['body']));
                $post['writable']       = true;
 
-               $o = DI::conversation()->create([$post], 'search', false, true);
+               $o = DI::conversation()->create([$post], Conversation::MODE_SEARCH, false, true);
 
                System::jsonExit(['preview' => $o]);
        }
index 00a74eecad0b7f3c2f5fcc028e8846e264fa87fe..360441471f1dd4fc2eba08230e42a29ba2656995 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 use Friendica\App;
+use Friendica\Content\Conversation;
 use Friendica\Content\Nav;
 use Friendica\Content\Pager;
 use Friendica\Database\DBA;
@@ -84,7 +85,7 @@ function notes_content(App $a, bool $update = false)
 
                $count = count($notes);
 
-               $o .= DI::conversation()->create($notes, 'notes', $update);
+               $o .= DI::conversation()->create($notes, Conversation::MODE_NOTES, $update);
        }
 
        $o .= $pager->renderMinimal($count);
index 3c746ebccbe7d2e8861e5285709727e9634ceb03..a91d400ee88057d99b220f7e5a7f257b7e0c2b95 100644 (file)
@@ -73,6 +73,8 @@ class Page implements ArrayAccess
                'right_aside' => '',
                'template'    => '',
                'title'       => '',
+               'section'     => '',
+               'module'      => '',
        ];
        /**
         * @var string The basepath of the page
@@ -513,6 +515,11 @@ class Page implements ArrayAccess
 
                $page    = $this->page;
 
+               // add and escape some common but crucial content for direct "echo" in HTML (security)
+               $page['title']   = htmlspecialchars($page['title'] ?? '');
+               $page['section'] = htmlspecialchars($args->get(0) ?? 'generic');
+               $page['module']  = htmlspecialchars($args->getModuleName() ?? '');
+
                header("X-Friendica-Version: " . App::VERSION);
                header("Content-type: text/html; charset=utf-8");
 
index 7151acbfbd0190a6bb9bf8e63d1cce97f8f88503..e039a52799fc524e98f605cbb00ad51e198307a1 100644 (file)
@@ -246,13 +246,16 @@ class Avatar
         * Delete locally cached avatar pictures of a contact
         *
         * @param string $avatar
-        * @return void
+        * @return bool
         */
-       public static function deleteCache(array $contact)
+       public static function deleteCache(array $contact): bool
        {
+               $existed = (self::isCacheFile($contact['photo']) || self::isCacheFile($contact['thumb']) || self::isCacheFile($contact['micro']));
                self::deleteCacheFile($contact['photo']);
                self::deleteCacheFile($contact['thumb']);
                self::deleteCacheFile($contact['micro']);
+
+               return $existed;
        }
 
        /**
index f391bbb4acadaf714e992f0f83941f12463d90cb..c5e854b1d9ece6a02f55ab98e9238aec0ef4022b 100644 (file)
@@ -53,6 +53,16 @@ use Psr\Log\LoggerInterface;
 
 class Conversation
 {
+       const MODE_COMMUNITY     = 'community';
+       const MODE_CONTACTS      = 'contacts';
+       const MODE_CONTACT_POSTS = 'contact-posts';
+       const MODE_DISPLAY       = 'display';
+       const MODE_FILED         = 'filed';
+       const MODE_NETWORK       = 'network';
+       const MODE_NOTES         = 'notes';
+       const MODE_SEARCH        = 'search';
+       const MODE_PROFILE       = 'profile';
+
        /** @var Activity */
        private $activity;
        /** @var L10n */
@@ -444,7 +454,7 @@ class Conversation
 
                $previewing = (($preview) ? ' preview ' : '');
 
-               if ($mode === 'network') {
+               if ($mode === self::MODE_NETWORK) {
                        $items = $this->addChildren($items, false, $order, $uid, $mode);
                        if (!$update) {
                                /*
@@ -470,7 +480,7 @@ class Conversation
 
                                        . "'; </script>\r\n";
                        }
-               } elseif ($mode === 'profile') {
+               } elseif ($mode === self::MODE_PROFILE) {
                        $items = $this->addChildren($items, false, $order, $uid, $mode);
 
                        if (!$update) {
@@ -487,7 +497,7 @@ class Conversation
                                                . "; var netargs = '?f='; </script>\r\n";
                                }
                        }
-               } elseif ($mode === 'notes') {
+               } elseif ($mode === self::MODE_NOTES) {
                        $items = $this->addChildren($items, false, $order, $this->session->getLocalUserId(), $mode);
 
                        if (!$update) {
@@ -495,7 +505,7 @@ class Conversation
                                        . "<script> var profile_uid = " . $this->session->getLocalUserId()
                                        . "; var netargs = '?f='; </script>\r\n";
                        }
-               } elseif ($mode === 'display') {
+               } elseif ($mode === self::MODE_DISPLAY) {
                        $items = $this->addChildren($items, false, $order, $uid, $mode);
 
                        if (!$update) {
@@ -503,7 +513,7 @@ class Conversation
                                        . "<script> var profile_uid = " . ($this->session->getLocalUserId() ?: 0) . ";"
                                        . "</script>";
                        }
-               } elseif ($mode === 'community') {
+               } elseif ($mode === self::MODE_COMMUNITY) {
                        $items = $this->addChildren($items, true, $order, $uid, $mode);
 
                        if (!$update) {
@@ -514,7 +524,7 @@ class Conversation
                                        . (!empty($_GET['accounttype']) ? '&accounttype=' . rawurlencode($_GET['accounttype']) : '')
                                        . "'; </script>\r\n";
                        }
-               } elseif ($mode === 'contacts') {
+               } elseif ($mode === self::MODE_CONTACTS) {
                        $items = $this->addChildren($items, false, $order, $uid, $mode);
 
                        if (!$update) {
@@ -522,11 +532,11 @@ class Conversation
                                        . "<script> var profile_uid = -1; var netargs = '" . substr($this->args->getCommand(), 8)
                                        ."?f='; </script>\r\n";
                        }
-               } elseif ($mode === 'search') {
+               } elseif ($mode === self::MODE_SEARCH) {
                        $live_update_div = '<div id="live-search"></div>' . "\r\n";
                }
 
-               $page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != 'search';
+               $page_dropping = $this->session->getLocalUserId() && $this->session->getLocalUserId() == $uid && $mode != self::MODE_SEARCH;
 
                if (!$update) {
                        $_SESSION['return_path'] = $this->args->getQueryString();
@@ -558,7 +568,7 @@ class Conversation
                $formSecurityToken = BaseModule::getFormSecurityToken('contact_action');
 
                if (!empty($items)) {
-                       if (in_array($mode, ['community', 'contacts', 'profile'])) {
+                       if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_CONTACTS, self::MODE_PROFILE])) {
                                $writable = true;
                        } else {
                                $writable = $items[0]['writable'] || ($items[0]['uid'] == 0) && in_array($items[0]['network'], Protocol::FEDERATED);
@@ -568,7 +578,7 @@ class Conversation
                                $writable = false;
                        }
 
-                       if (in_array($mode, ['filed', 'search', 'contact-posts'])) {
+                       if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) {
 
                                /*
                                * "New Item View" on network page or search page results
@@ -621,7 +631,7 @@ class Conversation
                                        $location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: '');
 
                                        $this->item->localize($item);
-                                       if ($mode === 'filed') {
+                                       if ($mode === self::MODE_FILED) {
                                                $dropping = true;
                                        } else {
                                                $dropping = false;
@@ -972,6 +982,11 @@ class Conversation
                $condition = DBA::mergeConditions($condition,
                        ["`uid` IN (0, ?) AND (NOT `vid` IN (?, ?, ?) OR `vid` IS NULL)", $uid, Verb::getID(Activity::FOLLOW), Verb::getID(Activity::VIEW), Verb::getID(Activity::READ)]);
 
+               $condition = DBA::mergeConditions($condition,
+                       ["`visible` AND NOT `deleted` AND NOT `author-blocked` AND NOT `owner-blocked`
+                       AND ((NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?)",
+                       Contact::SHARING, Contact::FRIEND, 0]);
+
                $thread_parents = Post::select(['uri-id', 'causer-id'], $condition, ['order' => ['uri-id' => false, 'uid']]);
 
                $thr_parent = [];
@@ -983,17 +998,18 @@ class Conversation
 
                $params = ['order' => ['uri-id' => true, 'uid' => true]];
 
-               $thread_items = Post::selectForUser($uid, array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
+               $thread_items = Post::select(array_merge(ItemModel::DISPLAY_FIELDLIST, ['featured', 'contact-uid', 'gravity', 'post-type', 'post-reason']), $condition, $params);
 
                $items         = [];
                $quote_uri_ids = [];
+               $authors       = [];
 
                while ($row = Post::fetch($thread_items)) {
                        if (!empty($items[$row['uri-id']]) && ($row['uid'] == 0)) {
                                continue;
                        }
 
-                       if (($mode != 'contacts') && !$row['origin']) {
+                       if (($mode != self::MODE_CONTACTS) && !$row['origin']) {
                                $row['featured'] = false;
                        }
 
@@ -1006,6 +1022,9 @@ class Conversation
                                }
                        }
 
+                       $authors[] = $row['author-id'];
+                       $authors[] = $row['owner-id'];
+
                        if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT])) {
                                $quote_uri_ids[$row['uri-id']] = [
                                        'uri-id'        => $row['uri-id'],
@@ -1033,10 +1052,50 @@ class Conversation
                        $row['thr-parent']    = $quote_uri_ids[$quote['quote-uri-id']]['uri'];
                        $row['thr-parent-id'] = $quote_uri_ids[$quote['quote-uri-id']]['uri-id'];
 
+                       $authors[] = $row['author-id'];
+                       $authors[] = $row['owner-id'];
+
                        $items[$row['uri-id']] = $this->addRowInformation($row, [], []);
                }
                DBA::close($quotes);
 
+               $authors = array_unique($authors);
+
+               $blocks    = [];
+               $ignores   = [];
+               $collapses = [];
+               if (!empty($authors)) {
+                       $usercontacts = DBA::select('user-contact', ['cid', 'blocked', 'ignored', 'collapsed'], ['uid' => $uid, 'cid' => $authors]);
+                       while ($usercontact = DBA::fetch($usercontacts)) {
+                               if ($usercontact['blocked']) {
+                                       $blocks[] = $usercontact['cid'];
+                               }
+                               if ($usercontact['ignored']) {
+                                       $ignores[] = $usercontact['cid'];
+                               }
+                               if ($usercontact['collapsed']) {
+                                       $collapses[] = $usercontact['cid'];
+                               }
+                       }
+                       DBA::close($usercontacts);
+               }
+
+               foreach ($items as $key => $row) {
+                       $always_display = in_array($mode, [self::MODE_CONTACTS, self::MODE_CONTACT_POSTS]);
+
+                       $items[$key]['user-blocked-author']   = !$always_display && in_array($row['author-id'], $blocks);
+                       $items[$key]['user-ignored-author']   = !$always_display && in_array($row['author-id'], $ignores);
+                       $items[$key]['user-blocked-owner']    = !$always_display && in_array($row['owner-id'], $blocks);
+                       $items[$key]['user-ignored-owner']    = !$always_display && in_array($row['owner-id'], $ignores);
+                       $items[$key]['user-collapsed-author'] = !$always_display && in_array($row['author-id'], $collapses);
+                       $items[$key]['user-collapsed-owner']  = !$always_display && in_array($row['owner-id'], $collapses);
+
+                       if (in_array($mode, [self::MODE_COMMUNITY, self::MODE_NETWORK]) &&
+                               (in_array($row['author-id'], $blocks) || in_array($row['owner-id'], $blocks) || in_array($row['author-id'], $ignores) || in_array($row['owner-id'], $ignores))) {
+                               unset($items[$key]);
+                       }
+               }
+
                $items = $this->convSort($items, $order);
 
                $this->profiler->stopRecording();
index 09e2cd9144fdd8863fae4d7a4bd0958d4f167ead..2c3d6da3c885e5bd307770ae607f24997f6bcdd2 100644 (file)
@@ -58,20 +58,6 @@ interface IManageConfigValues
         */
        public function get(string $cat, string $key = null, $default_value = null);
 
-       /**
-        * Load all configuration values from a given cache and saves it back in the configuration node store
-        * @see ConfigFileManager::CONFIG_DATA_FILE
-        *
-        * All configuration values of the system are stored in the cache.
-        *
-        * @param Cache $cache a new cache
-        *
-        * @return void
-        *
-        * @throws ConfigPersistenceException In case the persistence layer throws errors
-        */
-       public function load(Cache $cache);
-
        /**
         * Sets a configuration value for system config
         *
index c96750694becdf0fae0216dedb60d25a0b84596c..46d5643b344bc66e4538b693b17bc400bcba296f 100644 (file)
@@ -49,6 +49,24 @@ class Config implements IManageConfigValues
                $this->configCache       = $configCache;
        }
 
+       /**
+        * Load all configuration values from a given cache and saves it back in the configuration node store
+        * @see ConfigFileManager::CONFIG_DATA_FILE
+        *
+        * All configuration values of the system are stored in the cache.
+        *
+        * @param Cache $cache a new cache
+        *
+        * @return void
+        *
+        * @throws ConfigPersistenceException In case the persistence layer throws errors
+        */
+       public function setCacheAndSave(Cache $cache)
+       {
+               $this->configCache = $cache;
+               $this->save();
+       }
+
        /**
         * {@inheritDoc}
         */
@@ -71,6 +89,8 @@ class Config implements IManageConfigValues
        {
                try {
                        $this->configFileManager->saveData($this->configCache);
+                       // reload after the save to possible reload default values of lower source-priorities again
+                       $this->reload();
                } catch (ConfigFileException $e) {
                        throw new ConfigPersistenceException('Cannot save config', $e);
                }
@@ -89,13 +109,6 @@ class Config implements IManageConfigValues
                $this->configCache = $configCache;
        }
 
-       /** {@inheritDoc} */
-       public function load(Cache $cache)
-       {
-               $this->configCache = $cache;
-               $this->save();
-       }
-
        /** {@inheritDoc} */
        public function get(string $cat, string $key = null, $default_value = null)
        {
@@ -116,7 +129,7 @@ class Config implements IManageConfigValues
        /** {@inheritDoc} */
        public function delete(string $cat, string $key): bool
        {
-               if ($this->configCache->delete($cat, $key, Cache::SOURCE_DATA)) {
+               if ($this->configCache->delete($cat, $key)) {
                        $this->save();
                        return true;
                } else {
index ec0a2b9c8b9692c3df244e425bd197eeec545a41..b9310301f37ef98981bbd42848bc9e88832a71b6 100644 (file)
@@ -57,7 +57,7 @@ class ConfigTransaction implements ISetConfigValuesTransactionally
        /** {@inheritDoc} */
        public function delete(string $cat, string $key): ISetConfigValuesTransactionally
        {
-               $this->cache->delete($cat, $key, Cache::SOURCE_DATA);
+               $this->cache->delete($cat, $key);
                $this->changedConfig = true;
 
                return $this;
@@ -72,7 +72,7 @@ class ConfigTransaction implements ISetConfigValuesTransactionally
                }
 
                try {
-                       $this->config->load($this->cache);
+                       $this->config->setCacheAndSave($this->cache);
                        $this->cache = clone $this->config->getCache();
                } catch (\Exception $e) {
                        throw new ConfigPersistenceException('Cannot save config', $e);
index 61a65c3e70ec1ada561e06c02f8d6aa7f106a017..acfac3ab9a99138f36a8210c948145a224d6ba9d 100644 (file)
@@ -55,6 +55,11 @@ class Cache
         */
        private $source = [];
 
+       /**
+        * @var bool[][]
+        */
+       private $delConfig = [];
+
        /**
         * @var bool
         */
@@ -87,10 +92,11 @@ class Cache
                                $keys = array_keys($config[$category]);
 
                                foreach ($keys as $key) {
-                                       $this->set($category, $key, $config[$category][$key] ?? null, $source);
+                                       $value = $config[$category][$key];
+                                       if (isset($value)) {
+                                               $this->set($category, $key, $value, $source);
+                                       }
                                }
-                       } else {
-                               $this->set($category, null, $config[$category], $source);
                        }
                }
        }
@@ -149,8 +155,6 @@ class Cache
                                                $data[$category][$key] = $this->config[$category][$key];
                                        }
                                }
-                       } elseif (is_int($this->source[$category])) {
-                               $data[$category] = null;
                        }
                }
 
@@ -160,47 +164,38 @@ class Cache
        /**
         * Sets a value in the config cache. Accepts raw output from the config table
         *
-        * @param string  $cat    Config category
-        * @param ?string $key    Config key
-        * @param ?mixed  $value  Value to set
-        * @param int     $source The source of the current config key
+        * @param string $cat    Config category
+        * @param string $key    Config key
+        * @param mixed  $value  Value to set
+        * @param int    $source The source of the current config key
         *
         * @return bool True, if the value is set
         */
-       public function set(string $cat, string $key = null, $value = null, int $source = self::SOURCE_DEFAULT): bool
+       public function set(string $cat, string $key, $value, int $source = self::SOURCE_DEFAULT): bool
        {
-               if (!isset($this->config[$cat]) && $key !== null) {
+               if (!isset($this->config[$cat])) {
                        $this->config[$cat] = [];
                        $this->source[$cat] = [];
                }
 
-               if ((isset($this->source[$cat][$key]) && $source < $this->source[$cat][$key]) ||
-                       (is_int($this->source[$cat] ?? null) && $source < $this->source[$cat])) {
+               if (isset($this->source[$cat][$key]) &&
+                       $source < $this->source[$cat][$key]) {
                        return false;
                }
 
                if ($this->hidePasswordOutput &&
                        $key == 'password' &&
                        is_string($value)) {
-                       $this->setCatKeyValueSource($cat, $key, new HiddenString($value), $source);
+                       $this->config[$cat][$key] = new HiddenString((string)$value);
                } else if (is_string($value)) {
-                       $this->setCatKeyValueSource($cat, $key, self::toConfigValue($value), $source);
+                       $this->config[$cat][$key] = self::toConfigValue($value);
                } else {
-                       $this->setCatKeyValueSource($cat, $key, $value, $source);
+                       $this->config[$cat][$key] = $value;
                }
 
-               return true;
-       }
+               $this->source[$cat][$key] = $source;
 
-       private function setCatKeyValueSource(string $cat, string $key = null, $value = null, int $source = self::SOURCE_DEFAULT)
-       {
-               if (isset($key)) {
-                       $this->config[$cat][$key] = $value;
-                       $this->source[$cat][$key] = $source;
-               } else {
-                       $this->config[$cat] = $value;
-                       $this->source[$cat] = $source;
-               }
+               return true;
        }
 
        /**
@@ -214,7 +209,7 @@ class Cache
         *
         * @param string|null $value
         *
-        * @return null|array|string
+        * @return mixed
         */
        public static function toConfigValue(?string $value)
        {
@@ -232,27 +227,25 @@ class Cache
        /**
         * Deletes a value from the config cache.
         *
-        * @param string  $cat Config category
-        * @param ?string $key Config key (if not set, the whole category will get deleted)
-        * @param int     $source The source of the current config key
+        * @param string $cat Config category
+        * @param string $key Config key
         *
         * @return bool true, if deleted
         */
-       public function delete(string $cat, string $key = null, int $source = self::SOURCE_DEFAULT): bool
+       public function delete(string $cat, string $key): bool
        {
                if (isset($this->config[$cat][$key])) {
-                       $this->config[$cat][$key] = null;
-                       $this->source[$cat][$key] = $source;
-                       if (empty(array_filter($this->config[$cat], function($value) { return !is_null($value); }))) {
-                               $this->config[$cat] = null;
-                               $this->source[$cat] = $source;
+                       unset($this->config[$cat][$key]);
+                       unset($this->source[$cat][$key]);
+                       $this->delConfig[$cat][$key] = true;
+                       if (count($this->config[$cat]) == 0) {
+                               unset($this->config[$cat]);
+                               unset($this->source[$cat]);
                        }
-               } elseif (isset($this->config[$cat])) {
-                       $this->config[$cat] = null;
-                       $this->source[$cat] = $source;
+                       return true;
+               } else {
+                       return false;
                }
-
-               return true;
        }
 
        /**
@@ -283,7 +276,7 @@ class Cache
                                $keys = array_keys($config[$category]);
 
                                foreach ($keys as $key) {
-                                       if (!key_exists($key, $this->config[$category] ?? [])) {
+                                       if (!isset($this->config[$category][$key])) {
                                                $return[$category][$key] = $config[$category][$key];
                                        }
                                }
@@ -326,6 +319,19 @@ class Cache
                        }
                }
 
+               $delCategories = array_keys($cache->delConfig);
+
+               foreach ($delCategories as $category) {
+                       if (is_array($cache->delConfig[$category])) {
+                               $keys = array_keys($cache->delConfig[$category]);
+
+                               foreach ($keys as $key) {
+                                       unset($newConfig[$category][$key]);
+                                       unset($newSource[$category][$key]);
+                               }
+                       }
+               }
+
                $newCache = new Cache();
                $newCache->config = $newConfig;
                $newCache->source = $newSource;
index 1145bd298321199e732d29ebdef042fe60df47e2..3167464a790da9f46d5261e2bbf5ffcbabdd3678 100644 (file)
@@ -167,7 +167,7 @@ class Hook
                                                if ($hook[0] != $fork_hook[0]) {
                                                        continue;
                                                }
-                                               self::callSingle(DI::app(), 'hook_fork', $fork_hook, $hookdata);
+                                               self::callSingle('hook_fork', $fork_hook, $hookdata);
                                        }
 
                                        if (!$hookdata['execute']) {
@@ -195,7 +195,7 @@ class Hook
        {
                if (array_key_exists($name, self::$hooks)) {
                        foreach (self::$hooks[$name] as $hook) {
-                               self::callSingle(DI::app(), $name, $hook, $data);
+                               self::callSingle($name, $hook, $data);
                        }
                }
        }
@@ -203,24 +203,23 @@ class Hook
        /**
         * Calls a single hook.
         *
-        * @param App             $a
         * @param string          $name of the hook to call
         * @param array           $hook Hook data
         * @param string|array   &$data to transmit to the callback handler
         * @return void
         * @throws \Friendica\Network\HTTPException\InternalServerErrorException
         */
-       public static function callSingle(App $a, string $name, array $hook, &$data = null)
+       public static function callSingle(string $name, array $hook, &$data = null)
        {
                // Don't run a theme's hook if the user isn't using the theme
-               if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . $a->getCurrentTheme()) === false) {
+               if (strpos($hook[0], 'view/theme/') !== false && strpos($hook[0], 'view/theme/' . DI::app()->getCurrentTheme()) === false) {
                        return;
                }
 
                @include_once($hook[0]);
                if (function_exists($hook[1])) {
                        $func = $hook[1];
-                       $func($a, $data);
+                       $func($data);
                } else {
                        // remove orphan hooks
                        $condition = ['hook' => $name, 'file' => $hook[0], 'function' => $hook[1]];
index 3870770323e53338e0b34f2b54423638d87db0b2..32ca03a62a55f481a16cad2de131fb2e0f4dd55b 100644 (file)
@@ -70,10 +70,9 @@ class Error extends BaseFactory
                System::jsonError(422, $errorObj->toArray());
        }
 
-       public function Unauthorized(string $error = '')
+       public function Unauthorized(string $error = '', string $error_description = '')
        {
                $error             = $error ?: $this->l10n->t('Unauthorized');
-               $error_description = '';
                $errorObj          = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
 
                $this->logError(401, $error);
index e30e69542071315263b8bbd68782c2960b41aedc..e847ce034666cf458ce7121363127af7f5d8eac1 100644 (file)
@@ -23,6 +23,7 @@ namespace Friendica\Model;
 
 use Friendica\Contact\Avatar;
 use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException;
+use Friendica\Content\Conversation As ConversationContent;
 use Friendica\Content\Pager;
 use Friendica\Content\Text\HTML;
 use Friendica\Core\Hook;
@@ -1609,7 +1610,7 @@ class Contact
                                }
                        }
 
-                       $o .= DI::conversation()->create($items, 'contacts', $update, false, 'pinned_commented', DI::userSession()->getLocalUserId());
+                       $o .= DI::conversation()->create($items, ConversationContent::MODE_CONTACTS, $update, false, 'pinned_commented', DI::userSession()->getLocalUserId());
                } else {
                        $fields = array_merge(Item::DISPLAY_FIELDLIST, ['featured']);
                        $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params));
@@ -1624,7 +1625,7 @@ class Contact
                                }
                        }
 
-                       $o .= DI::conversation()->create($items, 'contact-posts', $update);
+                       $o .= DI::conversation()->create($items, ConversationContent::MODE_CONTACT_POSTS, $update);
                }
 
                if (!$update) {
@@ -2251,7 +2252,9 @@ class Contact
                }
 
                if (in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) || $cache_avatar) {
-                       Avatar::deleteCache($contact);
+                       if (Avatar::deleteCache($contact)) {
+                               $force = true;
+                       }
 
                        if ($default_avatar && Proxy::isLocalImage($avatar)) {
                                $fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(),
index 4eafd28475a6b7964a9b22e29cff9ec350757753..05ff10273cb4894aaef3de85c9974df616cd4a8a 100644 (file)
@@ -623,10 +623,6 @@ class Item
                        return false;
                }
 
-               if (!empty($item['uid']) && !self::isAllowedByUser($item, $item['uid'])) {
-                       return false;
-               }
-
                if ($item['verb'] == Activity::FOLLOW) {
                        if (!$item['origin'] && ($item['author-id'] == Contact::getPublicIdByUserId($item['uid']))) {
                                // Our own follow request can be relayed to us. We don't store it to avoid notification chaos.
@@ -988,13 +984,6 @@ class Item
                                return 0;
                        }
 
-                       // If the thread originated from this node, we check the permission against the thread starter
-                       $condition = ['uri-id' => $toplevel_parent['uri-id'], 'wall' => true];
-                       $localTopLevelParent = Post::selectFirst(['uid'], $condition);
-                       if (!empty($localTopLevelParent['uid']) && !self::isAllowedByUser($item, $localTopLevelParent['uid'])) {
-                               return 0;
-                       }
-
                        $parent_id             = $toplevel_parent['id'];
                        $item['parent-uri']    = $toplevel_parent['uri'];
                        $item['parent-uri-id'] = $toplevel_parent['uri-id'];
@@ -3065,7 +3054,11 @@ class Item
                // Compile eventual content filter reasons
                $filter_reasons = [];
                if (!$is_preview && DI::userSession()->getPublicContactId() != $item['author-id']) {
-                       if (Contact\User::isCollapsed($item['author-id'], $item['uid'])) {
+                       if (!empty($item['user-blocked-author']) || !empty($item['user-blocked-owner'])) {
+                               $filter_reasons[] = DI::l10n()->t('%s is blocked', $item['author-name']);
+                       } elseif (!empty($item['user-ignored-author']) || !empty($item['user-ignored-owner'])) {
+                               $filter_reasons[] = DI::l10n()->t('%s is ignored', $item['author-name']);
+                       } elseif (!empty($item['user-collapsed-author']) || !empty($item['user-collapsed-owner'])) {
                                $filter_reasons[] = DI::l10n()->t('Content from %s is collapsed', $item['author-name']);
                        }
 
@@ -3706,53 +3699,6 @@ class Item
                return 0;
        }
 
-       /**
-        * Check a prospective item array against user-level permissions
-        *
-        * @param array $item Expected keys: uri, gravity, and
-        *                    author-link if is author-id is set,
-        *                    owner-link if is owner-id is set,
-        *                    causer-link if is causer-id is set.
-        * @param int   $user_id Local user ID
-        * @return bool
-        * @throws \Exception
-        */
-       protected static function isAllowedByUser(array $item, int $user_id): bool
-       {
-               if (!empty($item['author-id']) && Contact\User::isBlocked($item['author-id'], $user_id)) {
-                       Logger::notice('Author is blocked by user', ['author-link' => $item['author-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               if (!empty($item['owner-id']) && Contact\User::isBlocked($item['owner-id'], $user_id)) {
-                       Logger::notice('Owner is blocked by user', ['owner-link' => $item['owner-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               // The causer is set during a thread completion, for example because of a reshare. It countains the responsible actor.
-               if (!empty($item['causer-id']) && Contact\User::isBlocked($item['causer-id'], $user_id)) {
-                       Logger::notice('Causer is blocked by user', ['causer-link' => $item['causer-link'] ?? $item['causer-id'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               if (!empty($item['author-id']) && Contact\User::isIgnored($item['author-id'], $user_id)) {
-                       Logger::notice('Author is ignored by user', ['author-link' => $item['author-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               if (!empty($item['owner-id']) && Contact\User::isIgnored($item['owner-id'], $user_id)) {
-                       Logger::notice('Owner is ignored by user', ['owner-link' => $item['owner-link'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               if (!empty($item['causer-id']) && Contact\User::isIgnored($item['causer-id'], $user_id)) {
-                       Logger::notice('Causer is ignored by user', ['causer-link' => $item['causer-link'] ?? $item['causer-id'], 'uid' => $user_id, 'item-uri' => $item['uri']]);
-                       return false;
-               }
-
-               return true;
-       }
-
        /**
         * Fetch the uri-id of a quote
         *
index fd3a2d66c34717532dcfebb27d3f0fdda0681026..9aeef3bb52a66ca03fc22e5f0cc31ba0a770438a 100644 (file)
@@ -75,9 +75,7 @@ class Objects extends BaseModule
                        throw new HTTPException\NotFoundException();
                }
 
-               $owner = User::getById($item['uid'], ['hidewall']);
-
-               $validated = empty($owner['hidewall']) && in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]);
+               $validated = in_array($item['private'], [Item::PUBLIC, Item::UNLISTED]);
 
                if (!$validated) {
                        $requester = HTTPSignature::getSigner('', $_SERVER);
index f78cb07098956918042f4236477b6a1d8da8fdd2..40314a1149370ae3c2f3a5bd90485c6b6bea8a5a 100644 (file)
@@ -31,6 +31,7 @@ use Psr\Http\Message\ResponseInterface;
 
 /**
  * Apps class to register new OAuth clients
+ * @see https://docs.joinmastodon.org/methods/apps/#create
  */
 class Apps extends BaseApi
 {
@@ -44,6 +45,10 @@ class Apps extends BaseApi
         */
        protected function post(array $request = [])
        {
+               if (!empty($request['redirect_uris']) && is_array($request['redirect_uris'])) {
+                       $request['redirect_uris'] = $request['redirect_uris'][0];
+               }
+
                $request = $this->getRequest([
                        'client_name'   => '',
                        'redirect_uris' => '',
@@ -58,6 +63,10 @@ class Apps extends BaseApi
                        if (!empty($postrequest) && is_array($postrequest)) {
                                $request = array_merge($request, $postrequest);
                        }
+
+                       if (!empty($request['redirect_uris']) && is_array($request['redirect_uris'])) {
+                               $request['redirect_uris'] = $request['redirect_uris'][0];
+                       }       
                }
 
                if (empty($request['client_name']) || empty($request['redirect_uris'])) {
index 68c936927983f91b17ac9f6626375bdb3cc1daa2..3d45c7f9282b0cb07d1ffceff5fc4c6a1aa6c3d4 100644 (file)
@@ -23,11 +23,14 @@ namespace Friendica\Module\Calendar;
 
 use Friendica\App;
 use Friendica\BaseModule;
+use Friendica\Content\Feature;
 use Friendica\Core\L10n;
 use Friendica\Core\Session\Capability\IHandleUserSessions;
 use Friendica\Model\Event;
+use Friendica\Model\Profile;
 use Friendica\Model\User;
 use Friendica\Module\Response;
+use Friendica\Module\Security\Login;
 use Friendica\Navigation\SystemMessages;
 use Friendica\Network\HTTPException;
 use Friendica\Util\Profiler;
@@ -47,25 +50,39 @@ class Export extends BaseModule
        protected $session;
        /** @var SystemMessages */
        protected $sysMessages;
+       /** @var App */
+       protected $app;
 
-       public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, SystemMessages $sysMessages, array $server, array $parameters = [])
+       public function __construct(App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, IHandleUserSessions $session, SystemMessages $sysMessages, array $server, array $parameters = [])
        {
                parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
                $this->session     = $session;
                $this->sysMessages = $sysMessages;
+               $this->app         = $app;
        }
 
        protected function rawContent(array $request = [])
        {
-               if (!$this->session->getLocalUserId()) {
-                       throw new HTTPException\UnauthorizedException($this->t('Permission denied.'));
+               $nickname = $this->parameters['nickname'] ?? null;
+               if (!$nickname) {
+                       throw new HTTPException\BadRequestException();
                }
 
-               $owner = User::getByNickname($this->parameters['nickname'], ['uid']);
-               if (empty($owner)) {
+               $owner = Profile::load($this->app, $nickname, false);
+               if (!$owner || $owner['account_expired'] || $owner['account_removed']) {
                        throw new HTTPException\NotFoundException($this->t('User not found.'));
                }
+
+               if (!$this->session->isAuthenticated() && $owner['hidewall']) {
+                       $this->baseUrl->redirect('profile/' . $nickname . '/restricted');
+               }
+
+               if (!$this->session->isAuthenticated() && !Feature::isEnabled($owner['uid'], 'public_calendar')) {
+                       $this->sysMessages->addNotice($this->t('Permission denied.'));
+                       $this->baseUrl->redirect('profile/' . $nickname);
+               }
+
                $ownerUid = $owner['uid'];
                $format   = $this->parameters['format'] ?: static::DEFAULT_EXPORT;
 
index 09c319ac9d2329dffb7b20cad1513987534463cf..e5e7c2444fa431364497f5314d2d112212b5cfff 100644 (file)
@@ -64,7 +64,7 @@ class Show extends BaseModule
 
        protected function content(array $request = []): string
        {
-               $nickname = $this->parameters['nickname'] ?? $this->app->getLoggedInUserNickname();
+               $nickname = $this->parameters['nickname'] ?? $this->session->getLocalUserNickname();
                if (!$nickname) {
                        throw new HTTPException\UnauthorizedException();
                }
index 63cde443aee5e568a454de8c8004a2534640b393..818943733a905c2171e1263ffbfe96ae9fbdd670 100644 (file)
@@ -24,6 +24,7 @@ namespace Friendica\Module\Conversation;
 
 use Friendica\BaseModule;
 use Friendica\Content\BoundariesPager;
+use Friendica\Content\Conversation;
 use Friendica\Content\Feature;
 use Friendica\Content\Nav;
 use Friendica\Content\Text\HTML;
@@ -156,7 +157,7 @@ class Community extends BaseModule
                        return $o;
                }
 
-               $o .= DI::conversation()->create($items, 'community', false, false, 'commented', DI::userSession()->getLocalUserId());
+               $o .= DI::conversation()->create($items, Conversation::MODE_COMMUNITY, false, false, 'commented', DI::userSession()->getLocalUserId());
 
                $pager = new BoundariesPager(
                        DI::l10n(),
index 6670e7bb86aac3549e89c85c7693291b6a42a937..84d08ff9c2d15842fb07c01125677b3314ff22e2 100644 (file)
@@ -23,6 +23,7 @@ namespace Friendica\Module\Conversation;
 
 use Friendica\BaseModule;
 use Friendica\Content\BoundariesPager;
+use Friendica\Content\Conversation;
 use Friendica\Content\ForumManager;
 use Friendica\Content\Nav;
 use Friendica\Content\Widget;
@@ -200,7 +201,7 @@ class Network extends BaseModule
                        $ordering = '`commented`';
                }
 
-               $o .= DI::conversation()->create($items, 'network', false, false, $ordering, DI::userSession()->getLocalUserId());
+               $o .= DI::conversation()->create($items, Conversation::MODE_NETWORK, false, false, $ordering, DI::userSession()->getLocalUserId());
 
                if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) {
                        $o .= HTML::scrollLoader();
index 7b1535c413706a59e715e0d176cba6195e7df3dd..dbf91712fc07def07c36ee8c7ca6b7743f799049 100644 (file)
@@ -37,13 +37,13 @@ class Poll extends BaseModule
        {
                $owner = User::getByNickname(
                        $this->parameters['nickname'] ?? '',
-                       ['nickname', 'blocked', 'account_expired', 'account_removed', 'hidewall']
+                       ['nickname', 'blocked', 'account_expired', 'account_removed']
                );
                if (!$owner || $owner['account_expired'] || $owner['account_removed']) {
                        throw new HTTPException\NotFoundException($this->t('User not found.'));
                }
 
-               if ($owner['blocked'] || $owner['hidewall']) {
+               if ($owner['blocked']) {
                        throw new HTTPException\UnauthorizedException($this->t('Access to this profile has been restricted.'));
                }
 
index 654b8a4e9d4fcb62e99ab04aa68faa05e85a89f4..6d291198dcd09627e6fa60e984350c22ef38bc1b 100644 (file)
@@ -65,7 +65,7 @@ class Feed extends BaseModule
                        throw new HTTPException\NotFoundException($this->t('User not found.'));
                }
 
-               if ($owner['blocked'] || $owner['hidewall']) {
+               if ($owner['blocked']) {
                        throw new HTTPException\UnauthorizedException($this->t('Access to this profile has been restricted.'));
                }
 
index ad2ed6850e272e882c7bdcf61c10b618faeb8e41..a97c9db830f756903ed15ea389ddc81d6e693c20 100644 (file)
@@ -278,7 +278,7 @@ class Display extends BaseModule
                        $output .= $this->conversation->statusEditor([], 0, true);
                }
 
-               $output .= $this->conversation->create([$item], 'display', $updateUid, false, 'commented', $itemUid);
+               $output .= $this->conversation->create([$item], Conversation::MODE_DISPLAY, $updateUid, false, 'commented', $itemUid);
 
                return $output;
        }
index 1fdb57aba92553e5aad1b45d0da425198f32db17..7481bf75f538b202678d78ddef9818e4531be51a 100644 (file)
@@ -32,7 +32,7 @@ use Friendica\Util\DateTimeFormat;
 use Psr\Http\Message\ResponseInterface;
 
 /**
- * @see https://docs.joinmastodon.org/spec/oauth/
+ * @see https://docs.joinmastodon.org/methods/oauth/#token
  * @see https://aaronparecki.com/oauth-2-simplified/
  */
 class Token extends BaseApi
@@ -69,13 +69,13 @@ class Token extends BaseApi
                }
 
                if (empty($request['client_id']) || empty($request['client_secret'])) {
-                       Logger::warning('Incomplete request data', ['request' => $_REQUEST]);
-                       DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Incomplete request data'));
+                       Logger::warning('Incomplete request data', ['request' => $request]);
+                       DI::mstdnError()->Unauthorized('invalid_client', DI::l10n()->t('Incomplete request data'));
                }
 
                $application = OAuth::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']);
                if (empty($application)) {
-                       DI::mstdnError()->UnprocessableEntity();
+                       DI::mstdnError()->Unauthorized('invalid_client', DI::l10n()->t('Invalid data or unknown client'));
                }
 
                if ($request['grant_type'] == 'client_credentials') {
index 322cdc80ebcd68c090bcad5607022c163f8f5821..715bf45d3daa0b3557b58dfba919775566c5ec84 100644 (file)
@@ -240,7 +240,7 @@ class Conversations extends BaseProfile
                        $items  = array_merge($items, $pinned);
                }
 
-               $o .= $this->conversation->create($items, 'profile', false, false, 'pinned_received', $profile['uid']);
+               $o .= $this->conversation->create($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $profile['uid']);
 
                $o .= $pager->renderMinimal(count($items));
 
index 90a3c53f791eb7c00140f6e077608480c3a2face..4661a58664a8fc06f43b8ca1787fd62330d64ae0 100644 (file)
@@ -21,6 +21,7 @@
 
 namespace Friendica\Module\Search;
 
+use Friendica\Content\Conversation;
 use Friendica\Content\Nav;
 use Friendica\Content\Pager;
 use Friendica\Content\Text\HTML;
@@ -98,7 +99,7 @@ class Filed extends BaseSearch
 
                $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), Item::DISPLAY_FIELDLIST, $item_condition, $item_params));
 
-               $o .= DI::conversation()->create($items, 'filed', false, false, '', DI::userSession()->getLocalUserId());
+               $o .= DI::conversation()->create($items, Conversation::MODE_FILED, false, false, '', DI::userSession()->getLocalUserId());
 
                if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) {
                        $o .= HTML::scrollLoader();
index cd35d803a60397aef33e46316d5696412aaf75b0..d1cd5f40d3659f394471e960f851b3c599986849 100644 (file)
@@ -22,6 +22,7 @@
 namespace Friendica\Module\Search;
 
 use Friendica\App;
+use Friendica\Content\Conversation;
 use Friendica\Content\Nav;
 use Friendica\Content\Pager;
 use Friendica\Content\Text\HTML;
@@ -212,7 +213,7 @@ class Index extends BaseSearch
 
                Logger::info('Start Conversation.', ['q' => $search]);
 
-               $o .= DI::conversation()->create($items, 'search', false, false, 'commented', DI::userSession()->getLocalUserId());
+               $o .= DI::conversation()->create($items, Conversation::MODE_SEARCH, false, false, 'commented', DI::userSession()->getLocalUserId());
 
                if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) {
                        $o .= HTML::scrollLoader();
index ac2d188c0a5bae2bb0cbebdf10e9455b6ca0cae9..b6ac406ba6ebc19cc8039cf5f62f89c80fee2d13 100644 (file)
@@ -36,15 +36,12 @@ class Addons extends BaseSettings
 {
        /** @var Database */
        private $database;
-       /** @var App */
-       private $app;
 
-       public function __construct(App $app, Database $database, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
+       public function __construct(Database $database, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
        {
                parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
                $this->database = $database;
-               $this->app      = $app;
        }
 
        protected function post(array $request = [])
@@ -62,7 +59,7 @@ class Addons extends BaseSettings
                $addon_settings_forms = [];
                foreach ($this->database->selectToArray('hook', ['file', 'function'], ['hook' => 'addon_settings']) as $hook) {
                        $data = [];
-                       Hook::callSingle($this->app, 'addon_settings', [$hook['file'], $hook['function']], $data);
+                       Hook::callSingle('addon_settings', [$hook['file'], $hook['function']], $data);
 
                        if (!empty($data['href'])) {
                                $tpl                    = Renderer::getMarkupTemplate('settings/addons/link.tpl');
index 1070355bf89e59a4fbd5febf944d22cef1c92826..7c053e1681ef5e607a50b4cd39b8fc7f06413e4e 100644 (file)
@@ -49,10 +49,8 @@ class Connectors extends BaseSettings
        private $database;
        /** @var SystemMessages */
        private $systemMessages;
-       /** @var App */
-       private $app;
 
-       public function __construct(App $app, SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pconfig, IManageConfigValues $config, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
+       public function __construct(SystemMessages $systemMessages, Database $database, IManagePersonalConfigValues $pconfig, IManageConfigValues $config, IHandleUserSessions $session, App\Page $page, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = [])
        {
                parent::__construct($session, $page, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters);
 
@@ -60,7 +58,6 @@ class Connectors extends BaseSettings
                $this->pconfig        = $pconfig;
                $this->database       = $database;
                $this->systemMessages = $systemMessages;
-               $this->app            = $app;
        }
 
        protected function post(array $request = [])
@@ -146,7 +143,7 @@ class Connectors extends BaseSettings
                $connector_settings_forms = [];
                foreach ($this->database->selectToArray('hook', ['file', 'function'], ['hook' => 'connector_settings']) as $hook) {
                        $data = [];
-                       Hook::callSingle($this->app, 'connector_settings', [$hook['file'], $hook['function']], $data);
+                       Hook::callSingle('connector_settings', [$hook['file'], $hook['function']], $data);
 
                        $tpl                                          = Renderer::getMarkupTemplate('settings/addons/connector.tpl');
                        $connector_settings_forms[$data['connector']] = Renderer::replaceMacros($tpl, [
@@ -160,7 +157,7 @@ class Connectors extends BaseSettings
                        ]);
                }
 
-               if ($this->app->isSiteAdmin()) {
+               if ($this->session->isSiteAdmin()) {
                        $diasp_enabled = $this->config->get('system', 'diaspora_enabled') ?
                                $this->t('Built-in support for %s connectivity is enabled', $this->t('Diaspora (Socialhome, Hubzilla)')) :
                                $this->t('Built-in support for %s connectivity is disabled', $this->t('Diaspora (Socialhome, Hubzilla)'));
index 5b8e479fbfbbc9af06abb2c66552525266896bb2..1ac241e55aa4d006a5e13b0e850655fc48cf9d0c 100644 (file)
@@ -22,6 +22,7 @@
 
 namespace Friendica\Module\Update;
 
+use Friendica\Content\Conversation;
 use Friendica\Core\System;
 use Friendica\DI;
 use Friendica\Module\Conversation\Community as CommunityModule;
@@ -39,7 +40,7 @@ class Community extends CommunityModule
 
                $o = '';
                if (!empty($request['force'])) {
-                       $o = DI::conversation()->create(self::getItems(), 'community', true, false, 'commented', DI::userSession()->getLocalUserId());
+                       $o = DI::conversation()->create(self::getItems(), Conversation::MODE_COMMUNITY, true, false, 'commented', DI::userSession()->getLocalUserId());
                }
 
                System::htmlUpdateExit($o);
index 21196315653b02b8318e496c328863714dc79400..052ae040f066fd56396dab8aa22bd1011671cbf3 100644 (file)
@@ -21,6 +21,7 @@
 
 namespace Friendica\Module\Update;
 
+use Friendica\Content\Conversation;
 use Friendica\Core\System;
 use Friendica\DI;
 use Friendica\Model\Item;
@@ -78,7 +79,7 @@ class Network extends NetworkModule
                        $ordering = '`commented`';
                }
 
-               $o = DI::conversation()->create($items, 'network', $profile_uid, false, $ordering, DI::userSession()->getLocalUserId());
+               $o = DI::conversation()->create($items, Conversation::MODE_NETWORK, $profile_uid, false, $ordering, DI::userSession()->getLocalUserId());
 
                System::htmlUpdateExit($o);
        }
index 80d3b5189163c8575a84dfbc4c556f59b3ef1f3e..53406e195f82d9760141cce847c5a5332f5d0416 100644 (file)
@@ -22,6 +22,7 @@
 namespace Friendica\Module\Update;
 
 use Friendica\BaseModule;
+use Friendica\Content\Conversation;
 use Friendica\Core\System;
 use Friendica\Database\DBA;
 use Friendica\DI;
@@ -115,7 +116,7 @@ class Profile extends BaseModule
                        }
                }
 
-               $o .= DI::conversation()->create($items, 'profile', $a->getProfileOwner(), false, 'received', $a->getProfileOwner());
+               $o .= DI::conversation()->create($items, Conversation::MODE_PROFILE, $a->getProfileOwner(), false, 'received', $a->getProfileOwner());
 
                System::htmlUpdateExit($o);
        }
index f9f32d42229fcf88392202960adbb26e84a10059..30c4798a5a985dc1db09d4545a04f73c7009d9d5 100644 (file)
@@ -376,6 +376,7 @@ class Network
         */
        public static function addBasePath(string $url, string $basepath): string
        {
+               $url = trim($url);
                if (!empty(parse_url($url, PHP_URL_SCHEME)) || empty(parse_url($basepath, PHP_URL_SCHEME)) || empty($url) || empty(parse_url($url))) {
                        return $url;
                }
index 5df3c01b1e8d7f9fbc62d9670949c2597c2db18c..2405fbababcfdbcd8d6788f4ed28040c6b954c4f 100644 (file)
@@ -511,7 +511,7 @@ class Strings
                );
 
                if (is_null($return)) {
-                       Logger::warning('Received null value from preg_replace_callback', ['text' => $text, 'regex' => $regex, 'blocks' => $blocks, 'executionId' => $executionId, 'callstack' => System::callstack(10)]);
+                       Logger::notice('Received null value from preg_replace_callback', ['text' => $text, 'regex' => $regex, 'blocks' => $blocks, 'executionId' => $executionId, 'callstack' => System::callstack(10)]);
                }
 
                $text = $callback($return ?? $text) ?? '';
index 9e907dcfc2afc658503eda7d317f489246911542..15a9355342f8d7c3258fe46ec2fc004c8218a5d8 100644 (file)
@@ -51,7 +51,7 @@ class Expire
                        foreach (Hook::getByName('expire') as $hook) {
                                if ($hook[1] == $hook_function) {
                                        Logger::info('Calling expire hook', ['hook' => $hook[1]]);
-                                       Hook::callSingle($a, 'expire', $hook, $data);
+                                       Hook::callSingle('expire', $hook, $data);
                                }
                        }
                        return;
index da9fe990ad8b20b97a8390dbe4462cf271af8a97..406dcd171cbdb4e00ea85b9ec096bff8db05d384 100644 (file)
@@ -28,8 +28,6 @@ Class ForkHook
 {
        public static function execute($name, $hook, $data)
        {
-               $a = DI::app();
-
-               Hook::callSingle($a, $name, $hook, $data);
+               Hook::callSingle($name, $hook, $data);
        }
 }
index b3175c5d7394fd774fd8aaf970c7b12cee271ff5..a8fa44038d4ab093ad1377599e0d8f8288f976b6 100644 (file)
@@ -364,6 +364,11 @@ return [
                // If activated, all hashtags will point to the local server.
                'local_tags' => false,
 
+               // lock_driver (semaphore|database|memcache|memcached|redis|apcu)
+               // Whether to use semaphores, the database, Memcache, Memcached, Redis or APCu to handle locks.
+               // Default is auto detection which tries semaphores first, then falls back to the cache driver.
+               'lock_driver' => '',
+
                // logger_config (String)
                // Sets the logging adapter of Friendica globally (monolog, syslog, stream)
                'logger_config' => 'stream',
index 196ef4c6199a75429b9196bbe9efcc5a28503ca0..c1c2869e3eaac4e35777c649076765062d929702 100644 (file)
@@ -25,7 +25,7 @@ use Friendica\Core\L10n;
 use Friendica\Test\Util\SampleStorageBackend;
 use Mockery\MockInterface;
 
-function create_instance(App $a, &$data)
+function create_instance(&$data)
 {
        /** @var L10n|MockInterface $l10n */
        $l10n = \Mockery::mock(L10n::class);
index 7252b6653e5f71026d11194c466ad79e50b8b51d..ca46d53e4bd3f63ec80d0e3c0ede7dcda23eb012 100644 (file)
@@ -14,7 +14,7 @@ function authtest_install()
        Hook::register('authenticate', 'tests/Util/authtest/authtest.php', 'authtest_authenticate');
 }
 
-function authtest_authenticate($a,&$b)
+function authtest_authenticate(&$b)
 {
        $b['authenticated'] = \Friendica\Test\Util\AuthTestConfig::$authenticated;
        $b['user_record']   = User::getById(\Friendica\Test\Util\AuthTestConfig::$user_id);
index e14b7998c5db3f411cacffd47808b8956d7f924a..c4e536871be2c71b3b5e5bd5df837e4ebd1a2c26 100644 (file)
@@ -40,7 +40,6 @@ class CacheTest extends MockedTest
                                                'int' => 235,
                                                'dec' => 2.456,
                                                'array' => ['1', 2, '3', true, false],
-                                               'null' => null,
                                        ],
                                        'config' => [
                                                'a' => 'value',
@@ -124,7 +123,7 @@ class CacheTest extends MockedTest
 
                // wrong dataset
                $configCache->load(['system' => 'not_array']);
-               self::assertEquals(['system' => 'not_array'], $configCache->getAll());
+               self::assertEquals([], $configCache->getAll());
 
                // incomplete dataset (key is integer ID of the array)
                $configCache = new Cache();
@@ -209,16 +208,13 @@ class CacheTest extends MockedTest
        {
                $configCache = new Cache($data);
 
-               $assertion = [];
-
                foreach ($data as $cat => $values) {
-                       $assertion[$cat] = null;
                        foreach ($values as $key => $value) {
                                $configCache->delete($cat, $key);
                        }
                }
 
-               self::assertEquals($assertion, $configCache->getAll());
+               self::assertEmpty($configCache->getAll());
        }
 
        /**
@@ -554,4 +550,51 @@ class CacheTest extends MockedTest
 
                self::assertEquals('new_value', $newCache->get($category, 'new_key'));
        }
+
+       /**
+        * Test that keys are removed after a deletion
+        *
+        * @dataProvider dataTests
+        *
+        */
+       public function testDeleteRemovesKey($data)
+       {
+               $cache = new Cache();
+               $cache->load($data, Cache::SOURCE_FILE);
+
+               $cache->set('system', 'test', 'overwrite!', Cache::SOURCE_DATA);
+               self::assertEquals('overwrite!', $cache->get('system', 'test'));
+
+               // array should now be removed
+               $cache->delete('system', 'test');
+               self::assertArrayNotHasKey('test', $cache->getAll()['system']);
+
+               self::assertArrayHasKey('config', $cache->getAll());
+               self::assertArrayHasKey('a', $cache->getAll()['config']);
+
+               // category should now be removed
+               $cache->delete('config', 'a');
+               self::assertArrayNotHasKey('config', $cache->getAll());
+       }
+
+       /**
+        * Test that deleted keys are working with merge
+        *
+        * @dataProvider dataTests
+        */
+       public function testDeleteAndMergeWithDefault($data)
+       {
+               $cache = new Cache();
+               $cache->load($data, Cache::SOURCE_FILE);
+
+               $cache2 = new Cache();
+               $cache2->set('system', 'test', 'overrride');
+               $cache2->delete('system', 'test');
+
+               self::assertEquals('it', $cache->get('system', 'test'));
+               self::assertNull($cache2->get('system', 'test'));
+
+               $mergedCache = $cache->merge($cache2);
+               self::assertNull($mergedCache->get('system', 'test'));
+       }
 }
index 6c2c41ef65163f2a7a7d7c561a69dfa7dd8662d6..e5b630a200dac77ed45df3a90937faf81718c097 100644 (file)
@@ -443,7 +443,7 @@ class ConfigFileManagerTest extends MockedTest
        }
 
        /**
-        * If we delete something with the Cache::delete() functionality, be sure to override the underlying source as well
+        * If we delete something with the Cache::delete() functionality, be sure to probably reset it to the underlying key
         */
        public function testDeleteKeyOverwrite()
        {
@@ -465,51 +465,16 @@ class ConfigFileManagerTest extends MockedTest
 
                $configFileManager->setupCache($configCache);
 
-               $configCache->delete('system', 'default_timezone', Cache::SOURCE_DATA);
+               $configCache->delete('system', 'default_timezone');
 
                $configFileManager->saveData($configCache);
 
-               // assert that system.default_timezone is now null, even it's set with settings.conf.php
+               // assert that system.default_timezone is now the restored 'UTC' from the defaults
                $configCache       = new Cache();
 
                $configFileManager->setupCache($configCache);
 
-               self::assertNull($configCache->get('system', 'default_timezone'));
-       }
-
-       /**
-        * If we delete something with the Cache::delete() functionality, be sure to override the underlying source as well
-        */
-       public function testDeleteCategoryOverwrite()
-       {
-               $this->delConfigFile('node.config.php');
-
-               $fileDir = dirname(__DIR__) . DIRECTORY_SEPARATOR .
-                                  '..' . DIRECTORY_SEPARATOR .
-                                  '..' . DIRECTORY_SEPARATOR .
-                                  '..' . DIRECTORY_SEPARATOR .
-                                  'datasets' . DIRECTORY_SEPARATOR .
-                                  'config' . DIRECTORY_SEPARATOR;
-
-               vfsStream::newFile('B.config.php')
-                                ->at($this->root->getChild('config'))
-                                ->setContent(file_get_contents($fileDir . 'B.config.php'));
-
-               $configFileManager = (new Config())->createConfigFileManager($this->root->url());
-               $configCache       = new Cache();
-
-               $configFileManager->setupCache($configCache);
-
-               $configCache->delete('system');
-
-               $configFileManager->saveData($configCache);
-
-               // assert that system.default_timezone is now null, even it's set with settings.conf.php
-               $configCache       = new Cache();
-
-               $configFileManager->setupCache($configCache);
-
-               self::assertNull($configCache->get('system', 'default_timezone'));
+               self::assertEquals('UTC', $configCache->get('system', 'default_timezone'));
        }
 
        /**
index f7d7c070d3d4e5835cc1d465386bd80d5690d35f..f244044743e0c3a2ae4e86cf4a575f403f0fc947 100644 (file)
@@ -363,8 +363,6 @@ class ConfigTest extends MockedTest
                self::assertTrue($this->testedConfig->delete('test', 'it'));
                self::assertNull($this->testedConfig->get('test', 'it'));
                self::assertNull($this->testedConfig->getCache()->get('test', 'it'));
-
-               self::assertEquals(['test' => null], $this->testedConfig->getCache()->getAll());
        }
 
        /**
@@ -532,4 +530,22 @@ class ConfigTest extends MockedTest
 
                self::assertEquals($assertion, $config->get($category));
        }
+
+       /**
+        * Tests, if an overwritten value of an existing key will reset to it's default after deletion
+        */
+       public function testDeleteReturnsDefault()
+       {
+               vfsStream::newFile(ConfigFileManager::CONFIG_DATA_FILE)
+                                ->at($this->root->getChild('config'))
+                                ->setContent(ConfigFileTransformer::encode([
+                                        'config' => ['sitename' => 'overritten'],
+                                ]));
+
+               $config = $this->getInstance();
+               self::assertEquals('overritten', $config->get('config', 'sitename'));
+
+               $config->delete('config', 'sitename');
+               self::assertEquals('Friendica Social Network', $config->get('config', 'sitename'));
+       }
 }
index e0591e499d9a3b0cc192deab482e5e1333371a58..938c5665ed5ca9c43fe449577f74487429c48764 100644 (file)
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: 2023.03-dev\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2023-01-10 19:06-0500\n"
+"POT-Creation-Date: 2023-01-14 21:19+0000\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -18,34 +18,34 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 
 
-#: mod/item.php:101 mod/item.php:104 mod/item.php:170 mod/item.php:173
+#: mod/item.php:102 mod/item.php:105 mod/item.php:171 mod/item.php:174
 msgid "Unable to locate original post."
 msgstr ""
 
-#: mod/item.php:138
+#: mod/item.php:139
 msgid "Post updated."
 msgstr ""
 
-#: mod/item.php:203 mod/item.php:207
+#: mod/item.php:204 mod/item.php:208
 msgid "Item wasn't stored."
 msgstr ""
 
-#: mod/item.php:217
+#: mod/item.php:218
 msgid "Item couldn't be fetched."
 msgstr ""
 
-#: mod/item.php:255 mod/item.php:259
+#: mod/item.php:256 mod/item.php:260
 msgid "Empty post discarded."
 msgstr ""
 
-#: mod/item.php:411 src/Module/Admin/Themes/Details.php:39
+#: mod/item.php:412 src/Module/Admin/Themes/Details.php:39
 #: src/Module/Admin/Themes/Index.php:59 src/Module/Debug/ItemBody.php:42
 #: src/Module/Debug/ItemBody.php:57 src/Module/Item/Feed.php:80
 msgid "Item not found."
 msgstr ""
 
-#: mod/item.php:435 mod/message.php:69 mod/message.php:114 mod/notes.php:44
-#: mod/photos.php:158 mod/photos.php:675 src/Model/Event.php:522
+#: mod/item.php:436 mod/message.php:69 mod/message.php:114 mod/notes.php:45
+#: mod/photos.php:152 mod/photos.php:669 src/Model/Event.php:522
 #: src/Module/Attach.php:55 src/Module/BaseApi.php:95
 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52
 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84
@@ -219,7 +219,7 @@ msgstr ""
 msgid "Your password has been changed at %s"
 msgstr ""
 
-#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:322
+#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:321
 msgid "New Message"
 msgstr ""
 
@@ -245,7 +245,7 @@ msgstr ""
 msgid "Discard"
 msgstr ""
 
-#: mod/message.php:136 src/Content/Nav.php:319 view/theme/frio/theme.php:248
+#: mod/message.php:136 src/Content/Nav.php:318 view/theme/frio/theme.php:241
 msgid "Messages"
 msgstr ""
 
@@ -281,7 +281,7 @@ msgstr ""
 msgid "Your message:"
 msgstr ""
 
-#: mod/message.php:201 mod/message.php:357 src/Content/Conversation.php:342
+#: mod/message.php:201 mod/message.php:357 src/Content/Conversation.php:352
 #: src/Module/Post/Edit.php:128
 msgid "Upload photo"
 msgstr ""
@@ -291,16 +291,16 @@ msgstr ""
 msgid "Insert web link"
 msgstr ""
 
-#: mod/message.php:203 mod/message.php:360 mod/photos.php:1297
-#: src/Content/Conversation.php:371 src/Content/Conversation.php:717
+#: mod/message.php:203 mod/message.php:360 mod/photos.php:1291
+#: src/Content/Conversation.php:381 src/Content/Conversation.php:727
 #: src/Module/Item/Compose.php:204 src/Module/Post/Edit.php:142
 #: src/Module/Profile/UnkMail.php:155 src/Object/Post.php:544
 msgid "Please wait"
 msgstr ""
 
-#: mod/message.php:204 mod/message.php:359 mod/photos.php:708
-#: mod/photos.php:825 mod/photos.php:1103 mod/photos.php:1144
-#: mod/photos.php:1200 mod/photos.php:1274
+#: mod/message.php:204 mod/message.php:359 mod/photos.php:702
+#: mod/photos.php:819 mod/photos.php:1097 mod/photos.php:1138
+#: mod/photos.php:1194 mod/photos.php:1268
 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132
 #: src/Module/Contact/Profile.php:343
 #: src/Module/Debug/ActivityPubConversion.php:140
@@ -369,21 +369,21 @@ msgid_plural "%d messages"
 msgstr[0] ""
 msgstr[1] ""
 
-#: mod/notes.php:51 src/Module/BaseProfile.php:108
+#: mod/notes.php:52 src/Module/BaseProfile.php:108
 msgid "Personal Notes"
 msgstr ""
 
-#: mod/notes.php:55
+#: mod/notes.php:56
 msgid "Personal notes are visible only by yourself."
 msgstr ""
 
-#: mod/notes.php:56 src/Content/Text/HTML.php:884
+#: mod/notes.php:57 src/Content/Text/HTML.php:884
 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:74
 #: src/Module/Post/Edit.php:126
 msgid "Save"
 msgstr ""
 
-#: mod/photos.php:67 mod/photos.php:138 mod/photos.php:583
+#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:577
 #: src/Model/Event.php:514 src/Model/Profile.php:234
 #: src/Module/Calendar/Export.php:67 src/Module/Calendar/Show.php:74
 #: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51
@@ -405,90 +405,90 @@ msgstr ""
 msgid "Recent Photos"
 msgstr ""
 
-#: mod/photos.php:109 mod/photos.php:873 src/Module/Profile/Photos.php:402
+#: mod/photos.php:109 mod/photos.php:867 src/Module/Profile/Photos.php:402
 #: src/Module/Profile/Photos.php:422
 msgid "Upload New Photos"
 msgstr ""
 
-#: mod/photos.php:127 src/Module/BaseSettings.php:74
+#: mod/photos.php:121 src/Module/BaseSettings.php:74
 #: src/Module/Profile/Photos.php:383
 msgid "everybody"
 msgstr ""
 
-#: mod/photos.php:165
+#: mod/photos.php:159
 msgid "Contact information unavailable"
 msgstr ""
 
-#: mod/photos.php:194
+#: mod/photos.php:188
 msgid "Album not found."
 msgstr ""
 
-#: mod/photos.php:248
+#: mod/photos.php:242
 msgid "Album successfully deleted"
 msgstr ""
 
-#: mod/photos.php:250
+#: mod/photos.php:244
 msgid "Album was empty."
 msgstr ""
 
-#: mod/photos.php:282
+#: mod/photos.php:276
 msgid "Failed to delete the photo."
 msgstr ""
 
-#: mod/photos.php:550
+#: mod/photos.php:544
 msgid "a photo"
 msgstr ""
 
-#: mod/photos.php:550
+#: mod/photos.php:544
 #, php-format
 msgid "%1$s was tagged in %2$s by %3$s"
 msgstr ""
 
-#: mod/photos.php:587 src/Module/Conversation/Community.php:187
+#: mod/photos.php:581 src/Module/Conversation/Community.php:188
 #: src/Module/Directory.php:48 src/Module/Profile/Photos.php:315
-#: src/Module/Search/Index.php:64
+#: src/Module/Search/Index.php:65
 msgid "Public access denied."
 msgstr ""
 
-#: mod/photos.php:592
+#: mod/photos.php:586
 msgid "No photos selected"
 msgstr ""
 
-#: mod/photos.php:724
+#: mod/photos.php:718
 #, php-format
 msgid "The maximum accepted image size is %s"
 msgstr ""
 
-#: mod/photos.php:731
+#: mod/photos.php:725
 msgid "Upload Photos"
 msgstr ""
 
-#: mod/photos.php:735 mod/photos.php:821
+#: mod/photos.php:729 mod/photos.php:815
 msgid "New album name: "
 msgstr ""
 
-#: mod/photos.php:736
+#: mod/photos.php:730
 msgid "or select existing album:"
 msgstr ""
 
-#: mod/photos.php:737
+#: mod/photos.php:731
 msgid "Do not show a status post for this upload"
 msgstr ""
 
-#: mod/photos.php:739 mod/photos.php:1099 src/Content/Conversation.php:373
+#: mod/photos.php:733 mod/photos.php:1093 src/Content/Conversation.php:383
 #: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:179
 msgid "Permissions"
 msgstr ""
 
-#: mod/photos.php:802
+#: mod/photos.php:796
 msgid "Do you really want to delete this photo album and all its photos?"
 msgstr ""
 
-#: mod/photos.php:803 mod/photos.php:826
+#: mod/photos.php:797 mod/photos.php:820
 msgid "Delete Album"
 msgstr ""
 
-#: mod/photos.php:804 mod/photos.php:905 src/Content/Conversation.php:389
+#: mod/photos.php:798 mod/photos.php:899 src/Content/Conversation.php:399
 #: src/Module/Contact/Follow.php:172 src/Module/Contact/Revoke.php:109
 #: src/Module/Contact/Unfollow.php:126
 #: src/Module/Media/Attachment/Browser.php:77
@@ -498,154 +498,154 @@ msgstr ""
 msgid "Cancel"
 msgstr ""
 
-#: mod/photos.php:830
+#: mod/photos.php:824
 msgid "Edit Album"
 msgstr ""
 
-#: mod/photos.php:831
+#: mod/photos.php:825
 msgid "Drop Album"
 msgstr ""
 
-#: mod/photos.php:835
+#: mod/photos.php:829
 msgid "Show Newest First"
 msgstr ""
 
-#: mod/photos.php:837
+#: mod/photos.php:831
 msgid "Show Oldest First"
 msgstr ""
 
-#: mod/photos.php:858 src/Module/Profile/Photos.php:370
+#: mod/photos.php:852 src/Module/Profile/Photos.php:370
 msgid "View Photo"
 msgstr ""
 
-#: mod/photos.php:891
+#: mod/photos.php:885
 msgid "Permission denied. Access to this item may be restricted."
 msgstr ""
 
-#: mod/photos.php:893
+#: mod/photos.php:887
 msgid "Photo not available"
 msgstr ""
 
-#: mod/photos.php:903
+#: mod/photos.php:897
 msgid "Do you really want to delete this photo?"
 msgstr ""
 
-#: mod/photos.php:904 mod/photos.php:1104
+#: mod/photos.php:898 mod/photos.php:1098
 msgid "Delete Photo"
 msgstr ""
 
-#: mod/photos.php:1002
+#: mod/photos.php:996
 msgid "View photo"
 msgstr ""
 
-#: mod/photos.php:1004
+#: mod/photos.php:998
 msgid "Edit photo"
 msgstr ""
 
-#: mod/photos.php:1005
+#: mod/photos.php:999
 msgid "Delete photo"
 msgstr ""
 
-#: mod/photos.php:1006
+#: mod/photos.php:1000
 msgid "Use as profile photo"
 msgstr ""
 
-#: mod/photos.php:1013
+#: mod/photos.php:1007
 msgid "Private Photo"
 msgstr ""
 
-#: mod/photos.php:1019
+#: mod/photos.php:1013
 msgid "View Full Size"
 msgstr ""
 
-#: mod/photos.php:1072
+#: mod/photos.php:1066
 msgid "Tags: "
 msgstr ""
 
-#: mod/photos.php:1075
+#: mod/photos.php:1069
 msgid "[Select tags to remove]"
 msgstr ""
 
-#: mod/photos.php:1090
+#: mod/photos.php:1084
 msgid "New album name"
 msgstr ""
 
-#: mod/photos.php:1091
+#: mod/photos.php:1085
 msgid "Caption"
 msgstr ""
 
-#: mod/photos.php:1092
+#: mod/photos.php:1086
 msgid "Add a Tag"
 msgstr ""
 
-#: mod/photos.php:1092
+#: mod/photos.php:1086
 msgid "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"
 msgstr ""
 
-#: mod/photos.php:1093
+#: mod/photos.php:1087
 msgid "Do not rotate"
 msgstr ""
 
-#: mod/photos.php:1094
+#: mod/photos.php:1088
 msgid "Rotate CW (right)"
 msgstr ""
 
-#: mod/photos.php:1095
+#: mod/photos.php:1089
 msgid "Rotate CCW (left)"
 msgstr ""
 
-#: mod/photos.php:1141 mod/photos.php:1197 mod/photos.php:1271
+#: mod/photos.php:1135 mod/photos.php:1191 mod/photos.php:1265
 #: src/Module/Contact.php:589 src/Module/Item/Compose.php:188
 #: src/Object/Post.php:990
 msgid "This is you"
 msgstr ""
 
-#: mod/photos.php:1143 mod/photos.php:1199 mod/photos.php:1273
+#: mod/photos.php:1137 mod/photos.php:1193 mod/photos.php:1267
 #: src/Object/Post.php:538 src/Object/Post.php:992
 msgid "Comment"
 msgstr ""
 
-#: mod/photos.php:1145 mod/photos.php:1201 mod/photos.php:1275
-#: src/Content/Conversation.php:386 src/Module/Calendar/Event/Form.php:248
+#: mod/photos.php:1139 mod/photos.php:1195 mod/photos.php:1269
+#: src/Content/Conversation.php:396 src/Module/Calendar/Event/Form.php:248
 #: src/Module/Item/Compose.php:199 src/Module/Post/Edit.php:162
 #: src/Object/Post.php:1004
 msgid "Preview"
 msgstr ""
 
-#: mod/photos.php:1146 src/Content/Conversation.php:341
+#: mod/photos.php:1140 src/Content/Conversation.php:351
 #: src/Module/Post/Edit.php:127 src/Object/Post.php:994
 msgid "Loading..."
 msgstr ""
 
-#: mod/photos.php:1232 src/Content/Conversation.php:633 src/Object/Post.php:256
+#: mod/photos.php:1226 src/Content/Conversation.php:643 src/Object/Post.php:256
 msgid "Select"
 msgstr ""
 
-#: mod/photos.php:1233 src/Content/Conversation.php:634
+#: mod/photos.php:1227 src/Content/Conversation.php:644
 #: src/Module/Moderation/Users/Active.php:136
 #: src/Module/Moderation/Users/Blocked.php:136
 #: src/Module/Moderation/Users/Index.php:151
-#: src/Module/Settings/Connectors.php:242
+#: src/Module/Settings/Connectors.php:239
 msgid "Delete"
 msgstr ""
 
-#: mod/photos.php:1294 src/Object/Post.php:384
+#: mod/photos.php:1288 src/Object/Post.php:384
 msgid "Like"
 msgstr ""
 
-#: mod/photos.php:1295 src/Object/Post.php:384
+#: mod/photos.php:1289 src/Object/Post.php:384
 msgid "I like this (toggle)"
 msgstr ""
 
-#: mod/photos.php:1296 src/Object/Post.php:385
+#: mod/photos.php:1290 src/Object/Post.php:385
 msgid "Dislike"
 msgstr ""
 
-#: mod/photos.php:1298 src/Object/Post.php:385
+#: mod/photos.php:1292 src/Object/Post.php:385
 msgid "I don't like this (toggle)"
 msgstr ""
 
-#: mod/photos.php:1320
+#: mod/photos.php:1314
 msgid "Map"
 msgstr ""
 
@@ -657,23 +657,23 @@ msgstr ""
 msgid "Apologies but the website is unavailable at the moment."
 msgstr ""
 
-#: src/App/Page.php:247
+#: src/App/Page.php:248
 msgid "Delete this item?"
 msgstr ""
 
-#: src/App/Page.php:248
+#: src/App/Page.php:249
 msgid ""
 "Block this author? They won't be able to follow you nor see your public "
 "posts, and you won't be able to see their posts and their notifications."
 msgstr ""
 
-#: src/App/Page.php:249
+#: src/App/Page.php:250
 msgid ""
 "Ignore this author? You won't be able to see their posts and their "
 "notifications."
 msgstr ""
 
-#: src/App/Page.php:319
+#: src/App/Page.php:320
 msgid "toggle mobile"
 msgstr ""
 
@@ -1040,355 +1040,355 @@ msgstr ""
 msgid "%s (via %s)"
 msgstr ""
 
-#: src/Content/Conversation.php:210
+#: src/Content/Conversation.php:220
 #, php-format
 msgid "%s likes this."
 msgstr ""
 
-#: src/Content/Conversation.php:213
+#: src/Content/Conversation.php:223
 #, php-format
 msgid "%s doesn't like this."
 msgstr ""
 
-#: src/Content/Conversation.php:216
+#: src/Content/Conversation.php:226
 #, php-format
 msgid "%s attends."
 msgstr ""
 
-#: src/Content/Conversation.php:219
+#: src/Content/Conversation.php:229
 #, php-format
 msgid "%s doesn't attend."
 msgstr ""
 
-#: src/Content/Conversation.php:222
+#: src/Content/Conversation.php:232
 #, php-format
 msgid "%s attends maybe."
 msgstr ""
 
-#: src/Content/Conversation.php:225 src/Content/Conversation.php:263
-#: src/Content/Conversation.php:877
+#: src/Content/Conversation.php:235 src/Content/Conversation.php:273
+#: src/Content/Conversation.php:887
 #, php-format
 msgid "%s reshared this."
 msgstr ""
 
-#: src/Content/Conversation.php:231
+#: src/Content/Conversation.php:241
 msgid "and"
 msgstr ""
 
-#: src/Content/Conversation.php:234
+#: src/Content/Conversation.php:244
 #, php-format
 msgid "and %d other people"
 msgstr ""
 
-#: src/Content/Conversation.php:242
+#: src/Content/Conversation.php:252
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> like this"
 msgstr ""
 
-#: src/Content/Conversation.php:243
+#: src/Content/Conversation.php:253
 #, php-format
 msgid "%s like this."
 msgstr ""
 
-#: src/Content/Conversation.php:246
+#: src/Content/Conversation.php:256
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> don't like this"
 msgstr ""
 
-#: src/Content/Conversation.php:247
+#: src/Content/Conversation.php:257
 #, php-format
 msgid "%s don't like this."
 msgstr ""
 
-#: src/Content/Conversation.php:250
+#: src/Content/Conversation.php:260
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> attend"
 msgstr ""
 
-#: src/Content/Conversation.php:251
+#: src/Content/Conversation.php:261
 #, php-format
 msgid "%s attend."
 msgstr ""
 
-#: src/Content/Conversation.php:254
+#: src/Content/Conversation.php:264
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> don't attend"
 msgstr ""
 
-#: src/Content/Conversation.php:255
+#: src/Content/Conversation.php:265
 #, php-format
 msgid "%s don't attend."
 msgstr ""
 
-#: src/Content/Conversation.php:258
+#: src/Content/Conversation.php:268
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> attend maybe"
 msgstr ""
 
-#: src/Content/Conversation.php:259
+#: src/Content/Conversation.php:269
 #, php-format
 msgid "%s attend maybe."
 msgstr ""
 
-#: src/Content/Conversation.php:262
+#: src/Content/Conversation.php:272
 #, php-format
 msgid "<button type=\"button\" %1$s>%2$d people</button> reshared this"
 msgstr ""
 
-#: src/Content/Conversation.php:310
+#: src/Content/Conversation.php:320
 msgid "Visible to <strong>everybody</strong>"
 msgstr ""
 
-#: src/Content/Conversation.php:311 src/Module/Item/Compose.php:198
+#: src/Content/Conversation.php:321 src/Module/Item/Compose.php:198
 #: src/Object/Post.php:1003
 msgid "Please enter a image/video/audio/webpage URL:"
 msgstr ""
 
-#: src/Content/Conversation.php:312
+#: src/Content/Conversation.php:322
 msgid "Tag term:"
 msgstr ""
 
-#: src/Content/Conversation.php:313 src/Module/Filer/SaveTag.php:73
+#: src/Content/Conversation.php:323 src/Module/Filer/SaveTag.php:73
 msgid "Save to Folder:"
 msgstr ""
 
-#: src/Content/Conversation.php:314
+#: src/Content/Conversation.php:324
 msgid "Where are you right now?"
 msgstr ""
 
-#: src/Content/Conversation.php:315
+#: src/Content/Conversation.php:325
 msgid "Delete item(s)?"
 msgstr ""
 
-#: src/Content/Conversation.php:327 src/Module/Item/Compose.php:175
+#: src/Content/Conversation.php:337 src/Module/Item/Compose.php:175
 msgid "Created at"
 msgstr ""
 
-#: src/Content/Conversation.php:337
+#: src/Content/Conversation.php:347
 msgid "New Post"
 msgstr ""
 
-#: src/Content/Conversation.php:340
+#: src/Content/Conversation.php:350
 msgid "Share"
 msgstr ""
 
-#: src/Content/Conversation.php:343 src/Module/Post/Edit.php:129
+#: src/Content/Conversation.php:353 src/Module/Post/Edit.php:129
 msgid "upload photo"
 msgstr ""
 
-#: src/Content/Conversation.php:344 src/Module/Post/Edit.php:130
+#: src/Content/Conversation.php:354 src/Module/Post/Edit.php:130
 msgid "Attach file"
 msgstr ""
 
-#: src/Content/Conversation.php:345 src/Module/Post/Edit.php:131
+#: src/Content/Conversation.php:355 src/Module/Post/Edit.php:131
 msgid "attach file"
 msgstr ""
 
-#: src/Content/Conversation.php:346 src/Module/Item/Compose.php:190
+#: src/Content/Conversation.php:356 src/Module/Item/Compose.php:190
 #: src/Module/Post/Edit.php:168 src/Object/Post.php:995
 msgid "Bold"
 msgstr ""
 
-#: src/Content/Conversation.php:347 src/Module/Item/Compose.php:191
+#: src/Content/Conversation.php:357 src/Module/Item/Compose.php:191
 #: src/Module/Post/Edit.php:169 src/Object/Post.php:996
 msgid "Italic"
 msgstr ""
 
-#: src/Content/Conversation.php:348 src/Module/Item/Compose.php:192
+#: src/Content/Conversation.php:358 src/Module/Item/Compose.php:192
 #: src/Module/Post/Edit.php:170 src/Object/Post.php:997
 msgid "Underline"
 msgstr ""
 
-#: src/Content/Conversation.php:349 src/Module/Item/Compose.php:193
+#: src/Content/Conversation.php:359 src/Module/Item/Compose.php:193
 #: src/Module/Post/Edit.php:171 src/Object/Post.php:998
 msgid "Quote"
 msgstr ""
 
-#: src/Content/Conversation.php:350 src/Module/Item/Compose.php:194
+#: src/Content/Conversation.php:360 src/Module/Item/Compose.php:194
 #: src/Module/Post/Edit.php:172 src/Object/Post.php:999
 msgid "Code"
 msgstr ""
 
-#: src/Content/Conversation.php:351 src/Module/Item/Compose.php:195
+#: src/Content/Conversation.php:361 src/Module/Item/Compose.php:195
 #: src/Object/Post.php:1000
 msgid "Image"
 msgstr ""
 
-#: src/Content/Conversation.php:352 src/Module/Item/Compose.php:196
+#: src/Content/Conversation.php:362 src/Module/Item/Compose.php:196
 #: src/Module/Post/Edit.php:173 src/Object/Post.php:1001
 msgid "Link"
 msgstr ""
 
-#: src/Content/Conversation.php:353 src/Module/Item/Compose.php:197
+#: src/Content/Conversation.php:363 src/Module/Item/Compose.php:197
 #: src/Module/Post/Edit.php:174 src/Object/Post.php:1002
 msgid "Link or Media"
 msgstr ""
 
-#: src/Content/Conversation.php:354
+#: src/Content/Conversation.php:364
 msgid "Video"
 msgstr ""
 
-#: src/Content/Conversation.php:355 src/Module/Item/Compose.php:200
+#: src/Content/Conversation.php:365 src/Module/Item/Compose.php:200
 #: src/Module/Post/Edit.php:138
 msgid "Set your location"
 msgstr ""
 
-#: src/Content/Conversation.php:356 src/Module/Post/Edit.php:139
+#: src/Content/Conversation.php:366 src/Module/Post/Edit.php:139
 msgid "set location"
 msgstr ""
 
-#: src/Content/Conversation.php:357 src/Module/Post/Edit.php:140
+#: src/Content/Conversation.php:367 src/Module/Post/Edit.php:140
 msgid "Clear browser location"
 msgstr ""
 
-#: src/Content/Conversation.php:358 src/Module/Post/Edit.php:141
+#: src/Content/Conversation.php:368 src/Module/Post/Edit.php:141
 msgid "clear location"
 msgstr ""
 
-#: src/Content/Conversation.php:360 src/Module/Item/Compose.php:205
+#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:205
 #: src/Module/Post/Edit.php:154
 msgid "Set title"
 msgstr ""
 
-#: src/Content/Conversation.php:362 src/Module/Item/Compose.php:206
+#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:206
 #: src/Module/Post/Edit.php:156
 msgid "Categories (comma-separated list)"
 msgstr ""
 
-#: src/Content/Conversation.php:367 src/Module/Item/Compose.php:222
+#: src/Content/Conversation.php:377 src/Module/Item/Compose.php:222
 msgid "Scheduled at"
 msgstr ""
 
-#: src/Content/Conversation.php:372 src/Module/Post/Edit.php:143
+#: src/Content/Conversation.php:382 src/Module/Post/Edit.php:143
 msgid "Permission settings"
 msgstr ""
 
-#: src/Content/Conversation.php:382 src/Module/Post/Edit.php:152
+#: src/Content/Conversation.php:392 src/Module/Post/Edit.php:152
 msgid "Public post"
 msgstr ""
 
-#: src/Content/Conversation.php:396 src/Content/Widget/VCard.php:113
+#: src/Content/Conversation.php:406 src/Content/Widget/VCard.php:113
 #: src/Model/Profile.php:469 src/Module/Admin/Logs/View.php:93
 #: src/Module/Post/Edit.php:177
 msgid "Message"
 msgstr ""
 
-#: src/Content/Conversation.php:397 src/Module/Post/Edit.php:178
+#: src/Content/Conversation.php:407 src/Module/Post/Edit.php:178
 #: src/Module/Settings/TwoFactor/Trusted.php:140
 msgid "Browser"
 msgstr ""
 
-#: src/Content/Conversation.php:399 src/Module/Post/Edit.php:181
+#: src/Content/Conversation.php:409 src/Module/Post/Edit.php:181
 msgid "Open Compose page"
 msgstr ""
 
-#: src/Content/Conversation.php:661 src/Object/Post.php:243
+#: src/Content/Conversation.php:671 src/Object/Post.php:243
 msgid "Pinned item"
 msgstr ""
 
-#: src/Content/Conversation.php:677 src/Object/Post.php:491
+#: src/Content/Conversation.php:687 src/Object/Post.php:491
 #: src/Object/Post.php:492
 #, php-format
 msgid "View %s's profile @ %s"
 msgstr ""
 
-#: src/Content/Conversation.php:690 src/Object/Post.php:479
+#: src/Content/Conversation.php:700 src/Object/Post.php:479
 msgid "Categories:"
 msgstr ""
 
-#: src/Content/Conversation.php:691 src/Object/Post.php:480
+#: src/Content/Conversation.php:701 src/Object/Post.php:480
 msgid "Filed under:"
 msgstr ""
 
-#: src/Content/Conversation.php:699 src/Object/Post.php:505
+#: src/Content/Conversation.php:709 src/Object/Post.php:505
 #, php-format
 msgid "%s from %s"
 msgstr ""
 
-#: src/Content/Conversation.php:715
+#: src/Content/Conversation.php:725
 msgid "View in context"
 msgstr ""
 
-#: src/Content/Conversation.php:780
+#: src/Content/Conversation.php:790
 msgid "remove"
 msgstr ""
 
-#: src/Content/Conversation.php:784
+#: src/Content/Conversation.php:794
 msgid "Delete Selected Items"
 msgstr ""
 
-#: src/Content/Conversation.php:849 src/Content/Conversation.php:852
-#: src/Content/Conversation.php:855 src/Content/Conversation.php:858
+#: src/Content/Conversation.php:859 src/Content/Conversation.php:862
+#: src/Content/Conversation.php:865 src/Content/Conversation.php:868
 #, php-format
 msgid "You had been addressed (%s)."
 msgstr ""
 
-#: src/Content/Conversation.php:861
+#: src/Content/Conversation.php:871
 #, php-format
 msgid "You are following %s."
 msgstr ""
 
-#: src/Content/Conversation.php:864
+#: src/Content/Conversation.php:874
 msgid "You subscribed to one or more tags in this post."
 msgstr ""
 
-#: src/Content/Conversation.php:879
+#: src/Content/Conversation.php:889
 msgid "Reshared"
 msgstr ""
 
-#: src/Content/Conversation.php:879
+#: src/Content/Conversation.php:889
 #, php-format
 msgid "Reshared by %s <%s>"
 msgstr ""
 
-#: src/Content/Conversation.php:882
+#: src/Content/Conversation.php:892
 #, php-format
 msgid "%s is participating in this thread."
 msgstr ""
 
-#: src/Content/Conversation.php:885
+#: src/Content/Conversation.php:895
 msgid "Stored for general reasons"
 msgstr ""
 
-#: src/Content/Conversation.php:888
+#: src/Content/Conversation.php:898
 msgid "Global post"
 msgstr ""
 
-#: src/Content/Conversation.php:891
+#: src/Content/Conversation.php:901
 msgid "Sent via an relay server"
 msgstr ""
 
-#: src/Content/Conversation.php:891
+#: src/Content/Conversation.php:901
 #, php-format
 msgid "Sent via the relay server %s <%s>"
 msgstr ""
 
-#: src/Content/Conversation.php:894
+#: src/Content/Conversation.php:904
 msgid "Fetched"
 msgstr ""
 
-#: src/Content/Conversation.php:894
+#: src/Content/Conversation.php:904
 #, php-format
 msgid "Fetched because of %s <%s>"
 msgstr ""
 
-#: src/Content/Conversation.php:897
+#: src/Content/Conversation.php:907
 msgid "Stored because of a child post to complete this thread."
 msgstr ""
 
-#: src/Content/Conversation.php:900
+#: src/Content/Conversation.php:910
 msgid "Local delivery"
 msgstr ""
 
-#: src/Content/Conversation.php:903
+#: src/Content/Conversation.php:913
 msgid "Stored because of your activity (like, comment, star, ...)"
 msgstr ""
 
-#: src/Content/Conversation.php:906
+#: src/Content/Conversation.php:916
 msgid "Distributed"
 msgstr ""
 
-#: src/Content/Conversation.php:909
+#: src/Content/Conversation.php:919
 msgid "Pushed to us"
 msgstr ""
 
@@ -1504,7 +1504,7 @@ msgid ""
 "Contact birthday events are private to you."
 msgstr ""
 
-#: src/Content/ForumManager.php:151 src/Content/Nav.php:279
+#: src/Content/ForumManager.php:151 src/Content/Nav.php:278
 #: src/Content/Text/HTML.php:905 src/Content/Widget.php:524
 msgid "Forums"
 msgstr ""
@@ -1522,7 +1522,7 @@ msgstr ""
 msgid "show more"
 msgstr ""
 
-#: src/Content/Item.php:326 src/Model/Item.php:2910
+#: src/Content/Item.php:326 src/Model/Item.php:2899
 msgid "event"
 msgstr ""
 
@@ -1530,7 +1530,7 @@ msgstr ""
 msgid "status"
 msgstr ""
 
-#: src/Content/Item.php:335 src/Model/Item.php:2912
+#: src/Content/Item.php:335 src/Model/Item.php:2901
 #: src/Module/Post/Tag/Add.php:123
 msgid "photo"
 msgstr ""
@@ -1540,35 +1540,35 @@ msgstr ""
 msgid "%1$s tagged %2$s's %3$s with %4$s"
 msgstr ""
 
-#: src/Content/Item.php:419 view/theme/frio/theme.php:269
+#: src/Content/Item.php:419 view/theme/frio/theme.php:262
 msgid "Follow Thread"
 msgstr ""
 
-#: src/Content/Item.php:420 src/Model/Contact.php:1205
+#: src/Content/Item.php:420 src/Model/Contact.php:1206
 msgid "View Status"
 msgstr ""
 
-#: src/Content/Item.php:421 src/Content/Item.php:440 src/Model/Contact.php:1149
-#: src/Model/Contact.php:1197 src/Model/Contact.php:1206
+#: src/Content/Item.php:421 src/Content/Item.php:440 src/Model/Contact.php:1150
+#: src/Model/Contact.php:1198 src/Model/Contact.php:1207
 #: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:234
 msgid "View Profile"
 msgstr ""
 
-#: src/Content/Item.php:422 src/Model/Contact.php:1207
+#: src/Content/Item.php:422 src/Model/Contact.php:1208
 msgid "View Photos"
 msgstr ""
 
-#: src/Content/Item.php:423 src/Model/Contact.php:1198
-#: src/Model/Contact.php:1208
+#: src/Content/Item.php:423 src/Model/Contact.php:1199
+#: src/Model/Contact.php:1209
 msgid "Network Posts"
 msgstr ""
 
-#: src/Content/Item.php:424 src/Model/Contact.php:1199
-#: src/Model/Contact.php:1209
+#: src/Content/Item.php:424 src/Model/Contact.php:1200
+#: src/Model/Contact.php:1210
 msgid "View Contact"
 msgstr ""
 
-#: src/Content/Item.php:425 src/Model/Contact.php:1210
+#: src/Content/Item.php:425 src/Model/Contact.php:1211
 msgid "Send PM"
 msgstr ""
 
@@ -1598,7 +1598,7 @@ msgid "Languages"
 msgstr ""
 
 #: src/Content/Item.php:437 src/Content/Widget.php:80
-#: src/Model/Contact.php:1200 src/Model/Contact.php:1211
+#: src/Model/Contact.php:1201 src/Model/Contact.php:1212
 #: src/Module/Contact/Follow.php:166 view/theme/vier/theme.php:196
 msgid "Connect/Follow"
 msgstr ""
@@ -1607,116 +1607,116 @@ msgstr ""
 msgid "Unable to fetch user."
 msgstr ""
 
-#: src/Content/Nav.php:121
+#: src/Content/Nav.php:120
 msgid "Nothing new here"
 msgstr ""
 
-#: src/Content/Nav.php:125 src/Module/Special/HTTPException.php:77
+#: src/Content/Nav.php:124 src/Module/Special/HTTPException.php:77
 msgid "Go back"
 msgstr ""
 
-#: src/Content/Nav.php:126
+#: src/Content/Nav.php:125
 msgid "Clear notifications"
 msgstr ""
 
-#: src/Content/Nav.php:127 src/Content/Text/HTML.php:892
+#: src/Content/Nav.php:126 src/Content/Text/HTML.php:892
 msgid "@name, !forum, #tags, content"
 msgstr ""
 
-#: src/Content/Nav.php:223 src/Module/Security/Login.php:158
+#: src/Content/Nav.php:222 src/Module/Security/Login.php:158
 msgid "Logout"
 msgstr ""
 
-#: src/Content/Nav.php:223
+#: src/Content/Nav.php:222
 msgid "End this session"
 msgstr ""
 
-#: src/Content/Nav.php:225 src/Module/Bookmarklet.php:44
+#: src/Content/Nav.php:224 src/Module/Bookmarklet.php:44
 #: src/Module/Security/Login.php:159
 msgid "Login"
 msgstr ""
 
-#: src/Content/Nav.php:225
+#: src/Content/Nav.php:224
 msgid "Sign in"
 msgstr ""
 
-#: src/Content/Nav.php:230 src/Module/BaseProfile.php:57
+#: src/Content/Nav.php:229 src/Module/BaseProfile.php:57
 #: src/Module/Contact.php:484
 msgid "Conversations"
 msgstr ""
 
-#: src/Content/Nav.php:230
+#: src/Content/Nav.php:229
 msgid "Conversations you started"
 msgstr ""
 
-#: src/Content/Nav.php:231 src/Module/BaseProfile.php:49
+#: src/Content/Nav.php:230 src/Module/BaseProfile.php:49
 #: src/Module/BaseSettings.php:100 src/Module/Contact.php:476
 #: src/Module/Contact/Profile.php:399 src/Module/Profile/Profile.php:268
-#: src/Module/Welcome.php:57 view/theme/frio/theme.php:237
+#: src/Module/Welcome.php:57 view/theme/frio/theme.php:230
 msgid "Profile"
 msgstr ""
 
-#: src/Content/Nav.php:231 view/theme/frio/theme.php:237
+#: src/Content/Nav.php:230 view/theme/frio/theme.php:230
 msgid "Your profile page"
 msgstr ""
 
-#: src/Content/Nav.php:232 src/Module/BaseProfile.php:65
-#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:241
+#: src/Content/Nav.php:231 src/Module/BaseProfile.php:65
+#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:234
 msgid "Photos"
 msgstr ""
 
-#: src/Content/Nav.php:232 view/theme/frio/theme.php:241
+#: src/Content/Nav.php:231 view/theme/frio/theme.php:234
 msgid "Your photos"
 msgstr ""
 
-#: src/Content/Nav.php:233 src/Module/BaseProfile.php:73
+#: src/Content/Nav.php:232 src/Module/BaseProfile.php:73
 #: src/Module/BaseProfile.php:76 src/Module/Contact.php:500
-#: view/theme/frio/theme.php:242
+#: view/theme/frio/theme.php:235
 msgid "Media"
 msgstr ""
 
-#: src/Content/Nav.php:233 view/theme/frio/theme.php:242
+#: src/Content/Nav.php:232 view/theme/frio/theme.php:235
 msgid "Your postings with media"
 msgstr ""
 
-#: src/Content/Nav.php:234 src/Content/Nav.php:294
+#: src/Content/Nav.php:233 src/Content/Nav.php:293
 #: src/Module/BaseProfile.php:85 src/Module/BaseProfile.php:88
 #: src/Module/BaseProfile.php:96 src/Module/BaseProfile.php:99
-#: src/Module/Settings/Display.php:252 view/theme/frio/theme.php:243
-#: view/theme/frio/theme.php:247
+#: src/Module/Settings/Display.php:252 view/theme/frio/theme.php:236
+#: view/theme/frio/theme.php:240
 msgid "Calendar"
 msgstr ""
 
-#: src/Content/Nav.php:234 view/theme/frio/theme.php:243
+#: src/Content/Nav.php:233 view/theme/frio/theme.php:236
 msgid "Your calendar"
 msgstr ""
 
-#: src/Content/Nav.php:235
+#: src/Content/Nav.php:234
 msgid "Personal notes"
 msgstr ""
 
-#: src/Content/Nav.php:235
+#: src/Content/Nav.php:234
 msgid "Your personal notes"
 msgstr ""
 
-#: src/Content/Nav.php:252 src/Content/Nav.php:309
+#: src/Content/Nav.php:251 src/Content/Nav.php:308
 msgid "Home"
 msgstr ""
 
-#: src/Content/Nav.php:252 src/Module/Settings/OAuth.php:74
+#: src/Content/Nav.php:251 src/Module/Settings/OAuth.php:74
 msgid "Home Page"
 msgstr ""
 
-#: src/Content/Nav.php:256 src/Module/Register.php:168
+#: src/Content/Nav.php:255 src/Module/Register.php:168
 #: src/Module/Security/Login.php:124
 msgid "Register"
 msgstr ""
 
-#: src/Content/Nav.php:256
+#: src/Content/Nav.php:255
 msgid "Create an account"
 msgstr ""
 
-#: src/Content/Nav.php:262 src/Module/Help.php:67
+#: src/Content/Nav.php:261 src/Module/Help.php:67
 #: src/Module/Settings/TwoFactor/AppSpecific.php:129
 #: src/Module/Settings/TwoFactor/Index.php:118
 #: src/Module/Settings/TwoFactor/Recovery.php:107
@@ -1724,158 +1724,158 @@ msgstr ""
 msgid "Help"
 msgstr ""
 
-#: src/Content/Nav.php:262
+#: src/Content/Nav.php:261
 msgid "Help and documentation"
 msgstr ""
 
-#: src/Content/Nav.php:266
+#: src/Content/Nav.php:265
 msgid "Apps"
 msgstr ""
 
-#: src/Content/Nav.php:266
+#: src/Content/Nav.php:265
 msgid "Addon applications, utilities, games"
 msgstr ""
 
-#: src/Content/Nav.php:270 src/Content/Text/HTML.php:890
-#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:111
+#: src/Content/Nav.php:269 src/Content/Text/HTML.php:890
+#: src/Module/Admin/Logs/View.php:87 src/Module/Search/Index.php:112
 msgid "Search"
 msgstr ""
 
-#: src/Content/Nav.php:270
+#: src/Content/Nav.php:269
 msgid "Search site content"
 msgstr ""
 
-#: src/Content/Nav.php:273 src/Content/Text/HTML.php:899
+#: src/Content/Nav.php:272 src/Content/Text/HTML.php:899
 msgid "Full Text"
 msgstr ""
 
-#: src/Content/Nav.php:274 src/Content/Text/HTML.php:900
+#: src/Content/Nav.php:273 src/Content/Text/HTML.php:900
 #: src/Content/Widget/TagCloud.php:68
 msgid "Tags"
 msgstr ""
 
-#: src/Content/Nav.php:275 src/Content/Nav.php:330
+#: src/Content/Nav.php:274 src/Content/Nav.php:329
 #: src/Content/Text/HTML.php:901 src/Module/BaseProfile.php:127
 #: src/Module/BaseProfile.php:130 src/Module/Contact.php:411
-#: src/Module/Contact.php:507 view/theme/frio/theme.php:250
+#: src/Module/Contact.php:507 view/theme/frio/theme.php:243
 msgid "Contacts"
 msgstr ""
 
-#: src/Content/Nav.php:290
+#: src/Content/Nav.php:289
 msgid "Community"
 msgstr ""
 
-#: src/Content/Nav.php:290
+#: src/Content/Nav.php:289
 msgid "Conversations on this and other servers"
 msgstr ""
 
-#: src/Content/Nav.php:297
+#: src/Content/Nav.php:296
 msgid "Directory"
 msgstr ""
 
-#: src/Content/Nav.php:297
+#: src/Content/Nav.php:296
 msgid "People directory"
 msgstr ""
 
-#: src/Content/Nav.php:299 src/Module/BaseAdmin.php:85
+#: src/Content/Nav.php:298 src/Module/BaseAdmin.php:85
 #: src/Module/BaseModeration.php:108
 msgid "Information"
 msgstr ""
 
-#: src/Content/Nav.php:299
+#: src/Content/Nav.php:298
 msgid "Information about this friendica instance"
 msgstr ""
 
-#: src/Content/Nav.php:302 src/Module/Admin/Tos.php:78
+#: src/Content/Nav.php:301 src/Module/Admin/Tos.php:78
 #: src/Module/BaseAdmin.php:95 src/Module/Register.php:176
 #: src/Module/Tos.php:100
 msgid "Terms of Service"
 msgstr ""
 
-#: src/Content/Nav.php:302
+#: src/Content/Nav.php:301
 msgid "Terms of Service of this Friendica instance"
 msgstr ""
 
-#: src/Content/Nav.php:307 view/theme/frio/theme.php:246
+#: src/Content/Nav.php:306 view/theme/frio/theme.php:239
 msgid "Network"
 msgstr ""
 
-#: src/Content/Nav.php:307 view/theme/frio/theme.php:246
+#: src/Content/Nav.php:306 view/theme/frio/theme.php:239
 msgid "Conversations from your friends"
 msgstr ""
 
-#: src/Content/Nav.php:309 view/theme/frio/theme.php:236
+#: src/Content/Nav.php:308 view/theme/frio/theme.php:229
 msgid "Your posts and conversations"
 msgstr ""
 
-#: src/Content/Nav.php:313
+#: src/Content/Nav.php:312
 msgid "Introductions"
 msgstr ""
 
-#: src/Content/Nav.php:313
+#: src/Content/Nav.php:312
 msgid "Friend Requests"
 msgstr ""
 
-#: src/Content/Nav.php:314 src/Module/BaseNotifications.php:149
+#: src/Content/Nav.php:313 src/Module/BaseNotifications.php:149
 #: src/Module/Notifications/Introductions.php:75
 msgid "Notifications"
 msgstr ""
 
-#: src/Content/Nav.php:315
+#: src/Content/Nav.php:314
 msgid "See all notifications"
 msgstr ""
 
-#: src/Content/Nav.php:316 src/Module/Settings/Connectors.php:242
+#: src/Content/Nav.php:315 src/Module/Settings/Connectors.php:239
 msgid "Mark as seen"
 msgstr ""
 
-#: src/Content/Nav.php:316
+#: src/Content/Nav.php:315
 msgid "Mark all system notifications as seen"
 msgstr ""
 
-#: src/Content/Nav.php:319 view/theme/frio/theme.php:248
+#: src/Content/Nav.php:318 view/theme/frio/theme.php:241
 msgid "Private mail"
 msgstr ""
 
-#: src/Content/Nav.php:320
+#: src/Content/Nav.php:319
 msgid "Inbox"
 msgstr ""
 
-#: src/Content/Nav.php:321
+#: src/Content/Nav.php:320
 msgid "Outbox"
 msgstr ""
 
-#: src/Content/Nav.php:325
+#: src/Content/Nav.php:324
 msgid "Accounts"
 msgstr ""
 
-#: src/Content/Nav.php:325
+#: src/Content/Nav.php:324
 msgid "Manage other pages"
 msgstr ""
 
-#: src/Content/Nav.php:328 src/Module/Admin/Addons/Details.php:114
+#: src/Content/Nav.php:327 src/Module/Admin/Addons/Details.php:114
 #: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:170
-#: src/Module/Welcome.php:52 view/theme/frio/theme.php:249
+#: src/Module/Welcome.php:52 view/theme/frio/theme.php:242
 msgid "Settings"
 msgstr ""
 
-#: src/Content/Nav.php:328 view/theme/frio/theme.php:249
+#: src/Content/Nav.php:327 view/theme/frio/theme.php:242
 msgid "Account settings"
 msgstr ""
 
-#: src/Content/Nav.php:330 view/theme/frio/theme.php:250
+#: src/Content/Nav.php:329 view/theme/frio/theme.php:243
 msgid "Manage/edit friends and contacts"
 msgstr ""
 
-#: src/Content/Nav.php:335 src/Module/BaseAdmin.php:119
+#: src/Content/Nav.php:334 src/Module/BaseAdmin.php:119
 msgid "Admin"
 msgstr ""
 
-#: src/Content/Nav.php:335
+#: src/Content/Nav.php:334
 msgid "Site setup and configuration"
 msgstr ""
 
-#: src/Content/Nav.php:336 src/Module/BaseModeration.php:127
+#: src/Content/Nav.php:335 src/Module/BaseModeration.php:127
 #: src/Module/Moderation/Blocklist/Contact.php:110
 #: src/Module/Moderation/Blocklist/Server/Add.php:119
 #: src/Module/Moderation/Blocklist/Server/Import.php:115
@@ -1889,15 +1889,15 @@ msgstr ""
 msgid "Moderation"
 msgstr ""
 
-#: src/Content/Nav.php:336
+#: src/Content/Nav.php:335
 msgid "Content and user moderation"
 msgstr ""
 
-#: src/Content/Nav.php:339
+#: src/Content/Nav.php:338
 msgid "Navigation"
 msgstr ""
 
-#: src/Content/Nav.php:339
+#: src/Content/Nav.php:338
 msgid "Site map"
 msgstr ""
 
@@ -1936,8 +1936,8 @@ msgid ""
 "<a href=\"%1$s\" target=\"_blank\" rel=\"noopener noreferrer\">%2$s</a> %3$s"
 msgstr ""
 
-#: src/Content/Text/BBCode.php:1257 src/Model/Item.php:3579
-#: src/Model/Item.php:3585 src/Model/Item.php:3586
+#: src/Content/Text/BBCode.php:1257 src/Model/Item.php:3572
+#: src/Model/Item.php:3578 src/Model/Item.php:3579
 msgid "Link to source"
 msgstr ""
 
@@ -2097,7 +2097,7 @@ msgstr ""
 msgid "Organisations"
 msgstr ""
 
-#: src/Content/Widget.php:523 src/Model/Contact.php:1657
+#: src/Content/Widget.php:523 src/Model/Contact.php:1658
 msgid "News"
 msgstr ""
 
@@ -2178,8 +2178,8 @@ msgstr ""
 msgid "Network:"
 msgstr ""
 
-#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1201
-#: src/Model/Contact.php:1212 src/Model/Profile.php:465
+#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1202
+#: src/Model/Contact.php:1213 src/Model/Profile.php:465
 #: src/Module/Contact/Profile.php:436
 msgid "Unfollow"
 msgstr ""
@@ -2868,12 +2868,12 @@ msgstr ""
 msgid "Unauthorized"
 msgstr ""
 
-#: src/Factory/Api/Mastodon/Error.php:85
+#: src/Factory/Api/Mastodon/Error.php:84
 msgid ""
 "Token is not authorized with a valid user or is missing a required scope"
 msgstr ""
 
-#: src/Factory/Api/Mastodon/Error.php:95
+#: src/Factory/Api/Mastodon/Error.php:94
 msgid "Internal Server Error"
 msgstr ""
 
@@ -2882,82 +2882,82 @@ msgstr ""
 msgid "Legacy module file not found: %s"
 msgstr ""
 
-#: src/Model/Contact.php:1218 src/Module/Moderation/Users/Pending.php:102
+#: src/Model/Contact.php:1219 src/Module/Moderation/Users/Pending.php:102
 #: src/Module/Notifications/Introductions.php:132
 #: src/Module/Notifications/Introductions.php:204
 msgid "Approve"
 msgstr ""
 
-#: src/Model/Contact.php:1653
+#: src/Model/Contact.php:1654
 msgid "Organisation"
 msgstr ""
 
-#: src/Model/Contact.php:1661
+#: src/Model/Contact.php:1662
 msgid "Forum"
 msgstr ""
 
-#: src/Model/Contact.php:2928
+#: src/Model/Contact.php:2931
 msgid "Disallowed profile URL."
 msgstr ""
 
-#: src/Model/Contact.php:2933 src/Module/Friendica.php:83
+#: src/Model/Contact.php:2936 src/Module/Friendica.php:83
 msgid "Blocked domain"
 msgstr ""
 
-#: src/Model/Contact.php:2938
+#: src/Model/Contact.php:2941
 msgid "Connect URL missing."
 msgstr ""
 
-#: src/Model/Contact.php:2947
+#: src/Model/Contact.php:2950
 msgid ""
 "The contact could not be added. Please check the relevant network "
 "credentials in your Settings -> Social Networks page."
 msgstr ""
 
-#: src/Model/Contact.php:2965
+#: src/Model/Contact.php:2968
 #, php-format
 msgid "Expected network %s does not match actual network %s"
 msgstr ""
 
-#: src/Model/Contact.php:2982
+#: src/Model/Contact.php:2985
 msgid "The profile address specified does not provide adequate information."
 msgstr ""
 
-#: src/Model/Contact.php:2984
+#: src/Model/Contact.php:2987
 msgid "No compatible communication protocols or feeds were discovered."
 msgstr ""
 
-#: src/Model/Contact.php:2987
+#: src/Model/Contact.php:2990
 msgid "An author or name was not found."
 msgstr ""
 
-#: src/Model/Contact.php:2990
+#: src/Model/Contact.php:2993
 msgid "No browser URL could be matched to this address."
 msgstr ""
 
-#: src/Model/Contact.php:2993
+#: src/Model/Contact.php:2996
 msgid ""
 "Unable to match @-style Identity Address with a known protocol or email "
 "contact."
 msgstr ""
 
-#: src/Model/Contact.php:2994
+#: src/Model/Contact.php:2997
 msgid "Use mailto: in front of address to force email check."
 msgstr ""
 
-#: src/Model/Contact.php:3000
+#: src/Model/Contact.php:3003
 msgid ""
 "The profile address specified belongs to a network which has been disabled "
 "on this site."
 msgstr ""
 
-#: src/Model/Contact.php:3005
+#: src/Model/Contact.php:3008
 msgid ""
 "Limited profile. This person will be unable to receive direct/personal "
 "notifications from you."
 msgstr ""
 
-#: src/Model/Contact.php:3070
+#: src/Model/Contact.php:3073
 msgid "Unable to retrieve contact information."
 msgstr ""
 
@@ -3008,7 +3008,7 @@ msgid "No events to display"
 msgstr ""
 
 #: src/Model/Event.php:518 src/Module/DFRN/Poll.php:47 src/Module/Feed.php:69
-#: src/Module/Update/Profile.php:55
+#: src/Module/Update/Profile.php:56
 msgid "Access to this profile has been restricted."
 msgstr ""
 
@@ -3106,71 +3106,81 @@ msgstr ""
 msgid "Edit groups"
 msgstr ""
 
-#: src/Model/Item.php:2011
+#: src/Model/Item.php:2000
 #, php-format
 msgid "Detected languages in this post:\\n%s"
 msgstr ""
 
-#: src/Model/Item.php:2914
+#: src/Model/Item.php:2903
 msgid "activity"
 msgstr ""
 
-#: src/Model/Item.php:2916
+#: src/Model/Item.php:2905
 msgid "comment"
 msgstr ""
 
-#: src/Model/Item.php:2919 src/Module/Post/Tag/Add.php:123
+#: src/Model/Item.php:2908 src/Module/Post/Tag/Add.php:123
 msgid "post"
 msgstr ""
 
-#: src/Model/Item.php:3069
+#: src/Model/Item.php:3058
+#, php-format
+msgid "%s is blocked"
+msgstr ""
+
+#: src/Model/Item.php:3060
+#, php-format
+msgid "%s is ignored"
+msgstr ""
+
+#: src/Model/Item.php:3062
 #, php-format
 msgid "Content from %s is collapsed"
 msgstr ""
 
-#: src/Model/Item.php:3073
+#: src/Model/Item.php:3066
 #, php-format
 msgid "Content warning: %s"
 msgstr ""
 
-#: src/Model/Item.php:3491
+#: src/Model/Item.php:3484
 msgid "bytes"
 msgstr ""
 
-#: src/Model/Item.php:3522
+#: src/Model/Item.php:3515
 #, php-format
 msgid "%2$s (%3$d%%, %1$d vote)"
 msgid_plural "%2$s (%3$d%%, %1$d votes)"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/Model/Item.php:3524
+#: src/Model/Item.php:3517
 #, php-format
 msgid "%2$s (%1$d vote)"
 msgid_plural "%2$s (%1$d votes)"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/Model/Item.php:3529
+#: src/Model/Item.php:3522
 #, php-format
 msgid "%d voter. Poll end: %s"
 msgid_plural "%d voters. Poll end: %s"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/Model/Item.php:3531
+#: src/Model/Item.php:3524
 #, php-format
 msgid "%d voter."
 msgid_plural "%d voters."
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/Model/Item.php:3533
+#: src/Model/Item.php:3526
 #, php-format
 msgid "Poll end: %s"
 msgstr ""
 
-#: src/Model/Item.php:3567 src/Model/Item.php:3568
+#: src/Model/Item.php:3560 src/Model/Item.php:3561
 msgid "View on separate page"
 msgstr ""
 
@@ -3653,9 +3663,9 @@ msgstr ""
 #: src/Module/Admin/Addons/Index.php:69 src/Module/Admin/Features.php:87
 #: src/Module/Admin/Logs/Settings.php:81 src/Module/Admin/Site.php:438
 #: src/Module/Admin/Themes/Index.php:113 src/Module/Admin/Tos.php:86
-#: src/Module/Settings/Account.php:560 src/Module/Settings/Addons.php:81
-#: src/Module/Settings/Connectors.php:159
-#: src/Module/Settings/Connectors.php:244
+#: src/Module/Settings/Account.php:560 src/Module/Settings/Addons.php:78
+#: src/Module/Settings/Connectors.php:156
+#: src/Module/Settings/Connectors.php:241
 #: src/Module/Settings/Delegation.php:169 src/Module/Settings/Display.php:247
 #: src/Module/Settings/Features.php:76
 msgid "Save Settings"
@@ -5243,7 +5253,7 @@ msgstr ""
 msgid "API endpoint %s %s is not implemented but might be in the future."
 msgstr ""
 
-#: src/Module/Api/Mastodon/Apps.php:64
+#: src/Module/Api/Mastodon/Apps.php:73
 msgid "Missing parameters"
 msgstr ""
 
@@ -5467,7 +5477,7 @@ msgstr ""
 msgid "Display"
 msgstr ""
 
-#: src/Module/BaseSettings.php:127 src/Module/Settings/Connectors.php:203
+#: src/Module/BaseSettings.php:127 src/Module/Settings/Connectors.php:200
 msgid "Social Networks"
 msgstr ""
 
@@ -5677,7 +5687,7 @@ msgstr ""
 msgid "Search your contacts"
 msgstr ""
 
-#: src/Module/Contact.php:432 src/Module/Search/Index.php:206
+#: src/Module/Contact.php:432 src/Module/Search/Index.php:207
 #, php-format
 msgid "Results for: %s"
 msgstr ""
@@ -5805,7 +5815,7 @@ msgstr ""
 msgid "New photo from this URL"
 msgstr ""
 
-#: src/Module/Contact/Contacts.php:66 src/Module/Conversation/Network.php:188
+#: src/Module/Contact/Contacts.php:66 src/Module/Conversation/Network.php:189
 #: src/Module/Group.php:101
 msgid "Invalid contact."
 msgstr ""
@@ -5866,7 +5876,7 @@ msgstr[0] ""
 msgstr[1] ""
 
 #: src/Module/Contact/Follow.php:69 src/Module/Contact/Redir.php:62
-#: src/Module/Contact/Redir.php:222 src/Module/Conversation/Community.php:193
+#: src/Module/Contact/Redir.php:222 src/Module/Conversation/Community.php:194
 #: src/Module/Debug/ItemBody.php:38 src/Module/Diaspora/Receive.php:57
 #: src/Module/Item/Display.php:95 src/Module/Item/Feed.php:59
 #: src/Module/Item/Follow.php:41 src/Module/Item/Ignore.php:41
@@ -6158,7 +6168,7 @@ msgid "Actions"
 msgstr ""
 
 #: src/Module/Contact/Profile.php:397
-#: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:236
+#: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229
 msgid "Status"
 msgstr ""
 
@@ -6255,100 +6265,100 @@ msgstr ""
 msgid "Unable to unfollow this contact, please contact your administrator"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:73
+#: src/Module/Conversation/Community.php:74
 msgid ""
 "This community stream shows all public posts received by this node. They may "
 "not reflect the opinions of this node’s users."
 msgstr ""
 
-#: src/Module/Conversation/Community.php:86
+#: src/Module/Conversation/Community.php:87
 msgid "Local Community"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:89
+#: src/Module/Conversation/Community.php:90
 msgid "Posts from local users on this server"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:97
+#: src/Module/Conversation/Community.php:98
 msgid "Global Community"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:100
+#: src/Module/Conversation/Community.php:101
 msgid "Posts from users of the whole federated network"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:133
+#: src/Module/Conversation/Community.php:134
 msgid "Own Contacts"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:137
+#: src/Module/Conversation/Community.php:138
 msgid "Include"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:138
+#: src/Module/Conversation/Community.php:139
 msgid "Hide"
 msgstr ""
 
-#: src/Module/Conversation/Community.php:155 src/Module/Search/Index.php:151
-#: src/Module/Search/Index.php:193
+#: src/Module/Conversation/Community.php:156 src/Module/Search/Index.php:152
+#: src/Module/Search/Index.php:194
 msgid "No results."
 msgstr ""
 
-#: src/Module/Conversation/Community.php:211
+#: src/Module/Conversation/Community.php:212
 msgid "Community option not available."
 msgstr ""
 
-#: src/Module/Conversation/Community.php:227
+#: src/Module/Conversation/Community.php:228
 msgid "Not available."
 msgstr ""
 
-#: src/Module/Conversation/Network.php:174
+#: src/Module/Conversation/Network.php:175
 msgid "No such group"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:178
+#: src/Module/Conversation/Network.php:179
 #, php-format
 msgid "Group: %s"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:256
+#: src/Module/Conversation/Network.php:257
 msgid "Latest Activity"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:259
+#: src/Module/Conversation/Network.php:260
 msgid "Sort by latest activity"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:264
+#: src/Module/Conversation/Network.php:265
 msgid "Latest Posts"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:267
+#: src/Module/Conversation/Network.php:268
 msgid "Sort by post received date"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:272
+#: src/Module/Conversation/Network.php:273
 msgid "Latest Creation"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:275
+#: src/Module/Conversation/Network.php:276
 msgid "Sort by post creation date"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:280
+#: src/Module/Conversation/Network.php:281
 #: src/Module/Settings/Profile/Index.php:236
 msgid "Personal"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:283
+#: src/Module/Conversation/Network.php:284
 msgid "Posts that mention or involve you"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:288 src/Object/Post.php:356
+#: src/Module/Conversation/Network.php:289 src/Object/Post.php:356
 msgid "Starred"
 msgstr ""
 
-#: src/Module/Conversation/Network.php:291
+#: src/Module/Conversation/Network.php:292
 msgid "Favourite Posts"
 msgstr ""
 
@@ -8072,6 +8082,10 @@ msgid ""
 "close this window: %s"
 msgstr ""
 
+#: src/Module/OAuth/Token.php:78
+msgid "Invalid data or unknown client"
+msgstr ""
+
 #: src/Module/OAuth/Token.php:97
 msgid "Unsupported or missing grant type"
 msgstr ""
@@ -8615,15 +8629,15 @@ msgstr ""
 msgid "You must be logged in to use this module."
 msgstr ""
 
-#: src/Module/Search/Index.php:68
+#: src/Module/Search/Index.php:69
 msgid "Only logged in users are permitted to perform a search."
 msgstr ""
 
-#: src/Module/Search/Index.php:88
+#: src/Module/Search/Index.php:89
 msgid "Only one search per minute is permitted for not logged in users."
 msgstr ""
 
-#: src/Module/Search/Index.php:204
+#: src/Module/Search/Index.php:205
 #, php-format
 msgid "Items tagged with: %s"
 msgstr ""
@@ -9346,81 +9360,81 @@ msgstr ""
 msgid "Resend relocate message to contacts"
 msgstr ""
 
-#: src/Module/Settings/Addons.php:89
+#: src/Module/Settings/Addons.php:86
 msgid "Addon Settings"
 msgstr ""
 
-#: src/Module/Settings/Addons.php:90
+#: src/Module/Settings/Addons.php:87
 msgid "No Addon settings configured"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:121
+#: src/Module/Settings/Connectors.php:118
 msgid "Failed to connect with email account using the settings provided."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:165
-#: src/Module/Settings/Connectors.php:166
+#: src/Module/Settings/Connectors.php:162
+#: src/Module/Settings/Connectors.php:163
 msgid "Diaspora (Socialhome, Hubzilla)"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:165
-#: src/Module/Settings/Connectors.php:169
+#: src/Module/Settings/Connectors.php:162
+#: src/Module/Settings/Connectors.php:166
 #, php-format
 msgid "Built-in support for %s connectivity is enabled"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:166
-#: src/Module/Settings/Connectors.php:168
+#: src/Module/Settings/Connectors.php:163
+#: src/Module/Settings/Connectors.php:165
 #, php-format
 msgid "Built-in support for %s connectivity is disabled"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:168
-#: src/Module/Settings/Connectors.php:169
+#: src/Module/Settings/Connectors.php:165
+#: src/Module/Settings/Connectors.php:166
 msgid "OStatus (GNU Social)"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:181
+#: src/Module/Settings/Connectors.php:178
 msgid "Email access is disabled on this site."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:196
-#: src/Module/Settings/Connectors.php:242
+#: src/Module/Settings/Connectors.php:193
+#: src/Module/Settings/Connectors.php:239
 msgid "None"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:208
+#: src/Module/Settings/Connectors.php:205
 msgid "General Social Media Settings"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:211
+#: src/Module/Settings/Connectors.php:208
 msgid "Followed content scope"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:213
+#: src/Module/Settings/Connectors.php:210
 msgid ""
 "By default, conversations in which your follows participated but didn't "
 "start will be shown in your timeline. You can turn this behavior off, or "
 "expand it to the conversations in which your follows liked a post."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:215
+#: src/Module/Settings/Connectors.php:212
 msgid "Only conversations my follows started"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:216
+#: src/Module/Settings/Connectors.php:213
 msgid "Conversations my follows started or commented on (default)"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:217
+#: src/Module/Settings/Connectors.php:214
 msgid "Any conversation my follows interacted with, including likes"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:220
+#: src/Module/Settings/Connectors.php:217
 msgid "Enable Content Warning"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:220
+#: src/Module/Settings/Connectors.php:217
 msgid ""
 "Users on networks like Mastodon or Pleroma are able to set a content warning "
 "field which collapse their post by default. This enables the automatic "
@@ -9428,104 +9442,104 @@ msgid ""
 "affect any other content filtering you eventually set up."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:221
+#: src/Module/Settings/Connectors.php:218
 msgid "Enable intelligent shortening"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:221
+#: src/Module/Settings/Connectors.php:218
 msgid ""
 "Normally the system tries to find the best link to add to shortened posts. "
 "If disabled, every shortened post will always point to the original "
 "friendica post."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:222
+#: src/Module/Settings/Connectors.php:219
 msgid "Enable simple text shortening"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:222
+#: src/Module/Settings/Connectors.php:219
 msgid ""
 "Normally the system shortens posts at the next line feed. If this option is "
 "enabled then the system will shorten the text at the maximum character limit."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:223
+#: src/Module/Settings/Connectors.php:220
 msgid "Attach the link title"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:223
+#: src/Module/Settings/Connectors.php:220
 msgid ""
 "When activated, the title of the attached link will be added as a title on "
 "posts to Diaspora. This is mostly helpful with \"remote-self\" contacts that "
 "share feed content."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:224
+#: src/Module/Settings/Connectors.php:221
 msgid "Your legacy ActivityPub/GNU Social account"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:224
+#: src/Module/Settings/Connectors.php:221
 msgid ""
 "If you enter your old account name from an ActivityPub based system or your "
 "GNU Social/Statusnet account name here (in the format user@domain.tld), your "
 "contacts will be added automatically. The field will be emptied when done."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:227
+#: src/Module/Settings/Connectors.php:224
 msgid "Repair OStatus subscriptions"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:231
+#: src/Module/Settings/Connectors.php:228
 msgid "Email/Mailbox Setup"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:232
+#: src/Module/Settings/Connectors.php:229
 msgid ""
 "If you wish to communicate with email contacts using this service "
 "(optional), please specify how to connect to your mailbox."
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:233
+#: src/Module/Settings/Connectors.php:230
 msgid "Last successful email check:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:235
+#: src/Module/Settings/Connectors.php:232
 msgid "IMAP server name:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:236
+#: src/Module/Settings/Connectors.php:233
 msgid "IMAP port:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:237
+#: src/Module/Settings/Connectors.php:234
 msgid "Security:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:238
+#: src/Module/Settings/Connectors.php:235
 msgid "Email login name:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:239
+#: src/Module/Settings/Connectors.php:236
 msgid "Email password:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:240
+#: src/Module/Settings/Connectors.php:237
 msgid "Reply-to address:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:241
+#: src/Module/Settings/Connectors.php:238
 msgid "Send public posts to all email contacts:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:242
+#: src/Module/Settings/Connectors.php:239
 msgid "Action after import:"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:242
+#: src/Module/Settings/Connectors.php:239
 msgid "Move to folder"
 msgstr ""
 
-#: src/Module/Settings/Connectors.php:243
+#: src/Module/Settings/Connectors.php:240
 msgid "Move to folder:"
 msgstr ""
 
@@ -11649,11 +11663,11 @@ msgstr ""
 msgid "Back to top"
 msgstr ""
 
-#: view/theme/frio/theme.php:218
+#: view/theme/frio/theme.php:211
 msgid "Guest"
 msgstr ""
 
-#: view/theme/frio/theme.php:221
+#: view/theme/frio/theme.php:214
 msgid "Visitor"
 msgstr ""
 
index 336b52993546461697d1deb4515725370966ed2a..c6092393bdab5989bd93e2ce9785b2e166258f2b 100644 (file)
@@ -77,7 +77,7 @@ $is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser";
 ?>
        </head>
 
-       <body id="top" class="mod-<?php echo DI::args()->getModuleName() . " " . $is_singleuser_class . " " . $view_mode_class;?>">
+       <body id="top" class="mod-<?php echo $page['module'] . " " . $is_singleuser_class . " " . $view_mode_class;?>">
                <a href="#content" class="sr-only sr-only-focusable"><?php echo DI::l10n()->t('Skip to main content'); ?></a>
 <?php
        if (!empty($page['nav']) && !$minimal) {
@@ -125,7 +125,7 @@ $is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser";
 
                                        <div class="col-lg-7 col-md-7 col-sm-12 col-xs-12" id="content">
                                                <section class="sectiontop ';
-                                                       echo DI::args()->get(0, 'generic');
+                                                       echo $page['section'] ?? '';
                                                        echo '-content-wrapper">';
                                                        if (!empty($page['content'])) {
                                                                echo $page['content'];
index 253a55ec477f3c88d8dbde3cdc1df73394298cb4..05e45163faca1bd81f56525e880de21d518a2efe 100644 (file)
 
 use Friendica\App;
 use Friendica\Content\Text\Plaintext;
-use Friendica\Content\Widget;
 use Friendica\Core\Hook;
 use Friendica\Core\Logger;
 use Friendica\Core\Renderer;
 use Friendica\Database\DBA;
 use Friendica\DI;
-use Friendica\Model;
-use Friendica\Model\Item;
 use Friendica\Model\Contact;
+use Friendica\Model\Item;
 use Friendica\Model\Profile;
-use Friendica\Module;
-use Friendica\Util\Strings;
 
 const FRIO_SCHEME_ACCENT_BLUE   = '#1e87c2';
 const FRIO_SCHEME_ACCENT_RED    = '#b50404';
@@ -89,10 +85,9 @@ function frio_install()
  *  to the photo file. This function is nessesary to use colorbox
  *  in the network stream
  *
- * @param App $a Unused but required by hook definition
  * @param array $body_info The item and its html output
  */
-function frio_item_photo_links(App $a, &$body_info)
+function frio_item_photo_links(&$body_info)
 {
        $occurence = 0;
        $p = Plaintext::getBoundariesPosition($body_info['html'], '<a', '>');
@@ -125,10 +120,9 @@ function frio_item_photo_links(App $a, &$body_info)
  *  to call the addToModal javascript function so this pages can
  *  be loaded in a bootstrap modal
  *
- * @param App $a Unused but required by the hook definition
  * @param array $arr Contains item data and the original photo_menu
  */
-function frio_item_photo_menu(App $a, &$arr)
+function frio_item_photo_menu(&$arr)
 {
        foreach ($arr['menu'] as $k => $v) {
                if (strpos($v, 'message/new/') === 0) {
@@ -147,10 +141,9 @@ function frio_item_photo_menu(App $a, &$arr)
  *  Additionally the profile, status and photo page links  will be changed
  *  to don't open in a new tab if the contact is a friendica contact.
  *
- * @param App $a The app data
  * @param array $args Contains contact data and the original photo_menu
  */
-function frio_contact_photo_menu(App $a, &$args)
+function frio_contact_photo_menu(&$args)
 {
        $cid = $args['contact']['id'];
 
@@ -199,7 +192,7 @@ function frio_contact_photo_menu(App $a, &$args)
  * @param array $nav_info The original nav info array: nav, banner, userinfo, sitelocation
  * @throws Exception
  */
-function frio_remote_nav(App $a, array &$nav_info)
+function frio_remote_nav(array &$nav_info)
 {
        if (DI::mode()->has(App\Mode::MAINTENANCEDISABLED)) {
                // get the homelink from $_SESSION
@@ -211,8 +204,8 @@ function frio_remote_nav(App $a, array &$nav_info)
                // since $userinfo isn't available for the hook we write it to the nav array
                // this isn't optimal because the contact query will be done now twice
                $fields = ['id', 'url', 'avatar', 'micro', 'name', 'nick', 'baseurl', 'updated'];
-               if ($a->isLoggedIn()) {
-                       $remoteUser = Contact::selectFirst($fields, ['uid' => $a->getLoggedInUserId(), 'self' => true]);
+               if (DI::userSession()->isAuthenticated()) {
+                       $remoteUser = Contact::selectFirst($fields, ['uid' => DI::userSession()->getLocalUserId(), 'self' => true]);
                } elseif (!DI::userSession()->getLocalUserId() && DI::userSession()->getRemoteUserId()) {
                        $remoteUser                = Contact::getById(DI::userSession()->getRemoteUserId(), $fields);
                        $nav_info['nav']['remote'] = DI::l10n()->t('Guest');
@@ -253,7 +246,7 @@ function frio_remote_nav(App $a, array &$nav_info)
        }
 }
 
-function frio_display_item(App $a, &$arr)
+function frio_display_item(&$arr)
 {
        // Add follow to the item menu
        $followThread = [];