diff --git a/.gitignore b/.gitignore index 3db593f1d..2889d12b5 100644 --- a/.gitignore +++ b/.gitignore @@ -19,7 +19,7 @@ robots.txt /doc/cache #ignore reports, should be generated with every build -report/ +/report/ #ignore config files from eclipse, we don't want IDE files in our repository .project @@ -33,7 +33,7 @@ report/ #ignore NetBeans IDE's private files (at least) /nbproject/private/ -Ignore config files from VSCode +#Ignore config files from VSCode /.vscode/ #ignore smarty cache diff --git a/.woodpecker/.code_standards_check.yml b/.woodpecker/.code_standards_check.yml index f81ab960f..0c951d701 100644 --- a/.woodpecker/.code_standards_check.yml +++ b/.woodpecker/.code_standards_check.yml @@ -1,4 +1,4 @@ -pipeline: +steps: restore_cache: image: meltwater/drone-cache:dev settings: diff --git a/.woodpecker/.continuous-deployment.yml b/.woodpecker/.continuous-deployment.yml index 767fffde3..4ff956b3b 100644 --- a/.woodpecker/.continuous-deployment.yml +++ b/.woodpecker/.continuous-deployment.yml @@ -11,11 +11,11 @@ labels: skip_clone: true -pipeline: +steps: clone: image: alpine/git commands: - - git clone $CI_REPO_LINK . + - git clone $CI_REPO_CLONE_URL . - git checkout $CI_COMMIT_BRANCH - git fetch origin $CI_COMMIT_REF - git merge $CI_COMMIT_SHA diff --git a/.woodpecker/.database_checks.yml b/.woodpecker/.database_checks.yml index 04bdeed62..7d2553674 100644 --- a/.woodpecker/.database_checks.yml +++ b/.woodpecker/.database_checks.yml @@ -6,7 +6,11 @@ matrix: branches: exclude: [ stable ] -pipeline: +# This forces CI executions at the "opensocial" labeled location (because of much more power...) +labels: + location: opensocial + +steps: db_version_match: image: friendicaci/transifex commands: diff --git a/.woodpecker/.license_check.yml b/.woodpecker/.license_check.yml index 777986544..e7545f5f4 100644 --- a/.woodpecker/.license_check.yml +++ b/.woodpecker/.license_check.yml @@ -1,4 +1,4 @@ -pipeline: +steps: check: image: friendicaci/php-cs commands: diff --git a/.woodpecker/.messages.po_check.yml b/.woodpecker/.messages.po_check.yml index c5b283e1d..9c2509594 100644 --- a/.woodpecker/.messages.po_check.yml +++ b/.woodpecker/.messages.po_check.yml @@ -1,4 +1,4 @@ -pipeline: +steps: build_xgettext: image: friendicaci/transifex commands: @@ -9,4 +9,4 @@ pipeline: - /check-messages.sh branches: - exclude: [ stable ] \ No newline at end of file + exclude: [ stable ] diff --git a/.woodpecker/.phpunit.yml b/.woodpecker/.phpunit.yml index aee7fd384..302bd911d 100644 --- a/.woodpecker/.phpunit.yml +++ b/.woodpecker/.phpunit.yml @@ -5,20 +5,22 @@ matrix: - PHP_MAJOR_VERSION: 7.4 PHP_VERSION: 7.4.33 - PHP_MAJOR_VERSION: 8.0 - PHP_VERSION: 8.0.25 + PHP_VERSION: 8.0.29 - PHP_MAJOR_VERSION: 8.1 - PHP_VERSION: 8.1.12 + PHP_VERSION: 8.1.21 + - PHP_MAJOR_VERSION: 8.2 + PHP_VERSION: 8.2.8 # This forces PHP Unit executions at the "opensocial" labeled location (because of much more power...) labels: location: opensocial -pipeline: +steps: php-lint: image: php:${PHP_MAJOR_VERSION} group: lint commands: - - ./bin/composer.phar run lint + - find . -name \*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l restore_cache: image: meltwater/drone-cache:dev settings: diff --git a/.woodpecker/.releaser.yml b/.woodpecker/.releaser.yml index 482ea5429..006bcfec3 100644 --- a/.woodpecker/.releaser.yml +++ b/.woodpecker/.releaser.yml @@ -9,11 +9,11 @@ labels: skip_clone: true -pipeline: +steps: clone: image: alpine/git commands: - - git clone $CI_REPO_LINK . + - git clone $CI_REPO_CLONE_URL . - git checkout $CI_COMMIT_BRANCH - git fetch origin $CI_COMMIT_REF - git merge $CI_COMMIT_SHA diff --git a/CHANGELOG b/CHANGELOG index 25db7dfa3..94b2f067a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +Version 2023.09 (unreleased) + Friendica Core + + Friendica Addons + + Closed Issues + Version 2023.05 (2023-05-23) Friendica Core Updates to the translations HU, PL diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 76009424b..4ffdb9197 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,5 +1,5 @@ # How to Contribute -If you want to contribute to the project, you don’t need to have coding experience. There are a number of tasks listed in the issue tracker with the label “[Junior Jobs](https://github.com/friendica/friendica/issues?q=is%3Aopen+is%3Aissue+label%3A%22Junior+Jobs%22)” we think are good for new contributors. But you are by no means limited to these – if you find a solution to a problem (even a new one) please make a pull request at [github](https://github.com/friendica/friendica) or let us know in the [development forum](https://forum.friendi.ca/profile/developers). +If you want to contribute to the project, you don’t need to have coding experience. There are a number of tasks listed in the issue tracker with the label “[Junior Jobs](https://github.com/friendica/friendica/issues?q=is%3Aopen+is%3Aissue+label%3A%22Junior+Jobs%22)” we think are good for new contributors. But you are by no means limited to these – if you find a solution to a problem (even a new one) please make a pull request at [github](https://github.com/friendica/friendica) or let us know in the [development group](https://forum.friendi.ca/profile/developers). Contribution to Friendica is also not limited to coding. Any contribution to the [documentation](https://github.com/friendica/friendica/tree/develop/doc), the [translation](https://app.transifex.com/Friendica/friendica/dashboard/) or advertisement materials is welcome or reporting a problem. You don’t need to deal with Git(Hub) or Transifex if you don’t like to. Just [get in touch](https://forum.friendi.ca/profile/helpers) with us and we will get the materials to the appropriate places. diff --git a/README.md b/README.md index cbd801b5d..a57df5a21 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,11 @@ +# friendica_2020-09-1_sharedHosting by bitPickup + +## trying to create a fork of 2020.09-1 by adding this text directly to the readme.md +### the -> settings: "merge commit" -> "allow edits by mantainers by default" was enabled to do this editing inside the fork +#### the tag was set to 2020-09-1 inside the /friendica/friendica fork +##### setting "commit directly to the [develop] branch" was seleted for this commit + +====================================== Friendica Social Communications Server ====================================== @@ -17,29 +25,29 @@ Have a look at the [installation documentation](doc/Install.md) for further info ### Friendica Screenshots -| ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-2.png?raw=true "Frio theme in mobile browser") -|:--:| -|*Frio theme, mobile browser. Timeline and composer view.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-1.png?raw=true "Frio theme in desktop browser") -|*Frio theme, desktop browser. Timeline view, contact info popped up, control menu open.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-2.png?raw=true "Frio theme in desktop browser") -|*Frio theme, desktop browser. Menu open for controlling individual posts.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-3.png?raw=true "Frio theme in desktop browser") -|*Frio theme, desktop browser. Profile view, notification menu open.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-2.png?raw=true "Frio theme in desktop browser") -|*Number of new posts, in total and by group.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-1.png?raw=true "Frio theme in desktop browser") -|*Calender with popup of event.*| -|![Frio theme default colour in standard browser on tablet](images/screenshots/friendica-frio-default-profile-1.png?raw=true "Frio theme default colour in standard browser on tablet") -|*Notifications menu and private messages counter, standard browser on tablet.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-2.png?raw=true "Frio theme in desktop browser") -|*Number of visible contacts, standard browser.*| -|![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-1.png?raw=true "Frio theme in desktop browser") -|*Network posts chronologically ordered, standard browser.*| -|![Vier theme in desktop browser](images/screenshots/friendica-vier-profile.png?raw=true "Vier theme in desktop browser") -|*Vier theme, desktop browser. Public timeline view.*| -|![Vier theme in desktop browser](images/screenshots/friendica-vier-community.png?raw=true "Vier theme in desktop browser") -|*Vier theme, desktop browser. Community post displayed.*| +| ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-1.png?raw=true "Frio theme in mobile browser") ![Frio theme in mobile browser](images/screenshots/friendica-frio-mobile-profile-2.png?raw=true "Frio theme in mobile browser") | +|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:| +| *Frio theme, mobile browser. Timeline and composer view.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-1.png?raw=true "Frio theme in desktop browser") | +| *Frio theme, desktop browser. Timeline view, contact info popped up, control menu open.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-green-profile-2.png?raw=true "Frio theme in desktop browser") | +| *Frio theme, desktop browser. Menu open for controlling individual posts.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-3.png?raw=true "Frio theme in desktop browser") | +| *Frio theme, desktop browser. Profile view, notification menu open.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-2.png?raw=true "Frio theme in desktop browser") | +| *Number of new posts, in total and by circle.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-red-profile-1.png?raw=true "Frio theme in desktop browser") | +| *Calendar with popup of event.* | +| ![Frio theme default colour in standard browser on tablet](images/screenshots/friendica-frio-default-profile-1.png?raw=true "Frio theme default colour in standard browser on tablet") | +| *Notifications menu and private messages counter, standard browser on tablet.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-2.png?raw=true "Frio theme in desktop browser") | +| *Number of visible contacts, standard browser.* | +| ![Frio theme in desktop browser](images/screenshots/friendica-frio-brown-profile-1.png?raw=true "Frio theme in desktop browser") | +| *Network posts chronologically ordered, standard browser.* | +| ![Vier theme in desktop browser](images/screenshots/friendica-vier-profile.png?raw=true "Vier theme in desktop browser") | +| *Vier theme, desktop browser. Public timeline view.* | +| ![Vier theme in desktop browser](images/screenshots/friendica-vier-community.png?raw=true "Vier theme in desktop browser") | +| *Vier theme, desktop browser. Community post displayed.* | ## Endorsements diff --git a/VERSION b/VERSION index e4a82cd8e..c32d7efee 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2023.05 +2023.09-dev diff --git a/bin/auth_ejabberd.php b/bin/auth_ejabberd.php index 40e7d3b97..3a9553246 100755 --- a/bin/auth_ejabberd.php +++ b/bin/auth_ejabberd.php @@ -58,6 +58,7 @@ if (php_sapi_name() !== 'cli') { use Dice\Dice; use Friendica\App\Mode; +use Friendica\Core\Logger\Capability\LogChannel; use Friendica\Security\ExAuth; use Psr\Log\LoggerInterface; @@ -78,7 +79,10 @@ chdir($directory); require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['auth_ejabberd']]); +/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class,['constructParams' => [LogChannel::AUTH_JABBERED]]); \Friendica\DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/bin/console.php b/bin/console.php index e1bc6b498..b797e6ba9 100755 --- a/bin/console.php +++ b/bin/console.php @@ -26,13 +26,17 @@ if (php_sapi_name() !== 'cli') { } use Dice\Dice; +use Friendica\Core\Logger\Capability\LogChannel; use Friendica\DI; use Psr\Log\LoggerInterface; require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['console']]); +/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [LogChannel::CONSOLE]]); /// @fixme Necessary until Hooks inside the Logger can get loaded without the DI-class DI::init($dice); diff --git a/bin/daemon.php b/bin/daemon.php index e550aea89..cd774fe25 100755 --- a/bin/daemon.php +++ b/bin/daemon.php @@ -60,7 +60,10 @@ if (!file_exists('index.php') && (sizeof($_SERVER['argv']) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['daemon']]); +/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [Logger\Capability\LogChannel::DAEMON]]); DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/bin/worker.php b/bin/worker.php index a74213248..c855f9bc5 100755 --- a/bin/worker.php +++ b/bin/worker.php @@ -29,6 +29,7 @@ if (php_sapi_name() !== 'cli') { use Dice\Dice; use Friendica\App; use Friendica\App\Mode; +use Friendica\Core\Logger\Capability\LogChannel; use Friendica\Core\Update; use Friendica\Core\Worker; use Friendica\DI; @@ -54,7 +55,10 @@ if (!file_exists("index.php") && (sizeof($_SERVER["argv"]) != 0)) { require dirname(__DIR__) . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/../static/dependencies.config.php'); -$dice = $dice->addRule(LoggerInterface::class,['constructParams' => ['worker']]); +/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); +$dice = $dice->addRule(LoggerInterface::class, ['constructParams' => [LogChannel::WORKER]]); DI::init($dice); \Friendica\Core\Logger\Handler\ErrorHandler::register($dice->create(\Psr\Log\LoggerInterface::class)); diff --git a/composer.json b/composer.json index 6e0d9f984..9a86ebc2c 100644 --- a/composer.json +++ b/composer.json @@ -77,6 +77,12 @@ "npm-asset/textcomplete": "^0.18.2", "npm-asset/typeahead.js": "^0.11.1" }, + "suggest": { + "ext-imagick": "For faster image processing", + "ext-redis": "To use Redis as a locking or caching provider", + "ext-pdo": "To use PDO as a database driver, has priority over mysqli unless database.disable_pdo is set", + "ext-mysqli": "To use mysqli as a databse driver" + }, "repositories": [ { "type": "vcs", @@ -134,6 +140,7 @@ "scripts": { "test": "phpunit", "lint": "find . -name \\*.php -not -path './vendor/*' -not -path './view/asset/*' -print0 | xargs -0 -n1 php -l", + "docker:translate": "docker run --rm -v $PWD:/data -w /data friendicaci/transifex bin/run_xgettext.sh", "cs:install": "@composer install --working-dir=bin/dev/php-cs-fixer", "cs:check": [ "@cs:install", diff --git a/composer.lock b/composer.lock index af9186e8d..ac2d038f9 100644 --- a/composer.lock +++ b/composer.lock @@ -720,11 +720,11 @@ }, { "name": "friendica/json-ld", - "version": "1.1.2", + "version": "1.1.4", "source": { "type": "git", "url": "https://git.friendi.ca/friendica/php-json-ld", - "reference": "5f6ea87b261d346e57f03457ae906e6835f0205f" + "reference": "1f33c8766b5cfbecfbc2122238873debeed35fb6" }, "require": { "ext-json": "*", @@ -760,7 +760,7 @@ "Semantic Web", "jsonld" ], - "time": "2023-02-20T21:56:16+00:00" + "time": "2023-07-09T14:00:15+00:00" }, { "name": "fxp/composer-asset-plugin", @@ -1322,6 +1322,24 @@ "html", "markdown" ], + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://www.patreon.com/colinodell", + "type": "patreon" + } + ], "time": "2020-07-01T00:34:03+00:00" }, { diff --git a/database.sql b/database.sql index 6377222b0..c66de5bdd 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ --- Friendica 2023.05 (Giant Rhubarb) --- DB_UPDATE_VERSION 1518 +-- Friendica 2023.09-dev (Giant Rhubarb) +-- DB_UPDATE_VERSION 1530 -- ------------------------------------------ @@ -101,6 +101,19 @@ CREATE TABLE IF NOT EXISTS `user` ( FOREIGN KEY (`parent-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='The local users'; +-- +-- TABLE user-gserver +-- +CREATE TABLE IF NOT EXISTS `user-gserver` ( + `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', + `gsid` int unsigned NOT NULL DEFAULT 0 COMMENT 'Gserver id', + `ignored` boolean NOT NULL DEFAULT '0' COMMENT 'server accounts are ignored for the user', + PRIMARY KEY(`uid`,`gsid`), + INDEX `gsid` (`gsid`), + FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='User settings about remote servers'; + -- -- TABLE item-uri -- @@ -160,8 +173,8 @@ CREATE TABLE IF NOT EXISTS `contact` ( `archive` boolean NOT NULL DEFAULT '0' COMMENT '', `unsearchable` boolean NOT NULL DEFAULT '0' COMMENT 'Contact prefers to not be searchable', `sensitive` boolean NOT NULL DEFAULT '0' COMMENT 'Contact posts sensitive content', - `baseurl` varbinary(383) DEFAULT '' COMMENT 'baseurl of the contact', - `gsid` int unsigned COMMENT 'Global Server ID', + `baseurl` varbinary(383) DEFAULT '' COMMENT 'baseurl of the contact from the gserver record, can be missing', + `gsid` int unsigned COMMENT 'Global Server ID, can be missing', `bd` date NOT NULL DEFAULT '0001-01-01' COMMENT '', `reason` text COMMENT '', `self` boolean NOT NULL DEFAULT '0' COMMENT '1 if the contact is the user him/her self', @@ -190,7 +203,7 @@ CREATE TABLE IF NOT EXISTS `contact` ( `confirm` varbinary(383) COMMENT '', `poco` varbinary(383) COMMENT '', `writable` boolean NOT NULL DEFAULT '0' COMMENT '', - `forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a forum. Deprecated, use \'contact-type\' = \'community\' and \'manually-approve\' = false instead', + `forum` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a group. Deprecated, use \'contact-type\' = \'community\' and \'manually-approve\' = false instead', `prv` boolean NOT NULL DEFAULT '0' COMMENT 'contact is a private group. Deprecated, use \'contact-type\' = \'community\' and \'manually-approve\' = true instead', `bdyear` varchar(4) NOT NULL DEFAULT '' COMMENT '', `site-pubkey` text COMMENT 'Deprecated', @@ -252,9 +265,9 @@ CREATE TABLE IF NOT EXISTS `permissionset` ( `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner id of this permission set', `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', - `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed circles', `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', - `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied circles', PRIMARY KEY(`id`), INDEX `uid_allow_cid_allow_gid_deny_cid_deny_gid` (`uid`,`allow_cid`(50),`allow_gid`(30),`deny_cid`(50),`deny_gid`(30)), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE @@ -457,9 +470,9 @@ CREATE TABLE IF NOT EXISTS `attach` ( `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'creation time', `edited` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'last edit time', `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>', - `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed circles', `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', - `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied circles', `backend-class` tinytext COMMENT 'Storage backend class', `backend-ref` text COMMENT 'Storage backend data reference', PRIMARY KEY(`id`), @@ -500,6 +513,10 @@ CREATE TABLE IF NOT EXISTS `contact-relation` ( `last-interaction` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last interaction', `follow-updated` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT 'Date of the last update of the contact relationship', `follows` boolean NOT NULL DEFAULT '0' COMMENT '', + `score` smallint unsigned COMMENT 'score for interactions of cid on relation-cid', + `relation-score` smallint unsigned COMMENT 'score for interactions of relation-cid on cid', + `thread-score` smallint unsigned COMMENT 'score for interactions of cid on threads of relation-cid', + `relation-thread-score` smallint unsigned COMMENT 'score for interactions of relation-cid on threads of cid', PRIMARY KEY(`cid`,`relation-cid`), INDEX `relation-cid` (`relation-cid`), FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, @@ -662,9 +679,9 @@ CREATE TABLE IF NOT EXISTS `event` ( `nofinish` boolean NOT NULL DEFAULT '0' COMMENT 'if event does have no end this is 1', `ignore` boolean NOT NULL DEFAULT '0' COMMENT '0 or 1', `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', - `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed circles', `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', - `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied circles', PRIMARY KEY(`id`), INDEX `uid_start` (`uid`,`start`), INDEX `cid` (`cid`), @@ -716,29 +733,29 @@ CREATE TABLE IF NOT EXISTS `group` ( `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', `uid` mediumint unsigned NOT NULL DEFAULT 0 COMMENT 'Owner User id', `visible` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the member list is not private', - `deleted` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the group has been deleted', - `cid` int unsigned COMMENT 'Contact id of forum. When this field is filled then the members are synced automatically.', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'human readable name of group', + `deleted` boolean NOT NULL DEFAULT '0' COMMENT '1 indicates the circle has been deleted', + `cid` int unsigned COMMENT 'Contact id of group. When this field is filled then the members are synced automatically.', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'human readable name of circle', PRIMARY KEY(`id`), INDEX `uid` (`uid`), INDEX `cid` (`cid`), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, group info'; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy circles, circle info'; -- -- TABLE group_member -- CREATE TABLE IF NOT EXISTS `group_member` ( `id` int unsigned NOT NULL auto_increment COMMENT 'sequential ID', - `gid` int unsigned NOT NULL DEFAULT 0 COMMENT 'groups.id of the associated group', - `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id of the member assigned to the associated group', + `gid` int unsigned NOT NULL DEFAULT 0 COMMENT 'group.id of the associated circle', + `contact-id` int unsigned NOT NULL DEFAULT 0 COMMENT 'contact.id of the member assigned to the associated circle', PRIMARY KEY(`id`), INDEX `contactid` (`contact-id`), UNIQUE INDEX `gid_contactid` (`gid`,`contact-id`), FOREIGN KEY (`gid`) REFERENCES `group` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`contact-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy groups, member info'; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='privacy circles, member info'; -- -- TABLE gserver-tag @@ -1114,9 +1131,9 @@ CREATE TABLE IF NOT EXISTS `photo` ( `scale` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '', `profile` boolean NOT NULL DEFAULT '0' COMMENT '', `allow_cid` mediumtext COMMENT 'Access Control - list of allowed contact.id \'<19><78>\'', - `allow_gid` mediumtext COMMENT 'Access Control - list of allowed groups', + `allow_gid` mediumtext COMMENT 'Access Control - list of allowed circles', `deny_cid` mediumtext COMMENT 'Access Control - list of denied contact.id', - `deny_gid` mediumtext COMMENT 'Access Control - list of denied groups', + `deny_gid` mediumtext COMMENT 'Access Control - list of denied circles', `accessible` boolean NOT NULL DEFAULT '0' COMMENT 'Make photo publicly accessible, ignoring permissions', `backend-class` tinytext COMMENT 'Storage backend class', `backend-ref` text COMMENT 'Storage backend data reference', @@ -1586,7 +1603,7 @@ CREATE TABLE IF NOT EXISTS `profile` ( `profile-name` varchar(255) COMMENT 'Deprecated', `is-default` boolean COMMENT 'Deprecated', `hide-friends` boolean NOT NULL DEFAULT '0' COMMENT 'Hide friend list from viewers of this profile', - `name` varchar(255) NOT NULL DEFAULT '' COMMENT '', + `name` varchar(255) NOT NULL DEFAULT '' COMMENT 'Unused in favor of user.username', `pdesc` varchar(255) COMMENT 'Deprecated', `dob` varchar(32) NOT NULL DEFAULT '0000-00-00' COMMENT 'Day of birth', `address` varchar(255) NOT NULL DEFAULT '' COMMENT '', @@ -1695,19 +1712,34 @@ CREATE TABLE IF NOT EXISTS `report` ( `uid` mediumint unsigned COMMENT 'Reporting user', `reporter-id` int unsigned COMMENT 'Reporting contact', `cid` int unsigned NOT NULL COMMENT 'Reported contact', + `gsid` int unsigned COMMENT 'Reported contact server', `comment` text COMMENT 'Report', - `category` varchar(20) COMMENT 'Category of the report (spam, violation, other)', - `rules` text COMMENT 'Violated rules', + `category-id` int unsigned NOT NULL DEFAULT 1 COMMENT 'Report category, one of Entity\Report::CATEGORY_*', `forward` boolean COMMENT 'Forward the report to the remote server', - `created` datetime NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', - `status` tinyint unsigned COMMENT 'Status of the report', + `public-remarks` text COMMENT 'Remarks shared with the reporter', + `private-remarks` text COMMENT 'Remarks shared with the moderation team', + `last-editor-uid` mediumint unsigned COMMENT 'Last editor user', + `assigned-uid` mediumint unsigned COMMENT 'Assigned moderator user', + `status` tinyint unsigned NOT NULL COMMENT 'Status of the report, one of Entity\Report::STATUS_*', + `resolution` tinyint unsigned COMMENT 'Resolution of the report, one of Entity\Report::RESOLUTION_*', + `created` datetime(6) NOT NULL DEFAULT '0001-01-01 00:00:00' COMMENT '', + `edited` datetime(6) COMMENT 'Last time the report has been edited', PRIMARY KEY(`id`), INDEX `uid` (`uid`), INDEX `cid` (`cid`), INDEX `reporter-id` (`reporter-id`), + INDEX `gsid` (`gsid`), + INDEX `last-editor-uid` (`last-editor-uid`), + INDEX `assigned-uid` (`assigned-uid`), + INDEX `status-resolution` (`status`,`resolution`), + INDEX `created` (`created`), + INDEX `edited` (`edited`), FOREIGN KEY (`uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`reporter-id`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, - FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE + FOREIGN KEY (`cid`) REFERENCES `contact` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`gsid`) REFERENCES `gserver` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`last-editor-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE, + FOREIGN KEY (`assigned-uid`) REFERENCES `user` (`uid`) ON UPDATE RESTRICT ON DELETE CASCADE ) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; -- @@ -1721,7 +1753,18 @@ CREATE TABLE IF NOT EXISTS `report-post` ( INDEX `uri-id` (`uri-id`), FOREIGN KEY (`rid`) REFERENCES `report` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (`uri-id`) REFERENCES `item-uri` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE -) DEFAULT COLLATE utf8mb4_general_ci COMMENT=''; +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Individual posts attached to a moderation report'; + +-- +-- TABLE report-rule +-- +CREATE TABLE IF NOT EXISTS `report-rule` ( + `rid` int unsigned NOT NULL COMMENT 'Report id', + `line-id` int unsigned NOT NULL COMMENT 'Terms of service rule line number, may become invalid after a TOS change.', + `text` text NOT NULL COMMENT 'Terms of service rule text recorded at the time of the report', + PRIMARY KEY(`rid`,`line-id`), + FOREIGN KEY (`rid`) REFERENCES `report` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE +) DEFAULT COLLATE utf8mb4_general_ci COMMENT='Terms of service rule lines relevant to a moderation report'; -- -- TABLE search @@ -1808,8 +1851,8 @@ CREATE TABLE IF NOT EXISTS `user-contact` ( `rel` tinyint unsigned COMMENT 'The kind of the relation between the user and the contact', `info` mediumtext COMMENT '', `notify_new_posts` boolean COMMENT '', - `remote_self` boolean COMMENT '', - `fetch_further_information` tinyint unsigned COMMENT '', + `remote_self` tinyint unsigned COMMENT '0 => No mirroring, 1-2 => Mirror as own post, 3 => Mirror as reshare', + `fetch_further_information` tinyint unsigned COMMENT '0 => None, 1 => Fetch information, 3 => Fetch keywords, 2 => Fetch both', `ffi_keyword_denylist` text COMMENT '', `subhub` boolean COMMENT '', `hub-verify` varbinary(383) COMMENT '', @@ -1874,6 +1917,37 @@ CREATE VIEW `application-view` AS SELECT FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`; +-- +-- VIEW circle-member-view +-- +DROP VIEW IF EXISTS `circle-member-view`; +CREATE VIEW `circle-member-view` AS SELECT + `group_member`.`id` AS `id`, + `group`.`uid` AS `uid`, + `group_member`.`contact-id` AS `contact-id`, + `contact`.`uri-id` AS `contact-uri-id`, + `contact`.`url` AS `contact-link`, + `contact`.`addr` AS `contact-addr`, + `contact`.`name` AS `contact-name`, + `contact`.`nick` AS `contact-nick`, + `contact`.`thumb` AS `contact-avatar`, + `contact`.`network` AS `contact-network`, + `contact`.`blocked` AS `contact-blocked`, + `contact`.`hidden` AS `contact-hidden`, + `contact`.`readonly` AS `contact-readonly`, + `contact`.`archive` AS `contact-archive`, + `contact`.`pending` AS `contact-pending`, + `contact`.`self` AS `contact-self`, + `contact`.`rel` AS `contact-rel`, + `contact`.`contact-type` AS `contact-contact-type`, + `group_member`.`gid` AS `circle-id`, + `group`.`visible` AS `circle-visible`, + `group`.`deleted` AS `circle-deleted`, + `group`.`name` AS `circle-name` + FROM `group_member` + INNER JOIN `contact` ON `group_member`.`contact-id` = `contact`.`id` + INNER JOIN `group` ON `group_member`.`gid` = `group`.`id`; + -- -- VIEW post-user-view -- @@ -1882,7 +1956,7 @@ CREATE VIEW `post-user-view` AS SELECT `post-user`.`id` AS `id`, `post-user`.`id` AS `post-user-id`, `post-user`.`uid` AS `uid`, - `parent-post`.`id` AS `parent`, + `post-thread-user`.`post-user-id` AS `parent`, `item-uri`.`uri` AS `uri`, `post-user`.`uri-id` AS `uri-id`, `parent-item-uri`.`uri` AS `parent-uri`, @@ -1968,23 +2042,27 @@ CREATE VIEW `post-user-view` AS SELECT `author`.`addr` AS `author-addr`, IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`) AS `author-name`, `author`.`nick` AS `author-nick`, + `author`.`alias` AS `author-alias`, IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`) AS `author-avatar`, `author`.`network` AS `author-network`, `author`.`blocked` AS `author-blocked`, `author`.`hidden` AS `author-hidden`, `author`.`updated` AS `author-updated`, `author`.`gsid` AS `author-gsid`, + `author`.`baseurl` AS `author-baseurl`, `post-user`.`owner-id` AS `owner-id`, `owner`.`uri-id` AS `owner-uri-id`, `owner`.`url` AS `owner-link`, `owner`.`addr` AS `owner-addr`, IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`) AS `owner-name`, `owner`.`nick` AS `owner-nick`, + `owner`.`alias` AS `owner-alias`, IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`) AS `owner-avatar`, `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-user`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -1992,10 +2070,12 @@ CREATE VIEW `post-user-view` AS SELECT `causer`.`addr` AS `causer-addr`, `causer`.`name` AS `causer-name`, `causer`.`nick` AS `causer-nick`, + `causer`.`alias` AS `causer-alias`, `causer`.`thumb` AS `causer-avatar`, `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-delivery-data`.`postopts` AS `postopts`, `post-delivery-data`.`inform` AS `inform`, @@ -2025,14 +2105,14 @@ CREATE VIEW `post-user-view` AS SELECT EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-user`.`uri-id`) AS `has-media`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, - `parent-post`.`network` AS `parent-network`, - `parent-post`.`author-id` AS `parent-author-id`, + `post-thread-user`.`network` AS `parent-network`, + `post-thread-user`.`author-id` AS `parent-author-id`, `parent-post-author`.`url` AS `parent-author-link`, `parent-post-author`.`name` AS `parent-author-name`, `parent-post-author`.`nick` AS `parent-author-nick`, `parent-post-author`.`network` AS `parent-author-network` FROM `post-user` - STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` @@ -2050,8 +2130,7 @@ CREATE VIEW `post-user-view` AS SELECT LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-user`.`uri-id` AND `post-user`.`origin` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-user`.`uri-id` LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-user`.`psid` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`; + LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `post-thread-user`.`author-id`; -- -- VIEW post-thread-user-view @@ -2061,7 +2140,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `post-user`.`id` AS `id`, `post-user`.`id` AS `post-user-id`, `post-thread-user`.`uid` AS `uid`, - `parent-post`.`id` AS `parent`, + `post-thread-user`.`post-user-id` AS `parent`, `item-uri`.`uri` AS `uri`, `post-thread-user`.`uri-id` AS `uri-id`, `parent-item-uri`.`uri` AS `parent-uri`, @@ -2130,6 +2209,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `contact`.`pending` AS `contact-pending`, `contact`.`rel` AS `contact-rel`, `contact`.`uid` AS `contact-uid`, + `contact`.`gsid` AS `contact-gsid`, `contact`.`contact-type` AS `contact-contact-type`, IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`) AS `writable`, `contact`.`self` AS `self`, @@ -2146,6 +2226,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT `author`.`addr` AS `author-addr`, IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`) AS `author-name`, `author`.`nick` AS `author-nick`, + `author`.`alias` AS `author-alias`, IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`) AS `author-avatar`, `author`.`network` AS `author-network`, `author`.`blocked` AS `author-blocked`, @@ -2158,11 +2239,13 @@ CREATE VIEW `post-thread-user-view` AS SELECT `owner`.`addr` AS `owner-addr`, IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`) AS `owner-name`, `owner`.`nick` AS `owner-nick`, + `owner`.`alias` AS `owner-alias`, IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`) AS `owner-avatar`, `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-thread-user`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -2170,10 +2253,12 @@ CREATE VIEW `post-thread-user-view` AS SELECT `causer`.`addr` AS `causer-addr`, `causer`.`name` AS `causer-name`, `causer`.`nick` AS `causer-nick`, + `causer`.`alias` AS `causer-alias`, `causer`.`thumb` AS `causer-avatar`, `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-delivery-data`.`postopts` AS `postopts`, `post-delivery-data`.`inform` AS `inform`, @@ -2203,11 +2288,12 @@ CREATE VIEW `post-thread-user-view` AS SELECT EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread-user`.`uri-id`) AS `has-media`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, - `parent-post`.`network` AS `parent-network`, - `parent-post`.`author-id` AS `parent-author-id`, - `parent-post-author`.`url` AS `parent-author-link`, - `parent-post-author`.`name` AS `parent-author-name`, - `parent-post-author`.`network` AS `parent-author-network` + `post-thread-user`.`network` AS `parent-network`, + `post-thread-user`.`author-id` AS `parent-author-id`, + `author`.`url` AS `parent-author-link`, + `author`.`name` AS `parent-author-name`, + `author`.`nick` AS `parent-author-nick`, + `author`.`network` AS `parent-author-network` FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` @@ -2226,9 +2312,7 @@ CREATE VIEW `post-thread-user-view` AS SELECT LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-thread-user`.`uri-id` AND `post-thread-user`.`origin` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread-user`.`uri-id` - LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-thread-user`.`uid` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`; + LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid`; -- -- VIEW post-view @@ -2310,6 +2394,7 @@ CREATE VIEW `post-view` AS SELECT `author`.`addr` AS `author-addr`, `author`.`name` AS `author-name`, `author`.`nick` AS `author-nick`, + `author`.`alias` AS `author-alias`, `author`.`thumb` AS `author-avatar`, `author`.`network` AS `author-network`, `author`.`blocked` AS `author-blocked`, @@ -2322,23 +2407,27 @@ CREATE VIEW `post-view` AS SELECT `owner`.`addr` AS `owner-addr`, `owner`.`name` AS `owner-name`, `owner`.`nick` AS `owner-nick`, + `owner`.`alias` AS `owner-alias`, `owner`.`thumb` AS `owner-avatar`, `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, `owner`.`contact-type` AS `owner-contact-type`, + `owner`.`gsid` AS `owner-gsid`, `post`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, `causer`.`url` AS `causer-link`, `causer`.`addr` AS `causer-addr`, `causer`.`name` AS `causer-name`, `causer`.`nick` AS `causer-nick`, + `causer`.`alias` AS `causer-alias`, `causer`.`thumb` AS `causer-avatar`, `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, `causer`.`contact-type` AS `causer-contact-type`, + `causer`.`gsid` AS `causer-gsid`, `post-question`.`id` AS `question-id`, `post-question`.`multiple` AS `question-multiple`, `post-question`.`voters` AS `question-voters`, @@ -2347,10 +2436,11 @@ CREATE VIEW `post-view` AS SELECT EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post`.`uri-id`) AS `has-media`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, - `parent-post`.`network` AS `parent-network`, - `parent-post`.`author-id` AS `parent-author-id`, + `post-thread`.`network` AS `parent-network`, + `post-thread`.`author-id` AS `parent-author-id`, `parent-post-author`.`url` AS `parent-author-link`, `parent-post-author`.`name` AS `parent-author-name`, + `parent-post-author`.`nick` AS `parent-author-nick`, `parent-post-author`.`network` AS `parent-author-network` FROM `post` STRAIGHT_JOIN `post-thread` ON `post-thread`.`uri-id` = `post`.`parent-uri-id` @@ -2367,8 +2457,7 @@ CREATE VIEW `post-view` AS SELECT LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post`.`uri-id` LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post`.`uri-id` - LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`; + LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `post-thread`.`author-id`; -- -- VIEW post-thread-view @@ -2450,6 +2539,7 @@ CREATE VIEW `post-thread-view` AS SELECT `author`.`addr` AS `author-addr`, `author`.`name` AS `author-name`, `author`.`nick` AS `author-nick`, + `author`.`alias` AS `author-alias`, `author`.`thumb` AS `author-avatar`, `author`.`network` AS `author-network`, `author`.`blocked` AS `author-blocked`, @@ -2462,11 +2552,13 @@ CREATE VIEW `post-thread-view` AS SELECT `owner`.`addr` AS `owner-addr`, `owner`.`name` AS `owner-name`, `owner`.`nick` AS `owner-nick`, + `owner`.`alias` AS `owner-alias`, `owner`.`thumb` AS `owner-avatar`, `owner`.`network` AS `owner-network`, `owner`.`blocked` AS `owner-blocked`, `owner`.`hidden` AS `owner-hidden`, `owner`.`updated` AS `owner-updated`, + `owner`.`gsid` AS `owner-gsid`, `owner`.`contact-type` AS `owner-contact-type`, `post-thread`.`causer-id` AS `causer-id`, `causer`.`uri-id` AS `causer-uri-id`, @@ -2474,10 +2566,12 @@ CREATE VIEW `post-thread-view` AS SELECT `causer`.`addr` AS `causer-addr`, `causer`.`name` AS `causer-name`, `causer`.`nick` AS `causer-nick`, + `causer`.`alias` AS `causer-alias`, `causer`.`thumb` AS `causer-avatar`, `causer`.`network` AS `causer-network`, `causer`.`blocked` AS `causer-blocked`, `causer`.`hidden` AS `causer-hidden`, + `causer`.`gsid` AS `causer-gsid`, `causer`.`contact-type` AS `causer-contact-type`, `post-question`.`id` AS `question-id`, `post-question`.`multiple` AS `question-multiple`, @@ -2489,11 +2583,12 @@ CREATE VIEW `post-thread-view` AS SELECT (SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6) AS `total-actors`, `diaspora-interaction`.`interaction` AS `signed_text`, `parent-item-uri`.`guid` AS `parent-guid`, - `parent-post`.`network` AS `parent-network`, - `parent-post`.`author-id` AS `parent-author-id`, - `parent-post-author`.`url` AS `parent-author-link`, - `parent-post-author`.`name` AS `parent-author-name`, - `parent-post-author`.`network` AS `parent-author-network` + `post-thread`.`network` AS `parent-network`, + `post-thread`.`author-id` AS `parent-author-id`, + `author`.`url` AS `parent-author-link`, + `author`.`name` AS `parent-author-name`, + `author`.`nick` AS `parent-author-nick`, + `author`.`network` AS `parent-author-network` FROM `post-thread` INNER JOIN `post` ON `post`.`uri-id` = `post-thread`.`uri-id` STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-thread`.`author-id` @@ -2508,9 +2603,7 @@ CREATE VIEW `post-thread-view` AS SELECT LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread`.`uri-id` LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread`.`uri-id` LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` - LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id` - LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`; + LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id`; -- -- VIEW category-view @@ -2587,7 +2680,7 @@ CREATE VIEW `tag-view` AS SELECT DROP VIEW IF EXISTS `network-item-view`; CREATE VIEW `network-item-view` AS SELECT `post-user`.`uri-id` AS `uri-id`, - `parent-post`.`id` AS `parent`, + `post-thread-user`.`post-user-id` AS `parent`, `post-user`.`received` AS `received`, `post-thread-user`.`commented` AS `commented`, `post-user`.`created` AS `created`, @@ -2600,17 +2693,16 @@ CREATE VIEW `network-item-view` AS SELECT `post-user`.`contact-id` AS `contact-id`, `ownercontact`.`contact-type` AS `contact-type` FROM `post-user` - STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` - INNER JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` - INNER JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-user`.`hidden` IS NULL OR NOT `post-user`.`hidden`) - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`); + AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`); -- -- VIEW network-thread-view @@ -2618,7 +2710,7 @@ CREATE VIEW `network-item-view` AS SELECT DROP VIEW IF EXISTS `network-thread-view`; CREATE VIEW `network-thread-view` AS SELECT `post-thread-user`.`uri-id` AS `uri-id`, - `parent-post`.`id` AS `parent`, + `post-thread-user`.`post-user-id` AS `parent`, `post-thread-user`.`received` AS `received`, `post-thread-user`.`commented` AS `commented`, `post-thread-user`.`created` AS `created`, @@ -2631,15 +2723,14 @@ CREATE VIEW `network-thread-view` AS SELECT FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` - LEFT JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` + STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`) - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`); + AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`); -- -- VIEW owner-view diff --git a/doc/API-Entities.md b/doc/API-Entities.md index 213b2494f..de3eac9b9 100644 --- a/doc/API-Entities.md +++ b/doc/API-Entities.md @@ -454,7 +454,7 @@ Ex: Wed May 23 06:01:13 +0000 2007 allow_gid String (angle-brackets escaped integers) -Optional. List of allowed group ids +Optional. List of allowed circle ids @@ -466,7 +466,7 @@ Ex: Wed May 23 06:01:13 +0000 2007 deny_gid String (angle-brackets escaped integers) -Optional. List of disallowed group ids +Optional. List of disallowed circle ids @@ -583,7 +583,7 @@ Ex: Wed May 23 06:01:13 +0000 2007 friendica_owner - + Contact No @@ -984,7 +984,7 @@ Identical to [the Twitter Media Object](https://developer.twitter.com/en/docs/tw allow_gid String (ACL) -List of contact group ids wrapped in angle brackets allowed to access the photo. +List of contact circle ids wrapped in angle brackets allowed to access the photo. @@ -996,7 +996,7 @@ Identical to [the Twitter Media Object](https://developer.twitter.com/en/docs/tw deny_gid String (ACL) -List of contact group ids wrapped in angle brackets forbidden to access the photo. +List of contact circle ids wrapped in angle brackets forbidden to access the photo. @@ -1541,4 +1541,4 @@ Unused ## User Mention -Unused \ No newline at end of file +Unused diff --git a/doc/API-Friendica.md b/doc/API-Friendica.md index 197a5033e..785cbe41a 100644 --- a/doc/API-Friendica.md +++ b/doc/API-Friendica.md @@ -39,8 +39,8 @@ Create a new event for the current logged in user. - `publish` : (optional) create message for event - `allow_cid` : (optional) ACL-formatted list of allowed contact ids if private event - `allow_gid` : (optional) ACL-formatted list of disallowed contact ids if private event -- `deny_cid` : (optional) ACL-formatted list of allowed group ids if private event -- `deny_gid` : (optional) ACL-formatted list of disallowed group ids if private event +- `deny_cid` : (optional) ACL-formatted list of allowed circle ids if private event +- `deny_gid` : (optional) ACL-formatted list of disallowed circle ids if private event ### POST api/friendica/event_delete @@ -323,33 +323,37 @@ On error: --- -### GET api/friendica/group_show +### GET api/friendica/circle_show -Return all or a specified group of the user with the containing contacts as array. +Alternatively: GET api/friendica/group_show (Backward compatibility) + +Return all or a specified circle of the user with the containing contacts as array. #### Parameters -* `gid`: optional, if not given, API returns all groups of the user +* `gid`: optional, if not given, API returns all circles of the user #### Return values Array of: -* `name`: name of the group -* `gid`: id of the group +* `name`: name of the circle +* `gid`: id of the circle * `user`: array of [Contacts](help/API-Entities#Contact) -### POST api/friendica/group_create +### POST api/friendica/circle_create -Create the group with the posted array of contacts as members. +Alternatively: POST api/friendica/group_create + +Create the circle with the posted array of contacts as members. #### Parameters -* `name`: name of the group to be created +* `name`: name of the circle to be created #### POST data -JSON data as Array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show): +JSON data as Array like the result of [GET api/friendica/circle_show](#GET+api%2Ffriendica%2Fcircle_show): * `gid` * `name` @@ -360,23 +364,25 @@ JSON data as Array like the result of [GET api/friendica/group_show](#GET+api%2F Array of: * `success`: true if successfully created or reactivated -* `gid`: gid of the created group -* `name`: name of the created group +* `gid`: gid of the created circle +* `name`: name of the created circle * `status`: "missing user" | "reactivated" | "ok" * `wrong users`: array of users, which were not available in the contact table -### POST api/friendica/group_update +### POST api/friendica/circle_update -Update the group with the posted array of contacts as members (post all members of the group to the call; function will remove members not posted). +Alternatively: POST api/friendica/group_update + +Update the circle with the posted array of contacts as members (post all members of the circle to the call; function will remove members not posted). #### Parameters -* `gid`: id of the group to be changed -* `name`: name of the group to be changed +* `gid`: id of the circle to be changed +* `name`: name of the circle to be changed #### POST data -JSON data as array like the result of [GET api/friendica/group_show](#GET+api%2Ffriendica%2Fgroup_show): +JSON data as array like the result of [GET api/friendica/circle_show](#GET+api%2Ffriendica%2Fcircle_show): * `gid` * `name` @@ -387,27 +393,29 @@ JSON data as array like the result of [GET api/friendica/group_show](#GET+api%2F Array of: * `success`: true if successfully updated -* `gid`: gid of the changed group -* `name`: name of the changed group +* `gid`: gid of the changed circle +* `name`: name of the changed circle * `status`: "missing user" | "ok" * `wrong users`: array of users, which were not available in the contact table -### POST api/friendica/group_delete +### POST api/friendica/circle_delete -Delete the specified group of contacts; API call need to include the correct gid AND name of the group to be deleted. +Alternatively: POST api/friendica/group_delete + +Delete the specified circle of contacts; API call need to include the correct gid AND name of the circle to be deleted. #### Parameters -* `gid`: id of the group to be deleted -* `name`: name of the group to be deleted +* `gid`: id of the circle to be deleted +* `name`: name of the circle to be deleted #### Return values Array of: * `success`: true if successfully deleted -* `gid`: gid of the deleted group -* `name`: name of the deleted group +* `gid`: gid of the deleted circle +* `name`: name of the deleted circle * `status`: "deleted" if successfully deleted * `wrong users`: empty array @@ -556,7 +564,7 @@ Alias of [`api/friendica/photo/update`](#POST+api%2Ffriendica%2Fphoto%2Fupdate) Saves data for the scales 0-2 to database (see above for scale description). Call adds non-public entries to items table to enable authenticated contacts to comment/like the photo. -Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited group. +Client should pay attention to the fact that updated access rights are not transferred to the contacts. i.e. public photos remain publicly visible if they have been commented/liked before setting visibility back to a limited circle. Currently it is best to inform user that updating rights is not the right way to do this, and offer a solution to add photo as a new photo with the new rights instead. #### Parameters diff --git a/doc/API-Mastodon.md b/doc/API-Mastodon.md index 18a783720..2798446ba 100644 --- a/doc/API-Mastodon.md +++ b/doc/API-Mastodon.md @@ -211,7 +211,7 @@ Example: - `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`. - [`POST /api/v1/statuses`](https://docs.joinmastodon.org/methods/statuses/#create) - Does not support `polls` argument as Friendica does not have polls - - Additionally to the static values `public`, `unlisted` and `private`, the `visibility` parameter can contain a numeric value with a group id. + - Additionally to the static values `public`, `unlisted` and `private`, the `visibility` parameter can contain a numeric value with a circle id. - Additional field `quote_id` for the post that is being quote reshared - Additional fields `friendica` for Friendica specific parameters: - `title`: Explicitly sets the title for a post status, ignored if used on a comment status. For post statuses the legacy behavior is to use any "spoiler text" as the title if it is provided. If both the title and spoiler text are provided for a post status then they will each be used for their respective roles. If no title is provided then the legacy behavior will persist. If you want to create a post with no title but spoiler text then explicitly set the title but set it to an empty string `""`. diff --git a/doc/Accesskeys.md b/doc/Accesskeys.md index a94fd1ea9..9a68c62de 100644 --- a/doc/Accesskeys.md +++ b/doc/Accesskeys.md @@ -48,7 +48,7 @@ General * i - Only show ignored contacts * y - Only show archived contacts * h - Only show hidden contacts -* e - Edit contact groups +* e - Edit contact circles ../contact (single contact view) ------------------------------- diff --git a/doc/Account-Basics.md b/doc/Account-Basics.md index a205ea7e5..f03a488b5 100644 --- a/doc/Account-Basics.md +++ b/doc/Account-Basics.md @@ -41,9 +41,9 @@ This is the only bit of personal information that has to be accurate. ### Nickname A nickname is used to generate web addresses for many of your personal pages, and is also treated like an email address when establishing communications with others. -Due to the way that the nickname is used, it has some limitations. +Due to the way that the nickname is used, it has some limitations. It must contain only US-ASCII text characters and numbers, and must also start with a text character. -It also must be unique on this system. +It also must be unique on this system. This is used in many places to identify your account, and once set it cannot be changed. @@ -53,28 +53,28 @@ The registration form also allows you to choose whether or not to list your acco This is like a "phone book" and you may choose to be unlisted. We recommend that you select 'Yes' so that other people (friends, family, etc.) will be able to find you. If you choose 'No', you will essentially be invisible and have few opportunities for interaction. -Whichever you choose, this can be changed any time from your Settings page after you login. +Whichever you choose, this can be changed any time from your Settings page after you login. ### Register Once you have provided the necessary details, click the 'Register' button. An email will be sent to you providing your account login details. -Please check your email (including spam folders) for your registration details and initial password. +Please check your email (including spam folders) for your registration details and initial password. Login Page --- On the 'Login' page, please enter your login information that was provided during registration. -You may use either your nickname or email address as a Login Name. +You may use either your nickname or email address as a Login Name. If you use your account to manage other accounts and these all have the same email address, please enter the nickname for the account you wish to manage. If your account has been OpenID enabled, you may use your OpenID address as a login name and leave the password blank. -You will be redirected to your OpenID provider to complete your authorisation. +You will be redirected to your OpenID provider to complete your authorisation. Otherwise, enter your password. This will have been initially provided in your registration email message. -Your password is case-sensitive, so please check your 'Caps Lock' key if you are having difficulty logging in. +Your password is case-sensitive, so please check your 'Caps Lock' key if you are having difficulty logging in. Changing Your Password --- @@ -99,9 +99,9 @@ See Also * [Profiles](help/Profiles) -* [Global Directory](help/Making-Friends#The+Directories) +* [Global Directory](help/Making-Friends#The+Directories) -* [Groups and Privacy](help/Groups-and-Privacy) +* [Circles and Privacy](help/Circles-and-Privacy) * [Move Account](help/Move-Account) diff --git a/doc/Bugs-and-Issues.md b/doc/Bugs-and-Issues.md index 405604c75..126f6af58 100644 --- a/doc/Bugs-and-Issues.md +++ b/doc/Bugs-and-Issues.md @@ -6,7 +6,7 @@ Bugs and Issues If your server has a support page, you should report any bugs/issues you encounter there first. Reporting to your support page before reporting to the developers makes their job easier, as they don't have to deal with bug reports that might not have anything to do with them. Reducing the workload in this way helps us get new features faster. -You can also contact the [friendica support forum](https://forum.friendi.ca/profile/helpers) and report your problem there. +You can also contact the [friendica support group](https://forum.friendi.ca/profile/helpers) and report your problem there. Bugs are rarely limited to one person, and the chances are somebody from another node has encountered the problem too, and will be able to help you. If you're a technical user, or your site doesn't have a support page, you'll need to use the [Bug Tracker](https://github.com/friendica/friendica/issues). diff --git a/doc/Groups-and-Privacy.md b/doc/Circles-and-Privacy.md similarity index 62% rename from doc/Groups-and-Privacy.md rename to doc/Circles-and-Privacy.md index d8d5a3d8f..d701173c0 100644 --- a/doc/Groups-and-Privacy.md +++ b/doc/Circles-and-Privacy.md @@ -1,78 +1,76 @@ -Groups and Privacy +Circles and Privacy ================== * [Home](help) -Groups are merely collections of friends. +Circles are merely collections of friends. But Friendica uses these to unlock some very powerful features. -**Setting Up Groups** +**Setting Up Circles** -To create a group, visit your Friendica "Contacts" page and select "Create a new group". -Give the group a name. +To create a circle, visit your Friendica "Contacts" page and select "Create a new circle". +Give the circle a name. -This brings you to a page where you can select the group members. +This brings you to a page where you can select the circle members. You will have two boxes on this page. -The top box is the roster of current group members. -Below that is another box containing all of your friends who are *not* members of the group. +The top box is the roster of current circle members. +Below that is another box containing all of your friends who are *not* members of the circle. -If you click on a photo of a person who isn't in the group, they will be put into the group. -If you click on a photo of a person who is in the group, they will be removed from it. +If you click on a photo of a person who isn't in the circle, they will be put into the circle. +If you click on a photo of a person who is in the circle, they will be removed from it. **Access Control** -Once you have created a group, you may use it in any access control list. +Once you have created a circle, you may use it in any access control list. This is the little lock icon beneath the status update box on your home page. -If you click this you can select who can see and who can *not* see the post you are about to make.. -These can be individual people or groups. +If you click this, you can select who can see and who can *not* see the post you are about to make... +These can be individual people or circles. -On your "Network" page you will find posts and conversation from everybody in your network. -You may select an individual group on this page to show conversations pertaining only to members of that group. +On your "Network" page, you will find posts and conversations from everybody in your network. +You may select an individual circle on this page to show conversations pertaining only to members of that circle. But wait, there's more... -If you look carefully when visiting a group from your Network page, the lock icon under the status update box has an exclamation mark next to it. +If you look carefully when visiting a circle from your Network page, the lock icon under the status update box has an exclamation mark next to it. This is meant to draw attention to that lock. Click the lock. -You will see that since you are only viewing a certain group of people, your status updates while on that screen default to only being seen by that same group of people. +You will see that since you are only viewing a certain circle of people, your status updates while on that screen default to only being seen by that same circle of people. This is how you keep your future employers from seeing what you write to your drinking buddies. -You can over-ride this setting, but this makes it easy to separate your conversations into different friend circles. +You can override this setting, but this makes it easy to separate your conversations into different friend circles. **Default Post Privacy** By default, Friendica assumes that you want all of your posts to be private. -Therefore, when you sign up, Friendica creates a group for you that it will automatically add all of your contacts to. -All of your posts are restricted to that group by default. +Therefore, when you sign up, Friendica creates a circle for you that it will automatically add all of your contacts to. +All of your posts are restricted to that circle by default. -Note that this behaviour can be overridden by your site admin, in which case your posts will be "public" (i.e. visible to the entire Internet) by default. +Note that this behaviour can be overridden by your site admin, in which case your posts will be "public" (i.e., visible to the entire Internet) by default. If you want your posts to be "public" by default, you can change your default post permissions on your Settings page. -You also have the option there to change which groups you post to by default, or to change which group your new contacts get placed into by default. +You also have the option to change which circles you post to by default or which circle your new contacts get placed into by default. **Privacy Concerns To Be Aware Of** These private conversations work best when your friends are Friendica members. -We know who else can see the conversations - nobody, *unless* your friends cut and paste the messages and send them to others. +We know who else can see the conversations - nobody, *unless* your friends cut and paste the messages and send them to others. This is a trust issue you need to be aware of. No software in the world can prevent your friends from leaking your confidential and trusted communications. -Only a wise choice of friends. +Only a wise choice of friends. -But it isn't as clear cut when dealing with GNU Social and other network providers. +But it isn't as clear-cut when dealing with GNU Social and other network providers. If you look at the Contact Edit page for any person, we will tell you whether or not they are members of an insecure network where you should exercise caution. Once you have created a post, you can not change the permissions assigned. Within seconds it has been delivered to lots of people - and perhaps everybody it was addressed to. -If you mistakenly created a message and wish you could take it back, the best you can do is to delete it. -We will send out a delete notification to everybody who received the message - and this should wipe out the message with the same speed it was initially propagated. -In most cases it will be completely wiped from the Internet - in under a minute. +If you mistakenly created a message and wish to take it back, the best you can do is delete it. +We will send out a delete notification to everybody who received the message - and this should wipe out the message with the same speed as it was initially propagated. +In most cases, it will be completely wiped from the Internet - in under a minute. Again, this applies to Friendica networks. -Once a message spreads to other networks, it may not be removed quickly and in some cases it may not be removed at all. +Once a message spreads to other networks, it may not be removed quickly, and in some cases, it may not be removed at all. -In case you haven't yet figured this out, we are encouraging you to encourage your friends to use Friendica - because all these privacy features work much better within a privacy-aware network. -Many of the other social networks Friendica can connect to have no privacy controls. Profiles, Photos, and Privacy @@ -102,7 +100,7 @@ When Friendica sends a post to these networks which exceeds the service length l The original is a link back to your Friendica profile. As Friendica cannot prove who they are, it may not be possible for these people to view your post in full. -For people in this situation we would recommend providing a "Twitter-length" summary, with more detail for friends that can see the post in full. +For people in this situation we would recommend providing a "Twitter-length" summary, with more detail for friends that can see the post in full. You can do so by including the BBCode tag *abstract* in your posting. Blocking your profile or entire Friendica site from unknown web visitors also has serious implications for communicating with GNU Social members. diff --git a/doc/Developers-Intro.md b/doc/Developers-Intro.md index 329219925..c500b2774 100644 --- a/doc/Developers-Intro.md +++ b/doc/Developers-Intro.md @@ -13,14 +13,14 @@ Whether you feel like an expert or like a newbie - join us with your ideas! ## Contact us -The discussion of Friendica development takes place in the following Friendica forums: +The discussion of Friendica development takes place in the following Friendica groups: -* The main [forum for Friendica development](https://forum.friendi.ca/profile/developers) +* The main [group for Friendica development](https://forum.friendi.ca/profile/developers) ## Help other users Remember the questions you had when you first tried Friendica? -A good place to start can be to help new people find their way around Friendica in the [general support forum](https://forum.friendi.ca/profile/helpers). +A good place to start can be to help new people find their way around Friendica in the [general support group](https://forum.friendi.ca/profile/helpers). Welcome them, answer their questions, point them to documentation or ping other helpers directly if you can't help but think you know who can. ## Translation @@ -33,10 +33,10 @@ If you don't want to translate the UI, or it is already done to your satisfactio Are you good at designing things? If you have seen Friendica you probably have ideas to improve it, haven't you? -* If you would like to work with us on enhancing the user interface, please join the [forum for Friendica development](https://forum.friendi.ca/profile/developers). +* If you would like to work with us on enhancing the user interface, please join the [group for Friendica development](https://forum.friendi.ca/profile/developers). * Make plans for a better Friendica interface design and share them with us. * Tell us if you are able to realize your ideas or what kind of help you need. - We can't promise we have the right skills in the group but we'll try. + We can't promise we have the right skills in the group, but we'll try. * Choose a thing to start with, e.g. work on the icon set of your favorite theme ## Programming @@ -72,7 +72,7 @@ just place it into `.git/hooks/post-merge` and make it executable. ### Coding standards -For the sake of consistency between contribution and general code readability, Friendica follows the widespread [PSR-2 coding standards](http://www.php-fig.org/psr/psr-2/) to the exception of a few rules. +For the sake of consistency between contribution and general code readability, Friendica follows the widespread [PSR-2 coding standards](http://www.php-fig.org/psr/psr-2/) excepted a few rules. Here's a few primers if you are new to Friendica or to the PSR-2 coding standards: * Indentation is tabs, period (not PSR-2). @@ -88,7 +88,7 @@ Here's a few primers if you are new to Friendica or to the PSR-2 coding standard Don't worry, you don't have to know by heart the PSR-2 coding standards to start contributing to Friendica. There are a few tools you can use to check or fix your files before you commit. -For documentation we use the standard of *one sentence per line* for the `md` files in the `/doc` and `/doc/$lng` subdirectories. +For documentation, we use the standard of *one sentence per line* for the `md` files in the `/doc` and `/doc/$lng` subdirectories. #### Check with [PHP Code Sniffer](https://github.com/squizlabs/PHP_CodeSniffer) @@ -113,7 +113,7 @@ If the command-line tools `diff` and `patch` are unavailable for you, `phpcbf` c ### Code documentation -If you are interested in having the documentation of the Friendica code outside of the code files, you can use [Doxygen](http://doxygen.org) to generate it. +If you are interested in having the documentation of the Friendica code outside the code files, you can use [Doxygen](http://doxygen.org) to generate it. The configuration file for Doxygen is located in the base directory of the project sources. Run @@ -126,7 +126,7 @@ If you find missing documentation, don't hesitate to contact us and write it dow ### Issues -Have a look at our [issue tracker](https://github.com/friendica/friendica) on github! +Have a look at our [issue tracker](https://github.com/friendica/friendica) on GitHub! * Try to reproduce a bug that needs more inquiries and write down what you find out. * If a bug looks fixed, ask the bug reporters for feedback to find out if the bug can be closed. @@ -143,13 +143,13 @@ If you want to get involved here: * Look at the first steps that were made (e.g. the clean theme). Ask us to find out whom to talk to about their experiences. * Talk to design people if you know any. -* Let us know about your plans [in the dev forum](https://forum.friendi.ca/profile/developers) +* Let us know about your plans [in the dev group](https://forum.friendi.ca/profile/developers) Do not worry about cross-posting. ### Client software As Friendica is using a [Twitter/GNU Social compatible API](help/api) any of the clients for those platforms should work with Friendica as well. -Furthermore there are several client projects, especially for use with Friendica. +Furthermore, there are several client projects, especially for use with Friendica. If you are interested in improving those clients, please contact the developers of the clients directly. * Android / LinageOS: **Friendiqa** [src](https://git.friendi.ca/lubuwest/Friendiqa)/[Google Play](https://play.google.com/store/apps/details?id=org.qtproject.friendiqa) developed by [Marco R](https://freunde.ma-nic.de/profile/marco) diff --git a/doc/FAQ-admin.md b/doc/FAQ-admin.md index 94cef1627..e5f4f2a9f 100644 --- a/doc/FAQ-admin.md +++ b/doc/FAQ-admin.md @@ -52,4 +52,4 @@ You can manually execute the structure update from the CLI in the base directory bin/console dbstructure update -if there occur any errors, please contact the [support forum](https://forum.friendi.ca/profile/helpers). +if there occur any errors, please contact the [support group](https://forum.friendi.ca/profile/helpers). diff --git a/doc/FAQ.md b/doc/FAQ.md index 2a2af5688..ebb8c041b 100644 --- a/doc/FAQ.md +++ b/doc/FAQ.md @@ -4,14 +4,14 @@ Frequently Asked Questions - FAQ * [Home](help) * **[Where I can find help?](help/FAQ#help)** -* **[Why do I getting warnings about certificates?](help/FAQ#ssl)** +* **[Why do I get warnings about certificates?](help/FAQ#ssl)** * **[How can I upload images, files, links, videos and sound files to posts?](help/FAQ#upload)** * **[Is it possible to have different avatars per profile?](help/FAQ#avatars)** * **[How can I view Friendica in a certain language?](help/FAQ#language)** * **[How do blocked, ignored, archived and hidden contacts behave?](help/FAQ#contacts)** * **[What happens when an account is removed? Is it truly deleted?](help/FAQ#removed)** * **[Can I subscribe to a hashtag?](help/FAQ#hashtag)** -* **[How to create a RSS feed of the stream?](help/FAQ#rss)** +* **[How to create an RSS feed of the stream?](help/FAQ#rss)** * **[What friendica clients can I use?](help/FAQ#clients)** @@ -21,7 +21,7 @@ Frequently Asked Questions - FAQ If this FAQ does not answer your question you can always reach out to the community via the following options: - * Friendica Support Forum: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) + * Friendica Support Group: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) * Community chat rooms (the IRC, Matrix and XMPP rooms are bridged) these public chats are logged [from IRC](https://gnusociarg.nsupdate.info/2021/%23friendica/) and [Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/) * XMPP: support(at)forum.friendi.ca * IRC: #friendica at [libera.chat](https://web.libera.chat/?channels=#friendica) @@ -66,7 +66,7 @@ If this doesn't work, try to add the link by typing: [url=http://example.com]*se You can also add video and audio files to posts. However, instead of a direct upload you have to use one of the following methods: -1. Add the video or audio link of a hoster (Youtube, Vimeo, Soundcloud and anyone else with oembed/opengraph-support). Videos will be shown with a preview image you can click on to start. SoundCloud directly inserts a player to your post. +1. Add the video or audio link of a hoster (YouTube, Vimeo, Soundcloud and anyone else with oembed/opengraph-support). Videos will be shown with a preview image you can click on to start. SoundCloud directly inserts a player to your post. 2. If you have your own server, you can upload multimedia files via FTP and insert the URL. @@ -92,7 +92,7 @@ A question mark is required for the separation between url and parameters. Example: - https://social.example.com/profile/example + https://social.example.com/profile/example in German: @@ -107,48 +107,48 @@ When a certain language is forced, the language remains until session is closed. Direct communication will be blocked. Blocked contacts are not included in delivery, and their own posts to you are not imported. -However their conversations with your friends will still be visible in your stream. +However, their conversations with your friends will still be visible in your stream. If you remove a contact completely, they can send you another friend request. Blocked contacts cannot do this. They cannot communicate with you directly, only through friends. ##### Ignored Ignored contacts are included in delivery and will receive your posts and private messages. -However we do not import their posts or private messages to you. -Like blocking you will still see this person's comments to posts made by your friends. +However, we do not import their posts or private messages to you. +Like blocking, you will still see this person's comments to posts made by your friends. An addon called "blockem" can be installed to collapse/hide all posts from a particular person in your stream if you desire complete blocking of an individual, including their conversations with your other friends. ##### Archived Communication is not possible and will not be attempted. -However unlike blocking, existing posts this person made before being archived will be visible in your stream. +However, unlike blocking, existing posts this person made before being archived will be visible in your stream. ##### Hidden Contact not be displayed in your public friend list. -However a hidden contact will appear normally in conversations and this may expose their hidden status to anybody who can see the conversation. +However, a hidden contact will appear normally in conversations and this may expose their hidden status to anybody who can see the conversation. ### What happens when an account is removed? -If you remove your account, it will be scheduled for permanent deletion in *seven days*. -As soon as you activate the deletion process you won't be able to login any more. +If you remove your account, it will be scheduled for permanent deletion in *seven days*. +As soon as you activate the deletion process you won't be able to log in anymore. Only the administrator of your node can halt this process prior to permanent deletion. -After the elapsed time of seven days, all your posts, messages, photos, and personal information stored on your node will be deleted. -Your node will also issue removal requests to all your contacts; this will also remove your profile from the global directory if you are listed. +After the elapsed time of seven days, all your posts, messages, photos, and personal information stored on your node will be deleted. +Your node will also issue removal requests to all your contacts; this will also remove your profile from the global directory if you are listed. Your username cannot be reissued for future sign-ups for security reasons. ### Can I follow a hashtag? -Yes. Simply add the hash tag to your saved searches. +Yes. Simply add the hashtag to your saved searches. The posts will appear on your network page. For technical reasons, your answers to such posts won't appear on the "personal" tab in the network page and the whole thread isn't accessible via the API. -### How to create a RSS feed of the stream? +### How to create an RSS feed of the stream? If you want to share your public page via rss you can use one of the following links: @@ -191,10 +191,10 @@ The available features are client specific and may differ. #### iOS -* [Mastodon](https://joinmastodon.org/apps) ([AppStore](https://apps.apple.com/us/app/mastodon-for-iphone/id1571998974)) -* [Stella*](https://www.stella-app.net/) ([AppStore](https://apps.apple.com/us/app/stella-for-mastodon-twitter/id921372048)) -* [Tooot](https://github.com/tooot-app) ([AppStore](https://apps.apple.com/app/id1549772269) -* [TwidereX](https://github.com/TwidereProject/TwidereX-iOS) ([AppStore](https://apps.apple.com/app/twidere-x/id1530314034)) +* [Mastodon](https://joinmastodon.org/apps) ([App Store](https://apps.apple.com/us/app/mastodon-for-iphone/id1571998974)) +* [Stella*](https://www.stella-app.net/) ([App Store](https://apps.apple.com/us/app/stella-for-mastodon-twitter/id921372048)) +* [Tooot](https://github.com/tooot-app) ([App Store](https://apps.apple.com/app/id1549772269) +* [TwidereX](https://github.com/TwidereProject/TwidereX-iOS) ([App Store](https://apps.apple.com/app/twidere-x/id1530314034)) #### Linux @@ -206,7 +206,7 @@ The available features are client specific and may differ. #### macOS * [TheDesk](https://thedesk.top/en/) ([GitHub](https://github.com/cutls/TheDesk)) -* [Whalebird](https://whalebird.social/en/desktop/contents) ([AppStore](https://apps.apple.com/de/app/whalebird/id1378283354), [GitHub](https://github.com/h3poteto/whalebird-desktop)) +* [Whalebird](https://whalebird.social/en/desktop/contents) ([App Store](https://apps.apple.com/de/app/whalebird/id1378283354), [GitHub](https://github.com/h3poteto/whalebird-desktop)) #### Windows diff --git a/doc/Forums.md b/doc/Forums.md deleted file mode 100644 index d58a8565a..000000000 --- a/doc/Forums.md +++ /dev/null @@ -1,66 +0,0 @@ -Forums -===== - -* [Home](help) - - -Friendica also lets you create community forums and other types of accounts that can function as discussion forums, celebrity accounts, announcement channels, news reflectors, or organization pages, depending on how you want to interact with others. Management of these pages can be delegated to other accounts, or a parent account can be designated to easily toggle multiple identities. - -Every page in Friendica has a nickname and these must all be unique. This applies to all forums, whether they are normal profiles or forum profiles. - -Managing Accounts ---- - -To create a new linked account that can be used as a forum, log in to your normal account and go to Settings > Manage Accounts. -Here you can register additional accounts with new nicknames that will be linked to your primary account. - -You may appoint a delegate to manage your new account (e.g. forum page). -The Delegates section of Manage Accounts page will provide you with a list of contacts on this instance under "Potential Delegates". -Selecting one or more persons will give them access to manage your forum. -They will be able to edit contacts, profiles, and all content for this account/page. -Please use this facility wisely. -Delegated managers will not be able to alter basic account settings, such as passwords or page types, or remove the account. - -Additionally, this page is also where you can choose to designate an account as a parent user. -If your primary account is designated as the parent user, you will be able to easily toggle identities and manage your forums or other types of accounts. - -Types of Accounts ---- - -On the new account, visit the Settings > Account page. -Towards the end of the page is a section for "Advanced account types". -Typically you would use "Personal Page - Standard" for a normal personal account with manual approval of “friends” and “followers.” -This is the default selection. -On this page you can change the type of account if desired. - -The other subtypes of a Personal Page are “Soapbox” and “Love-all.” -A Soapbox account is an announcement channel that automatically approvals follower requests. -Everything posted by the account will go out to the followers, but there will be no opportunity for interaction. -This setting would typically be used for announcements or corporate communications. -“Love-all” automatically approves contacts as friends. - -In addition to Personal Page, there are options for Organization Page, News Page, and Community Forum. -Organization and New Pages automatically approve contact requests as followers. - -Community Forum provide the ability for people to become friends/fans of the forum without requiring approval. -This creates a forum page where all members can freely interact. - -Posting to Community forums ---- - -If you are a member of a community forum, you may post to the forum by including an @-tag in the post mentioning the forum. -For example @bicycle would send my post to all members of the group "bicycle" in addition to the normal recipients. -If you mention a forum (you are a member of) in a new posting, the posting will be distributed to all members of the forum, regardless of your privacy settings for the posting. -Also, if the forum is a public forum, your posting will be public for the all internet users. -If your post is private you must also explicitly include the group in the post permissions (to allow the forum "contact" to see the post) **and** mention it in a tag (which redistributes the post to the forum members). -Posting privately to a public forum, will result in your posting being displayed on the forum wall, but not on yours. - -Additionally it is possible to address a forum with the exclamation mark. -In the example above this means that you can address the bicycle forum via !bicycle. -The difference to the @ is that the post will only be sent to the addressed forum. -This also means that you shouldn't address multiple forums in a single post in that way since it will only be distributed by one the forums. - -You may also post to a community forum by posting a "wall-to-wall" post using secure cross-site authentication. - -Comments which are relayed to community forums will be relayed back to the original post creator. -Mentioning the forum with an @-tag in a comment does not relay the message, as distribution is controlled entirely by the original post creator. diff --git a/doc/GitHub.md b/doc/GitHub.md index 5fbc3788e..24f2e6aa4 100644 --- a/doc/GitHub.md +++ b/doc/GitHub.md @@ -3,7 +3,7 @@ Friendica on GitHub * [Home](help) -Here is how you can work on the code with us. If you have any questions please write to the Friendica developers' forum. +Here is how you can work on the code with us. If you have any questions please write to the Friendica developers' group. Introduction to the workflow with our GitHub repository ------------------------------------------------------- diff --git a/doc/Groups.md b/doc/Groups.md new file mode 100644 index 000000000..3c2e17929 --- /dev/null +++ b/doc/Groups.md @@ -0,0 +1,68 @@ +Groups +===== + +* [Home](help) + + +Friendica also lets you create accounts that can function as discussion groups, celebrity accounts, announcement channels, news reflectors, or organization pages, depending on how you want to interact with others. +Management of these accounts can be delegated to other accounts, or a parent account can be designated to easily toggle multiple identities. + +Every account in Friendica has a nickname and these must all be unique. +This applies to all accounts, whether they are individual profiles or group profiles. + +Managing Accounts +--- + +To create a new linked account that can be used as a group, log in to your normal account and go to Settings > Manage Accounts. +Here you can register additional accounts with new nicknames that will be linked to your primary account. + +You may appoint a delegate to manage your new account. +The Delegates section of Manage Accounts page will provide you with a list of contacts on this instance under "Potential Delegates". +Selecting one or more persons will give them access to manage your newly created account. +They will be able to edit contacts, profiles, and all content for this account. +Please use this facility wisely. +Delegated managers will not be able to alter basic account settings, such as passwords or account types, or remove the account. + +Additionally, this page is also where you can choose to designate an account as a parent user. +If your primary account is designated as the parent user, you will be able to easily toggle identities and manage your groups or other types of accounts. + +Types of Accounts +--- + +On the new account, visit the Settings > Account page. +Towards the end of the page is a section for "Advanced account types". +Typically, you would use "Personal Page - Standard" for a normal personal account with manual approval of “friends” and “followers.” +This is the default selection. +On this page you can change the type of account if desired. + +The other subtypes of a Personal Page are “Soapbox” and “Love-all.” +A Soapbox account is an announcement channel that automatically approvals follower requests. +Everything posted by the account will go out to the followers, but there will be no opportunity for interaction. +This setting would typically be used for announcements or corporate communications. +“Love-all” automatically approves contacts as friends. + +In addition to Personal Page, there are options for Organization Page, News Page, and Community Group. +Organization and New Pages automatically approve contact requests as followers. + +Community Group provide the ability for people to join the group without requiring approval. +This creates a group where all members can freely interact. + +Posting to Community groups +--- + +If you are a member of a community group, you may post to the group by including an @-mention in the post mentioning the group. +For example @bicycle would send my post to all members of the group "bicycle" in addition to the normal recipients. +If you mention a group (you are a member of) in a new posting, the posting will be distributed to all members of the group, regardless of your privacy settings for the posting. +Also, if the group is public, your posting will be public for the all internet users. +If your post is private you must also explicitly include the group in the post permissions (to allow the group "contact" to see the post) **and** mention it in a tag (which redistributes the post to the group members). +Posting privately to a public group, will result in your posting being displayed on the group wall, but not on yours. + +Additionally, it is possible to address a group with the exclamation mark. +In the example above this means that you can address the bicycle group via !bicycle. +The difference with the @-mention is that the post will only be sent to the addressed group. +This also means that you shouldn't address multiple groups in a single post in that way since it will only be distributed by one the groups. + +You may also post to a community group by posting a "wall-to-wall" post using secure cross-site authentication. + +Comments which are relayed to community groups will be relayed back to the original post creator. +Mentioning the group with an @-mention in a comment does not relay the message, as distribution is controlled entirely by the original post creator. diff --git a/doc/Home.md b/doc/Home.md index d343c41cc..9578e914a 100644 --- a/doc/Home.md +++ b/doc/Home.md @@ -14,9 +14,9 @@ Friendica Documentation and Resources * You and other users * [Connectors](help/Connectors) * [Making Friends](help/Making-Friends) - * [Groups and Privacy](help/Groups-and-Privacy) + * [Circles and Privacy](help/Circles-and-Privacy) * [Tags and Mentions](help/Tags-and-Mentions) - * [Community Forums](help/Forums) + * [Community Groups](help/Groups) * [Chats](help/Chats) * Further information * [Move your account](help/Move-Account) @@ -67,7 +67,7 @@ Friendica Documentation and Resources * [Main Website](https://friendi.ca) * Ways to get Support - * Friendica Support Forum: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) + * Friendica Support Group: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) * [Mailing List Archive](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) you can subscribe to the list by sending an email to ``support-request(at)friendi.ca?subject=subscribe`` * Community chat rooms (the IRC, Matrix and XMPP rooms are bridged) these public chats are logged [from IRC](https://gnusociarg.nsupdate.info/2021/%23friendica/) and [Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/) * XMPP/Jabber MUC: support(at)forum.friendi.ca diff --git a/doc/Improve-Performance.md b/doc/Improve-Performance.md index 1d0a859f1..727fa104b 100644 --- a/doc/Improve-Performance.md +++ b/doc/Improve-Performance.md @@ -3,7 +3,7 @@ How to improve the performance of a Friendica site * [Home](help) -Feel free to ask in the [Friendica support forum](https://forum.friendi.ca/profile/helpers) if you need some clarification about the following instructions or if you need help in any other way. +Feel free to ask in the [Friendica support group](https://forum.friendi.ca/profile/helpers) if you need some clarification about the following instructions or if you need help in any other way. System configuration -------- @@ -31,7 +31,7 @@ Active the following addons: ### rendertime -This addon doesn't speed up your system. +This addon doesn't speed up your system. It helps to analyze your bottlenecks. When enabled you see some values at the bottom of every page. diff --git a/doc/Install.md b/doc/Install.md index ddffe601c..bf9dffb35 100644 --- a/doc/Install.md +++ b/doc/Install.md @@ -15,7 +15,7 @@ Many will. But **please** review the [requirements](#Requirements) and confirm these with your hosting provider prior to installation. ## Support -If you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) forum or [file an issue](https://github.com/friendica/friendica/issues). +If you encounter installation issues, please let us know via the [helper](http://forum.friendi.ca/profile/helpers) or the [developer](https://forum.friendi.ca/profile/developers) group or [file an issue](https://github.com/friendica/friendica/issues). Please be as clear as you can about your operating environment and provide as much detail as possible about any error messages you may see, so that we can prevent it from happening in the future. Due to the large variety of operating systems and PHP platforms in existence we may have only limited ability to debug your PHP installation or acquire any missing modules - but we will do our best to solve any general code issues. @@ -23,7 +23,7 @@ Due to the large variety of operating systems and PHP platforms in existence we ## Prerequisites * Choose a domain name or subdomain name for your server. Put some thought into this. While changing it after installation is supported, things still might break. -* Setup HTTPS on your domain. +* Setup HTTPS on your domain. ### Requirements @@ -42,7 +42,7 @@ Due to the large variety of operating systems and PHP platforms in existence we For alternative server configurations (such as Nginx server and MariaDB database engine), refer to the [Friendica wiki](https://github.com/friendica/friendica/wiki). -### Optional +### Optional * PHP ImageMagick extension (php-imagick) for animated GIF support. @@ -105,11 +105,11 @@ If you encounter a bug, please let us know. ### Create a database -Create an empty database and note the access details (hostname, username, password, database name). +Create an empty database and note the access details (hostname, username, password, database name). Generate a strong password, then enter mysql with: mysql - + Then use the following script using the password you just generated: CREATE DATABASE friendicadb; @@ -148,7 +148,7 @@ You have the following options to automatically install Friendica: - using environment variables (f.e. `MYSQL_HOST`) - using options (f.e. `--dbhost `) -You can combine environment variables and options, but be aware that options are prioritized over environment variables. +You can combine environment variables and options, but be aware that options are prioritized over environment variables. For more information during the installation, you can use this command line option @@ -157,7 +157,7 @@ For more information during the installation, you can use this command line opti If you wish to include all optional checks, use `-a` like this statement: bin/console autoinstall -a - + *If* the automatic installation fails for any reason, check the following: * Does `config/local.config.php` already exist? If yes, the automatic installation won't start @@ -171,7 +171,7 @@ You can use a prepared config file like [local-sample.config.php](/config/local- Navigate to the main Friendica directory and execute the following command: bin/console autoinstall -f - + #### B.2: Environment variables There are two types of environment variables. @@ -194,7 +194,7 @@ if you don't use the option `--savedb` during installation, the DB credentials w **Friendica settings** This variables wont be used at normal Friendica runtime. -Instead, they get saved into `config/local.config.php`. +Instead, they get saved into `config/local.config.php`. - `FRIENDICA_URL_PATH` The URL path of Friendica (f.e. '/friendica') - `FRIENDICA_PHP_PATH` The path of the PHP binary @@ -238,7 +238,7 @@ Example: ### Verify the "host-meta" page is working Friendica should respond automatically to important addresses under the */.well-known/* rewrite path. -One critical URL would look like, for example: https://example.com/.well-known/host-meta +One critical URL would look like, for example: https://example.com/.well-known/host-meta It must be visible to the public and must respond with an XML file that is automatically customized to your site. If that URL is not working, it is possible that some other software is using the /.well-known/ path. @@ -257,7 +257,7 @@ It may be necessary to chmod the /.well-known/.htaccess file if you were not giv At this point visit your website again, and register your personal account with the same email as in the `config.admin_email` config value. Registration errors should all be recoverable automatically. -If you get any *critical* failure at this point, it generally indicates the database was not installed correctly. +If you get any *critical* failure at this point, it generally indicates the database was not installed correctly. You might wish to delete/rename `config/local.config.php` to another name and drop all the database tables so that you can start fresh. ## Post Install Configuration @@ -295,7 +295,7 @@ Once started, you can check the daemon status using the following command: cd /path/to/friendica; php bin/daemon.php status -After a server restart or any other failure, the daemon needs to be restarted. +After a server restart or any other failure, the daemon needs to be restarted. This could be achieved by a cronjob. ### (RECOMMENDED) Logging & Log Rotation @@ -408,7 +408,7 @@ provided by one of our members. > On my server I use the php protection system Suhosin [http://www.hardened-php.net/suhosin/]. > One of the things it does is to block certain functions like proc_open, as > configured in `/etc/php5/conf.d/suhosin.ini`: -> +> > suhosin.executor.func.blacklist = proc_open, ... > > For those sites like Friendica that really need these functions they can be @@ -418,34 +418,34 @@ provided by one of our members. > php_admin_value suhosin.executor.func.blacklist none > php_admin_value suhosin.executor.eval.blacklist none > -> +> > This enables every function for Friendica if accessed via browser, but not for > the cronjob that is called via php command line. I attempted to enable it for > cron by using something like: -> +> > */10 * * * * cd /var/www/friendica/friendica/ && sudo -u www-data /usr/bin/php \ > -d suhosin.executor.func.blacklist=none \ > -d suhosin.executor.eval.blacklist=none -f bin/worker.php -> +> > This worked well for simple test cases, but the friendica-cron still failed > with a fatal error: -> +> > suhosin[22962]: ALERT - function within blacklist called: proc_open() > (attacker 'REMOTE_ADDR not set', file '/var/www/friendica/friendica/boot.php', > line 1341) -> +> > After a while I noticed, that `bin/worker.php` calls further PHP script via `proc_open`. > These scripts themselves also use `proc_open` and fail, because they are NOT > called with `-d suhosin.executor.func.blacklist=none`. -> +> > So the simple solution is to put the correct parameters into `config/local.config.php`: -> +> > 'config' => [ > //Location of PHP command line processor > 'php_path' => '/usr/bin/php -d suhosin.executor.func.blacklist=none \ > -d suhosin.executor.eval.blacklist=none', > ], -> +> > This is obvious as soon as you notice that the friendica-cron uses `proc_open` > to execute PHP scripts that also use `proc_open`, but it took me quite some time to find that out. > I hope this saves some time for other people using suhosin with function blocklists. diff --git a/doc/Making-Friends.md b/doc/Making-Friends.md index aadf24796..d92899586 100644 --- a/doc/Making-Friends.md +++ b/doc/Making-Friends.md @@ -20,20 +20,20 @@ You'll also see a link to a **Global Directory**. There are several global directories across the globe that regularly exchange information with each other. The specific global directory that you see usually depends on where your server is located. If you click through to the global directory, you will be presented with a list of everybody who choses to be listed across all instances of Friendica. -You will also see a "Show Community Forums" link, which will direct you to Groups, Forums and Fanpages. -You connect to people, groups and forums in the same way, except groups and forums will automatically accept your introduction request, whereas a human will approve you manually. +You will also see a "Show Community Groups" link, which will direct you to Groups. +You connect to people and groups the same way, public groups will automatically accept your introduction, whereas private groups and some individual users will need to manually approve it. Connect to other Friendica users --- Visit their profile. Just beneath their profile picture will be the word 'Connect' (we're assuming this is an English language profile). -Click that 'Connect' button and it will take you to a 'Connect' form. +Click that 'Connect' button, and it will take you to a 'Connect' form. The form is going to ask you for your Identity Address. -This is necessary so that this person's website can find yours. +This is necessary so that this person's website can find yours. -If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would enter "bob@demo.friendica.com" in this form. +If your Friendica site is called "demo.friendica.com" and your username/nickname on that site is "bob", you would enter "bob@demo.friendica.com" in this form. Notice this looks just like an email address. It's meant to be that way. @@ -41,8 +41,8 @@ It's easy for people to remember. You *could* also put in the URL of your "home" page, such as "http://demo.friendica.com/profile/bob" instead of the email-style address. -When you've submitted the connection page, it will take you back to your own site where you must then login (if necessary) and verify the connection request on *your* site. -Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request). +When you've submitted the connection page, it will take you back to your own site where you must then log in (if necessary) and verify the connection request on *your* site. +Once you've done this, the two websites can communicate with each other to complete the process (after your new friend has approved the request). If you already know somebody's Identity Address, you can enter it in the "connect" box on your "Contacts" page. This will take you through a similar process. @@ -55,20 +55,20 @@ You can also use your Identity Address or other people's Identity Addresses to b Currently, Friendica supports connections with people on diaspora*, Red, Hubzilla, GNU Social, StatusNet, Mastodon, Pleroma, socialhome, and ganggo platforms. If you know (for instance) "alice" on gnusocial.net (a GNU Social site) you could put alice@gnusocial.net into your Contact page and become friends across networks. -Likewise you can put in the URL to Alice's gnusocial.net page, if you wish. +Likewise, you can put in the URL to Alice's gnusocial.net page, if you wish. Note: Some versions of GNU Social software may require the full URL to your profile and may not work with the identity address. People on these networks can also initiate contact with you, if they know your contact details. ### Other social media If you server provides this functionality, you can also connect with people one -Twitter or important feeds from Tumblr, Wordpress, and many more. +Twitter or important feeds from Tumblr, WordPress, and many more. To connect, enter their contact details in the "connect" box on your "Contacts" page. ### Email If you have supplied your mailbox connection information on your Settings page, you can enter the email address of anybody that has sent you a message recently and have their email messages show up in your social stream. -You can also reply to them from within Friendica. +You can also reply to them from within Friendica. Create an email contact with for example Alice on Gmail, enter her email in following format "mailto:alice@gmail.no". In order to avoid abuse or spam, you must have an email from Alice with the correct email address in your email inbox. @@ -78,7 +78,7 @@ To subscribe to a mailing list, enter the email in following example format "mai ### Syndication feeds You can "follow" almost anybody or any website that produces a syndication feed (RSS/Atom,etc.). -If we can find an information stream and a name to attach to the contact, we'll try to connect with them. +If we can find an information stream and a name to attach to the contact, we'll try to connect with them. Notification --- @@ -88,24 +88,24 @@ You will usually need to approve this before the friendship is complete. Approval --- Some networks allow people to send you messages without being friends and without your approval. -Friendica does not allow this by default, as it would open a gateway for spam. +Friendica does not allow this by default, as it would open a gateway for spam. Unilateral or bilateral friendships --- When you receive a friendship notification from another Friendica member, you will have the option of allowing them as a "Follower" or as a "Friend". If they are a follower, they can see what you have to say, including private communications that you send to them, but not vice versa. -As a friend, you can both communicate with each other. +As a friend, you can both communicate with each other. -diaspora* uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends. +diaspora* uses a different terminology, and you are given the option of allowing them to "share with you", or being full friends. Ignoring, blocking and deleting contacts --- Once you have become friends, if you find the person constantly sends you spam or worthless information, you can "Ignore" them - without breaking off the friendship or even alerting them to the fact that you aren't interested in anything they are saying. In many ways they are like a "follower" - but they don't know this. -They think they are a friend. +They think they are a friend. You can also "block" a person. This completely blocks communications with that person. -They may still be able to see your public posts, as can anybody in the world, but they cannot communicate with you directly. +They may still be able to see your public posts, as can anybody in the world, but they cannot communicate with you directly. You can also delete a friend no matter what the friendship status - which completely removes everything relating to that person from your website. diff --git a/doc/Move-Account.md b/doc/Move-Account.md index f2b56b982..2983184be 100644 --- a/doc/Move-Account.md +++ b/doc/Move-Account.md @@ -8,7 +8,7 @@ How to move your account between servers * Go to "Settings" -> "[Export personal data](uexport)" * Click on "Export account" to save your account data. -* **Save the file in a secure place!** It contains your details, your contacts, groups, and personal settings. It also contains your secret keys to authenticate yourself to your contacts. +* **Save the file in a secure place!** It contains your details, your contacts, circles, and personal settings. It also contains your secret keys to authenticate yourself to your contacts. * Go to your new server, and open *http://newserver.com/user/import* (there is not a direct link to this page at the moment). Please consider that this is only possible on servers with open registration. On other systems only the administrator can add accounts with an uploaded file. * Do NOT create a new account prior to importing your old settings - user import should be used *instead* of register. * Load your saved account file and click "Import". @@ -17,7 +17,7 @@ How to move your account between servers Friendica contacts --- -Friendica will recreate your account on the new server, with your contacts and groups. +Friendica will recreate your account on the new server, with your contacts and circles. A message is sent to Friendica contacts, to inform them about your move: If your contacts are running on an updated server, your details on their side will be automatically updated. diff --git a/doc/Quick-Start-andfinally.md b/doc/Quick-Start-andfinally.md index 3e7845d10..7ea3f5dc7 100644 --- a/doc/Quick-Start-andfinally.md +++ b/doc/Quick-Start-andfinally.md @@ -4,8 +4,7 @@ Here are some more things to help get you started: **Groups** - -- Friendica Support - problems? This is the place to ask. +- Friendica Support - problems? This is the place to ask. **Documentation** diff --git a/doc/Quick-Start-groupsandpages.md b/doc/Quick-Start-groupsandpages.md index f64f3afcb..c9a27c6f1 100644 --- a/doc/Quick-Start-groupsandpages.md +++ b/doc/Quick-Start-groupsandpages.md @@ -1,9 +1,9 @@ This is the global directory. If you get lost, you can click this link to bring yourself back here. -On this page, you'll find a collection of groups, forums and celebrity pages. +On this page, you'll find a collection of groups. Groups are not real people. -Connecting to them is similar to "liking" something on Facebook, or signing up for a new forum. +Connecting to them is similar to "liking" something on Facebook, or signing up for a new group. You don't have to feel awkward about introducing yourself to a new person, because they're not people! When you connect to a group, all messages to that group will start appearing in your network tab. @@ -15,6 +15,6 @@ Remember the link at the top of this page will bring you back here. Once you've added some groups, move on to the next section. - + diff --git a/doc/StrategyHooks.md b/doc/StrategyHooks.md new file mode 100644 index 000000000..2960ceeaa --- /dev/null +++ b/doc/StrategyHooks.md @@ -0,0 +1,89 @@ +Friendica strategy Hooks +=========================================== + +* [Home](help) + +## Strategy hooks + +This type of hook is based on the [Strategy Design Pattern](https://refactoring.guru/design-patterns/strategy). + +A strategy class defines a possible implementation of a given interface based on a unique name. +Every name is possible as long as it's unique and not `null`. +Using an empty name (`''`) is possible as well and should be used as the "default" implementation. +To register a strategy, use the [`ICanRegisterInstance`](../src/Core/Hooks/Capability/ICanRegisterInstances.php) interface. + +After registration, a caller can automatically create this instance with the [`ICanCreateInstances`](../src/Core/Hooks/Capability/ICanCreateInstances.php) interface and the chosen name. + +This is useful in case there are different, possible implementations for the same purpose, like for logging, locking, caching, ... + +Normally, a config entry is used to choose the right implementation at runtime. +And if no config entry is set, the "default" implementation should be used. + +### Example + +```php +interface ExampleInterface +{ + public function testMethod(); +} + +public class ConcreteClassA implements ExampleInterface +{ + public function testMethod() + { + echo "concrete class A"; + } +} + +public class ConcreteClassB implements ExampleInterface +{ + public function testMethod() + { + echo "concrete class B"; + } +} + +/** @var \Friendica\Core\Hooks\Capability\ICanRegisterStrategies $instanceRegister */ +$instanceRegister->registerStrategy(ExampleInterface::class, ConcreteClassA::class, 'A'); +$instanceRegister->registerStrategy(ExampleInterface::class, ConcreteClassB::class, 'B'); + +/** @var \Friendica\Core\Hooks\Capability\ICanCreateInstances $instanceManager */ +/** @var ConcreteClassA $concreteClass */ +$concreteClass = $instanceManager->create(ExampleInterface::class, 'A'); + +$concreteClass->testMethod(); +// output: +// "concrete class A"; +``` + +## hooks.config.php + +To avoid registering all strategies manually inside the code, Friendica introduced the [`hooks.config.php`](../static/hooks.config.php) file. + +There, you can register all kind of strategies in one file. + +### [`HookType::STRATEGY`](../src/Core/Hooks/Capability/HookType.php) + +For each given interface, a list of key-value pairs can be set, where the key is the concrete implementation class and the value is an array of unique names. + +### Example + +```php +use Friendica\Core\Hooks\Capability\BehavioralHookType as H; + +return [ + H::STRATEGY => [ + ExampleInterface::class => [ + ConcreteClassA::class => ['A'], + ConcreteClassB::class => ['B'], + ], + ], +]; +``` + +## Addons + +The hook logic is useful for decoupling the Friendica core logic, but its primary goal is to modularize Friendica in creating addons. + +Therefor you can either use the interfaces directly as shown above, or you can place your own `hooks.config.php` file inside a `static` directory directly under your addon core directory. +Friendica will automatically search these config files for each **activated** addon and register the given hooks. diff --git a/doc/Tags-and-Mentions.md b/doc/Tags-and-Mentions.md index ab87470b6..8424b026c 100644 --- a/doc/Tags-and-Mentions.md +++ b/doc/Tags-and-Mentions.md @@ -15,7 +15,7 @@ You can tag **persons who are in your social circle** by adding the "@"-sign in * @mike - indicates a known contact in your social circle whose nickname is "mike" * @mike_macgirvin - indicates a known contact in your social circle whose full name is "Mike Macgirvin". Note that spaces cannot be used inside tags. -* @mike+151 - this form is used by the drop-down tag completion tool. It indicates the contact whose nickname is mike and whose contact identifier number is 151. The drop-down tool may be used to resolve people with duplicate nicknames. +* @mike+151 - this form is used by the drop-down tag completion tool. It indicates the contact whose nickname is mike and whose contact identifier number is 151. The drop-down tool may be used to resolve people with duplicate nicknames. You can tag a person on a different network or one that is **not in your social circle** by using the following notation: @@ -23,27 +23,27 @@ You can tag a person on a different network or one that is **not in your social Unless their system blocks unsolicited "mentions", the person tagged will likely receive a "Mention" post/activity or become a direct participant in the conversation in the case of public posts. Friendica blocks incoming “mentions” from people with no relationship to you. -The exception is an ongoing conversation started from a contact of both you and the 3rd person or a conversation in a forum where you are a member of. +The exception is an ongoing conversation started from a contact of both you and the 3rd person or a conversation in a group where you are a member of. This is a spam prevention measure. Remote mentions are delivered using the OStatus protocol. This protocol is used by Friendica and GNU Social and several other systems like Mastodon, but is not currently implemented in Diaspora. As the OStatus protocol allows this Friendica user can be @-mentioned by users from platforms using this protocol in conversations if the "Enable OStatus support" is activated on the Friendica node. -These @-mentions wont be blocked, even if there is no relationship between the sender and the receiver of the message. +These @-mentions won't be blocked, even if there is no relationship between the sender and the receiver of the message. -Friendica makes no distinction between people and forums for the purpose of tagging. -You can use @-mentions for forums like for other accounts to tag the forum. -If you want to post something exclusively to a forum (e.g. the support forum) please use the bang-notation instead of the @tag. -So !helpers will be an exclusive posting to the support forum if you are connected with the forum. -If you select a forum from the ACL a !-mention will be added automatically to your posting. +Friendica makes no distinction between people and groups for the purpose of tagging. +You can use @-mentions for groups like for other accounts to tag the group. +If you want to post something exclusively to a group (e.g. the support group) please use the !-mention instead of the @-mention. +So !helpers will be an exclusive posting to the support group if you are connected with the group. +If you select a group from the ACL a !-mention will be added automatically to your posting. -If you sort your contacts into groups, you cannot @-mention these groups. -But you can select the group in the access control when creating a new posting, to allow (or disallow) a certain group of people to see the posting. -See [Groups and Privacy](help/Groups-and-Privacy) for more details about grouping your contacts. +If you sort your contacts into circles, you cannot @-mention these circles. +But you can select the circle in the access control when creating a new posting, to allow (or disallow) a certain circle of people to see the posting. +See [Circles and Privacy](help/Circles-and-Privacy) for more details about grouping your contacts. **Topical Tags** -Topical tags are indicated by preceding the tag name with the # character. +Topical tags are indicated by preceding the tag name with the # character. This will create a link in the post to a generalised site search for the term provided. For example, #cars will provide a search link for all posts mentioning 'cars' on your site. Topical tags are generally a minimum of three characters in length. diff --git a/doc/Text_editor.md b/doc/Text_editor.md index b7d0937aa..c20b9ac64 100644 --- a/doc/Text_editor.md +++ b/doc/Text_editor.md @@ -88,11 +88,11 @@ Click on "show" under contact name to hide the post to everyone but selected. Click on "Visible to everybody" to make the post public again. -If you have defined some groups, you can check "show" for groups also. All contact in that group will see the post. -If you want to hide the post to one contact of a group selected for "show", click "don't show" under contact name. +If you have defined some circles, you can check "show" for circles also. All contact in that circle will see the post. +If you want to hide the post to one contact of a circle selected for "show", click "don't show" under contact name. Click again on "show" or "don't show" to switch it off. -You can search for contacts or groups with the search box. +You can search for contacts or circles with the search box. -See also [Group and Privacy](help/Groups-and-Privacy) +See also [Circles and Privacy](help/Circles-and-Privacy) diff --git a/doc/Update.md b/doc/Update.md index d019d03b0..40de14082 100644 --- a/doc/Update.md +++ b/doc/Update.md @@ -10,8 +10,10 @@ If you installed Friendica in the ``path/to/friendica`` folder: 1. Unpack the new Friendica archive in ``path/to/friendica_new``. 2. Copy the following items from ``path/to/friendica`` to ``path/to/friendica_new``: * ``config/local.config.php`` - * ``proxy/`` -The following items only need to be copied if they are located inside your friendica path: + * ``proxy/`` + * ``.htaccess`` if using Apache web server + + The following items only need to be copied if they are located inside your friendica path: * your storage folder as set in **Admin -> Site -> File Upload -> Storage base path** * your item cache as set in **Admin -> Site -> Performance -> Path to item cache** * your temp folder as set in **Admin -> Site -> Advanced -> Temp path** diff --git a/doc/api.md b/doc/api.md index f3fae8201..a3ca4d244 100644 --- a/doc/api.md +++ b/doc/api.md @@ -68,8 +68,8 @@ xml: The [RSStoFriendika](https://github.com/pafcu/RSStoFriendika) code can be used as an example of how to use the API with python. The lines for posting are located at [line 21](https://github.com/pafcu/RSStoFriendika/blob/master/RSStoFriendika.py#L21) and following. -def tweet(server, message, group_allow=None): +def tweet(server, message, circle_allow=None): url = server + '/api/statuses/update' -urllib2.urlopen(url, urllib.urlencode({'status': message,'group_allow[]':group_allow}, doseq=True)) +urllib2.urlopen(url, urllib.urlencode({'status': message, 'circle_allow[]': circle_allow}, doseq=True)) There is also a [module for python 3](https://bitbucket.org/tobiasd/python-friendica) for using the API. diff --git a/doc/database.md b/doc/database.md index 461c1c2d9..284870657 100644 --- a/doc/database.md +++ b/doc/database.md @@ -30,8 +30,8 @@ Database Tables | [fetch-entry](help/database/db_fetch-entry) | | | [fetched-activity](help/database/db_fetched-activity) | Id of fetched activities | | [fsuggest](help/database/db_fsuggest) | friend suggestion stuff | -| [group](help/database/db_group) | privacy groups, group info | -| [group_member](help/database/db_group_member) | privacy groups, member info | +| [group](help/database/db_group) | privacy circles, circle info | +| [group_member](help/database/db_group_member) | privacy circles, member info | | [gserver](help/database/db_gserver) | Global servers | | [gserver-tag](help/database/db_gserver-tag) | Tags that the server has subscribed | | [hook](help/database/db_hook) | addon hook registry | @@ -77,7 +77,8 @@ Database Tables | [push_subscriber](help/database/db_push_subscriber) | Used for OStatus: Contains feed subscribers | | [register](help/database/db_register) | registrations requiring admin approval | | [report](help/database/db_report) | | -| [report-post](help/database/db_report-post) | | +| [report-post](help/database/db_report-post) | Individual posts attached to a moderation report | +| [report-rule](help/database/db_report-rule) | Terms of service rule lines relevant to a moderation report | | [search](help/database/db_search) | | | [session](help/database/db_session) | web session storage | | [storage](help/database/db_storage) | Data stored by Database storage backend | @@ -85,6 +86,7 @@ Database Tables | [tag](help/database/db_tag) | tags and mentions | | [user](help/database/db_user) | The local users | | [user-contact](help/database/db_user-contact) | User specific public contact data | +| [user-gserver](help/database/db_user-gserver) | User settings about remote servers | | [userd](help/database/db_userd) | Deleted usernames | | [verb](help/database/db_verb) | Activity Verbs | | [worker-ipc](help/database/db_worker-ipc) | Inter process communication between the frontend and the worker | diff --git a/doc/database/db_attach.md b/doc/database/db_attach.md index 76d8e01f2..38ce83a7c 100644 --- a/doc/database/db_attach.md +++ b/doc/database/db_attach.md @@ -18,9 +18,9 @@ Fields | created | creation time | datetime | NO | | 0001-01-01 00:00:00 | | | edited | last edit time | datetime | NO | | 0001-01-01 00:00:00 | | | allow_cid | Access Control - list of allowed contact.id '<19><78> | mediumtext | YES | | NULL | | -| allow_gid | Access Control - list of allowed groups | mediumtext | YES | | NULL | | +| allow_gid | Access Control - list of allowed circles | mediumtext | YES | | NULL | | | deny_cid | Access Control - list of denied contact.id | mediumtext | YES | | NULL | | -| deny_gid | Access Control - list of denied groups | mediumtext | YES | | NULL | | +| deny_gid | Access Control - list of denied circles | mediumtext | YES | | NULL | | | backend-class | Storage backend class | tinytext | YES | | NULL | | | backend-ref | Storage backend data reference | text | YES | | NULL | | diff --git a/doc/database/db_contact-relation.md b/doc/database/db_contact-relation.md index 8628b1ef6..1e9a2c41c 100644 --- a/doc/database/db_contact-relation.md +++ b/doc/database/db_contact-relation.md @@ -6,13 +6,17 @@ Contact relations Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ---------------- | --------------------------------------------------- | ------------ | ---- | --- | ------------------- | ----- | -| cid | contact the related contact had interacted with | int unsigned | NO | PRI | 0 | | -| relation-cid | related contact who had interacted with the contact | int unsigned | NO | PRI | 0 | | -| last-interaction | Date of the last interaction | datetime | NO | | 0001-01-01 00:00:00 | | -| follow-updated | Date of the last update of the contact relationship | datetime | NO | | 0001-01-01 00:00:00 | | -| follows | | boolean | NO | | 0 | | +| Field | Description | Type | Null | Key | Default | Extra | +| --------------------- | -------------------------------------------------------- | ----------------- | ---- | --- | ------------------- | ----- | +| cid | contact the related contact had interacted with | int unsigned | NO | PRI | 0 | | +| relation-cid | related contact who had interacted with the contact | int unsigned | NO | PRI | 0 | | +| last-interaction | Date of the last interaction | datetime | NO | | 0001-01-01 00:00:00 | | +| follow-updated | Date of the last update of the contact relationship | datetime | NO | | 0001-01-01 00:00:00 | | +| follows | | boolean | NO | | 0 | | +| score | score for interactions of cid on relation-cid | smallint unsigned | YES | | NULL | | +| relation-score | score for interactions of relation-cid on cid | smallint unsigned | YES | | NULL | | +| thread-score | score for interactions of cid on threads of relation-cid | smallint unsigned | YES | | NULL | | +| relation-thread-score | score for interactions of relation-cid on threads of cid | smallint unsigned | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_contact.md b/doc/database/db_contact.md index f8999054f..8221f279e 100644 --- a/doc/database/db_contact.md +++ b/doc/database/db_contact.md @@ -51,8 +51,8 @@ Fields | archive | | boolean | NO | | 0 | | | unsearchable | Contact prefers to not be searchable | boolean | NO | | 0 | | | sensitive | Contact posts sensitive content | boolean | NO | | 0 | | -| baseurl | baseurl of the contact | varbinary(383) | YES | | | | -| gsid | Global Server ID | int unsigned | YES | | NULL | | +| baseurl | baseurl of the contact from the gserver record, can be missing | varbinary(383) | YES | | | | +| gsid | Global Server ID, can be missing | int unsigned | YES | | NULL | | | bd | | date | NO | | 0001-01-01 | | | reason | | text | YES | | NULL | | | self | 1 if the contact is the user him/her self | boolean | NO | | 0 | | @@ -81,7 +81,7 @@ Fields | confirm | | varbinary(383) | YES | | NULL | | | poco | | varbinary(383) | YES | | NULL | | | writable | | boolean | NO | | 0 | | -| forum | contact is a forum. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead | boolean | NO | | 0 | | +| forum | contact is a group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead | boolean | NO | | 0 | | | prv | contact is a private group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = true instead | boolean | NO | | 0 | | | bdyear | | varchar(4) | NO | | | | | site-pubkey | Deprecated | text | YES | | NULL | | diff --git a/doc/database/db_event.md b/doc/database/db_event.md index 499e550c4..c7daea987 100644 --- a/doc/database/db_event.md +++ b/doc/database/db_event.md @@ -25,9 +25,9 @@ Fields | nofinish | if event does have no end this is 1 | boolean | NO | | 0 | | | ignore | 0 or 1 | boolean | NO | | 0 | | | allow_cid | Access Control - list of allowed contact.id '<19><78>' | mediumtext | YES | | NULL | | -| allow_gid | Access Control - list of allowed groups | mediumtext | YES | | NULL | | +| allow_gid | Access Control - list of allowed circles | mediumtext | YES | | NULL | | | deny_cid | Access Control - list of denied contact.id | mediumtext | YES | | NULL | | -| deny_gid | Access Control - list of denied groups | mediumtext | YES | | NULL | | +| deny_gid | Access Control - list of denied circles | mediumtext | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_group.md b/doc/database/db_group.md index ad7fa4a3d..f717247ad 100644 --- a/doc/database/db_group.md +++ b/doc/database/db_group.md @@ -1,7 +1,7 @@ Table group =========== -privacy groups, group info +privacy circles, circle info Fields ------ @@ -11,9 +11,9 @@ Fields | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | uid | Owner User id | mediumint unsigned | NO | | 0 | | | visible | 1 indicates the member list is not private | boolean | NO | | 0 | | -| deleted | 1 indicates the group has been deleted | boolean | NO | | 0 | | -| cid | Contact id of forum. When this field is filled then the members are synced automatically. | int unsigned | YES | | NULL | | -| name | human readable name of group | varchar(255) | NO | | | | +| deleted | 1 indicates the circle has been deleted | boolean | NO | | 0 | | +| cid | Contact id of group. When this field is filled then the members are synced automatically. | int unsigned | YES | | NULL | | +| name | human readable name of circle | varchar(255) | NO | | | | Indexes ------------ diff --git a/doc/database/db_group_member.md b/doc/database/db_group_member.md index a544f3b0e..efe83e4ae 100644 --- a/doc/database/db_group_member.md +++ b/doc/database/db_group_member.md @@ -1,16 +1,16 @@ Table group_member =========== -privacy groups, member info +privacy circles, member info Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ---------- | --------------------------------------------------------- | ------------ | ---- | --- | ------- | -------------- | -| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | -| gid | groups.id of the associated group | int unsigned | NO | | 0 | | -| contact-id | contact.id of the member assigned to the associated group | int unsigned | NO | | 0 | | +| Field | Description | Type | Null | Key | Default | Extra | +| ---------- | ---------------------------------------------------------- | ------------ | ---- | --- | ------- | -------------- | +| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | +| gid | group.id of the associated circle | int unsigned | NO | | 0 | | +| contact-id | contact.id of the member assigned to the associated circle | int unsigned | NO | | 0 | | Indexes ------------ diff --git a/doc/database/db_permissionset.md b/doc/database/db_permissionset.md index 38c6fe8f3..82059b2f3 100644 --- a/doc/database/db_permissionset.md +++ b/doc/database/db_permissionset.md @@ -11,9 +11,9 @@ Fields | id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | | uid | Owner id of this permission set | mediumint unsigned | NO | | 0 | | | allow_cid | Access Control - list of allowed contact.id '<19><78>' | mediumtext | YES | | NULL | | -| allow_gid | Access Control - list of allowed groups | mediumtext | YES | | NULL | | +| allow_gid | Access Control - list of allowed circles | mediumtext | YES | | NULL | | | deny_cid | Access Control - list of denied contact.id | mediumtext | YES | | NULL | | -| deny_gid | Access Control - list of denied groups | mediumtext | YES | | NULL | | +| deny_gid | Access Control - list of denied circles | mediumtext | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_photo.md b/doc/database/db_photo.md index ed417f614..c41e913ca 100644 --- a/doc/database/db_photo.md +++ b/doc/database/db_photo.md @@ -30,9 +30,9 @@ Fields | scale | | tinyint unsigned | NO | | 0 | | | profile | | boolean | NO | | 0 | | | allow_cid | Access Control - list of allowed contact.id '<19><78>' | mediumtext | YES | | NULL | | -| allow_gid | Access Control - list of allowed groups | mediumtext | YES | | NULL | | +| allow_gid | Access Control - list of allowed circles | mediumtext | YES | | NULL | | | deny_cid | Access Control - list of denied contact.id | mediumtext | YES | | NULL | | -| deny_gid | Access Control - list of denied groups | mediumtext | YES | | NULL | | +| deny_gid | Access Control - list of denied circles | mediumtext | YES | | NULL | | | accessible | Make photo publicly accessible, ignoring permissions | boolean | NO | | 0 | | | backend-class | Storage backend class | tinytext | YES | | NULL | | | backend-ref | Storage backend data reference | text | YES | | NULL | | diff --git a/doc/database/db_profile.md b/doc/database/db_profile.md index ec47b94ec..c4a8b0170 100644 --- a/doc/database/db_profile.md +++ b/doc/database/db_profile.md @@ -13,7 +13,7 @@ Fields | profile-name | Deprecated | varchar(255) | YES | | NULL | | | is-default | Deprecated | boolean | YES | | NULL | | | hide-friends | Hide friend list from viewers of this profile | boolean | NO | | 0 | | -| name | | varchar(255) | NO | | | | +| name | Unused in favor of user.username | varchar(255) | NO | | | | | pdesc | Deprecated | varchar(255) | YES | | NULL | | | dob | Day of birth | varchar(32) | NO | | 0000-00-00 | | | address | | varchar(255) | NO | | | | diff --git a/doc/database/db_report-post.md b/doc/database/db_report-post.md index fcaff6c2e..d005b31e3 100644 --- a/doc/database/db_report-post.md +++ b/doc/database/db_report-post.md @@ -1,7 +1,7 @@ Table report-post =========== - +Individual posts attached to a moderation report Fields ------ diff --git a/doc/database/db_report-rule.md b/doc/database/db_report-rule.md new file mode 100644 index 000000000..f82d757eb --- /dev/null +++ b/doc/database/db_report-rule.md @@ -0,0 +1,29 @@ +Table report-rule +=========== + +Terms of service rule lines relevant to a moderation report + +Fields +------ + +| Field | Description | Type | Null | Key | Default | Extra | +| ------- | ------------------------------------------------------------------------- | ------------ | ---- | --- | ------- | ----- | +| rid | Report id | int unsigned | NO | PRI | NULL | | +| line-id | Terms of service rule line number, may become invalid after a TOS change. | int unsigned | NO | PRI | NULL | | +| text | Terms of service rule text recorded at the time of the report | text | NO | | NULL | | + +Indexes +------------ + +| Name | Fields | +| ------- | ------------ | +| PRIMARY | rid, line-id | + +Foreign Keys +------------ + +| Field | Target Table | Target Field | +|-------|--------------|--------------| +| rid | [report](help/database/db_report) | id | + +Return to [database documentation](help/database) diff --git a/doc/database/db_report.md b/doc/database/db_report.md index 92c0cced3..c2890e25a 100644 --- a/doc/database/db_report.md +++ b/doc/database/db_report.md @@ -6,28 +6,40 @@ Table report Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ----------- | ----------------------------------------------- | ------------------ | ---- | --- | ------------------- | -------------- | -| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | -| uid | Reporting user | mediumint unsigned | YES | | NULL | | -| reporter-id | Reporting contact | int unsigned | YES | | NULL | | -| cid | Reported contact | int unsigned | NO | | NULL | | -| comment | Report | text | YES | | NULL | | -| category | Category of the report (spam, violation, other) | varchar(20) | YES | | NULL | | -| rules | Violated rules | text | YES | | NULL | | -| forward | Forward the report to the remote server | boolean | YES | | NULL | | -| created | | datetime | NO | | 0001-01-01 00:00:00 | | -| status | Status of the report | tinyint unsigned | YES | | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| --------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------------------- | -------------- | +| id | sequential ID | int unsigned | NO | PRI | NULL | auto_increment | +| uid | Reporting user | mediumint unsigned | YES | | NULL | | +| reporter-id | Reporting contact | int unsigned | YES | | NULL | | +| cid | Reported contact | int unsigned | NO | | NULL | | +| gsid | Reported contact server | int unsigned | YES | | NULL | | +| comment | Report | text | YES | | NULL | | +| category-id | Report category, one of Entity\Report::CATEGORY_* | int unsigned | NO | | 1 | | +| forward | Forward the report to the remote server | boolean | YES | | NULL | | +| public-remarks | Remarks shared with the reporter | text | YES | | NULL | | +| private-remarks | Remarks shared with the moderation team | text | YES | | NULL | | +| last-editor-uid | Last editor user | mediumint unsigned | YES | | NULL | | +| assigned-uid | Assigned moderator user | mediumint unsigned | YES | | NULL | | +| status | Status of the report, one of Entity\Report::STATUS_* | tinyint unsigned | NO | | NULL | | +| resolution | Resolution of the report, one of Entity\Report::RESOLUTION_* | tinyint unsigned | YES | | NULL | | +| created | | datetime(6) | NO | | 0001-01-01 00:00:00 | | +| edited | Last time the report has been edited | datetime(6) | YES | | NULL | | Indexes ------------ -| Name | Fields | -| ----------- | ----------- | -| PRIMARY | id | -| uid | uid | -| cid | cid | -| reporter-id | reporter-id | +| Name | Fields | +| ----------------- | ------------------ | +| PRIMARY | id | +| uid | uid | +| cid | cid | +| reporter-id | reporter-id | +| gsid | gsid | +| last-editor-uid | last-editor-uid | +| assigned-uid | assigned-uid | +| status-resolution | status, resolution | +| created | created | +| edited | edited | Foreign Keys ------------ @@ -37,5 +49,8 @@ Foreign Keys | uid | [user](help/database/db_user) | uid | | reporter-id | [contact](help/database/db_contact) | id | | cid | [contact](help/database/db_contact) | id | +| gsid | [gserver](help/database/db_gserver) | id | +| last-editor-uid | [user](help/database/db_user) | uid | +| assigned-uid | [user](help/database/db_user) | uid | Return to [database documentation](help/database) diff --git a/doc/database/db_user-contact.md b/doc/database/db_user-contact.md index 71fdc14e4..ac89aab1d 100644 --- a/doc/database/db_user-contact.md +++ b/doc/database/db_user-contact.md @@ -6,28 +6,28 @@ User specific public contact data Fields ------ -| Field | Description | Type | Null | Key | Default | Extra | -| ------------------------- | ------------------------------------------------------------ | ------------------ | ---- | --- | ------- | ----- | -| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | | -| uid | User id | mediumint unsigned | NO | PRI | 0 | | -| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | | -| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | | -| ignored | Posts from this contact are ignored | boolean | YES | | NULL | | -| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | | -| hidden | This contact is hidden from the others | boolean | YES | | NULL | | -| is-blocked | User is blocked by this contact | boolean | YES | | NULL | | -| pending | | boolean | YES | | NULL | | -| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | | -| info | | mediumtext | YES | | NULL | | -| notify_new_posts | | boolean | YES | | NULL | | -| remote_self | | boolean | YES | | NULL | | -| fetch_further_information | | tinyint unsigned | YES | | NULL | | -| ffi_keyword_denylist | | text | YES | | NULL | | -| subhub | | boolean | YES | | NULL | | -| hub-verify | | varbinary(383) | YES | | NULL | | -| protocol | Protocol of the contact | char(4) | YES | | NULL | | -| rating | Automatically detected feed poll frequency | tinyint | YES | | NULL | | -| priority | Feed poll priority | tinyint unsigned | YES | | NULL | | +| Field | Description | Type | Null | Key | Default | Extra | +| ------------------------- | ----------------------------------------------------------------------- | ------------------ | ---- | --- | ------- | ----- | +| cid | Contact id of the linked public contact | int unsigned | NO | PRI | 0 | | +| uid | User id | mediumint unsigned | NO | PRI | 0 | | +| uri-id | Id of the item-uri table entry that contains the contact url | int unsigned | YES | | NULL | | +| blocked | Contact is completely blocked for this user | boolean | YES | | NULL | | +| ignored | Posts from this contact are ignored | boolean | YES | | NULL | | +| collapsed | Posts from this contact are collapsed | boolean | YES | | NULL | | +| hidden | This contact is hidden from the others | boolean | YES | | NULL | | +| is-blocked | User is blocked by this contact | boolean | YES | | NULL | | +| pending | | boolean | YES | | NULL | | +| rel | The kind of the relation between the user and the contact | tinyint unsigned | YES | | NULL | | +| info | | mediumtext | YES | | NULL | | +| notify_new_posts | | boolean | YES | | NULL | | +| remote_self | 0 => No mirroring, 1-2 => Mirror as own post, 3 => Mirror as reshare | tinyint unsigned | YES | | NULL | | +| fetch_further_information | 0 => None, 1 => Fetch information, 3 => Fetch keywords, 2 => Fetch both | tinyint unsigned | YES | | NULL | | +| ffi_keyword_denylist | | text | YES | | NULL | | +| subhub | | boolean | YES | | NULL | | +| hub-verify | | varbinary(383) | YES | | NULL | | +| protocol | Protocol of the contact | char(4) | YES | | NULL | | +| rating | Automatically detected feed poll frequency | tinyint | YES | | NULL | | +| priority | Feed poll priority | tinyint unsigned | YES | | NULL | | Indexes ------------ diff --git a/doc/database/db_user-gserver.md b/doc/database/db_user-gserver.md new file mode 100644 index 000000000..6cfbe34eb --- /dev/null +++ b/doc/database/db_user-gserver.md @@ -0,0 +1,31 @@ +Table user-gserver +=========== + +User settings about remote servers + +Fields +------ + +| Field | Description | Type | Null | Key | Default | Extra | +| ------- | ---------------------------------------- | ------------------ | ---- | --- | ------- | ----- | +| uid | Owner User id | mediumint unsigned | NO | | 0 | | +| gsid | Gserver id | int unsigned | NO | | 0 | | +| ignored | server accounts are ignored for the user | boolean | NO | | 0 | | + +Indexes +------------ + +| Name | Fields | +| ------- | --------- | +| PRIMARY | uid, gsid | +| gsid | gsid | + +Foreign Keys +------------ + +| Field | Target Table | Target Field | +|-------|--------------|--------------| +| uid | [user](help/database/db_user) | uid | +| gsid | [gserver](help/database/db_gserver) | id | + +Return to [database documentation](help/database) diff --git a/doc/de/Account-Basics.md b/doc/de/Account-Basics.md index 81ce68c04..ef7ca4e63 100644 --- a/doc/de/Account-Basics.md +++ b/doc/de/Account-Basics.md @@ -9,14 +9,14 @@ Account - Basics Viele, aber nicht alle Friendica-Knoten (Server) bieten die Möglichkeit zur Registrierung an. Falls der Friendica-Knoten, den Du besuchst, keine Registrierung anbietet, oder Du glaubst, dass Dir ein anderer Knoten möglicherweise besser gefällt, dann findest Du hier eine [Liste von öffentlichen Friendica-Knoten](https://dir.friendica.social/servers), aus der Du Dir eine netten Knoten heraussuchen kannst. -Auf der Startseite des Knotens wird unter dem Login-Feld ein "Registrieren"-Link angezeigt. -Dieser Link führt dann direkt auf das Registrierungsformular. +Auf der Startseite des Knotens wird unter dem Login-Feld ein "Registrieren"-Link angezeigt. +Dieser Link führt dann direkt auf das Registrierungsformular. ### OpenID Falls du keine [OpenID-Adresse](https://de.wikipedia.org/wiki/OpenID">OpenID-Adresse) hast, kannst du diesen Punkt ignorieren. -Solltest du eine OpenID Adresse haben, kannst Du sie im ersten Feld eintragen und "Registrieren" klicken. +Solltest du eine OpenID Adresse haben, kannst Du sie im ersten Feld eintragen und "Registrieren" klicken. Friendica wird versuchen, so viele Informationen wie möglich von Deinem OpenID-Provider zu übernehmen, um diese in Dein Profil auf dieser Seite einzutragen. @@ -33,55 +33,55 @@ Bitte trage eine richtige Email-Adresse ein. Dies ist die einzige persönliche Information, die korrekt sein muss. Deine Email-Adresse wird **niemals** veröffentlicht. -Wir benötigen diese, um Dir Account-Informationen, das Initialpasswort und die Login-Daten zu schicken. Oder z.B. Dein Passwort zurückzusetzen. +Wir benötigen diese, um Dir Account-Informationen, das Initialpasswort und die Login-Daten zu schicken. Oder z.B. Dein Passwort zurückzusetzen. Du erhältst zudem von Zeit zu Zeit Benachrichtigungen über eingegangene Nachrichten oder Punkte, die Deine Aufmerksamkeit benötigen. Diese Nachrichten sind in den Einstellungen jederzeit an- oder abschaltbar. ### Spitzname/Nickname -Der Spitzname wird benötigt, um eine Webadresse (Profiladresse) für viele Deiner persönlichen Seiten zu erstellen. -Auch wird dieser wie eine Email-Adresse genutzt, wenn eine Verbindung zu anderen Personen hergestellt werden soll. -Durch die Art, wie der Spitzname genutzt wird, gibt es bestimmte Einschränkungen: +Der Spitzname wird benötigt, um eine Webadresse (Profiladresse) für viele Deiner persönlichen Seiten zu erstellen. +Auch wird dieser wie eine Email-Adresse genutzt, wenn eine Verbindung zu anderen Personen hergestellt werden soll. +Durch die Art, wie der Spitzname genutzt wird, gibt es bestimmte Einschränkungen: * **er muss mit einem Buchstaben beginnen** * **er darf nur US-ASCII-Textzeichen und Nummern enthalten** * **er muss einzigartig auf diesem Friendica-Knoten sein** * **er kann später nicht mehr geändert werden** -Dieser Spitzname wird an vielen Stellen genutzt, um Deinen Account zu identifizieren, daher ist es nicht möglich ihn später zu ändern. +Dieser Spitzname wird an vielen Stellen genutzt, um Deinen Account zu identifizieren, daher ist es nicht möglich ihn später zu ändern. ### Verzeichnis-Eintrag -Das Registrierungsformular erlaubt es dir, direkt auszuwählen, ob Du im [Onlineverzeichnis](https://dir.friendica.social/) (Friendica Directory) aufgelistet wirst oder nicht. -Das ist wie ein Telefonbuch und Du entscheidest, ob du darin eingetragen werden möchtest, oder nicht. +Das Registrierungsformular erlaubt es dir, direkt auszuwählen, ob Du im [Onlineverzeichnis](https://dir.friendica.social/) (Friendica Directory) aufgelistet wirst oder nicht. +Das ist wie ein Telefonbuch und Du entscheidest, ob du darin eingetragen werden möchtest, oder nicht. * Wir bitten dich, "Ja" zu wählen, damit Andere Dich finden können, so wie Du sie finden kannst -* Wählst Du "Nein", bist Du für Andere *nicht einfach auffindbar* +* Wählst Du "Nein", bist Du für Andere *nicht einfach auffindbar* Was auch immer Du wählst, kann jederzeit nach dem Login in Deinen Account-Einstellungen geändert werden. ### Registrierung -Sobald Du die nötigen Informationen eingegeben hast, klicke auf "Registrieren". -Eine Email mit den Registrierungsdetails und Deinem Initialpasswort wird an die hinterlegte Email-Adresse geschickt. +Sobald Du die nötigen Informationen eingegeben hast, klicke auf "Registrieren". +Eine Email mit den Registrierungsdetails und Deinem Initialpasswort wird an die hinterlegte Email-Adresse geschickt. Bitte prüfe den Posteingang (inkl. dem Spam-Ordner). ## Login-Seite -Gib auf der "Login"-Seite die Informationen ein, die Du mit der oben genannten Email erhalten hast. +Gib auf der "Login"-Seite die Informationen ein, die Du mit der oben genannten Email erhalten hast. Du kannst entweder Deinen Spitznamen oder die Email-Adresse als Login-Namen nutzen. Wenn Du Deinen Account nutzt, um unterschiedliche '[Seiten](help/Pages)' zu verwalten, die die gleiche Email-Adresse verwenden, dann nutze bitte den Spitznamen des Accounts, der verwaltet werden soll. -*Wenn* Dein Account OpenID nutzt, dann kannst Du Deine OpenID-Adresse als Login-Name nutzen und das Passwort-Feld frei lassen. -Du wirst zu Deinem OpenID-Anbieter weitergeleitet, wo Du Deine Anmeldung abschließt. +*Wenn* Dein Account OpenID nutzt, dann kannst Du Deine OpenID-Adresse als Login-Name nutzen und das Passwort-Feld frei lassen. +Du wirst zu Deinem OpenID-Anbieter weitergeleitet, wo Du Deine Anmeldung abschließt. -Wenn Du OpenID nicht nutzt, dann gib Dein Passwort ein, das Du mit der Registrierungsmail erhalten hast. -Das Passwort muss genau so geschrieben werden, wie es in der Email steht; Groß- und Kleinschreibung wird beachtet. +Wenn Du OpenID nicht nutzt, dann gib Dein Passwort ein, das Du mit der Registrierungsmail erhalten hast. +Das Passwort muss genau so geschrieben werden, wie es in der Email steht; Groß- und Kleinschreibung wird beachtet. Falls Du Schwierigkeiten beim Login hast, prüfe bitte, ob z. B. Deine Feststelltaste aktiv ist. @@ -90,7 +90,7 @@ Falls Du Schwierigkeiten beim Login hast, prüfe bitte, ob z. B. Deine Feststell Besuche nach Deinem ersten Login bitte die Einstellungsseite und wechsle das Passwort in eines, dass Du Dir merken kannst. -## Die ersten Schritte +## Die ersten Schritte ### Persönliche Daten exportieren @@ -98,9 +98,9 @@ Du solltest dir als erstes Deinen neu erstellen [Account exportieren](uexport) u In diesem Export (JSON-Datei) sind enthalten * Deine Identität, die mit kryptographischen Schlüsseln ausgestattet ist -* Deine Kontakte +* Deine Kontakte -Dies ist z.B. dann nützlich wenn du mit deinem Account auf einen anderen Friendica Knoten umziehen willst, oder musst. +Dies ist z.B. dann nützlich wenn du mit deinem Account auf einen anderen Friendica Knoten umziehen willst, oder musst. ### Hilfe für Neulinge @@ -109,7 +109,7 @@ Ein ['Tipp für neue Mitglieder'](newmember)-Link zeigt sich in den ersten beide ## Schau Dir ebenfalls folgende Seiten an -* [Gruppen und Privatssphäre](help/Groups-and-Privacy) +* [Circles und Privatssphäre](help/Circles-and-Privacy) * [Account löschen](help/Remove-Account) diff --git a/doc/de/Groups-and-Privacy.md b/doc/de/Circles-and-Privacy.md similarity index 66% rename from doc/de/Groups-and-Privacy.md rename to doc/de/Circles-and-Privacy.md index 4ce4d28e1..aebaff871 100644 --- a/doc/de/Groups-and-Privacy.md +++ b/doc/de/Circles-and-Privacy.md @@ -1,112 +1,112 @@ -Gruppen und Privatsphäre +Circles und Privatsphäre ================== * [Zur Startseite der Hilfe](help) -Gruppen sind nur eine Ansammlung von Freunden. +Circles sind nur eine Ansammlung von Freunden. Aber Friendica nutzt diese, um sehr mächtige Features zur Verfügung zu stellen. -**Gruppen erstellen** +**Circles erstellen** -Um eine Gruppe zu erstellen, besuche deine "Kontakte"-Seite und wähle "Neue Gruppe erstellen" (je nach Design nur als Pluszeichen angezeigt). -Gib deiner Gruppe einen Namen. +Um eine Circle zu erstellen, besuche deine "Kontakte"-Seite und wähle "Neue Circle erstellen" (je nach Design nur als Pluszeichen angezeigt). +Gib deiner Circle einen Namen. -Das führt dich zu einer Seite, auf der du die Gruppenmitglieder auswählen kannst. +Das führt dich zu einer Seite, auf der du die Gruppenmitglieder auswählen kannst. -Du hast zwei Boxen auf der Seite. -Die obere Box ist die Übersicht der aktuellen Mitglieder. -Die untere beinhaltet alle Freunde, die *nicht* Mitglied dieser Gruppe sind. +Du hast zwei Boxen auf der Seite. +Die obere Box ist die Übersicht der aktuellen Mitglieder. +Die untere beinhaltet alle Freunde, die *nicht* Mitglied dieser Circle sind. -Wenn du auf das Foto einer Person klickst, die nicht in der Gruppe ist, wird diese in die Gruppe verschoben. -Wenn du auf das Foto einer Person klickst, die bereits in der Gruppe ist, dann wird diese Person daraus entfernt. +Wenn du auf das Foto einer Person klickst, die nicht in der Circle ist, wird diese in die Circle verschoben. +Wenn du auf das Foto einer Person klickst, die bereits in der Circle ist, dann wird diese Person daraus entfernt. **Zugriffskontrolle** -Sobald du eine Gruppe erstellt hast, kannst du diese auf jeder Zugriffsrechteliste nutzen. -Damit ist das kleine Schloss neben deinem Statuseditor auf deiner Startseite gemeint. -Wenn du darauf klickst, kannst du auswählen, wer deinen Beitrag sehen kann und wer *nicht*. -Dabei kann es sich um eine einzelne Person oder eine ganze Gruppe handeln. +Sobald du eine Circle erstellt hast, kannst du diese auf jeder Zugriffsrechteliste nutzen. +Damit ist das kleine Schloss neben deinem Statuseditor auf deiner Startseite gemeint. +Wenn du darauf klickst, kannst du auswählen, wer deinen Beitrag sehen kann und wer *nicht*. +Dabei kann es sich um eine einzelne Person oder eine ganze Circle handeln. -Auf deiner "Netzwerk"-Seite ("Unterhaltungen deiner Kontakte") findest du Beiträge und Gespräche aller deiner Kontakte in deinem Netzwerk. -Du kannst aber auch eine einzelne Gruppe auswählen und nur Beiträge dieser Gruppenmitglieder anzeigen lassen. +Auf deiner "Netzwerk"-Seite ("Unterhaltungen deiner Kontakte") findest du Beiträge und Gespräche aller deiner Kontakte in deinem Netzwerk. +Du kannst aber auch eine einzelne Circle auswählen und nur Beiträge dieser Gruppenmitglieder anzeigen lassen. Aber stopp, es gibt noch mehr... -Wenn du auf deiner "Netzwerk"-Seite eine bestimmte Gruppe ausgewählt hast, dann findest du im Statuseditor neben dem Schloss ein Ausrufezeichen. -Dies dient dazu, deine Aufmerksamkeit auf das Schloss zu richten. -Klicke auf das Schloss. -Dort siehst du, dass dein Status-Update in dieser Ansicht standardmäßig nur für diese Gruppe freigegeben ist. -Das hilft dir, deinen zukünftigen Mitarbeitern nicht das Gleiche zu schreiben wie deinen Trinkfreunden. -Du kannst diese Einstellung natürlich auch überschreiben. +Wenn du auf deiner "Netzwerk"-Seite eine bestimmte Circle ausgewählt hast, dann findest du im Statuseditor neben dem Schloss ein Ausrufezeichen. +Dies dient dazu, deine Aufmerksamkeit auf das Schloss zu richten. +Klicke auf das Schloss. +Dort siehst du, dass dein Status-Update in dieser Ansicht standardmäßig nur für diese Circle freigegeben ist. +Das hilft dir, deinen zukünftigen Mitarbeitern nicht das Gleiche zu schreiben wie deinen Trinkfreunden. +Du kannst diese Einstellung natürlich auch überschreiben. **Standardmäßige Zugriffsrechte von Beiträgen** -Standardmäßig geht Friendica davon aus, dass alle deine Beiträge privat sein sollen. -Aus diesem Grund erstellt Friendica nach der Anmeldung eine Gruppe, in die automatisch alle deine Kontakte hinzugefügt werden. -Alle deine Beiträge sind nur auf diese Gruppe beschränkt. +Standardmäßig geht Friendica davon aus, dass alle deine Beiträge privat sein sollen. +Aus diesem Grund erstellt Friendica nach der Anmeldung eine Circle, in die automatisch alle deine Kontakte hinzugefügt werden. +Alle deine Beiträge sind nur auf diese Circle beschränkt. Beachte, dass diese Einstellung von deinem Seiten-Administrator überschrieben werden kann, was bedeutet, dass alle deine Beiträge standardmäßig "öffentlich" sind (bspw. für das gesamte Internet). -Wenn du deine Beiträge standardmäßig "öffentlich" haben willst, dann kannst du deine Standardzugriffsrechte auf deiner Einstellungseite ändern. -Dort kannst du außerdem festlegen, welchen Gruppen standardmäßig deine Beiträge erhalten oder in welche Gruppe deine neuen Kontakte standardmäßig eingeordnet werden. +Wenn du deine Beiträge standardmäßig "öffentlich" haben willst, dann kannst du deine Standardzugriffsrechte auf deiner Einstellungseite ändern. +Dort kannst du außerdem festlegen, welchen Circles standardmäßig deine Beiträge erhalten oder in welche Circle deine neuen Kontakte standardmäßig eingeordnet werden. **Fragen der Privatssphäre, die zu beachten sind** -Diese privaten Gespräche funktionieren am besten, wenn deine Freunde Friendica-Mitglieder sind. +Diese privaten Gespräche funktionieren am besten, wenn deine Freunde Friendica-Mitglieder sind. So wissen wir, wer sonst noch deine Gespräche sehen kann - niemand, *solange* deine Freunde deine Nachrichten nicht kopieren und an andere verschicken. -Dies ist eine Vertrauensfrage, die du beachten musst. -Keine Software der Welt kann deine Freunde davon abhalten, die privaten Unterhaltungen zu veröffentlichen. -Nur eine gute Auswahl deiner Freunde. +Dies ist eine Vertrauensfrage, die du beachten musst. +Keine Software der Welt kann deine Freunde davon abhalten, die privaten Unterhaltungen zu veröffentlichen. +Nur eine gute Auswahl deiner Freunde. -Bei GNu Social und anderen Netzwerk-Anbietern ist es nicht so gesichert. -Du musst **sehr** vorsichtig sein, wenn du Mitglieder anderer Netzwerke in einer deiner Gruppen hast, da es möglich ist, dass deine privaten Nachrichten in einem öffentlichen Stream enden. +Bei GNu Social und anderen Netzwerk-Anbietern ist es nicht so gesichert. +Du musst **sehr** vorsichtig sein, wenn du Mitglieder anderer Netzwerke in einer deiner Circles hast, da es möglich ist, dass deine privaten Nachrichten in einem öffentlichen Stream enden. Wenn du auf die "Kontakt bearbeiten"-Seite einer Person gehst, zeigen wir dir, ob sie Mitglied eines unsicheren Netzwerks ist oder nicht. -Sobald du einen Post erstellt hast, kannst du die Zugriffsrechte nicht mehr ändern. -Innerhalb von Sekunden ist dieser an viele verschiedene Personen verschickt worden - möglicherweise bereits an alle Addressierten. -Wenn du versehentlich eine Nachricht erstellt hast und sie zurücknehmen willst, dann ist es das beste, diese zu löschen. -Wir senden eine Löschmitteilung an jeden, der deine Nachricht erhalten hat - und das sollte die Nachricht genauso schnell löschen, wie sie zunächst erstellt wurde. -In vielen Fällen wird sie in weniger als einer Minute aus dem Internet gelöscht. -Nochmals: das gilt für Friendica-Netzwerke. +Sobald du einen Post erstellt hast, kannst du die Zugriffsrechte nicht mehr ändern. +Innerhalb von Sekunden ist dieser an viele verschiedene Personen verschickt worden - möglicherweise bereits an alle Addressierten. +Wenn du versehentlich eine Nachricht erstellt hast und sie zurücknehmen willst, dann ist es das beste, diese zu löschen. +Wir senden eine Löschmitteilung an jeden, der deine Nachricht erhalten hat - und das sollte die Nachricht genauso schnell löschen, wie sie zunächst erstellt wurde. +In vielen Fällen wird sie in weniger als einer Minute aus dem Internet gelöscht. +Nochmals: das gilt für Friendica-Netzwerke. Sobald eine Nachricht an ein anderes Netzwerk geschickt wurde, kann es nicht mehr so schnell gelöscht werden und in manchen Fällen auch gar nicht mehr. -Wenn du das bisher noch nicht wusstest, dann empfehlen wir dir, deine Freunde dazu zu ermutigen, auch Friendica zu nutzen, da alle diese Privatsphären-Einstellungen innerhalb eines privatsphärenbewussten Netzwerk viel besser funktionieren. +Wenn du das bisher noch nicht wusstest, dann empfehlen wir dir, deine Freunde dazu zu ermutigen, auch Friendica zu nutzen, da alle diese Privatsphären-Einstellungen innerhalb eines privatsphärenbewussten Netzwerk viel besser funktionieren. Viele andere Netzwerke, mit denen sich Friendica verbinden kann, bieten keine Kontrolle über die Privatsphäre. Profile, Fotos und die Privatsphäre ============================= -Die dezentralisierte Natur von Friendica (statt eine Webseite zu haben, die alles kontrolliert, gibt es viele Webseiten, die Information austauschen) hat in der Kommunikation mit anderen Seiten einige Konsequenzen. +Die dezentralisierte Natur von Friendica (statt eine Webseite zu haben, die alles kontrolliert, gibt es viele Webseiten, die Information austauschen) hat in der Kommunikation mit anderen Seiten einige Konsequenzen. Du solltest dir über einige Dinge bewusst sein, um am besten entscheiden zu können, wie du mit deiner Privatsphäre umgehst. **Fotos** -Fotos privat zu verteilen ist ein Problem. -Wir können Fotos nur mit Friendica-Nutzern __privat__ austauschen. -Um mit anderen Leuten Fotos zu teilen, müssen wir erkennen, wer sie sind. -Wir können die Identität von Friendica-Nutzern prüfen, da es hierfür einen Mechanismus gibt. -Deine Freunde anderer Netzwerke werden deine privaten Fotos nicht sehen können, da wir deren Identität nicht überprüfen können. +Fotos privat zu verteilen ist ein Problem. +Wir können Fotos nur mit Friendica-Nutzern __privat__ austauschen. +Um mit anderen Leuten Fotos zu teilen, müssen wir erkennen, wer sie sind. +Wir können die Identität von Friendica-Nutzern prüfen, da es hierfür einen Mechanismus gibt. +Deine Freunde anderer Netzwerke werden deine privaten Fotos nicht sehen können, da wir deren Identität nicht überprüfen können. -Unsere Entwickler arbeiten an einer Lösung, um deinen Freunden den Zugriff zu ermöglichen - unabhängig, zu welchem Netzwerk sie gehören. +Unsere Entwickler arbeiten an einer Lösung, um deinen Freunden den Zugriff zu ermöglichen - unabhängig, zu welchem Netzwerk sie gehören. Wir nehmen hingegen Privatsphäre ernst und agieren nicht wie andere Netzwerke, die __nur so tun__ als ob deine Fotos privat sind, sie aber trotzdem anderen ohne Identitätsprüfung zeigen. **Profile** -Dein Profil und deine "Wall" sollen vielleicht auch von Freunden anderer Netzwerke besucht werden können. -Wenn du diese Seiten allerdings für Webbesucher sperrst, die Friendica nicht kennt, kann das auch Freunde anderer Netzwerke blockieren. +Dein Profil und deine "Wall" sollen vielleicht auch von Freunden anderer Netzwerke besucht werden können. +Wenn du diese Seiten allerdings für Webbesucher sperrst, die Friendica nicht kennt, kann das auch Freunde anderer Netzwerke blockieren. -Das kann möglicherweise ungewollte Ergebnisse produzieren, wenn du lange Statusbeiträge z.B. für Twitter oder Facebook schreibst. -Wenn Friendica einen Beitrag an diese Netzwerke schickt und nur eine bestimmte Nachrichtenlänge erlaubt ist, dann verkürzen wir diesen und erstellen einen Link, der zum Originalbeitrag führt. -Der Originallink führt zurück zu deinem Friendica-Profil. +Das kann möglicherweise ungewollte Ergebnisse produzieren, wenn du lange Statusbeiträge z.B. für Twitter oder Facebook schreibst. +Wenn Friendica einen Beitrag an diese Netzwerke schickt und nur eine bestimmte Nachrichtenlänge erlaubt ist, dann verkürzen wir diesen und erstellen einen Link, der zum Originalbeitrag führt. +Der Originallink führt zurück zu deinem Friendica-Profil. Da Friendica nicht bestätigen kann, um wen es sich handelt, kann es passieren, dass diese Leute den Beitrag nicht komplett lesen können. -Für Leute, die davon betroffen sind, schlagen wir vor, eine Zusammenfassung in Twitter-Länge zu erstellen mit mehr Details für Freunde, die den ganzen Beitrag sehen können. +Für Leute, die davon betroffen sind, schlagen wir vor, eine Zusammenfassung in Twitter-Länge zu erstellen mit mehr Details für Freunde, die den ganzen Beitrag sehen können. -Dein Profil oder deine gesamte Friendica-Seite zu blockieren, hat außerdem ernsthafte Einflüsse auf deine Kommunikation mit GNU Social-Nutzern. -Diese Netzwerke kommunizieren mit anderen über öffentliche Protokolle, die nicht authentifiziert werden. -Um deine Beiträge zu sehen, müssen diese Netzwerke deine Beiträge als "unbekannte Webbesucher" ansehen. -Wenn wir das erlauben, würde es dazu führen, das absolut jeder deine Beiträge sehen. -Und du hast Friendica so eingestellt, das nicht zuzulassen. +Dein Profil oder deine gesamte Friendica-Seite zu blockieren, hat außerdem ernsthafte Einflüsse auf deine Kommunikation mit GNU Social-Nutzern. +Diese Netzwerke kommunizieren mit anderen über öffentliche Protokolle, die nicht authentifiziert werden. +Um deine Beiträge zu sehen, müssen diese Netzwerke deine Beiträge als "unbekannte Webbesucher" ansehen. +Wenn wir das erlauben, würde es dazu führen, das absolut jeder deine Beiträge sehen. +Und du hast Friendica so eingestellt, das nicht zuzulassen. Beachte also, dass das Blockieren von unbekannten Besuchern auch dazu führen kann, dass öffentliche Netzwerke (wie GNU Social) und Newsfeed-Reader auch geblockt werden. diff --git a/doc/de/FAQ-admin.md b/doc/de/FAQ-admin.md index 14528c2d6..2441a5130 100644 --- a/doc/de/FAQ-admin.md +++ b/doc/de/FAQ-admin.md @@ -56,4 +56,4 @@ Starte dazu bitte vom Grundverzeichnis deiner Friendica Instanz folgendes Komman bin/console dbstructure update -sollten bei der Ausführung Fehler auftreten, kontaktiere bitte das [Support Forum](https://forum.friendi.ca/profile/helpers). +sollten bei der Ausführung Fehler auftreten, kontaktiere bitte die [Support Gruppe](https://forum.friendi.ca/profile/helpers). diff --git a/doc/de/FAQ.md b/doc/de/FAQ.md index 0e5f9c42f..57d5569c1 100644 --- a/doc/de/FAQ.md +++ b/doc/de/FAQ.md @@ -23,7 +23,7 @@ Wenn Du Deinen Account nicht nutzen kannst, kannst Du einen Account auf einer ö Wenn du dir keinen weiteren Friendica Account einrichten willst, kannst du auch gerne über einen der folgenden alternativen Kanäle Hilfe suchen: - * Friendica Support Forum: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) + * Friendica Support Gruppe: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) * Chats der Friendica Community (die IRC, Matrix und XMPP Räume sind mit einer Brücke verbunden) Logs dieser öffentlichen Chaträume können [hier aus dem IRC](https://gnusociarg.nsupdate.info/2021/%23friendica/) und [hier aus der Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/) gefunden werden. * XMPP: support(at)forum.friendi.ca * IRC: #friendica auf [libera.chat](https://web.libera.chat/?channels=#friendica) @@ -108,7 +108,7 @@ Zwischen der URL und dem Parameter muss ein Fragezeichen als Trennzeichen verwen Ein Beispiel: - https://social.example.com/profile/example + https://social.example.com/profile/example auf Deutsch: diff --git a/doc/de/Forums.md b/doc/de/Forums.md deleted file mode 100644 index a6ddf2efd..000000000 --- a/doc/de/Forums.md +++ /dev/null @@ -1,63 +0,0 @@ -Foren -===== - -* [Zur Startseite der Hilfe](help) - - -In Friendica kannst Du auch Foren und/oder Prominenten-Seiten erstellen. - -Jede Seite in Friendica hat einen einmaligen Spitznamen. -Das gilt für alle Seiten, unabhängig davon, ob es sich um normale Profile oder Forenseiten handelt. - -Das Erste, was Du machen musst, um ein neues Forum zu kreieren, ist einen neuen Account zu erstellen. -Bitte beachte, dass der Seitenadministrator die Registrierung neuer Accounts sperren oder an Bedingungen knüpfen kann. - -Wenn Du einen zweiten Account in einem System erstellst und die gleiche Email-Adresse oder den gleichen OpenID-Account nutzt, kannst Du Dich zukünftig nur noch mit Deinem Spitznamen anmelden. - -Gehe im neuen Account auf die "Einstellungs"-Seite und dort am Ende der Seite auf "Erweiterte Konto-/Seitentyp-Einstellungen". -Normalerweise nutzt Du "Normales Konto" für einen normalen, persönlichen Account. -Das ist die Standardeinstellung. -Gr‬uppenseiten bieten die Möglichkeit, Leute als Freund/Fan ohne Kontaktbestätigung zuzulassen. - -Die Auswahl der Einstellung, die Du wählst, hängt davon ab, wie Du mit anderen Leuten auf Deiner Seite interagieren willst. -Die "Marktschreier"-Einstellung (Soapbox) lässt den Seitenbesitzer die gesamte Kommunikation kontrollieren. -Alles was Du schreibst, geht an alle Seitennutzer, aber es gibt keine Möglichkeit, zu interagieren. -Diese Seite wird normalerweise für Ankündigungen oder die Kommunikation von Gemeinschaften genutzt. - -Die normalste Einstellung ist das "Forum-/Promi-Konto". -Diese erstellt eine Gruppenseite, in der alle Mitglieder frei miteinander interagieren können. - -Der "Automatische Freunde Seite"-Account ist typischerweise für persönliche Profile, bei denen Du alle Freundschaftsanfragen automatisch bestätigen willst. - - -**Multiple Foren verwalten** - -Wir schlagen vor, dass Du ein Gruppenforum mit der gleichen Email-Adresse und dem gleichen Passwort wie bei Deinem normalen Account nutzt. -Wenn Du das machst, findest Du einen neuen "Verwalten"-Link in der Menüleiste, über den Du einfach zwischen den Identitäten wechseln kannst. -Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus- und wieder einzuloggen. -Und das kann umständlich sein, wenn Du mehrere verschiedene Foren/Identitäten verwaltest. - -Du kannst ebenso jemanden wählen, der Dein Forum verwaltet. -Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst. -Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt. -Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Dein Forum zu verwalten. -Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten. -Bitte nutze diese Einstellung mit Vorsicht. -Delegierte haben allerdings keine Möglichkeit, grundlegende Account-Einstellungen wie das Passwort oder den Seitentypen zu ändern bzw. den Account zu löschen. - - -**Beiträge auf Community-Foren** - -Wenn Du Mitglied eines Community-Forums bist, kannst Du das Forum in einem Beitrag hinzufügen/erwähnen, wenn Du den @-Tag nutzt. -Zum Beispiel würde @Fahrrad Deinen Beitrag neben den sonst ausgewählten Nutzern an alle Nutzer schicken, die in der Gruppe "Fahrrad" sind. -Wenn Dein Beitrag privat ist, musst Du diese Gruppe explizit in den Zugriffsrechten des Beitrags auswählen **und** sie mit dem @-Tag erwähnen (was den Beitrag auf die Gruppenmitglieder erweitert). - -Zusätzlich ist es möglich, Foren mit dem Ausrufezeichen zu adressieren. -Im obigen Beispiel bedeutet dies, dass Du das Fahrrad-Forum per !Fahrrad erreichen würdest. -Der Unterschied zum @ besteht darin, dass der Beitrag auschließlich über das Forum verbreitet wird und nicht an weitere Nutzer. -Dies bedeutet auch, dass es nicht sinnvoll ist, mehrere Foren per ! in einem Beitrag zu adressieren, da nur eines der Foren den Beitrag verbreiten wird. - -Du kannst außerdem via "Wall zu Wall" einen Beitrag auf der Community-Seite bzw. in dem Community-Forum erstellen. - -Kommentare, die Du an ein Community-Forum schickst, werden dem Originalbeitrag hinzugefügt. -Ein weiteres Forum mit dem @-Tag zu erwähnen, leitet den Beitrag nicht an dieses weiter, da die Verteilung der Kommentare komplett vom Originalbeitrag bestimmt wird. diff --git a/doc/de/Groups.md b/doc/de/Groups.md new file mode 100644 index 000000000..52455cfa7 --- /dev/null +++ b/doc/de/Groups.md @@ -0,0 +1,63 @@ +Gruppen +===== + +* [Zur Startseite der Hilfe](help) + + +In Friendica kannst Du auch Gruppen und/oder Prominenten-Seiten erstellen. + +Jede Seite in Friendica hat einen einmaligen Spitznamen. +Das gilt für alle Seiten, unabhängig davon, ob es sich um normale Profile oder Forenseiten handelt. + +Das Erste, was Du machen musst, um eine neue Gruppe zu kreieren, ist einen neuen Account zu erstellen. +Bitte beachte, dass der Seitenadministrator die Registrierung neuer Accounts sperren oder an Bedingungen knüpfen kann. + +Wenn Du einen zweiten Account in einem System erstellst und die gleiche Email-Adresse oder den gleichen OpenID-Account nutzt, kannst Du Dich zukünftig nur noch mit Deinem Spitznamen anmelden. + +Gehe im neuen Account auf die "Einstellungs"-Seite und dort am Ende der Seite auf "Erweiterte Konto-/Seitentyp-Einstellungen". +Normalerweise nutzt Du "Normales Konto" für einen normalen, persönlichen Account. +Das ist die Standardeinstellung. +Gruppenseiten bieten die Möglichkeit, Leute als Freund/Fan ohne Kontaktbestätigung zuzulassen. + +Die Auswahl der Einstellung, die Du wählst, hängt davon ab, wie Du mit anderen Leuten auf Deiner Seite interagieren willst. +Die "Marktschreier"-Einstellung (Soapbox) lässt den Seitenbesitzer die gesamte Kommunikation kontrollieren. +Alles was Du schreibst, geht an alle Seitennutzer, aber es gibt keine Möglichkeit, zu interagieren. +Diese Seite wird normalerweise für Ankündigungen oder die Kommunikation von Gemeinschaften genutzt. + +Die normalste Einstellung ist das "Gruppe-/Promi-Konto". +Diese erstellt eine Gruppenseite, in der alle Mitglieder frei miteinander interagieren können. + +Der "Automatische Freunde Seite"-Account ist typischerweise für persönliche Profile, bei denen Du alle Freundschaftsanfragen automatisch bestätigen willst. + + +**Multiple Gruppen verwalten** + +Wir schlagen vor, dass Du eine Gruppe mit der gleichen Email-Adresse und dem gleichen Passwort wie bei Deinem normalen Account nutzt. +Wenn Du das machst, findest Du einen neuen "Verwalten"-Link in der Menüleiste, über den Du einfach zwischen den Identitäten wechseln kannst. +Du musst das nicht machen, die Alternative ist allerdings, Dich immer wieder aus- und wieder einzuloggen. +Und das kann umständlich sein, wenn Du mehrere verschiedene Gruppen/Identitäten verwaltest. + +Du kannst ebenso jemanden wählen, der Deine Gruppe verwaltet. +Mach das, indem Du die [Delegations-Setup-Seite](/settings/delegation) besuchst. +Dort wird Dir eine Liste an "Potentiellen Bevollmächtigen" angezeigt. +Die Auswahl einer oder mehrerer Personen gibt diesen die Möglichkeit, Deine Gruppe zu verwalten. +Sie können Kontakte, Profile und alle Inhalte Deines Accounts/deiner Seite bearbeiten. +Bitte nutze diese Einstellung mit Vorsicht. +Delegierte haben allerdings keine Möglichkeit, grundlegende Account-Einstellungen wie das Passwort oder den Seitentypen zu ändern bzw. den Account zu löschen. + + +**Beiträge auf Community-Gruppen** + +Wenn Du Mitglied einer Community-Gruppen bist, kannst Du die Gruppe in einem Beitrag hinzufügen/erwähnen, wenn Du die @-Erwähnung nutzt. +Zum Beispiel würde @Fahrrad Deinen Beitrag neben den sonst ausgewählten Nutzern an alle Nutzer schicken, die in der Gruppe "Fahrrad" sind. +Wenn Dein Beitrag privat ist, musst Du diese Gruppe explizit in den Zugriffsrechten des Beitrags auswählen **und** sie mit der @-Erwähnung ansprechen (was den Beitrag auf die Gruppenmitglieder erweitert). + +Zusätzlich ist es möglich, Gruppen mit einem Ausrufezeichen zu adressieren. +Im obigen Beispiel bedeutet dies, dass Du das Fahrrad-Gruppe per !Fahrrad erreichen würdest. +Der Unterschied zum @ besteht darin, dass der Beitrag auschließlich über die Gruppe verbreitet wird und nicht an weitere Nutzer. +Dies bedeutet auch, dass es nicht sinnvoll ist, mehrere Gruppen per ! in einem Beitrag zu adressieren, da nur eine der Gruppen den Beitrag verbreiten wird. + +Du kannst außerdem via "Wall zu Wall" einen Beitrag auf der Community-Seite bzw. in der Community-Gruppe erstellen. + +Kommentare, die Du an eine Community-Gruppe schickst, werden dem Originalbeitrag hinzugefügt. +Eine weitere Gruppe mit dem @-Erwähnung anzusprechen, leitet den Beitrag nicht an dieses weiter, da die Verteilung der Kommentare komplett vom Originalbeitrag bestimmt wird. diff --git a/doc/de/Home.md b/doc/de/Home.md index 437208bbb..91976bb28 100644 --- a/doc/de/Home.md +++ b/doc/de/Home.md @@ -14,9 +14,9 @@ Friendica - Dokumentation und Ressourcen * Du und andere Nutzer * [Konnektoren (Connectors)](help/Connectors) * [Freunde finden](help/Making-Friends) - * [Gruppen und Privatsphäre](help/Groups-and-Privacy) + * [Circles und Privatsphäre](help/Circles-and-Privacy) * [Tags und Erwähnungen](help/Tags-and-Mentions) - * [Community-Foren](help/Forums) + * [Community-Gruppen](help/Groups) * [Chats](help/Chats) * Weiterführende Informationen * [Account umziehen](help/Move-Account) @@ -63,7 +63,7 @@ Friendica - Dokumentation und Ressourcen * [Haupt-Webseite](https://friendi.ca) * Support Kanäle - * Friendica Support Forum: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) + * Friendica Support Gruppe: [@helpers@forum.friendi.ca](https://forum.friendi.ca/~helpers) * [Mailing Listen Archiv](http://mailman.friendi.ca/mailman/listinfo/support-friendi.ca) zum Abonnieren der Liste eine E-Mail an ``support-request(at)friendi.ca?subject=subscribe`` senden * Chats der Friendica Community (die IRC, Matrix und XMPP Räume sind mit einer Brücke verbunden) Logs dieser öffentlichen Chaträume können [hier aus dem IRC](https://gnusociarg.nsupdate.info/2021/%23frie) und [hier aus der Matrix](https://view.matrix.org/alias/%23friendi.ca:matrix.org/) gefunden werden. * XMPP/Jabber MUC: support(at)forum.friendi.ca diff --git a/doc/de/Install.md b/doc/de/Install.md index 94ca08a2b..304023013 100644 --- a/doc/de/Install.md +++ b/doc/de/Install.md @@ -12,7 +12,7 @@ Diese Funktionalität benötigt ein wenig mehr als die normalen Blogs. Nicht jeder PHP/MySQL-Hosting-Anbieter kann Friendica unterstützen. Viele hingegen können es. Aber **bitte** prüfe die Voraussetzungen deines Servers vor der Installation. -Wenn dir Fehler während der Installation auffallen, sag uns bitte über [Helper](http://forum.friendi.ca/profile/helpers) oder das [Entwickler Forum](https://forum.friendi.ca/profile/developers) Bescheid oder [erstelle ein Issue](https://github.com/friendica/friendica/issues). +Wenn dir Fehler während der Installation auffallen, sag uns bitte über [Helper](http://forum.friendi.ca/profile/helpers) oder die [Entwickler Gruppe](https://forum.friendi.ca/profile/developers) Bescheid oder [erstelle ein Issue](https://github.com/friendica/friendica/issues). Gib uns bitte so viele Infos zu deinem System, wie du kannst, und beschreibe den Fehler mit allen Details und Fehlermeldungen, so dass wir den Fehler zukünftig verhindern können. Aufgrund der großen Anzahl an verschiedenen Betriebssystemen und PHP-Plattformen haben wir nur geringe Kapazitäten, um deine PHP-Installation zu debuggen oder fehlende Module zu ersetzen, aber wir tun unser Bestes, um allgemeine Code-Fehler zu beheben. @@ -182,7 +182,7 @@ Sie werden stattdessen direkt in `config/local.config.php` gespeichert. Gehe im Anschluss in den Friendica-Hauptordner und führe den Kommandozeilen Befehl aus: bin/console autoinstall [--savedb] - + #### B.3: Optionen Alle Optionen werden in `config/local.config.php` gespeichert und überschreiben etwaige, zugehörige Umgebungsvariablen. diff --git a/doc/de/Making-Friends.md b/doc/de/Making-Friends.md index b9ff78761..041365103 100644 --- a/doc/de/Making-Friends.md +++ b/doc/de/Making-Friends.md @@ -3,75 +3,75 @@ Freunde finden * [Zur Startseite der Hilfe](help) -Freundschaft kann in Friendica viele verschiedene Bedeutungen annehmen. -Aber lasst es uns einfach halten, du willst einfach mit jemandem befreundet sein. +Freundschaft kann in Friendica viele verschiedene Bedeutungen annehmen. +Aber lasst es uns einfach halten, du willst einfach mit jemandem befreundet sein. Wie machst du das? -Schau dir das Verzeichnis an. -Das Verzeichnis ist in zwei Teile aufgeteilt. -Wenn du auf den "Verzeichnis"-Button klickst, wirst du zunächst alle Mitglieder deines Servers sehen, die sich dazu entschlossen haben, angezeigt zu werden. -Außerdem siehst du dort einen Link zum globalen Verzeichnis. -Wenn du dich durch das globale Verzeichnis klickst, siehst du alle Nutzer weltweit auf allen Servern, die sich entschlossen haben, im Verzeichnis zu erscheinen. -Du wirst außerdem den Link "Show Community Forums" sehen, welcher dich zu Gruppen, Foren und Fan-Seiten führt. -Du verbindest dich mit Personen, Gruppen und Foren auf die gleiche Art, wobei Gruppen und Foren deine Anfrage automatisch annehmen, wohingegen ein Mensch dich erst manuell bestätigen muss. +Schau dir das Verzeichnis an. +Das Verzeichnis ist in zwei Teile aufgeteilt. +Wenn du auf den "Verzeichnis"-Button klickst, wirst du zunächst alle Mitglieder deines Servers sehen, die sich dazu entschlossen haben, angezeigt zu werden. +Außerdem siehst du dort einen Link zum globalen Verzeichnis. +Wenn du dich durch das globale Verzeichnis klickst, siehst du alle Nutzer weltweit auf allen Servern, die sich entschlossen haben, im Verzeichnis zu erscheinen. +Du wirst außerdem den Link "Show Community Groups" sehen, welcher dich zu Gruppen und Fan-Seiten führt. +Du verbindest dich mit Personen und Gruppen auf die gleiche Art, wobei Gruppen deine Anfrage automatisch annehmen, wohingegen ein Mensch dich erst manuell bestätigen muss. *Mit anderen Friendica-Nutzern verbinden* -Bes‪uche ihr Profil. -Direkt unter dem Profilfoto ist das Wort "Verbinden" (bzw. "Connect" in einem englischsprachigem Profil). -Klicke drauf und du gelangst zur "Verbinden"-Seite. -Dort wirst du nach deiner Identitätsadresse gefragt. +Besuche ihr Profil. +Direkt unter dem Profilfoto ist das Wort "Verbinden" (bzw. "Connect" in einem englischsprachigem Profil). +Klicke drauf und du gelangst zur "Verbinden"-Seite. +Dort wirst du nach deiner Identitätsadresse gefragt. Das ist nötig, damit die Seite dein Profil finden kann. *Was kommt in die Box?* -Wenn deine Friendica-Seite "demo.friendica.com" heißt und dein Nutzername/Spitzname auf der Seite "bob" ist, dann wäre es "bob@demo.friendica.com". -Wie du siehst, sieht es wie eine Email-Adresse aus. -Das ist beabsichtigt, da sich die Leute das so leichter merken können. +Wenn deine Friendica-Seite "demo.friendica.com" heißt und dein Nutzername/Spitzname auf der Seite "bob" ist, dann wäre es "bob@demo.friendica.com". +Wie du siehst, sieht es wie eine Email-Adresse aus. +Das ist beabsichtigt, da sich die Leute das so leichter merken können. Du *kannst* auch die URL deiner Startseite eintragen, wie z.B. "http://demo.friendica.com/profile/bob", aber der Email-Adressen-Stil ist einfacher. -Wenn du die "Verbinden"-Seite bestätigt hast, kommst du zurück zu deiner Seite, um dort die Anfrage zu bestätigen. +Wenn du die "Verbinden"-Seite bestätigt hast, kommst du zurück zu deiner Seite, um dort die Anfrage zu bestätigen. Wenn du das gemacht hast, können beide Seiten miteinander kommunizieren, um den Prozess abzuschließen (sobald dein neuer Freund die Anfrage bestätigt hat). -Wenn du bereits die Identitäts-Adresse einer Person kennst, kannst du diese auch direkt in das "Verbinden"-Feld auf deiner "Kontakte"-Seite eintragen. +Wenn du bereits die Identitäts-Adresse einer Person kennst, kannst du diese auch direkt in das "Verbinden"-Feld auf deiner "Kontakte"-Seite eintragen. Dies wird dich durch einen ähnlichen Prozess leiten. **Alternative Netzwerke** -Du kannst deine oder andere Identitäts-Adressen ebenfalls nutzen, um über verschiedene Netzwerke hinweg Freundschaften aufzubauen. -Die Liste möglicher Netzwerke steigt immer weiter. -Wenn du z.B. "bob" auf quitter.se (eine GNU Social-Seite) kennst, dann kannst du bob@quitter.se auf deiner "Kontakt"-Seite verbinden. (Oder du kannst die URL von Bobs quitter.se-Seite eintragen, wenn du es wünscht). -Tatsächlich kannst du jedem und jeder Website folgen, der/die einen Syndication-Feed (RSS/Atom etc.) zur Verfügung stellt. -Wenn wir einen Informationsstrom und einen Namen dazu finden, können wir auch versuchen, uns damit zu verbinden. +Du kannst deine oder andere Identitäts-Adressen ebenfalls nutzen, um über verschiedene Netzwerke hinweg Freundschaften aufzubauen. +Die Liste möglicher Netzwerke steigt immer weiter. +Wenn du z.B. "bob" auf quitter.se (eine GNU Social-Seite) kennst, dann kannst du bob@quitter.se auf deiner "Kontakt"-Seite verbinden. (Oder du kannst die URL von Bobs quitter.se-Seite eintragen, wenn du es wünscht). +Tatsächlich kannst du jedem und jeder Website folgen, der/die einen Syndication-Feed (RSS/Atom etc.) zur Verfügung stellt. +Wenn wir einen Informationsstrom und einen Namen dazu finden, können wir auch versuchen, uns damit zu verbinden. -Wenn du deine Email-Postfachverbindung auf deiner Einstellungsseite konfiguriert hast, dann kannst du die Email-Adresse jeder Person eintragen, die dir schon eine Nachricht an dein Postfach geschickt hat und bereits in deinem sozialen Stream erscheint. +Wenn du deine Email-Postfachverbindung auf deiner Einstellungsseite konfiguriert hast, dann kannst du die Email-Adresse jeder Person eintragen, die dir schon eine Nachricht an dein Postfach geschickt hat und bereits in deinem sozialen Stream erscheint. Du kannst diesen Personen außerdem von Friendica aus antworten. -Leute können sich ebenfalls von anderen Netzwerken aus mit dir befreunden. -Ein Freund von dir hat einen GNU Social-Account und kann sich mit dir befreunden, indem er deine Identitäts-Adresse in seine GNU Social-Verbinden-Dialogbox einträgt. -Ein ähnlicher Mechanismus ist für Diaspora-Nutzer vorhanden, indem deine Identitäts-Adresse in ihre Suchleiste eingegeben wird. +Leute können sich ebenfalls von anderen Netzwerken aus mit dir befreunden. +Ein Freund von dir hat einen GNU Social-Account und kann sich mit dir befreunden, indem er deine Identitäts-Adresse in seine GNU Social-Verbinden-Dialogbox einträgt. +Ein ähnlicher Mechanismus ist für Diaspora-Nutzer vorhanden, indem deine Identitäts-Adresse in ihre Suchleiste eingegeben wird. Beachte: Manche GNU Social-Versionen benötigen die volle URL deines Profils und funktionieren möglicherweise nicht mit der Identitäts-Adresse. -Wenn jemand eine Freundschaftsanfrage schickt, erhältst du eine Benachrichtigung. -Du musst dann diese Anfrage bestätigen, um die Freundschaftsanfrage abzuschließen. +Wenn jemand eine Freundschaftsanfrage schickt, erhältst du eine Benachrichtigung. +Du musst dann diese Anfrage bestätigen, um die Freundschaftsanfrage abzuschließen. -Einige Netzwerke erlauben es, Nachrichten zu schicken, ohne befreundet zu sein oder deine Bestätigung zu benötigen. +Einige Netzwerke erlauben es, Nachrichten zu schicken, ohne befreundet zu sein oder deine Bestätigung zu benötigen. Friendica erlaubt dies in der Standardeinstellung nicht, da es zu Spam führen kann. -Wenn du eine Freundschaftsanfrage von einem anderen Friendica-Nutzer erhältst, dann hast du die Möglichkeit, diesen als "Fan" oder "Freund" einzutragen. -Ein Fan kann sehen, was du schreibst und auch private Kommunikation sehen, die du zu diesen sendest, aber nicht umgekehrt. +Wenn du eine Freundschaftsanfrage von einem anderen Friendica-Nutzer erhältst, dann hast du die Möglichkeit, diesen als "Fan" oder "Freund" einzutragen. +Ein Fan kann sehen, was du schreibst und auch private Kommunikation sehen, die du zu diesen sendest, aber nicht umgekehrt. Als Freund kannst du in beide Richtungen kommunizieren. Diaspora nutzt eine andere Terminologie mit der Unterteilung in "mit dir teilen" und "Freund". -Sobald ihr Freunde geworden seid, dir die Person aber permanent Spam oder sinnlose Informationen schickt, dann kannst du diese "ignorieren" - ohne die Freundschaft komplett zu beenden oder denjenigen zu zeigen, dass du nicht daran interessiert bist, was diese Person sagt. -In verschiedener Hinsicht sind diese Personen wie "Fans", aber sie wissen es nicht. +Sobald ihr Freunde geworden seid, dir die Person aber permanent Spam oder sinnlose Informationen schickt, dann kannst du diese "ignorieren" - ohne die Freundschaft komplett zu beenden oder denjenigen zu zeigen, dass du nicht daran interessiert bist, was diese Person sagt. +In verschiedener Hinsicht sind diese Personen wie "Fans", aber sie wissen es nicht. Sie denken, sie sind als Freunde eingetragen. -Du kannst auch eine Person "blocken". -Das blockt die komplette Kommunikation mit dieser Person. +Du kannst auch eine Person "blocken". +Das blockt die komplette Kommunikation mit dieser Person. Sie können zwar weiterhin öffentliche Beiträge sehen, wie auch jeder andere in der Welt, allerdings können sie nicht direkt mit dir kommunizieren. Du kannst Freunde löschen, egal wie der Freundschaftsstatus ist, was dazu führt, dass alles, was mit dieser Person verbunden ist, von deiner Webseite gelöscht wird. diff --git a/doc/de/Quick-Start-groupsandpages.md b/doc/de/Quick-Start-groupsandpages.md index 66df79d3f..d4ea55d3d 100644 --- a/doc/de/Quick-Start-groupsandpages.md +++ b/doc/de/Quick-Start-groupsandpages.md @@ -1,26 +1,26 @@ -Gruppen und Seiten +Gruppen und Seiten ========== * [Zur Startseite der Hilfe](help) -Hier siehst Du das globale Verzeichnis. +Hier siehst Du das globale Verzeichnis. Wenn Du Dich mal verirrt hast, kannst Du diesen Link klicken und wieder hierher kommen. -Auf dieser Seite findest Du eine Zusammenstellung von Gruppen, Foren und Promi-Seiten. -Gruppen sind keine realen Personen. +Auf dieser Seite findest Du eine Zusammenstellung von Gruppen. +Gruppen sind keine realen Personen. Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet. Du musst nicht unsicher sein, ob Du jemandem zu nahe trittst, wenn Du Dich so ohne weiteres mit einer Gruppe verbindest; es handelt sich eben nicht um reale Personen. -Wenn Du Dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in Deinem "Netzwerk"-Tab. -Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eines der Gruppenmitglieder persönlich hinzuzufügen. -Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen. -Du findest Personen Deines Interesses, anstatt Fremde hinzuzufügen. -Suche Dir einfach eine Gruppe und füge sie so hinzu, wie Du auch normale Freunde hinzufügst. -Es gibt eine Menge Gruppen. +Wenn Du Dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in Deinem "Netzwerk"-Tab. +Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eines der Gruppenmitglieder persönlich hinzuzufügen. +Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen. +Du findest Personen Deines Interesses, anstatt Fremde hinzuzufügen. +Suche Dir einfach eine Gruppe und füge sie so hinzu, wie Du auch normale Freunde hinzufügst. +Es gibt eine Menge Gruppen. Solltest Du beim Stöbern durch die vielen Gruppen nicht wieder hierher zurück finden, so nutze einfach den Link oben auf dieser Seite. Wenn Du einige Gruppen hinzugefügt hast, gehe weiter zum nächsten Schritt. - + diff --git a/doc/de/Tags-and-Mentions.md b/doc/de/Tags-and-Mentions.md index e99d758db..8ab5bb581 100644 --- a/doc/de/Tags-and-Mentions.md +++ b/doc/de/Tags-and-Mentions.md @@ -7,37 +7,37 @@ Wie viele andere soziale Netzwerke benutzt auch Friendica eine spezielle Schreib **Erwähnungen** -Personen werden "getaggt", indem du das "@"-Zeichen vor den Namen schreibst. +Personen werden "getaggt", indem du das "@"-Zeichen vor den Namen schreibst. + +Personen **in deiner Kontaktliste** werden „getaggt“, indem du das “@“-Zeichen vor den Namen schreibst. -Personen **in deiner Kontaktliste** werden „getaggt“, indem du das “@“-Zeichen vor den Namen schreibst. - * @mike - deutet auf eine Person hin, die im Netzwerk den Namen "mike" nutzt * @mike_macgirvin - deutet auf eine Person hin, die sich im Netzwerk "Mike Macgirvin" nennt. Beachte, dass Leerzeichen in Tags nicht genutzt werden können. -* @mike+151 - diese Schreibweise deutet auf eine Person hin, die "mike" heißt und deren Kontakt-Identitäts-Nummer 151 ist. Bei der Eingabe erscheint direkt ein Auswahlmenü, sodass du diese Nummer nicht selbst kennen musst. +* @mike+151 - diese Schreibweise deutet auf eine Person hin, die "mike" heißt und deren Kontakt-Identitäts-Nummer 151 ist. Bei der Eingabe erscheint direkt ein Auswahlmenü, sodass du diese Nummer nicht selbst kennen musst. + +Personen, die in einem anderen Netzwerk sind oder die sich **NICHT in deiner Kontaktliste** befinden, werden wie folgt getaggt: -Personen, die in einem anderen Netzwerk sind oder die sich **NICHT in deiner Kontaktliste** befinden, werden wie folgt getaggt: - * @mike@macgirvin.com - diese Schreibweise wird "Fernerwähnung" (remote mention)genannt und kann nur im Email-Stil geschrieben werden, nicht als Internetadresse/URL. -Wenn das System ungewollte Erwähnungen nicht blockiert, erhält diese Person eine Mitteilung oder nimmt direkt an der Diskussion teil, wenn es sich um einen öffentlichen Beitrag handelt. -Bitte beachte, dass Friendica eingehende "Erwähnungs"-Nachrichten von Personen blockt, die du nicht zu deinem Profil hinzugefügt hast. +Wenn das System ungewollte Erwähnungen nicht blockiert, erhält diese Person eine Mitteilung oder nimmt direkt an der Diskussion teil, wenn es sich um einen öffentlichen Beitrag handelt. +Bitte beachte, dass Friendica eingehende "Erwähnungs"-Nachrichten von Personen blockt, die du nicht zu deinem Profil hinzugefügt hast. Diese Maßnahme dient dazu, Spam zu vermeiden. -"Fernerwähnungen" werden durch das OStatus-Protokoll übermittelt. -Dieses Protokoll wird von Friendica, GNU Social und anderen Systemen genutzt, ist allerdings derzeit nicht in Diaspora eingebaut. +"Fernerwähnungen" werden durch das OStatus-Protokoll übermittelt. +Dieses Protokoll wird von Friendica, GNU Social und anderen Systemen genutzt, ist allerdings derzeit nicht in Diaspora eingebaut. -Friendica unterscheidet bei Tags nicht zwischen Personen und Gruppen (einige andere Netzwerke nutzen "!gruppe", um solche zu markieren). +Friendica unterscheidet bei Tags nicht zwischen Personen und Gruppen (einige andere Netzwerke nutzen "!circle", um solche zu markieren). **Thematische Tags** -Thematische Tags werden durch eine "#" gekennzeichnet. -Dieses Zeichen erstellen einen Link zur allgemeinen Seitensuche mit dem ausgewählten Begriff. -So wird z.B. #Autos zu einer Suche führen, die alle Beiträge deiner Seite umfasst, die dieses Wort erwähnen. -Thematische Tags haben generell eine Mindestlänge von 3 Stellen. -Kürzere Suchbegriffe finden meist keine Suchergebnisse, wobei dieses abhängig von der Datenbankeinstellung ist. -Tags mit einem Leerzeichen werden, wie es auch bei Namen der Fall ist, durch einen Unterstrich gekennzeichnet. -Es ist hingegen nicht möglich, Tags zu erstellen, deren gesuchtes Wort einen Unterstrich enthält. +Thematische Tags werden durch eine "#" gekennzeichnet. +Dieses Zeichen erstellen einen Link zur allgemeinen Seitensuche mit dem ausgewählten Begriff. +So wird z.B. #Autos zu einer Suche führen, die alle Beiträge deiner Seite umfasst, die dieses Wort erwähnen. +Thematische Tags haben generell eine Mindestlänge von 3 Stellen. +Kürzere Suchbegriffe finden meist keine Suchergebnisse, wobei dieses abhängig von der Datenbankeinstellung ist. +Tags mit einem Leerzeichen werden, wie es auch bei Namen der Fall ist, durch einen Unterstrich gekennzeichnet. +Es ist hingegen nicht möglich, Tags zu erstellen, deren gesuchtes Wort einen Unterstrich enthält. Thematische Tags werden auch dann nicht verlinkt, wenn sie nur aus Nummern bestehen, wie z.B. #1. Wenn du einen numerischen Tag nutzen willst, füge bitte einen Beschreibungstext hinzu wie z.B. #2012_Wahl. diff --git a/doc/de/groupsandpages.md b/doc/de/groupsandpages.md deleted file mode 100644 index a65dab906..000000000 --- a/doc/de/groupsandpages.md +++ /dev/null @@ -1,26 +0,0 @@ -Gruppen und Seiten -========== - -* [Zur Startseite der Hilfe](help) - -Hier siehst du das globale Verzeichnis. -Wenn du dich mal verirrt hast, kannst du diesen Link klicken und wieder hierher kommen. - -Auf dieser Seite findest du eine Zusammenstellung von Gruppen, Foren und bekannten Seiten. -Gruppen sind keine realen Personen. -Sich mit diesen zu verbinden ist, als wenn man jemanden auf Facebook "liked" ("gefällt mir") oder wenn man sich in einem Forum anmeldet. -Habe keine Sorge, falls du dich unbehaglich fühlst, wenn du dich einer neuen Person vorstellen sollst, da es sich nicht um Personen handelt. - -Wenn du dich mit einer Gruppe verbindest, erscheinen alle Nachrichten der Gruppe in deinem "Netzwerk"-Tab. -Du kannst diese Beiträge kommentieren oder selbst in der Gruppe schreiben, ohne eine der Gruppenmitglieder persönlich hinzuzufügen. -Das ist ein großartiger Weg, dynamisch neue Freunde zu gewinnen. -Du findest Personen, die du magst, anstatt Fremde hinzuzufügen. -Suche dir einfach eine Gruppe und füge sie so hinzu, wie du auch normale Freunde hinzufügst. -Es gibt eine Menge Gruppen und möglicherweise findest du nicht wieder zu dieser Seite zurück. -In diesem Fall nutze einfach den Link oben auf dieser Seite. - -Wenn du einige Gruppen hinzugefügt hast, gehe weiter zum nächsten Schritt. - - - - diff --git a/images/default-group-mm.png b/images/default-group-mm.png deleted file mode 100644 index bfc8b335a..000000000 Binary files a/images/default-group-mm.png and /dev/null differ diff --git a/images/icons/10/group.png b/images/icons/10/circle.png similarity index 100% rename from images/icons/10/group.png rename to images/icons/10/circle.png diff --git a/images/icons/16/group.png b/images/icons/16/circle.png similarity index 100% rename from images/icons/16/group.png rename to images/icons/16/circle.png diff --git a/images/icons/22/group.png b/images/icons/22/circle.png similarity index 100% rename from images/icons/22/group.png rename to images/icons/22/circle.png diff --git a/images/icons/48/group.png b/images/icons/48/circle.png similarity index 100% rename from images/icons/48/group.png rename to images/icons/48/circle.png diff --git a/images/icons/Makefile b/images/icons/Makefile index bfb5927df..18094baac 100644 --- a/images/icons/Makefile +++ b/images/icons/Makefile @@ -1,6 +1,6 @@ IMAGES=add.png edit.png gear.png info.png menu.png \ - notify_off.png star.png delete.png feed.png group.png \ + notify_off.png star.png delete.png feed.png circle.png \ lock.png notice.png notify_on.png user.png link.png \ play.png plugin.png unlock.png zip.png audio.png video.png \ image.png text.png @@ -10,7 +10,7 @@ DESTS=10/ 16/ 22/ 48/ \ $(addprefix 16/, $(IMAGES)) \ $(addprefix 22/, $(IMAGES)) \ $(addprefix 48/, $(IMAGES)) - + all: $(DESTS) %/: @@ -18,7 +18,7 @@ all: $(DESTS) 10/%.png: %.png convert $< -resize 10x10 $@ - + 16/%.png: %.png convert $< -resize 16x16 $@ diff --git a/images/icons/group.png b/images/icons/circle.png similarity index 100% rename from images/icons/group.png rename to images/icons/circle.png diff --git a/index.php b/index.php index 90df9c00e..87778308a 100644 --- a/index.php +++ b/index.php @@ -30,6 +30,9 @@ if (!file_exists(__DIR__ . '/vendor/autoload.php')) { require __DIR__ . '/vendor/autoload.php'; $dice = (new Dice())->addRules(include __DIR__ . '/static/dependencies.config.php'); +/** @var \Friendica\Core\Addon\Capability\ICanLoadAddons $addonLoader */ +$addonLoader = $dice->create(\Friendica\Core\Addon\Capability\ICanLoadAddons::class); +$dice = $dice->addRules($addonLoader->getActiveAddonConfig('dependencies')); $dice = $dice->addRule(Friendica\App\Mode::class, ['call' => [['determineRunMode', [false, $_SERVER], Dice::CHAIN_CALL]]]); \Friendica\DI::init($dice); diff --git a/mod/item.php b/mod/item.php index 369b0888a..72c2ed8c5 100644 --- a/mod/item.php +++ b/mod/item.php @@ -104,7 +104,7 @@ function item_edit(int $uid, array $request, bool $preview, string $return_path) } $post['edit'] = $post; - $post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']); + $post['file'] = Post\Category::getTextByURIId($post['uri-id'], $post['uid']); Post\Media::deleteByURIId($post['uri-id'], [Post\Media::AUDIO, Post\Media::VIDEO, Post\Media::IMAGE, Post\Media::HTML]); $post = item_process($post, $request, $preview, $return_path); @@ -266,6 +266,7 @@ function item_process(array $post, array $request, bool $preview, string $return $post['uri-id'] = -1; $post['author-network'] = Protocol::DFRN; $post['author-updated'] = ''; + $post['author-alias'] = ''; $post['author-gsid'] = 0; $post['author-uri-id'] = ItemURI::getIdByURI($post['author-link']); $post['owner-updated'] = ''; @@ -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], Conversation::MODE_SEARCH, false, true); + $o = DI::conversation()->render([$post], Conversation::MODE_SEARCH, false, true); System::jsonExit(['preview' => $o]); } @@ -340,7 +341,7 @@ function item_content(App $a) $args = DI::args(); - if (!$args->has(3)) { + if (!$args->has(2)) { throw new HTTPException\BadRequestException(); } diff --git a/mod/notes.php b/mod/notes.php index 360441471..554429d0e 100644 --- a/mod/notes.php +++ b/mod/notes.php @@ -85,7 +85,7 @@ function notes_content(App $a, bool $update = false) $count = count($notes); - $o .= DI::conversation()->create($notes, Conversation::MODE_NOTES, $update); + $o .= DI::conversation()->render($notes, Conversation::MODE_NOTES, $update); } $o .= $pager->renderMinimal($count); diff --git a/mod/photos.php b/mod/photos.php index 0a8dc472d..1b9120576 100644 --- a/mod/photos.php +++ b/mod/photos.php @@ -117,7 +117,7 @@ function photos_init(App $a) $tpl = Renderer::getMarkupTemplate("photos_head.tpl"); - DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl,[ + DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [ '$ispublic' => DI::l10n()->t('everybody') ]); } @@ -163,14 +163,14 @@ function photos_post(App $a) $aclFormatter = DI::aclFormatter(); $str_contact_allow = isset($_REQUEST['contact_allow']) ? $aclFormatter->toString($_REQUEST['contact_allow']) : $owner_record['allow_cid'] ?? ''; - $str_group_allow = isset($_REQUEST['group_allow']) ? $aclFormatter->toString($_REQUEST['group_allow']) : $owner_record['allow_gid'] ?? ''; + $str_circle_allow = isset($_REQUEST['circle_allow']) ? $aclFormatter->toString($_REQUEST['circle_allow']) : $owner_record['allow_gid'] ?? ''; $str_contact_deny = isset($_REQUEST['contact_deny']) ? $aclFormatter->toString($_REQUEST['contact_deny']) : $owner_record['deny_cid'] ?? ''; - $str_group_deny = isset($_REQUEST['group_deny']) ? $aclFormatter->toString($_REQUEST['group_deny']) : $owner_record['deny_gid'] ?? ''; + $str_circle_deny = isset($_REQUEST['circle_deny']) ? $aclFormatter->toString($_REQUEST['circle_deny']) : $owner_record['deny_gid'] ?? ''; $visibility = $_REQUEST['visibility'] ?? ''; if ($visibility === 'public') { // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected - $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + $str_contact_allow = $str_circle_allow = $str_contact_deny = $str_circle_deny = ''; } else if ($visibility === 'custom') { // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL // case that would make it public. So we always append the author's contact id to the allowed contacts. @@ -214,13 +214,15 @@ function photos_post(App $a) // get the list of photos we are about to delete if ($visitor) { - $r = DBA::toArray(DBA::p("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `contact-id` = ? AND `uid` = ? AND `album` = ?", + $r = DBA::toArray(DBA::p( + "SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `contact-id` = ? AND `uid` = ? AND `album` = ?", $visitor, $page_owner_uid, $album )); } else { - $r = DBA::toArray(DBA::p("SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `uid` = ? AND `album` = ?", + $r = DBA::toArray(DBA::p( + "SELECT distinct(`resource-id`) as `rid` FROM `photo` WHERE `uid` = ? AND `album` = ?", DI::userSession()->getLocalUserId(), $album )); @@ -258,7 +260,6 @@ function photos_post(App $a) // same as above but remove single photo if ($visitor) { $condition = ['contact-id' => $visitor, 'uid' => $page_owner_uid, 'resource-id' => DI::args()->getArgv()[3]]; - } else { $condition = ['uid' => DI::userSession()->getLocalUserId(), 'resource-id' => DI::args()->getArgv()[3]]; } @@ -338,7 +339,7 @@ function photos_post(App $a) $photo = $photos[0]; $ext = $phototypes[$photo['type']]; Photo::update( - ['desc' => $desc, 'album' => $albname, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny], + ['desc' => $desc, 'album' => $albname, 'allow_cid' => $str_contact_allow, 'allow_gid' => $str_circle_allow, 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_circle_deny], ['resource-id' => $resource_id, 'uid' => $page_owner_uid] ); @@ -405,7 +406,7 @@ function photos_post(App $a) if (strpos($tag, '@') === 0) { $profile = ''; $contact = null; - $name = substr($tag,1); + $name = substr($tag, 1); if ((strpos($name, '@')) || (strpos($name, 'http://'))) { $newname = $name; @@ -441,13 +442,15 @@ function photos_post(App $a) if ($tagcid) { $contact = DBA::selectFirst('contact', [], ['id' => $tagcid, 'uid' => $page_owner_uid]); } else { - $newname = str_replace('_',' ',$name); + $newname = str_replace('_', ' ', $name); //select someone from this user's contacts by name $contact = DBA::selectFirst('contact', [], ['name' => $newname, 'uid' => $page_owner_uid]); if (!DBA::isResult($contact)) { //select someone by attag or nick and the name passed in - $contact = DBA::selectFirst('contact', [], + $contact = DBA::selectFirst( + 'contact', + [], ['(`attag` = ? OR `nick` = ?) AND `uid` = ?', $name, $name, $page_owner_uid], ['order' => ['attag' => true]] ); @@ -689,11 +692,13 @@ function photos_content(App $a) $uploader = ''; - $ret = ['post_url' => 'profile/' . $user['nickname'] . '/photos', - 'addon_text' => $uploader, - 'default_upload' => true]; + $ret = [ + 'post_url' => 'profile/' . $user['nickname'] . '/photos', + 'addon_text' => $uploader, + 'default_upload' => true + ]; - Hook::callAll('photo_upload_form',$ret); + Hook::callAll('photo_upload_form', $ret); $default_upload_box = Renderer::replaceMacros(Renderer::getMarkupTemplate('photos_default_uploader_box.tpl'), []); $default_upload_submit = Renderer::replaceMacros(Renderer::getMarkupTemplate('photos_default_uploader_submit.tpl'), [ @@ -705,7 +710,7 @@ function photos_content(App $a) $umf_bytes = Strings::getBytesFromShorthand(ini_get('upload_max_filesize')); // Per Friendica definition a value of '0' means unlimited: - If ($mis_bytes == 0) { + if ($mis_bytes == 0) { $mis_bytes = INF; } @@ -719,7 +724,7 @@ function photos_content(App $a) $aclselect_e = ($visitor ? '' : ACL::getFullSelectorHTML(DI::page(), $a->getLoggedInUserId())); - $o .= Renderer::replaceMacros($tpl,[ + $o .= Renderer::replaceMacros($tpl, [ '$pagename' => DI::l10n()->t('Upload Photos'), '$sessid' => session_id(), '$usage' => $usage_message, @@ -747,7 +752,7 @@ function photos_content(App $a) if ($datatype === 'album') { // if $datum is not a valid hex, redirect to the default page if (is_null($datum) || !Strings::isHex($datum)) { - DI::baseUrl()->redirect('photos/' . $user['nickname']. '/album'); + DI::baseUrl()->redirect('photos/' . $user['nickname'] . '/album'); } $album = hex2bin($datum); @@ -756,7 +761,8 @@ function photos_content(App $a) } $total = 0; - $r = DBA::toArray(DBA::p("SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = ? AND `album` = ? + $r = DBA::toArray(DBA::p( + "SELECT `resource-id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = ? AND `album` = ? AND `scale` <= 4 $sql_extra GROUP BY `resource-id`", $owner_uid, $album @@ -775,7 +781,8 @@ function photos_content(App $a) $order = 'DESC'; } - $r = DBA::toArray(DBA::p("SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, + $r = DBA::toArray(DBA::p( + "SELECT `resource-id`, ANY_VALUE(`id`) AS `id`, ANY_VALUE(`filename`) AS `filename`, ANY_VALUE(`type`) AS `type`, max(`scale`) AS `scale`, ANY_VALUE(`desc`) as `desc`, ANY_VALUE(`created`) as `created` FROM `photo` WHERE `uid` = ? AND `album` = ? @@ -809,7 +816,7 @@ function photos_content(App $a) $album_e = $album; - $o .= Renderer::replaceMacros($edit_tpl,[ + $o .= Renderer::replaceMacros($edit_tpl, [ '$nametext' => DI::l10n()->t('New album name: '), '$nickname' => $user['nickname'], '$album' => $album_e, @@ -843,16 +850,16 @@ function photos_content(App $a) $desc_e = $rr['desc']; $photos[] = [ - 'id' => $rr['id'], - 'twist' => ' ' . ($twist ? 'rotleft' : 'rotright') . rand(2,4), - 'link' => 'photos/' . $user['nickname'] . '/image/' . $rr['resource-id'] + 'id' => $rr['id'], + 'twist' => ' ' . ($twist ? 'rotleft' : 'rotright') . rand(2, 4), + 'link' => 'photos/' . $user['nickname'] . '/image/' . $rr['resource-id'] . ($order_field === 'created' ? '?order=created' : ''), 'title' => DI::l10n()->t('View Photo'), - 'src' => 'photo/' . $rr['resource-id'] . '-' . $rr['scale'] . '.' .$ext, - 'alt' => $imgalt_e, - 'desc'=> $desc_e, - 'ext' => $ext, - 'hash'=> $rr['resource-id'], + 'src' => 'photo/' . $rr['resource-id'] . '-' . $rr['scale'] . '.' . $ext, + 'alt' => $imgalt_e, + 'desc' => $desc_e, + 'ext' => $ext, + 'hash' => $rr['resource-id'], ]; } } @@ -870,7 +877,6 @@ function photos_content(App $a) ]); return $o; - } // Display one photo @@ -955,7 +961,7 @@ function photos_content(App $a) } $tpl = Renderer::getMarkupTemplate('photo_edit_head.tpl'); - DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl,[ + DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [ '$prevlink' => $prevlink, '$nextlink' => $nextlink ]); @@ -967,7 +973,7 @@ function photos_content(App $a) if ($nextlink) { $nextlink = [$nextlink, '']; } - } + } } if (count($ph) == 1) { @@ -1007,12 +1013,12 @@ function photos_content(App $a) } $photo = [ - 'href' => 'photo/' . $hires['resource-id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']], - 'title'=> DI::l10n()->t('View Full Size'), - 'src' => 'photo/' . $lores['resource-id'] . '-' . $lores['scale'] . '.' . $phototypes[$lores['type']] . '?_u=' . DateTimeFormat::utcNow('ymdhis'), - 'height' => $hires['height'], - 'width' => $hires['width'], - 'album' => $hires['album'], + 'href' => 'photo/' . $hires['resource-id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']], + 'title' => DI::l10n()->t('View Full Size'), + 'src' => 'photo/' . $lores['resource-id'] . '-' . $lores['scale'] . '.' . $phototypes[$lores['type']] . '?_u=' . DateTimeFormat::utcNow('ymdhis'), + 'height' => $hires['height'], + 'width' => $hires['width'], + 'album' => $hires['album'], 'filename' => $hires['filename'], ]; @@ -1079,12 +1085,12 @@ function photos_content(App $a) $edit = Renderer::replaceMacros($edit_tpl, [ '$id' => $ph[0]['id'], - '$album' => ['albname', DI::l10n()->t('New album name'), $album_e,''], + '$album' => ['albname', DI::l10n()->t('New album name'), $album_e, ''], '$caption' => ['desc', DI::l10n()->t('Caption'), $caption_e, ''], '$tags' => ['newtag', DI::l10n()->t('Add a Tag'), "", DI::l10n()->t('Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping')], - '$rotate_none' => ['rotate', DI::l10n()->t('Do not rotate'),0,'', true], - '$rotate_cw' => ['rotate', DI::l10n()->t("Rotate CW \x28right\x29"),1,''], - '$rotate_ccw' => ['rotate', DI::l10n()->t("Rotate CCW \x28left\x29"),2,''], + '$rotate_none' => ['rotate', DI::l10n()->t('Do not rotate'), 0, '', true], + '$rotate_cw' => ['rotate', DI::l10n()->t("Rotate CW \x28right\x29"), 1, ''], + '$rotate_ccw' => ['rotate', DI::l10n()->t("Rotate CCW \x28left\x29"), 2, ''], '$nickname' => $user['nickname'], '$resource_id' => $ph[0]['resource-id'], @@ -1179,7 +1185,7 @@ function photos_content(App $a) $qcomment = $words ? explode("\n", $words) : []; } - $comments .= Renderer::replaceMacros($cmnt_tpl,[ + $comments .= Renderer::replaceMacros($cmnt_tpl, [ '$return_path' => '', '$jsreload' => $return_path, '$id' => $link_item['id'], @@ -1203,13 +1209,19 @@ function photos_content(App $a) $activity = DI::activity(); if (($activity->match($item['verb'], Activity::LIKE) || - $activity->match($item['verb'], Activity::DISLIKE)) && - ($item['gravity'] != Item::GRAVITY_PARENT)) { + $activity->match($item['verb'], Activity::DISLIKE)) && + ($item['gravity'] != Item::GRAVITY_PARENT) + ) { continue; } - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'] + ]; $profile_url = Contact::magicLinkByContact($author); if (strpos($profile_url, 'contact/redir/') === 0) { $sparkle = ' sparkle'; @@ -1228,7 +1240,7 @@ function photos_content(App $a) $title_e = $item['title']; $body_e = BBCode::convertForUriId($item['uri-id'], $item['body']); - $comments .= Renderer::replaceMacros($template,[ + $comments .= Renderer::replaceMacros($template, [ '$id' => $item['id'], '$profile_url' => $profile_url, '$name' => $item['author-name'], diff --git a/src/App.php b/src/App.php index e47054f55..db3e644c2 100644 --- a/src/App.php +++ b/src/App.php @@ -64,7 +64,7 @@ class App { const PLATFORM = 'Friendica'; const CODENAME = 'Giant Rhubarb'; - const VERSION = '2023.05'; + const VERSION = '2023.09-dev'; // Allow themes to control internal parameters // by changing App values in theme.php @@ -581,6 +581,7 @@ class App // Force SSL redirection if ($this->config->get('system', 'force_ssl') && (empty($server['HTTPS']) || $server['HTTPS'] === 'off') && + (empty($server['HTTP_X_FORWARDED_PROTO']) || $server['HTTP_X_FORWARDED_PROTO'] === 'http') && !empty($server['REQUEST_METHOD']) && $server['REQUEST_METHOD'] === 'GET') { System::externalRedirect($this->baseURL . '/' . $this->args->getQueryString()); @@ -694,6 +695,9 @@ class App $module = $router->getModule(); } + // Display can change depending on the requested language, so it shouldn't be cached whole + header('Vary: Accept-Language', false); + // Processes data from GET requests $httpinput = $httpInput->process(); $input = array_merge($httpinput['variables'], $httpinput['files'], $request ?? $_REQUEST); @@ -702,11 +706,13 @@ class App $timestamp = microtime(true); $response = $module->run($httpException, $input); $this->profiler->set(microtime(true) - $timestamp, 'content'); + + // Wrapping HTML responses in the theme template if ($response->getHeaderLine(ICanCreateResponses::X_HEADER) === ICanCreateResponses::TYPE_HTML) { - $page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId()); - } else { - $page->exit($response); + $response = $page->run($this, $this->baseURL, $this->args, $this->mode, $response, $this->l10n, $this->profiler, $this->config, $pconfig, $nav, $this->session->getLocalUserId()); } + + $page->exit($response); } catch (HTTPException $e) { $httpException->rawContent($e); } diff --git a/src/App/BaseURL.php b/src/App/BaseURL.php index 403030684..cc20343d1 100644 --- a/src/App/BaseURL.php +++ b/src/App/BaseURL.php @@ -127,4 +127,14 @@ class BaseURL extends Uri implements UriInterface $redirectTo = $this->__toString() . '/' . ltrim($toUrl, '/'); System::externalRedirect($redirectTo); } + + public function isLocalUrl(string $url): bool + { + return strpos(Strings::normaliseLink($url), Strings::normaliseLink((string)$this)) === 0; + } + + public function isLocalUri(UriInterface $uri): bool + { + return $this->isLocalUrl((string)$uri); + } } diff --git a/src/App/Page.php b/src/App/Page.php index 6252d9a88..e369d482e 100644 --- a/src/App/Page.php +++ b/src/App/Page.php @@ -39,6 +39,7 @@ use Friendica\Network\HTTPException; use Friendica\Util\Network; use Friendica\Util\Profiler; use Friendica\Util\Strings; +use GuzzleHttp\Psr7\Utils; use Psr\Http\Message\ResponseInterface; /** @@ -244,10 +245,12 @@ class Page implements ArrayAccess */ $this->page['htmlhead'] = Renderer::replaceMacros($tpl, [ '$l10n' => [ - 'delitem' => $l10n->t('Delete this item?'), - 'blockAuthor' => $l10n->t('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.'), - 'ignoreAuthor' => $l10n->t('Ignore this author? You won\'t be able to see their posts and their notifications.'), - 'collapseAuthor' => $l10n->t('Collapse this author\'s posts?'), + 'delitem' => $l10n->t('Delete this item?'), + 'blockAuthor' => $l10n->t("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."), + 'ignoreAuthor' => $l10n->t("Ignore this author? You won't be able to see their posts and their notifications."), + 'collapseAuthor' => $l10n->t("Collapse this author's posts?"), + 'ignoreServer' => $l10n->t("Ignore this author's server?"), + 'ignoreServerDesc' => $l10n->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."), 'likeError' => $l10n->t('Like not successful'), 'dislikeError' => $l10n->t('Dislike not successful'), @@ -499,20 +502,6 @@ class Page implements ArrayAccess $this->page['nav'] = $nav->getHtml(); } - foreach ($response->getHeaders() as $key => $header) { - if (is_array($header)) { - $header_str = implode(',', $header); - } else { - $header_str = $header; - } - - if (empty($key)) { - header($header_str); - } else { - header("$key: $header_str"); - } - } - // Build the page - now that we have all the components if (isset($_GET["mode"]) && (($_GET["mode"] == "raw") || ($_GET["mode"] == "minimal"))) { $doc = new DOMDocument(); @@ -583,6 +572,10 @@ class Page implements ArrayAccess // Used as is in view/php/default.php $lang = $l10n->getCurrentLang(); + ob_start(); require_once $template; + $body = ob_get_clean(); + + return $response->withBody(Utils::streamFor($body)); } } diff --git a/src/BaseModule.php b/src/BaseModule.php index b43e98477..619095dfb 100644 --- a/src/BaseModule.php +++ b/src/BaseModule.php @@ -251,6 +251,7 @@ abstract class BaseModule implements ICanHandleRequests throw $e; } + $this->response->setStatus($e->getCode(), $e->getMessage()); $this->response->addContent($httpException->content($e)); } finally { $this->profiler->set(microtime(true) - $timestamp, 'content'); diff --git a/src/Collection/Api/Notifications.php b/src/Collection/Api/Notifications.php index c2ccf2cff..4bb1eaa56 100644 --- a/src/Collection/Api/Notifications.php +++ b/src/Collection/Api/Notifications.php @@ -29,6 +29,7 @@ class Notifications extends BaseCollection /** * @return Notification */ + #[\ReturnTypeWillChange] public function current() { return parent::current(); diff --git a/src/Console/PostUpdate.php b/src/Console/PostUpdate.php index 742197e73..42cc63e10 100644 --- a/src/Console/PostUpdate.php +++ b/src/Console/PostUpdate.php @@ -22,7 +22,7 @@ namespace Friendica\Console; use Friendica\App; -use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\L10n; use Friendica\Core\Update; diff --git a/src/Console/Relay.php b/src/Console/Relay.php index 52682241e..11d1dbf82 100644 --- a/src/Console/Relay.php +++ b/src/Console/Relay.php @@ -23,8 +23,8 @@ namespace Friendica\Console; use Asika\SimpleConsole\CommandArgsException; use Friendica\Model\APContact; -use Friendica\Model\Contact; use Friendica\Protocol\ActivityPub\Transmitter; +use Friendica\Protocol\Relay as ProtocolRelay; /** * tool to control the list of ActivityPub relay servers from the CLI @@ -90,13 +90,9 @@ HELP; } if ((count($this->args) == 1) && ($this->getArgument(0) == 'list')) { - $contacts = $this->dba->select('apcontact', ['url'], - ["`type` IN (?, ?) AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", - 'Application', 'Service', 0, Contact::FRIEND]); - while ($contact = $this->dba->fetch($contacts)) { + foreach (ProtocolRelay::getList(['url']) as $contact) { $this->out($contact['url']); } - $this->dba->close($contacts); } elseif (count($this->args) == 0) { throw new CommandArgsException('too few arguments'); } elseif (count($this->args) == 1) { diff --git a/src/Contact/Avatar.php b/src/Contact/Avatar.php index 299c26399..fc4b7e38c 100644 --- a/src/Contact/Avatar.php +++ b/src/Contact/Avatar.php @@ -92,7 +92,7 @@ class Avatar return $fields; } - $filename = self::getFilename($contact['url']); + $filename = self::getFilename($contact['url'], $avatar); $timestamp = time(); $fields['blurhash'] = $image->getBlurHash(); @@ -120,7 +120,7 @@ class Avatar return $fields; } - $filename = self::getFilename($contact['url']); + $filename = self::getFilename($contact['url'], $contact['avatar']); $timestamp = time(); $fields['photo'] = self::storeAvatarCache($image, $filename, Proxy::PIXEL_SMALL, $timestamp); @@ -130,9 +130,9 @@ class Avatar return $fields; } - private static function getFilename(string $url): string + private static function getFilename(string $url, string $host): string { - $guid = Item::guidFromUri($url); + $guid = Item::guidFromUri($url, $host); return substr($guid, 0, 2) . '/' . substr($guid, 3, 2) . '/' . substr($guid, 5, 3) . '/' . substr($guid, 9, 2) .'/' . substr($guid, 11, 2) . '/' . substr($guid, 13, 4). '/' . substr($guid, 18) . '-'; diff --git a/src/Contact/Header.php b/src/Contact/Header.php new file mode 100644 index 000000000..d5116d290 --- /dev/null +++ b/src/Contact/Header.php @@ -0,0 +1,47 @@ +. + * + */ + +namespace Friendica\Contact; + +use Friendica\Core\Config\Capability\IManageConfigValues; + +class Header +{ + /** @var IManageConfigValues */ + private $config; + + public function __construct(IManageConfigValues $config) + { + $this->config = $config; + } + + /** + * Returns the Mastodon banner path relative to the Friendica folder. + * + * Ensures the existence of a leading slash. + * + * @return string + */ + public function getMastodonBannerPath(): string + { + return '/' . ltrim($this->config->get('api', 'mastodon_banner'), '/'); + } +} diff --git a/src/Contact/LocalRelationship/Entity/LocalRelationship.php b/src/Contact/LocalRelationship/Entity/LocalRelationship.php index 8a9c48745..4fc7ae366 100644 --- a/src/Contact/LocalRelationship/Entity/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Entity/LocalRelationship.php @@ -36,7 +36,7 @@ use Friendica\Model\Contact; * @property-read int $rel * @property-read string $info * @property-read bool $notifyNewPosts - * @property-read bool $isRemoteSelf + * @property-read int $remoteSelf * @property-read int $fetchFurtherInformation * @property-read string $ffiKeywordDenylist * @property-read bool $subhub @@ -47,6 +47,16 @@ use Friendica\Model\Contact; */ class LocalRelationship extends \Friendica\BaseEntity { + // Fetch Further Information options, not a binary flag + const FFI_NONE = 0; + const FFI_INFORMATION = 1; + const FFI_KEYWORD = 3; + const FFI_BOTH = 2; + + const MIRROR_DEACTIVATED = 0; + const MIRROR_OWN_POST = 2; + const MIRROR_NATIVE_RESHARE = 3; + /** @var int */ protected $userId; /** @var int */ @@ -67,9 +77,9 @@ class LocalRelationship extends \Friendica\BaseEntity protected $info; /** @var bool */ protected $notifyNewPosts; - /** @var bool */ - protected $isRemoteSelf; - /** @var int */ + /** @var int One of MIRROR_* */ + protected $remoteSelf; + /** @var int One of FFI_* */ protected $fetchFurtherInformation; /** @var string */ protected $ffiKeywordDenylist; @@ -84,7 +94,7 @@ class LocalRelationship extends \Friendica\BaseEntity /** @var int */ protected $priority; - public function __construct(int $userId, int $contactId, bool $blocked = false, bool $ignored = false, bool $collapsed = false, bool $hidden = false, bool $pending = false, int $rel = Contact::NOTHING, string $info = '', bool $notifyNewPosts = false, bool $isRemoteSelf = false, int $fetchFurtherInformation = 0, string $ffiKeywordDenylist = '', bool $subhub = false, string $hubVerify = '', string $protocol = Protocol::PHANTOM, ?int $rating = null, ?int $priority = null) + public function __construct(int $userId, int $contactId, bool $blocked = false, bool $ignored = false, bool $collapsed = false, bool $hidden = false, bool $pending = false, int $rel = Contact::NOTHING, string $info = '', bool $notifyNewPosts = false, int $remoteSelf = self::MIRROR_DEACTIVATED, int $fetchFurtherInformation = self::FFI_NONE, string $ffiKeywordDenylist = '', bool $subhub = false, string $hubVerify = '', string $protocol = Protocol::PHANTOM, ?int $rating = null, ?int $priority = null) { $this->userId = $userId; $this->contactId = $contactId; @@ -96,7 +106,7 @@ class LocalRelationship extends \Friendica\BaseEntity $this->rel = $rel; $this->info = $info; $this->notifyNewPosts = $notifyNewPosts; - $this->isRemoteSelf = $isRemoteSelf; + $this->remoteSelf = $remoteSelf; $this->fetchFurtherInformation = $fetchFurtherInformation; $this->ffiKeywordDenylist = $ffiKeywordDenylist; $this->subhub = $subhub; diff --git a/src/Contact/LocalRelationship/Factory/LocalRelationship.php b/src/Contact/LocalRelationship/Factory/LocalRelationship.php index 455dbe1c3..54fc86215 100644 --- a/src/Contact/LocalRelationship/Factory/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Factory/LocalRelationship.php @@ -45,8 +45,8 @@ class LocalRelationship extends BaseFactory implements ICanCreateFromTableRow $row['rel'] ?? Contact::NOTHING, $row['info'] ?? '', $row['notify_new_posts'] ?? false, - $row['remote_self'] ?? false, - $row['fetch_further_information'] ?? 0, + $row['remote_self'] ?? Entity\LocalRelationship::MIRROR_DEACTIVATED, + $row['fetch_further_information'] ?? Entity\LocalRelationship::FFI_NONE, $row['ffi_keyword_denylist'] ?? '', $row['subhub'] ?? false, $row['hub-verify'] ?? '', diff --git a/src/Contact/LocalRelationship/Repository/LocalRelationship.php b/src/Contact/LocalRelationship/Repository/LocalRelationship.php index a80a4f897..490a84e44 100644 --- a/src/Contact/LocalRelationship/Repository/LocalRelationship.php +++ b/src/Contact/LocalRelationship/Repository/LocalRelationship.php @@ -100,7 +100,7 @@ class LocalRelationship extends \Friendica\BaseRepository 'rel' => $localRelationship->rel, 'info' => $localRelationship->info, 'notify_new_posts' => $localRelationship->notifyNewPosts, - 'remote_self' => $localRelationship->isRemoteSelf, + 'remote_self' => $localRelationship->remoteSelf, 'fetch_further_information' => $localRelationship->fetchFurtherInformation, 'ffi_keyword_denylist' => $localRelationship->ffiKeywordDenylist, 'subhub' => $localRelationship->subhub, diff --git a/src/Content/ContactSelector.php b/src/Content/ContactSelector.php index 9a8af1cd2..5d33aa59e 100644 --- a/src/Content/ContactSelector.php +++ b/src/Content/ContactSelector.php @@ -220,7 +220,8 @@ class ContactSelector 'GNU Social' => 'gnu-social', 'gnusocial' => 'gnu-social', 'hubzilla' => 'hubzilla', 'mastodon' => 'mastodon', 'peertube' => 'peertube', 'pixelfed' => 'pixelfed', 'pleroma' => 'pleroma', 'red' => 'hubzilla', 'redmatrix' => 'hubzilla', - 'socialhome' => 'social-home', 'wordpress' => 'wordpress']; + 'socialhome' => 'social-home', 'wordpress' => 'wordpress', 'lemmy' => 'users', + 'firefish' => 'fire', 'calckey' => 'calculator', 'kbin' => 'check']; $search = array_keys($nets); $replace = array_values($nets); diff --git a/src/Content/Conversation.php b/src/Content/Conversation.php index e0205d3d0..7edd4415d 100644 --- a/src/Content/Conversation.php +++ b/src/Content/Conversation.php @@ -38,6 +38,7 @@ use Friendica\Database\DBA; use Friendica\Model\Contact; use Friendica\Model\Item as ItemModel; use Friendica\Model\Post; +use Friendica\Model\Post\Category; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Model\Verb; @@ -45,6 +46,8 @@ use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Object\Post as PostObject; use Friendica\Object\Thread; use Friendica\Protocol\Activity; +use Friendica\User\Settings\Entity\UserGServer; +use Friendica\User\Settings\Repository; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; @@ -90,22 +93,25 @@ class Conversation private $mode; /** @var IHandleUserSessions */ private $session; + /** @var Repository\UserGServer */ + private $userGServer; - public function __construct(LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) + public function __construct(Repository\UserGServer $userGServer, LoggerInterface $logger, Profiler $profiler, Activity $activity, L10n $l10n, Item $item, Arguments $args, BaseURL $baseURL, IManageConfigValues $config, IManagePersonalConfigValues $pConfig, App\Page $page, App\Mode $mode, App $app, IHandleUserSessions $session) { - $this->activity = $activity; - $this->item = $item; - $this->config = $config; - $this->mode = $mode; - $this->baseURL = $baseURL; - $this->profiler = $profiler; - $this->logger = $logger; - $this->l10n = $l10n; - $this->args = $args; - $this->pConfig = $pConfig; - $this->page = $page; - $this->app = $app; - $this->session = $session; + $this->activity = $activity; + $this->item = $item; + $this->config = $config; + $this->mode = $mode; + $this->baseURL = $baseURL; + $this->profiler = $profiler; + $this->logger = $logger; + $this->l10n = $l10n; + $this->args = $args; + $this->pConfig = $pConfig; + $this->page = $page; + $this->app = $app; + $this->session = $session; + $this->userGServer = $userGServer; } /** @@ -154,7 +160,8 @@ class Conversation 'uid' => 0, 'id' => $activity['author-id'], 'network' => $activity['author-network'], - 'url' => $activity['author-link'] + 'url' => $activity['author-link'], + 'alias' => $activity['author-alias'], ]; $url = Contact::magicLinkByContact($author); if (strpos($url, 'contact/redir/') === 0) { @@ -272,7 +279,7 @@ class Conversation $phrase = $this->l10n->tt(' attends', ' attend', $total, $spanatts); break; case 'attendno': - $phrase = $this->l10n->tt(' doesn\'t attend',' don\'t attend', $total, $spanatts); + $phrase = $this->l10n->tt(' doesn\'t attend', ' don\'t attend', $total, $spanatts); break; case 'attendmaybe': $phrase = $this->l10n->tt(' attends maybe', ' attend maybe', $total, $spanatts); @@ -366,6 +373,7 @@ class Conversation '$eduline' => $this->l10n->t('Underline'), '$edquote' => $this->l10n->t('Quote'), '$edemojis' => $this->l10n->t('Add emojis'), + '$contentwarn' => $this->l10n->t('Content Warning'), '$edcode' => $this->l10n->t('Code'), '$edimg' => $this->l10n->t('Image'), '$edurl' => $this->l10n->t('Link'), @@ -436,17 +444,17 @@ class Conversation * The $mode parameter decides between the various renderings and also * figures out how to determine page owner and other contextual items * that are based on unique features of the calling module. - * @param array $items - * @param string $mode - * @param $update @TODO Which type? - * @param bool $preview - * @param string $order + * @param array $items An array of Posts + * @param string $mode One of self::MODE_* + * @param bool $update Asynchronous update rendering + * @param bool $preview Post preview (no actual database record) + * @param string $order Either "received" or "commented" * @param int $uid * @return string * @throws ImagickException * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function create(array $items, string $mode, $update, bool $preview = false, string $order = 'commented', int $uid = 0): string + public function render(array $items, string $mode, bool $update = false, bool $preview = false, string $order = 'commented', int $uid = 0): string { $this->profiler->startRecording('rendering'); @@ -457,12 +465,14 @@ class Conversation $live_update_div = ''; - $blocklist = $this->getBlocklist(); + $userGservers = $this->userGServer->listIgnoredByUser($this->session->getLocalUserId()); - $previewing = (($preview) ? ' preview ' : ''); + $ignoredGsids = array_map(function (UserGServer $userGServer) { + return $userGServer->gsid; + }, $userGservers->getArrayCopy()); if ($mode === self::MODE_NETWORK) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { /* * The special div is needed for liveUpdate to kick in for this page. @@ -488,7 +498,7 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_PROFILE) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $tab = !empty($_GET['tab']) ? trim($_GET['tab']) : 'posts'; @@ -513,7 +523,7 @@ class Conversation . "; var netargs = '?f='; \r\n"; } } elseif ($mode === self::MODE_DISPLAY) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -521,7 +531,7 @@ class Conversation . ""; } } elseif ($mode === self::MODE_COMMUNITY) { - $items = $this->addChildren($items, true, $order, $uid, $mode); + $items = $this->addChildren($items, true, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" @@ -532,12 +542,12 @@ class Conversation . "'; \r\n"; } } elseif ($mode === self::MODE_CONTACTS) { - $items = $this->addChildren($items, false, $order, $uid, $mode); + $items = $this->addChildren($items, false, $order, $uid, $mode, $ignoredGsids); if (!$update) { $live_update_div = '
' . "\r\n" . "\r\n"; + . "?f='; \r\n"; } } elseif ($mode === self::MODE_SEARCH) { $live_update_div = '' . "\r\n"; @@ -554,240 +564,14 @@ class Conversation $items = $cb['items']; - $conv_responses = [ - 'like' => [], - 'dislike' => [], - 'attendyes' => [], - 'attendno' => [], - 'attendmaybe' => [], - 'announce' => [], - ]; - - if ($this->pConfig->get($this->session->getLocalUserId(), 'system', 'hide_dislike')) { - unset($conv_responses['dislike']); - } - - // array with html for each thread (parent+comments) - $threads = []; - $threadsid = -1; - - $page_template = Renderer::getMarkupTemplate("conversation.tpl"); $formSecurityToken = BaseModule::getFormSecurityToken('contact_action'); - if (!empty($items)) { - 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); - } + $threads = $this->getThreadList($items, $mode, $preview, $page_dropping, $formSecurityToken); - if (!$this->session->getLocalUserId()) { - $writable = false; - } - - if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) { - - /* - * "New Item View" on network page or search page results - * - just loop through the items and format them minimally for display - */ - - $tpl = 'search_item.tpl'; - - $uriids = []; - - foreach ($items as $item) { - if (in_array($item['uri-id'], $uriids)) { - continue; - } - - $uriids[] = $item['uri-id']; - - if (!$this->item->isVisibleActivity($item)) { - continue; - } - - if (in_array($item['author-id'], $blocklist)) { - continue; - } - - $threadsid++; - - // prevent private email from leaking. - if ($item['network'] === Protocol::MAIL && $this->session->getLocalUserId() != $item['uid']) { - continue; - } - - $profile_name = $item['author-name']; - if (!empty($item['author-link']) && empty($item['author-name'])) { - $profile_name = $item['author-link']; - } - - $tags = Tag::populateFromItem($item); - - $author = ['uid' => 0, 'id' => $item['author-id'], 'network' => $item['author-network'], 'url' => $item['author-link']]; - $profile_link = Contact::magicLinkByContact($author); - - $sparkle = ''; - if (strpos($profile_link, 'contact/redir/') === 0) { - $sparkle = ' sparkle'; - } - - $locate = ['location' => $item['location'], 'coord' => $item['coord'], 'html' => '']; - Hook::callAll('render_location', $locate); - $location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: ''); - - $this->item->localize($item); - if ($mode === self::MODE_FILED) { - $dropping = true; - } else { - $dropping = false; - } - - $drop = [ - 'dropping' => $dropping, - 'pagedrop' => $page_dropping, - 'select' => $this->l10n->t('Select'), - 'delete' => $this->l10n->t('Delete'), - ]; - - $likebuttons = [ - 'like' => null, - 'dislike' => null, - 'share' => null, - 'announce' => null, - ]; - - if ($this->pConfig->get($this->session->getLocalUserId(), 'system', 'hide_dislike')) { - unset($likebuttons['dislike']); - } - - $body_html = ItemModel::prepareBody($item, true, $preview); - - [$categories, $folders] = $this->item->determineCategoriesTerms($item, $this->session->getLocalUserId()); - - if (!empty($item['title'])) { - $title = $item['title']; - } elseif (!empty($item['content-warning']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'disable_cw', false)) { - $title = ucfirst($item['content-warning']); - } else { - $title = ''; - } - - if (!empty($item['featured'])) { - $pinned = $this->l10n->t('Pinned item'); - } else { - $pinned = ''; - } - - $tmp_item = [ - 'template' => $tpl, - 'id' => ($preview ? 'P0' : $item['id']), - 'guid' => ($preview ? 'Q0' : $item['guid']), - 'commented' => $item['commented'], - 'received' => $item['received'], - 'created_date' => $item['created'], - 'uriid' => $item['uri-id'], - 'network' => $item['network'], - 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), - 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']), - 'linktitle' => $this->l10n->t('View %s\'s profile @ %s', $profile_name, $item['author-link']), - 'profile_url' => $profile_link, - 'item_photo_menu_html' => $this->item->photoMenu($item, $formSecurityToken), - 'name' => $profile_name, - 'sparkle' => $sparkle, - 'lock' => false, - 'thumb' => $this->baseURL->remove($this->item->getAuthorAvatar($item)), - 'title' => $title, - 'body_html' => $body_html, - 'tags' => $tags['tags'], - 'hashtags' => $tags['hashtags'], - 'mentions' => $tags['mentions'], - 'implicit_mentions' => $tags['implicit_mentions'], - 'txt_cats' => $this->l10n->t('Categories:'), - 'txt_folders' => $this->l10n->t('Filed under:'), - 'has_cats' => ((count($categories)) ? 'true' : ''), - 'has_folders' => ((count($folders)) ? 'true' : ''), - 'categories' => $categories, - 'folders' => $folders, - 'text' => strip_tags($body_html), - 'localtime' => DateTimeFormat::local($item['created'], 'r'), - 'utc' => DateTimeFormat::utc($item['created'], 'c'), - 'ago' => (($item['app']) ? $this->l10n->t('%s from %s', Temporal::getRelativeDate($item['created']), $item['app']) : Temporal::getRelativeDate($item['created'])), - 'location_html' => $location_html, - 'indent' => '', - 'owner_name' => '', - 'owner_url' => '', - 'owner_photo' => $this->baseURL->remove($this->item->getOwnerAvatar($item)), - 'plink' => ItemModel::getPlink($item), - 'edpost' => false, - 'pinned' => $pinned, - 'isstarred' => 'unstarred', - 'star' => false, - 'drop' => $drop, - 'vote' => $likebuttons, - 'like_html' => '', - 'dislike_html ' => '', - 'comment_html' => '', - 'conv' => ($preview ? '' : ['href' => 'display/' . $item['guid'], 'title' => $this->l10n->t('View in context')]), - 'previewing' => $previewing, - 'wait' => $this->l10n->t('Please wait'), - 'thread_level' => 1, - ]; - - $arr = ['item' => $item, 'output' => $tmp_item]; - Hook::callAll('display_item', $arr); - - $threads[$threadsid]['id'] = $item['id']; - $threads[$threadsid]['network'] = $item['network']; - $threads[$threadsid]['items'] = [$arr['output']]; - } - } else { - // Normal View - $page_template = Renderer::getMarkupTemplate("threaded_conversation.tpl"); - - $conv = new Thread($mode, $preview, $writable); - - /* - * get all the topmost parents - * this shouldn't be needed, as we should have only them in our array - * But for now, this array respects the old style, just in case - */ - foreach ($items as $item) { - if (in_array($item['author-id'], $blocklist)) { - continue; - } - - // Can we put this after the visibility check? - $this->builtinActivityPuller($item, $conv_responses); - - // Only add what is visible - if ($item['network'] === Protocol::MAIL && $this->session->getLocalUserId() != $item['uid']) { - continue; - } - - if (!$this->item->isVisibleActivity($item)) { - continue; - } - - /// @todo Check if this call is needed or not - $arr = ['item' => $item]; - Hook::callAll('display_item', $arr); - - $item['pagedrop'] = $page_dropping; - - if ($item['gravity'] == ItemModel::GRAVITY_PARENT) { - $item_object = new PostObject($item); - $conv->addParent($item_object); - } - } - - $threads = $conv->getTemplateData($conv_responses, $formSecurityToken); - if (!$threads) { - $this->logger->info('[ERROR] conversation : Failed to get template data.'); - $threads = []; - } - } + if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) { + $page_template = Renderer::getMarkupTemplate('conversation.tpl'); + } else { + $page_template = Renderer::getMarkupTemplate('threaded_conversation.tpl'); } $o = Renderer::replaceMacros($page_template, [ @@ -805,6 +589,95 @@ class Conversation return $o; } + /** + * @param array $items + * @param string $mode One of self::MODE_* + * @param bool $preview + * @param bool $pagedrop Whether to enable the user to select the thread for deletion + * @param string $formSecurityToken A 'contact_action' form security token + * @return array + * @throws InternalServerErrorException + * @throws \ImagickException + */ + public function getThreadList(array $items, string $mode, bool $preview, bool $pagedrop, string $formSecurityToken): array + { + if (!$items) { + return []; + } + + if (in_array($mode, [self::MODE_FILED, self::MODE_SEARCH, self::MODE_CONTACT_POSTS])) { + $threads = $this->getContextLessThreadList($items, $mode, $preview, $pagedrop, $formSecurityToken); + } else { + $conv_responses = [ + 'like' => [], + 'dislike' => [], + 'attendyes' => [], + 'attendno' => [], + 'attendmaybe' => [], + 'announce' => [], + ]; + + if ($this->pConfig->get($this->session->getLocalUserId(), 'system', 'hide_dislike')) { + unset($conv_responses['dislike']); + } + + 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); + } + + if (!$this->session->getLocalUserId()) { + $writable = false; + } + + // Normal View + $conv = new Thread($mode, $preview, $writable); + + /* + * get all the topmost parents + * this shouldn't be needed, as we should have only them in our array + * But for now, this array respects the old style, just in case + */ + foreach ($items as $item) { + if (in_array($item['author-id'], $this->getBlocklist())) { + continue; + } + + // Can we put this after the visibility check? + $this->builtinActivityPuller($item, $conv_responses); + + // Only add what is visible + if ($item['network'] === Protocol::MAIL && $this->session->getLocalUserId() != $item['uid']) { + continue; + } + + if (!$this->item->isVisibleActivity($item)) { + continue; + } + + /// @todo Check if this call is needed or not + $arr = ['item' => $item]; + Hook::callAll('display_item', $arr); + + $item['pagedrop'] = $pagedrop; + + if ($item['gravity'] == ItemModel::GRAVITY_PARENT) { + $item_object = new PostObject($item); + $conv->addParent($item_object); + } + } + + $threads = $conv->getTemplateData($conv_responses, $formSecurityToken); + if (!$threads) { + $this->logger->info('[ERROR] conversation : Failed to get template data.'); + $threads = []; + } + } + + return $threads; + } + private function getBlocklist(): array { if (!$this->session->getLocalUserId()) { @@ -856,7 +729,8 @@ class Conversation $row['causer-avatar'] = $contact['thumb']; $row['causer-name'] = $contact['name']; } elseif (($row['gravity'] == ItemModel::GRAVITY_ACTIVITY) && ($row['verb'] == Activity::ANNOUNCE) && - ($row['author-id'] == $activity['causer-id'])) { + ($row['author-id'] == $activity['causer-id']) + ) { return $row; } } @@ -881,7 +755,12 @@ class Conversation $row['direction'] = ['direction' => 6, 'title' => $this->l10n->t('You are following %s.', $row['causer-name'] ?: $row['author-name'])]; break; case ItemModel::PR_TAG: - $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + $tags = Category::getArrayByURIId($row['uri-id'], $row['uid'], Category::SUBCRIPTION); + if (!empty($tags)) { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to %s.', implode(', ', $tags))]; + } else { + $row['direction'] = ['direction' => 4, 'title' => $this->l10n->t('You subscribed to one or more tags in this post.')]; + } break; case ItemModel::PR_ANNOUNCEMENT: if (!empty($row['causer-id']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'display_resharer')) { @@ -892,9 +771,15 @@ class Conversation } if (in_array($row['gravity'], [ItemModel::GRAVITY_PARENT, ItemModel::GRAVITY_COMMENT]) && !empty($row['causer-id'])) { - $causer = ['uid' => 0, 'id' => $row['causer-id'], 'network' => $row['causer-network'], 'url' => $row['causer-link']]; + $causer = [ + 'uid' => 0, + 'id' => $row['causer-id'], + 'network' => $row['causer-network'], + 'url' => $row['causer-link'], + 'alias' => $row['causer-alias'], + ]; - $row['reshared'] = $this->l10n->t('%s reshared this.', '' . htmlentities($row['causer-name']) . ''); + $row['reshared'] = $this->l10n->t('%s reshared this.', '' . htmlentities($row['causer-name']) . ''); } $row['direction'] = ['direction' => 3, 'title' => (empty($row['causer-id']) ? $this->l10n->t('Reshared') : $this->l10n->t('Reshared by %s <%s>', $row['causer-name'], $row['causer-link']))]; break; @@ -944,13 +829,14 @@ class Conversation * * @param array $parents Parent items * @param bool $block_authors - * @param bool $order + * @param string $order Either "received" or "commented" * @param int $uid - * @param string $mode + * @param string $mode One of self::MODE_* + * @param array $ignoredGsids List of ids of servers ignored by the user * @return array items with parents and comments - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * @throws InternalServerErrorException */ - private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode): array + private function addChildren(array $parents, bool $block_authors, string $order, int $uid, string $mode, array $ignoredGsids = []): array { $this->profiler->startRecording('rendering'); if (count($parents) > 1) { @@ -994,15 +880,21 @@ class Conversation $condition = DBA::mergeConditions($condition, ["(`gravity` != ? OR `origin`)", ItemModel::GRAVITY_ACTIVITY]); } - $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, + ["`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, ["(`uid` != ? OR `private` != ?)", 0, ItemModel::PRIVATE]); - $condition = DBA::mergeConditions($condition, - ["`visible` AND NOT `deleted` AND NOT `author-blocked` AND NOT `owner-blocked` + $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]); + Contact::SHARING, Contact::FRIEND, 0 + ] + ); $thread_parents = Post::select(['uri-id', 'causer-id'], $condition, ['order' => ['uri-id' => false, 'uid']]); @@ -1026,6 +918,13 @@ class Conversation continue; } + if (in_array($row['author-gsid'], $ignoredGsids) + || in_array($row['owner-gsid'], $ignoredGsids) + || in_array($row['causer-gsid'], $ignoredGsids) + ) { + continue; + } + if (($mode != self::MODE_CONTACTS) && !$row['origin']) { $row['featured'] = false; } @@ -1109,8 +1008,10 @@ class Conversation $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))) { + 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]); } } @@ -1145,7 +1046,7 @@ class Conversation $condition = DBA::mergeConditions(['parent-uri-id' => $uriids, 'gravity' => ItemModel::GRAVITY_ACTIVITY, 'verb' => $verbs], ["NOT `deleted`"]); $separator = chr(255) . chr(255) . chr(255); - $sql = "SELECT `thr-parent-id`, `body`, `verb`, COUNT(*) AS `total`, GROUP_CONCAT(REPLACE(`author-name`, '" . $separator . "', ' ') SEPARATOR '". $separator ."' LIMIT 50) AS `title` FROM `post-view` WHERE " . array_shift($condition) . " GROUP BY `thr-parent-id`, `verb`, `body`"; + $sql = "SELECT `thr-parent-id`, `body`, `verb`, COUNT(*) AS `total`, GROUP_CONCAT(REPLACE(`author-name`, '" . $separator . "', ' ') SEPARATOR '" . $separator . "' LIMIT 50) AS `title` FROM `post-view` WHERE " . array_shift($condition) . " GROUP BY `thr-parent-id`, `verb`, `body`"; $emojis = []; @@ -1286,7 +1187,7 @@ class Conversation // Searches the post item in the children $j = 0; while ($child['children'][$j]['verb'] !== Activity::POST && $j < count($child['children'])) { - $j ++; + $j++; } $moved_item = $child['children'][$j]; @@ -1360,8 +1261,10 @@ class Conversation * items and add them as children of their top-level post. */ foreach ($parents as $i => $parent) { - $parents[$i]['children'] = array_merge($this->getItemChildren($item_array, $parent, true), - $this->getItemChildren($item_array, $parent, false)); + $parents[$i]['children'] = array_merge( + $this->getItemChildren($item_array, $parent, true), + $this->getItemChildren($item_array, $parent, false) + ); } foreach ($parents as $i => $parent) { @@ -1469,4 +1372,179 @@ class Conversation { return strcmp($b['created'], $a['created']); } + + /** + * "New Item View" on network page or search page results + * - just loop through the items and format them minimally for display + * + * @param array $items + * @param string $mode One of self::MODE_* + * @param bool $preview Whether the display is a preview + * @param bool $pagedrop Whether the user can select the threads for deletion + * @param string $formSecurityToken A 'contact_action' form security token + * @return array + * @throws InternalServerErrorException + * @throws \ImagickException + */ + public function getContextLessThreadList(array $items, string $mode, bool $preview, bool $pagedrop, string $formSecurityToken): array + { + $threads = []; + $uriids = []; + + foreach ($items as $item) { + if (in_array($item['uri-id'], $uriids)) { + continue; + } + + $uriids[] = $item['uri-id']; + + if (!$this->item->isVisibleActivity($item)) { + continue; + } + + if (in_array($item['author-id'], $this->getBlocklist())) { + continue; + } + + // prevent private email from leaking. + if ($item['network'] === Protocol::MAIL && $this->session->getLocalUserId() != $item['uid']) { + continue; + } + + $profile_name = $item['author-name']; + if (!empty($item['author-link']) && empty($item['author-name'])) { + $profile_name = $item['author-link']; + } + + $tags = Tag::populateFromItem($item); + + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'], + ]; + $profile_link = Contact::magicLinkByContact($author); + + $sparkle = ''; + if (strpos($profile_link, 'contact/redir/') === 0) { + $sparkle = ' sparkle'; + } + + $locate = ['location' => $item['location'], 'coord' => $item['coord'], 'html' => '']; + Hook::callAll('render_location', $locate); + $location_html = $locate['html'] ?: Strings::escapeHtml($locate['location'] ?: $locate['coord'] ?: ''); + + $this->item->localize($item); + if ($mode === self::MODE_FILED) { + $dropping = true; + } else { + $dropping = false; + } + + $drop = [ + 'dropping' => $dropping, + 'pagedrop' => $pagedrop, + 'select' => $this->l10n->t('Select'), + 'delete' => $this->l10n->t('Delete'), + ]; + + $likebuttons = [ + 'like' => null, + 'dislike' => null, + 'share' => null, + 'announce' => null, + ]; + + if ($this->pConfig->get($this->session->getLocalUserId(), 'system', 'hide_dislike')) { + unset($likebuttons['dislike']); + } + + $body_html = ItemModel::prepareBody($item, true, $preview); + + [$categories, $folders] = $this->item->determineCategoriesTerms($item, $this->session->getLocalUserId()); + + if (!empty($item['title'])) { + $title = $item['title']; + } elseif (!empty($item['content-warning']) && $this->pConfig->get($this->session->getLocalUserId(), 'system', 'disable_cw', false)) { + $title = ucfirst($item['content-warning']); + } else { + $title = ''; + } + + if (!empty($item['featured'])) { + $pinned = $this->l10n->t('Pinned item'); + } else { + $pinned = ''; + } + + $tmp_item = [ + 'template' => 'search_item.tpl', + 'id' => ($preview ? 'P0' : $item['id']), + 'guid' => ($preview ? 'Q0' : $item['guid']), + 'commented' => $item['commented'], + 'received' => $item['received'], + 'created_date' => $item['created'], + 'uriid' => $item['uri-id'], + 'author_gsid' => $item['author-gsid'], + 'network' => $item['network'], + 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), + 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']), + 'linktitle' => $this->l10n->t('View %s\'s profile @ %s', $profile_name, $item['author-link']), + 'profile_url' => $profile_link, + 'item_photo_menu_html' => $this->item->photoMenu($item, $formSecurityToken), + 'name' => $profile_name, + 'sparkle' => $sparkle, + 'lock' => false, + 'thumb' => $this->baseURL->remove($this->item->getAuthorAvatar($item)), + 'title' => $title, + 'body_html' => $body_html, + 'tags' => $tags['tags'], + 'hashtags' => $tags['hashtags'], + 'mentions' => $tags['mentions'], + 'implicit_mentions' => $tags['implicit_mentions'], + 'txt_cats' => $this->l10n->t('Categories:'), + 'txt_folders' => $this->l10n->t('Filed under:'), + 'has_cats' => ((count($categories)) ? 'true' : ''), + 'has_folders' => ((count($folders)) ? 'true' : ''), + 'categories' => $categories, + 'folders' => $folders, + 'text' => strip_tags($body_html), + 'localtime' => DateTimeFormat::local($item['created'], 'r'), + 'utc' => DateTimeFormat::utc($item['created'], 'c'), + 'ago' => (($item['app']) ? $this->l10n->t('%s from %s', Temporal::getRelativeDate($item['created']), $item['app']) : Temporal::getRelativeDate($item['created'])), + 'location_html' => $location_html, + 'indent' => '', + 'owner_name' => '', + 'owner_url' => '', + 'owner_photo' => $this->baseURL->remove($this->item->getOwnerAvatar($item)), + 'plink' => ItemModel::getPlink($item), + 'edpost' => false, + 'pinned' => $pinned, + 'isstarred' => 'unstarred', + 'star' => false, + 'drop' => $drop, + 'vote' => $likebuttons, + 'like_html' => '', + 'dislike_html ' => '', + 'comment_html' => '', + 'conv' => $preview ? '' : ['href' => 'display/' . $item['guid'], 'title' => $this->l10n->t('View in context')], + 'previewing' => $preview ? ' preview ' : '', + 'wait' => $this->l10n->t('Please wait'), + 'thread_level' => 1, + ]; + + $arr = ['item' => $item, 'output' => $tmp_item]; + Hook::callAll('display_item', $arr); + + $threads[] = [ + 'id' => $item['id'], + 'network' => $item['network'], + 'items' => [$arr['output']], + ]; + } + + return $threads; + } } diff --git a/src/Content/Feature.php b/src/Content/Feature.php index f97a03011..b9b9d2e0e 100644 --- a/src/Content/Feature.php +++ b/src/Content/Feature.php @@ -102,7 +102,7 @@ class Feature // Post composition 'composition' => [ DI::l10n()->t('Post Composition Features'), - ['aclautomention', DI::l10n()->t('Auto-mention Forums'), DI::l10n()->t('Add/remove mention when a forum page is selected/deselected in ACL window.'), false, DI::config()->get('feature_lock', 'aclautomention', false)], + ['aclautomention', DI::l10n()->t('Auto-mention Groups'), DI::l10n()->t('Add/remove mention when a group page is selected/deselected in ACL window.'), false, DI::config()->get('feature_lock', 'aclautomention', false)], ['explicit_mentions', DI::l10n()->t('Explicit Mentions'), DI::l10n()->t('Add explicit mentions to comment box for manual control over who gets mentioned in replies.'), false, DI::config()->get('feature_lock', 'explicit_mentions', false)], ['add_abstract', DI::l10n()->t('Add an abstract from ActivityPub content warnings'), DI::l10n()->t('Add an abstract when commenting on ActivityPub posts with a content warning. Abstracts are displayed as content warning on systems like Mastodon or Pleroma.'), false, DI::config()->get('feature_lock', 'add_abstract', false)], ], @@ -116,7 +116,7 @@ class Feature // Advanced Profile Settings 'advanced_profile' => [ DI::l10n()->t('Advanced Profile Settings'), - ['forumlist_profile', DI::l10n()->t('List Forums'), DI::l10n()->t('Show visitors public community forums at the Advanced Profile Page'), false, DI::config()->get('feature_lock', 'forumlist_profile', false)], + ['forumlist_profile', DI::l10n()->t('List Groups'), DI::l10n()->t('Show visitors public groups at the Advanced Profile Page'), false, DI::config()->get('feature_lock', 'forumlist_profile', false)], ['tagadelic', DI::l10n()->t('Tag Cloud'), DI::l10n()->t('Provide a personal tag cloud on your profile page'), false, DI::config()->get('feature_lock', 'tagadelic', false)], ['profile_membersince', DI::l10n()->t('Display Membership Date'), DI::l10n()->t('Display membership date in profile'), false, DI::config()->get('feature_lock', 'profile_membersince', false)], ], diff --git a/src/Content/ForumManager.php b/src/Content/GroupManager.php similarity index 77% rename from src/Content/ForumManager.php rename to src/Content/GroupManager.php index 5decaac14..fc43080d9 100644 --- a/src/Content/ForumManager.php +++ b/src/Content/GroupManager.php @@ -29,21 +29,21 @@ use Friendica\DI; use Friendica\Model\Contact; /** - * This class handles methods related to the forum functionality + * This class handles methods related to the group functionality */ -class ForumManager +class GroupManager { /** - * Function to list all forums a user is connected with + * Function to list all groups a user is connected with * * @param int $uid of the profile owner * @param boolean $lastitem Sort by lastitem - * @param boolean $showhidden Show forums which are not hidden + * @param boolean $showhidden Show groups which are not hidden * @param boolean $showprivate Show private groups * * @return array - * 'url' => forum url - * 'name' => forum name + * 'url' => group url + * 'name' => group name * 'id' => number of the key from the array * 'micro' => contact photo in format micro * 'thumb' => contact photo in format thumb @@ -76,17 +76,18 @@ class ForumManager $condition = DBA::mergeConditions($condition, ['hidden' => false]); } - $forumlist = []; + $groupList = []; - $fields = ['id', 'url', 'name', 'micro', 'thumb', 'avatar', 'network', 'uid']; + $fields = ['id', 'url', 'alias', 'name', 'micro', 'thumb', 'avatar', 'network', 'uid']; $contacts = DBA::select('account-user-view', $fields, $condition, $params); if (!$contacts) { - return($forumlist); + return $groupList; } while ($contact = DBA::fetch($contacts)) { - $forumlist[] = [ + $groupList[] = [ 'url' => $contact['url'], + 'alias' => $contact['alias'], 'name' => $contact['name'], 'id' => $contact['id'], 'micro' => $contact['micro'], @@ -95,19 +96,19 @@ class ForumManager } DBA::close($contacts); - return($forumlist); + return($groupList); } /** - * Forumlist widget + * Group list widget * - * Sidebar widget to show subscribed friendica forums. If activated - * in the settings, it appears at the notwork page sidebar + * Sidebar widget to show subscribed Friendica groups. If activated + * in the settings, it appears in the network page sidebar * * @param string $baseurl Base module path * @param int $uid The ID of the User - * @param int $cid The contact id which is used to mark a forum as "selected" + * @param int $cid The contact id which is used to mark a group as "selected" * @return string * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException @@ -121,7 +122,7 @@ class ForumManager $contacts = self::getList($uid, $lastitem, true, true); $total = count($contacts); - $visible_forums = 10; + $visibleGroups = 10; if (DBA::isResult($contacts)) { $id = 0; @@ -129,7 +130,7 @@ class ForumManager $entries = []; foreach ($contacts as $contact) { - $selected = (($cid == $contact['id']) ? ' forum-selected' : ''); + $selected = (($cid == $contact['id']) ? ' group-selected' : ''); $entry = [ 'url' => $baseurl . '/' . $contact['id'], @@ -143,18 +144,20 @@ class ForumManager $entries[] = $entry; } - $tpl = Renderer::getMarkupTemplate('widget_forumlist.tpl'); + $tpl = Renderer::getMarkupTemplate('widget/group_list.tpl'); $o .= Renderer::replaceMacros( $tpl, [ - '$title' => DI::l10n()->t('Forums'), - '$forums' => $entries, - '$link_desc' => DI::l10n()->t('External link to forum'), + '$title' => DI::l10n()->t('Groups'), + '$groups' => $entries, + '$link_desc' => DI::l10n()->t('External link to group'), + '$new_group_page' => 'register/', '$total' => $total, - '$visible_forums' => $visible_forums, + '$visible_groups' => $visibleGroups, '$showless' => DI::l10n()->t('show less'), - '$showmore' => DI::l10n()->t('show more')] + '$showmore' => DI::l10n()->t('show more'), + '$create_new_group' => DI::l10n()->t('Create new group')] ); } @@ -162,9 +165,9 @@ class ForumManager } /** - * Format forumlist as contact block + * Format group list as contact block * - * This function is used to show the forumlist in + * This function is used to show the group list in * the advanced profile. * * @param int $uid The ID of the User @@ -181,7 +184,7 @@ class ForumManager $o = ''; - // place holder in case somebody wants configurability + // placeholder in case somebody wants configurability $show_total = 9999; //don't sort by last updated item @@ -191,7 +194,7 @@ class ForumManager $total_shown = 0; foreach ($contacts as $contact) { - $o .= HTML::micropro($contact, true, 'forumlist-profile-advanced'); + $o .= HTML::micropro($contact, true, 'grouplist-profile-advanced'); $total_shown++; if ($total_shown == $show_total) { break; @@ -202,14 +205,14 @@ class ForumManager } /** - * count unread forum items + * count unread group items * - * Count unread items of connected forums and private groups + * Count unread items of connected groups and private groups * * @return array * 'id' => contact id - * 'name' => contact/forum name - * 'count' => counted unseen forum items + * 'name' => contact/group name + * 'count' => counted unseen group items * @throws \Exception */ public static function countUnseenItems() diff --git a/src/Content/Item.php b/src/Content/Item.php index 172729f26..163db89aa 100644 --- a/src/Content/Item.php +++ b/src/Content/Item.php @@ -34,15 +34,16 @@ use Friendica\Core\Protocol; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\DBA; +use Friendica\DI; use Friendica\Model\Attach; +use Friendica\Model\Circle; use Friendica\Model\Contact; use Friendica\Model\Conversation; use Friendica\Model\FileTag; -use Friendica\Model\Group; use Friendica\Model\Item as ItemModel; use Friendica\Model\Photo; -use Friendica\Model\Tag; use Friendica\Model\Post; +use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Network\HTTPException; use Friendica\Object\EMail\ItemCCEMail; @@ -54,6 +55,7 @@ use Friendica\Util\ParseUrl; use Friendica\Util\Profiler; use Friendica\Util\Proxy; use Friendica\Util\XML; +use GuzzleHttp\Psr7\Uri; /** * A content helper class for displaying items @@ -305,18 +307,20 @@ class Item } $author_arr = [ - 'uid' => 0, - 'id' => $item['author-id'], + 'uid' => 0, + 'id' => $item['author-id'], 'network' => $item['author-network'], - 'url' => $item['author-link'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'], ]; $author = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $item['author-name'] . '[/url]'; $author_arr = [ - 'uid' => 0, - 'id' => $obj['author-id'], + 'uid' => 0, + 'id' => $obj['author-id'], 'network' => $obj['author-network'], - 'url' => $obj['author-link'], + 'url' => $obj['author-link'], + 'alias' => $obj['author-alias'], ]; $objauthor = '[url=' . Contact::magicLinkByContact($author_arr) . ']' . $obj['author-name'] . '[/url]'; @@ -365,17 +369,18 @@ class Item { $this->profiler->startRecording('rendering'); $sub_link = $contact_url = $pm_url = $status_link = ''; - $photos_link = $posts_link = $block_link = $ignore_link = ''; + $photos_link = $posts_link = $block_link = $ignore_link = $collapse_link = $ignoreserver_link = ''; if ($this->userSession->getLocalUserId() && $this->userSession->getLocalUserId() == $item['uid'] && $item['gravity'] == ItemModel::GRAVITY_PARENT && !$item['self'] && !$item['mention']) { $sub_link = 'javascript:doFollowThread(' . $item['id'] . '); return false;'; } $author = [ - 'uid' => 0, - 'id' => $item['author-id'], + 'uid' => 0, + 'id' => $item['author-id'], 'network' => $item['author-network'], - 'url' => $item['author-link'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'], ]; $profile_link = Contact::magicLinkByContact($author, $item['author-link']); if (strpos($profile_link, 'contact/redir/') === 0) { @@ -404,6 +409,11 @@ class Item $collapse_link = $item['self'] ? '' : $contact_url . '/collapse?t=' . $formSecurityToken; } + $authorBaseUri = new Uri($item['author-baseurl'] ?? ''); + if (!empty($item['author-gsid']) && $authorBaseUri->getHost() && !DI::baseUrl()->isLocalUrl($authorBaseUri)) { + $ignoreserver_link = 'settings/server/' . $item['author-gsid'] . '/ignore'; + } + if ($cid && !$item['self']) { $contact_url = 'contact/' . $cid; $posts_link = $contact_url . '/posts'; @@ -424,7 +434,8 @@ class Item $this->l10n->t('Send PM') => $pm_url, $this->l10n->t('Block') => $block_link, $this->l10n->t('Ignore') => $ignore_link, - $this->l10n->t('Collapse') => $collapse_link + $this->l10n->t('Collapse') => $collapse_link, + $this->l10n->t("Ignore %s server", $authorBaseUri->getHost()) => $ignoreserver_link, ]; if (!empty($item['language'])) { @@ -484,16 +495,16 @@ class Item { // Look for any tags and linkify them $item['inform'] = ''; - $private_forum = false; + $private_group = false; $private_id = null; - $only_to_forum = false; - $forum_contact = []; + $only_to_group = false; + $group_contact = []; $receivers = []; // Convert mentions in the body to a unified format $item['body'] = BBCode::setMentions($item['body'], $item['uid'], $item['network']); - // Search for forum mentions + // Search for group mentions foreach (Tag::getFromBody($item['body'], Tag::TAG_CHARACTER[Tag::MENTION] . Tag::TAG_CHARACTER[Tag::EXCLUSIVE_MENTION]) as $tag) { $contact = Contact::getByURLForUser($tag[2], $item['uid']); if (empty($contact)) { @@ -512,37 +523,45 @@ class Item } if (!empty($contact['prv']) || ($tag[1] == Tag::TAG_CHARACTER[Tag::EXCLUSIVE_MENTION])) { - $private_forum = $contact['prv']; - $only_to_forum = ($tag[1] == Tag::TAG_CHARACTER[Tag::EXCLUSIVE_MENTION]); + $private_group = $contact['prv']; + $only_to_group = ($tag[1] == Tag::TAG_CHARACTER[Tag::EXCLUSIVE_MENTION]); $private_id = $contact['id']; - $forum_contact = $contact; - Logger::info('Private forum or exclusive mention', ['url' => $tag[2], 'mention' => $tag[1]]); + $group_contact = $contact; + Logger::info('Private group or exclusive mention', ['url' => $tag[2], 'mention' => $tag[1]]); } elseif ($item['allow_cid'] == '<' . $contact['id'] . '>') { - $private_forum = false; - $only_to_forum = true; + $private_group = false; + $only_to_group = true; $private_id = $contact['id']; - $forum_contact = $contact; - Logger::info('Public forum', ['url' => $tag[2], 'mention' => $tag[1]]); + $group_contact = $contact; + Logger::info('Public group', ['url' => $tag[2], 'mention' => $tag[1]]); } else { - Logger::info('Post with forum mention will not be converted to a forum post', ['url' => $tag[2], 'mention' => $tag[1]]); + Logger::info('Post with group mention will not be converted to a group post', ['url' => $tag[2], 'mention' => $tag[1]]); } } Logger::info('Got inform', ['inform' => $item['inform']]); - if (($item['gravity'] == ItemModel::GRAVITY_PARENT) && !empty($forum_contact) && ($private_forum || $only_to_forum)) { - // we tagged a forum in a top level post. Now we change the post - $item['private'] = $private_forum ? ItemModel::PRIVATE : ItemModel::UNLISTED; + if (($item['gravity'] == ItemModel::GRAVITY_PARENT) && !empty($group_contact) && ($private_group || $only_to_group)) { + // we tagged a group in a top level post. Now we change the post + $item['private'] = $private_group ? ItemModel::PRIVATE : ItemModel::UNLISTED; + + if ($only_to_group) { + $cdata = Contact::getPublicAndUserContactID($group_contact['id'], $item['uid']); + if (!empty($cdata['user'])) { + $item['owner-id'] = $cdata['user']; + unset($item['owner-link']); + unset($item['owner-name']); + unset($item['owner-avatar']); + } - if ($only_to_forum) { $item['postopts'] = ''; } $item['deny_cid'] = ''; $item['deny_gid'] = ''; - if ($private_forum) { + if ($private_group) { $item['allow_cid'] = '<' . $private_id . '>'; - $item['allow_gid'] = '<' . Group::getIdForForum($forum_contact['id']) . '>'; + $item['allow_gid'] = '<' . Circle::getIdForGroup($group_contact['id']) . '>'; } else { $item['allow_cid'] = ''; $item['allow_gid'] = ''; @@ -658,14 +677,15 @@ class Item * Add a share block for the given item array * * @param array $item - * @param bool $add_media + * @param bool $add_media true = Media is added to the body + * @param bool $for_display true = The share block is used for display purposes, false = used for connectors, transport to other systems, ... * @return string */ - public function createSharedBlockByArray(array $item, bool $add_media = false): string + public function createSharedBlockByArray(array $item, bool $add_media = false, bool $for_display = false): string { if ($item['network'] == Protocol::FEED) { return PageInfo::getFooterFromUrl($item['plink']); - } elseif (!in_array($item['network'] ?? '', Protocol::FEDERATED)) { + } elseif (!in_array($item['network'] ?? '', Protocol::FEDERATED) && !$for_display) { $item['guid'] = ''; $item['uri'] = ''; } @@ -684,7 +704,7 @@ class Item // If it is a reshared post then reformat it to avoid display problems with two share elements if (!empty($shared)) { - if (!empty($shared['guid']) && ($encapsulated_share = $this->createSharedPostByGuid($shared['guid'], true))) { + if (($item['network'] != Protocol::BLUESKY) && !empty($shared['guid']) && ($encapsulated_share = $this->createSharedPostByGuid($shared['guid'], true))) { if (!empty(BBCode::fetchShareAttributes($item['body']))) { $item['body'] = preg_replace("/\[share.*?\](.*)\[\/share\]/ism", $encapsulated_share, $item['body']); } else { @@ -863,9 +883,9 @@ class Item } $post['allow_cid'] = isset($request['contact_allow']) ? $this->aclFormatter->toString($request['contact_allow']) : $user['allow_cid'] ?? ''; - $post['allow_gid'] = isset($request['group_allow']) ? $this->aclFormatter->toString($request['group_allow']) : $user['allow_gid'] ?? ''; + $post['allow_gid'] = isset($request['circle_allow']) ? $this->aclFormatter->toString($request['circle_allow']) : $user['allow_gid'] ?? ''; $post['deny_cid'] = isset($request['contact_deny']) ? $this->aclFormatter->toString($request['contact_deny']) : $user['deny_cid'] ?? ''; - $post['deny_gid'] = isset($request['group_deny']) ? $this->aclFormatter->toString($request['group_deny']) : $user['deny_gid'] ?? ''; + $post['deny_gid'] = isset($request['circle_deny']) ? $this->aclFormatter->toString($request['circle_deny']) : $user['deny_gid'] ?? ''; $visibility = $request['visibility'] ?? ''; if ($visibility === 'public') { @@ -1011,7 +1031,7 @@ class Item $post['body'] = $this->bbCodeVideo->transform($post['body']); $post = $this->setObjectType($post); - // Personal notes must never be altered to a forum post. + // Personal notes must never be altered to a group post. if ($post['post-type'] != ItemModel::PT_PERSONAL_NOTE) { // Look for any tags and linkify them $post = $this->expandTags($post); diff --git a/src/Content/Nav.php b/src/Content/Nav.php index 470882b07..c6634a95c 100644 --- a/src/Content/Nav.php +++ b/src/Content/Nav.php @@ -123,7 +123,7 @@ class Nav '$apps' => $this->getAppMenu(), '$home' => $this->l10n->t('Go back'), '$clear_notifs' => $this->l10n->t('Clear notifications'), - '$search_hint' => $this->l10n->t('@name, !forum, #tags, content') + '$search_hint' => $this->l10n->t('@name, !group, #tags, content') ]); Hook::callAll('page_header', $nav); @@ -273,7 +273,7 @@ class Nav ]; if ($this->config->get('system', 'poco_local_search')) { - $nav['searchoption'][] = $this->l10n->t('Forums'); + $nav['searchoption'][] = $this->l10n->t('Groups'); } } diff --git a/src/Content/OEmbed.php b/src/Content/OEmbed.php index 7afdfac35..df2cafea4 100644 --- a/src/Content/OEmbed.php +++ b/src/Content/OEmbed.php @@ -312,8 +312,7 @@ class OEmbed */ public static function BBCode2HTML(string $text): string { - $stopoembed = DI::config()->get('system', 'no_oembed'); - if ($stopoembed == true) { + if (DI::config()->get('system', 'no_oembed')) { return preg_replace("/\[embed\](.+?)\[\/embed\]/is", "" . DI::l10n()->t('Embedding disabled') . " : $1", $text); } return preg_replace_callback("/\[embed\](.+?)\[\/embed\]/is", [self::class, 'replaceCallback'], $text); diff --git a/src/Content/Text/BBCode.php b/src/Content/Text/BBCode.php index 89bd80202..ab7300da1 100644 --- a/src/Content/Text/BBCode.php +++ b/src/Content/Text/BBCode.php @@ -62,8 +62,10 @@ class BBCode const TWITTER = 8; const BACKLINK = 8; const ACTIVITYPUB = 9; + const BLUESKY = 10; - const TOP_ANCHOR = '
'; + const SHARED_ANCHOR = '
'; + const TOP_ANCHOR = '
'; const BOTTOM_ANCHOR = '
'; const PREVIEW_NONE = 0; @@ -140,7 +142,7 @@ class BBCode break; case 'title': - $value = self::convert(html_entity_decode($value, ENT_QUOTES, 'UTF-8'), false, true); + $value = self::toPlaintext(html_entity_decode($value, ENT_QUOTES, 'UTF-8')); $value = html_entity_decode($value, ENT_QUOTES, 'UTF-8'); $value = str_replace(['[', ']'], ['[', ']'], $value); $data['title'] = $value; @@ -234,7 +236,7 @@ class BBCode // Remove attachment $text = self::replaceAttachment($text); - $naked_text = HTML::toPlaintext(self::convert($text, false, 0, true), 0, !$keep_urls); + $naked_text = HTML::toPlaintext(self::convert($text, false, BBCode::EXTERNAL, true), 0, !$keep_urls); DI::profiler()->stopRecording(); return $naked_text; @@ -508,26 +510,7 @@ class BBCode */ private static function convertUrlForActivityPub(string $url): string { - return sprintf('%s', $url, self::getStyledURL($url)); - } - - /** - * Converts an URL in a nicer format (without the scheme and possibly shortened) - * - * @param string $url URL that is about to be reformatted - * @return string reformatted link - */ - private static function getStyledURL(string $url): string - { - $parts = parse_url($url); - $scheme = $parts['scheme'] . '://'; - $styled_url = str_replace($scheme, '', $url); - - if (strlen($styled_url) > 30) { - $styled_url = substr($styled_url, 0, 30) . "…"; - } - - return $styled_url; + return sprintf('%s', $url, Strings::getStyledURL($url)); } /* @@ -948,7 +931,7 @@ class BBCode $network = $contact['network'] ?? Protocol::PHANTOM; $tpl = Renderer::getMarkupTemplate('shared_content.tpl'); - $text .= Renderer::replaceMacros($tpl, [ + $text .= BBCode::SHARED_ANCHOR . Renderer::replaceMacros($tpl, [ '$profile' => $attributes['profile'], '$avatar' => $attributes['avatar'], '$author' => $attributes['author'], @@ -1175,6 +1158,40 @@ class BBCode return $match[1] . '[url=' . $data['url'] . ']' . $data['nick'] . '[/url]'; } + /** + * Normalize links to Youtube and Vimeo to a unified format. + * + * @param string $text + * @return string + */ + private static function normalizeVideoLinks(string $text): string + { + $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); + $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); + $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/shorts\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); + $text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); + + $text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text); + $text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text); + + return $text; + } + + /** + * Expand Youtube and Vimeo links to + * + * @param string $text + * @return string + */ + public static function expandVideoLinks(string $text): string + { + $text = self::normalizeVideoLinks($text); + $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '[url=https://www.youtube.com/watch?v=$1]https://www.youtube.com/watch?v=$1[/url]', $text); + $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '[url=https://vimeo.com/$1]https://vimeo.com/$1[/url]', $text); + + return $text; + } + /** * Converts a BBCode message for a given URI-ID to a HTML message * @@ -1672,12 +1689,9 @@ class BBCode // Backward compatibility, [iframe] support has been removed in version 2020.12 $text = preg_replace("/\[iframe\](.*?)\[\/iframe\]/ism", '$1', $text); - // Youtube extensions - $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/watch\?v\=(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); - $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/embed\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); - $text = preg_replace("/\[youtube\]https?:\/\/www.youtube.com\/shorts\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); - $text = preg_replace("/\[youtube\]https?:\/\/youtu.be\/(.*?)\[\/youtube\]/ism", '[youtube]$1[/youtube]', $text); + $text = self::normalizeVideoLinks($text); + // Youtube extensions if ($try_oembed) { $text = preg_replace("/\[youtube\]([A-Za-z0-9\-_=]+)(.*?)\[\/youtube\]/ism", '', $text); } else { @@ -1688,9 +1702,7 @@ class BBCode ); } - $text = preg_replace("/\[vimeo\]https?:\/\/player.vimeo.com\/video\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text); - $text = preg_replace("/\[vimeo\]https?:\/\/vimeo.com\/([0-9]+)(.*?)\[\/vimeo\]/ism", '[vimeo]$1[/vimeo]', $text); - + // Vimeo extensions if ($try_oembed) { $text = preg_replace("/\[vimeo\]([0-9]+)(.*?)\[\/vimeo\]/ism", '', $text); } else { @@ -1790,7 +1802,7 @@ class BBCode $text ); - if (in_array($simple_html, [self::OSTATUS, self::TWITTER])) { + if (in_array($simple_html, [self::OSTATUS, self::TWITTER, self::BLUESKY])) { $text = preg_replace_callback("/([^#@!])\[url\=([^\]]*)\](.*?)\[\/url\]/ism", [self::class, 'expandLinksCallback'], $text); //$text = preg_replace("/[^#@!]\[url\=([^\]]*)\](.*?)\[\/url\]/ism", ' $2 [url]$1[/url]', $text); $text = preg_replace("/\[bookmark\=([^\]]*)\](.*?)\[\/bookmark\]/ism", ' $2 [url]$1[/url]', $text); @@ -2082,7 +2094,7 @@ class BBCode // Convert it to HTML - don't try oembed if ($for_diaspora) { - $text = self::convert($text, false, self::DIASPORA); + $text = self::convertForUriId(0, $text, self::DIASPORA); // Add all tags that maybe were removed if (preg_match_all("/#\[url\=([$url_search_string]*)\](.*?)\[\/url\]/ism", $original_text, $tags)) { @@ -2096,7 +2108,7 @@ class BBCode $text = $text . ' ' . $tagline; } } else { - $text = self::convert($text, false, self::CONNECTORS); + $text = self::convertForUriId(0, $text, self::CONNECTORS); } // If a link is followed by a quote then there should be a newline before it diff --git a/src/Content/Text/HTML.php b/src/Content/Text/HTML.php index 988274f8d..d30e7ead0 100644 --- a/src/Content/Text/HTML.php +++ b/src/Content/Text/HTML.php @@ -422,7 +422,8 @@ class HTML { $URLSearchString = "^\[\]"; - $matches = ["/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism", + $matches = [ + "/\[url\=([$URLSearchString]*)\].*?\[\/url\]/ism", "/\[url\]([$URLSearchString]*)\[\/url\]/ism", "/\[img\=[0-9]*x[0-9]*\](.*?)\[\/img\]/ism", "/\[img\](.*?)\[\/img\]/ism", @@ -531,8 +532,10 @@ class HTML $ignore = false; // A list of some links that should be ignored - $list = ["/user/", "/tag/", "/group/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/", - "//plus.google.com/", "//twitter.com/"]; + $list = [ + "/user/", "/tag/", "/group/", "/circle/", "/profile/", "/search?search=", "/search?tag=", "mailto:", "/u/", "/node/", + "//plus.google.com/", "//twitter.com/" + ]; foreach ($list as $listitem) { if (strpos($treffer[1], $listitem) !== false) { $ignore = true; @@ -861,7 +864,7 @@ class HTML '$id' => $id, '$search_label' => DI::l10n()->t('Search'), '$save_label' => $save_label, - '$search_hint' => DI::l10n()->t('@name, !forum, #tags, content'), + '$search_hint' => DI::l10n()->t('@name, !group, #tags, content'), '$mode' => $mode, '$return_url' => urlencode(Search::getSearchPath($s)), ]; @@ -874,7 +877,7 @@ class HTML ]; if (DI::config()->get('system', 'poco_local_search')) { - $values['$searchoption']['forums'] = DI::l10n()->t('Forums'); + $values['$searchoption']['groups'] = DI::l10n()->t('Groups'); } } @@ -941,7 +944,8 @@ class HTML $domain = '(?:(?!-)[A-Za-z0-9-]{1,63}(?set('URI.SafeIframeRegexp', + $config->set( + 'URI.SafeIframeRegexp', '%^https://(?: ' . implode('|', $allowedIframeDomains) . ' ) @@ -1050,7 +1054,8 @@ class HTML if (isset($mediaType->parameters['charset'])) { return strtolower($mediaType->parameters['charset']); } - } catch(\InvalidArgumentException $e) {} + } catch (\InvalidArgumentException $e) { + } return null; } diff --git a/src/Content/Text/NPF.php b/src/Content/Text/NPF.php index 2f0b36083..f5a6e2dc1 100644 --- a/src/Content/Text/NPF.php +++ b/src/Content/Text/NPF.php @@ -45,7 +45,7 @@ class NPF { $bbcode = self::prepareBody($bbcode); - $html = BBCode::convert($bbcode, false, BBCode::NPF); + $html = BBCode::convertForUriId($uri_id, $bbcode, BBCode::NPF); if (empty($html)) { return []; } diff --git a/src/Content/Text/Plaintext.php b/src/Content/Text/Plaintext.php index b297f75b3..86d720a02 100644 --- a/src/Content/Text/Plaintext.php +++ b/src/Content/Text/Plaintext.php @@ -137,6 +137,10 @@ class Plaintext $abstract = BBCode::getAbstract($item['body'], Protocol::STATUSNET); break; + case BBCode::BLUESKY: + $abstract = BBCode::getAbstract($item['body'], Protocol::BLUESKY); + break; + default: // We don't know the exact target. // We fetch an abstract since there is a posting limit. if ($limit > 0) { diff --git a/src/Content/Widget.php b/src/Content/Widget.php index 1d10f6142..ce4548d1a 100644 --- a/src/Content/Widget.php +++ b/src/Content/Widget.php @@ -29,7 +29,7 @@ use Friendica\Core\Search; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Profile; @@ -102,7 +102,7 @@ class Widget public static function unavailableNetworks(): array { // Always hide content from these networks - $networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::ZOT]; + $networks = [Protocol::PHANTOM, Protocol::FACEBOOK, Protocol::APPNET, Protocol::TWITTER, Protocol::ZOT]; if (!Addon::isEnabled("discourse")) { $networks[] = Protocol::DISCOURSE; @@ -116,10 +116,6 @@ class Widget $networks[] = Protocol::PUMPIO; } - if (!Addon::isEnabled("twitter")) { - $networks[] = Protocol::TWITTER; - } - if (!Addon::isEnabled("tumblr")) { $networks[] = Protocol::TUMBLR; } @@ -194,29 +190,29 @@ class Widget } /** - * Return group membership widget + * Return circle membership widget * * @param string $baseurl * @param string $selected * @return string * @throws \Exception */ - public static function groups(string $baseurl, string $selected = ''): string + public static function circles(string $baseurl, string $selected = ''): string { if (!DI::userSession()->getLocalUserId()) { return ''; } - $options = array_map(function ($group) { + $options = array_map(function ($circle) { return [ - 'ref' => $group['id'], - 'name' => $group['name'] + 'ref' => $circle['id'], + 'name' => $circle['name'] ]; - }, Group::getByUserId(DI::userSession()->getLocalUserId())); + }, Circle::getByUserId(DI::userSession()->getLocalUserId())); return self::filter( - 'group', - DI::l10n()->t('Groups'), + 'circle', + DI::l10n()->t('Circles'), '', DI::l10n()->t('Everyone'), $baseurl, @@ -243,6 +239,7 @@ class Widget ['ref' => 'followers', 'name' => DI::l10n()->t('Followers')], ['ref' => 'following', 'name' => DI::l10n()->t('Following')], ['ref' => 'mutuals', 'name' => DI::l10n()->t('Mutual friends')], + ['ref' => 'nothing', 'name' => DI::l10n()->t('No relationship')], ]; return self::filter( @@ -469,6 +466,10 @@ class Widget if ($dthen) { // Set the start and end date to the beginning of the month + $cutoffday = $dthen; + $thisday = substr($dnow, 4); + $nextday = date('Y-m-d', strtotime($dnow . ' + 1 day')); + $nextday = substr($nextday, 4); $dnow = substr($dnow, 0, 8) . '01'; $dthen = substr($dthen, 0, 8) . '01'; @@ -501,7 +502,7 @@ class Widget $cutoff_year = intval(DateTimeFormat::localNow('Y')) - $visible_years; $cutoff = array_key_exists($cutoff_year, $ret); - $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/posted_date.tpl'),[ + $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/posted_date.tpl'), [ '$title' => DI::l10n()->t('Archives'), '$size' => $visible_years, '$cutoff_year' => $cutoff_year, @@ -509,7 +510,11 @@ class Widget '$url' => $url, '$dates' => $ret, '$showless' => DI::l10n()->t('show less'), - '$showmore' => DI::l10n()->t('show more') + '$showmore' => DI::l10n()->t('show more'), + '$onthisdate' => DI::l10n()->t('On this date'), + '$thisday' => $thisday, + '$nextday' => $nextday, + '$cutoffday' => $cutoffday ]); return $o; @@ -529,10 +534,17 @@ class Widget ['ref' => 'person', 'name' => DI::l10n()->t('Persons')], ['ref' => 'organisation', 'name' => DI::l10n()->t('Organisations')], ['ref' => 'news', 'name' => DI::l10n()->t('News')], - ['ref' => 'community', 'name' => DI::l10n()->t('Forums')], + ['ref' => 'community', 'name' => DI::l10n()->t('Groups')], ]; - return self::filter('accounttype', DI::l10n()->t('Account Types'), '', - DI::l10n()->t('All'), $base, $accounts, $accounttype); + return self::filter( + 'accounttype', + DI::l10n()->t('Account Types'), + '', + DI::l10n()->t('All'), + $base, + $accounts, + $accounttype + ); } } diff --git a/src/Content/Widget/ContactBlock.php b/src/Content/Widget/ContactBlock.php index e206dbcb4..fbc492eaa 100644 --- a/src/Content/Widget/ContactBlock.php +++ b/src/Content/Widget/ContactBlock.php @@ -104,7 +104,7 @@ class ContactBlock $contact_uriids = array_column($personal_contacts, 'uri-id'); if (!empty($contact_uriids)) { - $contacts_stmt = DBA::select('contact', ['id', 'uid', 'addr', 'url', 'name', 'thumb', 'avatar', 'network'], ['uri-id' => $contact_uriids, 'uid' => $contact_uid]); + $contacts_stmt = DBA::select('contact', ['id', 'uid', 'addr', 'url', 'alias', 'name', 'thumb', 'avatar', 'network'], ['uri-id' => $contact_uriids, 'uid' => $contact_uid]); if (DBA::isResult($contacts_stmt)) { $contacts_title = DI::l10n()->tt('%d Contact', '%d Contacts', $total); diff --git a/src/Content/Widget/VCard.php b/src/Content/Widget/VCard.php index e462ab0aa..62a8e9085 100644 --- a/src/Content/Widget/VCard.php +++ b/src/Content/Widget/VCard.php @@ -29,6 +29,7 @@ use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\DI; use Friendica\Model\Contact; +use Friendica\Util\Network; use Friendica\Util\Strings; /** @@ -50,9 +51,15 @@ class VCard Logger::warning('Incomplete contact', ['contact' => $contact ?? [], 'callstack' => System::callstack(20)]); } + if (!Network::isValidHttpUrl($contact['url']) && Network::isValidHttpUrl($contact['alias'])) { + $contact_url = $contact['alias']; + } else { + $contact_url = $contact['url']; + } + if ($contact['network'] != '') { - $network_link = Strings::formatNetworkName($contact['network'], $contact['url']); - $network_avatar = ContactSelector::networkToIcon($contact['network'], $contact['url']); + $network_link = Strings::formatNetworkName($contact['network'], $contact_url); + $network_avatar = ContactSelector::networkToIcon($contact['network'], $contact_url); } else { $network_link = ''; $network_avatar = ''; @@ -83,9 +90,9 @@ class VCard if (empty($contact['self']) && Protocol::supportsFollow($contact['network'])) { if (in_array($rel, [Contact::SHARING, Contact::FRIEND])) { - $unfollow_link = 'contact/unfollow?url=' . urlencode($contact['url']) . '&auto=1'; + $unfollow_link = 'contact/unfollow?url=' . urlencode($contact_url) . '&auto=1'; } elseif (!$pending) { - $follow_link = 'contact/follow?url=' . urlencode($contact['url']) . '&auto=1'; + $follow_link = 'contact/follow?url=' . urlencode($contact_url) . '&auto=1'; } } @@ -97,7 +104,7 @@ class VCard return Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/vcard.tpl'), [ '$contact' => $contact, '$photo' => $photo, - '$url' => Contact::magicLinkByContact($contact, $contact['url']), + '$url' => Contact::magicLinkByContact($contact, $contact_url), '$about' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $contact['about'] ?? ''), '$xmpp' => DI::l10n()->t('XMPP:'), '$matrix' => DI::l10n()->t('Matrix:'), diff --git a/src/Core/ACL.php b/src/Core/ACL.php index aa5e2221b..1bf8ef03e 100644 --- a/src/Core/ACL.php +++ b/src/Core/ACL.php @@ -25,7 +25,7 @@ use Friendica\App\Page; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\User; /** @@ -167,12 +167,12 @@ class ACL $acl_contacts[] = $acl_yourself; - $acl_forums = Contact::selectToArray($fields, + $acl_groups = Contact::selectToArray($fields, ['uid' => $user_id, 'self' => false, 'blocked' => false, 'archive' => false, 'deleted' => false, 'network' => Protocol::FEDERATED, 'pending' => false, 'contact-type' => Contact::TYPE_COMMUNITY], $params ); - $acl_contacts = array_merge($acl_forums, $acl_contacts); + $acl_contacts = array_merge($acl_groups, $acl_contacts); array_walk($acl_contacts, function (&$value) { $value['type'] = 'contact'; @@ -182,40 +182,40 @@ class ACL } /** - * Returns the ACL list of groups (including meta-groups) for a given user id + * Returns the ACL list of circles (including meta-circles) for a given user id * * @param int $user_id * @return array */ - public static function getGroupListByUserId(int $user_id) + public static function getCircleListByUserId(int $user_id) { - $acl_groups = [ + $acl_circles = [ [ - 'id' => Group::FOLLOWERS, + 'id' => Circle::FOLLOWERS, 'name' => DI::l10n()->t('Followers'), 'addr' => '', 'micro' => 'images/twopeople.png', - 'type' => 'group', + 'type' => 'circle', ], [ - 'id' => Group::MUTUALS, + 'id' => Circle::MUTUALS, 'name' => DI::l10n()->t('Mutuals'), 'addr' => '', 'micro' => 'images/twopeople.png', - 'type' => 'group', + 'type' => 'circle', ] ]; - foreach (Group::getByUserId($user_id) as $group) { - $acl_groups[] = [ - 'id' => $group['id'], - 'name' => $group['name'], + foreach (Circle::getByUserId($user_id) as $circle) { + $acl_circles[] = [ + 'id' => $circle['id'], + 'name' => $circle['name'], 'addr' => '', 'micro' => 'images/twopeople.png', - 'type' => 'group', + 'type' => 'circle', ]; } - return $acl_groups; + return $acl_circles; } /** @@ -279,7 +279,7 @@ class ACL } else { $visibility = 'public'; // Default permission display for custom panel - $default_permissions['allow_gid'] = [Group::FOLLOWERS]; + $default_permissions['allow_gid'] = [Circle::FOLLOWERS]; } $jotnets_fields = []; @@ -303,15 +303,15 @@ class ACL $acl_contacts = self::getContactListByUserId($user['uid'], $condition); - $acl_groups = self::getGroupListByUserId($user['uid']); + $acl_circles = self::getCircleListByUserId($user['uid']); - $acl_list = array_merge($acl_groups, $acl_contacts); + $acl_list = array_merge($acl_circles, $acl_contacts); $input_names = [ 'visibility' => $form_prefix ? $form_prefix . '[visibility]' : 'visibility', - 'group_allow' => $form_prefix ? $form_prefix . '[group_allow]' : 'group_allow', + 'circle_allow' => $form_prefix ? $form_prefix . '[circle_allow]' : 'circle_allow', 'contact_allow' => $form_prefix ? $form_prefix . '[contact_allow]' : 'contact_allow', - 'group_deny' => $form_prefix ? $form_prefix . '[group_deny]' : 'group_deny', + 'circle_deny' => $form_prefix ? $form_prefix . '[circle_deny]' : 'circle_deny', 'contact_deny' => $form_prefix ? $form_prefix . '[contact_deny]' : 'contact_deny', 'emailcc' => $form_prefix ? $form_prefix . '[emailcc]' : 'emailcc', ]; @@ -321,7 +321,7 @@ class ACL '$public_title' => DI::l10n()->t('Public'), '$public_desc' => DI::l10n()->t('This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'), '$custom_title' => DI::l10n()->t('Limited/Private'), - '$custom_desc' => DI::l10n()->t('This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.') . DI::l10n()->t('Start typing the name of a contact or a group to show a filtered list. You can also mention the special groups "Followers" and "Mutuals".'), + '$custom_desc' => DI::l10n()->t('This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.') . DI::l10n()->t('Start typing the name of a contact or a circle to show a filtered list. You can also mention the special circles "Followers" and "Mutuals".'), '$allow_label' => DI::l10n()->t('Show to:'), '$deny_label' => DI::l10n()->t('Except to:'), '$emailcc' => DI::l10n()->t('CC: email addresses'), @@ -329,12 +329,12 @@ class ACL '$jotnets_summary' => DI::l10n()->t('Connectors'), '$visibility' => $visibility, '$acl_contacts' => json_encode($acl_contacts), - '$acl_groups' => json_encode($acl_groups), + '$acl_circles' => json_encode($acl_circles), '$acl_list' => json_encode($acl_list), '$contact_allow' => implode(',', $default_permissions['allow_cid']), - '$group_allow' => implode(',', $default_permissions['allow_gid']), + '$circle_allow' => implode(',', $default_permissions['allow_gid']), '$contact_deny' => implode(',', $default_permissions['deny_cid']), - '$group_deny' => implode(',', $default_permissions['deny_gid']), + '$circle_deny' => implode(',', $default_permissions['deny_gid']), '$for_federation' => $for_federation, '$jotnets_fields' => $jotnets_fields, '$input_names' => $input_names, @@ -381,7 +381,7 @@ class ACL * @return bool * @throws Exception */ - public static function isValidGroup($acl_string, $uid) + public static function isValidCircle($acl_string, $uid) { if (empty($acl_string)) { return true; @@ -394,7 +394,7 @@ class ACL $gid_array = $array[0]; foreach ($gid_array as $gid) { $gid = str_replace(['<', '>'], ['', ''], $gid); - if (!DBA::exists('group', ['id' => $gid, 'uid' => $uid, 'deleted' => false])) { + if (!DBA::exists('circle', ['id' => $gid, 'uid' => $uid, 'deleted' => false])) { return false; } } diff --git a/src/Core/Addon/Capability/ICanLoadAddons.php b/src/Core/Addon/Capability/ICanLoadAddons.php new file mode 100644 index 000000000..42af1a7b3 --- /dev/null +++ b/src/Core/Addon/Capability/ICanLoadAddons.php @@ -0,0 +1,37 @@ +. + * + */ + +namespace Friendica\Core\Addon\Capability; + +/** + * Interface for loading Addons specific content + */ +interface ICanLoadAddons +{ + /** + * Returns a merged config array of all active addons for a given config-name + * + * @param string $configName The config-name (config-file at the static directory, like 'hooks' => '{addon}/static/hooks.config.php) + * + * @return array the merged array + */ + public function getActiveAddonConfig(string $configName): array; +} diff --git a/src/Core/Addon/Exception/AddonInvalidConfigFileException.php b/src/Core/Addon/Exception/AddonInvalidConfigFileException.php new file mode 100644 index 000000000..bf173d0a4 --- /dev/null +++ b/src/Core/Addon/Exception/AddonInvalidConfigFileException.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Core\Addon\Exception; + +use Throwable; + +/** + * Exception in case one or more config files of the addons are invalid + */ +class AddonInvalidConfigFileException extends \RuntimeException +{ + public function __construct($message = '', $code = 0, Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Addon/Model/AddonLoader.php b/src/Core/Addon/Model/AddonLoader.php new file mode 100644 index 000000000..e808f2177 --- /dev/null +++ b/src/Core/Addon/Model/AddonLoader.php @@ -0,0 +1,70 @@ +. + * + */ + +namespace Friendica\Core\Addon\Model; + +use Friendica\Core\Addon\Capability\ICanLoadAddons; +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Util\Strings; + +class AddonLoader implements ICanLoadAddons +{ + const STATIC_PATH = 'static'; + /** @var string */ + protected $basePath; + /** @var IManageConfigValues */ + protected $config; + + public function __construct(string $basePath, IManageConfigValues $config) + { + $this->basePath = $basePath; + $this->config = $config; + } + + /** {@inheritDoc} */ + public function getActiveAddonConfig(string $configName): array + { + $addons = array_keys(array_filter($this->config->get('addons') ?? [])); + $returnConfig = []; + + foreach ($addons as $addon) { + $addonName = Strings::sanitizeFilePathItem(trim($addon)); + + $configFile = $this->basePath . '/addon/' . $addonName . '/' . static::STATIC_PATH . '/' . $configName . '.config.php'; + + if (!file_exists($configFile)) { + // Addon unmodified, skipping + continue; + } + + $config = include $configFile; + + if (!is_array($config)) { + throw new AddonInvalidConfigFileException('Error loading config file ' . $configFile); + } + + $returnConfig = array_merge_recursive($returnConfig, $config); + } + + return $returnConfig; + } +} diff --git a/src/Core/Cache/Factory/Cache.php b/src/Core/Cache/Factory/Cache.php index 107c6ab21..0c54bfe63 100644 --- a/src/Core/Cache/Factory/Cache.php +++ b/src/Core/Cache/Factory/Cache.php @@ -21,16 +21,13 @@ namespace Friendica\Core\Cache\Factory; -use Friendica\App\BaseURL; -use Friendica\Core\Cache\Enum; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Cache\Type; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Database\Database; +use Friendica\Core\Hooks\Capability\ICanCreateInstances; use Friendica\Util\Profiler; -use Psr\Log\LoggerInterface; /** * Class CacheFactory @@ -44,59 +41,32 @@ class Cache /** * @var string The default cache if nothing set */ - const DEFAULT_TYPE = Enum\Type::DATABASE; + const DEFAULT_TYPE = Type\DatabaseCache::NAME; + /** @var ICanCreateInstances */ + protected $instanceCreator; + /** @var IManageConfigValues */ + protected $config; + /** @var Profiler */ + protected $profiler; - /** - * @var IManageConfigValues The IConfiguration to read parameters out of the config - */ - private $config; - - /** - * @var Database The database connection in case that the cache is used the dba connection - */ - private $dba; - - /** - * @var string The hostname, used as Prefix for Caching - */ - private $hostname; - - /** - * @var Profiler The optional profiler if the cached should be profiled - */ - private $profiler; - - /** - * @var LoggerInterface The Friendica Logger - */ - private $logger; - - public function __construct(BaseURL $baseURL, IManageConfigValues $config, Database $dba, Profiler $profiler, LoggerInterface $logger) + public function __construct(ICanCreateInstances $instanceCreator, IManageConfigValues $config, Profiler $profiler) { - $this->hostname = $baseURL->getHost(); - $this->config = $config; - $this->dba = $dba; - $this->profiler = $profiler; - $this->logger = $logger; + $this->config = $config; + $this->instanceCreator = $instanceCreator; + $this->profiler = $profiler; } /** - * This method creates a CacheDriver for distributed caching with the given cache driver name - * - * @param string|null $type The cache type to create (default is per config) + * This method creates a CacheDriver for distributed caching * * @return ICanCache The instance of the CacheDriver * * @throws InvalidCacheDriverException In case the underlying cache driver isn't valid or not configured properly * @throws CachePersistenceException In case the underlying cache has errors during persistence */ - public function createDistributed(string $type = null): ICanCache + public function createDistributed(): ICanCache { - if ($type === Enum\Type::APCU) { - throw new InvalidCacheDriverException('apcu doesn\'t support distributed caching.'); - } - - return $this->create($type ?? $this->config->get('system', 'distributed_cache_driver', self::DEFAULT_TYPE)); + return $this->create($this->config->get('system', 'distributed_cache_driver', self::DEFAULT_TYPE)); } /** @@ -117,31 +87,17 @@ class Cache /** * Creates a new Cache instance * - * @param string $type The type of cache + * @param string $strategy The strategy, which cache instance should be used * * @return ICanCache * * @throws InvalidCacheDriverException In case the underlying cache driver isn't valid or not configured properly * @throws CachePersistenceException In case the underlying cache has errors during persistence */ - protected function create(string $type): ICanCache + protected function create(string $strategy): ICanCache { - switch ($type) { - case Enum\Type::MEMCACHE: - $cache = new Type\MemcacheCache($this->hostname, $this->config); - break; - case Enum\Type::MEMCACHED: - $cache = new Type\MemcachedCache($this->hostname, $this->config, $this->logger); - break; - case Enum\Type::REDIS: - $cache = new Type\RedisCache($this->hostname, $this->config); - break; - case Enum\Type::APCU: - $cache = new Type\APCuCache($this->hostname); - break; - default: - $cache = new Type\DatabaseCache($this->hostname, $this->dba); - } + /** @var ICanCache $cache */ + $cache = $this->instanceCreator->create(ICanCache::class, $strategy); $profiling = $this->config->get('system', 'profiling', false); diff --git a/src/Core/Cache/Type/APCuCache.php b/src/Core/Cache/Type/APCuCache.php index 05eb2fa07..f35815c15 100644 --- a/src/Core/Cache/Type/APCuCache.php +++ b/src/Core/Cache/Type/APCuCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; /** @@ -31,12 +30,12 @@ use Friendica\Core\Cache\Exception\InvalidCacheDriverException; */ class APCuCache extends AbstractCache implements ICanCacheInMemory { + const NAME = 'apcu'; + use CompareSetTrait; use CompareDeleteTrait; /** - * @param string $hostname - * * @throws InvalidCacheDriverException */ public function __construct(string $hostname) @@ -173,12 +172,4 @@ class APCuCache extends AbstractCache implements ICanCacheInMemory return true; } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::APCU; - } } diff --git a/src/Core/Cache/Type/AbstractCache.php b/src/Core/Cache/Type/AbstractCache.php index 5c00542a7..211f28b9a 100644 --- a/src/Core/Cache/Type/AbstractCache.php +++ b/src/Core/Cache/Type/AbstractCache.php @@ -28,6 +28,8 @@ use Friendica\Core\Cache\Capability\ICanCache; */ abstract class AbstractCache implements ICanCache { + const NAME = ''; + /** * @var string The hostname */ @@ -105,4 +107,10 @@ abstract class AbstractCache implements ICanCache return $result; } } + + /** {@inheritDoc} */ + public function getName(): string + { + return static::NAME; + } } diff --git a/src/Core/Cache/Type/ArrayCache.php b/src/Core/Cache/Type/ArrayCache.php index 8886a886a..34246afff 100644 --- a/src/Core/Cache/Type/ArrayCache.php +++ b/src/Core/Cache/Type/ArrayCache.php @@ -29,6 +29,8 @@ use Friendica\Core\Cache\Enum; */ class ArrayCache extends AbstractCache implements ICanCacheInMemory { + const NAME = 'array'; + use CompareDeleteTrait; /** @var array Array with the cached data */ @@ -108,12 +110,4 @@ class ArrayCache extends AbstractCache implements ICanCacheInMemory return false; } } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Enum\Type::ARRAY; - } } diff --git a/src/Core/Cache/Type/DatabaseCache.php b/src/Core/Cache/Type/DatabaseCache.php index fa7968b65..4959d6a75 100644 --- a/src/Core/Cache/Type/DatabaseCache.php +++ b/src/Core/Cache/Type/DatabaseCache.php @@ -32,6 +32,8 @@ use Friendica\Util\DateTimeFormat; */ class DatabaseCache extends AbstractCache implements ICanCache { + const NAME = 'database'; + /** * @var Database */ @@ -154,12 +156,4 @@ class DatabaseCache extends AbstractCache implements ICanCache throw new CachePersistenceException('Cannot clear cache', $exception); } } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Enum\Type::DATABASE; - } } diff --git a/src/Core/Cache/Type/MemcacheCache.php b/src/Core/Cache/Type/MemcacheCache.php index d19e7deb1..e8d3b07c8 100644 --- a/src/Core/Cache/Type/MemcacheCache.php +++ b/src/Core/Cache/Type/MemcacheCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -34,6 +33,8 @@ use Memcache; */ class MemcacheCache extends AbstractCache implements ICanCacheInMemory { + const NAME = 'memcache'; + use CompareSetTrait; use CompareDeleteTrait; use MemcacheCommandTrait; @@ -169,12 +170,4 @@ class MemcacheCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcache->add($cacheKey, serialize($value), MEMCACHE_COMPRESSED, $ttl); } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::MEMCACHE; - } } diff --git a/src/Core/Cache/Type/MemcachedCache.php b/src/Core/Cache/Type/MemcachedCache.php index 6d994ddf5..160c5a16f 100644 --- a/src/Core/Cache/Type/MemcachedCache.php +++ b/src/Core/Cache/Type/MemcachedCache.php @@ -23,7 +23,6 @@ namespace Friendica\Core\Cache\Type; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -35,6 +34,8 @@ use Psr\Log\LoggerInterface; */ class MemcachedCache extends AbstractCache implements ICanCacheInMemory { + const NAME = 'memcached'; + use CompareSetTrait; use CompareDeleteTrait; use MemcacheCommandTrait; @@ -185,12 +186,4 @@ class MemcachedCache extends AbstractCache implements ICanCacheInMemory $cacheKey = $this->getCacheKey($key); return $this->memcached->add($cacheKey, $value, $ttl); } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::MEMCACHED; - } } diff --git a/src/Core/Cache/Type/RedisCache.php b/src/Core/Cache/Type/RedisCache.php index b1fb9ba9c..a6ce7c44b 100644 --- a/src/Core/Cache/Type/RedisCache.php +++ b/src/Core/Cache/Type/RedisCache.php @@ -21,10 +21,8 @@ namespace Friendica\Core\Cache\Type; -use Exception; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum\Type; use Friendica\Core\Cache\Exception\CachePersistenceException; use Friendica\Core\Cache\Exception\InvalidCacheDriverException; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -35,6 +33,8 @@ use Redis; */ class RedisCache extends AbstractCache implements ICanCacheInMemory { + const NAME = 'redis'; + /** * @var Redis */ @@ -57,20 +57,30 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $redis_host = $config->get('system', 'redis_host'); $redis_port = $config->get('system', 'redis_port'); $redis_pw = $config->get('system', 'redis_password'); - $redis_db = $config->get('system', 'redis_db', 0); + $redis_db = (int)$config->get('system', 'redis_db', 0); - if (!empty($redis_port) && !@$this->redis->connect($redis_host, $redis_port)) { - throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ':' . $redis_port . ' isn\'t available'); - } elseif (!@$this->redis->connect($redis_host)) { - throw new CachePersistenceException('Expected Redis server at ' . $redis_host . ' isn\'t available'); - } + try { + if (is_numeric($redis_port) && $redis_port > -1) { + $connection_string = $redis_host . ':' . $redis_port; + if (!@$this->redis->connect($redis_host, $redis_port)) { + throw new CachePersistenceException('Expected Redis server at ' . $connection_string . " isn't available"); + } + } else { + $connection_string = $redis_host; + if (!@$this->redis->connect($redis_host)) { + throw new CachePersistenceException('Expected Redis server at ' . $connection_string . ' isn\'t available'); + } + } - if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { - throw new CachePersistenceException('Cannot authenticate redis server at ' . $redis_host . ':' . $redis_port); - } + if (!empty($redis_pw) && !$this->redis->auth($redis_pw)) { + throw new CachePersistenceException('Cannot authenticate redis server at ' . $connection_string); + } - if ($redis_db !== 0 && !$this->redis->select($redis_db)) { - throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $redis_host . ':' . $redis_port); + if ($redis_db !== 0 && !$this->redis->select($redis_db)) { + throw new CachePersistenceException('Cannot switch to redis db ' . $redis_db . ' at ' . $connection_string); + } + } catch (\RedisException $exception) { + throw new CachePersistenceException('Redis connection fails unexpectedly', $exception); } } @@ -211,12 +221,4 @@ class RedisCache extends AbstractCache implements ICanCacheInMemory $this->redis->unwatch(); return false; } - - /** - * {@inheritDoc} - */ - public function getName(): string - { - return Type::REDIS; - } } diff --git a/src/Core/Hooks/Capabilities/ICanManageInstances.php b/src/Core/Hooks/Capabilities/ICanManageInstances.php deleted file mode 100644 index bdad1b923..000000000 --- a/src/Core/Hooks/Capabilities/ICanManageInstances.php +++ /dev/null @@ -1,81 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Hooks\Capabilities; - -use Friendica\Core\Hooks\Exceptions\HookInstanceException; -use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; - -/** - * Managing special instance and decorator treatments for classes - */ -interface ICanManageInstances -{ - /** - * Register a class(strategy) for a given interface with a unique name. - * - * @see https://refactoring.guru/design-patterns/strategy - * - * @param string $interface The interface, which the given class implements - * @param string $name An arbitrary identifier for the given class, which will be used for factories, dependency injections etc. - * @param string $class The fully-qualified given class name - * @param ?array $arguments Additional arguments, which can be passed to the constructor - * - * @return $this This interface for chain-calls - * - * @throws HookRegisterArgumentException in case the given class for the interface isn't valid or already set - */ - public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): self; - - /** - * Register a new decorator for a given class or interface - * @see https://refactoring.guru/design-patterns/decorator - * - * @note Decorator attach new behaviors to classes without changing them or without letting them know about it. - * - * @param string $class The fully-qualified class or interface name, which gets decorated by a class - * @param string $decoratorClass The fully-qualified name of the class which mimics the given class or interface and adds new functionality - * @param array $arguments Additional arguments, which can be passed to the constructor of "decoratorClass" - * - * @return $this This interface for chain-calls - * - * @throws HookRegisterArgumentException in case the given class for the class or interface isn't valid - */ - public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): self; - - /** - * Returns a new instance of a given class for the corresponding name - * - * The instance will be build based on the registered strategy and the (unique) name - * - * In case, there are registered decorators for this class as well, all decorators of the list will be wrapped - * around the instance before returning it - * - * @param string $class The fully-qualified name of the given class or interface which will get returned - * @param string $name An arbitrary identifier to find a concrete instance strategy. - * @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime - * - * @return object The concrete instance of the type "$class" - * - * @throws HookInstanceException In case the class cannot get created - */ - public function getInstance(string $class, string $name, array $arguments = []): object; -} diff --git a/src/Core/Hooks/Capability/BehavioralHookType.php b/src/Core/Hooks/Capability/BehavioralHookType.php new file mode 100644 index 000000000..6de875e55 --- /dev/null +++ b/src/Core/Hooks/Capability/BehavioralHookType.php @@ -0,0 +1,37 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capability; + +/** + * An enum of hook types, based on behavioral design patterns + * @see https://refactoring.guru/design-patterns/behavioral-patterns + */ +interface BehavioralHookType +{ + /** + * Defines the key for the list of strategy-hooks. + * + * @see https://refactoring.guru/design-patterns/strategy + */ + const STRATEGY = 'strategy'; + const EVENT = 'event'; +} diff --git a/src/Core/Hooks/Capability/ICanCreateInstances.php b/src/Core/Hooks/Capability/ICanCreateInstances.php new file mode 100644 index 000000000..55740d276 --- /dev/null +++ b/src/Core/Hooks/Capability/ICanCreateInstances.php @@ -0,0 +1,41 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capability; + +/** + * creates special instances for given classes + */ +interface ICanCreateInstances +{ + /** + * Returns a new instance of a given class for the corresponding name + * + * The instance will be build based on the registered strategy and the (unique) name + * + * @param string $class The fully-qualified name of the given class or interface which will get returned + * @param string $strategy An arbitrary identifier to find a concrete instance strategy. + * @param array $arguments Additional arguments, which can be passed to the constructor of "$class" at runtime + * + * @return object The concrete instance of the type "$class" + */ + public function create(string $class, string $strategy, array $arguments = []): object; +} diff --git a/src/Core/Hooks/Capability/ICanRegisterStrategies.php b/src/Core/Hooks/Capability/ICanRegisterStrategies.php new file mode 100644 index 000000000..875665764 --- /dev/null +++ b/src/Core/Hooks/Capability/ICanRegisterStrategies.php @@ -0,0 +1,46 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Capability; + +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; + +/** + * Register strategies for given classes + */ +interface ICanRegisterStrategies +{ + /** + * Register a class(strategy) for a given interface with a unique name. + * + * @see https://refactoring.guru/design-patterns/strategy + * + * @param string $interface The interface, which the given class implements + * @param string $class The fully-qualified given class name + * A placeholder for dependencies is possible as well + * @param ?string $name An arbitrary identifier for the given strategy, which will be used for factories, dependency injections etc. + * + * @return $this This interface for chain-calls + * + * @throws HookRegisterArgumentException in case the given class for the interface isn't valid or already set + */ + public function registerStrategy(string $interface, string $class, ?string $name = null): self; +} diff --git a/src/Core/Logger/Exception/LoggerInvalidException.php b/src/Core/Hooks/Exceptions/HookConfigException.php similarity index 82% rename from src/Core/Logger/Exception/LoggerInvalidException.php rename to src/Core/Hooks/Exceptions/HookConfigException.php index db6ecb78c..6588787eb 100644 --- a/src/Core/Logger/Exception/LoggerInvalidException.php +++ b/src/Core/Hooks/Exceptions/HookConfigException.php @@ -19,13 +19,11 @@ * */ -namespace Friendica\Core\Logger\Exception; +namespace Friendica\Core\Hooks\Exceptions; -use Throwable; - -class LoggerInvalidException extends \RuntimeException +class HookConfigException extends \RuntimeException { - public function __construct($message = "", Throwable $previous = null) + public function __construct($message = '', \Throwable $previous = null) { parent::__construct($message, 500, $previous); } diff --git a/src/Core/Hooks/Model/DiceInstanceManager.php b/src/Core/Hooks/Model/DiceInstanceManager.php new file mode 100644 index 000000000..07ea72979 --- /dev/null +++ b/src/Core/Hooks/Model/DiceInstanceManager.php @@ -0,0 +1,70 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Model; + +use Dice\Dice; +use Friendica\Core\Hooks\Capability\ICanCreateInstances; +use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; +use Friendica\Core\Hooks\Exceptions\HookInstanceException; +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; +use Friendica\Core\Hooks\Util\StrategiesFileManager; + +/** + * This class represents an instance register, which uses Dice for creation + * + * @see Dice + */ +class DiceInstanceManager implements ICanCreateInstances, ICanRegisterStrategies +{ + protected $instance = []; + + /** @var Dice */ + protected $dice; + + public function __construct(Dice $dice, StrategiesFileManager $strategiesFileManager) + { + $this->dice = $dice; + $strategiesFileManager->setupStrategies($this); + } + + /** {@inheritDoc} */ + public function registerStrategy(string $interface, string $class, ?string $name = null): ICanRegisterStrategies + { + if (!empty($this->instance[$interface][strtolower($name)])) { + throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface)); + } + + $this->instance[$interface][strtolower($name)] = $class; + + return $this; + } + + /** {@inheritDoc} */ + public function create(string $class, string $strategy, array $arguments = []): object + { + if (empty($this->instance[$class][strtolower($strategy)])) { + throw new HookInstanceException(sprintf('The class with the name %s isn\'t registered for the class or interface %s', $strategy, $class)); + } + + return $this->dice->create($this->instance[$class][strtolower($strategy)], $arguments); + } +} diff --git a/src/Core/Hooks/Model/InstanceManager.php b/src/Core/Hooks/Model/InstanceManager.php deleted file mode 100644 index 7bfcfa420..000000000 --- a/src/Core/Hooks/Model/InstanceManager.php +++ /dev/null @@ -1,104 +0,0 @@ -. - * - */ - -namespace Friendica\Core\Hooks\Model; - -use Dice\Dice; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Hooks\Exceptions\HookInstanceException; -use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; - -/** {@inheritDoc} */ -class InstanceManager implements ICanManageInstances -{ - protected $instance = []; - protected $instanceArguments = []; - protected $decorator = []; - - /** @var Dice */ - protected $dice; - - public function __construct(Dice $dice) - { - $this->dice = $dice; - } - - /** {@inheritDoc} */ - public function registerStrategy(string $interface, string $name, string $class, array $arguments = null): ICanManageInstances - { - if (!is_a($class, $interface, true)) { - throw new HookRegisterArgumentException(sprintf('%s is not a valid class for the interface %s', $class, $interface)); - } - - if (!is_a($class, IAmAStrategy::class, true)) { - throw new HookRegisterArgumentException(sprintf('%s does not inherit from the marker interface %s', $class, IAmAStrategy::class)); - } - - if (!empty($this->instance[$interface][$name])) { - throw new HookRegisterArgumentException(sprintf('A class with the name %s is already set for the interface %s', $name, $interface)); - } - - $this->instance[$interface][$name] = $class; - $this->instanceArguments[$interface][$name] = $arguments; - - return $this; - } - - /** {@inheritDoc} */ - public function registerDecorator(string $class, string $decoratorClass, array $arguments = []): ICanManageInstances - { - if (!is_a($decoratorClass, $class, true)) { - throw new HookRegisterArgumentException(sprintf('%s is not a valid substitution for the given class or interface %s', $decoratorClass, $class)); - } - - $this->decorator[$class][] = [ - 'class' => $decoratorClass, - 'arguments' => $arguments, - ]; - - return $this; - } - - /** {@inheritDoc} */ - public function getInstance(string $class, string $name, array $arguments = []): object - { - if (empty($this->instance[$class][$name])) { - throw new HookInstanceException(sprintf('The class with the name %s isn\'t registered for the class or interface %s', $name, $class)); - } - - $instance = $this->dice->create($this->instance[$class][$name], array_merge($this->instanceArguments[$class][$name] ?? [], $arguments)); - - foreach ($this->decorator[$class] ?? [] as $decorator) { - $this->dice = $this->dice->addRule($class, [ - 'instanceOf' => $decorator['class'], - 'constructParams' => empty($decorator['arguments']) ? null : $decorator['arguments'], - /// @todo maybe support call structures for hooks as well in a later stage - could make factory calls easier - 'call' => null, - 'substitutions' => [$class => $instance], - ]); - - $instance = $this->dice->create($class); - } - - return $instance; - } -} diff --git a/src/Core/Hooks/Util/StrategiesFileManager.php b/src/Core/Hooks/Util/StrategiesFileManager.php new file mode 100644 index 000000000..860166fb6 --- /dev/null +++ b/src/Core/Hooks/Util/StrategiesFileManager.php @@ -0,0 +1,100 @@ +. + * + */ + +namespace Friendica\Core\Hooks\Util; + +use Friendica\Core\Addon\Capability\ICanLoadAddons; +use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; +use Friendica\Core\Hooks\Exceptions\HookConfigException; + +/** + * Manage all strategies.config.php files + */ +class StrategiesFileManager +{ + /** + * The default hook-file-key of strategies + * -> it's an empty string to cover empty/missing config values + */ + const STRATEGY_DEFAULT_KEY = ''; + const STATIC_DIR = 'static'; + const CONFIG_NAME = 'strategies'; + + /** @var ICanLoadAddons */ + protected $addonLoader; + /** @var array */ + protected $config = []; + /** @var string */ + protected $basePath; + + public function __construct(string $basePath, ICanLoadAddons $addonLoader) + { + $this->basePath = $basePath; + $this->addonLoader = $addonLoader; + } + + /** + * Loads all kinds of hooks and registers the corresponding instances + * + * @param ICanRegisterStrategies $instanceRegister The instance register + * + * @return void + */ + public function setupStrategies(ICanRegisterStrategies $instanceRegister) + { + foreach ($this->config as $interface => $strategy) { + foreach ($strategy as $dependencyName => $names) { + if (is_array($names)) { + foreach ($names as $name) { + $instanceRegister->registerStrategy($interface, $dependencyName, $name); + } + } else { + $instanceRegister->registerStrategy($interface, $dependencyName, $names); + } + } + } + } + + /** + * Reloads all hook config files into the config cache for later usage + * + * Merges all hook configs from every addon - if present - as well + * + * @return void + */ + public function loadConfig() + { + // load core hook config + $configFile = $this->basePath . '/' . static::STATIC_DIR . '/' . static::CONFIG_NAME . '.config.php'; + + if (!file_exists($configFile)) { + throw new HookConfigException(sprintf('config file %s does not exist.', $configFile)); + } + + $config = include $configFile; + + if (!is_array($config)) { + throw new HookConfigException(sprintf('Error loading config file %s.', $configFile)); + } + + $this->config = array_merge_recursive($config, $this->addonLoader->getActiveAddonConfig(static::CONFIG_NAME)); + } +} diff --git a/src/Core/KeyValueStorage/Capabilities/IManageKeyValuePairs.php b/src/Core/KeyValueStorage/Capability/IManageKeyValuePairs.php similarity index 97% rename from src/Core/KeyValueStorage/Capabilities/IManageKeyValuePairs.php rename to src/Core/KeyValueStorage/Capability/IManageKeyValuePairs.php index c9d215c49..5d9c8455e 100644 --- a/src/Core/KeyValueStorage/Capabilities/IManageKeyValuePairs.php +++ b/src/Core/KeyValueStorage/Capability/IManageKeyValuePairs.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Core\KeyValueStorage\Capabilities; +namespace Friendica\Core\KeyValueStorage\Capability; use Friendica\Core\KeyValueStorage\Exceptions\KeyValueStoragePersistenceException; diff --git a/src/Core/KeyValueStorage/Factory/KeyValueStorage.php b/src/Core/KeyValueStorage/Factory/KeyValueStorage.php new file mode 100644 index 000000000..467006614 --- /dev/null +++ b/src/Core/KeyValueStorage/Factory/KeyValueStorage.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Core\KeyValueStorage\Factory; + +use Friendica\Core\Hooks\Capability\ICanCreateInstances; +use Friendica\Core\Hooks\Util\StrategiesFileManager; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; + +class KeyValueStorage +{ + public function create(ICanCreateInstances $instanceCreator): IManageKeyValuePairs + { + /** @var IManageKeyValuePairs */ + return $instanceCreator->create(IManageKeyValuePairs::class, StrategiesFileManager::STRATEGY_DEFAULT_KEY); + } +} diff --git a/src/Core/KeyValueStorage/Type/AbstractKeyValueStorage.php b/src/Core/KeyValueStorage/Type/AbstractKeyValueStorage.php index a6924b61f..5d1b1f9d4 100644 --- a/src/Core/KeyValueStorage/Type/AbstractKeyValueStorage.php +++ b/src/Core/KeyValueStorage/Type/AbstractKeyValueStorage.php @@ -21,13 +21,15 @@ namespace Friendica\Core\KeyValueStorage\Type; -use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; /** * An abstract helper class for Key-Value storage classes */ abstract class AbstractKeyValueStorage implements IManageKeyValuePairs { + const NAME = ''; + /** {@inheritDoc} */ public function get(string $key) { diff --git a/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php b/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php index d31f3c1ce..cc152f0c9 100644 --- a/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php +++ b/src/Core/KeyValueStorage/Type/DBKeyValueStorage.php @@ -30,6 +30,7 @@ use Friendica\Database\Database; */ class DBKeyValueStorage extends AbstractKeyValueStorage { + const NAME = 'database'; const DB_KEY_VALUE_TABLE = 'key-value'; /** @var Database */ diff --git a/src/Core/Lock/Enum/Type.php b/src/Core/Lock/Enum/Type.php index 9e6e9194d..3a623b637 100644 --- a/src/Core/Lock/Enum/Type.php +++ b/src/Core/Lock/Enum/Type.php @@ -21,7 +21,7 @@ namespace Friendica\Core\Lock\Enum; -use Friendica\Core\Cache\Enum\Type as CacheType; +use Friendica\Core\Cache\Type\DatabaseCache; /** * Enumeration for lock types @@ -30,6 +30,6 @@ use Friendica\Core\Cache\Enum\Type as CacheType; */ abstract class Type { - const DATABASE = CacheType::DATABASE; + const DATABASE = DatabaseCache::NAME; const SEMAPHORE = 'semaphore'; } diff --git a/src/Core/Lock/Factory/Lock.php b/src/Core/Lock/Factory/Lock.php index bc4650c97..a60bc5a96 100644 --- a/src/Core/Lock/Factory/Lock.php +++ b/src/Core/Lock/Factory/Lock.php @@ -23,10 +23,10 @@ namespace Friendica\Core\Lock\Factory; use Friendica\Core\Cache\Factory\Cache; use Friendica\Core\Cache\Capability\ICanCacheInMemory; -use Friendica\Core\Cache\Enum; +use Friendica\Core\Cache\Type as CacheType; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Lock\Capability\ICanLock; -use Friendica\Core\Lock\Type; +use Friendica\Core\Lock\Type as LockType; use Friendica\Database\Database; use Psr\Log\LoggerInterface; @@ -78,20 +78,20 @@ class Lock try { switch ($lock_type) { - case Enum\Type::MEMCACHE: - case Enum\Type::MEMCACHED: - case Enum\Type::REDIS: - case Enum\Type::APCU: + case CacheType\MemcacheCache::NAME: + case CacheType\MemcachedCache::NAME: + case CacheType\RedisCache::NAME: + case CacheType\APCuCache::NAME: $cache = $this->cacheFactory->createLocal($lock_type); if ($cache instanceof ICanCacheInMemory) { - return new Type\CacheLock($cache); + return new LockType\CacheLock($cache); } else { throw new \Exception(sprintf('Incompatible cache driver \'%s\' for lock used', $lock_type)); } case 'database': - return new Type\DatabaseLock($this->dba); + return new LockType\DatabaseLock($this->dba); case 'semaphore': - return new Type\SemaphoreLock(); + return new LockType\SemaphoreLock(); default: return self::useAutoDriver(); } @@ -116,7 +116,7 @@ class Lock // 1. Try to use Semaphores for - local - locking if (function_exists('sem_get')) { try { - return new Type\SemaphoreLock(); + return new LockType\SemaphoreLock(); } catch (\Exception $exception) { $this->logger->warning('Using Semaphore driver for locking failed.', ['exception' => $exception]); } @@ -124,11 +124,11 @@ class Lock // 2. Try to use Cache Locking (don't use the DB-Cache Locking because it works different!) $cache_type = $this->config->get('system', 'cache_driver', 'database'); - if ($cache_type != Enum\Type::DATABASE) { + if ($cache_type != CacheType\DatabaseCache::NAME) { try { $cache = $this->cacheFactory->createLocal($cache_type); if ($cache instanceof ICanCacheInMemory) { - return new Type\CacheLock($cache); + return new LockType\CacheLock($cache); } } catch (\Exception $exception) { $this->logger->warning('Using Cache driver for locking failed.', ['exception' => $exception]); @@ -136,6 +136,6 @@ class Lock } // 3. Use Database Locking as a Fallback - return new Type\DatabaseLock($this->dba); + return new LockType\DatabaseLock($this->dba); } } diff --git a/src/Core/Lock/Type/AbstractLock.php b/src/Core/Lock/Type/AbstractLock.php index 3c47c0171..25eb47fe9 100644 --- a/src/Core/Lock/Type/AbstractLock.php +++ b/src/Core/Lock/Type/AbstractLock.php @@ -36,7 +36,7 @@ abstract class AbstractLock implements ICanLock /** * Check if we've locally acquired a lock * - * @param string key The Name of the lock + * @param string $key The Name of the lock * * @return bool Returns true if the lock is set */ diff --git a/src/Core/Logger/Capability/ICheckLoggerSettings.php b/src/Core/Logger/Capability/ICheckLoggerSettings.php new file mode 100644 index 000000000..abdbc3b50 --- /dev/null +++ b/src/Core/Logger/Capability/ICheckLoggerSettings.php @@ -0,0 +1,42 @@ +. + * + */ + +namespace Friendica\Core\Logger\Capability; + +/** + * Whenever a logging specific check is necessary, use this interface to encapsulate and centralize this logic + */ +interface ICheckLoggerSettings +{ + /** + * Checks if the logfile is set and usable + * + * @return string|null null in case everything is ok, otherwise returns the error + */ + public function checkLogfile(): ?string; + + /** + * Checks if the debugging logfile is usable in case it is set! + * + * @return string|null null in case everything is ok, otherwise returns the error + */ + public function checkDebugLogfile(): ?string; +} diff --git a/src/Core/Logger/Capabilities/IHaveCallIntrospections.php b/src/Core/Logger/Capability/IHaveCallIntrospections.php similarity index 96% rename from src/Core/Logger/Capabilities/IHaveCallIntrospections.php rename to src/Core/Logger/Capability/IHaveCallIntrospections.php index 83d75f976..918232af3 100644 --- a/src/Core/Logger/Capabilities/IHaveCallIntrospections.php +++ b/src/Core/Logger/Capability/IHaveCallIntrospections.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Core\Logger\Capabilities; +namespace Friendica\Core\Logger\Capability; interface IHaveCallIntrospections { diff --git a/src/Core/Logger/Capability/LogChannel.php b/src/Core/Logger/Capability/LogChannel.php new file mode 100644 index 000000000..c3b631644 --- /dev/null +++ b/src/Core/Logger/Capability/LogChannel.php @@ -0,0 +1,43 @@ +. + * + */ + +namespace Friendica\Core\Logger\Capability; + +/** + * An enum class for the Log channels + */ +interface LogChannel +{ + /** @var string channel for the auth_ejabbered script */ + public const AUTH_JABBERED = 'auth_ejabberd'; + /** @var string Default channel in case it isn't set explicit */ + public const DEFAULT = self::APP; + /** @var string channel for console execution */ + public const CONSOLE = 'console'; + /** @var string channel for developer focused logging */ + public const DEV = 'dev'; + /** @var string channel for daemon executions */ + public const DAEMON = 'daemon'; + /** @var string channel for worker execution */ + public const WORKER = 'worker'; + /** @var string channel for frontend app executions */ + public const APP = 'app'; +} diff --git a/src/Core/Logger/Exception/LogLevelException.php b/src/Core/Logger/Exception/LogLevelException.php index 36b2c31cf..9cf649a86 100644 --- a/src/Core/Logger/Exception/LogLevelException.php +++ b/src/Core/Logger/Exception/LogLevelException.php @@ -23,9 +23,12 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * Exception in case the loglevel isn't set or isn't valid + */ class LogLevelException extends \InvalidArgumentException { - public function __construct($message = "", Throwable $previous = null) + public function __construct($message = '', Throwable $previous = null) { parent::__construct($message, 500, $previous); } diff --git a/src/Core/Logger/Exception/LoggerArgumentException.php b/src/Core/Logger/Exception/LoggerArgumentException.php index a0b9949b0..6925be4c7 100644 --- a/src/Core/Logger/Exception/LoggerArgumentException.php +++ b/src/Core/Logger/Exception/LoggerArgumentException.php @@ -23,9 +23,12 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * Exception in case an argument of a logger class isn't valid + */ class LoggerArgumentException extends \InvalidArgumentException { - public function __construct($message = "", Throwable $previous = null) + public function __construct($message = '', Throwable $previous = null) { parent::__construct($message, 500, $previous); } diff --git a/src/Core/Logger/Exception/LoggerException.php b/src/Core/Logger/Exception/LoggerException.php index 7e3637327..7529f6e78 100644 --- a/src/Core/Logger/Exception/LoggerException.php +++ b/src/Core/Logger/Exception/LoggerException.php @@ -23,9 +23,12 @@ namespace Friendica\Core\Logger\Exception; use Throwable; +/** + * A generic exception of the logging namespace + */ class LoggerException extends \Exception { - public function __construct($message = "", Throwable $previous = null) + public function __construct($message = '', Throwable $previous = null) { parent::__construct($message, 500, $previous); } diff --git a/src/Core/Logger/Exception/LoggerUnusableException.php b/src/Core/Logger/Exception/LoggerUnusableException.php new file mode 100644 index 000000000..401a63482 --- /dev/null +++ b/src/Core/Logger/Exception/LoggerUnusableException.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Core\Logger\Exception; + +use Throwable; + +/** + * Exception in case the used logging instance is unusable because of some circumstances + */ +class LoggerUnusableException extends \RuntimeException +{ + public function __construct($message = '', Throwable $previous = null) + { + parent::__construct($message, 500, $previous); + } +} diff --git a/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php b/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php new file mode 100644 index 000000000..86dfeae63 --- /dev/null +++ b/src/Core/Logger/Factory/AbstractLoggerTypeFactory.php @@ -0,0 +1,80 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; +use Psr\Log\LogLevel; + +/** + * Abstract class for creating logger types, which includes common necessary logic/content + */ +abstract class AbstractLoggerTypeFactory +{ + /** @var string */ + protected $channel; + /** @var IHaveCallIntrospections */ + protected $introspection; + + /** + * @param string $channel The channel for the logger + */ + public function __construct(IHaveCallIntrospections $introspection, string $channel) + { + $this->channel = $channel; + $this->introspection = $introspection; + } + + /** + * Mapping a legacy level to the PSR-3 compliant levels + * + * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel + * + * @param string $level the level to be mapped + * + * @return string the PSR-3 compliant level + */ + protected static function mapLegacyConfigDebugLevel(string $level): string + { + switch ($level) { + // legacy WARNING + case "0": + return LogLevel::ERROR; + // legacy INFO + case "1": + return LogLevel::WARNING; + // legacy TRACE + case "2": + return LogLevel::NOTICE; + // legacy DEBUG + case "3": + return LogLevel::INFO; + // legacy DATA + case "4": + // legacy ALL + case "5": + return LogLevel::DEBUG; + // default if nothing set + default: + return $level; + } + } +} diff --git a/src/Core/Logger/Factory/Logger.php b/src/Core/Logger/Factory/Logger.php index 2821a813c..f1086f585 100644 --- a/src/Core/Logger/Factory/Logger.php +++ b/src/Core/Logger/Factory/Logger.php @@ -22,134 +22,46 @@ namespace Friendica\Core\Logger\Factory; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Core\Logger\Type\ProfilerLogger; -use Friendica\Core\Logger\Type\StreamLogger; -use Friendica\Core\Logger\Type\SyslogLogger; +use Friendica\Core\Hooks\Capability\ICanCreateInstances; +use Friendica\Core\Logger\Capability\LogChannel; +use Friendica\Core\Logger\Type\ProfilerLogger as ProfilerLoggerClass; +use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; -use Psr\Log\LogLevel; use Psr\Log\NullLogger; +use Throwable; /** - * A logger factory + * The logger factory for the core logging instances */ class Logger { - const DEV_CHANNEL = 'dev'; - - /** @var string The log-channel (app, worker, ...) */ + /** @var string The channel */ protected $channel; - /** @var ICanManageInstances */ - protected $instanceManager; - /** @var IManageConfigValues */ - protected $config; - public function __construct(string $channel, ICanManageInstances $instanceManager, IManageConfigValues $config, string $logfile = null) + public function __construct(string $channel = LogChannel::DEFAULT) { - $this->channel = $channel; - $this->instanceManager = $instanceManager; - $this->config = $config; - - $this->instanceManager - ->registerStrategy(LoggerInterface::class, 'syslog', SyslogLogger::class) - ->registerStrategy(LoggerInterface::class, 'stream', StreamLogger::class, isset($logfile) ? [$logfile] : null); - - if ($this->config->get('system', 'profiling') ?? false) { - $this->instanceManager->registerDecorator(LoggerInterface::class, ProfilerLogger::class); - } + $this->channel = $channel; } - /** - * Creates a new PSR-3 compliant logger instances - * - * @param string|null $loglevel (optional) A given loglevel in case the loglevel in the config isn't applicable - * - * @return LoggerInterface The PSR-3 compliant logger instance - */ - public function create(string $loglevel = null): LoggerInterface + public function create(ICanCreateInstances $instanceCreator, IManageConfigValues $config, Profiler $profiler): LoggerInterface { - if (empty($this->config->get('system', 'debugging') ?? false)) { + if (empty($config->get('system', 'debugging') ?? false)) { return new NullLogger(); } - $loglevel = $loglevel ?? static::mapLegacyConfigDebugLevel($this->config->get('system', 'loglevel')); - $name = $this->config->get('system', 'logger_config') ?? 'stream'; + $name = $config->get('system', 'logger_config') ?? ''; try { - /** @var LoggerInterface */ - return $this->instanceManager->getInstance(LoggerInterface::class, $name, [$this->channel, $loglevel]); - } catch (LogLevelException $exception) { - // If there's a wrong config value for loglevel, try again with standard - $logger = $this->create(LogLevel::NOTICE); - $logger->warning('Invalid loglevel set in config.', ['loglevel' => $loglevel]); - return $logger; - } catch (\Throwable $e) { + /** @var LoggerInterface $logger */ + $logger = $instanceCreator->create(LoggerInterface::class, $name, [$this->channel]); + if ($config->get('system', 'profiling') ?? false) { + return new ProfilerLoggerClass($logger, $profiler); + } else { + return $logger; + } + } catch (Throwable $e) { // No logger ... return new NullLogger(); } } - - /** - * Creates a new PSR-3 compliant develop logger - * - * If you want to debug only interactions from your IP or the IP of a remote server for federation debug, - * you'll use this logger instance for the duration of your work. - * - * It should never get filled during normal usage of Friendica - * - * @return LoggerInterface The PSR-3 compliant logger instance - * @throws \Exception - */ - public function createDev() - { - $debugging = $this->config->get('system', 'debugging'); - $stream = $this->config->get('system', 'dlogfile'); - $developerIp = $this->config->get('system', 'dlogip'); - - if ((!isset($developerIp) || !$debugging) && - (!is_file($stream) || is_writable($stream))) { - return new NullLogger(); - } - - $name = $this->config->get('system', 'logger_config') ?? 'stream'; - - /** @var LoggerInterface */ - return $this->instanceManager->getInstance(LoggerInterface::class, $name, [self::DEV_CHANNEL, LogLevel::DEBUG, $stream]); - } - - /** - * Mapping a legacy level to the PSR-3 compliant levels - * - * @see https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md#5-psrlogloglevel - * - * @param string $level the level to be mapped - * - * @return string the PSR-3 compliant level - */ - private static function mapLegacyConfigDebugLevel(string $level): string - { - switch ($level) { - // legacy WARNING - case "0": - return LogLevel::ERROR; - // legacy INFO - case "1": - return LogLevel::WARNING; - // legacy TRACE - case "2": - return LogLevel::NOTICE; - // legacy DEBUG - case "3": - return LogLevel::INFO; - // legacy DATA - case "4": - // legacy ALL - case "5": - return LogLevel::DEBUG; - // default if nothing set - default: - return $level; - } - } } diff --git a/src/Core/Logger/Factory/StreamLogger.php b/src/Core/Logger/Factory/StreamLogger.php new file mode 100644 index 000000000..7f32d66b1 --- /dev/null +++ b/src/Core/Logger/Factory/StreamLogger.php @@ -0,0 +1,100 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Capability\LogChannel; +use Friendica\Core\Logger\Exception\LoggerArgumentException; +use Friendica\Core\Logger\Exception\LoggerException; +use Friendica\Core\Logger\Exception\LogLevelException; +use Friendica\Core\Logger\Type\StreamLogger as StreamLoggerClass; +use Friendica\Core\Logger\Util\FileSystem; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * The logger factory for the StreamLogger instance + * + * @see StreamLoggerClass + */ +class StreamLogger extends AbstractLoggerTypeFactory +{ + /** + * Creates a new PSR-3 compliant stream logger instance + * + * @param IManageConfigValues $config The system configuration + * @param string|null $logfile (optional) A given logfile which should be used as stream (e.g. in case of + * developer logging) + * @param string|null $channel (optional) A given channel in case it is different from the default + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException in case the logger cannot get created + */ + public function create(IManageConfigValues $config, string $logfile = null, string $channel = null): LoggerInterface + { + $fileSystem = new FileSystem(); + + $logfile = $logfile ?? $config->get('system', 'logfile'); + if (!@file_exists($logfile) || !@is_writable($logfile)) { + throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $logfile)); + } + + $loglevel = static::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); + + if (array_key_exists($loglevel, StreamLoggerClass::levelToInt)) { + $loglevel = StreamLoggerClass::levelToInt[$loglevel]; + } else { + throw new LogLevelException(sprintf('The level "%s" is not valid.', $loglevel)); + } + + $stream = $fileSystem->createStream($logfile); + + return new StreamLoggerClass($channel ?? $this->channel, $this->introspection, $stream, $loglevel, getmypid()); + } + + /** + * Creates a new PSR-3 compliant develop logger + * + * If you want to debug only interactions from your IP or the IP of a remote server for federation debug, + * you'll use this logger instance for the duration of your work. + * + * It should never get filled during normal usage of Friendica + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException + */ + public function createDev(IManageConfigValues $config) + { + $debugging = $config->get('system', 'debugging'); + $logfile = $config->get('system', 'dlogfile'); + $developerIp = $config->get('system', 'dlogip'); + + if ((!isset($developerIp) || !$debugging) && + (!is_file($logfile) || is_writable($logfile))) { + return new NullLogger(); + } + + return $this->create($config, $logfile, LogChannel::DEV); + } +} diff --git a/src/Core/Logger/Factory/SyslogLogger.php b/src/Core/Logger/Factory/SyslogLogger.php new file mode 100644 index 000000000..7b1712344 --- /dev/null +++ b/src/Core/Logger/Factory/SyslogLogger.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\Core\Logger\Factory; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Exception\LoggerException; +use Friendica\Core\Logger\Exception\LogLevelException; +use Friendica\Core\Logger\Type\SyslogLogger as SyslogLoggerClass; +use Psr\Log\LoggerInterface; + +/** + * The logger factory for the SyslogLogger instance + * + * @see SyslogLoggerClass + */ +class SyslogLogger extends AbstractLoggerTypeFactory +{ + /** + * Creates a new PSR-3 compliant syslog logger instance + * + * @param IManageConfigValues $config The system configuration + * + * @return LoggerInterface The PSR-3 compliant logger instance + * + * @throws LoggerException in case the logger cannot get created + */ + public function create(IManageConfigValues $config): LoggerInterface + { + $logOpts = $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS; + $logFacility = $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY; + $loglevel = SyslogLogger::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); + + if (array_key_exists($loglevel, SyslogLoggerClass::logLevels)) { + $loglevel = SyslogLoggerClass::logLevels[$loglevel]; + } else { + throw new LogLevelException(sprintf('The level "%s" is not valid.', $loglevel)); + } + + return new SyslogLoggerClass($this->channel, $this->introspection, $loglevel, $logOpts, $logFacility); + } +} diff --git a/src/Core/Logger/Type/AbstractLogger.php b/src/Core/Logger/Type/AbstractLogger.php index 77a61e920..7de0e4160 100644 --- a/src/Core/Logger/Type/AbstractLogger.php +++ b/src/Core/Logger/Type/AbstractLogger.php @@ -21,7 +21,7 @@ namespace Friendica\Core\Logger\Type; -use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Util\Strings; use Psr\Log\LoggerInterface; @@ -38,6 +38,8 @@ use Psr\Log\LogLevel; */ abstract class AbstractLogger implements LoggerInterface { + const NAME = ''; + /** * The output channel of this logger * @var string diff --git a/src/Core/Logger/Type/README.md b/src/Core/Logger/Type/README.md deleted file mode 100644 index b204353c0..000000000 --- a/src/Core/Logger/Type/README.md +++ /dev/null @@ -1,26 +0,0 @@ -## Friendica\Util\Logger - -This namespace contains the different implementations of a Logger. - -### Configuration guideline - -The following settings are possible for `logger_config`: -- [`stream`](StreamLogger.php): A small logger for files or streams -- [`syslog`](SyslogLogger.php): Prints the logging output into the syslog - -[`VoidLogger`](VoidLogger.php) is a fallback logger without any function if no debugging is enabled. - -[`ProfilerLogger`](ProfilerLogger.php) is a wrapper around an existing logger in case profiling is enabled for Friendica. -Every log call will be saved to the `Profiler` with a timestamp. - -### Implementation guideline - -Each logging implementation should pe capable of printing at least the following information: -- An unique ID for each Request/Call -- The process ID (PID) -- A timestamp of the logging entry -- The critically of the log entry -- A log message -- A context of the log message (f.e which user) - -If possible, a Logger should extend [`AbstractLogger`](AbstractLogger.php), because it contains additional, Friendica specific business logic for each logging call. diff --git a/src/Core/Logger/Type/StreamLogger.php b/src/Core/Logger/Type/StreamLogger.php index d56f5b20e..8cadd8cc7 100644 --- a/src/Core/Logger/Type/StreamLogger.php +++ b/src/Core/Logger/Type/StreamLogger.php @@ -21,33 +21,25 @@ namespace Friendica\Core\Logger\Type; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; -use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; -use Friendica\Core\Logger\Exception\LoggerArgumentException; +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Util\DateTimeFormat; -use Friendica\Util\FileSystem; use Psr\Log\LogLevel; /** * A Logger instance for logging into a stream (file, stdout, stderr) */ -class StreamLogger extends AbstractLogger implements IAmAStrategy +class StreamLogger extends AbstractLogger { + const NAME = 'stream'; + /** * The minimum loglevel at which this logger will be triggered * @var string */ private $logLevel; - /** - * The file URL of the stream (if needed) - * @var string - */ - private $url; - /** * The stream, where the current logger is writing into * @var resource @@ -60,16 +52,11 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy */ private $pid; - /** - * @var FileSystem - */ - private $fileSystem; - /** * Translates LogLevel log levels to integer values * @var array */ - private $levelToInt = [ + public const levelToInt = [ LogLevel::EMERGENCY => 0, LogLevel::ALERT => 1, LogLevel::CRITICAL => 2, @@ -84,41 +71,20 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy * {@inheritdoc} * @param string $level The minimum loglevel at which this logger will be triggered * - * @throws LoggerArgumentException - * @throws LogLevelException + * @throws LoggerException */ - public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, FileSystem $fileSystem, string $level = LogLevel::DEBUG) + public function __construct(string $channel, IHaveCallIntrospections $introspection, $stream, int $logLevel, int $pid) { - $this->fileSystem = $fileSystem; - - $stream = $this->logfile ?? $config->get('system', 'logfile'); - if ((@file_exists($stream) && !@is_writable($stream)) && !@is_writable(basename($stream))) { - throw new LoggerArgumentException(sprintf('%s is not a valid logfile', $stream)); - } - parent::__construct($channel, $introspection); - if (is_resource($stream)) { - $this->stream = $stream; - } elseif (is_string($stream)) { - $this->url = $stream; - } else { - throw new LoggerArgumentException('A stream must either be a resource or a string.'); - } - - $this->pid = getmypid(); - if (array_key_exists($level, $this->levelToInt)) { - $this->logLevel = $this->levelToInt[$level]; - } else { - throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); - } - - $this->checkStream(); + $this->stream = $stream; + $this->pid = $pid; + $this->logLevel = $logLevel; } public function close() { - if ($this->url && is_resource($this->stream)) { + if (is_resource($this->stream)) { fclose($this->stream); } @@ -139,18 +105,16 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy */ protected function addEntry($level, string $message, array $context = []) { - if (!array_key_exists($level, $this->levelToInt)) { + if (!array_key_exists($level, static::levelToInt)) { throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); } - $logLevel = $this->levelToInt[$level]; + $logLevel = static::levelToInt[$level]; if ($logLevel > $this->logLevel) { return; } - $this->checkStream(); - $formattedLog = $this->formatLog($level, $message, $context); fwrite($this->stream, $formattedLog); } @@ -185,27 +149,4 @@ class StreamLogger extends AbstractLogger implements IAmAStrategy return $logMessage; } - - /** - * Checks the current stream - * - * @throws LoggerException - * @throws LoggerArgumentException - */ - private function checkStream() - { - if (is_resource($this->stream)) { - return; - } - - if (empty($this->url)) { - throw new LoggerArgumentException('Missing stream URL.'); - } - - try { - $this->stream = $this->fileSystem->createStream($this->url); - } catch (\UnexpectedValueException $exception) { - throw new LoggerException('Cannot create stream.', $exception); - } - } } diff --git a/src/Core/Logger/Type/SyslogLogger.php b/src/Core/Logger/Type/SyslogLogger.php index 3c9ab581a..556351a7e 100644 --- a/src/Core/Logger/Type/SyslogLogger.php +++ b/src/Core/Logger/Type/SyslogLogger.php @@ -21,9 +21,7 @@ namespace Friendica\Core\Logger\Type; -use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; -use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Psr\Log\LogLevel; @@ -32,8 +30,10 @@ use Psr\Log\LogLevel; * A Logger instance for syslogging (fast, but simple) * @see http://php.net/manual/en/function.syslog.php */ -class SyslogLogger extends AbstractLogger implements IAmAStrategy +class SyslogLogger extends AbstractLogger { + const NAME = 'syslog'; + const IDENT = 'Friendica'; /** @var int The default syslog flags */ @@ -45,7 +45,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy * Translates LogLevel log levels to syslog log priorities. * @var array */ - private $logLevels = [ + public const logLevels = [ LogLevel::DEBUG => LOG_DEBUG, LogLevel::INFO => LOG_INFO, LogLevel::NOTICE => LOG_NOTICE, @@ -60,7 +60,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy * Translates log priorities to string outputs * @var array */ - private $logToString = [ + protected const logToString = [ LOG_DEBUG => 'DEBUG', LOG_INFO => 'INFO', LOG_NOTICE => 'NOTICE', @@ -101,19 +101,18 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy /** * {@inheritdoc} - * @param string $level The minimum loglevel at which this logger will be triggered * - * @throws LogLevelException - * @throws LoggerException + * @param string $logLevel The minimum loglevel at which this logger will be triggered + * @param string $logOptions + * @param string $logFacility */ - public function __construct(string $channel, IManageConfigValues $config, IHaveCallIntrospections $introspection, string $level = LogLevel::NOTICE) + public function __construct(string $channel, IHaveCallIntrospections $introspection, string $logLevel, string $logOptions, string $logFacility) { parent::__construct($channel, $introspection); - $this->logOpts = $config->get('system', 'syslog_flags') ?? static::DEFAULT_FLAGS; - $this->logFacility = $config->get('system', 'syslog_facility') ?? static::DEFAULT_FACILITY; - $this->logLevel = $this->mapLevelToPriority($level); - $this->introspection->addClasses([self::class]); + $this->logOpts = $logOptions; + $this->logFacility = $logFacility; + $this->logLevel = $logLevel; } /** @@ -149,11 +148,11 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy */ public function mapLevelToPriority(string $level): int { - if (!array_key_exists($level, $this->logLevels)) { + if (!array_key_exists($level, static::logLevels)) { throw new LogLevelException(sprintf('The level "%s" is not valid.', $level)); } - return $this->logLevels[$level]; + return static::logLevels[$level]; } /** @@ -202,7 +201,7 @@ class SyslogLogger extends AbstractLogger implements IAmAStrategy $record = array_merge($record, ['uid' => $this->logUid]); $logMessage = $this->channel . ' '; - $logMessage .= '[' . $this->logToString[$level] . ']: '; + $logMessage .= '[' . static::logToString[$level] . ']: '; $logMessage .= $this->psrInterpolate($message, $context) . ' '; $logMessage .= $this->jsonEncodeArray($context) . ' - '; $logMessage .= $this->jsonEncodeArray($record); diff --git a/src/Util/FileSystem.php b/src/Core/Logger/Util/FileSystem.php similarity index 81% rename from src/Util/FileSystem.php rename to src/Core/Logger/Util/FileSystem.php index a21e7fb60..41bb423b4 100644 --- a/src/Util/FileSystem.php +++ b/src/Core/Logger/Util/FileSystem.php @@ -19,10 +19,12 @@ * */ -namespace Friendica\Util; +namespace Friendica\Core\Logger\Util; + +use Friendica\Core\Logger\Exception\LoggerUnusableException; /** - * Util class for filesystem manipulation + * Util class for filesystem manipulation for Logger classes */ class FileSystem { @@ -37,8 +39,10 @@ class FileSystem * @param string $file The file * * @return string The directory name (empty if no directory is found, like urls) + * + * @throws LoggerUnusableException */ - public function createDir(string $file) + public function createDir(string $file): string { $dirname = null; $pos = strpos($file, '://'); @@ -57,7 +61,7 @@ class FileSystem restore_error_handler(); if (!$status && !is_dir($dirname)) { - throw new \UnexpectedValueException(sprintf('Directory "%s" cannot get created: ' . $this->errorMessage, $dirname)); + throw new LoggerUnusableException(sprintf('Directory "%s" cannot get created: ' . $this->errorMessage, $dirname)); } return $dirname; @@ -75,7 +79,7 @@ class FileSystem * * @return resource the open stream resource * - * @throws \UnexpectedValueException + * @throws LoggerUnusableException */ public function createStream(string $url) { @@ -89,7 +93,7 @@ class FileSystem restore_error_handler(); if (!is_resource($stream)) { - throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened: ' . $this->errorMessage, $url)); + throw new LoggerUnusableException(sprintf('The stream or file "%s" could not be opened: ' . $this->errorMessage, $url)); } return $stream; diff --git a/src/Core/Logger/Util/Introspection.php b/src/Core/Logger/Util/Introspection.php index e0f7e8554..0b703da82 100644 --- a/src/Core/Logger/Util/Introspection.php +++ b/src/Core/Logger/Util/Introspection.php @@ -22,7 +22,7 @@ namespace Friendica\Core\Logger\Util; use Friendica\App\Request; -use Friendica\Core\Logger\Capabilities\IHaveCallIntrospections; +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; /** * Get Introspection information about the current call diff --git a/src/Core/Logger/Util/LoggerSettingsCheck.php b/src/Core/Logger/Util/LoggerSettingsCheck.php new file mode 100644 index 000000000..cb598d5f2 --- /dev/null +++ b/src/Core/Logger/Util/LoggerSettingsCheck.php @@ -0,0 +1,91 @@ +. + * + */ + +namespace Friendica\Core\Logger\Util; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\L10n; +use Friendica\Core\Logger\Capability\ICheckLoggerSettings; +use Friendica\Core\Logger\Exception\LoggerUnusableException; + +/** {@inheritDoc} */ +class LoggerSettingsCheck implements ICheckLoggerSettings +{ + /** @var IManageConfigValues */ + protected $config; + /** @var $fileSystem */ + protected $fileSystem; + /** @var L10n */ + protected $l10n; + + public function __construct(IManageConfigValues $config, FileSystem $fileSystem, L10n $l10n) + { + $this->config = $config; + $this->fileSystem = $fileSystem; + $this->l10n = $l10n; + } + + /** {@inheritDoc} */ + public function checkLogfile(): ?string + { + // Check logfile permission + if ($this->config->get('system', 'debugging')) { + $file = $this->config->get('system', 'logfile'); + + try { + $stream = $this->fileSystem->createStream($file); + + if (!isset($stream)) { + throw new LoggerUnusableException('Stream is null.'); + } + } catch (\Throwable $exception) { + return $this->l10n->t('The logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); + } + } + + return null; + } + + /** {@inheritDoc} */ + public function checkDebugLogfile(): ?string + { + // Check logfile permission + if ($this->config->get('system', 'debugging')) { + $file = $this->config->get('system', 'dlogfile'); + + if (empty($file)) { + return null; + } + + try { + $stream = $this->fileSystem->createStream($file); + + if (!isset($stream)) { + throw new LoggerUnusableException('Stream is null.'); + } + } catch (\Throwable $exception) { + return $this->l10n->t('The debug logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); + } + } + + return null; + } +} diff --git a/src/Core/PConfig/Factory/PConfig.php b/src/Core/PConfig/Factory/PConfig.php index cde97759e..059675289 100644 --- a/src/Core/PConfig/Factory/PConfig.php +++ b/src/Core/PConfig/Factory/PConfig.php @@ -22,28 +22,16 @@ namespace Friendica\Core\PConfig\Factory; use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Hooks\Capability\ICanCreateInstances; use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; -use Friendica\Core\PConfig\Repository; -use Friendica\Core\PConfig\Type; -use Friendica\Core\PConfig\ValueObject; class PConfig { - /** - * @param IManageConfigValues $config The config - * @param ValueObject\Cache $pConfigCache The personal config cache - * @param Repository\PConfig $configRepo The configuration model - * - * @return IManagePersonalConfigValues - */ - public function create(IManageConfigValues $config, ValueObject\Cache $pConfigCache, Repository\PConfig $configRepo): IManagePersonalConfigValues + public function create(ICanCreateInstances $instanceCreator, IManageConfigValues $config): IManagePersonalConfigValues { - if ($config->get('system', 'config_adapter') === 'preload') { - $configuration = new Type\PreloadPConfig($pConfigCache, $configRepo); - } else { - $configuration = new Type\JitPConfig($pConfigCache, $configRepo); - } + $strategy = $config->get('system', 'config_adapter'); - return $configuration; + /** @var IManagePersonalConfigValues */ + return $instanceCreator->create(IManagePersonalConfigValues::class, $strategy); } } diff --git a/src/Core/PConfig/Type/AbstractPConfigValues.php b/src/Core/PConfig/Type/AbstractPConfigValues.php index 39be8f4e7..e567cbaed 100644 --- a/src/Core/PConfig/Type/AbstractPConfigValues.php +++ b/src/Core/PConfig/Type/AbstractPConfigValues.php @@ -34,6 +34,8 @@ use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues; */ abstract class AbstractPConfigValues implements IManagePersonalConfigValues { + const NAME = ''; + /** * @var Cache */ diff --git a/src/Core/PConfig/Type/JitPConfig.php b/src/Core/PConfig/Type/JitPConfig.php index c5c20577e..b851015e7 100644 --- a/src/Core/PConfig/Type/JitPConfig.php +++ b/src/Core/PConfig/Type/JitPConfig.php @@ -33,6 +33,8 @@ use Friendica\Core\PConfig\ValueObject; */ class JitPConfig extends AbstractPConfigValues { + const NAME = 'jit'; + /** * @var array Array of already loaded db values (even if there was no value) */ diff --git a/src/Core/PConfig/Type/PreloadPConfig.php b/src/Core/PConfig/Type/PreloadPConfig.php index b3b709286..6ae028c5e 100644 --- a/src/Core/PConfig/Type/PreloadPConfig.php +++ b/src/Core/PConfig/Type/PreloadPConfig.php @@ -32,6 +32,8 @@ use Friendica\Core\PConfig\ValueObject; */ class PreloadPConfig extends AbstractPConfigValues { + const NAME = 'preload'; + /** @var array */ private $config_loaded; diff --git a/src/Core/Search.php b/src/Core/Search.php index 4b3bb1c7c..98517361e 100644 --- a/src/Core/Search.php +++ b/src/Core/Search.php @@ -42,7 +42,7 @@ class Search const DEFAULT_DIRECTORY = 'https://dir.friendica.social'; const TYPE_PEOPLE = 0; - const TYPE_FORUM = 1; + const TYPE_GROUP = 1; const TYPE_ALL = 2; /** @@ -55,7 +55,7 @@ class Search * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function getContactsFromProbe(string $user, $only_forum = false): ResultList + public static function getContactsFromProbe(string $user, $only_group = false): ResultList { $emptyResultList = new ResultList(); @@ -68,7 +68,7 @@ class Search return $emptyResultList; } - if ($only_forum && ($user_data['contact-type'] != Contact::TYPE_COMMUNITY)) { + if ($only_group && ($user_data['contact-type'] != Contact::TYPE_COMMUNITY)) { return $emptyResultList; } @@ -112,8 +112,8 @@ class Search $searchUrl = $server . '/search'; switch ($type) { - case self::TYPE_FORUM: - $searchUrl .= '/forum'; + case self::TYPE_GROUP: + $searchUrl .= '/group'; break; case self::TYPE_PEOPLE: $searchUrl .= '/people'; @@ -174,7 +174,7 @@ class Search { Logger::info('Searching', ['search' => $search, 'type' => $type, 'start' => $start, 'itempage' => $itemPage]); - $contacts = Contact::searchByName($search, $type == self::TYPE_FORUM ? 'community' : '', true); + $contacts = Contact::searchByName($search, $type == self::TYPE_GROUP ? 'community' : '', true); $resultList = new ResultList($start, count($contacts), $itemPage); @@ -240,7 +240,9 @@ class Search $return = array_map(function ($result) { static $contactType = [ 'People' => Contact::TYPE_PERSON, + // Kept for backward compatibility 'Forum' => Contact::TYPE_COMMUNITY, + 'Group' => Contact::TYPE_COMMUNITY, 'Organization' => Contact::TYPE_ORGANISATION, 'News' => Contact::TYPE_NEWS, ]; diff --git a/src/Core/Session/Capability/IHandleUserSessions.php b/src/Core/Session/Capability/IHandleUserSessions.php index 5734eafdf..3b135b521 100644 --- a/src/Core/Session/Capability/IHandleUserSessions.php +++ b/src/Core/Session/Capability/IHandleUserSessions.php @@ -93,6 +93,13 @@ interface IHandleUserSessions extends IHandleSessions */ public function isSiteAdmin(): bool; + /** + * Check if current user is a moderator. + * + * @return bool true if user is a moderator + */ + public function isModerator(): bool; + /** * Returns User ID of the managed user in case it's a different identity * diff --git a/src/Core/Session/Factory/Session.php b/src/Core/Session/Factory/Session.php index 239b050e7..e12dbd9af 100644 --- a/src/Core/Session/Factory/Session.php +++ b/src/Core/Session/Factory/Session.php @@ -22,8 +22,8 @@ namespace Friendica\Core\Session\Factory; use Friendica\App; -use Friendica\Core\Cache\Enum; use Friendica\Core\Cache\Factory\Cache; +use Friendica\Core\Cache\Type\DatabaseCache; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Session\Type; @@ -74,7 +74,7 @@ class Session $cache = $cacheFactory->createDistributed(); // In case we're using the db as cache driver, use the native db session, not the cache - if ($config->get('system', 'cache_driver') === Enum\Type::DATABASE) { + if ($config->get('system', 'cache_driver') === DatabaseCache::NAME) { $handler = new Handler\Database($dba, $logger, $server); } else { $handler = new Handler\Cache($cache, $logger); diff --git a/src/Core/Session/Model/UserSession.php b/src/Core/Session/Model/UserSession.php index 8dfc3d832..c1a38dffa 100644 --- a/src/Core/Session/Model/UserSession.php +++ b/src/Core/Session/Model/UserSession.php @@ -139,6 +139,12 @@ class UserSession implements IHandleUserSessions return User::isSiteAdmin($this->getLocalUserId()); } + /** {@inheritDoc} */ + public function isModerator(): bool + { + return User::isModerator($this->getLocalUserId()); + } + /** {@inheritDoc} */ public function setVisitorsContacts(string $my_url) { diff --git a/src/Core/System.php b/src/Core/System.php index 00bdcd455..f15548346 100644 --- a/src/Core/System.php +++ b/src/Core/System.php @@ -25,6 +25,7 @@ use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\DI; +use Friendica\Model\User; use Friendica\Module\Response; use Friendica\Network\HTTPException\FoundException; use Friendica\Network\HTTPException\MovedPermanentlyException; @@ -226,9 +227,10 @@ class System * @param integer $depth How many calls to include in the stacks after filtering * @param int $offset How many calls to shave off the top of the stack, for example if * this is called from a centralized method that isn't relevant to the callstack + * @param bool $full If enabled, the callstack is not compacted * @return string */ - public static function callstack(int $depth = 4, int $offset = 0): string + public static function callstack(int $depth = 4, int $offset = 0, bool $full = false): string { $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); @@ -243,7 +245,7 @@ class System while ($func = array_pop($trace)) { if (!empty($func['class'])) { - if (in_array($previous['function'], ['insert', 'fetch', 'toArray', 'exists', 'count', 'selectFirst', 'selectToArray', + if (!$full && in_array($previous['function'], ['insert', 'fetch', 'toArray', 'exists', 'count', 'selectFirst', 'selectToArray', 'select', 'update', 'delete', 'selectFirstForUser', 'selectForUser']) && (substr($previous['class'], 0, 15) === 'Friendica\Model')) { continue; @@ -251,7 +253,7 @@ class System // Don't show multiple calls from the Database classes to show the essential parts of the callstack $func['database'] = in_array($func['class'], ['Friendica\Database\DBA', 'Friendica\Database\Database']); - if (!$previous['database'] || !$func['database']) { + if ($full || !$previous['database'] || !$func['database']) { $classparts = explode("\\", $func['class']); $callstack[] = array_pop($classparts).'::'.$func['function'] . (isset($func['line']) ? ' (' . $func['line'] . ')' : ''); $previous = $func; @@ -669,9 +671,7 @@ class System if (DI::config()->get('system', 'tosdisplay')) { $rulelist = DI::config()->get('system', 'tosrules') ?: DI::config()->get('system', 'tostext'); - $html = BBCode::convert($rulelist, false, BBCode::EXTERNAL); - - $msg = HTML::toPlaintext($html, 0, true); + $msg = BBCode::toPlaintext($rulelist, false); foreach (explode("\n", trim($msg)) as $line) { $line = trim($line); if ($line) { diff --git a/src/Core/Worker.php b/src/Core/Worker.php index 00885f692..7075b4b23 100644 --- a/src/Core/Worker.php +++ b/src/Core/Worker.php @@ -1365,6 +1365,17 @@ class Worker return $new_retrial; } + /** + * Get the number of retrials for the current worker task + * + * @return integer + */ + public static function getRetrial(): int + { + $queue = DI::app()->getQueue(); + return $queue['retrial'] ?? 0; + } + /** * Defers the current worker entry * diff --git a/src/DI.php b/src/DI.php index 8d706ed37..2d6eb6ede 100644 --- a/src/DI.php +++ b/src/DI.php @@ -22,6 +22,8 @@ namespace Friendica; use Dice\Dice; +use Friendica\Core\Logger\Capability\ICheckLoggerSettings; +use Friendica\Core\Logger\Util\LoggerSettingsCheck; use Friendica\Core\Session\Capability\IHandleSessions; use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Navigation\SystemMessages; @@ -208,9 +210,9 @@ abstract class DI return self::$dice->create(Core\Config\Util\ConfigFileManager::class); } - public static function keyValue(): Core\KeyValueStorage\Capabilities\IManageKeyValuePairs + public static function keyValue(): Core\KeyValueStorage\Capability\IManageKeyValuePairs { - return self::$dice->create(Core\KeyValueStorage\Capabilities\IManageKeyValuePairs::class); + return self::$dice->create(Core\KeyValueStorage\Capability\IManageKeyValuePairs::class); } /** @@ -295,6 +297,11 @@ abstract class DI static::init($flushDice); } + public static function logCheck(): ICheckLoggerSettings + { + return self::$dice->create(LoggerSettingsCheck::class); + } + /** * @return LoggerInterface */ @@ -664,6 +671,15 @@ abstract class DI return self::$dice->create(Security\Authentication::class); } + // + // "User" namespace instances + // + + public static function userGServer(): User\Settings\Repository\UserGServer + { + return self::$dice->create(User\Settings\Repository\UserGServer::class); + } + // // "Util" namespace instances // @@ -692,14 +708,6 @@ abstract class DI return self::$dice->create(Util\DateTimeFormat::class); } - /** - * @return Util\FileSystem - */ - public static function fs() - { - return self::$dice->create(Util\FileSystem::class); - } - /** * @return Util\Profiler */ diff --git a/src/Database/Database.php b/src/Database/Database.php index 78a534ead..9366f1b31 100644 --- a/src/Database/Database.php +++ b/src/Database/Database.php @@ -752,8 +752,8 @@ class Database @file_put_contents( $this->config->get('system', 'db_log'), DateTimeFormat::utcNow() . "\t" . $duration . "\t" . - basename($backtrace[1]["file"]) . "\t" . - $backtrace[1]["line"] . "\t" . $backtrace[2]["function"] . "\t" . + basename($backtrace[1]['file']) . "\t" . + $backtrace[1]['line'] . "\t" . $backtrace[2]['function'] . "\t" . substr($this->replaceParameters($sql, $args), 0, 4000) . "\n", FILE_APPEND ); diff --git a/src/Factory/Api/Friendica/Group.php b/src/Factory/Api/Friendica/Circle.php similarity index 82% rename from src/Factory/Api/Friendica/Group.php rename to src/Factory/Api/Friendica/Circle.php index 4f085cd2b..bf20ceb6d 100644 --- a/src/Factory/Api/Friendica/Group.php +++ b/src/Factory/Api/Friendica/Circle.php @@ -27,7 +27,7 @@ use Friendica\Network\HTTPException; use Psr\Log\LoggerInterface; use Friendica\Factory\Api\Twitter\User as TwitterUser; -class Group extends BaseFactory +class Circle extends BaseFactory { /** @var twitterUser entity */ private $twitterUser; @@ -43,19 +43,19 @@ class Group extends BaseFactory } /** - * @param int $id id of the group + * @param int $id id of the circle * @return array * @throws HTTPException\InternalServerErrorException */ public function createFromId(int $id): array { - $group = $this->dba->selectFirst('group', [], ['id' => $id, 'deleted' => false]); - if (empty($group)) { + $circle = $this->dba->selectFirst('group', [], ['id' => $id, 'deleted' => false]); + if (empty($circle)) { return []; } - $user = $this->twitterUser->createFromUserId($group['uid'])->toArray(); - $object = new \Friendica\Object\Api\Friendica\Group($group, $user); + $user = $this->twitterUser->createFromUserId($circle['uid'])->toArray(); + $object = new \Friendica\Object\Api\Friendica\Circle($circle, $user); return $object->toArray(); } diff --git a/src/Factory/Api/Mastodon/Field.php b/src/Factory/Api/Mastodon/Field.php index 8b24eb486..e4fe20305 100644 --- a/src/Factory/Api/Mastodon/Field.php +++ b/src/Factory/Api/Mastodon/Field.php @@ -38,7 +38,7 @@ class Field extends BaseFactory */ public function createFromProfileField(ProfileField $profileField): \Friendica\Object\Api\Mastodon\Field { - return new \Friendica\Object\Api\Mastodon\Field($profileField->label, BBCode::convert($profileField->value, false, BBCode::ACTIVITYPUB)); + return new \Friendica\Object\Api\Mastodon\Field($profileField->label, BBCode::convertForUriId($profileField->uriId, $profileField->value, BBCode::ACTIVITYPUB)); } /** diff --git a/src/Factory/Api/Mastodon/ListEntity.php b/src/Factory/Api/Mastodon/ListEntity.php index a78c8dd63..effdd45a1 100644 --- a/src/Factory/Api/Mastodon/ListEntity.php +++ b/src/Factory/Api/Mastodon/ListEntity.php @@ -40,9 +40,9 @@ class ListEntity extends BaseFactory /** * @throws InternalServerErrorException */ - public function createFromGroupId(int $id): \Friendica\Object\Api\Mastodon\ListEntity + public function createFromCircleId(int $id): \Friendica\Object\Api\Mastodon\ListEntity { - $group = $this->dba->selectFirst('group', ['name'], ['id' => $id, 'deleted' => false]); - return new \Friendica\Object\Api\Mastodon\ListEntity($id, $group['name'] ?? '', 'list'); + $circle = $this->dba->selectFirst('group', ['name'], ['id' => $id, 'deleted' => false]); + return new \Friendica\Object\Api\Mastodon\ListEntity($id, $circle['name'] ?? '', 'list'); } } diff --git a/src/Federation/Entity/GServer.php b/src/Federation/Entity/GServer.php new file mode 100644 index 000000000..0e331f480 --- /dev/null +++ b/src/Federation/Entity/GServer.php @@ -0,0 +1,151 @@ +. + * + */ + +namespace Friendica\Federation\Entity; + +use DateTimeImmutable; +use Psr\Http\Message\UriInterface; + +/** + * @property-read int $id + * @property-read string $url + * @property-read string $nurl + * @property-read string $version + * @property-read string $siteName + * @property-read string $info + * @property-read int $registerPolicy + * @property-read int $registeredUsers + * @property-read string $poco + * @property-read string $noscrape + * @property-read string $network + * @property-read string $platform + * @property-read int $relaySubscribe + * @property-read string $relayScope + * @property-read DateTimeImmutable $created + * @property-read ?DateTimeImmutable $lastPocoQuery + * @property-read ?DateTimeImmutable $lastContact + * @property-read ?DateTimeImmutable $lastFailure + * @property-read int $directoryType + * @property-read int $detectionMethod + * @property-read bool $failed + * @property-read DateTimeImmutable $nextContact + * @property-read int $protocol + * @property-read int $activeWeekUsers + * @property-read int $activeMonthUsers + * @property-read int $activeHalfyearUsers + * @property-read int $localPosts + * @property-read int $localComments + * @property-read bool $blocked + */ +class GServer extends \Friendica\BaseEntity +{ + /** @var ?int */ + protected $id; + /** @var UriInterface */ + protected $url; + /** @var UriInterface */ + protected $nurl; + /** @var string */ + protected $version; + /** @var string */ + protected $siteName; + /** @var string */ + protected $info; + /** @var int One of Module\Register::* constant values */ + protected $registerPolicy; + /** @var int */ + protected $registeredUsers; + /** @var ?UriInterface */ + protected $poco; + /** @var ?UriInterface */ + protected $noscrape; + /** @var string One of the Protocol::* constant values */ + protected $network; + /** @var string */ + protected $platform; + /** @var bool */ + protected $relaySubscribe; + /** @var string */ + protected $relayScope; + /** @var DateTimeImmutable */ + protected $created; + /** @var DateTimeImmutable */ + protected $lastPocoQuery; + /** @var DateTimeImmutable */ + protected $lastContact; + /** @var DateTimeImmutable */ + protected $lastFailure; + /** @var int One of Model\Gserver::DT_* constant values */ + protected $directoryType; + /** @var ?int One of Model\Gserver::DETECT_* constant values */ + protected $detectionMethod; + /** @var bool */ + protected $failed; + /** @var DateTimeImmutable */ + protected $nextContact; + /** @var ?int One of Model\Post\DeliveryData::* constant values */ + protected $protocol; + /** @var ?int */ + protected $activeWeekUsers; + /** @var ?int */ + protected $activeMonthUsers; + /** @var ?int */ + protected $activeHalfyearUsers; + /** @var ?int */ + protected $localPosts; + /** @var ?int */ + protected $localComments; + /** @var bool */ + protected $blocked; + + public function __construct(UriInterface $url, UriInterface $nurl, string $version, string $siteName, string $info, int $registerPolicy, int $registeredUsers, ?UriInterface $poco, ?UriInterface $noscrape, string $network, string $platform, bool $relaySubscribe, string $relayScope, DateTimeImmutable $created, ?DateTimeImmutable $lastPocoQuery, ?DateTimeImmutable $lastContact, ?DateTimeImmutable $lastFailure, int $directoryType, ?int $detectionMethod, bool $failed, ?DateTimeImmutable $nextContact, ?int $protocol, ?int $activeWeekUsers, ?int $activeMonthUsers, ?int $activeHalfyearUsers, ?int $localPosts, ?int $localComments, bool $blocked, ?int $id = null) + { + $this->url = $url; + $this->nurl = $nurl; + $this->version = $version; + $this->siteName = $siteName; + $this->info = $info; + $this->registerPolicy = $registerPolicy; + $this->registeredUsers = $registeredUsers; + $this->poco = $poco; + $this->noscrape = $noscrape; + $this->network = $network; + $this->platform = $platform; + $this->relaySubscribe = $relaySubscribe; + $this->relayScope = $relayScope; + $this->created = $created; + $this->lastPocoQuery = $lastPocoQuery; + $this->lastContact = $lastContact; + $this->lastFailure = $lastFailure; + $this->directoryType = $directoryType; + $this->detectionMethod = $detectionMethod; + $this->failed = $failed; + $this->nextContact = $nextContact; + $this->protocol = $protocol; + $this->activeWeekUsers = $activeWeekUsers; + $this->activeMonthUsers = $activeMonthUsers; + $this->activeHalfyearUsers = $activeHalfyearUsers; + $this->localPosts = $localPosts; + $this->localComments = $localComments; + $this->blocked = $blocked; + $this->id = $id; + } +} diff --git a/src/Federation/Factory/GServer.php b/src/Federation/Factory/GServer.php new file mode 100644 index 000000000..681cad7af --- /dev/null +++ b/src/Federation/Factory/GServer.php @@ -0,0 +1,68 @@ +. + * + */ + +namespace Friendica\Federation\Factory; + +use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Database\DBA; +use Friendica\Federation\Entity; +use GuzzleHttp\Psr7\Uri; + +class GServer extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + /** + * @inheritDoc + */ + public function createFromTableRow(array $row): Entity\GServer + { + return new Entity\GServer( + new Uri($row['url']), + new Uri($row['nurl']), + $row['version'], + $row['site_name'], + $row['info'] ?? '', + $row['register_policy'], + $row['registered-users'], + $row['poco'] ? new Uri($row['poco']) : null, + $row['noscrape'] ? new Uri($row['noscrape']) : null, + $row['network'], + $row['platform'], + $row['relay-subscribe'], + $row['relay-scope'], + new \DateTimeImmutable($row['created']), + $row['last_poco_query'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_poco_query']) : null, + $row['last_contact'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_contact']) : null, + $row['last_failure'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['last_failure']) : null, + $row['directory-type'], + $row['detection-method'], + $row['failed'], + $row['next_contact'] !== DBA::NULL_DATETIME ? new \DateTimeImmutable($row['next_contact']) : null, + $row['protocol'], + $row['active-week-users'], + $row['active-month-users'], + $row['active-halfyear-users'], + $row['local-posts'], + $row['local-comments'], + $row['blocked'], + $row['id'], + ); + } +} diff --git a/src/Federation/Repository/GServer.php b/src/Federation/Repository/GServer.php new file mode 100644 index 000000000..47a9244f6 --- /dev/null +++ b/src/Federation/Repository/GServer.php @@ -0,0 +1,47 @@ +. + * + */ + +namespace Friendica\Federation\Repository; + +use Friendica\Database\Database; +use Friendica\Federation\Factory; +use Friendica\Federation\Entity; +use Psr\Log\LoggerInterface; + +class GServer extends \Friendica\BaseRepository +{ + protected static $table_name = 'gserver'; + + public function __construct(Database $database, LoggerInterface $logger, Factory\GServer $factory) + { + parent::__construct($database, $logger, $factory); + } + + /** + * @param int $gsid + * @return Entity\GServer + * @throws \Friendica\Network\HTTPException\NotFoundException + */ + public function selectOneById(int $gsid): Entity\GServer + { + return $this->_selectOne(['id' => $gsid]); + } +} diff --git a/src/Model/APContact.php b/src/Model/APContact.php index dc062fe5b..c49017b59 100644 --- a/src/Model/APContact.php +++ b/src/Model/APContact.php @@ -119,6 +119,11 @@ class APContact return []; } + if (!Network::isValidHttpUrl($url) && !filter_var($url, FILTER_VALIDATE_EMAIL)) { + Logger::info('Invalid URL', ['url' => $url]); + return []; + } + $fetched_contact = []; if (empty($update)) { @@ -579,6 +584,14 @@ class APContact */ public static function isRelay(array $apcontact): bool { + if (in_array($apcontact['type'], ['Person', 'Organization'])) { + return false; + } + + if (($apcontact['type'] == 'Service') && empty($apcontact['outbox']) && empty($apcontact['sharedinbox']) && empty($apcontact['following']) && empty($apcontact['followers']) && empty($apcontact['statuses_count'])) { + return true; + } + if (empty($apcontact['nick']) || $apcontact['nick'] != 'relay') { return false; } diff --git a/src/Model/Attach.php b/src/Model/Attach.php index 3dfb2e21e..a008b3a4d 100644 --- a/src/Model/Attach.php +++ b/src/Model/Attach.php @@ -190,9 +190,9 @@ class Attach * @param string $filetype Mimetype. optional, default = '' * @param integer $filesize File size in bytes. optional, default = null * @param string $allow_cid Permissions, allowed contacts. optional, default = '' - * @param string $allow_gid Permissions, allowed groups. optional, default = '' - * @param string $deny_cid Permissions, denied contacts.optional, default = '' - * @param string $deny_gid Permissions, denied group.optional, default = '' + * @param string $allow_gid Permissions, allowed circles. optional, default = '' + * @param string $deny_cid Permissions, denied contacts. optional, default = '' + * @param string $deny_gid Permissions, denied circle. optional, default = '' * * @return boolean|integer Row id on success, False on errors * @throws \Friendica\Network\HTTPException\InternalServerErrorException diff --git a/src/Model/Group.php b/src/Model/Circle.php similarity index 57% rename from src/Model/Group.php rename to src/Model/Circle.php index 45e1ee72d..2b32103db 100644 --- a/src/Model/Group.php +++ b/src/Model/Circle.php @@ -22,6 +22,7 @@ namespace Friendica\Model; use Friendica\BaseModule; +use Friendica\Content\Widget; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Core\Renderer; @@ -34,16 +35,16 @@ use Friendica\Protocol\ActivityPub; /** * functions for interacting with the group database table */ -class Group +class Circle { const FOLLOWERS = '~'; const MUTUALS = '&'; /** - * Fetches group record by user id and maybe includes deleted groups as well + * Fetches circle record by user id and maybe includes deleted circles as well * - * @param int $uid User id to fetch group(s) for - * @param bool $includesDeleted Whether deleted groups should be included + * @param int $uid User id to fetch circle(s) for + * @param bool $includesDeleted Whether deleted circles should be included * @return array|bool Array on success, bool on error */ public static function getByUserId(int $uid, bool $includesDeleted = false) @@ -58,16 +59,16 @@ class Group } /** - * Checks whether given group id is found in database + * Checks whether given circle id is found in database * - * @param int $group_id Group id + * @param int $circle_id Circle id * @param int $uid Optional user id * @return bool * @throws \Exception */ - public static function exists(int $group_id, int $uid = null): bool + public static function exists(int $circle_id, int $uid = null): bool { - $condition = ['id' => $group_id, 'deleted' => false]; + $condition = ['id' => $circle_id, 'deleted' => false]; if (!is_null($uid)) { $condition = [ @@ -79,13 +80,13 @@ class Group } /** - * Create a new contact group + * Create a new contact circle * - * Note: If we found a deleted group with the same name, we restore it + * Note: If we found a deleted circle with the same name, we restore it * - * @param int $uid User id to create group for - * @param string $name Name of group - * @return int|boolean Id of newly created group or false on error + * @param int $uid User id to create circle for + * @param string $name Name of circle + * @return int|boolean Id of newly created circle or false on error * @throws \Exception */ public static function create(int $uid, string $name) @@ -95,14 +96,14 @@ class Group $gid = self::getIdByName($uid, $name); // check for dupes if ($gid !== false) { // This could be a problem. - // Let's assume we've just created a group which we once deleted - // all the old members are gone, but the group remains so we don't break any security - // access lists. What we're doing here is reviving the dead group, but old content which - // was restricted to this group may now be seen by the new group members. - $group = DBA::selectFirst('group', ['deleted'], ['id' => $gid]); - if (DBA::isResult($group) && $group['deleted']) { + // Let's assume we've just created a circle which we once deleted + // all the old members are gone, but the circle remains, so we don't break any security + // access lists. What we're doing here is reviving the dead circle, but old content which + // was restricted to this circle may now be seen by the new circle members. + $circle = DBA::selectFirst('group', ['deleted'], ['id' => $gid]); + if (DBA::isResult($circle) && $circle['deleted']) { DBA::update('group', ['deleted' => 0], ['id' => $gid]); - DI::sysmsg()->addNotice(DI::l10n()->t('A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name.')); + DI::sysmsg()->addNotice(DI::l10n()->t('A deleted circle with this name was revived. Existing item permissions may apply to this circle and any future members. If this is not what you intended, please create another circle with a different name.')); } return true; } @@ -116,10 +117,10 @@ class Group } /** - * Update group information. + * Update circle information. * - * @param int $id Group ID - * @param string $name Group name + * @param int $id Circle ID + * @param string $name Circle name * * @return bool Was the update successful? * @throws \Exception @@ -130,10 +131,10 @@ class Group } /** - * Get a list of group ids a contact belongs to + * Get a list of circle ids a contact belongs to * * @param int $cid Contact id - * @return array Group ids + * @return array Circle ids * @throws \Exception */ public static function getIdsByContactId(int $cid): array @@ -143,50 +144,50 @@ class Group return []; } - $groupIds = []; + $circleIds = []; $stmt = DBA::select('group_member', ['gid'], ['contact-id' => $cid]); - while ($group = DBA::fetch($stmt)) { - $groupIds[] = $group['gid']; + while ($circle = DBA::fetch($stmt)) { + $circleIds[] = $circle['gid']; } DBA::close($stmt); - // Meta-groups + // Meta-circles if ($contact['rel'] == Contact::FOLLOWER || $contact['rel'] == Contact::FRIEND) { - $groupIds[] = self::FOLLOWERS; + $circleIds[] = self::FOLLOWERS; } if ($contact['rel'] == Contact::FRIEND) { - $groupIds[] = self::MUTUALS; + $circleIds[] = self::MUTUALS; } - return $groupIds; + return $circleIds; } /** - * count unread group items + * count unread circle items * - * Count unread items of each groups of the local user + * Count unread items of each circle of the local user * * @return array - * 'id' => group id - * 'name' => group name - * 'count' => counted unseen group items + * 'id' => circle id + * 'name' => circle name + * 'count' => counted unseen circle items * @throws \Exception */ public static function countUnseen() { - $stmt = DBA::p("SELECT `group`.`id`, `group`.`name`, - (SELECT COUNT(*) FROM `post-user` + $stmt = DBA::p("SELECT `circle`.`id`, `circle`.`name`, + (SELECT COUNT(*) FROM `post-user-view` WHERE `uid` = ? AND `unseen` AND `contact-id` IN (SELECT `contact-id` - FROM `group_member` - WHERE `group_member`.`gid` = `group`.`id`) + FROM `group_member` AS `circle_member` + WHERE `circle_member`.`gid` = `circle`.`id`) ) AS `count` - FROM `group` - WHERE `group`.`uid` = ?;", + FROM `group` AS `circle` + WHERE `circle`.`uid` = ?;", DI::userSession()->getLocalUserId(), DI::userSession()->getLocalUserId() ); @@ -195,13 +196,13 @@ class Group } /** - * Get the group id for a user/name couple + * Get the circle id for a user/name couple * - * Returns false if no group has been found. + * Returns false if no circle has been found. * * @param int $uid User id - * @param string $name Group name - * @return int|boolean Groups' id number or false on error + * @param string $name Circle name + * @return int|boolean Circle's id number or false on error * @throws \Exception */ public static function getIdByName(int $uid, string $name) @@ -210,16 +211,16 @@ class Group return false; } - $group = DBA::selectFirst('group', ['id'], ['uid' => $uid, 'name' => $name]); - if (DBA::isResult($group)) { - return $group['id']; + $circle = DBA::selectFirst('group', ['id'], ['uid' => $uid, 'name' => $name]); + if (DBA::isResult($circle)) { + return $circle['id']; } return false; } /** - * Mark a group as deleted + * Mark a circle as deleted * * @param int $gid * @return boolean @@ -231,13 +232,13 @@ class Group return false; } - $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]); - if (!DBA::isResult($group)) { + $circle = DBA::selectFirst('group', ['uid'], ['id' => $gid]); + if (!DBA::isResult($circle)) { return false; } - // remove group from default posting lists - $user = DBA::selectFirst('user', ['def_gid', 'allow_gid', 'deny_gid'], ['uid' => $group['uid']]); + // remove circle from default posting lists + $user = DBA::selectFirst('user', ['def_gid', 'allow_gid', 'deny_gid'], ['uid' => $circle['uid']]); if (DBA::isResult($user)) { $change = false; @@ -255,21 +256,21 @@ class Group } if ($change) { - DBA::update('user', $user, ['uid' => $group['uid']]); + DBA::update('user', $user, ['uid' => $circle['uid']]); } } // remove all members DBA::delete('group_member', ['gid' => $gid]); - // remove group + // remove circle $return = DBA::update('group', ['deleted' => 1], ['id' => $gid]); return $return; } /** - * Adds a contact to a group + * Adds a contact to a circle * * @param int $gid * @param int $cid @@ -283,12 +284,12 @@ class Group } // @TODO Backward compatibility with user contacts, remove by version 2022.03 - $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]); - if (empty($group)) { - throw new HTTPException\NotFoundException('Group not found.'); + $circle = DBA::selectFirst('group', ['uid'], ['id' => $gid]); + if (empty($circle)) { + throw new HTTPException\NotFoundException('Circle not found.'); } - $cdata = Contact::getPublicAndUserContactID($cid, $group['uid']); + $cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']); if (empty($cdata['user'])) { throw new HTTPException\NotFoundException('Invalid contact.'); } @@ -297,7 +298,7 @@ class Group } /** - * Removes a contact from a group + * Removes a contact from a circle * * @param int $gid * @param int $cid @@ -311,12 +312,12 @@ class Group } // @TODO Backward compatibility with user contacts, remove by version 2022.03 - $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]); - if (empty($group)) { - throw new HTTPException\NotFoundException('Group not found.'); + $circle = DBA::selectFirst('group', ['uid'], ['id' => $gid]); + if (empty($circle)) { + throw new HTTPException\NotFoundException('Circle not found.'); } - $cdata = Contact::getPublicAndUserContactID($cid, $group['uid']); + $cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']); if (empty($cdata['user'])) { throw new HTTPException\NotFoundException('Invalid contact.'); } @@ -325,7 +326,7 @@ class Group } /** - * Adds contacts to a group + * Adds contacts to a circle * * @param int $gid * @param array $contacts Array with contact ids @@ -339,13 +340,13 @@ class Group } // @TODO Backward compatibility with user contacts, remove by version 2022.03 - $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]); - if (empty($group)) { - throw new HTTPException\NotFoundException('Group not found.'); + $circle = DBA::selectFirst('group', ['uid'], ['id' => $gid]); + if (empty($circle)) { + throw new HTTPException\NotFoundException('Circle not found.'); } foreach ($contacts as $cid) { - $cdata = Contact::getPublicAndUserContactID($cid, $group['uid']); + $cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']); if (empty($cdata['user'])) { throw new HTTPException\NotFoundException('Invalid contact.'); } @@ -355,9 +356,9 @@ class Group } /** - * Removes contacts from a group + * Removes contacts from a circle * - * @param int $gid Group id + * @param int $gid Circle id * @param array $contacts Contact ids * @return bool * @throws \Exception @@ -369,15 +370,15 @@ class Group } // @TODO Backward compatibility with user contacts, remove by version 2022.03 - $group = DBA::selectFirst('group', ['uid'], ['id' => $gid]); - if (empty($group)) { - throw new HTTPException\NotFoundException('Group not found.'); + $circle = DBA::selectFirst('group', ['uid'], ['id' => $gid]); + if (empty($circle)) { + throw new HTTPException\NotFoundException('Circle not found.'); } $contactIds = []; foreach ($contacts as $cid) { - $cdata = Contact::getPublicAndUserContactID($cid, $group['uid']); + $cdata = Contact::getPublicAndUserContactID($cid, $circle['uid']); if (empty($cdata['user'])) { throw new HTTPException\NotFoundException('Invalid contact.'); } @@ -390,18 +391,18 @@ class Group } /** - * Returns the combined list of contact ids from a group id list + * Returns the combined list of contact ids from a circle id list * * @param int $uid User id - * @param array $group_ids Groups ids + * @param array $circle_ids Circles ids * @param boolean $check_dead Whether check "dead" records (?) * @param boolean $expand_followers Expand the list of followers * @return array * @throws \Exception */ - public static function expand(int $uid, array $group_ids, bool $check_dead = false, bool $expand_followers = true): array + public static function expand(int $uid, array $circle_ids, bool $check_dead = false, bool $expand_followers = true): array { - if (!is_array($group_ids) || !count($group_ids)) { + if (!is_array($circle_ids) || !count($circle_ids)) { return []; } @@ -419,7 +420,7 @@ class Group $networks = array_diff($networks, [Protocol::MAIL]); } - $key = array_search(self::FOLLOWERS, $group_ids); + $key = array_search(self::FOLLOWERS, $circle_ids); if ($key !== false) { if ($expand_followers) { $followers = Contact::selectToArray(['id'], [ @@ -438,10 +439,10 @@ class Group } else { $followers_collection = true; } - unset($group_ids[$key]); + unset($circle_ids[$key]); } - $key = array_search(self::MUTUALS, $group_ids); + $key = array_search(self::MUTUALS, $circle_ids); if ($key !== false) { $mutuals = Contact::selectToArray(['id'], [ 'uid' => $uid, @@ -457,12 +458,12 @@ class Group $return[] = $mutual['id']; } - unset($group_ids[$key]); + unset($circle_ids[$key]); } - $stmt = DBA::select('group_member', ['contact-id'], ['gid' => $group_ids]); - while ($group_member = DBA::fetch($stmt)) { - $return[] = $group_member['contact-id']; + $stmt = DBA::select('group_member', ['contact-id'], ['gid' => $circle_ids]); + while ($circle_member = DBA::fetch($stmt)) { + $return[] = $circle_member['contact-id']; } DBA::close($stmt); @@ -478,17 +479,18 @@ class Group } /** - * Returns a templated group selection list + * Returns a templated circle selection list * * @param int $uid User id - * @param int $gid An optional pre-selected group - * @param string $label An optional label of the list + * @param int $gid A pre-selected circle + * @param string $id The id of the option group + * @param string $label The label of the option group * @return string * @throws \Exception */ - public static function displayGroupSelection(int $uid, int $gid = 0, string $label = ''): string + public static function getSelectorHTML(int $uid, int $gid, string $id, string $label): string { - $display_groups = [ + $display_circles = [ [ 'name' => '', 'id' => '0', @@ -497,53 +499,50 @@ class Group ]; $stmt = DBA::select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null], ['order' => ['name']]); - while ($group = DBA::fetch($stmt)) { - $display_groups[] = [ - 'name' => $group['name'], - 'id' => $group['id'], - 'selected' => $gid == $group['id'] ? 'true' : '' + while ($circle = DBA::fetch($stmt)) { + $display_circles[] = [ + 'name' => $circle['name'], + 'id' => $circle['id'], + 'selected' => $gid == $circle['id'] ? 'true' : '' ]; } DBA::close($stmt); - Logger::info('Got groups', $display_groups); + Logger::info('Got circles', $display_circles); - if ($label == '') { - $label = DI::l10n()->t('Default privacy group for new contacts'); - } - - $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('group_selection.tpl'), [ + $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('circle_selection.tpl'), [ + '$id' => $id, '$label' => $label, - '$groups' => $display_groups + '$circles' => $display_circles ]); return $o; } /** - * Create group sidebar widget + * Create circle sidebar widget * * @param string $every * @param string $each * @param string $editmode - * 'standard' => include link 'Edit groups' - * 'extended' => include link 'Create new group' - * 'full' => include link 'Create new group' and provide for each group a link to edit this group - * @param string|int $group_id Distinct group id or 'everyone' + * 'standard' => include link 'Edit circles' + * 'extended' => include link 'Create new circle' + * 'full' => include link 'Create new circle' and provide for each circle a link to edit this circle + * @param string|int $circle_id Distinct circle id or 'everyone' * @param int $cid Contact id * @return string Sidebar widget HTML code * @throws \Exception */ - public static function sidebarWidget(string $every = 'contact', string $each = 'group', string $editmode = 'standard', $group_id = '', int $cid = 0) + public static function sidebarWidget(string $every = 'contact', string $each = 'circle', string $editmode = 'standard', $circle_id = '', int $cid = 0) { if (!DI::userSession()->getLocalUserId()) { return ''; } - $display_groups = [ + $display_circles = [ [ 'text' => DI::l10n()->t('Everybody'), 'id' => 0, - 'selected' => (($group_id === 'everyone') ? 'group-selected' : ''), + 'selected' => (($circle_id === 'everyone') ? 'circle-selected' : ''), 'href' => $every, ] ]; @@ -554,77 +553,82 @@ class Group } $stmt = DBA::select('group', [], ['deleted' => false, 'uid' => DI::userSession()->getLocalUserId(), 'cid' => null], ['order' => ['name']]); - while ($group = DBA::fetch($stmt)) { - $selected = (($group_id == $group['id']) ? ' group-selected' : ''); + while ($circle = DBA::fetch($stmt)) { + $selected = (($circle_id == $circle['id']) ? ' circle-selected' : ''); if ($editmode == 'full') { - $groupedit = [ - 'href' => 'group/' . $group['id'], + $circleedit = [ + 'href' => 'circle/' . $circle['id'], 'title' => DI::l10n()->t('edit'), ]; } else { - $groupedit = null; + $circleedit = null; } - if ($each == 'group') { - $count = DBA::count('group_member', ['gid' => $group['id']]); - $group_name = sprintf('%s (%d)', $group['name'], $count); + if ($each == 'circle') { + $networks = Widget::unavailableNetworks(); + $sql_values = array_merge([$circle['id']], $networks); + $condition = ["`circle-id` = ? AND NOT `contact-network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")"]; + $condition = array_merge($condition, $sql_values); + + $count = DBA::count('circle-member-view', $condition); + $circle_name = sprintf('%s (%d)', $circle['name'], $count); } else { - $group_name = $group['name']; + $circle_name = $circle['name']; } - $display_groups[] = [ - 'id' => $group['id'], + $display_circles[] = [ + 'id' => $circle['id'], 'cid' => $cid, - 'text' => $group_name, - 'href' => $each . '/' . $group['id'], - 'edit' => $groupedit, + 'text' => $circle_name, + 'href' => $each . '/' . $circle['id'], + 'edit' => $circleedit, 'selected' => $selected, - 'ismember' => in_array($group['id'], $member_of), + 'ismember' => in_array($circle['id'], $member_of), ]; } DBA::close($stmt); - // Don't show the groups on the network page when there is only one - if ((count($display_groups) <= 2) && ($each == 'network')) { + // Don't show the circles on the network page when there is only one + if ((count($display_circles) <= 2) && ($each == 'network')) { return ''; } - $tpl = Renderer::getMarkupTemplate('group_side.tpl'); + $tpl = Renderer::getMarkupTemplate('circle_side.tpl'); $o = Renderer::replaceMacros($tpl, [ '$add' => DI::l10n()->t('add'), - '$title' => DI::l10n()->t('Groups'), - '$groups' => $display_groups, - 'newgroup' => $editmode == 'extended' || $editmode == 'full' ? 1 : '', - 'grouppage' => 'group/', - '$edittext' => DI::l10n()->t('Edit group'), - '$ungrouped' => $every === 'contact' ? DI::l10n()->t('Contacts not in any group') : '', - '$ungrouped_selected' => (($group_id === 'none') ? 'group-selected' : ''), - '$createtext' => DI::l10n()->t('Create a new group'), - '$creategroup' => DI::l10n()->t('Group Name: '), - '$editgroupstext' => DI::l10n()->t('Edit groups'), - '$form_security_token' => BaseModule::getFormSecurityToken('group_edit'), + '$title' => DI::l10n()->t('Circles'), + '$circles' => $display_circles, + '$new_circle' => $editmode == 'extended' || $editmode == 'full' ? 1 : '', + '$circle_page' => 'circle/', + '$edittext' => DI::l10n()->t('Edit circle'), + '$uncircled' => $every === 'contact' ? DI::l10n()->t('Contacts not in any circle') : '', + '$uncircled_selected' => (($circle_id === 'none') ? 'circle-selected' : ''), + '$createtext' => DI::l10n()->t('Create a new circle'), + '$create_circle' => DI::l10n()->t('Circle Name: '), + '$edit_circles_text' => DI::l10n()->t('Edit circles'), + '$form_security_token' => BaseModule::getFormSecurityToken('circle_edit'), ]); return $o; } /** - * Fetch the group id for the given contact id + * Fetch the circle id for the given contact id * * @param integer $id Contact ID - * @return integer Group IO + * @return integer Circle ID */ - public static function getIdForForum(int $id): int + public static function getIdForGroup(int $id): int { - Logger::info('Get id for forum id', ['id' => $id]); + Logger::info('Get id for group id', ['id' => $id]); $contact = Contact::getById($id, ['uid', 'name', 'contact-type', 'manually-approve']); if (empty($contact) || ($contact['contact-type'] != Contact::TYPE_COMMUNITY) || !$contact['manually-approve']) { return 0; } - $group = DBA::selectFirst('group', ['id'], ['uid' => $contact['uid'], 'cid' => $id]); - if (empty($group)) { + $circle = DBA::selectFirst('group', ['id'], ['uid' => $contact['uid'], 'cid' => $id]); + if (empty($circle)) { $fields = [ 'uid' => $contact['uid'], 'name' => $contact['name'], @@ -633,21 +637,21 @@ class Group DBA::insert('group', $fields); $gid = DBA::lastInsertId(); } else { - $gid = $group['id']; + $gid = $circle['id']; } return $gid; } /** - * Fetch the followers of a given contact id and store them as group members + * Fetch the followers of a given contact id and store them as circle members * * @param integer $id Contact ID * @return void */ - public static function updateMembersForForum(int $id) + public static function updateMembersForGroup(int $id) { - Logger::info('Update forum members', ['id' => $id]); + Logger::info('Update group members', ['id' => $id]); $contact = Contact::getById($id, ['uid', 'url']); if (empty($contact)) { @@ -659,14 +663,14 @@ class Group return; } - $gid = self::getIdForForum($id); + $gid = self::getIdForGroup($id); if (empty($gid)) { return; } - $group_members = DBA::selectToArray('group_member', ['contact-id'], ['gid' => $gid]); - if (!empty($group_members)) { - $current = array_unique(array_column($group_members, 'contact-id')); + $circle_members = DBA::selectToArray('group_member', ['contact-id'], ['gid' => $gid]); + if (!empty($circle_members)) { + $current = array_unique(array_column($circle_members, 'contact-id')); } else { $current = []; } @@ -682,6 +686,6 @@ class Group } DBA::delete('group_member', ['gid' => $gid, 'contact-id' => $current]); - Logger::info('Updated forum members', ['id' => $id, 'count' => DBA::count('group_member', ['gid' => $gid])]); + Logger::info('Updated group members', ['id' => $id, 'count' => DBA::count('group_member', ['gid' => $gid])]); } } diff --git a/src/Model/Contact.php b/src/Model/Contact.php index 134bbc1e5..dcb7ff99c 100644 --- a/src/Model/Contact.php +++ b/src/Model/Contact.php @@ -22,8 +22,10 @@ namespace Friendica\Model; use Friendica\Contact\Avatar; +use Friendica\Contact\Header; use Friendica\Contact\Introduction\Exception\IntroductionNotFoundException; -use Friendica\Content\Conversation As ConversationContent; +use Friendica\Contact\LocalRelationship\Entity\LocalRelationship; +use Friendica\Content\Conversation as ConversationContent; use Friendica\Content\Pager; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -79,7 +81,7 @@ class Contact * TYPE_NEWS - the account is a news reflector * Associated page type: PAGE_SOAPBOX * - * TYPE_COMMUNITY - the account is community forum + * TYPE_COMMUNITY - the account is community group * Associated page types: PAGE_COMMUNITY, PAGE_PRVGROUP * * TYPE_RELAY - the account is a relay @@ -111,12 +113,16 @@ class Contact * @} */ - const MIRROR_DEACTIVATED = 0; - const MIRROR_FORWARDED = 1; // Deprecated, now does the same like MIRROR_OWN_POST - const MIRROR_OWN_POST = 2; - const MIRROR_NATIVE_RESHARE = 3; + /** @deprecated Use Entity\LocalRelationship::MIRROR_DEACTIVATED instead */ + const MIRROR_DEACTIVATED = LocalRelationship::MIRROR_DEACTIVATED; + /** @deprecated Now does the same as MIRROR_OWN_POST */ + const MIRROR_FORWARDED = 1; + /** @deprecated Use Entity\LocalRelationship::MIRROR_OWN_POST instead */ + const MIRROR_OWN_POST = LocalRelationship::MIRROR_OWN_POST; + /** @deprecated Use Entity\LocalRelationship::MIRROR_NATIVE_RESHARE instead */ + const MIRROR_NATIVE_RESHARE = LocalRelationship::MIRROR_NATIVE_RESHARE; - /** + /** * @param array $fields Array of selected fields, empty for all * @param array $condition Array of fields for condition * @param array $params Array of several parameters @@ -216,6 +222,11 @@ class Contact Contact\User::insertForContactArray($contact); + if ((empty($contact['baseurl']) || empty($contact['gsid'])) && Probe::isProbable($contact['network'])) { + Logger::debug('Update missing baseurl', ['id' => $contact['id'], 'url' => $contact['url'], 'callstack' => System::callstack(4, 0, true)]); + UpdateContact::add(['priority' => Worker::PRIORITY_MEDIUM, 'dont_fork' => true], $contact['id']); + } + return $contact['id']; } @@ -725,8 +736,11 @@ class Contact */ public static function createSelfFromUserId(int $uid): bool { - $user = DBA::selectFirst('user', ['uid', 'username', 'nickname', 'pubkey', 'prvkey'], - ['uid' => $uid, 'account_expired' => false]); + $user = DBA::selectFirst( + 'user', + ['uid', 'username', 'nickname', 'pubkey', 'prvkey'], + ['uid' => $uid, 'account_expired' => false] + ); if (!DBA::isResult($user)) { return false; } @@ -779,29 +793,33 @@ class Contact /** * Updates the self-contact for the provided user id * - * @param int $uid - * @param bool $update_avatar Force the avatar update + * @param int $uid + * @param bool $update_avatar Force the avatar update * @return bool "true" if updated - * @throws HTTPException\InternalServerErrorException + * @throws \Exception */ public static function updateSelfFromUserID(int $uid, bool $update_avatar = false): bool { - $fields = ['id', 'uri-id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', 'manually-approve', + $fields = [ + 'id', 'uri-id', 'name', 'nick', 'location', 'about', 'keywords', 'avatar', 'prvkey', 'pubkey', 'manually-approve', 'xmpp', 'matrix', 'contact-type', 'forum', 'prv', 'avatar-date', 'url', 'nurl', 'unsearchable', - 'photo', 'thumb', 'micro', 'header', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network']; + 'photo', 'thumb', 'micro', 'header', 'addr', 'request', 'notify', 'poll', 'confirm', 'poco', 'network' + ]; $self = DBA::selectFirst('contact', $fields, ['uid' => $uid, 'self' => true]); if (!DBA::isResult($self)) { return false; } - $fields = ['uid', 'nickname', 'page-flags', 'account-type', 'prvkey', 'pubkey']; + $fields = ['uid', 'username', 'nickname', 'page-flags', 'account-type', 'prvkey', 'pubkey']; $user = DBA::selectFirst('user', $fields, ['uid' => $uid, 'account_expired' => false]); if (!DBA::isResult($user)) { return false; } - $fields = ['name', 'photo', 'thumb', 'about', 'address', 'locality', 'region', - 'country-name', 'pub_keywords', 'xmpp', 'matrix', 'net-publish']; + $fields = [ + 'name', 'photo', 'thumb', 'about', 'address', 'locality', 'region', + 'country-name', 'pub_keywords', 'xmpp', 'matrix', 'net-publish' + ]; $profile = DBA::selectFirst('profile', $fields, ['uid' => $uid]); if (!DBA::isResult($profile)) { return false; @@ -811,7 +829,7 @@ class Contact $url = DI::baseUrl() . '/profile/' . $user['nickname']; $fields = [ - 'name' => $profile['name'], + 'name' => $user['username'], 'nick' => $user['nickname'], 'avatar-date' => $self['avatar-date'], 'location' => Profile::formatLocation($profile), @@ -830,11 +848,10 @@ class Contact 'addr' => $user['nickname'] . '@' . substr(DI::baseUrl(), strpos(DI::baseUrl(), '://') + 3), 'request' => DI::baseUrl() . '/dfrn_request/' . $user['nickname'], 'notify' => DI::baseUrl() . '/dfrn_notify/' . $user['nickname'], - 'poll' => DI::baseUrl() . '/dfrn_poll/'. $user['nickname'], + 'poll' => DI::baseUrl() . '/dfrn_poll/' . $user['nickname'], 'confirm' => DI::baseUrl() . '/dfrn_confirm/' . $user['nickname'], ]; - $avatar = Photo::selectFirst(['resource-id', 'type'], ['uid' => $uid, 'profile' => true]); if (DBA::isResult($avatar)) { if ($update_avatar) { @@ -850,7 +867,7 @@ class Contact // We are adding a timestamp value so that other systems won't use cached content $timestamp = strtotime($fields['avatar-date']); - $prefix = DI::baseUrl() . '/photo/' .$avatar['resource-id'] . '-'; + $prefix = DI::baseUrl() . '/photo/' . $avatar['resource-id'] . '-'; $suffix = '.' . $file_suffix . '?ts=' . $timestamp; $fields['photo'] = $prefix . '4' . $suffix; @@ -1188,22 +1205,22 @@ class Contact */ if (empty($contact['uid'])) { $menu = [ - 'profile' => [DI::l10n()->t('View Profile') , $profile_link , true ], - 'network' => [DI::l10n()->t('Network Posts') , $posts_link , false], - 'edit' => [DI::l10n()->t('View Contact') , $contact_url , false], - 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true ], - 'unfollow' => [DI::l10n()->t('Unfollow') , $unfollow_link, true ], + 'profile' => [DI::l10n()->t('View Profile'), $profile_link, true], + 'network' => [DI::l10n()->t('Network Posts'), $posts_link, false], + 'edit' => [DI::l10n()->t('View Contact'), $contact_url, false], + 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link, true], + 'unfollow' => [DI::l10n()->t('Unfollow'), $unfollow_link, true], ]; } else { $menu = [ - 'status' => [DI::l10n()->t('View Status') , $status_link , true ], - 'profile' => [DI::l10n()->t('View Profile') , $profile_link , true ], - 'photos' => [DI::l10n()->t('View Photos') , $photos_link , true ], - 'network' => [DI::l10n()->t('Network Posts') , $posts_link , false], - 'edit' => [DI::l10n()->t('View Contact') , $contact_url , false], - 'pm' => [DI::l10n()->t('Send PM') , $pm_url , false], - 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link , true ], - 'unfollow' => [DI::l10n()->t('Unfollow') , $unfollow_link, true ], + 'status' => [DI::l10n()->t('View Status'), $status_link, true], + 'profile' => [DI::l10n()->t('View Profile'), $profile_link, true], + 'photos' => [DI::l10n()->t('View Photos'), $photos_link, true], + 'network' => [DI::l10n()->t('Network Posts'), $posts_link, false], + 'edit' => [DI::l10n()->t('View Contact'), $contact_url, false], + 'pm' => [DI::l10n()->t('Send PM'), $pm_url, false], + 'follow' => [DI::l10n()->t('Connect/Follow'), $follow_link, true], + 'unfollow' => [DI::l10n()->t('Unfollow'), $unfollow_link, true], ]; if (!empty($contact['pending'])) { @@ -1310,9 +1327,11 @@ class Contact if (($uid == 0) && (empty($data['network']) || ($data['network'] == Protocol::PHANTOM))) { // Fetch data for the public contact via the first found personal contact /// @todo Check if this case can happen at all (possibly with mail accounts?) - $fields = ['name', 'nick', 'url', 'addr', 'alias', 'avatar', 'header', 'contact-type', + $fields = [ + 'name', 'nick', 'url', 'addr', 'alias', 'avatar', 'header', 'contact-type', 'keywords', 'location', 'about', 'unsearchable', 'batch', 'notify', 'poll', - 'request', 'confirm', 'poco', 'subscribe', 'network', 'baseurl', 'gsid']; + 'request', 'confirm', 'poco', 'subscribe', 'network', 'baseurl', 'gsid' + ]; $personal_contact = DBA::selectFirst('contact', $fields, ["`addr` = ? AND `uid` != 0", $url]); if (!DBA::isResult($personal_contact)) { @@ -1358,6 +1377,7 @@ class Contact $fields = [ 'uid' => $uid, 'url' => $data['url'], + 'baseurl' => $data['baseurl'] ?? '', 'nurl' => Strings::normaliseLink($data['url']), 'network' => $data['network'], 'created' => DateTimeFormat::utcNow(), @@ -1458,7 +1478,7 @@ class Contact if (!empty($contact['batch'])) { $condition = ['archive' => true, 'uid' => 0, 'network' => Protocol::FEDERATED, 'batch' => $contact['batch'], 'contact-type' => self::TYPE_RELAY]; return DBA::exists('contact', $condition); - } + } return false; } @@ -1551,11 +1571,15 @@ class Contact $contact_field = ((($contact["contact-type"] == self::TYPE_COMMUNITY) || ($contact['network'] == Protocol::MAIL)) ? 'owner-id' : 'author-id'); if ($thread_mode) { - $condition = ["((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `protocol` != ? AND `thr-parent-id` = `parent-uri-id`)) AND " . $sql, - $cid, Item::GRAVITY_PARENT, $cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA, DI::userSession()->getLocalUserId()]; + $condition = [ + "((`$contact_field` = ? AND `gravity` = ?) OR (`author-id` = ? AND `gravity` = ? AND `vid` = ? AND `protocol` != ? AND `thr-parent-id` = `parent-uri-id`)) AND " . $sql, + $cid, Item::GRAVITY_PARENT, $cid, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), Conversation::PARCEL_DIASPORA, DI::userSession()->getLocalUserId() + ]; } else { - $condition = ["`$contact_field` = ? AND `gravity` IN (?, ?) AND " . $sql, - $cid, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, DI::userSession()->getLocalUserId()]; + $condition = [ + "`$contact_field` = ? AND `gravity` IN (?, ?) AND " . $sql, + $cid, Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT, DI::userSession()->getLocalUserId() + ]; } if (!empty($parent)) { @@ -1568,16 +1592,26 @@ class Contact } if ($only_media) { - $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", - Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); + $condition = DBA::mergeConditions($condition, [ + "`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", + Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO + ]); } if (DI::mode()->isMobile()) { - $itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network', - DI::config()->get('system', 'itemspage_network_mobile')); + $itemsPerPage = DI::pConfig()->get( + DI::userSession()->getLocalUserId(), + 'system', + 'itemspage_mobile_network', + DI::config()->get('system', 'itemspage_network_mobile') + ); } else { - $itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_network', - DI::config()->get('system', 'itemspage_network')); + $itemsPerPage = DI::pConfig()->get( + DI::userSession()->getLocalUserId(), + 'system', + 'itemspage_network', + DI::config()->get('system', 'itemspage_network') + ); } $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), $itemsPerPage); @@ -1603,7 +1637,7 @@ class Contact } } - $o .= DI::conversation()->create($items, ConversationContent::MODE_CONTACTS, $update, false, 'pinned_commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->render($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)); @@ -1611,14 +1645,16 @@ class Contact if ($pager->getStart() == 0) { $cdata = self::getPublicAndUserContactID($cid, DI::userSession()->getLocalUserId()); if (!empty($cdata['public'])) { - $condition = ["`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)", - $cdata['public'], Post\Collection::FEATURED]; + $condition = [ + "`uri-id` IN (SELECT `uri-id` FROM `collection-view` WHERE `cid` = ? AND `type` = ?)", + $cdata['public'], Post\Collection::FEATURED + ]; $pinned = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params)); $items = array_merge($pinned, $items); } } - $o .= DI::conversation()->create($items, ConversationContent::MODE_CONTACT_POSTS, $update); + $o .= DI::conversation()->render($items, ConversationContent::MODE_CONTACT_POSTS, $update); } if (!$update) { @@ -1652,7 +1688,7 @@ class Contact break; case self::TYPE_COMMUNITY: - $account_type = DI::l10n()->t("Forum"); + $account_type = DI::l10n()->t("Group"); break; default: @@ -1719,7 +1755,7 @@ class Contact } elseif (DI::config()->get('system', 'avatar_cache') && (empty($contact['photo']) || empty($contact['thumb']) || empty($contact['micro']))) { Logger::info('Adding avatar cache file', ['id' => $cid, 'contact' => $contact]); self::updateAvatar($cid, $contact['avatar'], true); - return; + return; } } @@ -1870,13 +1906,7 @@ class Contact switch ($platform) { case 'friendica': case 'friendika': - /** - * Picture credits - * @author Lostinlight - * @license CC0 https://creativecommons.org/share-your-work/public-domain/cc0/ - * @link https://gitlab.com/lostinlight/per_aspera_ad_astra/-/blob/master/friendica-404/friendica-promo-bubbles.jpg - */ - $header = DI::baseUrl() . '/images/friendica-banner.jpg'; + $header = DI::baseUrl() . (new Header(DI::config()))->getMastodonBannerPath(); break; case 'diaspora': /** @@ -2121,8 +2151,10 @@ class Contact */ public static function getAvatarUrlForUrl(string $url, int $uid, string $size = ''): string { - $condition = ["`nurl` = ? AND ((`uid` = ? AND `network` IN (?, ?)) OR `uid` = ?)", - Strings::normaliseLink($url), $uid, Protocol::FEED, Protocol::MAIL, 0]; + $condition = [ + "`nurl` = ? AND ((`uid` = ? AND `network` IN (?, ?)) OR `uid` = ?)", + Strings::normaliseLink($url), $uid, Protocol::FEED, Protocol::MAIL, 0 + ]; $contact = self::selectFirst(['id', 'updated'], $condition, ['order' => ['uid' => true]]); return self::getAvatarUrlForId($contact['id'] ?? 0, $size, $contact['updated'] ?? ''); } @@ -2193,8 +2225,11 @@ class Contact */ public static function updateAvatar(int $cid, string $avatar, bool $force = false, bool $create_cache = false) { - $contact = DBA::selectFirst('contact', ['uid', 'avatar', 'photo', 'thumb', 'micro', 'blurhash', 'xmpp', 'addr', 'nurl', 'url', 'network', 'uri-id'], - ['id' => $cid, 'self' => false]); + $contact = DBA::selectFirst( + 'contact', + ['uid', 'avatar', 'photo', 'thumb', 'micro', 'blurhash', 'xmpp', 'addr', 'nurl', 'url', 'network', 'uri-id'], + ['id' => $cid, 'self' => false] + ); if (!DBA::isResult($contact)) { return; } @@ -2268,10 +2303,12 @@ class Contact } if ($default_avatar && Proxy::isLocalImage($avatar)) { - $fields = ['avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(), + $fields = [ + 'avatar' => $avatar, 'avatar-date' => DateTimeFormat::utcNow(), 'photo' => $avatar, 'thumb' => self::getDefaultAvatar($contact, Proxy::SIZE_THUMB), - 'micro' => self::getDefaultAvatar($contact, Proxy::SIZE_MICRO)]; + 'micro' => self::getDefaultAvatar($contact, Proxy::SIZE_MICRO) + ]; Logger::debug('Use default avatar', ['id' => $cid, 'uid' => $uid]); } @@ -2330,8 +2367,11 @@ class Contact $uids = []; if (($uid == 0) && !in_array($contact['network'], [Protocol::FEED, Protocol::MAIL])) { // Collect all user contacts of the given public contact - $personal_contacts = DBA::select('contact', ['id', 'uid'], - ["`nurl` = ? AND `id` != ? AND NOT `self`", $contact['nurl'], $cid]); + $personal_contacts = DBA::select( + 'contact', + ['id', 'uid'], + ["`nurl` = ? AND `id` != ? AND NOT `self`", $contact['nurl'], $cid] + ); while ($personal_contact = DBA::fetch($personal_contacts)) { $cids[] = $personal_contact['id']; $uids[] = $personal_contact['uid']; @@ -2560,7 +2600,7 @@ class Contact * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function updateFromProbe(int $id, string $network = '') + public static function updateFromProbe(int $id, string $network = ''): bool { $contact = DBA::selectFirst('contact', ['uid', 'url'], ['id' => $id]); if (!DBA::isResult($contact)) { @@ -2650,10 +2690,12 @@ class Contact // These fields aren't updated by this routine: // 'sensitive' - $fields = ['uid', 'uri-id', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe', + $fields = [ + 'uid', 'uri-id', 'avatar', 'header', 'name', 'nick', 'location', 'keywords', 'about', 'subscribe', 'manually-approve', 'unsearchable', 'url', 'addr', 'batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'network', 'alias', 'baseurl', 'gsid', 'forum', 'prv', 'contact-type', 'pubkey', 'last-item', 'xmpp', 'matrix', - 'created', 'last-update']; + 'created', 'last-update' + ]; $contact = DBA::selectFirst('contact', $fields, ['id' => $id]); if (!DBA::isResult($contact)) { return false; @@ -2677,7 +2719,7 @@ class Contact return true; } - $has_local_data = self::hasLocalData($id, $contact); + $has_local_data = self::hasLocalData($id, $contact); $uid = $contact['uid']; unset($contact['uid']); @@ -2724,7 +2766,8 @@ class Contact // We must not try to update relay contacts via probe. They are no real contacts. // We check after the probing to be able to correct falsely detected contact types. if (($contact['contact-type'] == self::TYPE_RELAY) && - (!Strings::compareLink($ret['url'], $contact['url']) || in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM]))) { + (!Strings::compareLink($ret['url'], $contact['url']) || in_array($ret['network'], [Protocol::FEED, Protocol::PHANTOM])) + ) { self::updateContact($id, $uid, $uriid, $contact['url'], ['failed' => false, 'local-data' => $has_local_data, 'last-update' => $updated, 'next-update' => $success_next_update, 'success_update' => $updated]); Logger::info('Not updating relais', ['id' => $id, 'url' => $contact['url']]); return true; @@ -2773,7 +2816,7 @@ class Contact } $update = false; - $guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url']); + $guid = ($ret['guid'] ?? '') ?: Item::guidFromUri($ret['url'], $ret['baseurl'] ?? $ret['alias'] ?? ''); // make sure to not overwrite existing values with blank entries except some technical fields $keep = ['batch', 'notify', 'poll', 'request', 'confirm', 'poco', 'baseurl']; @@ -2962,7 +3005,7 @@ class Contact return $result; } - $arr = ['url' => $url, 'contact' => []]; + $arr = ['url' => $url, 'uid' => $uid, 'contact' => []]; Hook::callAll('follow', $arr); @@ -3060,31 +3103,32 @@ class Contact // create contact record self::insert([ - 'uid' => $uid, - 'created' => DateTimeFormat::utcNow(), - 'url' => $ret['url'], - 'nurl' => Strings::normaliseLink($ret['url']), - 'addr' => $ret['addr'], - 'alias' => $ret['alias'], - 'batch' => $ret['batch'], - 'notify' => $ret['notify'], - 'poll' => $ret['poll'], - 'poco' => $ret['poco'], - 'name' => $ret['name'], - 'nick' => $ret['nick'], - 'network' => $ret['network'], - 'baseurl' => $ret['baseurl'], - 'gsid' => $ret['gsid'] ?? null, - 'protocol' => $protocol, - 'pubkey' => $ret['pubkey'], - 'rel' => $new_relation, - 'priority'=> $ret['priority'], - 'writable'=> $writeable, - 'hidden' => $hidden, - 'blocked' => 0, - 'readonly'=> 0, - 'pending' => $pending, - 'subhub' => $subhub + 'uid' => $uid, + 'created' => DateTimeFormat::utcNow(), + 'url' => $ret['url'], + 'nurl' => Strings::normaliseLink($ret['url']), + 'addr' => $ret['addr'], + 'alias' => $ret['alias'], + 'batch' => $ret['batch'], + 'notify' => $ret['notify'], + 'poll' => $ret['poll'], + 'poco' => $ret['poco'], + 'name' => $ret['name'], + 'nick' => $ret['nick'], + 'network' => $ret['network'], + 'baseurl' => $ret['baseurl'], + 'gsid' => $ret['gsid'] ?? null, + 'contact-type' => $ret['account-type'] ?? self::TYPE_PERSON, + 'protocol' => $protocol, + 'pubkey' => $ret['pubkey'], + 'rel' => $new_relation, + 'priority' => $ret['priority'], + 'writable' => $writeable, + 'hidden' => $hidden, + 'blocked' => 0, + 'readonly' => 0, + 'pending' => $pending, + 'subhub' => $subhub ]); } @@ -3097,7 +3141,11 @@ class Contact $contact_id = $contact['id']; $result['cid'] = $contact_id; - Group::addMember(User::getDefaultGroup($uid), $contact_id); + if ($contact['contact-type'] == self::TYPE_COMMUNITY) { + Circle::addMember(User::getDefaultGroupCircle($uid), $contact_id); + } else { + Circle::addMember(User::getDefaultCircle($uid), $contact_id); + } // Update the avatar self::updateAvatar($contact_id, $ret['photo']); @@ -3139,7 +3187,7 @@ class Contact return false; } - $fields = ['id', 'url', 'name', 'nick', 'avatar', 'photo', 'network', 'blocked']; + $fields = ['id', 'url', 'name', 'nick', 'avatar', 'photo', 'network', 'blocked', 'baseurl']; $pub_contact = DBA::selectFirst('contact', $fields, ['id' => $datarray['author-id']]); if (!DBA::isResult($pub_contact)) { // Should never happen @@ -3172,8 +3220,10 @@ class Contact } // Contact is blocked at user-level - if (!empty($contact['id']) && !empty($importer['id']) && - Contact\User::isBlocked($contact['id'], $importer['id'])) { + if ( + !empty($contact['id']) && !empty($importer['id']) && + Contact\User::isBlocked($contact['id'], $importer['id']) + ) { return false; } @@ -3181,9 +3231,12 @@ class Contact self::unmarkForArchival($contact); if (($contact['rel'] == self::SHARING) - || ($sharing && $contact['rel'] == self::FOLLOWER)) { - self::update(['rel' => self::FRIEND, 'writable' => true, 'pending' => false], - ['id' => $contact['id'], 'uid' => $importer['uid']]); + || ($sharing && $contact['rel'] == self::FOLLOWER) + ) { + self::update( + ['rel' => self::FRIEND, 'writable' => true, 'pending' => false], + ['id' => $contact['id'], 'uid' => $importer['uid']] + ); } // Ensure to always have the correct network type, independent from the connection request method @@ -3205,6 +3258,7 @@ class Contact 'created' => DateTimeFormat::utcNow(), 'url' => $url, 'nurl' => Strings::normaliseLink($url), + 'baseurl' => $pub_contact['baseurl'] ?? '', 'name' => $name, 'nick' => $nick, 'network' => $network, @@ -3222,7 +3276,7 @@ class Contact Post\UserNotification::insertNotification($pub_contact['id'], Activity::FOLLOW, $importer['uid']); - $contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo'], ['id' => $contact_id]); + $contact_record = DBA::selectFirst('contact', ['id', 'network', 'name', 'url', 'photo', 'contact-type'], ['id' => $contact_id]); /// @TODO Encapsulate this into a function/method $fields = ['uid', 'username', 'email', 'page-flags', 'notify-flags', 'language']; @@ -3238,7 +3292,11 @@ class Contact DI::intro()->save($intro); } - Group::addMember(User::getDefaultGroup($importer['uid']), $contact_record['id']); + if ($contact_record['contact-type'] == self::TYPE_COMMUNITY) { + Circle::addMember(User::getDefaultGroupCircle($importer['uid']), $contact_record['id']); + } else { + Circle::addMember(User::getDefaultCircle($importer['uid']), $contact_record['id']); + } if (($user['notify-flags'] & Notification\Type::INTRO) && $user['page-flags'] == User::PAGE_FLAGS_NORMAL) { DI::notify()->createFromArray([ @@ -3422,7 +3480,7 @@ class Contact */ public static function magicLinkById(int $cid, string $url = ''): string { - $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], ['id' => $cid]); + $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'alias', 'uid'], ['id' => $cid]); return self::magicLinkByContact($contact, $url); } @@ -3439,7 +3497,7 @@ class Contact */ public static function magicLinkByContact(array $contact, string $url = ''): string { - $destination = $url ?: $contact['url']; + $destination = $url ?: (!Network::isValidHttpUrl($contact['url']) && !empty($contact['alias']) && Network::isValidHttpUrl($contact['alias']) ? $contact['alias'] : $contact['url']); if (!DI::userSession()->isAuthenticated()) { return $destination; @@ -3472,13 +3530,13 @@ class Contact } /** - * Is the contact a forum? + * Is the contact a group? * * @param integer $contactid ID of the contact * - * @return boolean "true" if it is a forum + * @return boolean "true" if it is a group */ - public static function isForum(int $contactid): bool + public static function isGroup(int $contactid): bool { $fields = ['contact-type']; $condition = ['id' => $contactid]; @@ -3487,7 +3545,7 @@ class Contact return false; } - // Is it a forum? + // Is it a group? return ($contact['contact-type'] == self::TYPE_COMMUNITY); } @@ -3568,8 +3626,10 @@ class Contact $params['limit'] = $limit; } - $condition = DBA::mergeConditions($condition, - ["(`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $search, $search, $search]); + $condition = DBA::mergeConditions( + $condition, + ["(`addr` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", $search, $search, $search] + ); return DBA::selectToArray('account-user-view', [], $condition, $params); } @@ -3619,7 +3679,7 @@ class Contact */ public static function getRandomContact(): array { - $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'uid'], [ + $contact = DBA::selectFirst('contact', ['id', 'network', 'url', 'alias', 'uid'], [ "`uid` = ? AND `network` = ? AND NOT `failed` AND `last-item` > ?", 0, Protocol::DFRN, DateTimeFormat::utc('now - 1 month'), ], ['order' => ['RAND()']]); diff --git a/src/Model/Contact/Group.php b/src/Model/Contact/Circle.php similarity index 56% rename from src/Model/Contact/Group.php rename to src/Model/Contact/Circle.php index 37742f6bb..7cd18acbb 100644 --- a/src/Model/Contact/Group.php +++ b/src/Model/Contact/Circle.php @@ -21,17 +21,18 @@ namespace Friendica\Model\Contact; +use Friendica\Content\Widget; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; /** - * This class provides information about contact groups based on the "group_member" table. + * This class provides information about contact circles based on the "group_member" table. */ -class Group +class Circle { /** - * Returns a list of contacts belonging in a group + * Returns a list of contacts belonging in a circle * * @param int $gid * @return array @@ -42,19 +43,22 @@ class Group $return = []; if (intval($gid)) { - $stmt = DBA::p('SELECT `group_member`.`contact-id`, `contact`.* + $networks = Widget::unavailableNetworks(); + $sql_values = array_merge([$gid, DI::userSession()->getLocalUserId()], $networks); + + $stmt = DBA::p('SELECT `circle_member`.`contact-id`, `contact`.* FROM `contact` - INNER JOIN `group_member` - ON `contact`.`id` = `group_member`.`contact-id` + INNER JOIN `group_member` AS `circle_member` + ON `contact`.`id` = `circle_member`.`contact-id` WHERE `gid` = ? AND `contact`.`uid` = ? AND NOT `contact`.`self` AND NOT `contact`.`deleted` AND NOT `contact`.`blocked` AND NOT `contact`.`pending` + AND NOT `contact`.`network` IN (' . substr(str_repeat('?, ', count($networks)), 0, -2) . ') ORDER BY `contact`.`name` ASC', - $gid, - DI::userSession()->getLocalUserId() + $sql_values ); if (DBA::isResult($stmt)) { @@ -66,24 +70,29 @@ class Group } /** - * Returns ungrouped contact count or list for user + * Returns uncircled contact count or list for user * - * Returns either the total number of ungrouped contacts for the given user - * id or a paginated list of ungrouped contacts. + * Returns either the total number of uncircled contacts for the given user + * id or a paginated list of uncircled contacts. * * @param int $uid uid * @return array * @throws \Exception */ - public static function listUngrouped(int $uid) + public static function listUncircled(int $uid) { - return Contact::selectToArray([], ["`uid` = ? AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `failed` - AND `id` NOT IN (SELECT DISTINCT(`contact-id`) FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` - WHERE `group`.`uid` = ? AND `contact-id` = `contact`.`id`)", $uid, $uid]); + $networks = Widget::unavailableNetworks(); + $query = "`uid` = ? AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `failed` + AND NOT `network` IN (" . substr(str_repeat('?, ', count($networks)), 0, -2) . ") + AND `id` NOT IN (SELECT DISTINCT(`contact-id`) FROM `group_member` AS `circle_member` INNER JOIN `group` AS `circle` ON `circle`.`id` = `circle_member`.`gid` + WHERE `circle`.`uid` = ? AND `contact-id` = `contact`.`id`)"; + $condition = array_merge([$query], [$uid], $networks, [$uid]); + + return Contact::selectToArray([], $condition); } /** - * Remove a contact from all groups + * Remove a contact from all circles * * @param integer $contact_id * diff --git a/src/Model/Contact/Relation.php b/src/Model/Contact/Relation.php index d0be33cca..94b5f63ff 100644 --- a/src/Model/Contact/Relation.php +++ b/src/Model/Contact/Relation.php @@ -31,6 +31,8 @@ use Friendica\Model\APContact; use Friendica\Model\Contact; use Friendica\Model\Profile; use Friendica\Model\User; +use Friendica\Model\Verb; +use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; use Friendica\Util\DateTimeFormat; use Friendica\Util\Strings; @@ -770,4 +772,77 @@ class Relation ['limit' => [$offset, $count], 'order' => [$shuffle ? 'RAND()' : 'name']] ); } + + /** + * Calculate the interaction scores for the given user + * + * @param integer $uid + * @return void + */ + public static function calculateInteractionScore(int $uid) + { + $days = DI::config()->get('system', 'interaction_score_days'); + $contact_id = Contact::getPublicIdByUserId($uid); + + Logger::debug('Calculation - start', ['uid' => $uid, 'cid' => $contact_id, 'days' => $days]); + + $follow = Verb::getID(Activity::FOLLOW); + $view = Verb::getID(Activity::VIEW); + $read = Verb::getID(Activity::READ); + + DBA::update('contact-relation', ['score' => 0, 'relation-score' => 0, 'thread-score' => 0, 'relation-thread-score' => 0], ['cid' => $contact_id]); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['score' => $score], ['cid' => $contact_id, 'relation-cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate thread-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post`.`uri-id` = `post-user`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['thread-score' => $score], ['cid' => $contact_id, 'relation-cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate relation-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`thr-parent-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['relation-score' => $score], ['cid' => $contact_id, 'relation-cid' => $interaction['author-id']]); + } + DBA::close($interactions); + + $total = DBA::fetchFirst("SELECT count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?)", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + + Logger::debug('Calculate relation-thread-score', ['uid' => $uid, 'total' => $total['activity']]); + + $interactions = DBA::p("SELECT `post`.`author-id`, count(*) AS `activity` FROM `post-user` INNER JOIN `post` ON `post-user`.`uri-id` = `post`.`parent-uri-id` WHERE `post-user`.`author-id` = ? AND `post-user`.`received` >= ? AND `post-user`.`uid` = ? AND `post`.`author-id` != ? AND NOT `post`.`vid` IN (?, ?, ?) GROUP BY `post`.`author-id`", + $contact_id, DateTimeFormat::utc('now - ' . $days . ' day'), $uid, $contact_id, $follow, $view, $read); + while ($interaction = DBA::fetch($interactions)) { + $score = min((int)(($interaction['activity'] / $total['activity']) * 65535), 65535); + DBA::update('contact-relation', ['relation-thread-score' => $score], ['cid' => $contact_id, 'relation-cid' => $interaction['author-id']]); + } + DBA::close($interactions); + Logger::debug('Calculation - end', ['uid' => $uid]); + } } diff --git a/src/Model/Contact/User.php b/src/Model/Contact/User.php index a3091f7d8..8c214a5c9 100644 --- a/src/Model/Contact/User.php +++ b/src/Model/Contact/User.php @@ -27,7 +27,6 @@ use Friendica\Core\Protocol; use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Database\DBA; -use Friendica\Database\DBStructure; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\ItemURI; @@ -95,13 +94,14 @@ class User $update_fields = self::preparedFields($fields); if (!empty($update_fields)) { - $contacts = DBA::select('contact', ['uri-id', 'uid'], $condition); + $contacts = DBA::select('account-user-view', ['pid', 'uri-id', 'uid'], $condition); while ($contact = DBA::fetch($contacts)) { if (empty($contact['uri-id']) || empty($contact['uid'])) { continue; } - $ret = DBA::update('user-contact', $update_fields, ['uri-id' => $contact['uri-id'], 'uid' => $contact['uid']]); - Logger::info('Updated user contact', ['uid' => $contact['uid'], 'uri-id' => $contact['uri-id'], 'ret' => $ret]); + $update_fields['cid'] = $contact['pid']; + $ret = DBA::update('user-contact', $update_fields, ['uri-id' => $contact['uri-id'], 'uid' => $contact['uid']], true); + Logger::info('Updated user contact', ['uid' => $contact['uid'], 'id' => $contact['pid'], 'uri-id' => $contact['uri-id'], 'ret' => $ret]); } DBA::close($contacts); diff --git a/src/Model/Event.php b/src/Model/Event.php index dc818d8f1..6f7783220 100644 --- a/src/Model/Event.php +++ b/src/Model/Event.php @@ -344,7 +344,6 @@ class Event $event['id'] = $event_id; $item['uid'] = $event['uid']; - $item['contact-id'] = $event['cid']; $item['uri'] = $event['uri']; $item['uri-id'] = ItemURI::getIdByURI($event['uri']); $item['guid'] = $event['guid']; @@ -363,11 +362,10 @@ class Event $item['allow_gid'] = $event['allow_gid']; $item['deny_cid'] = $event['deny_cid']; $item['deny_gid'] = $event['deny_gid']; - $item['private'] = intval($event['private'] ?? 0); + $item['private'] = $event['allow_cid'] && $event['allow_gid'] && $event['deny_cid'] && $event['deny_gid'] ? 0 : 1; $item['visible'] = 1; $item['verb'] = Activity::POST; $item['object-type'] = Activity\ObjectType::EVENT; - $item['post-type'] = Item::PT_EVENT; $item['origin'] = $event['cid'] === 0 ? 1 : 0; $item['body'] = self::getBBCode($event); $item['event-id'] = $event['id']; @@ -547,13 +545,14 @@ class Event // Query for the event by event id $events = DBA::toArray(DBA::p( "SELECT `event`.*, `post-user`.`id` AS `itemid` FROM `event` - LEFT JOIN `post-user` - ON `post-user`.`event-id` = `event`.`id` + LEFT JOIN `post-user` + ON `post-user`.`event-id` = `event`.`id` AND `post-user`.`uid` = `event`.`uid` WHERE `event`.`id` = ? AND `event`.`uid` = ? $sql_perms", - $event_id, $owner_uid + $event_id, + $owner_uid )); if (empty($events)) { throw new HTTPException\NotFoundException(DI::l10n()->t('Event not found.')); @@ -616,7 +615,8 @@ class Event AND `start` <= ? $sql_perms", $owner_uid, - $start, $start, + $start, + $start, $finish )); @@ -661,9 +661,9 @@ class Event $copy = null; $drop = null; if (DI::userSession()->getLocalUserId() && DI::userSession()->getLocalUserId() == $event['uid'] && $event['type'] == 'event') { - $edit = !$event['cid'] ? ['calendar/event/edit/' . $event['id'], DI::l10n()->t('Edit event') , '', ''] : null; - $copy = !$event['cid'] ? ['calendar/event/copy/' . $event['id'] , DI::l10n()->t('Duplicate event'), '', ''] : null; - $drop = ['calendar/api/delete/' . $event['id'] , DI::l10n()->t('Delete event') , '', '']; + $edit = !$event['cid'] ? ['calendar/event/edit/' . $event['id'], DI::l10n()->t('Edit event'), '', ''] : null; + $copy = !$event['cid'] ? ['calendar/event/copy/' . $event['id'], DI::l10n()->t('Duplicate event'), '', ''] : null; + $drop = ['calendar/api/delete/' . $event['id'], DI::l10n()->t('Delete event'), '', '']; } $title = BBCode::convertForUriId($event['uri-id'], Strings::escapeHtml($event['summary'])); @@ -708,7 +708,7 @@ class Event } switch ($format) { - // Format the exported data as a CSV file. + // Format the exported data as a CSV file. case "csv": $o .= '"Subject", "Start Date", "Start Time", "Description", "End Date", "End Time", "Location"' . PHP_EOL; @@ -728,7 +728,7 @@ class Event } break; - // Format the exported data as a ics file. + // Format the exported data as a ics file. case "ical": $o = 'BEGIN:VCALENDAR' . PHP_EOL . 'VERSION:2.0' . PHP_EOL @@ -929,8 +929,13 @@ class Event $location = self::locationToArray($item['event-location']); // Construct the profile link (magic-auth). - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'] + ]; $profile_link = Contact::magicLinkByContact($author); $tpl = Renderer::getMarkupTemplate('event_stream_item.tpl'); @@ -1005,7 +1010,7 @@ class Event } } - $location['name'] = BBCode::convert($location['name']); + $location['name'] = BBCode::toPlaintext($location['name'], false); // Construct the map HTML. if (isset($location['address'])) { diff --git a/src/Model/Item.php b/src/Model/Item.php index 6da214398..9eddf885c 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -21,6 +21,7 @@ namespace Friendica\Model; +use Friendica\Contact\LocalRelationship\Entity\LocalRelationship; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; use Friendica\Core\Hook; @@ -31,6 +32,7 @@ use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; +use Friendica\Model\Post\Category; use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; @@ -94,9 +96,9 @@ class Item 'wall', 'private', 'starred', 'origin', 'parent-origin', 'title', 'body', 'language', 'content-warning', 'location', 'coord', 'app', 'rendered-hash', 'rendered-html', 'object', 'quote-uri', 'quote-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'mention', 'global', - 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-addr', 'author-uri-id', - 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', - 'causer-id', 'causer-link', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', + 'author-id', 'author-link', 'author-alias', 'author-name', 'author-avatar', 'author-network', 'author-updated', 'author-gsid', 'author-baseurl', 'author-addr', 'author-uri-id', + 'owner-id', 'owner-link', 'owner-alias', 'owner-name', 'owner-avatar', 'owner-network', 'owner-contact-type', 'owner-updated', 'owner-gsid', + 'causer-id', 'causer-link', 'causer-alias', 'causer-name', 'causer-avatar', 'causer-contact-type', 'causer-network', 'causer-gsid', 'contact-id', 'contact-uid', 'contact-link', 'contact-name', 'contact-avatar', 'writable', 'self', 'cid', 'alias', 'event-created', 'event-edited', 'event-start', 'event-finish', @@ -108,31 +110,35 @@ class Item ]; // Field list that is used to deliver items via the protocols - const DELIVER_FIELDLIST = ['uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', - 'parent-guid', 'conversation', 'received', 'created', 'edited', 'verb', 'object-type', 'object', 'target', - 'private', 'title', 'body', 'raw-body', 'location', 'coord', 'app', - 'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity', - 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', - 'author-id', 'author-addr', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid', - 'signed_text', 'network', 'wall', 'contact-id', 'plink', 'origin', - 'thr-parent-id', 'parent-uri-id', 'quote-uri', 'quote-uri-id', 'postopts', 'pubmail', - 'event-created', 'event-edited', 'event-start', 'event-finish', - 'event-summary', 'event-desc', 'event-location', 'event-type', - 'event-nofinish', 'event-ignore', 'event-id']; + const DELIVER_FIELDLIST = [ + 'uid', 'id', 'parent', 'uri-id', 'uri', 'thr-parent', 'parent-uri', 'guid', + 'parent-guid', 'conversation', 'received', 'created', 'edited', 'verb', 'object-type', 'object', 'target', + 'private', 'title', 'body', 'raw-body', 'location', 'coord', 'app', + 'inform', 'deleted', 'extid', 'post-type', 'post-reason', 'gravity', + 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', + 'author-id', 'author-addr', 'author-link', 'author-name', 'author-avatar', 'owner-id', 'owner-link', 'contact-uid', + 'signed_text', 'network', 'wall', 'contact-id', 'plink', 'origin', + 'thr-parent-id', 'parent-uri-id', 'quote-uri', 'quote-uri-id', 'postopts', 'pubmail', + 'event-created', 'event-edited', 'event-start', 'event-finish', + 'event-summary', 'event-desc', 'event-location', 'event-type', + 'event-nofinish', 'event-ignore', 'event-id' + ]; // All fields in the item table - const ITEM_FIELDLIST = ['id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', - 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'conversation', 'vid', - 'quote-uri', 'quote-uri-id', 'contact-id', 'wall', 'gravity', 'extid', 'psid', - 'created', 'edited', 'commented', 'received', 'changed', 'verb', - 'postopts', 'plink', 'resource-id', 'event-id', 'inform', - 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', 'post-reason', - 'private', 'pubmail', 'visible', 'starred', - 'unseen', 'deleted', 'origin', 'mention', 'global', 'network', - 'title', 'content-warning', 'body', 'location', 'coord', 'app', - 'rendered-hash', 'rendered-html', 'object-type', 'object', 'target-type', 'target', - 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', - 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'causer-id']; + const ITEM_FIELDLIST = [ + 'id', 'uid', 'parent', 'uri', 'parent-uri', 'thr-parent', + 'guid', 'uri-id', 'parent-uri-id', 'thr-parent-id', 'conversation', 'vid', + 'quote-uri', 'quote-uri-id', 'contact-id', 'wall', 'gravity', 'extid', 'psid', + 'created', 'edited', 'commented', 'received', 'changed', 'verb', + 'postopts', 'plink', 'resource-id', 'event-id', 'inform', + 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'post-type', 'post-reason', + 'private', 'pubmail', 'visible', 'starred', + 'unseen', 'deleted', 'origin', 'mention', 'global', 'network', + 'title', 'content-warning', 'body', 'location', 'coord', 'app', + 'rendered-hash', 'rendered-html', 'object-type', 'object', 'target-type', 'target', + 'author-id', 'author-link', 'author-name', 'author-avatar', 'author-network', + 'owner-id', 'owner-link', 'owner-name', 'owner-avatar', 'causer-id' + ]; // List of all verbs that don't need additional content data. // Never reorder or remove entries from this list. Just add new ones at the end, if needed. @@ -140,7 +146,8 @@ class Item Activity::LIKE, Activity::DISLIKE, Activity::ATTEND, Activity::ATTENDNO, Activity::ATTENDMAYBE, Activity::FOLLOW, - Activity::ANNOUNCE]; + Activity::ANNOUNCE + ]; // Privacy levels const PUBLIC = 0; @@ -191,8 +198,10 @@ class Item } // We only need to call the line by line update for specific fields - if (empty($fields['body']) && empty($fields['file']) && - empty($fields['attach']) && empty($fields['edited'])) { + if ( + empty($fields['body']) && empty($fields['file']) && + empty($fields['attach']) && empty($fields['edited']) + ) { return $rows; } @@ -319,9 +328,11 @@ class Item { Logger::info('Mark item for deletion by id', ['id' => $item_id, 'callstack' => System::callstack()]); // locate item to be deleted - $fields = ['id', 'uri', 'uri-id', 'uid', 'parent', 'parent-uri-id', 'origin', + $fields = [ + 'id', 'uri', 'uri-id', 'uid', 'parent', 'parent-uri-id', 'origin', 'deleted', 'resource-id', 'event-id', - 'verb', 'object-type', 'object', 'target', 'contact-id', 'psid', 'gravity']; + 'verb', 'object-type', 'object', 'target', 'contact-id', 'psid', 'gravity' + ]; $item = Post::selectFirst($fields, ['id' => $item_id]); if (!DBA::isResult($item)) { Logger::info('Item not found.', ['id' => $item_id]); @@ -359,7 +370,7 @@ class Item // If item has attachments, drop them $attachments = Post\Media::getByURIId($item['uri-id'], [Post\Media::DOCUMENT]); - foreach($attachments as $attachment) { + foreach ($attachments as $attachment) { if (preg_match('|attach/(\d+)|', $attachment['url'], $matches)) { Attach::delete(['id' => $matches[1], 'uid' => $item['uid']]); } @@ -473,7 +484,7 @@ class Item private static function contactId(array $item): int { if ($item['uid'] == 0) { - return $item['author-id']; + return $item['owner-id']; } if ($item['origin']) { @@ -481,6 +492,23 @@ class Item return $owner['id']; } + $contact_id = 0; + $user_contact_id = 0; + foreach (['group-link', 'causer-link', 'owner-link', 'author-link'] as $field) { + if (empty($item[$field])) { + continue; + } + if (!$user_contact_id && Contact::isSharingByURL($item[$field], $item['uid'], true)) { + $user_contact_id = Contact::getIdForURL($item[$field], $item['uid']); + } elseif (!$contact_id) { + $contact_id = Contact::getIdForURL($item[$field]); + } + } + + if ($user_contact_id) { + return $user_contact_id; + } + if (!empty($item['causer-id']) && Contact::isSharing($item['causer-id'], $item['uid'], true)) { $cdata = Contact::getPublicAndUserContactID($item['causer-id'], $item['uid']); if (!empty($cdata['user'])) { @@ -488,24 +516,7 @@ class Item } } - if ($item['gravity'] == self::GRAVITY_PARENT) { - if (Contact::isSharingByURL($item['owner-link'], $item['uid'], true)) { - $contact_id = Contact::getIdForURL($item['owner-link'], $item['uid']); - } else { - $contact_id = Contact::getIdForURL($item['owner-link']); - } - if (!empty($contact_id)) { - return $contact_id; - } - } - - if (Contact::isSharingByURL($item['author-link'], $item['uid'], true)) { - $contact_id = Contact::getIdForURL($item['author-link'], $item['uid']); - } else { - $contact_id = Contact::getIdForURL($item['author-link']); - } - - if (!empty($contact_id)) { + if ($contact_id) { return $contact_id; } @@ -551,8 +562,10 @@ class Item return true; } - $condition = ['uri-id' => $item['uri-id'], 'uid' => $item['uid'], - 'network' => [$item['network'], Protocol::DFRN]]; + $condition = [ + 'uri-id' => $item['uri-id'], 'uid' => $item['uid'], + 'network' => [$item['network'], Protocol::DFRN] + ]; if (Post::exists($condition)) { Logger::notice('duplicated item with the same uri found.', $condition); return true; @@ -567,8 +580,10 @@ class Item } } elseif ($item['network'] == Protocol::OSTATUS) { // Check for an existing post with the same content. There seems to be a problem with OStatus. - $condition = ["`body` = ? AND `network` = ? AND `created` = ? AND `contact-id` = ? AND `uid` = ?", - $item['body'], $item['network'], $item['created'], $item['contact-id'], $item['uid']]; + $condition = [ + "`body` = ? AND `network` = ? AND `created` = ? AND `contact-id` = ? AND `uid` = ?", + $item['body'], $item['network'], $item['created'], $item['contact-id'], $item['uid'] + ]; if (Post::exists($condition)) { Logger::notice('duplicated item with the same body found.', $item); return true; @@ -642,8 +657,10 @@ class Item return false; } - $condition = ['verb' => Activity::FOLLOW, 'uid' => $item['uid'], - 'parent-uri' => $item['parent-uri'], 'author-id' => $item['author-id']]; + $condition = [ + 'verb' => Activity::FOLLOW, 'uid' => $item['uid'], + 'parent-uri' => $item['parent-uri'], 'author-id' => $item['author-id'] + ]; if (Post::exists($condition)) { // It happens that we receive multiple follow requests by the same author - we only store one. Logger::info('Follow: Found existing follow request from author', ['author-id' => $item['author-id'], 'parent-uri' => $item['parent-uri']]); @@ -695,7 +712,8 @@ class Item private static function getDuplicateID(array $item): int { if (empty($item['network']) || in_array($item['network'], Protocol::FEDERATED)) { - $condition = ['`uri-id` = ? AND `uid` = ? AND `network` IN (?, ?, ?, ?)', + $condition = [ + '`uri-id` = ? AND `uid` = ? AND `network` IN (?, ?, ?, ?)', $item['uri-id'], $item['uid'], Protocol::ACTIVITYPUB, @@ -751,10 +769,12 @@ class Item */ private static function getTopLevelParent(array $item): array { - $fields = ['uid', 'uri', 'parent-uri', 'id', 'deleted', + $fields = [ + 'uid', 'uri', 'parent-uri', 'id', 'deleted', 'uri-id', 'parent-uri-id', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', - 'wall', 'private', 'origin', 'author-id']; + 'wall', 'private', 'origin', 'author-id' + ]; $condition = ['uri-id' => [$item['thr-parent-id'], $item['parent-uri-id']], 'uid' => $item['uid']]; $params = ['order' => ['id' => false]]; $parent = Post::selectFirst($fields, $condition, $params); @@ -779,9 +799,11 @@ class Item return $parent; } - $condition = ['uri-id' => $parent['parent-uri-id'], + $condition = [ + 'uri-id' => $parent['parent-uri-id'], 'parent-uri-id' => $parent['parent-uri-id'], - 'uid' => $parent['uid']]; + 'uid' => $parent['uid'] + ]; $params = ['order' => ['id' => false]]; $toplevel_parent = Post::selectFirst($fields, $condition, $params); @@ -946,7 +968,7 @@ class Item // Communities aren't working with the Diaspora protocol if (($uid != 0) && ($item['network'] == Protocol::DIASPORA)) { $user = User::getById($uid, ['account-type']); - if ($user['account-type'] == Contact::TYPE_COMMUNITY) { + if ($user['account-type'] == Contact::TYPE_COMMUNITY) { Logger::info('Community posts are not supported via Diaspora'); return 0; } @@ -966,12 +988,16 @@ class Item $item['gravity'] = self::getGravity($item); - $default = ['url' => $item['author-link'], 'name' => $item['author-name'], - 'photo' => $item['author-avatar'], 'network' => $item['network']]; + $default = [ + 'url' => $item['author-link'], 'name' => $item['author-name'], + 'photo' => $item['author-avatar'], 'network' => $item['network'] + ]; $item['author-id'] = ($item['author-id'] ?? 0) ?: Contact::getIdForURL($item['author-link'], 0, null, $default); - $default = ['url' => $item['owner-link'], 'name' => $item['owner-name'], - 'photo' => $item['owner-avatar'], 'network' => $item['network']]; + $default = [ + 'url' => $item['owner-link'], 'name' => $item['owner-name'], + 'photo' => $item['owner-avatar'], 'network' => $item['network'] + ]; $item['owner-id'] = ($item['owner-id'] ?? 0) ?: Contact::getIdForURL($item['owner-link'], 0, null, $default); $item['post-reason'] = self::getPostReason($item); @@ -982,8 +1008,10 @@ class Item $item['contact-id'] = self::contactId($item); - if (!empty($item['direction']) && in_array($item['direction'], [Conversation::PUSH, Conversation::RELAY]) && - empty($item['origin']) && self::isTooOld($item)) { + if ( + !empty($item['direction']) && in_array($item['direction'], [Conversation::PUSH, Conversation::RELAY]) && + empty($item['origin']) && self::isTooOld($item) + ) { Logger::info('Item is too old', ['item' => $item]); return 0; } @@ -1004,7 +1032,7 @@ class Item $item['deleted'] = $toplevel_parent['deleted']; $item['wall'] = $toplevel_parent['wall']; - // Reshares have to keep their permissions to allow forums to work + // Reshares have to keep their permissions to allow groups to work if (!$defined_permissions && (!$item['origin'] || ($item['verb'] != Activity::ANNOUNCE))) { $item['allow_cid'] = $toplevel_parent['allow_cid']; $item['allow_gid'] = $toplevel_parent['allow_gid']; @@ -1124,7 +1152,8 @@ class Item $item['allow_gid'], $item['deny_cid'], $item['deny_gid'] - ))->id; + ) + )->id; if (!empty($item['extid'])) { $item['external-id'] = ItemURI::getIdByURI($item['extid']); @@ -1307,7 +1336,7 @@ class Item Post::update($fields, ['uri-id' => $posted_item['parent-uri-id'], 'uid' => $posted_item['uid']]); - // In that function we check if this is a forum post. Additionally we delete the item under certain circumstances + // In that function we check if this is a group post. Additionally we delete the item under certain circumstances if (self::tagDeliver($posted_item['uid'], $post_user_id)) { // Get the user information for the logging $user = User::getById($uid); @@ -1356,7 +1385,8 @@ class Item // Don't relay participation messages if (($posted_item['verb'] == Activity::FOLLOW) && - (!$posted_item['origin'] || ($posted_item['author-id'] != Contact::getPublicIdByUserId($uid)))) { + (!$posted_item['origin'] || ($posted_item['author-id'] != Contact::getPublicIdByUserId($uid))) + ) { Logger::info('Participation messages will not be relayed', ['item' => $posted_item['id'], 'uri' => $posted_item['uri'], 'verb' => $posted_item['verb']]); $transmit = false; } @@ -1418,19 +1448,21 @@ class Item } /** - * Change the owner of a parent item if it had been shared by a forum + * Change the owner of a parent item if it had been shared by a group * - * (public) forum posts in the new format consist of the regular post by the author - * followed by an announce message sent from the forum account. - * Changing the owner helps in grouping forum posts. + * (public) group posts in the new format consist of the regular post by the author + * followed by an announce message sent from the group account. + * Changing the owner helps in grouping group posts. * * @param array $item * @return void */ private static function setOwnerforResharedItem(array $item) { - $parent = Post::selectFirst(['id', 'causer-id', 'owner-id', 'author-id', 'author-link', 'origin', 'post-reason'], - ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']]); + $parent = Post::selectFirst( + ['id', 'causer-id', 'owner-id', 'author-id', 'author-link', 'origin', 'post-reason'], + ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']] + ); if (!DBA::isResult($parent)) { Logger::error('Parent not found', ['uri-id' => $item['thr-parent-id'], 'uid' => $item['uid']]); return; @@ -1458,7 +1490,7 @@ class Item } if (Contact::isSharing($parent['owner-id'], $item['uid'])) { - Logger::info('The resharer is no forum: quit', ['resharer' => $item['author-id'], 'owner' => $parent['owner-id'], 'author' => $parent['author-id'], 'uid' => $item['uid']]); + Logger::info('The resharer is no group: quit', ['resharer' => $item['author-id'], 'owner' => $parent['owner-id'], 'author' => $parent['author-id'], 'uid' => $item['uid']]); return; } } @@ -1478,10 +1510,13 @@ class Item return; } - $uids = Tag::getUIDListByURIId($item['uri-id']); - foreach ($uids as $uid) { + foreach (Tag::getUIDListByURIId($item['uri-id']) as $uid => $tags) { $stored = self::storeForUserByUriId($item['uri-id'], $uid, ['post-reason' => self::PR_TAG]); Logger::info('Stored item for users', ['uri-id' => $item['uri-id'], 'uid' => $uid, 'stored' => $stored]); + foreach ($tags as $tag) { + $stored = Category::storeFileByURIId($item['uri-id'], $uid, Category::SUBCRIPTION, $tag); + Logger::debug('Stored tag subscription for user', ['uri-id' => $item['uri-id'], 'uid' => $uid, $tag, 'stored' => $stored]); + } } } @@ -1502,9 +1537,11 @@ class Item } // Only distribute public items from native networks - $condition = ['id' => $itemid, 'uid' => 0, - 'network' => array_merge(Protocol::FEDERATED ,['']), - 'visible' => true, 'deleted' => false, 'private' => [self::PUBLIC, self::UNLISTED]]; + $condition = [ + 'id' => $itemid, 'uid' => 0, + 'network' => array_merge(Protocol::FEDERATED, ['']), + 'visible' => true, 'deleted' => false, 'private' => [self::PUBLIC, self::UNLISTED] + ]; $item = Post::selectFirst(array_merge(self::ITEM_FIELDLIST, ['protocol']), $condition); if (!DBA::isResult($item)) { Logger::warning('Item not found', ['condition' => $condition]); @@ -1603,7 +1640,7 @@ class Item if (($uid != 0) && ($item['gravity'] == self::GRAVITY_PARENT)) { $owner = User::getOwnerDataById($uid); if (($owner['contact-type'] == User::ACCOUNT_TYPE_COMMUNITY) && !Tag::isMentioned($uri_id, $owner['url'])) { - Logger::info('Target user is a forum but is not mentioned here, thread will not be stored', ['uid' => $uid, 'uri-id' => $uri_id]); + Logger::info('Target user is a group but is not mentioned here, thread will not be stored', ['uid' => $uid, 'uri-id' => $uri_id]); return 0; } } @@ -1625,7 +1662,8 @@ class Item if (($uid != 0) && (($item['gravity'] == self::GRAVITY_PARENT) || $is_reshare) && DI::pConfig()->get($uid, 'system', 'accept_only_sharer') == self::COMPLETION_NONE && - !in_array($item['post-reason'], [self::PR_FOLLOWER, self::PR_TAG, self::PR_TO, self::PR_CC, self::PR_ACTIVITY, self::PR_AUDIENCE])) { + !in_array($item['post-reason'], [self::PR_FOLLOWER, self::PR_TAG, self::PR_TO, self::PR_CC, self::PR_ACTIVITY, self::PR_AUDIENCE]) + ) { Logger::info('Contact is not a follower, thread will not be stored', ['author' => $item['author-link'], 'uid' => $uid, 'uri-id' => $uri_id, 'post-reason' => $item['post-reason']]); return 0; } @@ -1709,7 +1747,7 @@ class Item return 0; } - // When the post belongs to a a forum then all forum users are allowed to access it + // When the post belongs to a a group then all group users are allowed to access it foreach (Tag::getByURIId($uriid, [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $tag) { if (DBA::exists('contact', ['uid' => $uid, 'nurl' => Strings::normaliseLink($tag['url']), 'contact-type' => Contact::TYPE_COMMUNITY])) { $target_uid = User::getIdForURL($tag['url']); @@ -1821,7 +1859,7 @@ class Item } // is it an entry from a connector? Only add an entry for natively connected networks - if (!in_array($item["network"], array_merge(Protocol::FEDERATED ,['']))) { + if (!in_array($item["network"], array_merge(Protocol::FEDERATED, ['']))) { return; } @@ -2044,13 +2082,17 @@ class Item // Remove the scheme to make sure that "https" and "http" doesn't make a difference unset($parsed['scheme']); - $hostPart = $host ?? $parsed['host'] ?? ''; + $hostPart = $host ?: $parsed['host'] ?? ''; if (!$hostPart) { Logger::warning('Empty host GUID part', ['uri' => $uri, 'host' => $host, 'parsed' => $parsed, 'callstack' => System::callstack(10)]); } // Glue it together to be able to make a hash from it - $host_id = implode('/', $parsed); + if (!empty($parsed)) { + $host_id = implode('/', $parsed); + } else { + $host_id = $uri; + } // Use a mixture of several hashes to provide some GUID like experience return hash('crc32', $hostPart) . '-' . hash('joaat', $host_id) . '-' . hash('fnv164', $host_id); @@ -2100,7 +2142,7 @@ class Item /// @todo On private posts we could obfuscate the date $update = ($arr['private'] != self::PRIVATE) || in_array($arr['network'], Protocol::FEDERATED); - // Is it a forum? Then we don't care about the rules from above + // Is it a group? Then we don't care about the rules from above if (!$update && in_array($arr["network"], [Protocol::ACTIVITYPUB, Protocol::DFRN]) && ($arr["parent-uri-id"] === $arr["uri-id"])) { if (DBA::exists('contact', ['id' => $arr['contact-id'], 'forum' => true])) { $update = true; @@ -2120,12 +2162,16 @@ class Item } // Now do the same for the system wide contacts with uid=0 if ($arr['private'] != self::PRIVATE) { - Contact::update(['failed' => false, 'local-data' => true, 'success_update' => $arr['received'], 'last-item' => $arr['received']], - ['id' => $arr['owner-id']]); + Contact::update( + ['failed' => false, 'local-data' => true, 'success_update' => $arr['received'], 'last-item' => $arr['received']], + ['id' => $arr['owner-id']] + ); if ($arr['owner-id'] != $arr['author-id']) { - Contact::update(['failed' => false, 'local-data' => true, 'success_update' => $arr['received'], 'last-item' => $arr['received']], - ['id' => $arr['author-id']]); + Contact::update( + ['failed' => false, 'local-data' => true, 'success_update' => $arr['received'], 'last-item' => $arr['received']], + ['id' => $arr['author-id']] + ); } } } @@ -2151,29 +2197,44 @@ class Item // All hashtags should point to the home server if "local_tags" is activated if (DI::config()->get('system', 'local_tags')) { - $body = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - "#[url=" . DI::baseUrl() . "/search?tag=$2]$2[/url]", $body); + $body = preg_replace( + "/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", + "#[url=" . DI::baseUrl() . "/search?tag=$2]$2[/url]", + $body + ); } // mask hashtags inside of url, bookmarks and attachments to avoid urls in urls - $body = preg_replace_callback("/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", + $body = preg_replace_callback( + "/\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", function ($match) { return ("[url=" . str_replace("#", "#", $match[1]) . "]" . str_replace("#", "#", $match[2]) . "[/url]"); - }, $body); + }, + $body + ); - $body = preg_replace_callback("/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", + $body = preg_replace_callback( + "/\[bookmark\=([$URLSearchString]*)\](.*?)\[\/bookmark\]/ism", function ($match) { return ("[bookmark=" . str_replace("#", "#", $match[1]) . "]" . str_replace("#", "#", $match[2]) . "[/bookmark]"); - }, $body); + }, + $body + ); - $body = preg_replace_callback("/\[attachment (.*?)\](.*?)\[\/attachment\]/ism", + $body = preg_replace_callback( + "/\[attachment (.*?)\](.*?)\[\/attachment\]/ism", function ($match) { return ("[attachment " . str_replace("#", "#", $match[1]) . "]" . $match[2] . "[/attachment]"); - }, $body); + }, + $body + ); // Repair recursive urls - $body = preg_replace("/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", - "#$2", $body); + $body = preg_replace( + "/#\[url\=([$URLSearchString]*)\](.*?)\[\/url\]/ism", + "#$2", + $body + ); foreach ($tags as $tag) { if ((strpos($tag, '#') !== 0) || strpos($tag, '[url=') || strlen($tag) < 2 || $tag[1] == '#') { @@ -2196,7 +2257,7 @@ class Item } /** - * look for mention tags and setup a second delivery chain for forum/community posts if appropriate + * look for mention tags and setup a second delivery chain for group/community posts if appropriate * * @param int $uid * @param int $item_id @@ -2206,8 +2267,6 @@ class Item */ private static function tagDeliver(int $uid, int $item_id): bool { - $mention = false; - $owner = User::getOwnerDataById($uid); if (!DBA::isResult($owner)) { Logger::warning('User not found, quitting here.', ['uid' => $uid]); @@ -2250,7 +2309,7 @@ class Item if ($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) { $allow_cid = ''; - $allow_gid = '<' . Group::FOLLOWERS . '>'; + $allow_gid = '<' . Circle::FOLLOWERS . '>'; $deny_cid = ''; $deny_gid = ''; self::performActivity($item['id'], 'announce', $uid, $allow_cid, $allow_gid, $deny_cid, $deny_gid); @@ -2279,12 +2338,7 @@ class Item return; } - $cdata = Contact::getPublicAndUserContactID($item['author-id'], $item['uid']); - if (empty($cdata['user']) || ($cdata['user'] != $item['contact-id'])) { - return; - } - - if (!DBA::exists('contact', ['id' => $cdata['user'], 'remote_self' => Contact::MIRROR_NATIVE_RESHARE])) { + if (!DBA::exists('contact', ['id' => $cdata['user'], 'remote_self' => LocalRelationship::MIRROR_NATIVE_RESHARE])) { return; } @@ -2292,6 +2346,10 @@ class Item return; } + if (User::getById($item['uid'], ['blocked'])['blocked'] ?? false) { + return; + } + Logger::info('Automatically reshare item', ['uid' => $item['uid'], 'id' => $item['id'], 'guid' => $item['guid'], 'uri-id' => $item['uri-id']]); self::performActivity($item['id'], 'announce', $item['uid']); @@ -2299,7 +2357,7 @@ class Item public static function isRemoteSelf(array $contact, array &$datarray): bool { - if ($contact['remote_self'] != Contact::MIRROR_OWN_POST) { + if ($contact['remote_self'] != LocalRelationship::MIRROR_OWN_POST) { return false; } @@ -2326,11 +2384,19 @@ class Item return false; } - $datarray2 = $datarray; - Logger::info('remote-self start', ['contact' => $contact['url'], 'remote_self'=> $contact['remote_self'], 'item' => $datarray]); + if (User::getById($contact['uid'], ['blocked'])['blocked'] ?? false) { + Logger::info('User is blocked', ['contact' => $contact]); + return false; + } - $self = DBA::selectFirst('contact', ['id', 'name', 'url', 'thumb'], - ['uid' => $contact['uid'], 'self' => true]); + $datarray2 = $datarray; + Logger::info('remote-self start', ['contact' => $contact['url'], 'remote_self' => $contact['remote_self'], 'item' => $datarray]); + + $self = DBA::selectFirst( + 'contact', + ['id', 'name', 'url', 'thumb'], + ['uid' => $contact['uid'], 'self' => true] + ); if (!DBA::isResult($self)) { Logger::error('Self contact not found', ['uid' => $contact['uid']]); return false; @@ -2366,7 +2432,7 @@ class Item // Store the original post $result = self::insert($datarray2); - Logger::info('remote-self post original item', ['contact' => $contact['url'], 'result'=> $result, 'item' => $datarray2]); + Logger::info('remote-self post original item', ['contact' => $contact['url'], 'result' => $result, 'item' => $datarray2]); } else { $datarray['private'] = self::PUBLIC; $datarray['app'] = 'Feed'; @@ -2493,7 +2559,8 @@ class Item if (($obj1['allow_cid'] == $obj2['allow_cid']) && ($obj1['allow_gid'] == $obj2['allow_gid']) && ($obj1['deny_cid'] == $obj2['deny_cid']) - && ($obj1['deny_gid'] == $obj2['deny_gid'])) { + && ($obj1['deny_gid'] == $obj2['deny_gid']) + ) { return true; } @@ -2524,13 +2591,13 @@ class Item $expand_followers = true; } - $allow_people = $aclFormatter->expand($obj['allow_cid']); - $allow_groups = Group::expand($obj['uid'], $aclFormatter->expand($obj['allow_gid']), $check_dead, $expand_followers); - $deny_people = $aclFormatter->expand($obj['deny_cid']); - $deny_groups = Group::expand($obj['uid'], $aclFormatter->expand($obj['deny_gid']), $check_dead); - $recipients = array_unique(array_merge($allow_people, $allow_groups)); - $deny = array_unique(array_merge($deny_people, $deny_groups)); - $recipients = array_diff($recipients, $deny); + $allow_people = $aclFormatter->expand($obj['allow_cid']); + $allow_circles = Circle::expand($obj['uid'], $aclFormatter->expand($obj['allow_gid']), $check_dead, $expand_followers); + $deny_people = $aclFormatter->expand($obj['deny_cid']); + $deny_circles = Circle::expand($obj['uid'], $aclFormatter->expand($obj['deny_gid']), $check_dead); + $recipients = array_unique(array_merge($allow_people, $allow_circles)); + $deny = array_unique(array_merge($deny_people, $deny_circles)); + $recipients = array_diff($recipients, $deny); return $recipients; } @@ -2540,8 +2607,10 @@ class Item return; } - $condition = ["`uid` = ? AND NOT `deleted` AND `gravity` = ?", - $uid, self::GRAVITY_PARENT]; + $condition = [ + "`uid` = ? AND NOT `deleted` AND `gravity` = ?", + $uid, self::GRAVITY_PARENT + ]; /* * $expire_network_only = save your own wall posts @@ -2615,8 +2684,10 @@ class Item return false; } - $condition = ["`uid` = ? AND `wall` = ? AND NOT `deleted` AND `visible` AND `received` >= ?", - $uid, $wall, $user['register_date']]; + $condition = [ + "`uid` = ? AND `wall` = ? AND NOT `deleted` AND `visible` AND `received` >= ?", + $uid, $wall, $user['register_date'] + ]; $params = ['order' => ['received' => false]]; $thread = Post::selectFirstThread(['received'], $condition, $params); if (DBA::isResult($thread)) { @@ -2748,8 +2819,10 @@ class Item $vids = Verb::getID($activity); } - $condition = ['vid' => $vids, 'deleted' => false, 'gravity' => self::GRAVITY_ACTIVITY, - 'author-id' => $author_id, 'uid' => $uid, 'thr-parent-id' => $uri_id]; + $condition = [ + 'vid' => $vids, 'deleted' => false, 'gravity' => self::GRAVITY_ACTIVITY, + 'author-id' => $author_id, 'uid' => $uid, 'thr-parent-id' => $uri_id + ]; $like_item = Post::selectFirst(['id', 'guid', 'verb'], $condition); if (DBA::isResult($like_item)) { @@ -2853,12 +2926,14 @@ class Item // Profile owner - everything is visible $condition = []; } elseif ($remote_user) { - // Authenticated visitor - fetch the matching permissionsets + // Authenticated visitor - fetch the matching permissionsets $permissionSets = DI::permissionSet()->selectByContactId($remote_user, $owner_id); if (!empty($set)) { - $condition = ["(`private` != ? OR (`private` = ? AND `wall` + $condition = [ + "(`private` != ? OR (`private` = ? AND `wall` AND `psid` IN (" . implode(', ', array_fill(0, count($set), '?')) . ")))", - self::PRIVATE, self::PRIVATE]; + self::PRIVATE, self::PRIVATE + ]; $condition = array_merge($condition, $permissionSets->column('id')); } } @@ -2896,9 +2971,9 @@ class Item /* * Authenticated visitor. Unless pre-verified, * check that the contact belongs to this $owner_id - * and load the groups the visitor belongs to. + * and load the circles the visitor belongs to. * If pre-verified, the caller is expected to have already - * done this and passed the groups into this function. + * done this and passed the circles into this function. */ $permissionSets = DI::permissionSet()->selectByContactId($remote_user, $owner_id); @@ -2954,7 +3029,8 @@ class Item $rendered_hash = $item['rendered-hash'] ?? ''; $rendered_html = $item['rendered-html'] ?? ''; - if ($rendered_hash == '' + if ( + $rendered_hash == '' || $rendered_html == '' || $rendered_hash != hash('md5', BBCode::VERSION . '::' . $body) || DI::config()->get('system', 'ignore_cache') @@ -3071,7 +3147,7 @@ class Item if (!empty($quote_uri_id)) { if (isset($shared_item['plink'])) { - $item['body'] .= "\n" . DI::contentItem()->createSharedBlockByArray($shared_item); + $item['body'] .= "\n" . DI::contentItem()->createSharedBlockByArray($shared_item, false, true); } else { DI::logger()->warning('Missing plink in shared item', ['item' => $item, 'shared' => $shared, 'quote_uri_id' => $quote_uri_id, 'shared_item' => $shared_item]); } @@ -3150,6 +3226,12 @@ class Item $body = BBCode::removeSharedData($body); } + $pos = strpos($s, BBCode::SHARED_ANCHOR); + if ($pos) { + $shared_html = substr($s, $pos + strlen(BBCode::SHARED_ANCHOR)); + $s = substr($s, 0, $pos); + } + $s = self::addGallery($s, $attachments, $item['uri-id']); $s = self::addVisualAttachments($attachments, $item, $s, false); $s = self::addLinkAttachment($item['uri-id'], $attachments, $body, $s, false, $shared_links); @@ -3170,6 +3252,10 @@ class Item $s = preg_replace('|(]+src="[^"]+/photo/[0-9a-f]+)-[0-9]|', "$1-" . $ps, $s); } + if (!empty($shared_html)) { + $s .= $shared_html; + } + $s = HTML::applyContentFilter($s, $filter_reasons); $hook_data = ['item' => $item, 'html' => $s]; @@ -3259,8 +3345,10 @@ class Item } foreach ([0, 1, 2] as $size) { - if (preg_match('#/photo/.*-' . $size . '\.#ism', $url) && - strpos(preg_replace('#(/photo/.*)-[012]\.#ism', '$1-' . $size . '.', $body), $url)) { + if ( + preg_match('#/photo/.*-' . $size . '\.#ism', $url) && + strpos(preg_replace('#(/photo/.*)-[012]\.#ism', '$1-' . $size . '.', $body), $url) + ) { return true; } } @@ -3457,7 +3545,8 @@ class Item 'text' => '', 'title' => $attachment['name'] ?? '', 'type' => 'link', - 'url' => $attachment['url']]; + 'url' => $attachment['url'] + ]; if ($preview && !empty($attachment['preview'])) { if ($attachment['preview-width'] >= 500) { @@ -3547,8 +3636,13 @@ class Item continue; } - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'] + ]; $the_url = Contact::magicLinkByContact($author, $attachment['url']); $title = Strings::escapeHtml(trim(($attachment['description'] ?? '') ?: $attachment['url'])); @@ -3597,7 +3691,7 @@ class Item $summary = DI::l10n()->tt('%d voter.', '%d voters.', $question['voters']); } elseif (!empty($question['endtime'])) { $summary = DI::l10n()->t('Poll end: %s', Temporal::getRelativeDate($question['endtime'])); - } else { + } else { $summary = ''; } @@ -3606,7 +3700,7 @@ class Item '$options' => $options, '$summary' => $summary, ]); - } + } DI::profiler()->stopRecording(); return $content; } @@ -3635,8 +3729,13 @@ class Item ]; if (!empty($plink) && ($item['private'] == self::PRIVATE)) { - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'], + ]; $plink = Contact::magicLinkByContact($author, $plink); } @@ -3659,15 +3758,22 @@ class Item } /** - * Does the given uri-id belongs to a post that is sent as starting post to a forum? + * Does the given uri-id belongs to a post that is sent as starting post to a group? + * This does apply to posts that are sent via ! and not in parallel to a group via @ * * @param int $uri_id * - * @return boolean "true" when it is a forum post + * @return boolean "true" when it is a group post */ - public static function isForumPost(int $uri_id): bool + public static function isGroupPost(int $uri_id): bool { - foreach (Tag::getByURIId($uri_id, [Tag::EXCLUSIVE_MENTION]) as $tag) { + if (Post::exists(['private' => Item::PUBLIC, 'uri-id' => $uri_id])) { + return false; + } + + foreach (Tag::getByURIId($uri_id, [Tag::EXCLUSIVE_MENTION, Tag::AUDIENCE]) as $tag) { + // @todo Possibly check for a public audience in the future, see https://socialhub.activitypub.rocks/t/fep-1b12-group-federation/2724 + // and https://codeberg.org/fediverse/fep/src/branch/main/feps/fep-1b12.md if (DBA::exists('contact', ['uid' => 0, 'nurl' => Strings::normaliseLink($tag['url']), 'contact-type' => Contact::TYPE_COMMUNITY])) { return true; } diff --git a/src/Model/Mail.php b/src/Model/Mail.php index a6cb8a078..78dd6329c 100644 --- a/src/Model/Mail.php +++ b/src/Model/Mail.php @@ -233,7 +233,7 @@ class Mail foreach ($images as $image) { $image_rid = Photo::ridFromURI($image); if (!empty($image_rid)) { - Photo::update(['allow-cid' => '<' . $recipient . '>'], ['resource-id' => $image_rid, 'album' => 'Wall Photos', 'uid' => $sender_uid]); + Photo::update(['allow_cid' => '<' . $recipient . '>'], ['resource-id' => $image_rid, 'album' => 'Wall Photos', 'uid' => $sender_uid]); } } } diff --git a/src/Model/Nodeinfo.php b/src/Model/Nodeinfo.php index 4dbe06c9b..825afb4a9 100644 --- a/src/Model/Nodeinfo.php +++ b/src/Model/Nodeinfo.php @@ -109,8 +109,9 @@ class Nodeinfo 'outbound' => [], ]; - if (Addon::isEnabled('blogger')) { - $services['outbound'][] = 'blogger'; + if (Addon::isEnabled('bluesky')) { + $services['inbound'][] = 'bluesky'; + $services['outbound'][] = 'bluesky'; } if (Addon::isEnabled('dwpost')) { $services['outbound'][] = 'dreamwidth'; @@ -125,18 +126,9 @@ class Nodeinfo if (Addon::isEnabled('libertree')) { $services['outbound'][] = 'libertree'; } - if (Addon::isEnabled('buffer')) { - $services['outbound'][] = 'linkedin'; - } if (Addon::isEnabled('ljpost')) { $services['outbound'][] = 'livejournal'; } - if (Addon::isEnabled('buffer')) { - $services['outbound'][] = 'pinterest'; - } - if (Addon::isEnabled('posterous')) { - $services['outbound'][] = 'posterous'; - } if (Addon::isEnabled('pumpio')) { $services['inbound'][] = 'pumpio'; $services['outbound'][] = 'pumpio'; @@ -147,7 +139,7 @@ class Nodeinfo if (Addon::isEnabled('tumblr')) { $services['outbound'][] = 'tumblr'; } - if (Addon::isEnabled('twitter') || Addon::isEnabled('buffer')) { + if (Addon::isEnabled('twitter')) { $services['outbound'][] = 'twitter'; } if (Addon::isEnabled('wppost')) { diff --git a/src/Model/Notification/Type.php b/src/Model/Notification/Type.php index c823545fb..3476a2ca9 100644 --- a/src/Model/Notification/Type.php +++ b/src/Model/Notification/Type.php @@ -42,7 +42,7 @@ class Type const TAG_SELF = 128; /** @var int Notification about getting poked/prodded/etc. (Obsolete) */ const POKE = 512; - /** @var int Notification about either a contact had posted something directly or the contact is a mentioned forum */ + /** @var int Notification about either a contact had posted something directly or the contact is a mentioned group */ const SHARE = 1024; /** @var int Global System notifications */ diff --git a/src/Model/Photo.php b/src/Model/Photo.php index 1b87e82d5..f39321154 100644 --- a/src/Model/Photo.php +++ b/src/Model/Photo.php @@ -414,9 +414,9 @@ class Photo * @param integer $scale Scale * @param integer $type Photo type, optional, default: Photo::DEFAULT * @param string $allow_cid Permissions, allowed contacts. optional, default = "" - * @param string $allow_gid Permissions, allowed groups. optional, default = "" - * @param string $deny_cid Permissions, denied contacts.optional, default = "" - * @param string $deny_gid Permissions, denied group.optional, default = "" + * @param string $allow_gid Permissions, allowed circles. optional, default = "" + * @param string $deny_cid Permissions, denied contacts. optional, default = "" + * @param string $deny_gid Permissions, denied circle. optional, default = "" * @param string $desc Photo caption. optional, default = "" * * @return boolean True on success @@ -830,13 +830,13 @@ class Photo * Changes photo permissions that had been embedded in a post * * @todo This function currently does have some flaws: - * - Sharing a post with a forum will create a photo that only the forum can see. + * - Sharing a post with a group will create a photo that only the group can see. * - Sharing a photo again that been shared non public before doesn't alter the permissions. * * @return string * @throws \Exception */ - public static function setPermissionFromBody($body, $uid, $original_contact_id, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny) + public static function setPermissionFromBody($body, $uid, $original_contact_id, $str_contact_allow, $str_circle_allow, $str_contact_deny, $str_circle_deny) { // Simplify image codes $img_body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); @@ -877,11 +877,11 @@ class Photo /** * @todo Existing permissions need to be mixed with the new ones. * Otherwise this creates problems with sharing the same picture multiple times - * Also check if $str_contact_allow does contain a public forum. + * Also check if $str_contact_allow does contain a public group. * Then set the permissions to public. */ - self::setPermissionForResource($image_rid, $uid, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + self::setPermissionForResource($image_rid, $uid, $str_contact_allow, $str_circle_allow, $str_contact_deny, $str_circle_deny); } return true; @@ -894,15 +894,15 @@ class Photo * @param string $image_rid * @param integer $uid * @param string $str_contact_allow - * @param string $str_group_allow + * @param string $str_circle_allow * @param string $str_contact_deny - * @param string $str_group_deny + * @param string $str_circle_deny * @return void */ - public static function setPermissionForResource(string $image_rid, int $uid, string $str_contact_allow, string $str_group_allow, string $str_contact_deny, string $str_group_deny) + public static function setPermissionForResource(string $image_rid, int $uid, string $str_contact_allow, string $str_circle_allow, string $str_contact_deny, string $str_circle_deny) { - $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_group_allow, - 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_group_deny, + $fields = ['allow_cid' => $str_contact_allow, 'allow_gid' => $str_circle_allow, + 'deny_cid' => $str_contact_deny, 'deny_gid' => $str_circle_deny, 'accessible' => DI::pConfig()->get($uid, 'system', 'accessible-photos', false)]; $condition = ['resource-id' => $image_rid, 'uid' => $uid]; @@ -989,6 +989,35 @@ class Photo return DBA::exists('photo', ['resource-id' => $guid]); } + /** + * Resize to a given maximum file size + * + * @param Image $image + * @param integer $maximagesize + * @return Image + */ + public static function resizeToFileSize(Image $image, int $maximagesize): Image + { + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); + + if ($maximagesize && ($filesize > $maximagesize)) { + // Scale down to multiples of 640 until the maximum size isn't exceeded anymore + foreach ([5120, 2560, 1280, 640, 320] as $pixels) { + if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) { + Logger::info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); + $image->scaleDown($pixels); + $filesize = strlen($image->asString()); + $width = $image->getWidth(); + $height = $image->getHeight(); + } + } + } + + return $image; + } + /** * Tries to resize image to wanted maximum size * @@ -1002,31 +1031,8 @@ class Photo $image->scaleDown($max_length); Logger::info('File upload: Scaling picture to new size', ['max-length' => $max_length]); } - - $filesize = strlen($image->asString()); - $width = $image->getWidth(); - $height = $image->getHeight(); - - $maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize')); - - if ($maximagesize && ($filesize > $maximagesize)) { - // Scale down to multiples of 640 until the maximum size isn't exceeded anymore - foreach ([5120, 2560, 1280, 640] as $pixels) { - if (($filesize > $maximagesize) && (max($width, $height) > $pixels)) { - Logger::info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); - $image->scaleDown($pixels); - $filesize = strlen($image->asString()); - $width = $image->getWidth(); - $height = $image->getHeight(); - } - } - if ($filesize > $maximagesize) { - Logger::notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); - return null; - } - } - - return $image; + + return self::resizeToFileSize($image, Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'))); } /** @@ -1228,41 +1234,16 @@ class Photo * @param string $album Album name * @param string $description Photo caption * @param string $allow_cid Permissions, allowed contacts - * @param string $allow_gid Permissions, allowed groups + * @param string $allow_gid Permissions, allowed circles * @param string $deny_cid Permissions, denied contacts - * @param string $deny_gid Permissions, denied group + * @param string $deny_gid Permissions, denied circles * * @return integer preview photo size * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ public static function storeWithPreview(Image $image, int $uid, string $resource_id, string $filename, int $filesize, string $album, string $description, string $allow_cid, string $allow_gid, string $deny_cid, string $deny_gid): int { - if ($filesize == 0) { - $filesize = strlen($image->asString()); - } - - $width = $image->getWidth(); - $height = $image->getHeight(); - - $maximagesize = Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize')); - - if ($maximagesize && $filesize > $maximagesize) { - // Scale down to multiples of 640 until the maximum size isn't exceeded anymore - foreach ([5120, 2560, 1280, 640, 320] as $pixels) { - if ($filesize > $maximagesize && max($width, $height) > $pixels) { - DI::logger()->info('Resize', ['size' => $filesize, 'width' => $width, 'height' => $height, 'max' => $maximagesize, 'pixels' => $pixels]); - $image->scaleDown($pixels); - $filesize = strlen($image->asString()); - $width = $image->getWidth(); - $height = $image->getHeight(); - } - } - - if ($filesize > $maximagesize) { - DI::logger()->notice('Image size is too big', ['size' => $filesize, 'max' => $maximagesize]); - return -1; - } - } + $image = self::resizeToFileSize($image, Strings::getBytesFromShorthand(DI::config()->get('system', 'maximagesize'))); $width = $image->getWidth(); $height = $image->getHeight(); diff --git a/src/Model/Post.php b/src/Model/Post.php index 770ab0831..6f855867f 100644 --- a/src/Model/Post.php +++ b/src/Model/Post.php @@ -453,12 +453,10 @@ class Post AND (NOT `causer-blocked` OR `causer-id` = ? OR `causer-id` IS NULL) AND NOT `contact-blocked` AND ((NOT `contact-readonly` AND NOT `contact-pending` AND (`contact-rel` IN (?, ?))) OR `self` OR `contact-uid` = ?) - AND NOT `" . $view . "`.`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `hidden`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `blocked` AND `cid` = `owner-id`) - AND NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `author-id`) - AND NOT `owner-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `ignored` AND `cid` = `owner-id`)", - 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid, $uid, $uid]); + AND NOT EXISTS(SELECT `uri-id` FROM `post-user` WHERE `uid` = ? AND `uri-id` = " . DBA::quoteIdentifier($view) . ".`uri-id` AND `hidden`) + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND `cid` IN (`author-id`, `owner-id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = ? AND `gsid` IN (`author-gsid`, `owner-gsid`, `causer-gsid`) AND `ignored`)", + 0, Contact::SHARING, Contact::FRIEND, 0, $uid, $uid, $uid]); $select_string = implode(', ', array_map([DBA::class, 'quoteIdentifier'], $selected)); diff --git a/src/Model/Post/Category.php b/src/Model/Post/Category.php index 2c35a40ad..c242e8ffd 100644 --- a/src/Model/Post/Category.php +++ b/src/Model/Post/Category.php @@ -33,9 +33,10 @@ use Friendica\Model\Tag; */ class Category { - const UNKNOWN = 0; - const CATEGORY = 3; - const FILE = 5; + const UNKNOWN = 0; + const CATEGORY = 3; + const FILE = 5; + const SUBCRIPTION = 10; /** * Delete all categories and files from a given uri-id and user @@ -80,7 +81,7 @@ class Category { $file_text = ''; - $tags = DBA::selectToArray('category-view', ['type', 'name'], ['uri-id' => $uri_id, 'uid' => $uid]); + $tags = DBA::selectToArray('category-view', ['type', 'name'], ['uri-id' => $uri_id, 'uid' => $uid, 'type' => [Category::FILE, Category::CATEGORY]]); foreach ($tags as $tag) { if ($tag['type'] == self::CATEGORY) { $file_text .= '<' . $tag['name'] . '>'; @@ -177,12 +178,7 @@ class Category continue; } - DBA::replace('post-category', [ - 'uri-id' => $uri_id, - 'uid' => $uid, - 'type' => self::FILE, - 'tid' => $tagid - ]); + self::storeByURIId($uri_id, $uid, self::FILE, $tagid); } } @@ -193,13 +189,18 @@ class Category } } - public static function storeFileByURIId(int $uri_id, int $uid, int $type, string $file) + public static function storeFileByURIId(int $uri_id, int $uid, int $type, string $file, string $url = ''): bool { - $tagid = Tag::getID($file); + $tagid = Tag::getID($file, $url); if (empty($tagid)) { return false; } + return self::storeByURIId($uri_id, $uid, $type, $tagid); + } + + private static function storeByURIId(int $uri_id, int $uid, int $type, int $tagid): bool + { return DBA::replace('post-category', [ 'uri-id' => $uri_id, 'uid' => $uid, diff --git a/src/Model/Post/User.php b/src/Model/Post/User.php index aba47534a..e1a9e40b1 100644 --- a/src/Model/Post/User.php +++ b/src/Model/Post/User.php @@ -25,6 +25,8 @@ use Friendica\Database\DBA; use \BadMethodCallException; use Friendica\Database\Database; use Friendica\DI; +use Friendica\Model\Item; +use Friendica\Protocol\Activity; class User { @@ -49,8 +51,8 @@ class User $fields['uri-id'] = $uri_id; $fields['uid'] = $uid; - // Public posts are always seen - if ($uid == 0) { + // Public posts and activities (like, dislike, ...) are always seen + if ($uid == 0 || (($data['gravity'] == Item::GRAVITY_ACTIVITY) && ($data['verb'] != Activity::ANNOUNCE))) { $fields['unseen'] = false; } diff --git a/src/Model/Post/UserNotification.php b/src/Model/Post/UserNotification.php index dd0bbbe1e..726e82d7e 100644 --- a/src/Model/Post/UserNotification.php +++ b/src/Model/Post/UserNotification.php @@ -133,14 +133,14 @@ class UserNotification public static function setNotification(int $uri_id, int $uid) { $fields = ['id', 'uri-id', 'parent-uri-id', 'uid', 'body', 'parent', 'gravity', 'vid', 'gravity', - 'contact-id', 'author-id', 'owner-id', 'causer-id', + 'contact-id', 'author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid', 'private', 'thr-parent', 'thr-parent-id', 'parent-uri-id', 'parent-uri', 'verb']; $item = Post::selectFirst($fields, ['uri-id' => $uri_id, 'uid' => $uid, 'origin' => false]); if (!DBA::isResult($item)) { return; } - $parent = Post::selectFirstPost(['author-id', 'owner-id', 'causer-id'], ['uri-id' => $item['parent-uri-id']]); + $parent = Post::selectFirstPost(['author-id', 'author-gsid', 'owner-id', 'owner-gsid', 'causer-id', 'causer-gsid',], ['uri-id' => $item['parent-uri-id']]); if (!DBA::isResult($parent)) { return; } @@ -195,6 +195,13 @@ class UserNotification } } + foreach (array_unique([$parent['author-gsid'], $parent['owner-gsid'], $parent['causer-gsid'], $item['author-gsid'], $item['owner-gsid'], $item['causer-gsid']]) as $gsid) { + if ($gsid && DI::userGServer()->isIgnoredByUser($uid, $gsid)) { + Logger::debug('Server is ignored by user', ['uid' => $uid, 'gsid' => $gsid, 'uri-id' => $item['uri-id']]); + return; + } + } + $user = User::getById($uid, ['account-type', 'account_removed', 'account_expired']); if (in_array($user['account-type'], [User::ACCOUNT_TYPE_COMMUNITY, User::ACCOUNT_TYPE_RELAY])) { return; @@ -398,45 +405,23 @@ class UserNotification */ private static function getProfileForUser(int $uid): array { - $notification_data = ['uid' => $uid, 'profiles' => []]; - Hook::callAll('check_item_notification', $notification_data); - - $profiles = $notification_data['profiles']; - - $user = DBA::selectFirst('user', ['nickname'], ['uid' => $uid]); - if (!DBA::isResult($user)) { - return []; - } - - $owner = DBA::selectFirst('contact', ['url', 'alias'], ['self' => true, 'uid' => $uid]); + $owner = User::getOwnerDataById($uid); if (!DBA::isResult($owner)) { return []; } - // This is our regular URL format - $profiles[] = $owner['url']; + $profiles = [$owner['nurl']]; - // Now the alias - $profiles[] = $owner['alias']; + $notification_data = ['uid' => $uid, 'profiles' => []]; + Hook::callAll('check_item_notification', $notification_data); - // Notifications from Diaspora often have a URL in the Diaspora format - $profiles[] = DI::baseUrl() . '/u/' . $user['nickname']; - - // Validate and add profile links - foreach ($profiles as $key => $profile) { - // Check for invalid profile urls (without scheme, host or path) and remove them + // Normalize the connector profiles + foreach ($notification_data['profiles'] as $profile) { if (empty(parse_url($profile, PHP_URL_SCHEME)) || empty(parse_url($profile, PHP_URL_HOST)) || empty(parse_url($profile, PHP_URL_PATH))) { - unset($profiles[$key]); - continue; + $profiles[] = $profile; + } else { + $profiles[] = Strings::normaliseLink($profile); } - - // Add the normalized form - $profile = Strings::normaliseLink($profile); - $profiles[] = $profile; - - // Add the SSL form - $profile = str_replace('http://', 'https://', $profile); - $profiles[] = $profile; } return array_unique($profiles); diff --git a/src/Model/Profile.php b/src/Model/Profile.php index e6c8e4822..c1a350673 100644 --- a/src/Model/Profile.php +++ b/src/Model/Profile.php @@ -37,6 +37,7 @@ use Friendica\DI; use Friendica\Network\HTTPClient\Client\HttpClientAccept; use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Network\HTTPException; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; use Friendica\Security\PermissionSet\Entity\PermissionSet; @@ -93,10 +94,11 @@ class Profile /** * Update a profile entry and distribute the changes if needed * - * @param array $fields Profile fields to update - * @param integer $uid User id + * @param array $fields Profile fields to update + * @param integer $uid User id * * @return boolean Whether update was successful + * @throws \Exception */ public static function update(array $fields, int $uid): bool { @@ -116,10 +118,6 @@ class Profile return false; } - if ($old_owner['name'] != $owner['name']) { - User::update(['username' => $owner['name']], $uid); - } - $profile_fields = ['postal-code', 'dob', 'prv_keywords', 'homepage']; foreach ($profile_fields as $field) { if ($old_owner[$field] != $owner[$field]) { @@ -640,13 +638,13 @@ class Profile $istoday = true; } - $title = strip_tags(html_entity_decode(BBCode::convertForUriId($rr['uri-id'], $rr['summary']), ENT_QUOTES, 'UTF-8')); + $title = BBCode::toPlaintext($rr['summary'], false); if (strlen($title) > 35) { $title = substr($title, 0, 32) . '... '; } - $description = substr(strip_tags(BBCode::convertForUriId($rr['uri-id'], $rr['desc'])), 0, 32) . '... '; + $description = BBCode::toPlaintext($rr['desc'], false) . '... '; if (!$description) { $description = DI::l10n()->t('[No description]'); } diff --git a/src/Model/Tag.php b/src/Model/Tag.php index 215d81713..04f3f1627 100644 --- a/src/Model/Tag.php +++ b/src/Model/Tag.php @@ -50,7 +50,7 @@ class Tag */ const IMPLICIT_MENTION = 8; /** - * An exclusive mention transmits the post only to the target account without transmitting it to the followers, usually a forum. + * An exclusive mention transmits the post only to the target account without transmitting it to the followers, usually a group. */ const EXCLUSIVE_MENTION = 9; @@ -487,7 +487,7 @@ class Tag * * @return boolean */ - public static function isMentioned(int $uriId, string $url, array $type = [self::MENTION, self::EXCLUSIVE_MENTION]): bool + public static function isMentioned(int $uriId, string $url, array $type = [self::MENTION, self::EXCLUSIVE_MENTION, self::AUDIENCE]): bool { $tags = self::getByURIId($uriId, $type); foreach ($tags as $tag) { @@ -828,12 +828,13 @@ class Tag public static function getUIDListByURIId(int $uriId): array { $uids = []; - $tags = self::getByURIId($uriId, [self::HASHTAG]); - foreach ($tags as $tag) { - $uids = array_merge($uids, self::getUIDListByTag(self::TAG_CHARACTER[self::HASHTAG] . $tag['name'])); + foreach (self::getByURIId($uriId, [self::HASHTAG]) as $tag) { + foreach (self::getUIDListByTag(self::TAG_CHARACTER[self::HASHTAG] . $tag['name']) as $uid) { + $uids[$uid][] = $tag['name']; + } } - return array_unique($uids); + return $uids; } } diff --git a/src/Model/User.php b/src/Model/User.php index 3be13bebf..af7a81a15 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -37,6 +37,7 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module; use Friendica\Network\HTTPClient\Client\HttpClientAccept; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Security\TwoFactor\Model\AppSpecificPassword; use Friendica\Network\HTTPException; use Friendica\Object\Image; @@ -88,7 +89,7 @@ class User * ACCOUNT_TYPE_NEWS - the account is a news reflector * Associated page type: PAGE_FLAGS_SOAPBOX * - * ACCOUNT_TYPE_COMMUNITY - the account is community forum + * ACCOUNT_TYPE_COMMUNITY - the account is community group * Associated page types: PAGE_COMMUNITY, PAGE_FLAGS_PRVGROUP * * ACCOUNT_TYPE_RELAY - the account is a relay @@ -132,6 +133,17 @@ class User return null; } + /** + * Get the Uri-Id of the system account + * + * @return integer + */ + public static function getSystemUriId(): int + { + $system = self::getSystemAccount(); + return $system['uri-id'] ?? 0; + } + /** * Fetch the system account * @@ -483,23 +495,41 @@ class User } /** - * Returns the default group for a given user and network + * Returns the default circle for a given user * * @param int $uid User id * - * @return int group id + * @return int circle id * @throws Exception */ - public static function getDefaultGroup(int $uid): int + public static function getDefaultCircle(int $uid): int { $user = DBA::selectFirst('user', ['def_gid'], ['uid' => $uid]); if (DBA::isResult($user)) { - $default_group = $user["def_gid"]; + $default_circle = $user['def_gid']; } else { - $default_group = 0; + $default_circle = 0; } - return $default_group; + return $default_circle; + } + + /** + * Returns the default circle for groups for a given user + * + * @param int $uid User id + * + * @return int circle id + * @throws Exception + */ + public static function getDefaultGroupCircle(int $uid): int + { + $default_circle = DI::pConfig()->get($uid, 'system', 'default-group-gid'); + if (empty($default_circle)) { + $default_circle = self::getDefaultCircle($uid); + } + + return $default_circle; } /** @@ -675,6 +705,10 @@ class User */ public static function updateLastActivity(int $uid) { + if (!$uid) { + return; + } + $user = User::getById($uid, ['last-activity']); if (empty($user)) { return; @@ -847,6 +881,20 @@ class User ]); } + /** + * Returns if the given uid is valid and a moderator + * + * @param int $uid + * + * @return bool + * @throws Exception + */ + public static function isModerator(int $uid): bool + { + // @todo Replace with a moderator check in the future + return self::isSiteAdmin($uid); + } + /** * Checks if a nickname is in the list of the forbidden nicknames * @@ -1188,13 +1236,13 @@ class User throw new Exception(DI::l10n()->t('An error occurred creating your self contact. Please try again.')); } - // Create a group with no members. This allows somebody to use it - // right away as a default group for new contacts. - $def_gid = Group::create($uid, DI::l10n()->t('Friends')); + // Create a circle with no members. This allows somebody to use it + // right away as a default circle for new contacts. + $def_gid = Circle::create($uid, DI::l10n()->t('Friends')); if (!$def_gid) { DBA::delete('user', ['uid' => $uid]); - throw new Exception(DI::l10n()->t('An error occurred creating your default contact group. Please try again.')); + throw new Exception(DI::l10n()->t('An error occurred creating your default contact circle. Please try again.')); } $fields = ['def_gid' => $def_gid]; @@ -1204,6 +1252,11 @@ class User DBA::update('user', $fields, ['uid' => $uid]); + $def_gid_groups = Circle::create($uid, DI::l10n()->t('Groups')); + if ($def_gid_groups) { + DI::pConfig()->set($uid, 'system', 'default-group-gid', $def_gid_groups); + } + // if we have no OpenID photo try to look up an avatar if (!strlen($photo)) { $photo = Network::lookupAvatarByEmail($email); @@ -1276,33 +1329,18 @@ class User /** * Update a user entry and distribute the changes if needed * - * @param array $fields + * @param array $fields * @param integer $uid * @return boolean + * @throws Exception */ public static function update(array $fields, int $uid): bool { - $old_owner = self::getOwnerDataById($uid); - if (empty($old_owner)) { - return false; - } - if (!DBA::update('user', $fields, ['uid' => $uid])) { return false; } - $update = Contact::updateSelfFromUserID($uid); - - $owner = self::getOwnerDataById($uid); - if (empty($owner)) { - return false; - } - - if ($old_owner['name'] != $owner['name']) { - Profile::update(['name' => $owner['name']], $uid); - } - - if ($update) { + if (Contact::updateSelfFromUserID($uid)) { Profile::publishUpdate($uid); } @@ -1640,7 +1678,7 @@ class User */ public static function identities(int $uid): array { - if (empty($uid)) { + if (!$uid) { return []; } @@ -1651,7 +1689,7 @@ class User return $identities; } - if ($user['parent-uid'] == 0) { + if (!$user['parent-uid']) { // First add our own entry $identities = [[ 'uid' => $user['uid'], @@ -1712,7 +1750,7 @@ class User */ public static function hasIdentities(int $uid): bool { - if (empty($uid)) { + if (!$uid) { return false; } @@ -1721,7 +1759,7 @@ class User return false; } - if ($user['parent-uid'] != 0) { + if ($user['parent-uid']) { return true; } @@ -1848,8 +1886,8 @@ class User { $condition = [ 'email' => self::getAdminEmailList(), - 'parent-uid' => 0, - 'blocked' => 0, + 'parent-uid' => null, + 'blocked' => false, 'verified' => true, 'account_removed' => false, 'account_expired' => false, diff --git a/src/Core/Cache/Enum/Type.php b/src/Moderation/Collection/Report/Posts.php similarity index 74% rename from src/Core/Cache/Enum/Type.php rename to src/Moderation/Collection/Report/Posts.php index 98ed9e41f..374654dc3 100644 --- a/src/Core/Cache/Enum/Type.php +++ b/src/Moderation/Collection/Report/Posts.php @@ -19,17 +19,15 @@ * */ -namespace Friendica\Core\Cache\Enum; +namespace Friendica\Moderation\Collection\Report; -/** - * Enumeration for cache types - */ -abstract class Type +class Posts extends \Friendica\BaseCollection { - const APCU = 'apcu'; - const REDIS = 'redis'; - const ARRAY = 'array'; - const MEMCACHE = 'memcache'; - const DATABASE = 'database'; - const MEMCACHED = 'memcached'; + /** + * @return \Friendica\Moderation\Entity\Report\Post + */ + public function current(): \Friendica\Moderation\Entity\Report\Post + { + return parent::current(); + } } diff --git a/src/Moderation/Collection/Report/Rules.php b/src/Moderation/Collection/Report/Rules.php new file mode 100644 index 000000000..4803c6bda --- /dev/null +++ b/src/Moderation/Collection/Report/Rules.php @@ -0,0 +1,33 @@ +. + * + */ + +namespace Friendica\Moderation\Collection\Report; + +class Rules extends \Friendica\BaseCollection +{ + /** + * @return \Friendica\Moderation\Entity\Report\Rule + */ + public function current(): \Friendica\Moderation\Entity\Report\Rule + { + return parent::current(); + } +} diff --git a/src/Moderation/Entity/Report.php b/src/Moderation/Entity/Report.php index 8d9a1cedc..ffc60047a 100644 --- a/src/Moderation/Entity/Report.php +++ b/src/Moderation/Entity/Report.php @@ -21,51 +21,126 @@ namespace Friendica\Moderation\Entity; +use Friendica\Moderation\Collection; + /** - * @property-read int $id - * @property-read int $reporterId - * @property-read int $cid - * @property-read string $comment - * @property-read string|null $category - * @property-read bool $forward - * @property-read array $postUriIds - * @property-read int $uid - * @property-read \DateTime|null $created + * @property-read int $id + * @property-read int $reporterCid + * @property-read int $cid + * @property-read int $gsid + * @property-read string $comment + * @property-read string $publicRemarks + * @property-read string $privateRemarks + * @property-read bool $forward + * @property-read int $category + * @property-read int $status + * @property-read int|null $resolution + * @property-read int $reporterUid + * @property-read int|null $lastEditorUid + * @property-read int|null $assignedUid + * @property-read \DateTimeImmutable $created + * @property-read \DateTimeImmutable|null $edited + * @property-read Collection\Report\Posts $posts + * @property-read Collection\Report\Rules $rules */ -class Report extends \Friendica\BaseEntity +final class Report extends \Friendica\BaseEntity { + const CATEGORY_OTHER = 1; + const CATEGORY_SPAM = 2; + const CATEGORY_ILLEGAL = 4; + const CATEGORY_SAFETY = 8; + const CATEGORY_UNWANTED = 16; + const CATEGORY_VIOLATION = 32; + + const CATEGORIES = [ + self::CATEGORY_OTHER, + self::CATEGORY_SPAM, + self::CATEGORY_ILLEGAL, + self::CATEGORY_SAFETY, + self::CATEGORY_UNWANTED, + self::CATEGORY_VIOLATION, + ]; + + const STATUS_CLOSED = 0; + const STATUS_OPEN = 1; + + const RESOLUTION_ACCEPTED = 0; + const RESOLUTION_REJECTED = 1; + /** @var int|null */ protected $id; - /** @var int ID of the contact making a moderation report*/ - protected $reporterId; - /** @var int ID of the contact being reported*/ + /** @var int ID of the contact making a moderation report */ + protected $reporterCid; + /** @var int ID of the contact being reported */ protected $cid; - /** @var string Optional comment */ + /** @var int ID of the gserver of the contact being reported */ + protected $gsid; + /** @var string Reporter comment */ protected $comment; - /** @var string Optional category */ + /** @var int One of CATEGORY_* */ protected $category; - /** @var string Violated rules */ - protected $rules; + /** @var int ID of the user making a moderation report, null in case of an incoming forwarded report */ + protected $reporterUid; /** @var bool Whether this report should be forwarded to the remote server */ protected $forward; - /** @var \DateTime|null When the report was created */ + /** @var \DateTimeImmutable When the report was created */ protected $created; - /** @var array Optional list of URI IDs of posts supporting the report*/ - protected $postUriIds; - /** @var int ID of the user making a moderation report*/ - protected $uid; + /** @var Collection\Report\Rules List of terms of service rule lines being possibly violated */ + protected $rules; + /** @var Collection\Report\Posts List of URI IDs of posts supporting the report */ + protected $posts; + /** @var string Remarks shared with the reporter */ + protected $publicRemarks; + /** @var string Remarks shared with the moderation team */ + protected $privateRemarks; + /** @var \DateTimeImmutable|null When the report was last edited */ + protected $edited; + /** @var int One of STATUS_* */ + protected $status; + /** @var int|null One of RESOLUTION_* if any */ + protected $resolution; + /** @var int|null Assigned moderator user id if any */ + protected $assignedUid; + /** @var int|null Last editor user ID if any */ + protected $lastEditorUid; - public function __construct(int $reporterId, int $cid, \DateTime $created, string $comment = '', string $category = null, string $rules = '', bool $forward = false, array $postUriIds = [], int $uid = null, int $id = null) - { - $this->reporterId = $reporterId; - $this->cid = $cid; - $this->created = $created; - $this->comment = $comment; - $this->category = $category; - $this->rules = $rules; - $this->forward = $forward; - $this->postUriIds = $postUriIds; - $this->uid = $uid; - $this->id = $id; + public function __construct( + int $reporterCid, + int $cid, + int $gsid, + \DateTimeImmutable $created, + int $category, + int $reporterUid = null, + string $comment = '', + bool $forward = false, + Collection\Report\Posts $posts = null, + Collection\Report\Rules $rules = null, + string $publicRemarks = '', + string $privateRemarks = '', + \DateTimeImmutable $edited = null, + int $status = self::STATUS_OPEN, + int $resolution = null, + int $assignedUid = null, + int $lastEditorUid = null, + int $id = null + ) { + $this->reporterCid = $reporterCid; + $this->cid = $cid; + $this->gsid = $gsid; + $this->created = $created; + $this->category = $category; + $this->reporterUid = $reporterUid; + $this->comment = $comment; + $this->forward = $forward; + $this->posts = $posts ?? new Collection\Report\Posts(); + $this->rules = $rules ?? new Collection\Report\Rules(); + $this->publicRemarks = $publicRemarks; + $this->privateRemarks = $privateRemarks; + $this->edited = $edited; + $this->status = $status; + $this->resolution = $resolution; + $this->assignedUid = $assignedUid; + $this->lastEditorUid = $lastEditorUid; + $this->id = $id; } } diff --git a/src/Moderation/Entity/Report/Post.php b/src/Moderation/Entity/Report/Post.php new file mode 100644 index 000000000..956052a30 --- /dev/null +++ b/src/Moderation/Entity/Report/Post.php @@ -0,0 +1,44 @@ +. + * + */ + +namespace Friendica\Moderation\Entity\Report; + +/** + * @property-read int $uriId URI Id of the reported post + * @property-read int $status One of STATUS_* + */ +final class Post extends \Friendica\BaseEntity +{ + const STATUS_NO_ACTION = 0; + const STATUS_UNLISTED = 1; + const STATUS_DELETED = 2; + + /** @var int */ + protected $uriId; + /** @var int|null */ + protected $status; + + public function __construct(int $uriId, int $status = self::STATUS_NO_ACTION) + { + $this->uriId = $uriId; + $this->status = $status; + } +} diff --git a/src/Moderation/Entity/Report/Rule.php b/src/Moderation/Entity/Report/Rule.php new file mode 100644 index 000000000..3d1d1f8d1 --- /dev/null +++ b/src/Moderation/Entity/Report/Rule.php @@ -0,0 +1,40 @@ +. + * + */ + +namespace Friendica\Moderation\Entity\Report; + +/** + * @property-read int $lineId Terms of service text line number + * @property-read string $text Terms of service rule text + */ +final class Rule extends \Friendica\BaseEntity +{ + /** @var int */ + protected $lineId; + /** @var string */ + protected $text; + + public function __construct(int $lineId, string $text) + { + $this->lineId = $lineId; + $this->text = $text; + } +} diff --git a/src/Moderation/Factory/Report.php b/src/Moderation/Factory/Report.php index 7cf400970..4d2e0bb75 100644 --- a/src/Moderation/Factory/Report.php +++ b/src/Moderation/Factory/Report.php @@ -22,28 +22,52 @@ namespace Friendica\Moderation\Factory; use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Core\System; +use Friendica\Model\Contact; +use Friendica\Moderation\Collection; use Friendica\Moderation\Entity; +use Psr\Clock\ClockInterface; +use Psr\Log\LoggerInterface; class Report extends \Friendica\BaseFactory implements ICanCreateFromTableRow { + /** @var ClockInterface */ + private $clock; + + public function __construct(LoggerInterface $logger, ClockInterface $clock) + { + parent::__construct($logger); + + $this->clock = $clock; + } + /** - * @param array $row `report` table row - * @param array $postUriIds List of post URI ids from the `report-post` table + * @param array $row `report` table row + * @param Collection\Report\Posts|null $posts List of posts attached to the report + * @param Collection\Report\Rules|null $rules List of rules from the terms of service, see System::getRules() * @return Entity\Report * @throws \Exception */ - public function createFromTableRow(array $row, array $postUriIds = []): Entity\Report + public function createFromTableRow(array $row, Collection\Report\Posts $posts = null, Collection\Report\Rules $rules = null): Entity\Report { return new Entity\Report( $row['reporter-id'], $row['cid'], - new \DateTime($row['created'] ?? 'now', new \DateTimeZone('UTC')), - $row['comment'], - $row['category'], - $row['rules'], - $row['forward'], - $postUriIds, + $row['gsid'], + new \DateTimeImmutable($row['created'], new \DateTimeZone('UTC')), + $row['category-id'], $row['uid'], + $row['comment'], + $row['forward'], + $posts ?? new Collection\Report\Posts(), + $rules ?? new Collection\Report\Rules(), + $row['public-remarks'], + $row['private-remarks'], + $row['edited'] ? new \DateTimeImmutable($row['edited'], new \DateTimeZone('UTC')) : null, + $row['status'], + $row['resolution'], + $row['assigned-uid'], + $row['last-editor-uid'], $row['id'], ); } @@ -51,29 +75,73 @@ class Report extends \Friendica\BaseFactory implements ICanCreateFromTableRow /** * Creates a Report entity from a Mastodon API /reports request * - * @see \Friendica\Module\Api\Mastodon\Reports::post() - * - * @param int $uid + * @param array $rules Line-number indexed node rules array, see System::getRules(true) * @param int $reporterId * @param int $cid + * @param int $gsid * @param string $comment + * @param string $category * @param bool $forward * @param array $postUriIds + * @param array $ruleIds + * @param ?int $uid * @return Entity\Report - * @throws \Exception + * @see \Friendica\Module\Api\Mastodon\Reports::post() */ - public function createFromReportsRequest(int $reporterId, int $cid, string $comment = '', string $category = null, string $rules = '', bool $forward = false, array $postUriIds = [], int $uid = null): Entity\Report + public function createFromReportsRequest(array $rules, int $reporterId, int $cid, int $gsid, string $comment = '', string $category = '', bool $forward = false, array $postUriIds = [], array $ruleIds = [], int $uid = null): Entity\Report { + if (count($ruleIds)) { + $categoryId = Entity\Report::CATEGORY_VIOLATION; + } elseif ($category == 'spam') { + $categoryId = Entity\Report::CATEGORY_SPAM; + } else { + $categoryId = Entity\Report::CATEGORY_OTHER; + } + return new Entity\Report( $reporterId, $cid, - new \DateTime('now', new \DateTimeZone('UTC')), - $comment, - $category, - $rules, - $forward, - $postUriIds, + $gsid, + $this->clock->now(), + $categoryId, $uid, + $comment, + $forward, + new Collection\Report\Posts(array_map(function ($uriId) { + return new Entity\Report\Post($uriId); + }, $postUriIds)), + new Collection\Report\Rules(array_map(function ($lineId) use ($rules) { + return new Entity\Report\Rule($lineId, $rules[$lineId] ?? ''); + }, $ruleIds)), + ); + } + + public function createFromForm(array $rules, int $cid, int $reporterId, int $categoryId, array $ruleIds, string $comment, array $uriIds, bool $forward): Entity\Report + { + $contact = Contact::getById($cid, ['gsid']); + if (!$contact) { + throw new \InvalidArgumentException('Contact with id: ' . $cid . ' not found'); + } + + if (!in_array($categoryId, Entity\Report::CATEGORIES)) { + throw new \OutOfBoundsException('Category with id: ' . $categoryId . ' not found in set: [' . implode(', ', Entity\Report::CATEGORIES) . ']'); + } + + return new Entity\Report( + Contact::getPublicIdByUserId($reporterId), + $cid, + $contact['gsid'], + $this->clock->now(), + $categoryId, + $reporterId, + $comment, + $forward, + new Collection\Report\Posts(array_map(function ($uriId) { + return new Entity\Report\Post($uriId); + }, $uriIds)), + new Collection\Report\Rules(array_map(function ($lineId) use ($rules) { + return new Entity\Report\Rule($lineId, $rules[$lineId] ?? ''); + }, $ruleIds)), ); } } diff --git a/src/Moderation/Factory/Report/Post.php b/src/Moderation/Factory/Report/Post.php new file mode 100644 index 000000000..f70460a28 --- /dev/null +++ b/src/Moderation/Factory/Report/Post.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Moderation\Factory\Report; + +use Friendica\Capabilities\ICanCreateFromTableRow; + +class Post extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + public function createFromTableRow(array $row): \Friendica\Moderation\Entity\Report\Post + { + return new \Friendica\Moderation\Entity\Report\Post( + $row['uri-id'], + $row['status'] + ); + } +} diff --git a/src/Moderation/Factory/Report/Rule.php b/src/Moderation/Factory/Report/Rule.php new file mode 100644 index 000000000..334570630 --- /dev/null +++ b/src/Moderation/Factory/Report/Rule.php @@ -0,0 +1,35 @@ +. + * + */ + +namespace Friendica\Moderation\Factory\Report; + +use Friendica\Capabilities\ICanCreateFromTableRow; + +class Rule extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + public function createFromTableRow(array $row): \Friendica\Moderation\Entity\Report\Rule + { + return new \Friendica\Moderation\Entity\Report\Rule( + $row['line-id'], + $row['text'] + ); + } +} diff --git a/src/Moderation/Repository/Report.php b/src/Moderation/Repository/Report.php index 101f15389..29f034351 100644 --- a/src/Moderation/Repository/Report.php +++ b/src/Moderation/Repository/Report.php @@ -25,24 +25,30 @@ use Friendica\BaseEntity; use Friendica\Core\Logger; use Friendica\Database\Database; use Friendica\Model\Post; +use Friendica\Moderation\Factory; +use Friendica\Moderation\Collection; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Util\DateTimeFormat; use Psr\Log\LoggerInterface; -class Report extends \Friendica\BaseRepository +final class Report extends \Friendica\BaseRepository { protected static $table_name = 'report'; - /** - * @var \Friendica\Moderation\Factory\Report - */ + /** @var Factory\Report */ protected $factory; + /** @var Factory\Report\Post */ + protected $postFactory; + /** @var Factory\Report\Rule */ + protected $ruleFactory; - public function __construct(Database $database, LoggerInterface $logger, \Friendica\Moderation\Factory\Report $factory) + public function __construct(Database $database, LoggerInterface $logger, Factory\Report $factory, Factory\Report\Post $postFactory, Factory\Report\Rule $ruleFactory) { parent::__construct($database, $logger, $factory); - $this->factory = $factory; + $this->factory = $factory; + $this->postFactory = $postFactory; + $this->ruleFactory = $ruleFactory; } public function selectOneById(int $lastInsertId): \Friendica\Moderation\Entity\Report @@ -50,37 +56,46 @@ class Report extends \Friendica\BaseRepository return $this->_selectOne(['id' => $lastInsertId]); } - public function save(\Friendica\Moderation\Entity\Report $Report) + public function save(\Friendica\Moderation\Entity\Report $Report): \Friendica\Moderation\Entity\Report { $fields = [ - 'uid' => $Report->uid, - 'reporter-id' => $Report->reporterId, - 'cid' => $Report->cid, - 'comment' => $Report->comment, - 'category' => $Report->category, - 'rules' => $Report->rules, - 'forward' => $Report->forward, + 'reporter-id' => $Report->reporterCid, + 'uid' => $Report->reporterUid, + 'cid' => $Report->cid, + 'gsid' => $Report->gsid, + 'comment' => $Report->comment, + 'forward' => $Report->forward, + 'category-id' => $Report->category, + 'public-remarks' => $Report->publicRemarks, + 'private-remarks' => $Report->privateRemarks, + 'last-editor-uid' => $Report->lastEditorUid, + 'assigned-uid' => $Report->assignedUid, + 'status' => $Report->status, + 'resolution' => $Report->resolution, + 'created' => $Report->created->format(DateTimeFormat::MYSQL), + 'edited' => $Report->edited ? $Report->edited->format(DateTimeFormat::MYSQL) : null, ]; - $postUriIds = $Report->postUriIds; - if ($Report->id) { $this->db->update(self::$table_name, $fields, ['id' => $Report->id]); } else { - $fields['created'] = DateTimeFormat::utcNow(); $this->db->insert(self::$table_name, $fields, Database::INSERT_IGNORE); - $Report = $this->selectOneById($this->db->lastInsertId()); - } + $newReportId = $this->db->lastInsertId(); - $this->db->delete('report-post', ['rid' => $Report->id]); - - foreach ($postUriIds as $uriId) { - if (Post::exists(['uri-id' => $uriId])) { - $this->db->insert('report-post', ['rid' => $Report->id, 'uri-id' => $uriId]); - } else { - Logger::notice('Post does not exist', ['uri-id' => $uriId, 'report' => $Report]); + foreach ($Report->posts as $post) { + if (Post::exists(['uri-id' => $post->uriId])) { + $this->db->insert('report-post', ['rid' => $newReportId, 'uri-id' => $post->uriId, 'status' => $post->status]); + } else { + Logger::notice('Post does not exist', ['uri-id' => $post->uriId, 'report' => $Report]); + } } + + foreach ($Report->rules as $rule) { + $this->db->insert('report-rule', ['rid' => $newReportId, 'line-id' => $rule->lineId, 'text' => $rule->text]); + } + + $Report = $this->selectOneById($newReportId); } return $Report; @@ -88,13 +103,14 @@ class Report extends \Friendica\BaseRepository protected function _selectOne(array $condition, array $params = []): BaseEntity { - $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + $fields = $this->db->selectFirst(self::$table_name, [], $condition, $params); if (!$this->db->isResult($fields)) { throw new NotFoundException(); } - $postUriIds = array_column($this->db->selectToArray('report-post', ['uri-id'], ['rid' => $condition['id'] ?? 0]), 'uri-id'); + $reportPosts = new Collection\Report\Posts(array_map([$this->postFactory, 'createFromTableRow'], $this->db->selectToArray('report-post', ['uri-id', 'status'], ['rid' => $condition['id'] ?? 0]))); + $reportRules = new Collection\Report\Rules(array_map([$this->ruleFactory, 'createFromTableRow'], $this->db->selectToArray('report-rule', ['line-id', 'text'], ['rid' => $condition['id'] ?? 0]))); - return $this->factory->createFromTableRow($fields, $postUriIds); + return $this->factory->createFromTableRow($fields, $reportPosts, $reportRules); } } diff --git a/src/Module/Admin/Federation.php b/src/Module/Admin/Federation.php index 517e8cb4a..51b83ccb4 100644 --- a/src/Module/Admin/Federation.php +++ b/src/Module/Admin/Federation.php @@ -42,9 +42,9 @@ class Federation extends BaseAdmin 'akkoma' => ['name' => 'Akkoma', 'color' => '#9574cd'], // Color from the page 'birdsitelive' => ['name' => 'BirdsiteLIVE', 'color' => '#1b6ec2'], // Color from the page 'bookwyrm' => ['name' => 'BookWyrm', 'color' => '#00d1b2'], // Color from the page - 'calckey' => ['name' => 'Calckey', 'color' => '#286983'], // Color from the page 'castopod' => ['name' => 'Castopod', 'color' => '#00564a'], // Background color from the page 'diaspora' => ['name' => 'Diaspora', 'color' => '#a1a1a1'], // logo is black and white, makes a gray + 'calckey' => ['name' => 'firefish (Calckey)', 'color' => '#1c4a5c'], // Color from the page 'foundkey' => ['name' => 'Foundkey', 'color' => '#609926'], // Some random color from the repository 'funkwhale' => ['name' => 'Funkwhale', 'color' => '#4082B4'], // From the homepage 'gancio' => ['name' => 'Gancio', 'color' => '#7253ed'], // Fontcolor from the page @@ -53,6 +53,7 @@ class Federation extends BaseAdmin 'hometown' => ['name' => 'Hometown', 'color' => '#1f70c1'], // Color from the Patreon page 'honk' => ['name' => 'Honk', 'color' => '##0d0d0d'], // Background color from the page 'hubzilla' => ['name' => 'Hubzilla/Red Matrix', 'color' => '#43488a'], // blue from the logo + 'kbin' => ['name' => 'kbin', 'color' => '#61366b'], // Color from their main instance 'lemmy' => ['name' => 'Lemmy', 'color' => '#00c853'], // Green from the page 'mastodon' => ['name' => 'Mastodon', 'color' => '#1a9df9'], // blue from the Mastodon logo 'microblog' => ['name' => 'Microblog', 'color' => '#fdb52b'], // Color from the page @@ -115,6 +116,8 @@ class Federation extends BaseAdmin $version['version'] = $gserver['platform'] . ' ' . $version['version']; } elseif (in_array($gserver['platform'], ['activityrelay', 'pub-relay', 'selective-relay', 'aoderelay'])) { $version['version'] = $gserver['platform'] . '-' . $version['version']; + } elseif (in_array($gserver['platform'], ['calckey', 'firefish'])) { + $version['version'] = $gserver['platform'] . '-' . $version['version']; } $versionCounts[] = $version; @@ -125,6 +128,8 @@ class Federation extends BaseAdmin if ($platform == 'friendika') { $platform = 'friendica'; + } elseif (in_array($platform, ['calckey', 'firefish'])) { + $platform = 'calckey'; } elseif (in_array($platform, ['red matrix', 'redmatrix', 'red'])) { $platform = 'hubzilla'; } elseif (in_array($platform, ['osada', 'mistpark', 'roadhouse', 'streams', 'zap'])) { diff --git a/src/Module/Admin/Site.php b/src/Module/Admin/Site.php index 4f5a35ab7..09624dcfc 100644 --- a/src/Module/Admin/Site.php +++ b/src/Module/Admin/Site.php @@ -131,7 +131,7 @@ class Site extends BaseAdmin $temppath = (!empty($_POST['temppath']) ? trim($_POST['temppath']) : ''); $singleuser = (!empty($_POST['singleuser']) ? trim($_POST['singleuser']) : ''); $only_tag_search = !empty($_POST['only_tag_search']); - $compute_group_counts = !empty($_POST['compute_group_counts']); + $compute_circle_counts = !empty($_POST['compute_circle_counts']); $check_new_version_url = (!empty($_POST['check_new_version_url']) ? trim($_POST['check_new_version_url']) : 'none'); $worker_queues = (!empty($_POST['worker_queues']) ? intval($_POST['worker_queues']) : 10); @@ -278,7 +278,7 @@ class Site extends BaseAdmin $transactionConfig->set('system', 'temppath', $temppath); $transactionConfig->set('system', 'only_tag_search' , $only_tag_search); - $transactionConfig->set('system', 'compute_group_counts', $compute_group_counts); + $transactionConfig->set('system', 'compute_circle_counts', $compute_circle_counts); $transactionConfig->set('system', 'worker_queues' , $worker_queues); $transactionConfig->set('system', 'worker_fastlane' , $worker_fastlane); @@ -452,7 +452,7 @@ class Site extends BaseAdmin '$block_public' => ['block_public', DI::l10n()->t('Block public'), DI::config()->get('system', 'block_public'), DI::l10n()->t('Check to block public access to all otherwise public personal pages on this site unless you are currently logged in.')], '$force_publish' => ['publish_all', DI::l10n()->t('Force publish'), DI::config()->get('system', 'publish_all'), DI::l10n()->t('Check to force all profiles on this site to be listed in the site directory.') . '' . DI::l10n()->t('Enabling this may violate privacy laws like the GDPR') . ''], '$global_directory' => ['directory', DI::l10n()->t('Global directory URL'), DI::config()->get('system', 'directory'), DI::l10n()->t('URL to the global directory. If this is not set, the global directory is completely unavailable to the application.')], - '$newuser_private' => ['newuser_private', DI::l10n()->t('Private posts by default for new users'), DI::config()->get('system', 'newuser_private'), DI::l10n()->t('Set default post permissions for all new members to the default privacy group rather than public.')], + '$newuser_private' => ['newuser_private', DI::l10n()->t('Private posts by default for new users'), DI::config()->get('system', 'newuser_private'), DI::l10n()->t('Set default post permissions for all new members to the default privacy circle rather than public.')], '$enotify_no_content' => ['enotify_no_content', DI::l10n()->t('Don\'t include post content in email notifications'), DI::config()->get('system', 'enotify_no_content'), DI::l10n()->t('Don\'t include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.')], '$private_addons' => ['private_addons', DI::l10n()->t('Disallow public access to addons listed in the apps menu.'), DI::config()->get('config', 'private_addons'), DI::l10n()->t('Checking this box will restrict addons listed in the apps menu to members only.')], '$disable_embedded' => ['disable_embedded', DI::l10n()->t('Don\'t embed private images in posts'), DI::config()->get('system', 'disable_embedded'), DI::l10n()->t('Don\'t replace locally-hosted private photos in posts with an embedded copy of the image. This means that contacts who receive posts containing private photos will have to authenticate and load each image, which may take a while.')], @@ -504,7 +504,7 @@ class Site extends BaseAdmin '$max_display_comments' => ['max_display_comments', DI::l10n()->t('Maximum numbers of comments per post on the display page'), DI::config()->get('system', 'max_display_comments'), DI::l10n()->t('How many comments should be shown on the single view for each post? Default value is 1000.')], '$temppath' => ['temppath', DI::l10n()->t('Temp path'), DI::config()->get('system', 'temppath'), DI::l10n()->t('If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.')], '$only_tag_search' => ['only_tag_search', DI::l10n()->t('Only search in tags'), DI::config()->get('system', 'only_tag_search'), DI::l10n()->t('On large systems the text search can slow down the system extremely.')], - '$compute_group_counts' => ['compute_group_counts', DI::l10n()->t('Generate counts per contact group when calculating network count'), DI::config()->get('system', 'compute_group_counts'), DI::l10n()->t('On systems with users that heavily use contact groups the query can be very expensive.')], + '$compute_circle_counts' => ['compute_circle_counts', DI::l10n()->t('Generate counts per contact circle when calculating network count'), DI::config()->get('system', 'compute_group_counts') ?? DI::config()->get('system', 'compute_circle_counts'), DI::l10n()->t('On systems with users that heavily use contact circles the query can be very expensive.')], '$worker_queues' => ['worker_queues', DI::l10n()->t('Maximum number of parallel workers'), DI::config()->get('system', 'worker_queues'), DI::l10n()->t('On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.', 5, 20, 10)], '$worker_fastlane' => ['worker_fastlane', DI::l10n()->t('Enable fastlane'), DI::config()->get('system', 'worker_fastlane'), DI::l10n()->t('When enabed, the fastlane mechanism starts an additional worker if processes with higher priority are blocked by processes of lower priority.')], diff --git a/src/Module/Admin/Summary.php b/src/Module/Admin/Summary.php index d872f4825..99d0e3325 100644 --- a/src/Module/Admin/Summary.php +++ b/src/Module/Admin/Summary.php @@ -79,7 +79,7 @@ class Summary extends BaseAdmin // Check if github.com/friendica/stable/VERSION is higher then // the local version of Friendica. Check is opt-in, source may be stable or develop branch if (DI::config()->get('system', 'check_new_version_url', 'none') != 'none') { - $gitversion = DI::keyValue()->get('git_friendica_version') ?? ''; + $gitversion = DI::keyValue()->get('git_friendica_version') ?? ''; if (version_compare(App::VERSION, $gitversion) < 0) { $warningtext[] = DI::l10n()->t('There is a new version of Friendica available for download. Your current version is %1$s, upstream version is %2$s', App::VERSION, $gitversion); @@ -126,35 +126,11 @@ class Summary extends BaseAdmin } // Check logfile permission - if (DI::config()->get('system', 'debugging')) { - $file = DI::config()->get('system', 'logfile'); - - $fileSystem = DI::fs(); - - try { - $stream = $fileSystem->createStream($file); - - if (!isset($stream)) { - throw new ServiceUnavailableException('Stream is null.'); - } - - } catch (\Throwable $exception) { - $warningtext[] = DI::l10n()->t('The logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); - } - - $file = DI::config()->get('system', 'dlogfile'); - - try { - if (!empty($file)) { - $stream = $fileSystem->createStream($file); - - if (!isset($stream)) { - throw new ServiceUnavailableException('Stream is null.'); - } - } - } catch (\Throwable $exception) { - $warningtext[] = DI::l10n()->t('The debug logfile \'%s\' is not usable. No logging possible (error: \'%s\')', $file, $exception->getMessage()); - } + if (($return = DI::logCheck()->checkLogfile()) !== null) { + $warningtext[] = $return; + } + if (($return = DI::logCheck()->checkDebugLogfile()) !== null) { + $warningtext[] = $return; } // check legacy basepath settings diff --git a/src/Module/Api/Friendica/Group/Create.php b/src/Module/Api/Friendica/Circle/Create.php similarity index 77% rename from src/Module/Api/Friendica/Group/Create.php rename to src/Module/Api/Friendica/Circle/Create.php index 290389931..b2787bdd5 100644 --- a/src/Module/Api/Friendica/Group/Create.php +++ b/src/Module/Api/Friendica/Circle/Create.php @@ -19,14 +19,15 @@ * */ -namespace Friendica\Module\Api\Friendica\Group; +namespace Friendica\Module\Api\Friendica\Circle; use Friendica\Database\DBA; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\BaseApi; use Friendica\Network\HTTPException; /** + * API endpoint: /api/friendica/circle_create * API endpoint: /api/friendica/group_create */ class Create extends BaseApi @@ -43,23 +44,22 @@ class Create extends BaseApi // error if no name specified if ($name == '') { - throw new HTTPException\BadRequestException('group name not specified'); + throw new HTTPException\BadRequestException('circle name not specified'); } - // error message if specified group name already exists + // error message if specified circle name already exists if (DBA::exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) { - throw new HTTPException\BadRequestException('group name already exists'); + throw new HTTPException\BadRequestException('circle name already exists'); } - // Check if the group needs to be reactivated + // Check if the circle needs to be reactivated if (DBA::exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => true])) { - $reactivate_group = true; + $reactivate_circle = true; } - // create group - $ret = Group::create($uid, $name); + $ret = Circle::create($uid, $name); if ($ret) { - $gid = Group::getIdByName($uid, $name); + $gid = Circle::getIdByName($uid, $name); } else { throw new HTTPException\BadRequestException('other API error'); } @@ -70,7 +70,7 @@ class Create extends BaseApi foreach ($users as $user) { $cid = $user['cid']; if (DBA::exists('contact', ['id' => $cid, 'uid' => $uid])) { - Group::addMember($gid, $cid); + Circle::addMember($gid, $cid); } else { $erroraddinguser = true; $errorusers[] = $cid; @@ -78,7 +78,7 @@ class Create extends BaseApi } // return success message incl. missing users in array - $status = ($erroraddinguser ? 'missing user' : ((isset($reactivate_group) && $reactivate_group) ? 'reactivated' : 'ok')); + $status = ($erroraddinguser ? 'missing user' : (!empty($reactivate_circle) ? 'reactivated' : 'ok')); $result = ['success' => true, 'gid' => $gid, 'name' => $name, 'status' => $status, 'wrong users' => $errorusers]; diff --git a/src/Module/Api/Friendica/Group/Delete.php b/src/Module/Api/Friendica/Circle/Delete.php similarity index 88% rename from src/Module/Api/Friendica/Group/Delete.php rename to src/Module/Api/Friendica/Circle/Delete.php index 68e0a0578..18db1216b 100644 --- a/src/Module/Api/Friendica/Group/Delete.php +++ b/src/Module/Api/Friendica/Circle/Delete.php @@ -19,15 +19,16 @@ * */ -namespace Friendica\Module\Api\Friendica\Group; +namespace Friendica\Module\Api\Friendica\Circle; use Friendica\Database\DBA; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\BaseApi; use Friendica\Network\HTTPException\BadRequestException; /** * API endpoint: /api/friendica/group/delete + * API endpoint: /api/friendica/circle/delete */ class Delete extends BaseApi { @@ -55,16 +56,16 @@ class Delete extends BaseApi // error message if specified gid is not in database if (!DBA::exists('group', ['uid' => $uid, 'id' => $request['gid'], 'name' => $request['name']])) { - throw new BadRequestException('wrong group name'); + throw new BadRequestException('wrong circle name'); } - // delete group - $gid = Group::getIdByName($uid, $request['name']); + // delete circle + $gid = Circle::getIdByName($uid, $request['name']); if (empty($request['gid'])) { throw new BadRequestException('other API error'); } - $ret = Group::remove($gid); + $ret = Circle::remove($gid); if ($ret) { // return success diff --git a/src/Module/Api/Friendica/Group/Show.php b/src/Module/Api/Friendica/Circle/Show.php similarity index 75% rename from src/Module/Api/Friendica/Group/Show.php rename to src/Module/Api/Friendica/Circle/Show.php index 336393107..9f2f93ede 100644 --- a/src/Module/Api/Friendica/Group/Show.php +++ b/src/Module/Api/Friendica/Circle/Show.php @@ -19,7 +19,7 @@ * */ -namespace Friendica\Module\Api\Friendica\Group; +namespace Friendica\Module\Api\Friendica\Circle; use Friendica\Database\DBA; use Friendica\DI; @@ -28,6 +28,7 @@ use Friendica\Module\BaseApi; use Friendica\Network\HTTPException; /** + * API endpoint: /api/friendica/circle_show * API endpoint: /api/friendica/group_show */ class Show extends BaseApi @@ -41,22 +42,22 @@ class Show extends BaseApi // params $gid = $this->getRequestValue($request, 'gid', 0); - // get data of the specified group id or all groups if not specified + // get data of the specified circle id or all circles if not specified if ($gid != 0) { - $groups = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid, 'id' => $gid]); + $circles = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid, 'id' => $gid]); // error message if specified gid is not in database - if (!DBA::isResult($groups)) { + if (!DBA::isResult($circles)) { throw new HTTPException\BadRequestException('gid not available'); } } else { - $groups = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid]); + $circles = DBA::selectToArray('group', [], ['deleted' => false, 'uid' => $uid]); } - // loop through all groups and retrieve all members for adding data in the user array + // loop through all circles and retrieve all members for adding data in the user array $grps = []; - foreach ($groups as $rr) { - $members = Contact\Group::getById($rr['id']); + foreach ($circles as $circle) { + $members = Contact\Circle::getById($circle['id']); $users = []; if ($type == 'xml') { @@ -71,7 +72,7 @@ class Show extends BaseApi $users[] = DI::twitterUser()->createFromContactId($member['contact-id'], $uid, true)->toArray(); } } - $grps[] = ['name' => $rr['name'], 'gid' => $rr['id'], $user_element => $users]; + $grps[] = ['name' => $circle['name'], 'gid' => $circle['id'], $user_element => $users]; } $this->response->exit('group_update', ['group' => $grps], $this->parameters['extension'] ?? null); diff --git a/src/Module/Api/Friendica/Group/Update.php b/src/Module/Api/Friendica/Circle/Update.php similarity index 87% rename from src/Module/Api/Friendica/Group/Update.php rename to src/Module/Api/Friendica/Circle/Update.php index bee037d97..38bbea382 100644 --- a/src/Module/Api/Friendica/Group/Update.php +++ b/src/Module/Api/Friendica/Circle/Update.php @@ -19,15 +19,16 @@ * */ -namespace Friendica\Module\Api\Friendica\Group; +namespace Friendica\Module\Api\Friendica\Circle; use Friendica\Database\DBA; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\BaseApi; use Friendica\Network\HTTPException\BadRequestException; /** + * API endpoint: /api/friendica/circle_update * API endpoint: /api/friendica/group_update */ class Update extends BaseApi @@ -45,7 +46,7 @@ class Update extends BaseApi // error if no name specified if (!$name) { - throw new BadRequestException('group name not specified'); + throw new BadRequestException('circle name not specified'); } // error if no gid specified @@ -54,15 +55,15 @@ class Update extends BaseApi } // remove members - $members = Contact\Group::getById($gid); + $members = Contact\Circle::getById($gid); foreach ($members as $member) { $cid = $member['id']; foreach ($users as $user) { $found = $user['cid'] == $cid; } if (!isset($found) || !$found) { - $gid = Group::getIdByName($uid, $name); - Group::removeMember($gid, $cid); + $gid = Circle::getIdByName($uid, $name); + Circle::removeMember($gid, $cid); } } @@ -73,7 +74,7 @@ class Update extends BaseApi $cid = $user['cid']; if (DBA::exists('contact', ['id' => $cid, 'uid' => $uid])) { - Group::addMember($gid, $cid); + Circle::addMember($gid, $cid); } else { $erroraddinguser = true; $errorusers[] = $cid; diff --git a/src/Module/Api/Friendica/Events/Create.php b/src/Module/Api/Friendica/Events/Create.php index a0b969ee2..4eb92e9c8 100644 --- a/src/Module/Api/Friendica/Events/Create.php +++ b/src/Module/Api/Friendica/Events/Create.php @@ -53,9 +53,9 @@ class Create extends BaseApi 'place' => '', //location of the event 'publish' => 0, //publish message 'allow_cid' => '', //array of allowed person, if access restricted - 'allow_gid' => '', //array of allowed groups, if access restricted + 'allow_gid' => '', //array of allowed circles, if access restricted 'deny_cid' => '', //array of denied person, if access restricted - 'deny_gid' => '', //array of denied groups, if access restricted + 'deny_gid' => '', //array of denied circles, if access restricted ], $request); // error if no name specified diff --git a/src/Module/Api/Friendica/Photo/Create.php b/src/Module/Api/Friendica/Photo/Create.php index 6cb9241c9..4190145aa 100644 --- a/src/Module/Api/Friendica/Photo/Create.php +++ b/src/Module/Api/Friendica/Photo/Create.php @@ -78,8 +78,8 @@ class Create extends BaseApi $acl_input_error = false; $acl_input_error |= !ACL::isValidContact($allow_cid, $uid); $acl_input_error |= !ACL::isValidContact($deny_cid, $uid); - $acl_input_error |= !ACL::isValidGroup($allow_gid, $uid); - $acl_input_error |= !ACL::isValidGroup($deny_gid, $uid); + $acl_input_error |= !ACL::isValidCircle($allow_gid, $uid); + $acl_input_error |= !ACL::isValidCircle($deny_gid, $uid); if ($acl_input_error) { throw new HTTPException\BadRequestException('acl data invalid'); } diff --git a/src/Module/Api/Friendica/Photo/Update.php b/src/Module/Api/Friendica/Photo/Update.php index 0eec5a344..d9ff769aa 100644 --- a/src/Module/Api/Friendica/Photo/Update.php +++ b/src/Module/Api/Friendica/Photo/Update.php @@ -79,8 +79,8 @@ class Update extends BaseApi $acl_input_error = false; $acl_input_error |= !ACL::isValidContact($allow_cid, $uid); $acl_input_error |= !ACL::isValidContact($deny_cid, $uid); - $acl_input_error |= !ACL::isValidGroup($allow_gid, $uid); - $acl_input_error |= !ACL::isValidGroup($deny_gid, $uid); + $acl_input_error |= !ACL::isValidCircle($allow_gid, $uid); + $acl_input_error |= !ACL::isValidCircle($deny_gid, $uid); if ($acl_input_error) { throw new HTTPException\BadRequestException('acl data invalid'); } diff --git a/src/Module/Api/Friendica/Profile/Show.php b/src/Module/Api/Friendica/Profile/Show.php index 28909f0e3..b97fcdcab 100644 --- a/src/Module/Api/Friendica/Profile/Show.php +++ b/src/Module/Api/Friendica/Profile/Show.php @@ -78,7 +78,7 @@ class Show extends BaseApi foreach ($profileFields as $profileField) { $custom_fields[] = [ 'label' => $profileField->label, - 'value' => BBCode::convert($profileField->value, false, BBCode::TWITTER_API), + 'value' => BBCode::convertForUriId($profileField->uriId, $profileField->value, BBCode::TWITTER_API), ]; } diff --git a/src/Module/Api/Mastodon/Accounts/Lists.php b/src/Module/Api/Mastodon/Accounts/Lists.php index 2d254a296..e34dd4137 100644 --- a/src/Module/Api/Mastodon/Accounts/Lists.php +++ b/src/Module/Api/Mastodon/Accounts/Lists.php @@ -53,11 +53,11 @@ class Lists extends BaseApi $cdata = Contact::getPublicAndUserContactID($id, $uid); if (!empty($cdata['user'])) { - $groups = DBA::select('group_member', ['gid'], ['contact-id' => $cdata['user']]); - while ($group = DBA::fetch($groups)) { - $lists[] = DI::mstdnList()->createFromGroupId($group['gid']); + $circles = DBA::select('group_member', ['gid'], ['contact-id' => $cdata['user']]); + while ($circle = DBA::fetch($circles)) { + $lists[] = DI::mstdnList()->createFromCircleId($circle['gid']); } - DBA::close($groups); + DBA::close($circles); } System::jsonExit($lists); diff --git a/src/Module/Api/Mastodon/InstanceV2.php b/src/Module/Api/Mastodon/InstanceV2.php index 402e0ae93..bf5cbcfb5 100644 --- a/src/Module/Api/Mastodon/InstanceV2.php +++ b/src/Module/Api/Mastodon/InstanceV2.php @@ -23,6 +23,7 @@ namespace Friendica\Module\Api\Mastodon; use Exception; use Friendica\App; +use Friendica\Contact\Header; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\L10n; use Friendica\Core\System; @@ -49,6 +50,9 @@ class InstanceV2 extends BaseApi /** @var IManageConfigValues */ private $config; + /** @var Header */ + private $contactHeader; + public function __construct( App $app, L10n $l10n, @@ -64,8 +68,9 @@ class InstanceV2 extends BaseApi ) { parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->database = $database; - $this->config = $config; + $this->database = $database; + $this->config = $config; + $this->contactHeader = new Header($config); } /** @@ -82,7 +87,7 @@ class InstanceV2 extends BaseApi $version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')'; $description = $this->config->get('config', 'info'); $usage = $this->buildUsageInfo(); - $thumbnail = new InstanceEntity\Thumbnail($this->baseUrl->withPath('images/friendica-banner.jpg')); + $thumbnail = new InstanceEntity\Thumbnail($this->baseUrl . $this->contactHeader->getMastodonBannerPath()); $languages = [$this->config->get('system', 'language')]; $configuration = $this->buildConfigurationInfo(); $registration = $this->buildRegistrationsInfo(); diff --git a/src/Module/Api/Mastodon/Lists.php b/src/Module/Api/Mastodon/Lists.php index 3e5a47198..a007c80d3 100644 --- a/src/Module/Api/Mastodon/Lists.php +++ b/src/Module/Api/Mastodon/Lists.php @@ -24,7 +24,7 @@ namespace Friendica\Module\Api\Mastodon; use Friendica\Core\System; use Friendica\DI; use Friendica\Module\BaseApi; -use Friendica\Model\Group; +use Friendica\Model\Circle; /** * @see https://docs.joinmastodon.org/methods/timelines/lists/ @@ -40,11 +40,11 @@ class Lists extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - if (!Group::exists($this->parameters['id'], $uid)) { + if (!Circle::exists($this->parameters['id'], $uid)) { DI::mstdnError()->RecordNotFound(); } - if (!Group::remove($this->parameters['id'])) { + if (!Circle::remove($this->parameters['id'])) { DI::mstdnError()->InternalError(); } @@ -64,14 +64,14 @@ class Lists extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - Group::create($uid, $request['title']); + Circle::create($uid, $request['title']); - $id = Group::getIdByName($uid, $request['title']); + $id = Circle::getIdByName($uid, $request['title']); if (!$id) { DI::mstdnError()->InternalError(); } - System::jsonExit(DI::mstdnList()->createFromGroupId($id)); + System::jsonExit(DI::mstdnList()->createFromCircleId($id)); } public function put(array $request = []) @@ -85,7 +85,7 @@ class Lists extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - Group::update($this->parameters['id'], $request['title']); + Circle::update($this->parameters['id'], $request['title']); } /** @@ -99,18 +99,16 @@ class Lists extends BaseApi if (empty($this->parameters['id'])) { $lists = []; - $groups = Group::getByUserId($uid); - - foreach ($groups as $group) { - $lists[] = DI::mstdnList()->createFromGroupId($group['id']); + foreach (Circle::getByUserId($uid) as $circle) { + $lists[] = DI::mstdnList()->createFromCircleId($circle['id']); } } else { $id = $this->parameters['id']; - if (!Group::exists($id, $uid)) { + if (!Circle::exists($id, $uid)) { DI::mstdnError()->RecordNotFound(); } - $lists = DI::mstdnList()->createFromGroupId($id); + $lists = DI::mstdnList()->createFromCircleId($id); } System::jsonExit($lists); diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index e19dfb031..465f22a26 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -24,7 +24,7 @@ namespace Friendica\Module\Api\Mastodon\Lists; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\BaseApi; /** @@ -46,7 +46,7 @@ class Accounts extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - return Group::removeMembers($this->parameters['id'], $request['account_ids']); + return Circle::removeMembers($this->parameters['id'], $request['account_ids']); } protected function post(array $request = []) @@ -61,7 +61,7 @@ class Accounts extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - Group::addMembers($this->parameters['id'], $request['account_ids']); + Circle::addMembers($this->parameters['id'], $request['account_ids']); } /** diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index e26637601..921ebdaf7 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -38,13 +38,20 @@ class Media extends BaseApi self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); + $request = $this->getRequest([ + 'file' => [], // The file to be attached, using multipart form data. + 'thumbnail' => [], // The custom thumbnail of the media to be attached, using multipart form data. + 'description' => '', // A plain-text description of the media, for accessibility purposes. + 'focus' => '', // Two floating points (x,y), comma-delimited ranging from -1.0 to 1.0 + ], $request); + Logger::info('Photo post', ['request' => $request, 'files' => $_FILES]); if (empty($_FILES['file'])) { DI::mstdnError()->UnprocessableEntity(); } - $media = Photo::upload($uid, $_FILES['file']); + $media = Photo::upload($uid, $_FILES['file'], '', null, null, '', '', $request['description']); if (empty($media)) { DI::mstdnError()->UnprocessableEntity(); } diff --git a/src/Module/Api/Mastodon/Reports.php b/src/Module/Api/Mastodon/Reports.php index 1f0f2839e..401d3da19 100644 --- a/src/Module/Api/Mastodon/Reports.php +++ b/src/Module/Api/Mastodon/Reports.php @@ -62,21 +62,23 @@ class Reports extends BaseApi 'forward' => false, // If the account is remote, should the report be forwarded to the remote admin? ], $request); - $contact = Contact::getById($request['account_id'], ['id']); + $contact = Contact::getById($request['account_id'], ['id', 'gsid']); if (empty($contact)) { throw new HTTPException\NotFoundException('Account ' . $request['account_id'] . ' not found'); } - $violation = ''; - $rules = System::getRules(true); - - foreach ($request['rule_ids'] as $key) { - if (!empty($rules[$key])) { - $violation .= $rules[$key] . "\n"; - } - } - - $report = $this->reportFactory->createFromReportsRequest(Contact::getPublicIdByUserId(self::getCurrentUserID()), $request['account_id'], $request['comment'], $request['category'], trim($violation), $request['forward'], $request['status_ids'], self::getCurrentUserID()); + $report = $this->reportFactory->createFromReportsRequest( + System::getRules(), + Contact::getPublicIdByUserId(self::getCurrentUserID()), + $contact['id'], + $contact['gsid'], + $request['comment'], + $request['category'], + $request['forward'], + $request['status_ids'], + $request['rule_ids'], + self::getCurrentUserID() + ); $this->reportRepo->save($report); diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index 72641235d..a8f1dc1c6 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -30,7 +30,7 @@ use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Item; use Friendica\Model\Photo; use Friendica\Model\Post; @@ -76,16 +76,9 @@ class Statuses extends BaseApi throw new HTTPException\NotFoundException('Item with URI ID ' . $this->parameters['id'] . ' not found for user ' . $uid . '.'); } - // The imput is defined as text. So we can use Markdown for some enhancements - $body = Markdown::toBBCode($request['status']); - - if (DI::pConfig()->get($uid, 'system', 'api_auto_attach', false) && preg_match("/\[url=[^\[\]]*\](.*)\[\/url\]\z/ism", $body, $matches)) { - $body = preg_replace("/\[url=[^\[\]]*\].*\[\/url\]\z/ism", PageInfo::getFooterFromUrl($matches[1]), $body); - } - $item['title'] = ''; $item['uid'] = $post['uid']; - $item['body'] = $body; + $item['body'] = $this->formatStatus($request['status'], $uid); $item['network'] = $post['network']; $item['gravity'] = $post['gravity']; $item['verb'] = $post['verb']; @@ -190,13 +183,6 @@ class Statuses extends BaseApi $owner = User::getOwnerDataById($uid); - // The imput is defined as text. So we can use Markdown for some enhancements - $body = Markdown::toBBCode($request['status']); - - if (DI::pConfig()->get($uid, 'system', 'api_auto_attach', false) && preg_match("/\[url=[^\[\]]*\](.*)\[\/url\]\z/ism", $body, $matches)) { - $body = preg_replace("/\[url=[^\[\]]*\].*\[\/url\]\z/ism", PageInfo::getFooterFromUrl($matches[1]), $body); - } - $item = []; $item['network'] = Protocol::DFRN; $item['uid'] = $uid; @@ -204,7 +190,7 @@ class Statuses extends BaseApi $item['contact-id'] = $owner['id']; $item['author-id'] = $item['owner-id'] = Contact::getPublicIdByUserId($uid); $item['title'] = ''; - $item['body'] = $body; + $item['body'] = $this->formatStatus($request['status'], $uid); $item['app'] = $this->getApp(); switch ($request['visibility']) { @@ -230,7 +216,7 @@ class Statuses extends BaseApi $item['deny_gid'] = $owner['deny_gid']; } else { $item['allow_cid'] = ''; - $item['allow_gid'] = '<' . Group::FOLLOWERS . '>'; + $item['allow_gid'] = '<' . Circle::FOLLOWERS . '>'; $item['deny_cid'] = ''; $item['deny_gid'] = ''; } @@ -241,7 +227,7 @@ class Statuses extends BaseApi // The permissions are assigned in "expandTags" break; default: - if (is_numeric($request['visibility']) && Group::exists($request['visibility'], $uid)) { + if (is_numeric($request['visibility']) && Circle::exists($request['visibility'], $uid)) { $item['allow_cid'] = ''; $item['allow_gid'] = '<' . $request['visibility'] . '>'; $item['deny_cid'] = ''; @@ -415,4 +401,28 @@ class Statuses extends BaseApi } return $item; } + + /** + * Format the status via Markdown and a link description if enabled for this user + * + * @param string $status + * @param integer $uid + * @return string + */ + private function formatStatus(string $status, int $uid): string + { + // The input is defined as text. So we can use Markdown for some enhancements + $status = Markdown::toBBCode($status); + + if (!DI::pConfig()->get($uid, 'system', 'api_auto_attach', false)) { + return $status; + } + + $status = BBCode::expandVideoLinks($status); + if (preg_match("/\[url=[^\[\]]*\](.*)\[\/url\]\z/ism", $status, $matches)) { + $status = preg_replace("/\[url=[^\[\]]*\].*\[\/url\]\z/ism", PageInfo::getFooterFromUrl($matches[1]), $status); + } + + return $status; + } } diff --git a/src/Module/Api/Mastodon/Statuses/Bookmark.php b/src/Module/Api/Mastodon/Statuses/Bookmark.php index 255b459c3..7f32c9a43 100644 --- a/src/Module/Api/Mastodon/Statuses/Bookmark.php +++ b/src/Module/Api/Mastodon/Statuses/Bookmark.php @@ -42,7 +42,7 @@ class Bookmark extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginal(['uid', 'id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]); + $item = Post::selectOriginal(['uid', 'id', 'uri-id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -52,7 +52,7 @@ class Bookmark extends BaseApi } if ($item['uid'] == 0) { - $stored = Item::storeForUserByUriId($item['id'], $uid, ['post-reason' => Item::PR_ACTIVITY]); + $stored = Item::storeForUserByUriId($item['uri-id'], $uid, ['post-reason' => Item::PR_ACTIVITY]); if (!empty($stored)) { $item = Post::selectFirst(['id', 'gravity'], ['id' => $stored]); if (!DBA::isResult($item)) { @@ -65,6 +65,11 @@ class Bookmark extends BaseApi Item::update(['starred' => true], ['id' => $item['id']]); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Card.php b/src/Module/Api/Mastodon/Statuses/Card.php index 6d29ee879..3e973d9bb 100644 --- a/src/Module/Api/Mastodon/Statuses/Card.php +++ b/src/Module/Api/Mastodon/Statuses/Card.php @@ -43,11 +43,11 @@ class Card extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - if (!$post = Post::selectOriginal(['id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { + if (!$post = Post::selectOriginal(['uri-id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { throw new HTTPException\NotFoundException('Item with URI ID ' . $this->parameters['id'] . ' not found' . ($uid ? ' for user ' . $uid : '.')); } - $card = DI::mstdnCard()->createFromUriId($post['id']); + $card = DI::mstdnCard()->createFromUriId($post['uri-id']); System::jsonExit($card->toArray()); } diff --git a/src/Module/Api/Mastodon/Statuses/Context.php b/src/Module/Api/Mastodon/Statuses/Context.php index 0b2e7bda6..c510fc9a8 100644 --- a/src/Module/Api/Mastodon/Statuses/Context.php +++ b/src/Module/Api/Mastodon/Statuses/Context.php @@ -56,6 +56,7 @@ class Context extends BaseApi $parents = []; $children = []; + $deleted = []; $parent = Post::selectOriginal(['uri-id', 'parent-uri-id'], ['uri-id' => $id]); if (DBA::isResult($parent)) { @@ -66,11 +67,11 @@ class Context extends BaseApi if (!empty($request['max_id'])) { $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]); } - + if (!empty($request['since_id'])) { $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['since_id']]); } - + if (!empty($request['min_id'])) { $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]); $params['order'] = ['uri-id']; @@ -82,8 +83,8 @@ class Context extends BaseApi ["NOT `author-id` IN (SELECT `cid` FROM `user-contact` WHERE `uid` = ? AND (`blocked` OR `ignored`))", $uid] ); } - - $posts = Post::selectPosts(['uri-id', 'thr-parent-id'], $condition, $params); + + $posts = Post::selectPosts(['uri-id', 'thr-parent-id', 'deleted'], $condition, $params); while ($post = Post::fetch($posts)) { if ($post['uri-id'] == $post['thr-parent-id']) { continue; @@ -93,6 +94,10 @@ class Context extends BaseApi $parents[$post['uri-id']] = $post['thr-parent-id']; $children[$post['thr-parent-id']][] = $post['uri-id']; + + if ($post['deleted']) { + $deleted[] = $post['uri-id']; + } } DBA::close($posts); @@ -117,7 +122,7 @@ class Context extends BaseApi $statuses = ['ancestors' => [], 'descendants' => []]; - $ancestors = self::getParents($id, $parents); + $ancestors = array_diff(self::getParents($id, $parents), $deleted); asort($ancestors); @@ -127,7 +132,7 @@ class Context extends BaseApi $statuses['ancestors'][] = DI::mstdnStatus()->createFromUriId($ancestor, $uid, $display_quotes); } - $descendants = self::getChildren($id, $children); + $descendants = array_diff(self::getChildren($id, $children), $deleted); asort($descendants); diff --git a/src/Module/Api/Mastodon/Statuses/Favourite.php b/src/Module/Api/Mastodon/Statuses/Favourite.php index d1a68862c..3543a3ba8 100644 --- a/src/Module/Api/Mastodon/Statuses/Favourite.php +++ b/src/Module/Api/Mastodon/Statuses/Favourite.php @@ -42,13 +42,18 @@ class Favourite extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['id', 'uri-id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } Item::performActivity($item['id'], 'like', $uid); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/FavouritedBy.php b/src/Module/Api/Mastodon/Statuses/FavouritedBy.php index 326e48d82..fcfb97d92 100644 --- a/src/Module/Api/Mastodon/Statuses/FavouritedBy.php +++ b/src/Module/Api/Mastodon/Statuses/FavouritedBy.php @@ -44,11 +44,11 @@ class FavouritedBy extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - if (!$post = Post::selectOriginal(['id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { + if (!$post = Post::selectOriginal(['uri-id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { DI::mstdnError()->RecordNotFound(); } - $activities = Post::selectPosts(['author-id'], ['thr-parent-id' => $post['id'], 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::LIKE, 'deleted' => false]); + $activities = Post::selectPosts(['author-id'], ['thr-parent-id' => $post['uri-id'], 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::LIKE, 'deleted' => false]); $accounts = []; diff --git a/src/Module/Api/Mastodon/Statuses/Mute.php b/src/Module/Api/Mastodon/Statuses/Mute.php index 0c1068490..a99cd6863 100644 --- a/src/Module/Api/Mastodon/Statuses/Mute.php +++ b/src/Module/Api/Mastodon/Statuses/Mute.php @@ -42,7 +42,7 @@ class Mute extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['uri-id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -51,8 +51,13 @@ class Mute extends BaseApi DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be muted')); } - Post\ThreadUser::setIgnored($item['id'], $uid, true); + Post\ThreadUser::setIgnored($item['uri-id'], $uid, true); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Pin.php b/src/Module/Api/Mastodon/Statuses/Pin.php index d092b4255..5d9a18113 100644 --- a/src/Module/Api/Mastodon/Statuses/Pin.php +++ b/src/Module/Api/Mastodon/Statuses/Pin.php @@ -41,13 +41,18 @@ class Pin extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'gravity', 'author-id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['uri-id', 'gravity', 'author-id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } - Post\Collection::add($item['id'], Post\Collection::FEATURED, $item['author-id'], $uid); + Post\Collection::add($item['uri-id'], Post\Collection::FEATURED, $item['author-id'], $uid); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(),$isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Reblog.php b/src/Module/Api/Mastodon/Statuses/Reblog.php index f1922d727..98cbd417d 100644 --- a/src/Module/Api/Mastodon/Statuses/Reblog.php +++ b/src/Module/Api/Mastodon/Statuses/Reblog.php @@ -45,7 +45,7 @@ class Reblog extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'network'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['id', 'uri-id', 'network'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -58,6 +58,11 @@ class Reblog extends BaseApi Item::performActivity($item['id'], 'announce', $uid); } - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/RebloggedBy.php b/src/Module/Api/Mastodon/Statuses/RebloggedBy.php index b225d1743..a12975a8b 100644 --- a/src/Module/Api/Mastodon/Statuses/RebloggedBy.php +++ b/src/Module/Api/Mastodon/Statuses/RebloggedBy.php @@ -44,11 +44,11 @@ class RebloggedBy extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - if (!$post = Post::selectOriginal(['id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { + if (!$post = Post::selectOriginal(['uri-id'], ['uri-id' => $this->parameters['id'], 'uid' => [0, $uid]])) { DI::mstdnError()->RecordNotFound(); } - $activities = Post::selectPosts(['author-id'], ['thr-parent-id' => $post['id'], 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::ANNOUNCE]); + $activities = Post::selectPosts(['author-id'], ['thr-parent-id' => $post['uri-id'], 'gravity' => Item::GRAVITY_ACTIVITY, 'verb' => Activity::ANNOUNCE]); $accounts = []; diff --git a/src/Module/Api/Mastodon/Statuses/Unbookmark.php b/src/Module/Api/Mastodon/Statuses/Unbookmark.php index 4f6db11fd..556db2b4b 100644 --- a/src/Module/Api/Mastodon/Statuses/Unbookmark.php +++ b/src/Module/Api/Mastodon/Statuses/Unbookmark.php @@ -42,7 +42,7 @@ class Unbookmark extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginal(['uid', 'id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]); + $item = Post::selectOriginal(['uid', 'id', 'uri-id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]], ['order' => ['uid' => true]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -52,7 +52,7 @@ class Unbookmark extends BaseApi } if ($item['uid'] == 0) { - $stored = Item::storeForUserByUriId($item['id'], $uid, ['post-reason' => Item::PR_ACTIVITY]); + $stored = Item::storeForUserByUriId($item['uri-id'], $uid, ['post-reason' => Item::PR_ACTIVITY]); if (!empty($stored)) { $item = Post::selectFirst(['id', 'gravity'], ['id' => $stored]); if (!DBA::isResult($item)) { @@ -65,6 +65,11 @@ class Unbookmark extends BaseApi Item::update(['starred' => false], ['id' => $item['id']]); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Unfavourite.php b/src/Module/Api/Mastodon/Statuses/Unfavourite.php index a3760b454..99358be55 100644 --- a/src/Module/Api/Mastodon/Statuses/Unfavourite.php +++ b/src/Module/Api/Mastodon/Statuses/Unfavourite.php @@ -42,13 +42,18 @@ class Unfavourite extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['id', 'uri-id'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } Item::performActivity($item['id'], 'unlike', $uid); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Unmute.php b/src/Module/Api/Mastodon/Statuses/Unmute.php index b7a24beed..b6d9c2b19 100644 --- a/src/Module/Api/Mastodon/Statuses/Unmute.php +++ b/src/Module/Api/Mastodon/Statuses/Unmute.php @@ -42,7 +42,7 @@ class Unmute extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['uri-id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -51,8 +51,13 @@ class Unmute extends BaseApi DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Only starting posts can be unmuted')); } - Post\ThreadUser::setIgnored($item['id'], $uid, false); + Post\ThreadUser::setIgnored($item['uri-id'], $uid, false); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Unpin.php b/src/Module/Api/Mastodon/Statuses/Unpin.php index 523ce4d55..75b1d6fa5 100644 --- a/src/Module/Api/Mastodon/Statuses/Unpin.php +++ b/src/Module/Api/Mastodon/Statuses/Unpin.php @@ -41,13 +41,18 @@ class Unpin extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['uri-id', 'gravity'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } - Post\Collection::remove($item['id'], Post\Collection::FEATURED, $uid); + Post\Collection::remove($item['uri-id'], Post\Collection::FEATURED, $uid); - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Mastodon/Statuses/Unreblog.php b/src/Module/Api/Mastodon/Statuses/Unreblog.php index 54a18823a..6730e0fb5 100644 --- a/src/Module/Api/Mastodon/Statuses/Unreblog.php +++ b/src/Module/Api/Mastodon/Statuses/Unreblog.php @@ -44,7 +44,7 @@ class Unreblog extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - $item = Post::selectOriginalForUser($uid, ['id', 'network'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); + $item = Post::selectOriginalForUser($uid, ['id', 'uri-id', 'network'], ['uri-id' => $this->parameters['id'], 'uid' => [$uid, 0]]); if (!DBA::isResult($item)) { DI::mstdnError()->RecordNotFound(); } @@ -64,6 +64,11 @@ class Unreblog extends BaseApi Item::performActivity($item['id'], 'unannounce', $uid); } - System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes())->toArray()); + // @TODO Remove once mstdnStatus()->createFromUriId is fixed so that it returns posts not reshared posts if given an ID to an original post that has been reshared + // Introduced in this PR: https://github.com/friendica/friendica/pull/13175 + // Issue tracking the behavior of createFromUriId: https://github.com/friendica/friendica/issues/13350 + $isReblog = $item['uri-id'] != $this->parameters['id']; + + System::jsonExit(DI::mstdnStatus()->createFromUriId($this->parameters['id'], $uid, self::appSupportsQuotes(), $isReblog)->toArray()); } } diff --git a/src/Module/Api/Twitter/Lists/Create.php b/src/Module/Api/Twitter/Lists/Create.php index f7612d32f..1f2f63882 100644 --- a/src/Module/Api/Twitter/Lists/Create.php +++ b/src/Module/Api/Twitter/Lists/Create.php @@ -24,34 +24,34 @@ namespace Friendica\Module\Api\Twitter\Lists; use Friendica\App; use Friendica\Core\L10n; use Friendica\Database\Database; -use Friendica\Factory\Api\Friendica\Group as FriendicaGroup; +use Friendica\Factory\Api\Friendica\Circle as FriendicaCircle; use Friendica\Module\BaseApi; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\Api\ApiResponse; use Friendica\Network\HTTPException; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; /** - * Update information about a group. + * Update information about a circle. * * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update */ class Create extends BaseApi { - /** @var friendicaGroup */ - private $friendicaGroup; + /** @var FriendicaCircle */ + private $friendicaCircle; /** @var Database */ private $dba; - public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) + public function __construct(Database $dba, FriendicaCircle $friendicaCircle, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) { parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->dba = $dba; - $this->friendicaGroup = $friendicaGroup; + $this->dba = $dba; + $this->friendicaCircle = $friendicaCircle; } protected function rawContent(array $request = []) @@ -63,22 +63,22 @@ class Create extends BaseApi $name = $this->getRequestValue($request, 'name', ''); if ($name == '') { - throw new HTTPException\BadRequestException('group name not specified'); + throw new HTTPException\BadRequestException('circle name not specified'); } - // error message if specified group name already exists + // error message if specified circle name already exists if ($this->dba->exists('group', ['uid' => $uid, 'name' => $name, 'deleted' => false])) { - throw new HTTPException\BadRequestException('group name already exists'); + throw new HTTPException\BadRequestException('circle name already exists'); } - $ret = Group::create($uid, $name); + $ret = Circle::create($uid, $name); if ($ret) { - $gid = Group::getIdByName($uid, $name); + $gid = Circle::getIdByName($uid, $name); } else { throw new HTTPException\BadRequestException('other API error'); } - $grp = $this->friendicaGroup->createFromId($gid); + $grp = $this->friendicaCircle->createFromId($gid); $this->response->exit('statuses', ['lists' => ['lists' => $grp]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); } diff --git a/src/Module/Api/Twitter/Lists/Destroy.php b/src/Module/Api/Twitter/Lists/Destroy.php index 6a4e2eab8..0214e3ff6 100644 --- a/src/Module/Api/Twitter/Lists/Destroy.php +++ b/src/Module/Api/Twitter/Lists/Destroy.php @@ -24,34 +24,34 @@ namespace Friendica\Module\Api\Twitter\Lists; use Friendica\App; use Friendica\Core\L10n; use Friendica\Database\Database; -use Friendica\Factory\Api\Friendica\Group as FriendicaGroup; +use Friendica\Factory\Api\Friendica\Circle as FriendicaCirle; use Friendica\Module\BaseApi; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\Api\ApiResponse; use Friendica\Network\HTTPException; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; /** - * Delete a group. + * Delete a circle. * * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-destroy */ class Destroy extends BaseApi { - /** @var friendicaGroup */ - private $friendicaGroup; + /** @var FriendicaCirle */ + private $friendicaCircle; /** @var Database */ private $dba; - public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) + public function __construct(Database $dba, FriendicaCirle $friendicaCircle, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) { parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->dba = $dba; - $this->friendicaGroup = $friendicaGroup; + $this->dba = $dba; + $this->friendicaCircle = $friendicaCircle; } protected function rawContent(array $request = []) @@ -67,16 +67,16 @@ class Destroy extends BaseApi throw new HTTPException\BadRequestException('gid not specified'); } - // get data of the specified group id - $group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]); + // get data of the specified circle id + $circle = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]); // error message if specified gid is not in database - if (!$group) { + if (!$circle) { throw new HTTPException\BadRequestException('gid not available'); } - $list = $this->friendicaGroup->createFromId($gid); + $list = $this->friendicaCircle->createFromId($gid); - if (Group::remove($gid)) { + if (Circle::remove($gid)) { $this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); } } diff --git a/src/Module/Api/Twitter/Lists/Ownership.php b/src/Module/Api/Twitter/Lists/Ownership.php index 6ecd58689..2a1ea5ac6 100644 --- a/src/Module/Api/Twitter/Lists/Ownership.php +++ b/src/Module/Api/Twitter/Lists/Ownership.php @@ -24,7 +24,7 @@ namespace Friendica\Module\Api\Twitter\Lists; use Friendica\App; use Friendica\Core\L10n; use Friendica\Database\Database; -use Friendica\Factory\Api\Friendica\Group as FriendicaGroup; +use Friendica\Factory\Api\Friendica\Circle as FriendicaCircle; use Friendica\Module\BaseApi; use Friendica\Model\Contact; use Friendica\Module\Api\ApiResponse; @@ -32,36 +32,36 @@ use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; /** - * Returns all groups the user owns. + * Returns all circles the user owns. * * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships */ class Ownership extends BaseApi { - /** @var friendicaGroup */ - private $friendicaGroup; + /** @var FriendicaCircle */ + private $friendicaCircle; /** @var Database */ private $dba; - public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) + public function __construct(Database $dba, FriendicaCircle $friendicaCircle, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) { parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->dba = $dba; - $this->friendicaGroup = $friendicaGroup; + $this->dba = $dba; + $this->friendicaCircle = $friendicaCircle; } protected function rawContent(array $request = []) { BaseApi::checkAllowedScope(BaseApi::SCOPE_READ); $uid = BaseApi::getCurrentUserID(); - $groups = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]); + $circles = $this->dba->select('group', [], ['deleted' => false, 'uid' => $uid, 'cid' => null]); - // loop through all groups + // loop through all circles $lists = []; - foreach ($groups as $group) { - $lists[] = $this->friendicaGroup->createFromId($group['id']); + foreach ($circles as $circle) { + $lists[] = $this->friendicaCircle->createFromId($circle['id']); } $this->response->exit('statuses', ['lists' => ['lists' => $lists]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); diff --git a/src/Module/Api/Twitter/Lists/Statuses.php b/src/Module/Api/Twitter/Lists/Statuses.php index 4f64a54e8..7d159c498 100644 --- a/src/Module/Api/Twitter/Lists/Statuses.php +++ b/src/Module/Api/Twitter/Lists/Statuses.php @@ -36,7 +36,7 @@ use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; /** - * Returns recent statuses from users in the specified group. + * Returns recent statuses from users in the specified circle. * * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/get-lists-ownerships */ @@ -76,9 +76,9 @@ class Statuses extends BaseApi $start = max(0, ($page - 1) * $count); - $groups = $this->dba->selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]); - $gids = array_column($groups, 'contact-id'); - $condition = ['uid' => $uid, 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT], 'contact-id' => $gids]; + $members = $this->dba->selectToArray('group_member', ['contact-id'], ['gid' => $request['list_id']]); + $cids = array_column($members, 'contact-id'); + $condition = ['uid' => $uid, 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT], 'contact-id' => $cids]; $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $since_id]); if ($max_id > 0) { diff --git a/src/Module/Api/Twitter/Lists/Update.php b/src/Module/Api/Twitter/Lists/Update.php index d6748d72e..6a925eeda 100644 --- a/src/Module/Api/Twitter/Lists/Update.php +++ b/src/Module/Api/Twitter/Lists/Update.php @@ -24,34 +24,34 @@ namespace Friendica\Module\Api\Twitter\Lists; use Friendica\App; use Friendica\Core\L10n; use Friendica\Database\Database; -use Friendica\Factory\Api\Friendica\Group as FriendicaGroup; +use Friendica\Factory\Api\Friendica\Circle as FriendicaCircle; use Friendica\Module\BaseApi; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Module\Api\ApiResponse; use Friendica\Network\HTTPException; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; /** - * Update information about a group. + * Update information about a circle. * * @see https://developer.twitter.com/en/docs/accounts-and-users/create-manage-lists/api-reference/post-lists-update */ class Update extends BaseApi { - /** @var friendicaGroup */ - private $friendicaGroup; + /** @var FriendicaCircle */ + private $friendicaCircle; /** @var Database */ private $dba; - public function __construct(Database $dba, FriendicaGroup $friendicaGroup, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) + public function __construct(Database $dba, FriendicaCircle $friendicaCircle, App $app, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, ApiResponse $response, array $server, array $parameters = []) { parent::__construct($app, $l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - $this->dba = $dba; - $this->friendicaGroup = $friendicaGroup; + $this->dba = $dba; + $this->friendicaCircle = $friendicaCircle; } protected function rawContent(array $request = []) @@ -68,15 +68,15 @@ class Update extends BaseApi throw new HTTPException\BadRequestException('gid not specified'); } - // get data of the specified group id - $group = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]); + // get data of the specified circle id + $circle = $this->dba->selectFirst('group', [], ['uid' => $uid, 'id' => $gid]); // error message if specified gid is not in database - if (!$group) { + if (!$circle) { throw new HTTPException\BadRequestException('gid not available'); } - if (Group::update($gid, $name)) { - $list = $this->friendicaGroup->createFromId($gid); + if (Circle::update($gid, $name)) { + $list = $this->friendicaCircle->createFromId($gid); $this->response->exit('statuses', ['lists' => ['lists' => $list]], $this->parameters['extension'] ?? null, Contact::getPublicIdByUserId($uid)); } diff --git a/src/Module/Api/Twitter/Statuses/Update.php b/src/Module/Api/Twitter/Statuses/Update.php index df51ff8a8..397e3bbd2 100644 --- a/src/Module/Api/Twitter/Statuses/Update.php +++ b/src/Module/Api/Twitter/Statuses/Update.php @@ -62,9 +62,9 @@ class Update extends BaseApi 'source' => '', 'include_entities' => false, 'contact_allow' => $owner['allow_cid'], - 'group_allow' => $owner['allow_gid'], + 'circle_allow' => $owner['allow_gid'], 'contact_deny' => $owner['deny_cid'], - 'group_deny' => $owner['deny_gid'], + 'circle_deny' => $owner['deny_gid'], ], $request); if (!empty($request['htmlstatus'])) { @@ -102,9 +102,9 @@ class Update extends BaseApi $aclFormatter = DI::aclFormatter(); $item['allow_cid'] = $aclFormatter->toString($request['contact_allow']); - $item['allow_gid'] = $aclFormatter->toString($request['group_allow']); + $item['allow_gid'] = $aclFormatter->toString($request['circle_allow']); $item['deny_cid'] = $aclFormatter->toString($request['contact_deny']); - $item['deny_gid'] = $aclFormatter->toString($request['group_deny']); + $item['deny_gid'] = $aclFormatter->toString($request['circle_deny']); if (!empty($item['allow_cid'] . $item['allow_gid'] . $item['deny_cid'] . $item['deny_gid'])) { $item['private'] = Item::PRIVATE; diff --git a/src/Module/BaseModeration.php b/src/Module/BaseModeration.php index 3de46b319..a575e51f7 100644 --- a/src/Module/BaseModeration.php +++ b/src/Module/BaseModeration.php @@ -82,12 +82,12 @@ abstract class BaseModeration extends BaseModule } } - if (!$this->app->isSiteAdmin()) { - throw new HTTPException\ForbiddenException($this->t('You don\'t have access to administration pages.')); + if (!$this->session->isModerator()) { + throw new HTTPException\ForbiddenException($this->t('You don\'t have access to moderation pages.')); } if ($this->session->getSubManagedUserId()) { - throw new HTTPException\ForbiddenException($this->t('Submanaged account can\'t access the administration pages. Please log back in as the main account.')); + throw new HTTPException\ForbiddenException($this->t('Submanaged account can\'t access the moderation pages. Please log back in as the main account.')); } } diff --git a/src/Module/BaseSearch.php b/src/Module/BaseSearch.php index 262ec94a2..4a25b71a5 100644 --- a/src/Module/BaseSearch.php +++ b/src/Module/BaseSearch.php @@ -71,8 +71,8 @@ class BaseSearch extends BaseModule $header = DI::l10n()->t('People Search - %s', $search); } elseif (strpos($search, '!') === 0) { $search = trim(substr($search, 1)); - $type = Search::TYPE_FORUM; - $header = DI::l10n()->t('Forum Search - %s', $search); + $type = Search::TYPE_GROUP; + $header = DI::l10n()->t('Group Search - %s', $search); } $search = Network::convertToIdn($search); @@ -98,7 +98,7 @@ class BaseSearch extends BaseModule } if (!$results->getTotal()) { - $results = Search::getContactsFromProbe(Network::convertToIdn($search), $type == Search::TYPE_FORUM); + $results = Search::getContactsFromProbe(Network::convertToIdn($search), $type == Search::TYPE_GROUP); } return self::printResult($results, $pager, $header); @@ -151,4 +151,4 @@ class BaseSearch extends BaseModule '$paginate' => $pager->renderFull($results->getTotal()), ]); } -} \ No newline at end of file +} diff --git a/src/Module/BaseSettings.php b/src/Module/BaseSettings.php index a1e88e9a1..4b26a0f26 100644 --- a/src/Module/BaseSettings.php +++ b/src/Module/BaseSettings.php @@ -151,6 +151,13 @@ class BaseSettings extends BaseModule 'accesskey' => 'b', ]; + $tabs[] = [ + 'label' => $this->t('Remote servers'), + 'url' => 'settings/server', + 'selected' => static::class == Settings\Server\Index::class ? 'active' : '', + 'accesskey' => 's', + ]; + $tabs[] = [ 'label' => $this->t('Export personal data'), 'url' => 'settings/userexport', diff --git a/src/Module/Calendar/Event/API.php b/src/Module/Calendar/Event/API.php index acb2dd4ea..e8fce8ed7 100644 --- a/src/Module/Calendar/Event/API.php +++ b/src/Module/Calendar/Event/API.php @@ -212,14 +212,14 @@ class API extends BaseModule } $strAclContactAllow = isset($request['contact_allow']) ? $aclFormatter->toString($request['contact_allow']) : $user['allow_cid'] ?? ''; - $strAclGroupAllow = isset($request['group_allow']) ? $aclFormatter->toString($request['group_allow']) : $user['allow_gid'] ?? ''; - $strContactDeny = isset($request['contact_deny']) ? $aclFormatter->toString($request['contact_deny']) : $user['deny_cid'] ?? ''; - $strGroupDeny = isset($request['group_deny']) ? $aclFormatter->toString($request['group_deny']) : $user['deny_gid'] ?? ''; + $strAclCircleAllow = isset($request['circle_allow']) ? $aclFormatter->toString($request['circle_allow']) : $user['allow_gid'] ?? ''; + $strContactDeny = isset($request['contact_deny']) ? $aclFormatter->toString($request['contact_deny']) : $user['deny_cid'] ?? ''; + $strCircleDeny = isset($request['circle_deny']) ? $aclFormatter->toString($request['circle_deny']) : $user['deny_gid'] ?? ''; $visibility = $request['visibility'] ?? ''; if ($visibility === 'public') { // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected - $strAclContactAllow = $strAclGroupAllow = $strContactDeny = $strGroupDeny = ''; + $strAclContactAllow = $strAclCircleAllow = $strContactDeny = $strCircleDeny = ''; } elseif ($visibility === 'custom') { // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL // case that would make it public. So we always append the author's contact id to the allowed contacts. @@ -228,9 +228,9 @@ class API extends BaseModule } } else { $strAclContactAllow = $aclFormatter->toString($self); - $strAclGroupAllow = ''; + $strAclCircleAllow = ''; $strContactDeny = ''; - $strGroupDeny = ''; + $strCircleDeny = ''; } $datarray = [ @@ -244,9 +244,9 @@ class API extends BaseModule 'uid' => $uid, 'cid' => $cid, 'allow_cid' => $strAclContactAllow, - 'allow_gid' => $strAclGroupAllow, + 'allow_gid' => $strAclCircleAllow, 'deny_cid' => $strContactDeny, - 'deny_gid' => $strGroupDeny, + 'deny_gid' => $strCircleDeny, 'id' => $eventId, ]; diff --git a/src/Module/Group.php b/src/Module/Circle.php similarity index 56% rename from src/Module/Group.php rename to src/Module/Circle.php index 78b49d993..a51583ae9 100644 --- a/src/Module/Group.php +++ b/src/Module/Circle.php @@ -22,13 +22,14 @@ namespace Friendica\Module; use Friendica\BaseModule; +use Friendica\Content\Widget; use Friendica\Core\Renderer; use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model; -class Group extends BaseModule +class Circle extends BaseModule { protected function post(array $request = []) { @@ -43,34 +44,34 @@ class Group extends BaseModule // @TODO: Replace with parameter from router if ((DI::args()->getArgc() == 2) && (DI::args()->getArgv()[1] === 'new')) { - BaseModule::checkFormSecurityTokenRedirectOnError('/group/new', 'group_edit'); + BaseModule::checkFormSecurityTokenRedirectOnError('/circle/new', 'circle_edit'); - $name = trim($request['groupname']); - $r = Model\Group::create(DI::userSession()->getLocalUserId(), $name); + $name = trim($request['circle_name']); + $r = Model\Circle::create(DI::userSession()->getLocalUserId(), $name); if ($r) { - $r = Model\Group::getIdByName(DI::userSession()->getLocalUserId(), $name); + $r = Model\Circle::getIdByName(DI::userSession()->getLocalUserId(), $name); if ($r) { - DI::baseUrl()->redirect('group/' . $r); + DI::baseUrl()->redirect('circle/' . $r); } } else { - DI::sysmsg()->addNotice(DI::l10n()->t('Could not create group.')); + DI::sysmsg()->addNotice(DI::l10n()->t('Could not create circle.')); } - DI::baseUrl()->redirect('group'); + DI::baseUrl()->redirect('circle'); } // @TODO: Replace with parameter from router if ((DI::args()->getArgc() == 2) && intval(DI::args()->getArgv()[1])) { - BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_edit'); + BaseModule::checkFormSecurityTokenRedirectOnError('/circle', 'circle_edit'); - $group = DBA::selectFirst('group', ['id', 'name'], ['id' => DI::args()->getArgv()[1], 'uid' => DI::userSession()->getLocalUserId()]); - if (!DBA::isResult($group)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Group not found.')); + $circle = DBA::selectFirst('group', ['id', 'name'], ['id' => DI::args()->getArgv()[1], 'uid' => DI::userSession()->getLocalUserId()]); + if (!DBA::isResult($circle)) { + DI::sysmsg()->addNotice(DI::l10n()->t('Circle not found.')); DI::baseUrl()->redirect('contact'); } - $groupname = trim($_POST['groupname']); - if (strlen($groupname) && ($groupname != $group['name'])) { - if (!Model\Group::update($group['id'], $groupname)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Group name was not changed.')); + $circlename = trim($_POST['circle_name']); + if (strlen($circlename) && ($circlename != $circle['name'])) { + if (!Model\Circle::update($circle['id'], $circlename)) { + DI::sysmsg()->addNotice(DI::l10n()->t('Circle name was not changed.')); } } } @@ -84,11 +85,11 @@ class Group extends BaseModule } if (isset($this->parameters['command'])) { - $group_id = $this->parameters['group']; + $circle_id = $this->parameters['circle']; $contact_id = $this->parameters['contact']; - if (!Model\Group::exists($group_id, DI::userSession()->getLocalUserId())) { - throw new \Exception(DI::l10n()->t('Unknown group.'), 404); + if (!Model\Circle::exists($circle_id, DI::userSession()->getLocalUserId())) { + throw new \Exception(DI::l10n()->t('Unknown circle.'), 404); } // @TODO Backward compatibility with user contacts, remove by version 2022.03 @@ -112,18 +113,18 @@ class Group extends BaseModule switch($this->parameters['command']) { case 'add': - if (!Model\Group::addMember($group_id, $cdata['user'])) { - throw new \Exception(DI::l10n()->t('Unable to add the contact to the group.'), 500); + if (!Model\Circle::addMember($circle_id, $cdata['user'])) { + throw new \Exception(DI::l10n()->t('Unable to add the contact to the circle.'), 500); } - $message = DI::l10n()->t('Contact successfully added to group.'); + $message = DI::l10n()->t('Contact successfully added to circle.'); break; case 'remove': - if (!Model\Group::removeMember($group_id, $cdata['user'])) { - throw new \Exception(DI::l10n()->t('Unable to remove the contact from the group.'), 500); + if (!Model\Circle::removeMember($circle_id, $cdata['user'])) { + throw new \Exception(DI::l10n()->t('Unable to remove the contact from the circle.'), 500); } - $message = DI::l10n()->t('Contact successfully removed from group.'); + $message = DI::l10n()->t('Contact successfully removed from circle.'); break; } } else { @@ -146,58 +147,58 @@ class Group extends BaseModule throw new \Friendica\Network\HTTPException\ForbiddenException(); } - $a = DI::app(); + DI::page()['aside'] = Model\Circle::sidebarWidget('contact', 'circle', 'extended', ((DI::args()->getArgc() > 1) ? DI::args()->getArgv()[1] : 'everyone')); - DI::page()['aside'] = Model\Group::sidebarWidget('contact', 'group', 'extended', ((DI::args()->getArgc() > 1) ? DI::args()->getArgv()[1] : 'everyone')); - - // With no group number provided we jump to the unassigned contacts as a starting point + // With no circle number provided we jump to the unassigned contacts as a starting point // @TODO: Replace with parameter from router if (DI::args()->getArgc() == 1) { - DI::baseUrl()->redirect('group/none'); + DI::baseUrl()->redirect('circle/none'); } - // Switch to text mode interface if we have more than 'n' contacts or group members - $switchtotext = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'groupedit_image_limit'); + // Switch to text mode interface if we have more than 'n' contacts or circle members + $switchtotext = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'circle_edit_image_limit') ?? + DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'groupedit_image_limit'); if (is_null($switchtotext)) { - $switchtotext = DI::config()->get('system', 'groupedit_image_limit', 200); + $switchtotext = DI::config()->get('system', 'groupedit_image_limit') ?? + DI::config()->get('system', 'circle_edit_image_limit'); } - $tpl = Renderer::getMarkupTemplate('group_edit.tpl'); + $tpl = Renderer::getMarkupTemplate('circle_edit.tpl'); $context = [ - '$submit' => DI::l10n()->t('Save Group'), + '$submit' => DI::l10n()->t('Save Circle'), '$submit_filter' => DI::l10n()->t('Filter'), ]; // @TODO: Replace with parameter from router if ((DI::args()->getArgc() == 2) && (DI::args()->getArgv()[1] === 'new')) { return Renderer::replaceMacros($tpl, $context + [ - '$title' => DI::l10n()->t('Create a group of contacts/friends.'), - '$gname' => ['groupname', DI::l10n()->t('Group Name: '), '', ''], + '$title' => DI::l10n()->t('Create a circle of contacts/friends.'), + '$gname' => ['circle_name', DI::l10n()->t('Circle Name: '), '', ''], '$gid' => 'new', - '$form_security_token' => BaseModule::getFormSecurityToken("group_edit"), + '$form_security_token' => BaseModule::getFormSecurityToken('circle_edit'), ]); } - $nogroup = false; + $nocircle = false; // @TODO: Replace with parameter from router if ((DI::args()->getArgc() == 2) && (DI::args()->getArgv()[1] === 'none') || - (DI::args()->getArgc() == 1) && (DI::args()->getArgv()[0] === 'nogroup')) { + (DI::args()->getArgc() == 1) && (DI::args()->getArgv()[0] === 'nocircle')) { $id = -1; - $nogroup = true; - $group = [ + $nocircle = true; + $circle = [ 'id' => $id, - 'name' => DI::l10n()->t('Contacts not in any group'), + 'name' => DI::l10n()->t('Contacts not in any circle'), ]; $members = []; $preselected = []; $context = $context + [ - '$title' => $group['name'], - '$gname' => ['groupname', DI::l10n()->t('Group Name: '), $group['name'], ''], + '$title' => $circle['name'], + '$gname' => ['circle_name', DI::l10n()->t('Circle Name: '), $circle['name'], ''], '$gid' => $id, '$editable' => 0, ]; @@ -205,25 +206,25 @@ class Group extends BaseModule // @TODO: Replace with parameter from router if ((DI::args()->getArgc() == 3) && (DI::args()->getArgv()[1] === 'drop')) { - BaseModule::checkFormSecurityTokenRedirectOnError('/group', 'group_drop', 't'); + BaseModule::checkFormSecurityTokenRedirectOnError('/circle', 'circle_drop', 't'); // @TODO: Replace with parameter from router if (intval(DI::args()->getArgv()[2])) { - if (!Model\Group::exists(DI::args()->getArgv()[2], DI::userSession()->getLocalUserId())) { - DI::sysmsg()->addNotice(DI::l10n()->t('Group not found.')); + if (!Model\Circle::exists(DI::args()->getArgv()[2], DI::userSession()->getLocalUserId())) { + DI::sysmsg()->addNotice(DI::l10n()->t('Circle not found.')); DI::baseUrl()->redirect('contact'); } - if (!Model\Group::remove(DI::args()->getArgv()[2])) { - DI::sysmsg()->addNotice(DI::l10n()->t('Unable to remove group.')); + if (!Model\Circle::remove(DI::args()->getArgv()[2])) { + DI::sysmsg()->addNotice(DI::l10n()->t('Unable to remove circle.')); } } - DI::baseUrl()->redirect('group'); + DI::baseUrl()->redirect('circle'); } // @TODO: Replace with parameter from router if ((DI::args()->getArgc() > 2) && intval(DI::args()->getArgv()[1]) && intval(DI::args()->getArgv()[2])) { - BaseModule::checkFormSecurityTokenForbiddenOnError('group_member_change', 't'); + BaseModule::checkFormSecurityTokenForbiddenOnError('circle_member_change', 't'); if (DBA::exists('contact', ['id' => DI::args()->getArgv()[2], 'uid' => DI::userSession()->getLocalUserId(), 'self' => false, 'pending' => false, 'blocked' => false])) { $change = intval(DI::args()->getArgv()[2]); @@ -232,13 +233,13 @@ class Group extends BaseModule // @TODO: Replace with parameter from router if ((DI::args()->getArgc() > 1) && intval(DI::args()->getArgv()[1])) { - $group = DBA::selectFirst('group', ['id', 'name'], ['id' => DI::args()->getArgv()[1], 'uid' => DI::userSession()->getLocalUserId(), 'deleted' => false]); - if (!DBA::isResult($group)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Group not found.')); + $circle = DBA::selectFirst('group', ['id', 'name'], ['id' => DI::args()->getArgv()[1], 'uid' => DI::userSession()->getLocalUserId(), 'deleted' => false]); + if (!DBA::isResult($circle)) { + DI::sysmsg()->addNotice(DI::l10n()->t('Circle not found.')); DI::baseUrl()->redirect('contact'); } - $members = Model\Contact\Group::getById($group['id']); + $members = Model\Contact\Circle::getById($circle['id']); $preselected = []; if (count($members)) { @@ -249,12 +250,12 @@ class Group extends BaseModule if ($change) { if (in_array($change, $preselected)) { - Model\Group::removeMember($group['id'], $change); + Model\Circle::removeMember($circle['id'], $change); } else { - Model\Group::addMember($group['id'], $change); + Model\Circle::addMember($circle['id'], $change); } - $members = Model\Contact\Group::getById($group['id']); + $members = Model\Contact\Circle::getById($circle['id']); $preselected = []; if (count($members)) { foreach ($members as $member) { @@ -263,104 +264,106 @@ class Group extends BaseModule } } - $drop_tpl = Renderer::getMarkupTemplate('group_drop.tpl'); + $drop_tpl = Renderer::getMarkupTemplate('circle_drop.tpl'); $drop_txt = Renderer::replaceMacros($drop_tpl, [ - '$id' => $group['id'], - '$delete' => DI::l10n()->t('Delete Group'), - '$form_security_token' => BaseModule::getFormSecurityToken("group_drop"), + '$id' => $circle['id'], + '$delete' => DI::l10n()->t('Delete Circle'), + '$form_security_token' => BaseModule::getFormSecurityToken('circle_drop'), ]); $context = $context + [ - '$title' => $group['name'], - '$gname' => ['groupname', DI::l10n()->t('Group Name: '), $group['name'], ''], - '$gid' => $group['id'], + '$title' => $circle['name'], + '$gname' => ['circle_name', DI::l10n()->t('Circle Name: '), $circle['name'], ''], + '$gid' => $circle['id'], '$drop' => $drop_txt, - '$form_security_token' => BaseModule::getFormSecurityToken('group_edit'), - '$edit_name' => DI::l10n()->t('Edit Group Name'), + '$form_security_token' => BaseModule::getFormSecurityToken('circle_edit'), + '$edit_name' => DI::l10n()->t('Edit Circle Name'), '$editable' => 1, ]; } - if (!isset($group)) { + if (!isset($circle)) { throw new \Friendica\Network\HTTPException\BadRequestException(); } - $groupeditor = [ + $circle_editor = [ 'label_members' => DI::l10n()->t('Members'), 'members' => [], 'label_contacts' => DI::l10n()->t('All Contacts'), - 'group_is_empty' => DI::l10n()->t('Group is empty'), + 'circle_is_empty' => DI::l10n()->t('Circle is empty'), 'contacts' => [], ]; - $sec_token = addslashes(BaseModule::getFormSecurityToken('group_member_change')); + $sec_token = addslashes(BaseModule::getFormSecurityToken('circle_member_change')); - // Format the data of the group members + // Format the data of the circle members foreach ($members as $member) { if ($member['url']) { $entry = Contact::getContactTemplateVars($member); $entry['label'] = 'members'; $entry['photo_menu'] = ''; $entry['change_member'] = [ - 'title' => DI::l10n()->t("Remove contact from group"), - 'gid' => $group['id'], + 'title' => DI::l10n()->t('Remove contact from circle'), + 'gid' => $circle['id'], 'cid' => $member['id'], 'sec_token' => $sec_token ]; - $groupeditor['members'][] = $entry; + $circle_editor['members'][] = $entry; } else { - Model\Group::removeMember($group['id'], $member['id']); + Model\Circle::removeMember($circle['id'], $member['id']); } } - if ($nogroup) { - $contacts = Model\Contact\Group::listUngrouped(DI::userSession()->getLocalUserId()); + if ($nocircle) { + $contacts = Model\Contact\Circle::listUncircled(DI::userSession()->getLocalUserId()); } else { - $contacts_stmt = DBA::select('contact', [], - ['rel' => [Model\Contact::FOLLOWER, Model\Contact::FRIEND, Model\Contact::SHARING], - 'uid' => DI::userSession()->getLocalUserId(), 'pending' => false, 'blocked' => false, 'failed' => false, 'self' => false], - ['order' => ['name']] - ); + $networks = Widget::unavailableNetworks(); + $query = "`uid` = ? AND NOT `self` AND NOT `deleted` AND NOT `blocked` AND NOT `pending` AND NOT `failed` + AND `rel` IN (?, ?, ?) + AND NOT `network` IN (" . substr(str_repeat('?, ', count($networks)), 0, -2) . ")"; + $condition = array_merge([$query], [DI::userSession()->getLocalUserId(), Model\Contact::FOLLOWER, Model\Contact::FRIEND, Model\Contact::SHARING], $networks); + + $contacts_stmt = DBA::select('contact', [], $condition, ['order' => ['name']]); $contacts = DBA::toArray($contacts_stmt); $context['$desc'] = DI::l10n()->t('Click on a contact to add or remove.'); } if (DBA::isResult($contacts)) { - // Format the data of the contacts who aren't in the contact group + // Format the data of the contacts who aren't in the contact circle foreach ($contacts as $member) { if (!in_array($member['id'], $preselected)) { $entry = Contact::getContactTemplateVars($member); $entry['label'] = 'contacts'; - if (!$nogroup) + if (!$nocircle) $entry['photo_menu'] = []; - if (!$nogroup) { + if (!$nocircle) { $entry['change_member'] = [ - 'title' => DI::l10n()->t("Add contact to group"), - 'gid' => $group['id'], + 'title' => DI::l10n()->t('Add contact to circle'), + 'gid' => $circle['id'], 'cid' => $member['id'], 'sec_token' => $sec_token ]; } - $groupeditor['contacts'][] = $entry; + $circle_editor['contacts'][] = $entry; } } } - $context['$groupeditor'] = $groupeditor; + $context['$circle_editor'] = $circle_editor; // If there are to many contacts we could provide an alternative view mode - $total = count($groupeditor['members']) + count($groupeditor['contacts']); + $total = count($circle_editor['members']) + count($circle_editor['contacts']); $context['$shortmode'] = (($switchtotext && ($total > $switchtotext)) ? true : false); if ($change) { - $tpl = Renderer::getMarkupTemplate('groupeditor.tpl'); + $tpl = Renderer::getMarkupTemplate('circle_editor.tpl'); echo Renderer::replaceMacros($tpl, $context); System::exit(); } return Renderer::replaceMacros($tpl, $context); } -} \ No newline at end of file +} diff --git a/src/Module/Contact.php b/src/Module/Contact.php index a70db0234..6e480c193 100644 --- a/src/Module/Contact.php +++ b/src/Module/Contact.php @@ -191,7 +191,7 @@ class Contact extends BaseModule $search = trim($_GET['search'] ?? ''); $nets = trim($_GET['nets'] ?? ''); $rel = trim($_GET['rel'] ?? ''); - $group = trim($_GET['group'] ?? ''); + $circle = trim($_GET['circle'] ?? ''); $accounttype = $_GET['accounttype'] ?? ''; $accounttypeid = User::getAccountTypeByString($accounttype); @@ -211,16 +211,15 @@ class Contact extends BaseModule $follow_widget = Widget::follow(); } - $account_widget = Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype); + $account_widget = Widget::accountTypes($_SERVER['REQUEST_URI'], $accounttype); $networks_widget = Widget::networks($_SERVER['REQUEST_URI'], $nets); - $rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel); - $groups_widget = Widget::groups($_SERVER['REQUEST_URI'], $group); + $rel_widget = Widget::contactRels($_SERVER['REQUEST_URI'], $rel); + $circles_widget = Widget::circles($_SERVER['REQUEST_URI'], $circle); - DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $rel_widget . $groups_widget . $networks_widget . $account_widget; + DI::page()['aside'] .= $vcard_widget . $findpeople_widget . $follow_widget . $rel_widget . $circles_widget . $networks_widget . $account_widget; $tpl = Renderer::getMarkupTemplate('contacts-head.tpl'); - DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, [ - ]); + DI::page()['htmlhead'] .= Renderer::replaceMacros($tpl, []); $o = ''; Nav::setSelected('contact'); @@ -304,11 +303,19 @@ class Contact extends BaseModule $sql_extra .= " AND `rel` = ?"; $sql_values[] = Model\Contact::FRIEND; break; + case 'nothing': + $sql_extra .= " AND `rel` = ?"; + $sql_values[] = Model\Contact::NOTHING; + break; + default: + $sql_extra .= " AND `rel` != ?"; + $sql_values[] = Model\Contact::NOTHING; + break; } - if ($group) { + if ($circle) { $sql_extra .= " AND `id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?)"; - $sql_values[] = $group; + $sql_values[] = $circle; } $networks = Widget::unavailableNetworks(); @@ -391,11 +398,11 @@ class Contact extends BaseModule 'accesskey' => 'h', ], [ - 'label' => DI::l10n()->t('Groups'), - 'url' => 'group', + 'label' => DI::l10n()->t('Circles'), + 'url' => 'circle', 'sel' => '', - 'title' => DI::l10n()->t('Organize your contact groups'), - 'id' => 'contactgroups-tab', + 'title' => DI::l10n()->t('Organize your contact circles'), + 'id' => 'contactcircles-tab', 'accesskey' => 'e', ], ]; @@ -404,19 +411,41 @@ class Contact extends BaseModule $tabs_html = Renderer::replaceMacros($tabs_tpl, ['$tabs' => $tabs]); switch ($rel) { - case 'followers': $header = DI::l10n()->t('Followers'); break; - case 'following': $header = DI::l10n()->t('Following'); break; - case 'mutuals': $header = DI::l10n()->t('Mutual friends'); break; - default: $header = DI::l10n()->t('Contacts'); + case 'followers': + $header = DI::l10n()->t('Followers'); + break; + case 'following': + $header = DI::l10n()->t('Following'); + break; + case 'mutuals': + $header = DI::l10n()->t('Mutual friends'); + break; + case 'nothing': + $header = DI::l10n()->t('No relationship'); + break; + default: + $header = DI::l10n()->t('Contacts'); } switch ($type) { - case 'pending': $header .= ' - ' . DI::l10n()->t('Pending'); break; - case 'blocked': $header .= ' - ' . DI::l10n()->t('Blocked'); break; - case 'hidden': $header .= ' - ' . DI::l10n()->t('Hidden'); break; - case 'ignored': $header .= ' - ' . DI::l10n()->t('Ignored'); break; - case 'collapsed': $header .= ' - ' . DI::l10n()->t('Collapsed'); break; - case 'archived': $header .= ' - ' . DI::l10n()->t('Archived'); break; + case 'pending': + $header .= ' - ' . DI::l10n()->t('Pending'); + break; + case 'blocked': + $header .= ' - ' . DI::l10n()->t('Blocked'); + break; + case 'hidden': + $header .= ' - ' . DI::l10n()->t('Hidden'); + break; + case 'ignored': + $header .= ' - ' . DI::l10n()->t('Ignored'); + break; + case 'collapsed': + $header .= ' - ' . DI::l10n()->t('Collapsed'); + break; + case 'archived': + $header .= ' - ' . DI::l10n()->t('Archived'); + break; } $header .= $nets ? ' - ' . ContactSelector::networkToName($nets) : ''; @@ -503,7 +532,8 @@ class Contact extends BaseModule 'id' => 'media-tab', 'accesskey' => 'd', ], - ['label' => DI::l10n()->t('Contacts'), + [ + 'label' => DI::l10n()->t('Contacts'), 'url' => 'contact/' . $pcid . '/contacts', 'sel' => (($active_tab == self::TAB_CONTACTS) ? 'active' : ''), 'title' => DI::l10n()->t('View all known contacts'), @@ -513,7 +543,8 @@ class Contact extends BaseModule ]; if (!empty($contact['network']) && in_array($contact['network'], [Protocol::FEED, Protocol::MAIL]) && ($cid != $pcid)) { - $tabs[] = ['label' => DI::l10n()->t('Advanced'), + $tabs[] = [ + 'label' => DI::l10n()->t('Advanced'), 'url' => 'contact/' . $cid . '/advanced/', 'sel' => (($active_tab == self::TAB_ADVANCED) ? 'active' : ''), 'title' => DI::l10n()->t('Advanced Contact Settings'), diff --git a/src/Module/Contact/Profile.php b/src/Module/Contact/Profile.php index d80405e23..e6dedf1b4 100644 --- a/src/Module/Contact/Profile.php +++ b/src/Module/Contact/Profile.php @@ -23,8 +23,7 @@ namespace Friendica\Module\Contact; use Friendica\App; use Friendica\BaseModule; -use Friendica\Contact\LocalRelationship\Entity; -use Friendica\Contact\LocalRelationship\Repository; +use Friendica\Contact\LocalRelationship; use Friendica\Content\ContactSelector; use Friendica\Content\Nav; use Friendica\Content\Text\BBCode; @@ -34,13 +33,16 @@ use Friendica\Core\Hook; use Friendica\Core\L10n; use Friendica\Core\Protocol; use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Database\Database; use Friendica\Database\DBA; -use Friendica\DI; +use Friendica\Model\Circle; use Friendica\Model\Contact; -use Friendica\Model\Group; use Friendica\Module; use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; use Friendica\Network\HTTPException; +use Friendica\User\Settings; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -50,31 +52,37 @@ use Psr\Log\LoggerInterface; */ class Profile extends BaseModule { - /** - * @var Repository\LocalRelationship - */ + /** @var LocalRelationship\Repository\LocalRelationship */ private $localRelationship; - /** - * @var App\Page - */ + /** @var App\Page */ private $page; - /** - * @var IManageConfigValues - */ + /** @var IManageConfigValues */ private $config; + /** @var IHandleUserSessions */ + private $session; + /** @var SystemMessages */ + private $systemMessages; + /** @var Database */ + private $db; + /** @var Settings\Repository\UserGServer */ + private $userGServer; - public function __construct(L10n $l10n, Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) + public function __construct(Settings\Repository\UserGServer $userGServer, Database $db, SystemMessages $systemMessages, IHandleUserSessions $session, L10n $l10n, LocalRelationship\Repository\LocalRelationship $localRelationship, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, App\Page $page, IManageConfigValues $config, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); $this->localRelationship = $localRelationship; $this->page = $page; $this->config = $config; + $this->session = $session; + $this->systemMessages = $systemMessages; + $this->db = $db; + $this->userGServer = $userGServer; } protected function post(array $request = []) { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { return; } @@ -82,8 +90,8 @@ class Profile extends BaseModule // Backward compatibility: The update still needs a user-specific contact ID // Change to user-contact table check by version 2022.03 - $cdata = Contact::getPublicAndUserContactID($contact_id, DI::userSession()->getLocalUserId()); - if (empty($cdata['user']) || !DBA::exists('contact', ['id' => $cdata['user'], 'deleted' => false])) { + $cdata = Contact::getPublicAndUserContactID($contact_id, $this->session->getLocalUserId()); + if (empty($cdata['user']) || !$this->db->exists('contact', ['id' => $cdata['user'], 'deleted' => false])) { return; } @@ -124,35 +132,35 @@ class Profile extends BaseModule $fields['info'] = $_POST['info']; } - if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => DI::userSession()->getLocalUserId()])) { - DI::sysmsg()->addNotice($this->t('Failed to update contact record.')); + if (!Contact::update($fields, ['id' => $cdata['user'], 'uid' => $this->session->getLocalUserId()])) { + $this->systemMessages->addNotice($this->t('Failed to update contact record.')); } } protected function content(array $request = []): string { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { return Module\Security\Login::form($_SERVER['REQUEST_URI']); } // Backward compatibility: Ensure to use the public contact when the user contact is provided // Remove by version 2022.03 - $data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), DI::userSession()->getLocalUserId()); + $data = Contact::getPublicAndUserContactID(intval($this->parameters['id']), $this->session->getLocalUserId()); if (empty($data)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } $contact = Contact::getById($data['public']); - if (!DBA::isResult($contact)) { + if (!$this->db->isResult($contact)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } // Don't display contacts that are about to be deleted - if (DBA::isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) { + if ($this->db->isResult($contact) && (!empty($contact['deleted']) || !empty($contact['network']) && $contact['network'] == Protocol::PHANTOM)) { throw new HTTPException\NotFoundException($this->t('Contact not found.')); } - $localRelationship = $this->localRelationship->getForUserContact(DI::userSession()->getLocalUserId(), $contact['id']); + $localRelationship = $this->localRelationship->getForUserContact($this->session->getLocalUserId(), $contact['id']); if ($localRelationship->rel === Contact::SELF) { $this->baseUrl->redirect('profile/' . $contact['nick'] . '/profile'); @@ -167,68 +175,68 @@ class Profile extends BaseModule } if ($cmd === 'updateprofile') { - self::updateContactFromProbe($contact['id']); + $this->updateContactFromProbe($contact['id']); } if ($cmd === 'block') { if ($localRelationship->blocked) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unblocked'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setBlocked($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setBlocked($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been blocked'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } if ($cmd === 'ignore') { if ($localRelationship->ignored) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been unignored'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setIgnored($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setIgnored($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been ignored'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } if ($cmd === 'collapse') { if ($localRelationship->collapsed) { // @TODO Backward compatibility, replace with $localRelationship->unblock() - Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), false); + Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), false); $message = $this->t('Contact has been uncollapsed'); } else { // @TODO Backward compatibility, replace with $localRelationship->block() - Contact\User::setCollapsed($contact['id'], DI::userSession()->getLocalUserId(), true); + Contact\User::setCollapsed($contact['id'], $this->session->getLocalUserId(), true); $message = $this->t('Contact has been collapsed'); } // @TODO: add $this->localRelationship->save($localRelationship); - DI::sysmsg()->addInfo($message); + $this->systemMessages->addInfo($message); } $this->baseUrl->redirect('contact/' . $contact['id']); } $vcard_widget = Widget\VCard::getHTML($contact); - $groups_widget = ''; + $circles_widget = ''; if (!in_array($localRelationship->rel, [Contact::NOTHING, Contact::SELF])) { - $groups_widget = Group::sidebarWidget('contact', 'group', 'full', 'everyone', $data['user']); + $circles_widget = Circle::sidebarWidget('contact', 'circle', 'full', 'everyone', $data['user']); } - $this->page['aside'] .= $vcard_widget . $groups_widget; + $this->page['aside'] .= $vcard_widget . $circles_widget; $o = ''; Nav::setSelected('contact'); @@ -246,7 +254,7 @@ class Profile extends BaseModule $relation_text = ''; } - if (!in_array($contact['network'], array_merge(Protocol::FEDERATED, [Protocol::TWITTER]))) { + if (!Protocol::supportsFollow($contact['network'])) { $relation_text = ''; } @@ -259,6 +267,17 @@ class Profile extends BaseModule $insecure = $this->t('Private communications are not available for this contact.'); + // @TODO: Figure out why gsid can be empty + if (empty($contact['gsid'])) { + $this->logger->notice('Empty gsid for contact', ['contact' => $contact]); + } + + $serverIgnored = + $contact['gsid'] && + $this->userGServer->isIgnoredByUser($this->session->getLocalUserId(), $contact['gsid']) ? + $this->t('This contact is on a server you ignored.') + : ''; + $last_update = (($contact['last-update'] <= DBA::NULL_DATETIME) ? $this->t('Never') : DateTimeFormat::local($contact['last-update'], 'D, j M Y, g:i A')); if ($contact['last-update'] > DBA::NULL_DATETIME) { @@ -283,10 +302,10 @@ class Profile extends BaseModule $localRelationship->fetchFurtherInformation, $this->t('Fetch information like preview pictures, title and teaser from the feed item. You can activate this if the feed doesn\'t contain much text. Keywords are taken from the meta header in the feed item and are posted as hash tags.'), [ - '0' => $this->t('Disabled'), - '1' => $this->t('Fetch information'), - '3' => $this->t('Fetch keywords'), - '2' => $this->t('Fetch information and keywords') + LocalRelationship\Entity\LocalRelationship::FFI_NONE => $this->t('Disabled'), + LocalRelationship\Entity\LocalRelationship::FFI_INFORMATION => $this->t('Fetch information'), + LocalRelationship\Entity\LocalRelationship::FFI_KEYWORD => $this->t('Fetch keywords'), + LocalRelationship\Entity\LocalRelationship::FFI_BOTH => $this->t('Fetch information and keywords') ] ]; } @@ -363,6 +382,8 @@ class Profile extends BaseModule '$collapsed' => $localRelationship->collapsed ? $this->t('Currently collapsed') : '', '$archived' => ($contact['archive'] ? $this->t('Currently archived') : ''), '$insecure' => (in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::MAIL, Protocol::DIASPORA]) ? '' : $insecure), + '$serverIgnored' => $serverIgnored, + '$manageServers' => $this->t('Manage remote servers'), '$cinfo' => ['info', '', $localRelationship->info, ''], '$hidden' => ['hidden', $this->t('Hide this contact from others'), $localRelationship->hidden, $this->t('Replies/likes to your public posts may still be visible')], '$notify_new_posts' => ['notify_new_posts', $this->t('Notification for new posts'), ($localRelationship->notifyNewPosts), $this->t('Send a notification of every new post of this contact')], @@ -394,7 +415,7 @@ class Profile extends BaseModule '$remote_self' => [ 'remote_self', $this->t('Mirror postings from this contact'), - $localRelationship->isRemoteSelf, + $localRelationship->remoteSelf, $this->t('Mark this contact as remote_self, this will cause friendica to repost new entries from this contact.'), $remote_self_options ], @@ -413,11 +434,11 @@ class Profile extends BaseModule * This includes actions like e.g. 'block', 'hide', 'delete' and others * * @param array $contact Public contact row - * @param Entity\LocalRelationship $localRelationship + * @param LocalRelationship\Entity\LocalRelationship $localRelationship * @return array with contact related actions * @throws HTTPException\InternalServerErrorException */ - private function getContactActions(array $contact, Entity\LocalRelationship $localRelationship): array + private function getContactActions(array $contact, LocalRelationship\Entity\LocalRelationship $localRelationship): array { $poll_enabled = in_array($contact['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::OSTATUS, Protocol::FEED, Protocol::MAIL]); $contact_actions = []; @@ -518,10 +539,9 @@ class Profile extends BaseModule * @throws HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function updateContactFromProbe(int $contact_id) + private function updateContactFromProbe(int $contact_id) { - $contact = DBA::selectFirst('contact', ['url'], ['id' => $contact_id, 'uid' => [0, DI::userSession()->getLocalUserId()], 'deleted' => false]); - if (!DBA::isResult($contact)) { + if (!$this->db->exists('contact', ['id' => $contact_id, 'uid' => [0, $this->session->getLocalUserId()], 'deleted' => false])) { return; } diff --git a/src/Module/Contact/Unfollow.php b/src/Module/Contact/Unfollow.php index 9bbc34eee..670fe57e6 100644 --- a/src/Module/Contact/Unfollow.php +++ b/src/Module/Contact/Unfollow.php @@ -93,7 +93,7 @@ class Unfollow extends \Friendica\BaseModule Strings::normaliseLink($url), Strings::normaliseLink($url), $url, ]; - $contact = $this->database->selectFirst('contact', ['url', 'id', 'uid', 'network', 'addr', 'name'], $condition); + $contact = $this->database->selectFirst('contact', ['url', 'alias', 'id', 'uid', 'network', 'addr', 'name'], $condition); if (!$this->database->isResult($contact)) { $this->systemMessages->addNotice($this->t("You aren't following this contact.")); $this->baseUrl->redirect($base_return_path); diff --git a/src/Module/Conversation/Community.php b/src/Module/Conversation/Community.php index ae6297e48..3c3bbb8a8 100644 --- a/src/Module/Conversation/Community.php +++ b/src/Module/Conversation/Community.php @@ -92,7 +92,7 @@ class Community extends BaseModule 'accesskey' => 'l' ]; } - + if (DI::userSession()->isAuthenticated() || in_array(self::$page_style, [self::LOCAL_AND_GLOBAL, self::GLOBAL])) { $tabs[] = [ 'label' => DI::l10n()->t('Global Community'), @@ -110,14 +110,14 @@ class Community extends BaseModule Nav::setSelected('community'); DI::page()['aside'] .= Widget::accountTypes('community/' . self::$content, self::$accountTypeString); - + if (DI::userSession()->getLocalUserId() && DI::config()->get('system', 'community_no_sharer')) { $path = self::$content; if (!empty($this->parameters['accounttype'])) { $path .= '/' . $this->parameters['accounttype']; } $query_parameters = []; - + if (!empty($_GET['min_id'])) { $query_parameters['min_id'] = $_GET['min_id']; } @@ -127,7 +127,7 @@ class Community extends BaseModule if (!empty($_GET['last_commented'])) { $query_parameters['max_id'] = $_GET['last_commented']; } - + $path_all = $path . (!empty($query_parameters) ? '?' . http_build_query($query_parameters) : ''); $path_no_sharer = $path . '?' . http_build_query(array_merge($query_parameters, ['no_sharer' => true])); DI::page()['aside'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('widget/community_sharer.tpl'), [ @@ -139,7 +139,7 @@ class Community extends BaseModule '$no_sharer_label' => DI::l10n()->t('Hide'), ]); } - + if (Feature::isEnabled(DI::userSession()->getLocalUserId(), 'trending_tags')) { DI::page()['aside'] .= TrendingTags::getHTML(self::$content); } @@ -157,7 +157,7 @@ class Community extends BaseModule return $o; } - $o .= DI::conversation()->create($items, Conversation::MODE_COMMUNITY, false, false, 'commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->render($items, Conversation::MODE_COMMUNITY, false, false, 'commented', DI::userSession()->getLocalUserId()); $pager = new BoundariesPager( DI::l10n(), @@ -339,7 +339,7 @@ class Community extends BaseModule $condition[0] .= " AND NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `post-user`.`uid` = ? AND `post-user`.`uri-id` = `post-thread-user-view`.`uri-id`)"; $condition[] = DI::userSession()->getLocalUserId(); } - + if (isset($max_id)) { $condition[0] .= " AND `commented` < ?"; $condition[] = $max_id; @@ -356,7 +356,7 @@ class Community extends BaseModule } } - $r = Post::selectThreadForUser(0, ['uri-id', 'commented', 'author-link'], $condition, $params); + $r = Post::selectThreadForUser(DI::userSession()->getLocalUserId() ?: 0, ['uri-id', 'commented', 'author-link'], $condition, $params); $items = Post::toArray($r); if (empty($items)) { diff --git a/src/Module/Conversation/Network.php b/src/Module/Conversation/Network.php index 5653b128a..ed53f7d23 100644 --- a/src/Module/Conversation/Network.php +++ b/src/Module/Conversation/Network.php @@ -24,7 +24,7 @@ namespace Friendica\Module\Conversation; use Friendica\BaseModule; use Friendica\Content\BoundariesPager; use Friendica\Content\Conversation; -use Friendica\Content\ForumManager; +use Friendica\Content\GroupManager; use Friendica\Content\Nav; use Friendica\Content\Widget; use Friendica\Content\Text\HTML; @@ -36,7 +36,7 @@ use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Profile; @@ -50,9 +50,9 @@ use Friendica\Util\DateTimeFormat; class Network extends BaseModule { /** @var int */ - private static $groupId; + private static $circleId; /** @var int */ - private static $forumContactId; + private static $groupContactId; /** @var string */ private static $selectedTab; /** @var mixed */ @@ -89,10 +89,10 @@ class Network extends BaseModule $module = 'network'; DI::page()['aside'] .= Widget::accountTypes($module, self::$accountTypeString); - DI::page()['aside'] .= Group::sidebarWidget($module, $module . '/group', 'standard', self::$groupId); - DI::page()['aside'] .= ForumManager::widget($module . '/forum', DI::userSession()->getLocalUserId(), self::$forumContactId); + DI::page()['aside'] .= Circle::sidebarWidget($module, $module . '/circle', 'standard', self::$circleId); + DI::page()['aside'] .= GroupManager::widget($module . '/group', DI::userSession()->getLocalUserId(), self::$groupContactId); DI::page()['aside'] .= Widget::postedByYear($module . '/archive', DI::userSession()->getLocalUserId(), false); - DI::page()['aside'] .= Widget::networks($module, !self::$forumContactId ? self::$network : ''); + DI::page()['aside'] .= Widget::networks($module, !self::$groupContactId ? self::$network : ''); DI::page()['aside'] .= Widget\SavedSearches::getHTML(DI::args()->getQueryString()); DI::page()['aside'] .= Widget::fileAs('filed', ''); @@ -119,9 +119,9 @@ class Network extends BaseModule $content = ''; - if (self::$forumContactId) { - // If self::$forumContactId belongs to a community forum or a private group, add a mention to the status editor - $condition = ["`id` = ? AND `contact-type` = ?", self::$forumContactId, Contact::TYPE_COMMUNITY]; + if (self::$groupContactId) { + // If self::$groupContactId belongs to a community group or a private group, add a mention to the status editor + $condition = ["`id` = ? AND `contact-type` = ?", self::$groupContactId, Contact::TYPE_COMMUNITY]; $contact = DBA::selectFirst('contact', ['addr'], $condition); if (!empty($contact['addr'])) { $content = '!' . $contact['addr']; @@ -131,13 +131,13 @@ class Network extends BaseModule $a = DI::app(); $default_permissions = []; - if (self::$groupId) { - $default_permissions['allow_gid'] = [self::$groupId]; + if (self::$circleId) { + $default_permissions['allow_gid'] = [self::$circleId]; } $allowedCids = []; - if (self::$forumContactId) { - $allowedCids[] = (int) self::$forumContactId; + if (self::$groupContactId) { + $allowedCids[] = (int) self::$groupContactId; } elseif (self::$network) { $condition = [ 'uid' => DI::userSession()->getLocalUserId(), @@ -160,26 +160,26 @@ class Network extends BaseModule } $x = [ - 'lockstate' => self::$groupId || self::$forumContactId || self::$network || ACL::getLockstateForUserId($a->getLoggedInUserId()) ? 'lock' : 'unlock', + 'lockstate' => self::$circleId || self::$groupContactId || self::$network || ACL::getLockstateForUserId($a->getLoggedInUserId()) ? 'lock' : 'unlock', 'acl' => ACL::getFullSelectorHTML(DI::page(), $a->getLoggedInUserId(), true, $default_permissions), - 'bang' => ((self::$groupId || self::$forumContactId || self::$network) ? '!' : ''), + 'bang' => ((self::$circleId || self::$groupContactId || self::$network) ? '!' : ''), 'content' => $content, ]; $o .= DI::conversation()->statusEditor($x); } - if (self::$groupId) { - $group = DBA::selectFirst('group', ['name'], ['id' => self::$groupId, 'uid' => DI::userSession()->getLocalUserId()]); - if (!DBA::isResult($group)) { - DI::sysmsg()->addNotice(DI::l10n()->t('No such group')); + if (self::$circleId) { + $circle = DBA::selectFirst('group', ['name'], ['id' => self::$circleId, 'uid' => DI::userSession()->getLocalUserId()]); + if (!DBA::isResult($circle)) { + DI::sysmsg()->addNotice(DI::l10n()->t('No such circle')); } $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('section_title.tpl'), [ - '$title' => DI::l10n()->t('Group: %s', $group['name']) + '$title' => DI::l10n()->t('Circle: %s', $circle['name']) ]) . $o; - } elseif (self::$forumContactId) { - $contact = Contact::getById(self::$forumContactId); + } elseif (self::$groupContactId) { + $contact = Contact::getById(self::$groupContactId); if (DBA::isResult($contact)) { $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('contact/list.tpl'), [ 'contacts' => [ModuleContact::getContactTemplateVars($contact)], @@ -201,7 +201,7 @@ class Network extends BaseModule $ordering = '`commented`'; } - $o .= DI::conversation()->create($items, Conversation::MODE_NETWORK, false, false, $ordering, DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->render($items, Conversation::MODE_NETWORK, false, false, $ordering, DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); @@ -305,9 +305,9 @@ class Network extends BaseModule protected function parseRequest(array $get) { - self::$groupId = $this->parameters['group_id'] ?? 0; + self::$circleId = (int)($this->parameters['circle_id'] ?? 0); - self::$forumContactId = $this->parameters['contact_id'] ?? 0; + self::$groupContactId = (int)($this->parameters['contact_id'] ?? 0); self::$selectedTab = self::getTimelineOrderBySession(DI::userSession(), DI::pConfig()); @@ -411,12 +411,12 @@ class Network extends BaseModule $conditionStrings = DBA::mergeConditions($conditionStrings, ["`received` >= ? ", DateTimeFormat::convert(self::$dateTo, 'UTC', DI::app()->getTimeZone())]); } - if (self::$groupId) { - $conditionStrings = DBA::mergeConditions($conditionStrings, ["`contact-id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?)", self::$groupId]); - } elseif (self::$forumContactId) { + if (self::$circleId) { + $conditionStrings = DBA::mergeConditions($conditionStrings, ["`contact-id` IN (SELECT `contact-id` FROM `group_member` WHERE `gid` = ?)", self::$circleId]); + } elseif (self::$groupContactId) { $conditionStrings = DBA::mergeConditions($conditionStrings, ["((`contact-id` = ?) OR `uri-id` IN (SELECT `parent-uri-id` FROM `post-user-view` WHERE (`contact-id` = ? AND `gravity` = ? AND `vid` = ? AND `uid` = ?)))", - self::$forumContactId, self::$forumContactId, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), DI::userSession()->getLocalUserId()]); + self::$groupContactId, self::$groupContactId, Item::GRAVITY_ACTIVITY, Verb::getID(Activity::ANNOUNCE), DI::userSession()->getLocalUserId()]); } // Currently only the order modes "received" and "commented" are in use @@ -471,15 +471,15 @@ class Network extends BaseModule } if (DBA::isResult($items)) { - $parents = array_column($items, 'parent-uri-id'); + $parents = array_column($items, 'uri-id'); } else { $parents = []; } - // We aren't going to try and figure out at the item, group, and page + // We aren't going to try and figure out at the item, circle, and page // level which items you've seen and which you haven't. If you're looking // at the top level network page just mark everything seen. - if (!self::$groupId && !self::$forumContactId && !self::$star && !self::$mention) { + if (!self::$circleId && !self::$groupContactId && !self::$star && !self::$mention) { $condition = ['unseen' => true, 'uid' => DI::userSession()->getLocalUserId()]; self::setItemsSeenByCondition($condition); } elseif (!empty($parents)) { diff --git a/src/Module/Debug/Babel.php b/src/Module/Debug/Babel.php index 560d002a1..a914f4fe9 100644 --- a/src/Module/Debug/Babel.php +++ b/src/Module/Debug/Babel.php @@ -58,7 +58,7 @@ class Babel extends BaseModule 'content' => visible_whitespace($plain) ]; - $html = Text\BBCode::convert($bbcode); + $html = Text\BBCode::convertForUriId(0, $bbcode); $results[] = [ 'title' => DI::l10n()->t('BBCode::convert (raw HTML)'), 'content' => visible_whitespace($html) @@ -125,7 +125,7 @@ class Babel extends BaseModule 'title' => DI::l10n()->t('PageInfo::appendToBody'), 'content' => visible_whitespace($body2) ]; - $html3 = Text\BBCode::convert($body2); + $html3 = Text\BBCode::convertForUriId(0, $body2); $results[] = [ 'title' => DI::l10n()->t('PageInfo::appendToBody => BBCode::convert (raw HTML)'), 'content' => visible_whitespace($html3) @@ -203,7 +203,7 @@ class Babel extends BaseModule 'content' => visible_whitespace($bbcode) ]; - $html2 = Text\BBCode::convert($bbcode); + $html2 = Text\BBCode::convertForUriId(0, $bbcode); $results[] = [ 'title' => DI::l10n()->t('HTML::toBBCode => BBCode::convert'), 'content' => $html2 diff --git a/src/Module/Delegation.php b/src/Module/Delegation.php index 3595ff7f3..8a2b31300 100644 --- a/src/Module/Delegation.php +++ b/src/Module/Delegation.php @@ -53,7 +53,7 @@ class Delegation extends BaseModule } } - $identity = intval($_POST['identity'] ?? 0); + $identity = intval($request['identity'] ?? 0); if (!$identity) { return; } @@ -76,16 +76,16 @@ class Delegation extends BaseModule $user = DBA::selectFirst('user', [], ['uid' => $identity, 'parent-uid' => $orig_record['uid']]); // Check if the target user is one of our siblings - if (!DBA::isResult($user) && ($orig_record['parent-uid'] != 0)) { + if (!DBA::isResult($user) && $orig_record['parent-uid']) { $user = DBA::selectFirst('user', [], ['uid' => $identity, 'parent-uid' => $orig_record['parent-uid']]); } // Check if it's our parent or our own user if (!DBA::isResult($user) && ( - $orig_record['parent-uid'] != 0 && $orig_record['parent-uid'] == $identity + $orig_record['parent-uid'] && $orig_record['parent-uid'] === $identity || - $orig_record['uid'] != 0 && $orig_record['uid'] == $identity + $orig_record['uid'] && $orig_record['uid'] === $identity ) ) { $user = User::getById($identity); diff --git a/src/Module/Friendica.php b/src/Module/Friendica.php index 90869878e..fe4c846c9 100644 --- a/src/Module/Friendica.php +++ b/src/Module/Friendica.php @@ -24,26 +24,44 @@ namespace Friendica\Module; use Friendica\App; use Friendica\BaseModule; use Friendica\Core\Addon; +use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\Hook; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; +use Friendica\Core\L10n; use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\PostUpdate; -use Friendica\DI; use Friendica\Model\User; use Friendica\Network\HTTPException; use Friendica\Protocol\ActivityPub; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; /** * Prints information about the current node - * Either in human readable form or in JSON + * Either in human-readable form or in JSON */ class Friendica extends BaseModule { + /** @var IManageConfigValues */ + private $config; + /** @var IManageKeyValuePairs */ + private $keyValue; + /** @var IHandleUserSessions */ + private $session; + + public function __construct(IHandleUserSessions $session, IManageKeyValuePairs $keyValue, IManageConfigValues $config, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->config = $config; + $this->keyValue = $keyValue; + $this->session = $session; + } + protected function content(array $request = []): string { - $config = DI::config(); - $keyValue = DI::keyValue(); - $visibleAddonList = Addon::getVisibleList(); if (!empty($visibleAddonList)) { @@ -61,29 +79,29 @@ class Friendica extends BaseModule } } $addon = [ - 'title' => DI::l10n()->t('Installed addons/apps:'), + 'title' => $this->t('Installed addons/apps:'), 'list' => $sortedAddonList, ]; } else { $addon = [ - 'title' => DI::l10n()->t('No installed addons/apps'), + 'title' => $this->t('No installed addons/apps'), ]; } - $tos = ($config->get('system', 'tosdisplay')) ? - DI::l10n()->t('Read about the Terms of Service of this node.', DI::baseUrl()) : + $tos = ($this->config->get('system', 'tosdisplay')) ? + $this->t('Read about the Terms of Service of this node.', $this->baseUrl) : ''; - $blockList = $config->get('system', 'blocklist'); + $blockList = $this->config->get('system', 'blocklist') ?? []; - if (!empty($blockList)) { + if (!empty($blockList) && ($this->config->get('blocklist', 'public') || $this->session->isAuthenticated())) { $blocked = [ - 'title' => DI::l10n()->t('On this server the following remote servers are blocked.'), + 'title' => $this->t('On this server the following remote servers are blocked.'), 'header' => [ - DI::l10n()->t('Blocked domain'), - DI::l10n()->t('Reason for the block'), + $this->t('Blocked domain'), + $this->t('Reason for the block'), ], - 'download' => DI::l10n()->t('Download this list in CSV format'), + 'download' => $this->t('Download this list in CSV format'), 'list' => $blockList, ]; } else { @@ -97,14 +115,14 @@ class Friendica extends BaseModule $tpl = Renderer::getMarkupTemplate('friendica.tpl'); return Renderer::replaceMacros($tpl, [ - 'about' => DI::l10n()->t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.', + 'about' => $this->t('This is Friendica, version %s that is running at the web location %s. The database version is %s, the post update version is %s.', '' . App::VERSION . '', - DI::baseUrl(), - '' . $config->get('system', 'build') . '/' . DB_UPDATE_VERSION . '', - '' . $keyValue->get('post_update_version') . '/' . PostUpdate::VERSION . ''), - 'friendica' => DI::l10n()->t('Please visit Friendi.ca to learn more about the Friendica project.'), - 'bugs' => DI::l10n()->t('Bug reports and issues: please visit') . ' ' . '' . DI::l10n()->t('the bugtracker at github') . '', - 'info' => DI::l10n()->t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'), + $this->baseUrl, + '' . $this->config->get('system', 'build') . '/' . DB_UPDATE_VERSION . '', + '' . $this->keyValue->get('post_update_version') . '/' . PostUpdate::VERSION . ''), + 'friendica' => $this->t('Please visit Friendi.ca to learn more about the Friendica project.'), + 'bugs' => $this->t('Bug reports and issues: please visit') . ' ' . '' . $this->t('the bugtracker at github') . '', + 'info' => $this->t('Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'), 'visible_addons' => $addon, 'tos' => $tos, @@ -115,8 +133,7 @@ class Friendica extends BaseModule protected function rawContent(array $request = []) { - // @TODO: Replace with parameter from router - if (DI::args()->getArgc() <= 1 || (DI::args()->getArgv()[1] !== 'json')) { + if (empty($this->parameters['format']) || $this->parameters['format'] !== 'json') { if (!ActivityPub::isRequest()) { return; } @@ -131,16 +148,14 @@ class Friendica extends BaseModule } } - $config = DI::config(); - $register_policies = [ Register::CLOSED => 'REGISTER_CLOSED', Register::APPROVE => 'REGISTER_APPROVE', Register::OPEN => 'REGISTER_OPEN' ]; - $register_policy_int = intval($config->get('config', 'register_policy')); - if ($register_policy_int !== Register::CLOSED && $config->get('config', 'invitation_only')) { + $register_policy_int = $this->config->get('config', 'register_policy'); + if ($register_policy_int !== Register::CLOSED && $this->config->get('config', 'invitation_only')) { $register_policy = 'REGISTER_INVITATION'; } else { $register_policy = $register_policies[$register_policy_int]; @@ -151,15 +166,15 @@ class Friendica extends BaseModule if (!empty($administrator)) { $admin = [ 'name' => $administrator['username'], - 'profile' => DI::baseUrl() . '/profile/' . $administrator['nickname'], + 'profile' => $this->baseUrl . '/profile/' . $administrator['nickname'], ]; } $visible_addons = Addon::getVisibleList(); - $config->reload(); + $this->config->reload(); $locked_features = []; - $featureLocks = $config->get('config', 'feature_lock'); + $featureLocks = $this->config->get('config', 'feature_lock'); if (isset($featureLocks)) { foreach ($featureLocks as $feature => $lock) { if ($feature === 'config_loaded') { @@ -172,17 +187,17 @@ class Friendica extends BaseModule $data = [ 'version' => App::VERSION, - 'url' => (string)DI::baseUrl(), + 'url' => (string)$this->baseUrl, 'addons' => $visible_addons, 'locked_features' => $locked_features, - 'explicit_content' => intval($config->get('system', 'explicit_content', 0)), - 'language' => $config->get('system', 'language'), + 'explicit_content' => intval($this->config->get('system', 'explicit_content', 0)), + 'language' => $this->config->get('system', 'language'), 'register_policy' => $register_policy, 'admin' => $admin, - 'site_name' => $config->get('config', 'sitename'), + 'site_name' => $this->config->get('config', 'sitename'), 'platform' => strtolower(App::PLATFORM), - 'info' => $config->get('config', 'info'), - 'no_scrape_url' => DI::baseUrl() . '/noscrape', + 'info' => $this->config->get('config', 'info'), + 'no_scrape_url' => $this->baseUrl . '/noscrape', ]; System::jsonExit($data); diff --git a/src/Module/Invite.php b/src/Module/Invite.php index 3230dfa35..e4c22ae1e 100644 --- a/src/Module/Invite.php +++ b/src/Module/Invite.php @@ -149,14 +149,14 @@ class Invite extends BaseModule if ($config->get('config', 'register_policy') === Register::CLOSED) { $linkTxt = DI::l10n()->t('Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks.', $dirLocation . '/servers'); } else { - $linkTxt = DI::l10n()->t('To accept this invitation, please visit and register at %s or any other public Friendica website.', DI::baseUrl()) + $linkTxt = DI::l10n()->t('To accept this invitation, please visit and register at %s or any other public Friendica website.', DI::baseUrl() . '/register') . "\r\n" . "\r\n" . DI::l10n()->t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join.', $dirLocation . '/servers'); } } else { // there is no global directory URL defined if ($config->get('config', 'register_policy') === Register::CLOSED) { return DI::l10n()->t('Our apologies. This system is not currently configured to connect with other public sites or invite members.'); } else { - $linkTxt = DI::l10n()->t('To accept this invitation, please visit and register at %s.', DI::baseUrl() + $linkTxt = DI::l10n()->t('To accept this invitation, please visit and register at %s.', DI::baseUrl() . '/register' . "\r\n" . "\r\n" . DI::l10n()->t('Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks.')); } } diff --git a/src/Module/Item/Compose.php b/src/Module/Item/Compose.php index 8201a61a6..76a99750a 100644 --- a/src/Module/Item/Compose.php +++ b/src/Module/Item/Compose.php @@ -113,9 +113,9 @@ class Compose extends BaseModule $user = User::getById(DI::userSession()->getLocalUserId(), ['allow_cid', 'allow_gid', 'deny_cid', 'deny_gid', 'default-location']); $contact_allow_list = $this->ACLFormatter->expand($user['allow_cid']); - $group_allow_list = $this->ACLFormatter->expand($user['allow_gid']); + $circle_allow_list = $this->ACLFormatter->expand($user['allow_gid']); $contact_deny_list = $this->ACLFormatter->expand($user['deny_cid']); - $group_deny_list = $this->ACLFormatter->expand($user['deny_gid']); + $circle_deny_list = $this->ACLFormatter->expand($user['deny_gid']); switch ($posttype) { case Item::PT_PERSONAL_NOTE: @@ -123,9 +123,9 @@ class Compose extends BaseModule $type = 'note'; $doesFederate = false; $contact_allow_list = [$a->getContactId()]; - $group_allow_list = []; + $circle_allow_list = []; $contact_deny_list = []; - $group_deny_list = []; + $circle_deny_list = []; break; default: $compose_title = $this->l10n->t('Compose new post'); @@ -133,19 +133,19 @@ class Compose extends BaseModule $doesFederate = true; $contact_allow = $_REQUEST['contact_allow'] ?? ''; - $group_allow = $_REQUEST['group_allow'] ?? ''; + $circle_allow = $_REQUEST['circle_allow'] ?? ''; $contact_deny = $_REQUEST['contact_deny'] ?? ''; - $group_deny = $_REQUEST['group_deny'] ?? ''; + $circle_deny = $_REQUEST['circle_deny'] ?? ''; if ($contact_allow - . $group_allow + . $circle_allow . $contact_deny - . $group_deny) + . $circle_deny) { $contact_allow_list = $contact_allow ? explode(',', $contact_allow) : []; - $group_allow_list = $group_allow ? explode(',', $group_allow) : []; + $circle_allow_list = $circle_allow ? explode(',', $circle_allow) : []; $contact_deny_list = $contact_deny ? explode(',', $contact_deny) : []; - $group_deny_list = $group_deny ? explode(',', $group_deny) : []; + $circle_deny_list = $circle_deny ? explode(',', $circle_deny) : []; } break; @@ -191,7 +191,8 @@ class Compose extends BaseModule 'editalic' => $this->l10n->t('Italic'), 'eduline' => $this->l10n->t('Underline'), 'edquote' => $this->l10n->t('Quote'), - '$edemojis' => $this->l10n->t('Add emojis'), + 'edemojis' => $this->l10n->t('Add emojis'), + 'contentwarn' => $this->l10n->t('Content Warning'), 'edcode' => $this->l10n->t('Code'), 'edimg' => $this->l10n->t('Image'), 'edurl' => $this->l10n->t('Link'), @@ -229,18 +230,18 @@ class Compose extends BaseModule '$body' => $body, '$location' => $location, - '$contact_allow'=> implode(',', $contact_allow_list), - '$group_allow' => implode(',', $group_allow_list), - '$contact_deny' => implode(',', $contact_deny_list), - '$group_deny' => implode(',', $group_deny_list), + '$contact_allow' => implode(',', $contact_allow_list), + '$circle_allow' => implode(',', $circle_allow_list), + '$contact_deny' => implode(',', $contact_deny_list), + '$circle_deny' => implode(',', $circle_deny_list), '$jotplugins' => $jotplugins, '$rand_num' => Crypto::randomDigits(12), '$acl_selector' => ACL::getFullSelectorHTML($this->page, $a->getLoggedInUserId(), $doesFederate, [ 'allow_cid' => $contact_allow_list, - 'allow_gid' => $group_allow_list, + 'allow_gid' => $circle_allow_list, 'deny_cid' => $contact_deny_list, - 'deny_gid' => $group_deny_list, + 'deny_gid' => $circle_deny_list, ]), ]); } diff --git a/src/Module/Item/Display.php b/src/Module/Item/Display.php index b2ed43c5b..714598a8e 100644 --- a/src/Module/Item/Display.php +++ b/src/Module/Item/Display.php @@ -133,7 +133,9 @@ class Display extends BaseModule } if (empty($item)) { - throw new HTTPException\NotFoundException($this->t('The requested item doesn\'t exist or has been deleted.')); + $this->page['aside'] = ''; + $displayNotFound = new DisplayNotFound($this->l10n, $this->baseUrl, $this->args, $this->logger, $this->profiler, $this->response, $this->server, $this->parameters); + return $displayNotFound->content(); } if ($item['gravity'] != Item::GRAVITY_PARENT) { @@ -273,7 +275,7 @@ class Display extends BaseModule $output .= $this->conversation->statusEditor([], 0, true); } - $output .= $this->conversation->create([$item], Conversation::MODE_DISPLAY, $updateUid, false, 'commented', $itemUid); + $output .= $this->conversation->render([$item], Conversation::MODE_DISPLAY, $updateUid, false, 'commented', $itemUid); return $output; } diff --git a/src/Module/Magic.php b/src/Module/Magic.php index 5276252de..dc0d4f8ad 100644 --- a/src/Module/Magic.php +++ b/src/Module/Magic.php @@ -29,12 +29,14 @@ use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Model\Contact; +use Friendica\Model\GServer; use Friendica\Model\User; use Friendica\Network\HTTPClient\Capability\ICanSendHttpRequests; use Friendica\Network\HTTPClient\Client\HttpClientOptions; use Friendica\Util\HTTPSignature; use Friendica\Util\Profiler; use Friendica\Util\Strings; +use GuzzleHttp\Psr7\Uri; use Psr\Log\LoggerInterface; /** @@ -83,6 +85,8 @@ class Magic extends BaseModule $this->logger->debug('bdest detected', ['dest' => $dest]); } + $target = $dest ?: $addr; + if ($addr ?: $dest) { $contact = Contact::getByURL($addr ?: $dest); } @@ -110,17 +114,24 @@ class Magic extends BaseModule // OpenWebAuth $owner = User::getOwnerDataById($this->userSession->getLocalUserId()); - $gserver = $this->dba->selectFirst('gserver', ['url'], ['id' => $contact['gsid']]); - if (empty($gserver)) { - $this->logger->notice('Server not found, redirecting to destination.', ['gsid' => $contact['gsid'], 'dest' => $dest]); + if (!empty($contact['gsid'])) { + $gserver = $this->dba->selectFirst('gserver', ['url'], ['id' => $contact['gsid']]); + if (empty($gserver)) { + $this->logger->notice('Server not found, redirecting to destination.', ['gsid' => $contact['gsid'], 'dest' => $dest]); + System::externalRedirect($dest); + } + + $basepath = $gserver['url']; + } elseif (GServer::check($target)) { + $basepath = (string)GServer::cleanUri(new Uri($target)); + } else { + $this->logger->notice('The target is not a server path, redirecting to destination.', ['target' => $target]); System::externalRedirect($dest); } - $basepath = $gserver['url']; - $header = [ - 'Accept' => ['application/x-dfrn+json', 'application/x-zot+json'], - 'X-Open-Web-Auth' => [Strings::getRandomHex()], + 'Accept' => 'application/x-dfrn+json, application/x-zot+json', + 'X-Open-Web-Auth' => Strings::getRandomHex() ]; // Create a header that is signed with the local users private key. diff --git a/src/Module/Moderation/BaseUsers.php b/src/Module/Moderation/BaseUsers.php index cbcb625a8..2d352dbdc 100644 --- a/src/Module/Moderation/BaseUsers.php +++ b/src/Module/Moderation/BaseUsers.php @@ -118,15 +118,15 @@ abstract class BaseUsers extends BaseModeration $page_types = [ User::PAGE_FLAGS_NORMAL => $this->t('Normal Account Page'), User::PAGE_FLAGS_SOAPBOX => $this->t('Soapbox Page'), - User::PAGE_FLAGS_COMMUNITY => $this->t('Public Forum'), + User::PAGE_FLAGS_COMMUNITY => $this->t('Public Group'), User::PAGE_FLAGS_FREELOVE => $this->t('Automatic Friend Page'), - User::PAGE_FLAGS_PRVGROUP => $this->t('Private Forum') + User::PAGE_FLAGS_PRVGROUP => $this->t('Private Group') ]; $account_types = [ User::ACCOUNT_TYPE_PERSON => $this->t('Personal Page'), User::ACCOUNT_TYPE_ORGANISATION => $this->t('Organisation Page'), User::ACCOUNT_TYPE_NEWS => $this->t('News Page'), - User::ACCOUNT_TYPE_COMMUNITY => $this->t('Community Forum'), + User::ACCOUNT_TYPE_COMMUNITY => $this->t('Community Group'), User::ACCOUNT_TYPE_RELAY => $this->t('Relay'), ]; diff --git a/src/Module/Moderation/Report/Create.php b/src/Module/Moderation/Report/Create.php new file mode 100644 index 000000000..e309df3c1 --- /dev/null +++ b/src/Module/Moderation/Report/Create.php @@ -0,0 +1,344 @@ +. + * + */ + +namespace Friendica\Module\Moderation\Report; + +use Friendica\App; +use Friendica\BaseModule; +use Friendica\Content\Conversation as ConversationContent; +use Friendica\Content\Pager; +use Friendica\Content\Text\BBCode; +use Friendica\Core\L10n; +use Friendica\Core\Protocol; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Model\UserSession; +use Friendica\Core\System; +use Friendica\Database\DBA; +use Friendica\DI; +use Friendica\Model\Contact; +use Friendica\Model\Item; +use Friendica\Model\Post; +use Friendica\Moderation\Entity\Report; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\ForbiddenException; +use Friendica\Util\Network; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Create extends BaseModule +{ + const CONTACT_ACTION_NONE = 0; + const CONTACT_ACTION_COLLAPSE = 1; + const CONTACT_ACTION_IGNORE = 2; + const CONTACT_ACTION_BLOCK = 3; + + /** @var SystemMessages */ + private $systemMessages; + /** @var App\Page */ + private $page; + /** @var UserSession */ + private $session; + /** @var \Friendica\Moderation\Factory\Report */ + private $factory; + /** @var \Friendica\Moderation\Repository\Report */ + private $repository; + + public function __construct(\Friendica\Moderation\Repository\Report $repository, \Friendica\Moderation\Factory\Report $factory, UserSession $session, App\Page $page, SystemMessages $systemMessages, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->systemMessages = $systemMessages; + $this->page = $page; + $this->session = $session; + $this->factory = $factory; + $this->repository = $repository; + } + + protected function post(array $request = []) + { + if (!$this->session->getLocalUserId()) { + throw new ForbiddenException(); + } + + $report = []; + foreach (['cid', 'category', 'rule-ids', 'uri-ids'] as $key) { + if (isset($request[$key])) { + $report[$key] = $request[$key]; + } + } + + if (isset($request['url'])) { + $cid = Contact::getIdForURL($request['url']); + if ($cid) { + $report['cid'] = $cid; + } else { + $report['url'] = $request['url']; + $this->systemMessages->addNotice($this->t('Contact not found or their server is already blocked on this node.')); + } + } + + if (isset($request['comment'])) { + $this->session->set('report_comment', $request['comment']); + unset($request['comment']); + } + + if (isset($request['report_create'])) { + $report = $this->factory->createFromForm( + System::getRules(true), + $request['cid'], + $this->session->getLocalUserId(), + $request['category'], + !empty($request['rule-ids']) ? explode(',', $request['rule-ids']) : [], + $this->session->get('report_comment') ?? '', + !empty($request['uri-ids']) ? explode(',', $request['uri-ids']) : [], + (bool)($request['forward'] ?? false), + ); + $this->repository->save($report); + + switch ($request['contact_action'] ?? 0) { + case self::CONTACT_ACTION_COLLAPSE: + Contact\User::setCollapsed($request['cid'], $this->session->getLocalUserId(), true); + break; + case self::CONTACT_ACTION_IGNORE: + Contact\User::setIgnored($request['cid'], $this->session->getLocalUserId(), true); + break; + case self::CONTACT_ACTION_BLOCK: + Contact\User::setBlocked($request['cid'], $this->session->getLocalUserId(), true); + break; + } + } + + $this->baseUrl->redirect($this->args->getCommand() . '?' . http_build_query($report)); + } + + protected function content(array $request = []): string + { + if (!$this->session->getLocalUserId()) { + throw new ForbiddenException($this->t('Please login to access this page.')); + } + + $this->page['aside'] = $this->getAside($request); + + if (empty($request['cid'])) { + return $this->pickContact($request); + } + + if (empty($request['category'])) { + return $this->pickCategory($request); + } + + if ($request['category'] == Report::CATEGORY_VIOLATION && !isset($request['rule-ids'])) { + return $this->pickRules($request); + } + + if (!isset($request['uri-ids'])) { + return $this->pickPosts($request); + } + + return $this->summary($request); + } + + private function pickContact(array $request): string + { + $tpl = Renderer::getMarkupTemplate('moderation/report/create/pick_contact.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Create Moderation Report'), + 'page' => $this->t('Pick Contact'), + 'description' => $this->t('Please enter below the contact address or profile URL you would like to create a moderation report about.'), + 'submit' => $this->t('Submit'), + ], + + '$url' => ['url', $this->t('Contact address/URL'), $request['url'] ?? ''], + ]); + } + + private function pickCategory(array $request): string + { + $tpl = Renderer::getMarkupTemplate('moderation/report/create/pick_category.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Create Moderation Report'), + 'page' => $this->t('Pick Category'), + 'description' => $this->t('Please pick below the category of your report.'), + 'submit' => $this->t('Submit'), + ], + + '$category_spam' => ['category', $this->t('Spam') , Report::CATEGORY_SPAM , $this->t('This contact is publishing many repeated/overly long posts/replies or advertising their product/websites in otherwise irrelevant conversations.'), $request['category'] == Report::CATEGORY_SPAM], + '$category_illegal' => ['category', $this->t('Illegal Content') , Report::CATEGORY_ILLEGAL , $this->t("This contact is publishing content that is considered illegal in this node's hosting juridiction."), $request['category'] == Report::CATEGORY_ILLEGAL], + '$category_safety' => ['category', $this->t('Community Safety') , Report::CATEGORY_SAFETY , $this->t("This contact aggravated you or other people, by being provocative or insensitive, intentionally or not. This includes disclosing people's private information (doxxing), posting threats or offensive pictures in posts or replies."), $request['category'] == Report::CATEGORY_SAFETY], + '$category_unwanted' => ['category', $this->t('Unwanted Content/Behavior'), Report::CATEGORY_UNWANTED , $this->t("This contact has repeatedly published content irrelevant to the node's theme or is openly criticizing the node's administration/moderation without directly engaging with the relevant people for example or repeatedly nitpicking on a sensitive topic."), $request['category'] == Report::CATEGORY_UNWANTED], + '$category_violation' => ['category', $this->t('Rules Violation') , Report::CATEGORY_VIOLATION, $this->t('This contact violated one or more rules of this node. You will be able to pick which one(s) in the next step.'), $request['category'] == Report::CATEGORY_VIOLATION], + '$category_other' => ['category', $this->t('Other') , Report::CATEGORY_OTHER , $this->t('Please elaborate below why you submitted this report. The more details you provide, the better your report can be handled.'), $request['category'] == Report::CATEGORY_OTHER], + + '$comment' => ['comment', $this->t('Additional Information'), $this->session->get('report_comment') ?? '', $this->t('Please provide any additional information relevant to this particular report. You will be able to attach posts by this contact in the next step, but any context is welcome.')], + ]); + } + + private function pickRules(array $request): string + { + $rules = []; + + foreach (System::getRules(true) as $rule_line => $rule_text) { + $rules[] = ['rule-ids[]', $rule_line, $rule_text, in_array($rule_line, $request['rule_ids'] ?? [])]; + } + + $tpl = Renderer::getMarkupTemplate('moderation/report/create/pick_rules.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Create Moderation Report'), + 'page' => $this->t('Pick Rules'), + 'description' => $this->t('Please pick below the node rules you believe this contact violated.'), + 'submit' => $this->t('Submit'), + ], + + '$rules' => $rules, + ]); + } + + private function pickPosts(array $request): string + { + $threads = []; + + $contact = DBA::selectFirst('contact', ['contact-type', 'network'], ['id' => $request['cid']]); + if (DBA::isResult($contact)) { + $contact_field = $contact['contact-type'] == Contact::TYPE_COMMUNITY || $contact['network'] == Protocol::MAIL ? 'owner-id' : 'author-id'; + + $condition = [ + $contact_field => $request['cid'], + 'gravity' => [Item::GRAVITY_PARENT, Item::GRAVITY_COMMENT], + ]; + + if (empty($contact['network']) || in_array($contact['network'], Protocol::FEDERATED)) { + $condition = DBA::mergeConditions($condition, ['(`uid` = 0 OR (`uid` = ? AND NOT `global`))', DI::userSession()->getLocalUserId()]); + } else { + $condition['uid'] = DI::userSession()->getLocalUserId(); + } + + if (DI::mode()->isMobile()) { + $itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_mobile_network', + DI::config()->get('system', 'itemspage_network_mobile')); + } else { + $itemsPerPage = DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'itemspage_network', + DI::config()->get('system', 'itemspage_network')); + } + + $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), $itemsPerPage); + + $params = ['order' => ['received' => true], 'limit' => [$pager->getStart(), $pager->getItemsPerPage()]]; + + $fields = array_merge(Item::DISPLAY_FIELDLIST, ['featured']); + $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), $fields, $condition, $params)); + + $formSecurityToken = BaseModule::getFormSecurityToken('contact_action'); + + $threads = DI::conversation()->getContextLessThreadList($items, ConversationContent::MODE_CONTACT_POSTS, false, false, $formSecurityToken); + } + + $tpl = Renderer::getMarkupTemplate('moderation/report/create/pick_posts.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Create Moderation Report'), + 'page' => $this->t('Pick Posts'), + 'description' => $this->t('Please optionally pick posts to attach to your report.'), + 'submit' => $this->t('Submit'), + ], + + '$threads' => $threads, + ]); + } + + private function summary(array $request): string + { + $this->page['aside'] = ''; + + $contact = Contact::getById($request['cid'], ['url']); + + $tpl = Renderer::getMarkupTemplate('moderation/report/create/summary.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Create Moderation Report'), + 'page' => $this->t('Summary'), + 'submit' => $this->t('Submit Report'), + 'contact_action_title' => $this->t('Further Action'), + 'contact_action_desc' => $this->t('You can also perform one of the following action on the contact you reported:'), + ], + + '$cid' => $request['cid'], + '$category' => $request['category'], + '$ruleIds' => implode(',', $request['rule-ids'] ?? []), + '$uriIds' => implode(',', $request['uri-ids'] ?? []), + + '$nothing' => ['contact_action', $this->t('Nothing'), self::CONTACT_ACTION_NONE, '', true], + '$collapse' => ['contact_action', $this->t('Collapse contact'), self::CONTACT_ACTION_COLLAPSE, $this->t('Their posts and replies will keep appearing in your Network page but their content will be collapsed by default.')], + '$ignore' => ['contact_action', $this->t('Ignore contact'), self::CONTACT_ACTION_IGNORE, $this->t("Their posts won't appear in your Network page anymore, but their replies can appear in forum threads. They still can follow you.")], + '$block' => ['contact_action', $this->t('Block contact'), self::CONTACT_ACTION_BLOCK, $this->t("Their posts won't appear in your Network page anymore, but their replies can appear in forum threads, with their content collapsed by default. They cannot follow you but still can have access to your public posts by other means.")], + + '$display_forward' => !Network::isLocalLink($contact['url']), + '$forward' => ['report_forward', $this->t('Forward report'), self::CONTACT_ACTION_BLOCK, $this->t('Would you ike to forward this report to the remote server?')], + + '$summary' => $this->getAside($request), + ]); + } + + private function getAside(array $request): string + { + $contact = null; + if (!empty($request['cid'])) { + $contact = Contact::getById($request['cid']); + } + + switch ($request['category'] ?? 0) { + case Report::CATEGORY_SPAM: $category = $this->t('Spam'); break; + case Report::CATEGORY_ILLEGAL: $category = $this->t('Illegal Content'); break; + case Report::CATEGORY_SAFETY: $category = $this->t('Community Safety'); break; + case Report::CATEGORY_UNWANTED: $category = $this->t('Unwanted Content/Behavior'); break; + case Report::CATEGORY_VIOLATION: $category = $this->t('Rules Violation'); break; + case Report::CATEGORY_OTHER: $category = $this->t('Other'); break; + + default: $category = ''; + } + + if (!empty($request['rule-ids'])) { + $rules = array_filter(System::getRules(true), function ($rule_id) use ($request) { + return in_array($rule_id, $request['rule-ids']); + }, ARRAY_FILTER_USE_KEY); + } + + $tpl = Renderer::getMarkupTemplate('moderation/report/create/aside.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'contact_title' => $this->t('1. Pick a contact'), + 'category_title' => $this->t('2. Pick a category'), + 'rules_title' => $this->t('2a. Pick rules'), + 'comment_title' => $this->t('2b. Add comment'), + 'posts_title' => $this->t('3. Pick posts'), + ], + + '$contact' => $contact, + '$category' => $category, + '$rules' => $rules ?? [], + '$comment' => BBCode::convertForUriId($contact['uri-id'] ?? 0, $this->session->get('report_comment') ?? '', BBCode::EXTERNAL), + '$posts' => count($request['uri-ids'] ?? []), + ]); + } +} diff --git a/src/Module/Moderation/Summary.php b/src/Module/Moderation/Summary.php index 3d7c007a4..849eb284f 100644 --- a/src/Module/Moderation/Summary.php +++ b/src/Module/Moderation/Summary.php @@ -52,10 +52,10 @@ class Summary extends BaseModeration $accounts = [ [$this->t('Normal Account'), 0], [$this->t('Automatic Follower Account'), 0], - [$this->t('Public Forum Account'), 0], + [$this->t('Public Group Account'), 0], [$this->t('Automatic Friend Account'), 0], [$this->t('Blog Account'), 0], - [$this->t('Private Forum Account'), 0] + [$this->t('Private Group Account'), 0] ]; $users = 0; diff --git a/src/Module/NodeInfo110.php b/src/Module/NodeInfo110.php index aee7ade5b..85785ccca 100644 --- a/src/Module/NodeInfo110.php +++ b/src/Module/NodeInfo110.php @@ -88,10 +88,6 @@ class NodeInfo110 extends BaseModule $nodeinfo['metadata']['services'] = $nodeinfo['services']; - if (Addon::isEnabled('twitter')) { - $nodeinfo['metadata']['services']['inbound'][] = 'twitter'; - } - $nodeinfo['metadata']['explicitContent'] = $this->config->get('system', 'explicit_content', false) == true; $this->response->setType(ICanCreateResponses::TYPE_JSON); diff --git a/src/Module/NodeInfo120.php b/src/Module/NodeInfo120.php index a5547be3f..9fc72c528 100644 --- a/src/Module/NodeInfo120.php +++ b/src/Module/NodeInfo120.php @@ -72,10 +72,6 @@ class NodeInfo120 extends BaseModule $nodeinfo['protocols'][] = 'ostatus'; } - if (Addon::isEnabled('twitter')) { - $nodeinfo['services']['inbound'][] = 'twitter'; - } - $nodeinfo['services']['inbound'][] = 'atom1.0'; $nodeinfo['services']['inbound'][] = 'rss2.0'; $nodeinfo['services']['outbound'][] = 'atom1.0'; diff --git a/src/Module/NodeInfo210.php b/src/Module/NodeInfo210.php index e7112846c..a1a6e0b19 100644 --- a/src/Module/NodeInfo210.php +++ b/src/Module/NodeInfo210.php @@ -71,10 +71,6 @@ class NodeInfo210 extends BaseModule $nodeinfo['protocols'][] = 'ostatus'; } - if (Addon::isEnabled('twitter')) { - $nodeinfo['services']['inbound'][] = 'twitter'; - } - $nodeinfo['services']['inbound'][] = 'atom1.0'; $nodeinfo['services']['inbound'][] = 'rss2.0'; $nodeinfo['services']['outbound'][] = 'atom1.0'; diff --git a/src/Module/Notifications/Introductions.php b/src/Module/Notifications/Introductions.php index 246bed540..921761ab5 100644 --- a/src/Module/Notifications/Introductions.php +++ b/src/Module/Notifications/Introductions.php @@ -147,7 +147,7 @@ class Introductions extends BaseNotifications $knowyou = ''; } - $convertedName = BBCode::convert($Introduction->getName()); + $convertedName = BBCode::toPlaintext($Introduction->getName(), false); $helptext = $this->t('Shall your connection be bidirectional or not?'); $helptext2 = $this->t('Accepting %s as a friend allows %s to subscribe to your posts, and you will also receive updates from them in your news feed.', $convertedName, $convertedName); diff --git a/src/Module/Notifications/Ping.php b/src/Module/Notifications/Ping.php index 3cd4d7020..603d6408c 100644 --- a/src/Module/Notifications/Ping.php +++ b/src/Module/Notifications/Ping.php @@ -24,7 +24,7 @@ namespace Friendica\Module\Notifications; use Friendica\App; use Friendica\BaseModule; use Friendica\Contact\Introduction\Repository\Introduction; -use Friendica\Content\ForumManager; +use Friendica\Content\GroupManager; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Enum\Duration; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -35,7 +35,7 @@ use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\System; use Friendica\Database\Database; use Friendica\Database\DBA; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Post; use Friendica\Model\User; use Friendica\Model\Verb; @@ -52,6 +52,7 @@ use Friendica\Network\HTTPException; use Friendica\Protocol\Activity; use Friendica\Util\DateTimeFormat; use Friendica\Util\Profiler; +use Friendica\Util\Strings; use GuzzleHttp\Psr7\Uri; use Psr\Log\LoggerInterface; @@ -108,15 +109,15 @@ class Ping extends BaseModule $network_count = 0; $register_count = 0; $sysnotify_count = 0; + $circles_unseen = []; $groups_unseen = []; - $forums_unseen = []; $event_count = 0; $today_event_count = 0; $birthday_count = 0; $today_birthday_count = 0; - // Suppress notification display for forum accounts + // Suppress notification display for group accounts if ($this->session->getLocalUserId() && $this->session->get('page_flags', '') != User::PAGE_FLAGS_COMMUNITY) { if ($this->pconfig->get($this->session->getLocalUserId(), 'system', 'detailed_notif')) { $notifications = $this->notificationRepo->selectDetailedForUser($this->session->getLocalUserId()); @@ -151,18 +152,18 @@ class Ping extends BaseModule } } - $compute_group_counts = $this->config->get('system','compute_group_counts'); - if ($network_count && $compute_group_counts) { - // Find out how unseen network posts are spread across groups - foreach (Group::countUnseen() as $group_count) { - if ($group_count['count'] > 0) { - $groups_unseen[] = $group_count; + $compute_circle_counts = $this->config->get('system','compute_group_counts') ?? $this->config->get('system','compute_circle_counts'); + if ($network_count && $compute_circle_counts) { + // Find out how unseen network posts are spread across circles + foreach (Circle::countUnseen() as $circle_count) { + if ($circle_count['count'] > 0) { + $circles_unseen[] = $circle_count; } } - foreach (ForumManager::countUnseenItems() as $forum_count) { - if ($forum_count['count'] > 0) { - $forums_unseen[] = $forum_count; + foreach (GroupManager::countUnseenItems() as $group_count) { + if ($group_count['count'] > 0) { + $groups_unseen[] = $group_count; } } } @@ -174,7 +175,7 @@ class Ping extends BaseModule $myurl = $this->session->getMyUrl(); $mail_count = $this->database->count('mail', ["`uid` = ? AND NOT `seen` AND `from-url` != ?", $this->session->getLocalUserId(), $myurl]); - if (intval($this->config->get('config', 'register_policy')) === Register::APPROVE && $this->app->isSiteAdmin()) { + if (intval($this->config->get('config', 'register_policy')) === Register::APPROVE && $this->session->isSiteAdmin()) { $registrations = \Friendica\Model\Register::getPending(); $register_count = count($registrations); } @@ -289,15 +290,15 @@ class Ping extends BaseModule $data['events-today'] = $today_event_count; $data['birthdays'] = $birthday_count; $data['birthdays-today'] = $today_birthday_count; + $data['circles'] = $circles_unseen; $data['groups'] = $groups_unseen; - $data['forums'] = $forums_unseen; $data['notification'] = ($notification_count < 50) ? $notification_count : '49+'; $data['notifications'] = $navNotifications; $data['sysmsgs'] = [ - 'notice' => $this->systemMessages->flushNotices(), - 'info' => $this->systemMessages->flushInfos(), + 'notice' => array_map([Strings::class, 'escapeHtml'], $this->systemMessages->flushNotices()), + 'info' => array_map([Strings::class, 'escapeHtml'], $this->systemMessages->flushInfos()), ]; if (isset($_GET['callback'])) { diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index efa066694..ea91de5a0 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -91,7 +91,7 @@ class Authorize extends BaseApi } if ($application['redirect_uri'] != 'urn:ietf:wg:oauth:2.0:oob') { - DI::app()->redirect($application['redirect_uri'] . (strpos($application['redirect_uri'], '?') ? '&' : '?') . http_build_query(['code' => $token['code'], 'state' => $request['state']])); + DI::app()->redirect($request['redirect_uri'] . (strpos($request['redirect_uri'], '?') ? '&' : '?') . http_build_query(['code' => $token['code'], 'state' => $request['state']])); } self::$oauth_code = $token['code']; diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index f97a05bb0..f5aec0802 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -30,6 +30,7 @@ use Friendica\Module\BaseApi; use Friendica\Module\Special\HTTPException; use Friendica\Security\OAuth; use Friendica\Util\DateTimeFormat; +use GuzzleHttp\Psr7\Uri; use Psr\Http\Message\ResponseInterface; /** @@ -89,8 +90,11 @@ class Token extends BaseApi $me = null; } elseif ($request['grant_type'] == 'authorization_code') { // For security reasons only allow freshly created tokens - $condition = ["`redirect_uri` = ? AND `id` = ? AND `code` = ? AND `created_at` > ?", - $request['redirect_uri'], $application['id'], $request['code'], DateTimeFormat::utc('now - 5 minutes')]; + $uri = new Uri($request['redirect_uri']); + $condition = [ + "`redirect_uri` LIKE ? AND `id` = ? AND `code` = ? AND `created_at` > ?", + '%' . $uri->getScheme() . '://' . $uri->getHost() . $uri->getPath() . '%', $application['id'], $request['code'], DateTimeFormat::utc('now - 5 minutes') + ]; $token = DBA::selectFirst('application-view', ['access_token', 'created_at', 'uid'], $condition); if (!DBA::isResult($token)) { diff --git a/src/Module/PermissionTooltip.php b/src/Module/PermissionTooltip.php index dbfdd5ef2..4e5191e5a 100644 --- a/src/Module/PermissionTooltip.php +++ b/src/Module/PermissionTooltip.php @@ -27,7 +27,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\APContact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\Tag; @@ -113,29 +113,29 @@ class PermissionTooltip extends \Friendica\BaseModule exit; } - $allowed_users = $model['allow_cid']; - $allowed_groups = $model['allow_gid']; - $deny_users = $model['deny_cid']; - $deny_groups = $model['deny_gid']; + $allowed_users = $model['allow_cid']; + $allowed_circles = $model['allow_gid']; + $deny_users = $model['deny_cid']; + $deny_circles = $model['deny_gid']; $o = DI::l10n()->t('Visible to:') . '
'; $l = []; - if (count($allowed_groups)) { - $key = array_search(Group::FOLLOWERS, $allowed_groups); + if (count($allowed_circles)) { + $key = array_search(Circle::FOLLOWERS, $allowed_circles); if ($key !== false) { $l[] = '' . DI::l10n()->t('Followers') . ''; - unset($allowed_groups[$key]); + unset($allowed_circles[$key]); } - $key = array_search(Group::MUTUALS, $allowed_groups); + $key = array_search(Circle::MUTUALS, $allowed_circles); if ($key !== false) { $l[] = '' . DI::l10n()->t('Mutuals') . ''; - unset($allowed_groups[$key]); + unset($allowed_circles[$key]); } - foreach (DI::dba()->selectToArray('group', ['name'], ['id' => $allowed_groups]) as $group) { - $l[] = '' . $group['name'] . ''; + foreach (DI::dba()->selectToArray('group', ['name'], ['id' => $allowed_circles]) as $circle) { + $l[] = '' . $circle['name'] . ''; } } @@ -143,21 +143,21 @@ class PermissionTooltip extends \Friendica\BaseModule $l[] = $contact['name']; } - if (count($deny_groups)) { - $key = array_search(Group::FOLLOWERS, $deny_groups); + if (count($deny_circles)) { + $key = array_search(Circle::FOLLOWERS, $deny_circles); if ($key !== false) { $l[] = '' . DI::l10n()->t('Followers') . ''; - unset($deny_groups[$key]); + unset($deny_circles[$key]); } - $key = array_search(Group::MUTUALS, $deny_groups); + $key = array_search(Circle::MUTUALS, $deny_circles); if ($key !== false) { $l[] = '' . DI::l10n()->t('Mutuals') . ''; - unset($deny_groups[$key]); + unset($deny_circles[$key]); } - foreach (DI::dba()->selectToArray('group', ['name'], ['id' => $allowed_groups]) as $group) { - $l[] = '' . $group['name'] . ''; + foreach (DI::dba()->selectToArray('group', ['name'], ['id' => $allowed_circles]) as $circle) { + $l[] = '' . $circle['name'] . ''; } } diff --git a/src/Module/Photo.php b/src/Module/Photo.php index 954b3f3ee..c8e0656d2 100644 --- a/src/Module/Photo.php +++ b/src/Module/Photo.php @@ -22,6 +22,7 @@ namespace Friendica\Module; use Friendica\BaseModule; +use Friendica\Contact\Header; use Friendica\Core\Logger; use Friendica\Core\Protocol; use Friendica\Database\DBA; @@ -482,6 +483,6 @@ class Photo extends BaseApi if (!empty($photo)) { return $photo; } - return MPhoto::createPhotoForImageData(file_get_contents(DI::basePath() . '/images/friendica-banner.jpg')); + return MPhoto::createPhotoForImageData(file_get_contents(DI::basePath() . (new Header(DI::config()))->getMastodonBannerPath())); } } diff --git a/src/Module/Profile/Conversations.php b/src/Module/Profile/Conversations.php index 715bf45d3..cda8f03f9 100644 --- a/src/Module/Profile/Conversations.php +++ b/src/Module/Profile/Conversations.php @@ -103,10 +103,10 @@ class Conversations extends BaseProfile $this->page['htmlhead'] .= '' . "\n"; } - $this->page['htmlhead'] .= '' . "\n"; - $this->page['htmlhead'] .= '' . "\n"; - $this->page['htmlhead'] .= '' . "\n"; - $this->page['htmlhead'] .= '' . "\n"; + $this->page['htmlhead'] .= '' . "\n"; + $this->page['htmlhead'] .= '' . "\n"; + $this->page['htmlhead'] .= '' . "\n"; + $this->page['htmlhead'] .= '' . "\n"; $category = $datequery = $datequery2 = ''; @@ -165,7 +165,7 @@ class Conversations extends BaseProfile $o .= $this->conversation->statusEditor($x); } - // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups + // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched their circles $condition = Item::getPermissionsConditionArrayByUserId($profile['uid']); $last_updated_array = $this->session->get('last_updated', []); @@ -188,7 +188,7 @@ class Conversations extends BaseProfile $condition = DBA::mergeConditions($condition, ["`received` >= ?", DateTimeFormat::convert($datequery2, 'UTC', $this->app->getTimeZone())]); } - // Does the profile page belong to a forum? + // Does the profile page belong to a group? // If not then we can improve the performance with an additional condition if ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY) { $condition = DBA::mergeConditions($condition, ['contact-id' => $profile['id']]); @@ -240,7 +240,7 @@ class Conversations extends BaseProfile $items = array_merge($items, $pinned); } - $o .= $this->conversation->create($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $profile['uid']); + $o .= $this->conversation->render($items, Conversation::MODE_PROFILE, false, false, 'pinned_received', $profile['uid']); $o .= $pager->renderMinimal(count($items)); diff --git a/src/Module/Profile/Photos.php b/src/Module/Profile/Photos.php index 9d8b27592..fcd0b78b0 100644 --- a/src/Module/Profile/Photos.php +++ b/src/Module/Profile/Photos.php @@ -93,14 +93,14 @@ class Photos extends \Friendica\Module\BaseProfile } $str_contact_allow = isset($request['contact_allow']) ? $this->aclFormatter->toString($request['contact_allow']) : $this->owner['allow_cid'] ?? ''; - $str_group_allow = isset($request['group_allow']) ? $this->aclFormatter->toString($request['group_allow']) : $this->owner['allow_gid'] ?? ''; + $str_circle_allow = isset($request['circle_allow']) ? $this->aclFormatter->toString($request['circle_allow']) : $this->owner['allow_gid'] ?? ''; $str_contact_deny = isset($request['contact_deny']) ? $this->aclFormatter->toString($request['contact_deny']) : $this->owner['deny_cid'] ?? ''; - $str_group_deny = isset($request['group_deny']) ? $this->aclFormatter->toString($request['group_deny']) : $this->owner['deny_gid'] ?? ''; + $str_circle_deny = isset($request['circle_deny']) ? $this->aclFormatter->toString($request['circle_deny']) : $this->owner['deny_gid'] ?? ''; $visibility = $request['visibility'] ?? ''; if ($visibility === 'public') { // The ACL selector introduced in version 2019.12 sends ACL input data even when the Public visibility is selected - $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + $str_contact_allow = $str_circle_allow = $str_contact_deny = $str_circle_deny = ''; } else if ($visibility === 'custom') { // Since we know from the visibility parameter the item should be private, we have to prevent the empty ACL // case that would make it public. So we always append the author's contact id to the allowed contacts. @@ -231,7 +231,7 @@ class Photos extends \Friendica\Module\BaseProfile $resource_id = Photo::newResource(); - $preview = Photo::storeWithPreview($image, $this->owner['uid'], $resource_id, $filename, $filesize, $album, '', $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny); + $preview = Photo::storeWithPreview($image, $this->owner['uid'], $resource_id, $filename, $filesize, $album, '', $str_contact_allow, $str_circle_allow, $str_contact_deny, $str_circle_deny); if ($preview < 0) { $this->logger->warning('image store failed'); $this->systemMessages->addNotice($this->t('Image upload failed.')); @@ -267,9 +267,9 @@ class Photos extends \Friendica\Module\BaseProfile $arr['author-avatar'] = $this->owner['thumb']; $arr['title'] = ''; $arr['allow_cid'] = $str_contact_allow; - $arr['allow_gid'] = $str_group_allow; + $arr['allow_gid'] = $str_circle_allow; $arr['deny_cid'] = $str_contact_deny; - $arr['deny_gid'] = $str_group_deny; + $arr['deny_gid'] = $str_circle_deny; $arr['visible'] = $visible; $arr['origin'] = 1; diff --git a/src/Module/Profile/Profile.php b/src/Module/Profile/Profile.php index d753cd762..054943c13 100644 --- a/src/Module/Profile/Profile.php +++ b/src/Module/Profile/Profile.php @@ -23,7 +23,7 @@ namespace Friendica\Module\Profile; use Friendica\App; use Friendica\Content\Feature; -use Friendica\Content\ForumManager; +use Friendica\Content\GroupManager; use Friendica\Content\Nav; use Friendica\Content\Text\BBCode; use Friendica\Core\Config\Capability\IManageConfigValues; @@ -84,7 +84,7 @@ class Profile extends BaseProfile $user = $this->database->selectFirst('user', ['uid'], ['nickname' => $this->parameters['nickname'] ?? '', 'account_removed' => false]); if ($user) { try { - $data = ActivityPub\Transmitter::getProfile($user['uid']); + $data = ActivityPub\Transmitter::getProfile($user['uid'], ActivityPub::isAcceptedRequester($user['uid'])); header('Access-Control-Allow-Origin: *'); header('Cache-Control: max-age=23200, stale-while-revalidate=23200'); System::jsonExit($data, 'application/activity+json'); @@ -254,12 +254,12 @@ class Profile extends BaseProfile ); } - //show subscribed forum if it is enabled in the usersettings + //show subscribed group if it is enabled in the usersettings if (Feature::isEnabled($profile['uid'], 'forumlist_profile')) { $custom_fields += self::buildField( - 'forumlist', - $this->t('Forums:'), - ForumManager::profileAdvanced($profile['uid']) + 'group_list', + $this->t('Groups:'), + GroupManager::profileAdvanced($profile['uid']) ); } diff --git a/src/Module/Register.php b/src/Module/Register.php index d26fb0a3d..a62525a98 100644 --- a/src/Module/Register.php +++ b/src/Module/Register.php @@ -150,7 +150,7 @@ class Register extends BaseModule '$invite_label' => DI::l10n()->t('Your invitation code: '), '$invite_id' => $invite_id, '$regtitle' => DI::l10n()->t('Registration'), - '$registertext' => BBCode::convert(DI::config()->get('config', 'register_text', '')), + '$registertext' => BBCode::convertForUriId(User::getSystemUriId(), DI::config()->get('config', 'register_text', '')), '$fillwith' => $fillwith, '$fillext' => $fillext, '$oidlabel' => $oidlabel, diff --git a/src/Module/RobotsTxt.php b/src/Module/RobotsTxt.php index 49aab1471..a084c1f4a 100644 --- a/src/Module/RobotsTxt.php +++ b/src/Module/RobotsTxt.php @@ -38,6 +38,8 @@ class RobotsTxt extends BaseModule '/search', '/help', '/proxy', + '/photo', + '/avatar', ]; header('Content-Type: text/plain'); @@ -45,6 +47,15 @@ class RobotsTxt extends BaseModule foreach ($allDisallowed as $disallowed) { echo 'Disallow: ' . $disallowed . PHP_EOL; } + + echo PHP_EOL; + echo 'User-agent: ChatGPT-User' . PHP_EOL; + echo 'Disallow: /' . PHP_EOL; + + echo PHP_EOL; + echo 'User-agent: GPTBot' . PHP_EOL; + echo 'Disallow: /' . PHP_EOL; + System::exit(); } } diff --git a/src/Module/Search/Acl.php b/src/Module/Search/Acl.php index 11c3eea79..66e371dd1 100644 --- a/src/Module/Search/Acl.php +++ b/src/Module/Search/Acl.php @@ -46,13 +46,13 @@ use Psr\Log\LoggerInterface; */ class Acl extends BaseModule { - const TYPE_GLOBAL_CONTACT = 'x'; - const TYPE_MENTION_CONTACT = 'c'; - const TYPE_MENTION_GROUP = 'g'; - const TYPE_MENTION_CONTACT_GROUP = ''; - const TYPE_MENTION_FORUM = 'f'; - const TYPE_PRIVATE_MESSAGE = 'm'; - const TYPE_ANY_CONTACT = 'a'; + const TYPE_GLOBAL_CONTACT = 'x'; + const TYPE_MENTION_CONTACT = 'c'; + const TYPE_MENTION_CIRCLE = 'g'; + const TYPE_MENTION_CONTACT_CIRCLE = ''; + const TYPE_MENTION_GROUP = 'f'; + const TYPE_PRIVATE_MESSAGE = 'm'; + const TYPE_ANY_CONTACT = 'a'; /** @var IHandleUserSessions */ private $session; @@ -73,7 +73,7 @@ class Acl extends BaseModule throw new HTTPException\UnauthorizedException($this->t('You must be logged in to use this module.')); } - $type = $request['type'] ?? self::TYPE_MENTION_CONTACT_GROUP; + $type = $request['type'] ?? self::TYPE_MENTION_CONTACT_CIRCLE; if ($type === self::TYPE_GLOBAL_CONTACT) { $o = $this->globalContactSearch($request); } else { @@ -100,7 +100,7 @@ class Acl extends BaseModule 'nick' => $contact['addr'] ?: $contact['url'], 'network' => $contact['network'], 'link' => $contact['url'], - 'forum' => $contact['contact-type'] == Contact::TYPE_COMMUNITY, + 'group' => $contact['contact-type'] == Contact::TYPE_COMMUNITY, ]; } @@ -128,28 +128,28 @@ class Acl extends BaseModule $this->logger->info('ACL {action} - {subaction} - start', ['module' => 'acl', 'action' => 'content', 'subaction' => 'search', 'search' => $search, 'type' => $type, 'conversation' => $conv_id]); - $sql_extra = ''; - $condition = ["`uid` = ? AND NOT `deleted` AND NOT `pending` AND NOT `archive`", $this->session->getLocalUserId()]; - $condition_group = ["`uid` = ? AND NOT `deleted`", $this->session->getLocalUserId()]; + $sql_extra = ''; + $condition = ["`uid` = ? AND NOT `deleted` AND NOT `pending` AND NOT `archive`", $this->session->getLocalUserId()]; + $condition_circle = ["`uid` = ? AND NOT `deleted`", $this->session->getLocalUserId()]; if ($search != '') { - $sql_extra = "AND `name` LIKE '%%" . $this->database->escape($search) . "%%'"; - $condition = DBA::mergeConditions($condition, ["(`attag` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", + $sql_extra = "AND `name` LIKE '%%" . $this->database->escape($search) . "%%'"; + $condition = DBA::mergeConditions($condition, ["(`attag` LIKE ? OR `name` LIKE ? OR `nick` LIKE ?)", '%' . $search . '%', '%' . $search . '%', '%' . $search . '%']); - $condition_group = DBA::mergeConditions($condition_group, ["`name` LIKE ?", '%' . $search . '%']); + $condition_circle = DBA::mergeConditions($condition_circle, ["`name` LIKE ?", '%' . $search . '%']); } - // count groups and contacts - $group_count = 0; - if ($type == self::TYPE_MENTION_CONTACT_GROUP || $type == self::TYPE_MENTION_GROUP) { - $group_count = $this->database->count('group', $condition_group); + // count circles and contacts + $circle_count = 0; + if ($type == self::TYPE_MENTION_CONTACT_CIRCLE || $type == self::TYPE_MENTION_CIRCLE) { + $circle_count = $this->database->count('group', $condition_circle); } $networks = Widget::unavailableNetworks(); $condition = DBA::mergeConditions($condition, array_merge(["NOT `network` IN (" . substr(str_repeat("?, ", count($networks)), 0, -2) . ")"], $networks)); switch ($type) { - case self::TYPE_MENTION_CONTACT_GROUP: + case self::TYPE_MENTION_CONTACT_CIRCLE: $condition = DBA::mergeConditions($condition, ["NOT `self` AND NOT `blocked` AND `notify` != ? AND `network` != ?", '', Protocol::OSTATUS ]); @@ -161,7 +161,7 @@ class Acl extends BaseModule ]); break; - case self::TYPE_MENTION_FORUM: + case self::TYPE_MENTION_GROUP: $condition = DBA::mergeConditions($condition, ["NOT `self` AND NOT `blocked` AND `notify` != ? AND `contact-type` = ?", '', Contact::TYPE_COMMUNITY ]); @@ -176,52 +176,52 @@ class Acl extends BaseModule $contact_count = $this->database->count('contact', $condition); - $resultTotal = $group_count + $contact_count; + $resultTotal = $circle_count + $contact_count; - $resultGroups = []; + $resultCircles = []; $resultContacts = []; - if ($type == self::TYPE_MENTION_CONTACT_GROUP || $type == self::TYPE_MENTION_GROUP) { + if ($type == self::TYPE_MENTION_CONTACT_CIRCLE || $type == self::TYPE_MENTION_CIRCLE) { /// @todo We should cache this query. // This can be done when we can delete cache entries via wildcard - $groups = $this->database->toArray($this->database->p("SELECT `group`.`id`, `group`.`name`, GROUP_CONCAT(DISTINCT `group_member`.`contact-id` SEPARATOR ',') AS uids - FROM `group` - INNER JOIN `group_member` ON `group_member`.`gid`=`group`.`id` - WHERE NOT `group`.`deleted` AND `group`.`uid` = ? + $circles = $this->database->toArray($this->database->p("SELECT `circle`.`id`, `circle`.`name`, GROUP_CONCAT(DISTINCT `circle_member`.`contact-id` SEPARATOR ',') AS uids + FROM `group` AS `circle` + INNER JOIN `group_member` AS `circle_member` ON `circle_member`.`gid` = `circle`.`id` + WHERE NOT `circle`.`deleted` AND `circle`.`uid` = ? $sql_extra - GROUP BY `group`.`name`, `group`.`id` - ORDER BY `group`.`name` + GROUP BY `circle`.`name`, `circle`.`id` + ORDER BY `circle`.`name` LIMIT ?, ?", $this->session->getLocalUserId(), $start, $count )); - foreach ($groups as $group) { - $resultGroups[] = [ - 'type' => 'g', + foreach ($circles as $circle) { + $resultCircles[] = [ + 'type' => self::TYPE_MENTION_CIRCLE, 'photo' => 'images/twopeople.png', - 'name' => htmlspecialchars($group['name']), - 'id' => intval($group['id']), - 'uids' => array_map('intval', explode(',', $group['uids'])), + 'name' => htmlspecialchars($circle['name']), + 'id' => intval($circle['id']), + 'uids' => array_map('intval', explode(',', $circle['uids'])), 'link' => '', - 'forum' => '0' + 'group' => '0' ]; } - if ((count($resultGroups) > 0) && ($search == '')) { - $resultGroups[] = ['separator' => true]; + if ((count($resultCircles) > 0) && ($search == '')) { + $resultCircles[] = ['separator' => true]; } } $contacts = []; - if ($type != self::TYPE_MENTION_GROUP) { + if ($type != self::TYPE_MENTION_CIRCLE) { $contacts = Contact::selectToArray([], $condition, ['order' => ['name']]); } - $forums = []; + $groups = []; foreach ($contacts as $contact) { $entry = [ - 'type' => 'c', + 'type' => self::TYPE_MENTION_CONTACT, 'photo' => Contact::getMicro($contact, true), 'name' => htmlspecialchars($contact['name']), 'id' => intval($contact['id']), @@ -229,24 +229,24 @@ class Acl extends BaseModule 'link' => $contact['url'], 'nick' => htmlentities(($contact['attag'] ?? '') ?: $contact['nick']), 'addr' => htmlentities(($contact['addr'] ?? '') ?: $contact['url']), - 'forum' => $contact['contact-type'] == Contact::TYPE_COMMUNITY, + 'group' => $contact['contact-type'] == Contact::TYPE_COMMUNITY, ]; - if ($entry['forum']) { - $forums[] = $entry; + if ($entry['group']) { + $groups[] = $entry; } else { $resultContacts[] = $entry; } } - if ($forums) { + if ($groups) { if ($search == '') { - $forums[] = ['separator' => true]; + $groups[] = ['separator' => true]; } - $resultContacts = array_merge($forums, $resultContacts); + $resultContacts = array_merge($groups, $resultContacts); } - $resultItems = array_merge($resultGroups, $resultContacts); + $resultItems = array_merge($resultCircles, $resultContacts); if ($conv_id) { // In multithreaded posts the conv_id is not the parent of the whole thread @@ -277,7 +277,7 @@ class Acl extends BaseModule $contact = Contact::getByURL($author, false, ['micro', 'name', 'id', 'network', 'nick', 'addr', 'url', 'forum', 'avatar']); if ($contact) { $unknown_contacts[] = [ - 'type' => 'c', + 'type' => self::TYPE_MENTION_CONTACT, 'photo' => Contact::getMicro($contact, true), 'name' => htmlspecialchars($contact['name']), 'id' => intval($contact['id']), @@ -285,7 +285,7 @@ class Acl extends BaseModule 'link' => $contact['url'], 'nick' => htmlentities(($contact['nick'] ?? '') ?: $contact['addr']), 'addr' => htmlentities(($contact['addr'] ?? '') ?: $contact['url']), - 'forum' => $contact['forum'] + 'group' => $contact['forum'] ]; } } @@ -298,7 +298,7 @@ class Acl extends BaseModule 'tot' => $resultTotal, 'start' => $start, 'count' => $count, - 'groups' => $resultGroups, + 'circles' => $resultCircles, 'contacts' => $resultContacts, 'items' => $resultItems, 'type' => $type, diff --git a/src/Module/Search/Filed.php b/src/Module/Search/Filed.php index 4661a5866..5f519b60c 100644 --- a/src/Module/Search/Filed.php +++ b/src/Module/Search/Filed.php @@ -99,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, Conversation::MODE_FILED, false, false, '', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->render($items, Conversation::MODE_FILED, false, false, '', DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); diff --git a/src/Module/Search/Index.php b/src/Module/Search/Index.php index 167389684..f1d99bdf1 100644 --- a/src/Module/Search/Index.php +++ b/src/Module/Search/Index.php @@ -139,7 +139,7 @@ class Index extends BaseSearch break; case 'contacts': return self::performContactSearch($search, '@'); - case 'forums': + case 'groups': return self::performContactSearch($search, '!'); } } @@ -173,7 +173,7 @@ class Index extends BaseSearch $pager = new Pager(DI::l10n(), DI::args()->getQueryString(), $itemsPerPage); if ($tag) { - Logger::info('Start tag search.', ['q' => $search]); + Logger::info('Start tag search.', ['q' => $search, 'start' => $pager->getStart(), 'items' => $pager->getItemsPerPage(), 'last' => $last_uriid]); $uriids = Tag::getURIIdListByTag($search, DI::userSession()->getLocalUserId(), $pager->getStart(), $pager->getItemsPerPage(), $last_uriid); $count = Tag::countByTag($search, DI::userSession()->getLocalUserId()); } else { @@ -185,7 +185,7 @@ class Index extends BaseSearch if (!empty($uriids)) { $condition = ["(`uid` = ? OR (`uid` = ? AND NOT `global`))", 0, DI::userSession()->getLocalUserId()]; $condition = DBA::mergeConditions($condition, ['uri-id' => $uriids]); - $params = ['order' => ['id' => true]]; + $params = ['order' => ['uri-id' => true]]; $items = Post::toArray(Post::selectForUser(DI::userSession()->getLocalUserId(), Item::DISPLAY_FIELDLIST, $condition, $params)); } @@ -213,7 +213,7 @@ class Index extends BaseSearch Logger::info('Start Conversation.', ['q' => $search]); - $o .= DI::conversation()->create($items, Conversation::MODE_SEARCH, false, false, 'commented', DI::userSession()->getLocalUserId()); + $o .= DI::conversation()->render($items, Conversation::MODE_SEARCH, false, false, 'commented', DI::userSession()->getLocalUserId()); if (DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'infinite_scroll')) { $o .= HTML::scrollLoader(); diff --git a/src/Module/Settings/Account.php b/src/Module/Settings/Account.php index cba12cc39..8ff00addb 100644 --- a/src/Module/Settings/Account.php +++ b/src/Module/Settings/Account.php @@ -29,7 +29,7 @@ use Friendica\Core\Search; use Friendica\Core\Worker; use Friendica\Database\DBA; use Friendica\DI; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Notification; use Friendica\Model\Post\UserNotification; use Friendica\Model\Profile; @@ -162,23 +162,24 @@ class Account extends BaseSettings $blocktags = empty($request['blocktags']); // this setting is inverted! $unkmail = !empty($request['unkmail']); $cntunkmail = intval($request['cntunkmail'] ?? 0); - $def_gid = intval($request['group-selection'] ?? 0); + $def_gid = intval($request['circle-selection'] ?? 0); $aclFormatter = DI::aclFormatter(); - $str_group_allow = !empty($request['group_allow']) ? $aclFormatter->toString($request['group_allow']) : ''; $str_contact_allow = !empty($request['contact_allow']) ? $aclFormatter->toString($request['contact_allow']) : ''; - $str_group_deny = !empty($request['group_deny']) ? $aclFormatter->toString($request['group_deny']) : ''; - $str_contact_deny = !empty($request['contact_deny']) ? $aclFormatter->toString($request['contact_deny']) : ''; + $str_circle_allow = !empty($request['circle_allow']) ? $aclFormatter->toString($request['circle_allow']) : ''; + $str_contact_deny = !empty($request['contact_deny']) ? $aclFormatter->toString($request['contact_deny']) : ''; + $str_circle_deny = !empty($request['circle_deny']) ? $aclFormatter->toString($request['circle_deny']) : ''; DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'system', 'unlisted', !empty($request['unlisted'])); DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'system', 'accessible-photos', !empty($request['accessible-photos'])); + DI::pConfig()->set(DI::userSession()->getLocalUserId(), 'system', 'default-group-gid', intval($request['circle-selection-group'] ?? $def_gid)); $fields = [ 'allow_cid' => $str_contact_allow, - 'allow_gid' => $str_group_allow, + 'allow_gid' => $str_circle_allow, 'deny_cid' => $str_contact_deny, - 'deny_gid' => $str_group_deny, + 'deny_gid' => $str_circle_deny, 'maxreq' => $maxreq, 'def_gid' => $def_gid, 'blockwall' => $blockwall, @@ -329,7 +330,7 @@ class Account extends BaseSettings $fields = [ 'allow_cid' => '', 'allow_gid' => $page_flags == User::PAGE_FLAGS_PRVGROUP ? - '<' . Group::FOLLOWERS . '>' + '<' . Circle::FOLLOWERS . '>' : '', 'deny_cid' => '', 'deny_gid' => '', @@ -452,7 +453,7 @@ class Account extends BaseSettings $pagetype = Renderer::replaceMacros($pageset_tpl, [ '$account_types' => DI::l10n()->t("Account Types"), '$user' => DI::l10n()->t("Personal Page Subtypes"), - '$community' => DI::l10n()->t("Community Forum Subtypes"), + '$community' => DI::l10n()->t("Community Group Subtypes"), '$account_type' => $user['account-type'], '$type_person' => User::ACCOUNT_TYPE_PERSON, '$type_organisation' => User::ACCOUNT_TYPE_ORGANISATION, @@ -481,7 +482,7 @@ class Account extends BaseSettings ], '$account_community' => [ 'account-type', - DI::l10n()->t('Community Forum'), + DI::l10n()->t('Community Group'), User::ACCOUNT_TYPE_COMMUNITY, DI::l10n()->t('Account for community discussions.'), $user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY @@ -502,7 +503,7 @@ class Account extends BaseSettings ], '$page_community' => [ 'page-flags', - DI::l10n()->t('Public Forum'), + DI::l10n()->t('Public Group'), User::PAGE_FLAGS_COMMUNITY, DI::l10n()->t('Automatically approves all contact requests.'), $user['page-flags'] == User::PAGE_FLAGS_COMMUNITY @@ -516,7 +517,7 @@ class Account extends BaseSettings ], '$page_prvgroup' => [ 'page-flags', - DI::l10n()->t('Private Forum [Experimental]'), + DI::l10n()->t('Private Group [Experimental]'), User::PAGE_FLAGS_PRVGROUP, DI::l10n()->t('Requires manual approval of contact requests.'), $user['page-flags'] == User::PAGE_FLAGS_PRVGROUP @@ -572,7 +573,7 @@ class Account extends BaseSettings '$delete_openid' => ['delete_openid', DI::l10n()->t('Delete OpenID URL'), false, ''], '$h_basic' => DI::l10n()->t('Basic Settings'), - '$username' => ['username', DI::l10n()->t('Full Name:'), $username, '', false, 'autocomplete="off"'], + '$username' => ['username', DI::l10n()->t('Display name:'), $username, '', false, 'autocomplete="off"'], '$email' => ['email', DI::l10n()->t('Email Address:'), $email, '', '', 'autocomplete="off"', 'email'], '$timezone' => ['timezone_select', DI::l10n()->t('Your Timezone:'), Temporal::getTimezoneSelect($timezone), ''], '$language' => ['language', DI::l10n()->t('Your Language:'), $language, DI::l10n()->t('Set the language we use to show you friendica interface and to send you emails'), $lang_choices], @@ -592,7 +593,8 @@ class Account extends BaseSettings '$blocktags' => ['blocktags', DI::l10n()->t('Allow friends to tag your posts?'), (intval($user['blocktags']) ? '0' : '1'), DI::l10n()->t('Your contacts can add additional tags to your posts.')], '$unkmail' => ['unkmail', DI::l10n()->t('Permit unknown people to send you private mail?'), $unkmail, DI::l10n()->t('Friendica network users may send you private messages even if they are not in your contact list.')], '$cntunkmail' => ['cntunkmail', DI::l10n()->t('Maximum private messages per day from unknown people:'), $cntunkmail, DI::l10n()->t("(to prevent spam abuse)")], - '$group_select' => Group::displayGroupSelection(DI::userSession()->getLocalUserId(), $user['def_gid']), + '$circle_select' => Circle::getSelectorHTML(DI::userSession()->getLocalUserId(), $user['def_gid'], 'circle-selection', DI::l10n()->t('Default privacy circle for new contacts')), + '$circle_select_group' => Circle::getSelectorHTML(DI::userSession()->getLocalUserId(), DI::pConfig()->get(DI::userSession()->getLocalUserId(), 'system', 'default-group-gid', $user['def_gid']), 'circle-selection-group', DI::l10n()->t('Default privacy circle for new group contacts')), '$permissions' => DI::l10n()->t('Default Post Permissions'), '$aclselect' => ACL::getFullSelectorHTML(DI::page(), $a->getLoggedInUserId()), diff --git a/src/Module/Settings/Delegation.php b/src/Module/Settings/Delegation.php index 134b002c1..3fd5fef49 100644 --- a/src/Module/Settings/Delegation.php +++ b/src/Module/Settings/Delegation.php @@ -43,11 +43,13 @@ class Delegation extends BaseSettings BaseModule::checkFormSecurityTokenRedirectOnError('settings/delegation', 'delegate'); - $parent_uid = (int)$_POST['parent_user'] ?? 0; - $parent_password = $_POST['parent_password'] ?? ''; + $parent_uid = $request['parent_user'] ?? null; + $parent_password = $request['parent_password'] ?? ''; - if ($parent_uid != 0) { + if ($parent_uid) { try { + // An integer value will trigger the direct user query on uid in User::getAuthenticationInfo + $parent_uid = (int)$parent_uid; User::getIdFromPasswordAuthentication($parent_uid, $parent_password); DI::sysmsg()->addInfo(DI::l10n()->t('Delegation successfully granted.')); } catch (\Exception $ex) { @@ -142,7 +144,7 @@ class Delegation extends BaseSettings $parents = [0 => DI::l10n()->t('No parent user')]; $fields = ['uid', 'username', 'nickname']; - $condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => 0]; + $condition = ['email' => $user['email'], 'verified' => true, 'blocked' => false, 'parent-uid' => null]; $parent_users = DBA::selectToArray('user', $fields, $condition); foreach($parent_users as $parent) { if ($parent['uid'] != DI::userSession()->getLocalUserId()) { diff --git a/src/Module/Settings/Profile/Index.php b/src/Module/Settings/Profile/Index.php index 4e3967ec1..38d816833 100644 --- a/src/Module/Settings/Profile/Index.php +++ b/src/Module/Settings/Profile/Index.php @@ -21,43 +21,75 @@ namespace Friendica\Module\Settings\Profile; +use Friendica\App; use Friendica\Core\ACL; use Friendica\Core\Hook; +use Friendica\Core\L10n; use Friendica\Core\Protocol; use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; use Friendica\Core\Theme; use Friendica\Database\DBA; -use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Profile; -use Friendica\Profile\ProfileField\Collection\ProfileFields; -use Friendica\Profile\ProfileField\Entity\ProfileField; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Profile\ProfileField; use Friendica\Model\User; use Friendica\Module\BaseSettings; use Friendica\Module\Security\Login; use Friendica\Network\HTTPException; +use Friendica\Security\PermissionSet; +use Friendica\Util\ACLFormatter; use Friendica\Util\DateTimeFormat; +use Friendica\Util\Profiler; use Friendica\Util\Temporal; use Friendica\Core\Worker; +use Psr\Log\LoggerInterface; class Index extends BaseSettings { + /** @var ProfileField\Repository\ProfileField */ + private $profileFieldRepo; + /** @var ProfileField\Factory\ProfileField */ + private $profileFieldFactory; + /** @var SystemMessages */ + private $systemMessages; + /** @var PermissionSet\Repository\PermissionSet */ + private $permissionSetRepo; + /** @var PermissionSet\Factory\PermissionSet */ + private $permissionSetFactory; + /** @var ACLFormatter */ + private $aclFormatter; + + public function __construct(ACLFormatter $aclFormatter, PermissionSet\Factory\PermissionSet $permissionSetFactory, PermissionSet\Repository\PermissionSet $permissionSetRepo, SystemMessages $systemMessages, ProfileField\Factory\ProfileField $profileFieldFactory, ProfileField\Repository\ProfileField $profileFieldRepo, 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->profileFieldRepo = $profileFieldRepo; + $this->profileFieldFactory = $profileFieldFactory; + $this->systemMessages = $systemMessages; + $this->permissionSetRepo = $permissionSetRepo; + $this->permissionSetFactory = $permissionSetFactory; + $this->aclFormatter = $aclFormatter; + } + protected function post(array $request = []) { - if (!DI::userSession()->getLocalUserId()) { + if (!$this->session->getLocalUserId()) { return; } - $profile = Profile::getByUID(DI::userSession()->getLocalUserId()); - if (!DBA::isResult($profile)) { + $profile = Profile::getByUID($this->session->getLocalUserId()); + if (!$profile) { return; } self::checkFormSecurityTokenRedirectOnError('/settings/profile', 'settings_profile'); - Hook::callAll('profile_post', $_POST); + Hook::callAll('profile_post', $request); - $dob = trim($_POST['dob'] ?? ''); + $dob = trim($request['dob'] ?? ''); if ($dob && !in_array($dob, ['0000-00-00', DBA::NULL_DATE])) { $y = substr($dob, 0, 4); @@ -79,39 +111,40 @@ class Index extends BaseSettings } } - $name = trim($_POST['name'] ?? ''); - if (!strlen($name)) { - DI::sysmsg()->addNotice(DI::l10n()->t('Profile Name is required.')); + $username = trim($request['username'] ?? ''); + if (!$username) { + $this->systemMessages->addNotice($this->t('Display Name is required.')); return; } - $about = trim($_POST['about']); - $address = trim($_POST['address']); - $locality = trim($_POST['locality']); - $region = trim($_POST['region']); - $postal_code = trim($_POST['postal_code']); - $country_name = trim($_POST['country_name']); - $pub_keywords = self::cleanKeywords(trim($_POST['pub_keywords'])); - $prv_keywords = self::cleanKeywords(trim($_POST['prv_keywords'])); - $xmpp = trim($_POST['xmpp']); - $matrix = trim($_POST['matrix']); - $homepage = trim($_POST['homepage']); + $about = trim($request['about']); + $address = trim($request['address']); + $locality = trim($request['locality']); + $region = trim($request['region']); + $postal_code = trim($request['postal_code']); + $country_name = trim($request['country_name']); + $pub_keywords = self::cleanKeywords(trim($request['pub_keywords'])); + $prv_keywords = self::cleanKeywords(trim($request['prv_keywords'])); + $xmpp = trim($request['xmpp']); + $matrix = trim($request['matrix']); + $homepage = trim($request['homepage']); if ((strpos($homepage, 'http') !== 0) && (strlen($homepage))) { // neither http nor https in URL, add them $homepage = 'http://' . $homepage; } - $profileFieldsNew = self::getProfileFieldsFromInput( - DI::userSession()->getLocalUserId(), - $_REQUEST['profile_field'], - $_REQUEST['profile_field_order'] + $profileFieldsNew = $this->getProfileFieldsFromInput( + $this->session->getLocalUserId(), + $request['profile_field'], + $request['profile_field_order'] ); - DI::profileField()->saveCollectionForUser(DI::userSession()->getLocalUserId(), $profileFieldsNew); + $this->profileFieldRepo->saveCollectionForUser($this->session->getLocalUserId(), $profileFieldsNew); + + User::update(['username' => $username], $this->session->getLocalUserId()); $result = Profile::update( [ - 'name' => $name, 'about' => $about, 'dob' => $dob, 'address' => $address, @@ -125,23 +158,23 @@ class Index extends BaseSettings 'pub_keywords' => $pub_keywords, 'prv_keywords' => $prv_keywords, ], - DI::userSession()->getLocalUserId() + $this->session->getLocalUserId() ); - Worker::add(Worker::PRIORITY_MEDIUM, 'CheckRelMeProfileLink', DI::userSession()->getLocalUserId()); + Worker::add(Worker::PRIORITY_MEDIUM, 'CheckRelMeProfileLink', $this->session->getLocalUserId()); if (!$result) { - DI::sysmsg()->addNotice(DI::l10n()->t('Profile couldn\'t be updated.')); + $this->systemMessages->addNotice($this->t("Profile couldn't be updated.")); return; } - DI::baseUrl()->redirect('settings/profile'); + $this->baseUrl->redirect('settings/profile'); } protected function content(array $request = []): string { - if (!DI::userSession()->getLocalUserId()) { - DI::sysmsg()->addNotice(DI::l10n()->t('You must be logged in to use this module')); + if (!$this->session->getLocalUserId()) { + $this->systemMessages->addNotice($this->t('You must be logged in to use this module')); return Login::form(); } @@ -149,147 +182,145 @@ class Index extends BaseSettings $o = ''; - $profile = User::getOwnerDataById(DI::userSession()->getLocalUserId()); - if (!DBA::isResult($profile)) { + $owner = User::getOwnerDataById($this->session->getLocalUserId()); + if (!$owner) { throw new HTTPException\NotFoundException(); } - $a = DI::app(); - - DI::page()->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js'); - DI::page()->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js')); + $this->page->registerFooterScript('view/asset/es-jquery-sortable/source/js/jquery-sortable-min.js'); + $this->page->registerFooterScript(Theme::getPathForFile('js/module/settings/profile/index.js')); $custom_fields = []; - $profileFields = DI::profileField()->selectByUserId(DI::userSession()->getLocalUserId()); + $profileFields = $this->profileFieldRepo->selectByUserId($this->session->getLocalUserId()); foreach ($profileFields as $profileField) { - /** @var ProfileField $profileField */ $defaultPermissions = $profileField->permissionSet->withAllowedContacts( Contact::pruneUnavailable($profileField->permissionSet->allow_cid) ); $custom_fields[] = [ - 'id' => $profileField->id, + 'id' => $profileField->id, 'legend' => $profileField->label, 'fields' => [ - 'label' => ['profile_field[' . $profileField->id . '][label]', DI::l10n()->t('Label:'), $profileField->label], - 'value' => ['profile_field[' . $profileField->id . '][value]', DI::l10n()->t('Value:'), $profileField->value], - 'acl' => ACL::getFullSelectorHTML( - DI::page(), - $a->getLoggedInUserId(), + 'label' => ['profile_field[' . $profileField->id . '][label]', $this->t('Label:'), $profileField->label], + 'value' => ['profile_field[' . $profileField->id . '][value]', $this->t('Value:'), $profileField->value], + 'acl' => ACL::getFullSelectorHTML( + $this->page, + $this->session->getLocalUserId(), false, $defaultPermissions->toArray(), ['network' => Protocol::DFRN], 'profile_field[' . $profileField->id . ']' ), ], - 'permissions' => DI::l10n()->t('Field Permissions'), - 'permdesc' => DI::l10n()->t("(click to open/close)"), + + 'permissions' => $this->t('Field Permissions'), + 'permdesc' => $this->t("(click to open/close)"), ]; - }; + } $custom_fields[] = [ - 'id' => 'new', - 'legend' => DI::l10n()->t('Add a new profile field'), + 'id' => 'new', + 'legend' => $this->t('Add a new profile field'), 'fields' => [ - 'label' => ['profile_field[new][label]', DI::l10n()->t('Label:')], - 'value' => ['profile_field[new][value]', DI::l10n()->t('Value:')], - 'acl' => ACL::getFullSelectorHTML( - DI::page(), - $a->getLoggedInUserId(), + 'label' => ['profile_field[new][label]', $this->t('Label:')], + 'value' => ['profile_field[new][value]', $this->t('Value:')], + 'acl' => ACL::getFullSelectorHTML( + $this->page, + $this->session->getLocalUserId(), false, ['allow_cid' => []], ['network' => Protocol::DFRN], 'profile_field[new]' ), ], - 'permissions' => DI::l10n()->t('Field Permissions'), - 'permdesc' => DI::l10n()->t("(click to open/close)"), + + 'permissions' => $this->t('Field Permissions'), + 'permdesc' => $this->t("(click to open/close)"), ]; - DI::page()['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl'), [ - ]); + $this->page['htmlhead'] .= Renderer::replaceMacros(Renderer::getMarkupTemplate('settings/profile/index_head.tpl')); - $personal_account = ($profile['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); + $personal_account = ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); - if ($profile['homepage_verified']) { - $homepage_help_text = DI::l10n()->t('The homepage is verified. A rel="me" link back to your Friendica profile page was found on the homepage.'); + if ($owner['homepage_verified']) { + $homepage_help_text = $this->t('The homepage is verified. A rel="me" link back to your Friendica profile page was found on the homepage.'); } else { - $homepage_help_text = DI::l10n()->t('To verify your homepage, add a rel="me" link to it, pointing to your profile URL (%s).', $profile['url']); + $homepage_help_text = $this->t('To verify your homepage, add a rel="me" link to it, pointing to your profile URL (%s).', $owner['url']); } $tpl = Renderer::getMarkupTemplate('settings/profile/index.tpl'); $o .= Renderer::replaceMacros($tpl, [ - '$personal_account' => $personal_account, - - '$form_security_token' => self::getFormSecurityToken('settings_profile'), - '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), - - '$profile_action' => DI::l10n()->t('Profile Actions'), - '$banner' => DI::l10n()->t('Edit Profile Details'), - '$submit' => DI::l10n()->t('Submit'), - '$profpic' => DI::l10n()->t('Change Profile Photo'), - '$profpiclink' => '/profile/' . $profile['nickname'] . '/photos', - '$viewprof' => DI::l10n()->t('View Profile'), - - '$lbl_personal_section' => DI::l10n()->t('Personal'), - '$lbl_picture_section' => DI::l10n()->t('Profile picture'), - '$lbl_location_section' => DI::l10n()->t('Location'), - '$lbl_miscellaneous_section' => DI::l10n()->t('Miscellaneous'), - '$lbl_custom_fields_section' => DI::l10n()->t('Custom Profile Fields'), - - '$lbl_profile_photo' => DI::l10n()->t('Upload Profile Photo'), - - '$baseurl' => DI::baseUrl(), - '$nickname' => $profile['nickname'], - '$name' => ['name', DI::l10n()->t('Display name:'), $profile['name']], - '$about' => ['about', DI::l10n()->t('Description:'), $profile['about']], - '$dob' => Temporal::getDateofBirthField($profile['dob'], $profile['timezone']), - '$address' => ['address', DI::l10n()->t('Street Address:'), $profile['address']], - '$locality' => ['locality', DI::l10n()->t('Locality/City:'), $profile['locality']], - '$region' => ['region', DI::l10n()->t('Region/State:'), $profile['region']], - '$postal_code' => ['postal_code', DI::l10n()->t('Postal/Zip Code:'), $profile['postal-code']], - '$country_name' => ['country_name', DI::l10n()->t('Country:'), $profile['country-name']], - '$age' => ((intval($profile['dob'])) ? '(' . DI::l10n()->t('Age: ') . DI::l10n()->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($profile['dob'], $profile['timezone'])) . ')' : ''), - '$xmpp' => ['xmpp', DI::l10n()->t('XMPP (Jabber) address:'), $profile['xmpp'], DI::l10n()->t('The XMPP address will be published so that people can follow you there.')], - '$matrix' => ['matrix', DI::l10n()->t('Matrix (Element) address:'), $profile['matrix'], DI::l10n()->t('The Matrix address will be published so that people can follow you there.')], - '$homepage' => ['homepage', DI::l10n()->t('Homepage URL:'), $profile['homepage'], $homepage_help_text], - '$pub_keywords' => ['pub_keywords', DI::l10n()->t('Public Keywords:'), $profile['pub_keywords'], DI::l10n()->t('(Used for suggesting potential friends, can be seen by others)')], - '$prv_keywords' => ['prv_keywords', DI::l10n()->t('Private Keywords:'), $profile['prv_keywords'], DI::l10n()->t('(Used for searching profiles, never shown to others)')], - '$custom_fields_description' => DI::l10n()->t("

Custom fields appear on your profile page.

+ '$l10n' => [ + 'profile_action' => $this->t('Profile Actions'), + 'banner' => $this->t('Edit Profile Details'), + 'submit' => $this->t('Submit'), + 'profpic' => $this->t('Change Profile Photo'), + 'viewprof' => $this->t('View Profile'), + 'personal_section' => $this->t('Personal'), + 'picture_section' => $this->t('Profile picture'), + 'location_section' => $this->t('Location'), + 'miscellaneous_section' => $this->t('Miscellaneous'), + 'custom_fields_section' => $this->t('Custom Profile Fields'), + 'profile_photo' => $this->t('Upload Profile Photo'), + 'custom_fields_description' => $this->t('

Custom fields appear on your profile page.

You can use BBCodes in the field values.

Reorder by dragging the field title.

Empty the label field to remove a custom field.

-

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected groups.

", - 'profile/' . $profile['nickname'] . '/profile' - ), +

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

', + 'profile/' . $owner['nickname'] . '/profile' + ), + ], + + '$personal_account' => $personal_account, + + '$form_security_token' => self::getFormSecurityToken('settings_profile'), + '$form_security_token_photo' => self::getFormSecurityToken('settings_profile_photo'), + + '$profpiclink' => '/profile/' . $owner['nickname'] . '/photos', + + '$nickname' => $owner['nickname'], + '$username' => ['username', $this->t('Display name:'), $owner['name']], + '$about' => ['about', $this->t('Description:'), $owner['about']], + '$dob' => Temporal::getDateofBirthField($owner['dob'], $owner['timezone']), + '$address' => ['address', $this->t('Street Address:'), $owner['address']], + '$locality' => ['locality', $this->t('Locality/City:'), $owner['locality']], + '$region' => ['region', $this->t('Region/State:'), $owner['region']], + '$postal_code' => ['postal_code', $this->t('Postal/Zip Code:'), $owner['postal-code']], + '$country_name' => ['country_name', $this->t('Country:'), $owner['country-name']], + '$age' => ((intval($owner['dob'])) ? '(' . $this->t('Age: ') . $this->tt('%d year old', '%d years old', Temporal::getAgeByTimezone($owner['dob'], $owner['timezone'])) . ')' : ''), + '$xmpp' => ['xmpp', $this->t('XMPP (Jabber) address:'), $owner['xmpp'], $this->t('The XMPP address will be published so that people can follow you there.')], + '$matrix' => ['matrix', $this->t('Matrix (Element) address:'), $owner['matrix'], $this->t('The Matrix address will be published so that people can follow you there.')], + '$homepage' => ['homepage', $this->t('Homepage URL:'), $owner['homepage'], $homepage_help_text], + '$pub_keywords' => ['pub_keywords', $this->t('Public Keywords:'), $owner['pub_keywords'], $this->t('(Used for suggesting potential friends, can be seen by others)')], + '$prv_keywords' => ['prv_keywords', $this->t('Private Keywords:'), $owner['prv_keywords'], $this->t('(Used for searching profiles, never shown to others)')], '$custom_fields' => $custom_fields, ]); - $arr = ['profile' => $profile, 'entry' => $o]; + $arr = ['profile' => $owner, 'entry' => $o]; Hook::callAll('profile_edit', $arr); return $o; } - private static function getProfileFieldsFromInput(int $uid, array $profileFieldInputs, array $profileFieldOrder): ProfileFields + private function getProfileFieldsFromInput(int $uid, array $profileFieldInputs, array $profileFieldOrder): ProfileField\Collection\ProfileFields { - $profileFields = new ProfileFields(); + $profileFields = new ProfileField\Collection\ProfileFields(); // Returns an associative array of id => order values $profileFieldOrder = array_flip($profileFieldOrder); // Creation of the new field if (!empty($profileFieldInputs['new']['label'])) { - $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString( + $permissionSet = $this->permissionSetRepo->selectOrCreate($this->permissionSetFactory->createFromString( $uid, - DI::aclFormatter()->toString($profileFieldInputs['new']['contact_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['group_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['contact_deny'] ?? ''), - DI::aclFormatter()->toString($profileFieldInputs['new']['group_deny'] ?? '') + $this->aclFormatter->toString($profileFieldInputs['new']['contact_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['circle_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['contact_deny'] ?? ''), + $this->aclFormatter->toString($profileFieldInputs['new']['circle_deny'] ?? '') )); - $profileFields->append(DI::profileFieldFactory()->createFromValues( + $profileFields->append($this->profileFieldFactory->createFromValues( $uid, $profileFieldOrder['new'], $profileFieldInputs['new']['label'], @@ -302,15 +333,15 @@ class Index extends BaseSettings unset($profileFieldOrder['new']); foreach ($profileFieldInputs as $id => $profileFieldInput) { - $permissionSet = DI::permissionSet()->selectOrCreate(DI::permissionSetFactory()->createFromString( + $permissionSet = $this->permissionSetRepo->selectOrCreate($this->permissionSetFactory->createFromString( $uid, - DI::aclFormatter()->toString($profileFieldInput['contact_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['group_allow'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['contact_deny'] ?? ''), - DI::aclFormatter()->toString($profileFieldInput['group_deny'] ?? '') + $this->aclFormatter->toString($profileFieldInput['contact_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['circle_allow'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['contact_deny'] ?? ''), + $this->aclFormatter->toString($profileFieldInput['circle_deny'] ?? '') )); - $profileFields->append(DI::profileFieldFactory()->createFromValues( + $profileFields->append($this->profileFieldFactory->createFromValues( $uid, $profileFieldOrder[$id], $profileFieldInput['label'], @@ -322,22 +353,20 @@ class Index extends BaseSettings return $profileFields; } - private static function cleanKeywords($keywords) + private static function cleanKeywords($keywords): string { $keywords = str_replace(',', ' ', $keywords); $keywords = explode(' ', $keywords); $cleaned = []; foreach ($keywords as $keyword) { - $keyword = trim(strtolower($keyword)); + $keyword = trim($keyword); $keyword = trim($keyword, '#'); if ($keyword != '') { $cleaned[] = $keyword; } } - $keywords = implode(', ', $cleaned); - - return $keywords; + return implode(', ', $cleaned); } } diff --git a/src/Module/Settings/Server/Action.php b/src/Module/Settings/Server/Action.php new file mode 100644 index 000000000..e06cbf26b --- /dev/null +++ b/src/Module/Settings/Server/Action.php @@ -0,0 +1,117 @@ +. + * + */ + +namespace Friendica\Module\Settings\Server; + +use Friendica\App; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Core\System; +use Friendica\Federation\Repository\GServer; +use Friendica\Module\Response; +use Friendica\Network\HTTPException\BadRequestException; +use Friendica\User\Settings\Repository\UserGServer; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Action extends \Friendica\BaseModule +{ + /** @var IHandleUserSessions */ + private $session; + /** @var UserGServer */ + private $repository; + /** @var GServer */ + private $gserverRepo; + + public function __construct(GServer $gserverRepo, UserGServer $repository, IHandleUserSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, Response $response, array $server, array $parameters = []) + { + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); + + $this->session = $session; + $this->repository = $repository; + $this->gserverRepo = $gserverRepo; + } + + public function content(array $request = []): string + { + $GServer = $this->gserverRepo->selectOneById($this->parameters['gsid']); + + switch ($this->parameters['action']) { + case 'ignore': + $action = $this->t('Do you want to ignore this server?'); + $desc = $this->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."); + break; + case 'unignore': + $action = $this->t('Do you want to unignore this server?'); + $desc = ''; + break; + default: + throw new BadRequestException('Unknown user server action ' . $this->parameters['action']); + } + + $tpl = Renderer::getMarkupTemplate('settings/server/action.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Remote server settings'), + 'action' => $action, + 'siteName' => $this->t('Server Name'), + 'siteUrl' => $this->t('Server URL'), + 'desc' => $desc, + 'submit' => $this->t('Submit'), + ], + + '$action' => $this->args->getQueryString(), + + '$GServer' => $GServer, + + '$form_security_token' => self::getFormSecurityToken('settings-server'), + ]); + } + + public function post(array $request = []) + { + if (!empty($request['redirect_url'])) { + self::checkFormSecurityTokenRedirectOnError($this->args->getQueryString(), 'settings-server'); + } + + $userGServer = $this->repository->getOneByUserAndServer($this->session->getLocalUserId(), $this->parameters['gsid']); + + switch ($this->parameters['action']) { + case 'ignore': + $userGServer->ignore(); + break; + case 'unignore': + $userGServer->unignore(); + break; + default: + throw new BadRequestException('Unknown user server action ' . $this->parameters['action']); + } + + $this->repository->save($userGServer); + + if (!empty($request['redirect_url'])) { + $this->baseUrl->redirect($request['redirect_url']); + } + + System::exit(); + } +} diff --git a/src/Module/Settings/Server/Index.php b/src/Module/Settings/Server/Index.php new file mode 100644 index 000000000..f59e23a87 --- /dev/null +++ b/src/Module/Settings/Server/Index.php @@ -0,0 +1,126 @@ +. + * + */ + +namespace Friendica\Module\Settings\Server; + +use Friendica\App; +use Friendica\Content\Pager; +use Friendica\Core\L10n; +use Friendica\Core\Renderer; +use Friendica\Core\Session\Capability\IHandleUserSessions; +use Friendica\Module\BaseSettings; +use Friendica\Module\Response; +use Friendica\Navigation\SystemMessages; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\User\Settings\Entity\UserGServer; +use Friendica\User\Settings\Repository; +use Friendica\Util\Profiler; +use Psr\Log\LoggerInterface; + +class Index extends BaseSettings +{ + /** @var Repository\UserGServer */ + private $repository; + /** @var SystemMessages */ + private $systemMessages; + + public function __construct(SystemMessages $systemMessages, Repository\UserGServer $repository, 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->repository = $repository; + $this->systemMessages = $systemMessages; + } + + protected function post(array $request = []) + { + self::checkFormSecurityTokenRedirectOnError($this->args->getQueryString(), 'settings-server'); + + foreach ($request['delete'] ?? [] as $gsid => $delete) { + if ($delete) { + unset($request['ignored'][$gsid]); + + try { + $userGServer = $this->repository->selectOneByUserAndServer($this->session->getLocalUserId(), $gsid, false); + $this->repository->delete($userGServer); + } catch (NotFoundException $e) { + // Nothing to delete + } + } + } + + foreach ($request['ignored'] ?? [] as $gsid => $ignored) { + $userGServer = $this->repository->getOneByUserAndServer($this->session->getLocalUserId(), $gsid, false); + if ($userGServer->ignored != $ignored) { + $userGServer->toggleIgnored(); + $this->repository->save($userGServer); + } + } + + $this->systemMessages->addInfo($this->t('Settings saved')); + + $this->baseUrl->redirect($this->args->getQueryString()); + } + + protected function content(array $request = []): string + { + parent::content(); + + $pager = new Pager($this->l10n, $this->args->getQueryString(), 30); + + $total = $this->repository->countByUser($this->session->getLocalUserId()); + + $servers = $this->repository->selectByUserWithPagination($this->session->getLocalUserId(), $pager); + + $ignoredCheckboxes = array_map(function (UserGServer $server) { + return ['ignored[' . $server->gsid . ']', '', $server->ignored]; + }, $servers->getArrayCopy()); + + $deleteCheckboxes = array_map(function (UserGServer $server) { + return ['delete[' . $server->gsid . ']']; + }, $servers->getArrayCopy()); + + $tpl = Renderer::getMarkupTemplate('settings/server/index.tpl'); + return Renderer::replaceMacros($tpl, [ + '$l10n' => [ + 'title' => $this->t('Remote server settings'), + 'desc' => $this->t('Here you can find all the remote servers you have taken individual moderation actions against. For a list of servers your node has blocked, please check out the Information page.'), + 'siteName' => $this->t('Server Name'), + 'ignored' => $this->t('Ignored'), + 'ignored_title' => $this->t("You won't see any content from this server including reshares in your Network page, the community pages and individual conversations."), + 'delete' => $this->t('Delete'), + 'delete_title' => $this->t('Delete all your settings for the remote server'), + 'submit' => $this->t('Save changes'), + ], + + '$count' => $total, + + '$servers' => $servers, + + '$form_security_token' => self::getFormSecurityToken('settings-server'), + + '$ignoredCheckboxes' => $ignoredCheckboxes, + '$deleteCheckboxes' => $deleteCheckboxes, + + '$paginate' => $pager->renderFull($total), + ]); + } +} diff --git a/src/Module/Settings/UserExport.php b/src/Module/Settings/UserExport.php index 1eecea3f9..7ff08d97b 100644 --- a/src/Module/Settings/UserExport.php +++ b/src/Module/Settings/UserExport.php @@ -263,12 +263,12 @@ class UserExport extends BaseSettings sprintf("SELECT * FROM `pconfig` WHERE uid = %d", $user_id) ); - $group = $this->exportMultiRow( + $circle = $this->exportMultiRow( sprintf("SELECT * FROM `group` WHERE uid = %d", $user_id) ); - $group_member = $this->exportMultiRow( - sprintf("SELECT `group_member`.`gid`, `group_member`.`contact-id` FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` WHERE `group`.`uid` = %d", $user_id) + $circle_member = $this->exportMultiRow( + sprintf("SELECT `circle_member`.`gid`, `circle_member`.`contact-id` FROM `group_member` AS `circle_member` INNER JOIN `group` AS `circle` ON `circle`.`id` = `circle_member`.`gid` WHERE `circle`.`uid` = %d", $user_id) ); $output = [ @@ -281,8 +281,8 @@ class UserExport extends BaseSettings 'profile_fields' => $profile_fields, 'photo' => $photo, 'pconfig' => $pconfig, - 'group' => $group, - 'group_member' => $group_member, + 'circle' => $circle, + 'circle_member' => $circle_member, ]; echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR); diff --git a/src/Module/Special/DisplayNotFound.php b/src/Module/Special/DisplayNotFound.php index d66ececdd..293f40aa0 100644 --- a/src/Module/Special/DisplayNotFound.php +++ b/src/Module/Special/DisplayNotFound.php @@ -31,18 +31,21 @@ class DisplayNotFound extends \Friendica\BaseModule { protected function content(array $request = []): string { + $reasons = [ + $this->t("The top-level post isn't visible."), + $this->t('The top-level post was deleted.'), + $this->t('This node has blocked the top-level author or the author of the shared post.'), + $this->t('You have ignored or blocked the top-level author or the author of the shared post.'), + $this->t("You have ignored the top-level author's server or the shared post author's server."), + ]; + $tpl = Renderer::getMarkupTemplate('special/displaynotfound.tpl'); return Renderer::replaceMacros($tpl, [ '$l10n' => [ - 'title' => $this->t('Not Found'), - 'message' => $this->t("

Unfortunately, the requested conversation isn't available to you.

-

Possible reasons include:

-
    -
  • The top-level post isn't visible.
  • -
  • The top-level post was deleted.
  • -
  • The node has blocked the top-level author or the author of the shared post.
  • -
  • You have ignored or blocked the top-level author or the author of the shared post.
  • -
"), + 'title' => $this->t('Conversation Not Found'), + 'desc1' => $this->t("Unfortunately, the requested conversation isn't available to you."), + 'desc2' => $this->t('Possible reasons include:'), + 'reasons' => $reasons, ] ]); } diff --git a/src/Module/Special/HTTPException.php b/src/Module/Special/HTTPException.php index 8a8cc30eb..2cac142fc 100644 --- a/src/Module/Special/HTTPException.php +++ b/src/Module/Special/HTTPException.php @@ -126,8 +126,6 @@ class HTTPException */ public function content(\Friendica\Network\HTTPException $e): string { - header($this->server['SERVER_PROTOCOL'] ?? 'HTTP/1.0' . ' ' . $e->getCode() . ' ' . $e->getDescription()); - if ($e->getCode() >= 400) { $this->logger->debug('Exit with error', [ diff --git a/src/Module/Statistics.php b/src/Module/Statistics.php index 514f10bb7..dc2055782 100644 --- a/src/Module/Statistics.php +++ b/src/Module/Statistics.php @@ -25,7 +25,7 @@ use Friendica\App; use Friendica\BaseModule; use Friendica\Core\Addon; use Friendica\Core\Config\Capability\IManageConfigValues; -use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\L10n; use Friendica\Core\System; use Friendica\Network\HTTPException\NotFoundException; @@ -38,7 +38,7 @@ class Statistics extends BaseModule protected $config; /** @var IManageKeyValuePairs */ protected $keyValue; - + public function __construct(L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Profiler $profiler, IManageConfigValues $config, IManageKeyValuePairs $keyValue, Response $response, array $server, array $parameters = []) { parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); @@ -59,7 +59,7 @@ class Statistics extends BaseModule /// @todo mark the "service" addons and load them dynamically here $services = [ 'appnet' => Addon::isEnabled('appnet'), - 'buffer' => Addon::isEnabled('buffer'), + 'bluesky' => Addon::isEnabled('bluesky'), 'dreamwidth' => Addon::isEnabled('dreamwidth'), 'gnusocial' => Addon::isEnabled('gnusocial'), 'libertree' => Addon::isEnabled('libertree'), diff --git a/src/Module/ToggleMobile.php b/src/Module/ToggleMobile.php index 2408ef7f3..193f4566c 100644 --- a/src/Module/ToggleMobile.php +++ b/src/Module/ToggleMobile.php @@ -21,32 +21,43 @@ namespace Friendica\Module; +use Friendica\App; use Friendica\BaseModule; -use Friendica\DI; +use Friendica\Core\L10n; +use Friendica\Core\Session\Capability\IHandleSessions; +use Friendica\Core\System; +use Friendica\Network\HTTPException\BadRequestException; +use Friendica\Util; +use GuzzleHttp\Psr7\Uri; +use Psr\Log\LoggerInterface; /** * Toggles the mobile view (on/off) */ class ToggleMobile extends BaseModule { - protected function content(array $request = []): string + /** @var IHandleSessions */ + private $session; + + public function __construct(IHandleSessions $session, L10n $l10n, App\BaseURL $baseUrl, App\Arguments $args, LoggerInterface $logger, Util\Profiler $profiler, Response $response, array $server, array $parameters = []) { - $a = DI::app(); + parent::__construct($l10n, $baseUrl, $args, $logger, $profiler, $response, $server, $parameters); - if (isset($_GET['off'])) { - $_SESSION['show-mobile'] = false; - } else { - $_SESSION['show-mobile'] = true; + $this->session = $session; + } + + protected function rawContent(array $request = []) + { + $address = $request['address'] ?? '' ?: $this->baseUrl; + + $uri = new Uri($address); + + if (!$this->baseUrl->isLocalUri($uri)) { + throw new BadRequestException(); } - if (isset($_GET['address'])) { - $address = $_GET['address']; - } else { - $address = ''; - } + $this->session->set('show-mobile', !isset($request['off'])); - $a->redirect($address); - - return ''; + System::externalRedirect((string)$uri); } } diff --git a/src/Module/Tos.php b/src/Module/Tos.php index af6481008..3b151c31f 100644 --- a/src/Module/Tos.php +++ b/src/Module/Tos.php @@ -27,6 +27,7 @@ use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Core\L10n; use Friendica\Core\Renderer; use Friendica\Content\Text\BBCode; +use Friendica\Model\User; use Friendica\Util\Profiler; use Psr\Log\LoggerInterface; @@ -98,9 +99,9 @@ class Tos extends BaseModule return Renderer::replaceMacros($tpl, [ '$title' => $this->t('Terms of Service'), - '$tostext' => BBCode::convert($this->config->get('system', 'tostext')), + '$tostext' => BBCode::convertForUriId(User::getSystemUriId(), $this->config->get('system', 'tostext')), '$rulestitle' => $this->t('Rules'), - '$rules' => BBCode::convert($rules), + '$rules' => BBCode::convertForUriId(User::getSystemUriId(), $rules), '$displayprivstatement' => $this->config->get('system', 'tosprivstatement'), '$privstatementtitle' => $this->t('Privacy Statement'), '$privacy_operate' => $this->t('At the time of registration, and for providing communications between the user account and their contacts, the user has to provide a display name (pen name), an username (nickname) and a working email address. The names will be accessible on the profile page of the account by any visitor of the page, even if other profile details are not displayed. The email address will only be used to send the user notifications about interactions, but wont be visibly displayed. The listing of an account in the node\'s user directory or the global user directory is optional and can be controlled in the user settings, it is not necessary for communication.'), diff --git a/src/Module/Update/Community.php b/src/Module/Update/Community.php index 1ac241e55..7edb2949b 100644 --- a/src/Module/Update/Community.php +++ b/src/Module/Update/Community.php @@ -40,7 +40,7 @@ class Community extends CommunityModule $o = ''; if (!empty($request['force'])) { - $o = DI::conversation()->create(self::getItems(), Conversation::MODE_COMMUNITY, true, false, 'commented', DI::userSession()->getLocalUserId()); + $o = DI::conversation()->render(self::getItems(), Conversation::MODE_COMMUNITY, true, false, 'commented', DI::userSession()->getLocalUserId()); } System::htmlUpdateExit($o); diff --git a/src/Module/Update/Network.php b/src/Module/Update/Network.php index 052ae040f..7c9a07f36 100644 --- a/src/Module/Update/Network.php +++ b/src/Module/Update/Network.php @@ -79,7 +79,7 @@ class Network extends NetworkModule $ordering = '`commented`'; } - $o = DI::conversation()->create($items, Conversation::MODE_NETWORK, $profile_uid, false, $ordering, DI::userSession()->getLocalUserId()); + $o = DI::conversation()->render($items, Conversation::MODE_NETWORK, $profile_uid, false, $ordering, DI::userSession()->getLocalUserId()); System::htmlUpdateExit($o); } diff --git a/src/Module/Update/Profile.php b/src/Module/Update/Profile.php index 53406e195..4712cc3f5 100644 --- a/src/Module/Update/Profile.php +++ b/src/Module/Update/Profile.php @@ -63,7 +63,7 @@ class Profile extends BaseModule System::htmlUpdateExit($o); } - // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched his/her groups + // Get permissions SQL - if $remote_contact is true, our remote user has been pre-verified and we already have fetched their circles $sql_extra = Item::getPermissionsSQLByUserId($a->getProfileOwner()); $last_updated_array = DI::session()->get('last_updated', []); @@ -116,7 +116,7 @@ class Profile extends BaseModule } } - $o .= DI::conversation()->create($items, Conversation::MODE_PROFILE, $a->getProfileOwner(), false, 'received', $a->getProfileOwner()); + $o .= DI::conversation()->render($items, Conversation::MODE_PROFILE, $a->getProfileOwner(), false, 'received', $a->getProfileOwner()); System::htmlUpdateExit($o); } diff --git a/src/Module/User/Import.php b/src/Module/User/Import.php index 48dc0660f..33db88da9 100644 --- a/src/Module/User/Import.php +++ b/src/Module/User/Import.php @@ -231,6 +231,10 @@ class Import extends \Friendica\BaseModule return; } + // Backward compatibility + $account['circle'] = $account['circle'] ?? $account['group']; + $account['circle_member'] = $account['circle_member'] ?? $account['group_member']; + $oldBaseUrl = $account['baseurl']; $newBaseUrl = (string)$this->baseUrl; @@ -312,35 +316,35 @@ class Import extends \Friendica\BaseModule $this->systemMessages->addNotice($this->tt('%d contact not imported', '%d contacts not imported', $errorCount)); } - array_walk($account['group'], function (&$group) use ($newUid) { - $group['uid'] = $newUid; - if ($this->dbImportAssoc('group', $group) === false) { - $this->logger->warning('Error inserting group', ['name' => $group['name'], 'error' => $this->database->errorMessage()]); + array_walk($account['circle'], function (&$circle) use ($newUid) { + $circle['uid'] = $newUid; + if ($this->dbImportAssoc('group', $circle) === false) { + $this->logger->warning('Error inserting circle', ['name' => $circle['name'], 'error' => $this->database->errorMessage()]); } else { - $group['newid'] = $this->lastInsertId(); + $circle['newid'] = $this->lastInsertId(); } }); - foreach ($account['group_member'] as $group_member) { + foreach ($account['circle_member'] as $circle_member) { $import = 0; - foreach ($account['group'] as $group) { - if ($group['id'] == $group_member['gid'] && isset($group['newid'])) { - $group_member['gid'] = $group['newid']; + foreach ($account['circle'] as $circle) { + if ($circle['id'] == $circle_member['gid'] && isset($circle['newid'])) { + $circle_member['gid'] = $circle['newid']; $import++; break; } } foreach ($account['contact'] as $contact) { - if ($contact['id'] == $group_member['contact-id'] && isset($contact['newid'])) { - $group_member['contact-id'] = $contact['newid']; + if ($contact['id'] == $circle_member['contact-id'] && isset($contact['newid'])) { + $circle_member['contact-id'] = $contact['newid']; $import++; break; } } - if ($import == 2 && $this->dbImportAssoc('group_member', $group_member) === false) { - $this->logger->warning('Error inserting group member', ['gid' => $group_member['id'], 'error' => $this->database->errorMessage()]); + if ($import == 2 && $this->dbImportAssoc('group_member', $circle_member) === false) { + $this->logger->warning('Error inserting circle member', ['gid' => $circle_member['id'], 'error' => $this->database->errorMessage()]); } } diff --git a/src/Module/Welcome.php b/src/Module/Welcome.php index f93a7bd23..ad35f31e8 100644 --- a/src/Module/Welcome.php +++ b/src/Module/Welcome.php @@ -73,9 +73,9 @@ class Welcome extends BaseModule '$finding_link' => DI::l10n()->t('Finding New People'), '$finding_txt' => DI::l10n()->t('On the side panel of the Contacts page are several tools to find new friends. We can match people by interest, look up people by name or interest, and provide suggestions based on network relationships. On a brand new site, friend suggestions will usually begin to be populated within 24 hours.'), - '$groups' => DI::l10n()->t('Groups'), - '$group_contact_link' => DI::l10n()->t('Group Your Contacts'), - '$group_contact_txt' => DI::l10n()->t('Once you have made some friends, organize them into private conversation groups from the sidebar of your Contacts page and then you can interact with each group privately on your Network page.'), + '$circles' => DI::l10n()->t('Circles'), + '$circle_contact_link' => DI::l10n()->t('Add Your Contacts To Circle'), + '$circle_contact_txt' => DI::l10n()->t('Once you have made some friends, organize them into private conversation circles from the sidebar of your Contacts page and then you can interact with each circle privately on your Network page.'), '$newuser_private' => $newuser_private, '$private_link' => DI::l10n()->t('Why Aren\'t My Posts Public?'), '$private_txt' => DI::l10n()->t('Friendica respects your privacy. By default, your posts will only show up to people you\'ve added as friends. For more information, see the help section from the link above.'), diff --git a/src/Module/Xrd.php b/src/Module/Xrd.php index 6a4c0e860..af40bc3b0 100644 --- a/src/Module/Xrd.php +++ b/src/Module/Xrd.php @@ -38,6 +38,8 @@ class Xrd extends BaseModule { protected function rawContent(array $request = []) { + header('Vary: Accept', false); + // @TODO: Replace with parameter from router if (DI::args()->getArgv()[0] == 'xrd') { if (empty($_GET['uri'])) { @@ -80,6 +82,8 @@ class Xrd extends BaseModule throw new NotFoundException('Invalid host name for xrd query: ' . $host); } + header('Vary: Accept', false); + if ($name == User::getActorName()) { $owner = User::getSystemAccount(); if (empty($owner)) { @@ -326,7 +330,6 @@ class Xrd extends BaseModule ]); header('Access-Control-Allow-Origin: *'); - System::httpExit($xmlString, Response::TYPE_XML, 'application/xrd+xml'); } } diff --git a/src/Navigation/Notifications/Entity/Notify.php b/src/Navigation/Notifications/Entity/Notify.php index 45f450b1d..ab042bc9f 100644 --- a/src/Navigation/Notifications/Entity/Notify.php +++ b/src/Navigation/Notifications/Entity/Notify.php @@ -118,7 +118,7 @@ class Notify extends BaseEntity public function updateMsgFromPreamble($epreamble) { $this->msg = Renderer::replaceMacros($epreamble, ['$itemlink' => $this->link->__toString()]); - $this->msg_cache = self::formatMessage($this->name_cache, strip_tags(BBCode::convert($this->msg))); + $this->msg_cache = self::formatMessage($this->name_cache, BBCode::toPlaintext($this->msg, false)); } /** @@ -134,6 +134,6 @@ class Notify extends BaseEntity */ public static function formatMessage(string $name, string $message): string { - return str_replace('{0}', '' . strip_tags(BBCode::convert($name)) . '', htmlspecialchars($message)); + return str_replace('{0}', '' . BBCode::toPlaintext($name, false) . '', htmlspecialchars($message)); } } diff --git a/src/Navigation/Notifications/Factory/FormattedNotify.php b/src/Navigation/Notifications/Factory/FormattedNotify.php index 33abf63e4..9b200dea5 100644 --- a/src/Navigation/Notifications/Factory/FormattedNotify.php +++ b/src/Navigation/Notifications/Factory/FormattedNotify.php @@ -222,7 +222,7 @@ class FormattedNotify extends BaseFactory $this->baseUrl . '/notify/' . $Notify->id, Contact::getAvatarUrlForUrl($Notify->url, $Notify->uid, Proxy::SIZE_MICRO), $Notify->url, - strip_tags(BBCode::toPlaintext($Notify->msg ?? '')), + BBCode::toPlaintext($Notify->msg ?? '', false), DateTimeFormat::local($Notify->date->format(DateTimeFormat::MYSQL), 'r'), Temporal::getRelativeDate($Notify->date->format(DateTimeFormat::MYSQL)), $Notify->seen diff --git a/src/Navigation/Notifications/Factory/Introduction.php b/src/Navigation/Notifications/Factory/Introduction.php index 3d176743c..5078cac3c 100644 --- a/src/Navigation/Notifications/Factory/Introduction.php +++ b/src/Navigation/Notifications/Factory/Introduction.php @@ -163,8 +163,8 @@ class Introduction extends BaseFactory 'contact_id' => $intro['contact-id'], 'photo' => Contact::getPhoto($intro), 'name' => $intro['name'], - 'location' => BBCode::convert($intro['location'], false), - 'about' => BBCode::convert($intro['about'], false), + 'location' => BBCode::convertForUriId($intro['uri-id'], $intro['location'], BBCode::EXTERNAL), + 'about' => BBCode::convertForUriId ($intro['uri-id'], $intro['about'], BBCode::EXTERNAL), 'keywords' => $intro['keywords'], 'hidden' => $intro['hidden'] == 1, 'post_newfriend' => (intval($this->pConfig->get($this->session->getLocalUserId(), 'system', 'post_newfriend')) ? '1' : 0), diff --git a/src/Navigation/Notifications/Factory/Notification.php b/src/Navigation/Notifications/Factory/Notification.php index e4a9eab8e..e6bbc18c5 100644 --- a/src/Navigation/Notifications/Factory/Notification.php +++ b/src/Navigation/Notifications/Factory/Notification.php @@ -171,7 +171,7 @@ class Notification extends BaseFactory implements ICanCreateFromTableRow } } - if (($Notification->verb != Activity::POST) || !in_array($Notification->type, [Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT, Post\UserNotification::TYPE_IMPLICIT_TAGGED])) { + if (($Notification->verb != Activity::POST) || !in_array($Notification->type, [Post\UserNotification::TYPE_DIRECT_THREAD_COMMENT, Post\UserNotification::TYPE_IMPLICIT_TAGGED, Post\UserNotification::TYPE_DIRECT_COMMENT])) { $link_item = $item; } } diff --git a/src/Navigation/Notifications/Factory/Notify.php b/src/Navigation/Notifications/Factory/Notify.php index c180d4121..40c77c84d 100644 --- a/src/Navigation/Notifications/Factory/Notify.php +++ b/src/Navigation/Notifications/Factory/Notify.php @@ -68,7 +68,7 @@ class Notify extends BaseFactory implements ICanCreateFromTableRow false, $params['verb'] ?? '', $params['otype'] ?? '', - substr(strip_tags(BBCode::convertForUriId($uri_id, $params['source_name'])), 0, 255), + substr(BBCode::toPlaintext($params['source_name'], false), 0, 255), null, null, $item_id, diff --git a/src/Navigation/Notifications/Repository/Notify.php b/src/Navigation/Notifications/Repository/Notify.php index 6c3868524..2cacaa728 100644 --- a/src/Navigation/Notifications/Repository/Notify.php +++ b/src/Navigation/Notifications/Repository/Notify.php @@ -242,7 +242,7 @@ class Notify extends BaseRepository return false; } - // There is no need to create notifications for forum accounts + // There is no need to create notifications for group accounts if ($user['account-type'] == Model\User::ACCOUNT_TYPE_COMMUNITY) { return false; } diff --git a/src/Network/HTTPClient/Client/HttpClient.php b/src/Network/HTTPClient/Client/HttpClient.php index f47418060..d608774ec 100644 --- a/src/Network/HTTPClient/Client/HttpClient.php +++ b/src/Network/HTTPClient/Client/HttpClient.php @@ -73,7 +73,7 @@ class HttpClient implements ICanSendHttpRequests throw new \InvalidArgumentException('Unable to retrieve the host in URL: ' . $url); } - if(!filter_var($host, FILTER_VALIDATE_IP) && !@dns_get_record($host . '.', DNS_A + DNS_AAAA) && !gethostbyname($host)) { + if(!filter_var($host, FILTER_VALIDATE_IP) && !@dns_get_record($host . '.', DNS_A + DNS_AAAA)) { $this->logger->debug('URL cannot be resolved.', ['url' => $url, 'callstack' => System::callstack(20)]); $this->profiler->stopRecording(); return CurlResult::createErrorCurl($this->logger, $url); diff --git a/src/Network/Probe.php b/src/Network/Probe.php index b1931ae6d..a0887d5cb 100644 --- a/src/Network/Probe.php +++ b/src/Network/Probe.php @@ -341,7 +341,6 @@ class Probe * @param string $uri Address that should be probed * @param string $network Test for this specific network * @param integer $uid User ID for the probe (only used for mails) - * @param boolean $cache Use cached values? * * @return array uri data * @throws HTTPException\InternalServerErrorException @@ -416,14 +415,19 @@ class Probe } } - if (!empty($data['baseurl']) && empty($data['gsid'])) { - $data['gsid'] = GServer::getID($data['baseurl']); - } - if (empty($data['network'])) { $data['network'] = Protocol::PHANTOM; } + $baseurl = parse_url($data['url'], PHP_URL_SCHEME) . '://' . parse_url($data['url'], PHP_URL_HOST); + if (empty($data['baseurl']) && ($data['network'] == Protocol::ACTIVITYPUB) && (rtrim($data['url'], '/') == $baseurl)) { + $data['baseurl'] = $baseurl; + } + + if (!empty($data['baseurl']) && empty($data['gsid'])) { + $data['gsid'] = GServer::getID($data['baseurl']); + } + // Ensure that local connections always are DFRN if (($network == '') && ($data['network'] != Protocol::PHANTOM) && (self::ownHost($data['baseurl'] ?? '') || self::ownHost($data['url']))) { $data['network'] = Protocol::DFRN; @@ -1181,7 +1185,6 @@ class Probe $data = self::pollHcard($profile_link, $data, true); } - $prof_data = []; if (empty($data['addr']) || empty($data['nick'])) { $probe_data = self::uri($profile_link); @@ -1189,15 +1192,17 @@ class Probe $data['nick'] = ($data['nick'] ?? '') ?: $probe_data['nick']; } - $prof_data['addr'] = $data['addr']; - $prof_data['nick'] = $data['nick']; - $prof_data['dfrn-request'] = $data['request'] ?? null; - $prof_data['dfrn-confirm'] = $data['confirm'] ?? null; - $prof_data['dfrn-notify'] = $data['notify'] ?? null; - $prof_data['dfrn-poll'] = $data['poll'] ?? null; - $prof_data['photo'] = $data['photo'] ?? null; - $prof_data['fn'] = $data['name'] ?? null; - $prof_data['key'] = $data['pubkey'] ?? null; + $prof_data = [ + 'addr' => $data['addr'], + 'nick' => $data['nick'], + 'dfrn-request' => $data['request'] ?? null, + 'dfrn-confirm' => $data['confirm'] ?? null, + 'dfrn-notify' => $data['notify'] ?? null, + 'dfrn-poll' => $data['poll'] ?? null, + 'photo' => $data['photo'] ?? null, + 'fn' => $data['name'] ?? null, + 'key' => $data['pubkey'] ?? null, + ]; Logger::debug('Result', ['link' => $profile_link, 'data' => $prof_data]); diff --git a/src/Object/Api/Friendica/Group.php b/src/Object/Api/Friendica/Circle.php similarity index 77% rename from src/Object/Api/Friendica/Group.php rename to src/Object/Api/Friendica/Circle.php index ce75f9eec..5ff1a32cc 100644 --- a/src/Object/Api/Friendica/Group.php +++ b/src/Object/Api/Friendica/Circle.php @@ -23,12 +23,7 @@ namespace Friendica\Object\Api\Friendica; use Friendica\BaseDataTransferObject; -/** - * Class Group - * - * - */ -class Group extends BaseDataTransferObject +class Circle extends BaseDataTransferObject { /** @var string */ protected $name; @@ -42,18 +37,16 @@ class Group extends BaseDataTransferObject protected $mode; /** - * Creates an Group entity array - * - * @param array $group + * @param array $circle Circle row array * @param array $user * @throws \Friendica\Network\HTTPException\InternalServerErrorException */ - public function __construct(array $group, array $user) + public function __construct(array $circle, array $user) { - $this->name = $group['name']; - $this->id = $group['id']; - $this->id_str = (string)$group['id']; + $this->name = $circle['name']; + $this->id = $circle['id']; + $this->id_str = (string)$circle['id']; $this->user = $user; - $this->mode = $group['visible'] ? 'public' : 'private'; + $this->mode = $circle['visible'] ? 'public' : 'private'; } } diff --git a/src/Object/Api/Friendica/Notification.php b/src/Object/Api/Friendica/Notification.php index 92e6ff044..df59bb6b8 100644 --- a/src/Object/Api/Friendica/Notification.php +++ b/src/Object/Api/Friendica/Notification.php @@ -98,7 +98,7 @@ class Notification extends BaseDataTransferObject $this->date_rel = Temporal::getRelativeDate($this->date); try { - $this->msg_html = BBCode::convert($this->msg, false); + $this->msg_html = BBCode::convertForUriId($Notify->uriId, $this->msg, BBCode::EXTERNAL); } catch (\Exception $e) { $this->msg_html = ''; } diff --git a/src/Object/Api/Mastodon/Instance.php b/src/Object/Api/Mastodon/Instance.php index 118d491fc..a7549afd8 100644 --- a/src/Object/Api/Mastodon/Instance.php +++ b/src/Object/Api/Mastodon/Instance.php @@ -24,6 +24,7 @@ namespace Friendica\Object\Api\Mastodon; use Friendica\App; use Friendica\App\BaseURL; use Friendica\BaseDataTransferObject; +use Friendica\Contact\Header; use Friendica\Core\Config\Capability\IManageConfigValues; use Friendica\Database\Database; use Friendica\DI; @@ -89,9 +90,9 @@ class Instance extends BaseDataTransferObject $this->short_description = $this->description = $config->get('config', 'info'); $this->email = implode(',', User::getAdminEmailList()); $this->version = '2.8.0 (compatible; Friendica ' . App::VERSION . ')'; - $this->urls = null; // Not supported + $this->urls = ['streaming_api' => '']; // Not supported $this->stats = new Stats($config, $database); - $this->thumbnail = $baseUrl . '/images/friendica-banner.jpg'; + $this->thumbnail = $baseUrl . (new Header($config))->getMastodonBannerPath(); $this->languages = [$config->get('system', 'language')]; $this->max_toot_chars = (int)$config->get('config', 'api_import_size', $config->get('config', 'max_import_size')); $this->registrations = ($register_policy != Register::CLOSED); diff --git a/src/Object/Api/Mastodon/ScheduledStatus.php b/src/Object/Api/Mastodon/ScheduledStatus.php index de28b048a..65506a21d 100644 --- a/src/Object/Api/Mastodon/ScheduledStatus.php +++ b/src/Object/Api/Mastodon/ScheduledStatus.php @@ -67,7 +67,7 @@ class ScheduledStatus extends BaseDataTransferObject $this->scheduled_at = DateTimeFormat::utc($delayed_post['delayed'], DateTimeFormat::JSON); $this->params = [ - 'text' => BBCode::convert(BBCode::setMentionsToNicknames($parameters['item']['body'] ?? ''), false, BBCode::MASTODON_API), + 'text' => BBCode::convertForUriId($parameters['item']['uri-id'] ?? 0, BBCode::setMentionsToNicknames($parameters['item']['body'] ?? ''), BBCode::MASTODON_API), 'media_ids' => $media_ids, 'sensitive' => null, 'spoiler_text' => $parameters['item']['title'] ?? '', diff --git a/src/Object/Api/Mastodon/Status.php b/src/Object/Api/Mastodon/Status.php index 0a02a4854..122e62f9c 100644 --- a/src/Object/Api/Mastodon/Status.php +++ b/src/Object/Api/Mastodon/Status.php @@ -109,6 +109,7 @@ class Status extends BaseDataTransferObject */ public function __construct(array $item, Account $account, Counts $counts, UserAttributes $userAttributes, bool $sensitive, Application $application, array $mentions, array $tags, Card $card, array $attachments, array $in_reply, array $reblog, FriendicaExtension $friendica, array $quote = null, array $poll = null) { + $reblogged = !empty($reblog); $this->id = (string)$item['uri-id']; $this->created_at = DateTimeFormat::utc($item['created'], DateTimeFormat::JSON); $this->edited_at = DateTimeFormat::utc($item['edited'], DateTimeFormat::JSON); @@ -135,26 +136,26 @@ class Status extends BaseDataTransferObject $this->uri = $item['uri']; $this->url = $item['plink'] ?? null; - $this->replies_count = $counts->replies; - $this->reblogs_count = $counts->reblogs; - $this->favourites_count = $counts->favourites; + $this->replies_count = $reblogged ? 0 : $counts->replies; + $this->reblogs_count = $reblogged ? 0 : $counts->reblogs; + $this->favourites_count = $reblogged ? 0 : $counts->favourites; $this->favourited = $userAttributes->favourited; $this->reblogged = $userAttributes->reblogged; $this->muted = $userAttributes->muted; $this->bookmarked = $userAttributes->bookmarked; $this->pinned = $userAttributes->pinned; - $this->content = BBCode::convertForUriId($item['uri-id'], BBCode::setMentionsToNicknames($item['raw-body'] ?? $item['body']), BBCode::MASTODON_API); + $this->content = $reblogged ? '' : BBCode::convertForUriId($item['uri-id'], BBCode::setMentionsToNicknames($item['raw-body'] ?? $item['body']), BBCode::MASTODON_API); $this->reblog = $reblog; $this->quote = $quote; $this->application = $application->toArray(); $this->account = $account->toArray(); - $this->media_attachments = $attachments; - $this->mentions = $mentions; - $this->tags = $tags; - $this->emojis = []; - $this->card = $card->toArray() ?: null; - $this->poll = $poll; - $this->friendica = $friendica; + $this->media_attachments = $reblogged ? [] : $attachments; + $this->mentions = $reblogged ? [] : $mentions; + $this->tags = $reblogged ? [] : $tags; + $this->emojis = $reblogged ? [] : []; + $this->card = $reblogged ? null : ($card->toArray() ?: null); + $this->poll = $reblogged ? null : $poll; + $this->friendica = $reblogged ? null : $friendica; } /** diff --git a/src/Object/Api/Twitter/User.php b/src/Object/Api/Twitter/User.php index 60a7f9818..3ad5c5461 100644 --- a/src/Object/Api/Twitter/User.php +++ b/src/Object/Api/Twitter/User.php @@ -24,8 +24,8 @@ namespace Friendica\Object\Api\Twitter; use Friendica\BaseDataTransferObject; use Friendica\Content\ContactSelector; use Friendica\Content\Text\BBCode; -use Friendica\Core\Protocol; use Friendica\Model\Contact; +use Friendica\Network\HTTPException\InternalServerErrorException; use Friendica\Util\DateTimeFormat; use Friendica\Util\Proxy; @@ -82,6 +82,42 @@ class User extends BaseDataTransferObject protected $withheld_in_countries; /** @var string */ protected $withheld_scope; + /** @var string */ + protected $profile_image_url; + /** @var bool */ + protected $follow_request_sent; + /** @var string */ + protected $profile_image_url_large; + /** @var string */ + protected $profile_image_url_profile_size; + /** @var int */ + protected $utc_offset; + /** @var string */ + protected $time_zone; + /** @var bool */ + protected $geo_enabled; + /** @var null */ + protected $lang; + /** @var bool */ + protected $contributors_enabled; + /** @var bool */ + protected $is_translator; + /** @var bool */ + protected $is_translation_enabled; + /** @var bool */ + protected $following; + /** @var bool */ + protected $statusnet_blocking; + /** @var bool */ + protected $notifications; + /** @var int */ + protected $uid; + /** @var int */ + protected $pid; + /** @var int */ + protected $cid; + /** @var mixed */ + protected $statusnet_profile_url; /** * Missing fields: @@ -95,11 +131,12 @@ class User extends BaseDataTransferObject * @param array $publicContact Full contact table record with uid = 0 * @param array $apcontact Optional full apcontact table record * @param array $userContact Optional full contact table record with uid != 0 - * @param bool $skip_status Whether to remove the last status property, currently unused + * @param null $status * @param bool $include_user_entities Whether to add the entities property - * @throws \Friendica\Network\HTTPException\InternalServerErrorException + * + * @throws InternalServerErrorException */ - public function __construct(array $publicContact, array $apcontact = [], array $userContact = [], $status = null, $include_user_entities = true) + public function __construct(array $publicContact, array $apcontact = [], array $userContact = [], $status = null, bool $include_user_entities = true) { $uid = $userContact['uid'] ?? 0; diff --git a/src/Object/Post.php b/src/Object/Post.php index 9dfd205ec..dd3074cfa 100644 --- a/src/Object/Post.php +++ b/src/Object/Post.php @@ -31,16 +31,15 @@ use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Item; -use Friendica\Model\Photo; use Friendica\Model\Post as PostModel; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Protocol\Activity; use Friendica\Util\Crypto; use Friendica\Util\DateTimeFormat; -use Friendica\Util\Proxy; use Friendica\Util\Strings; use Friendica\Util\Temporal; +use GuzzleHttp\Psr7\Uri; use InvalidArgumentException; /** @@ -91,9 +90,13 @@ class Post } $this->writable = $this->getDataValue('writable') || $this->getDataValue('self'); - $author = ['uid' => 0, 'id' => $this->getDataValue('author-id'), + $author = [ + 'uid' => 0, + 'id' => $this->getDataValue('author-id'), 'network' => $this->getDataValue('author-network'), - 'url' => $this->getDataValue('author-link')]; + 'url' => $this->getDataValue('author-link'), + 'alias' => $this->getDataValue('author-alias') + ]; $this->redirect_url = Contact::magicLinkByContact($author); if (!$this->isToplevel()) { $this->threaded = true; @@ -206,7 +209,7 @@ class Post $connector = !in_array($item['network'], Protocol::NATIVE_SUPPORT) ? DI::l10n()->t('Connector Message') : false; $shareable = in_array($conv->getProfileOwner(), [0, DI::userSession()->getLocalUserId()]) && $item['private'] != Item::PRIVATE; - $announceable = $shareable && in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER, Protocol::TUMBLR]); + $announceable = $shareable && in_array($item['network'], [Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::TWITTER, Protocol::TUMBLR, Protocol::BLUESKY]); $commentable = ($item['network'] != Protocol::TUMBLR); // On Diaspora only toplevel posts can be reshared @@ -244,38 +247,47 @@ class Post $pinned = DI::l10n()->t('Pinned item'); } - // Showing the one or the other text, depending upon if we can only hide it or really delete it. - $delete = $origin ? DI::l10n()->t('Delete globally') : DI::l10n()->t('Remove locally'); - - $drop = false; - $block = false; - $ignore = false; - $collapse = false; + $drop = false; + $block = false; + $ignore = false; + $collapse = false; + $report = false; + $ignoreServer = false; if (DI::userSession()->getLocalUserId()) { $drop = [ 'dropping' => $dropping, 'pagedrop' => $item['pagedrop'], 'select' => DI::l10n()->t('Select'), - 'delete' => $delete, + 'label' => $origin ? DI::l10n()->t('Delete globally') : DI::l10n()->t('Remove locally'), ]; } if (!$item['self'] && DI::userSession()->getLocalUserId()) { $block = [ 'blocking' => true, - 'block' => DI::l10n()->t('Block %s', $item['author-name']), + 'label' => DI::l10n()->t('Block %s', $item['author-name']), 'author_id' => $item['author-id'], ]; $ignore = [ 'ignoring' => true, - 'ignore' => DI::l10n()->t('Ignore %s', $item['author-name']), + 'label' => DI::l10n()->t('Ignore %s', $item['author-name']), 'author_id' => $item['author-id'], ]; $collapse = [ 'collapsing' => true, - 'collapse' => DI::l10n()->t('Collapse %s', $item['author-name']), + 'label' => DI::l10n()->t('Collapse %s', $item['author-name']), 'author_id' => $item['author-id'], ]; + $report = [ + 'label' => DI::l10n()->t('Report post'), + 'href' => 'moderation/report/create?' . http_build_query(['cid' => $item['author-id'], 'uri-ids' => [$item['uri-id']]]), + ]; + $authorBaseUri = new Uri($item['author-baseurl'] ?? ''); + if ($authorBaseUri->getHost() && !DI::baseUrl()->isLocalUrl($authorBaseUri)) { + $ignoreServer = [ + 'label' => DI::l10n()->t("Ignore %s server", $authorBaseUri->getHost()), + ]; + } } $filer = DI::userSession()->getLocalUserId() ? DI::l10n()->t('Save to folder') : false; @@ -286,8 +298,13 @@ class Post } if (DI::userSession()->isAuthenticated()) { - $author = ['uid' => 0, 'id' => $item['author-id'], - 'network' => $item['author-network'], 'url' => $item['author-link']]; + $author = [ + 'uid' => 0, + 'id' => $item['author-id'], + 'network' => $item['author-network'], + 'url' => $item['author-link'], + 'alias' => $item['author-alias'], + ]; $profile_link = Contact::magicLinkByContact($author); } else { $profile_link = $item['author-link']; @@ -388,7 +405,7 @@ class Post } if ($conv->isWritable()) { - $buttons['like'] = [DI::l10n()->t("I like this \x28toggle\x29") , DI::l10n()->t('Like')]; + $buttons['like'] = [DI::l10n()->t("I like this \x28toggle\x29"), DI::l10n()->t('Like')]; $buttons['dislike'] = [DI::l10n()->t("I don't like this \x28toggle\x29"), DI::l10n()->t('Dislike')]; if ($shareable) { $buttons['share'] = [DI::l10n()->t('Quote share this'), DI::l10n()->t('Quote Share')]; @@ -451,8 +468,10 @@ class Post // Fetching of Diaspora posts doesn't always work. There are issues with reshares and possibly comments if (!DI::userSession()->getLocalUserId() && ($item['network'] != Protocol::DIASPORA) && !empty(DI::session()->get('remote_comment'))) { - $remote_comment = [DI::l10n()->t('Comment this item on your system'), DI::l10n()->t('Remote comment'), - str_replace('{uri}', urlencode($item['uri']), DI::session()->get('remote_comment'))]; + $remote_comment = [ + DI::l10n()->t('Comment this item on your system'), DI::l10n()->t('Remote comment'), + str_replace('{uri}', urlencode($item['uri']), DI::session()->get('remote_comment')) + ]; // Ensure to either display the remote comment or the local activities $buttons = []; @@ -543,6 +562,8 @@ class Post 'block' => $block, 'ignore_author' => $ignore, 'collapse' => $collapse, + 'report' => $report, + 'ignore_server' => $ignoreServer, 'vote' => $buttons, 'like_html' => $responses['like']['output'], 'dislike_html' => $responses['dislike']['output'], @@ -557,6 +578,7 @@ class Post 'wait' => DI::l10n()->t('Please wait'), 'thread_level' => $thread_level, 'edited' => $edited, + 'author_gsid' => $item['author-gsid'], 'network' => $item['network'], 'network_name' => ContactSelector::networkToName($item['author-network'], $item['author-link'], $item['network'], $item['author-gsid']), 'network_icon' => ContactSelector::networkToIcon($item['network'], $item['author-link'], $item['author-gsid']), @@ -670,7 +692,6 @@ class Post $title = DI::l10n()->t('Reacted with %s by: %s', $element['emoji'], $actors); $icon = []; break; - break; } $emojis[$index] = ['emoji' => $element['emoji'], 'total' => $element['total'], 'title' => $title, 'icon' => $icon]; } @@ -719,8 +740,10 @@ class Post if ($item->getDataValue('network') === Protocol::MAIL && DI::userSession()->getLocalUserId() != $item->getDataValue('uid')) { Logger::warning('Post object does not belong to local user', ['post' => $item, 'local_user' => DI::userSession()->getLocalUserId()]); return false; - } elseif (DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) || - DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE)) { + } elseif ( + DI::activity()->match($item->getDataValue('verb'), Activity::LIKE) || + DI::activity()->match($item->getDataValue('verb'), Activity::DISLIKE) + ) { Logger::warning('Post objects is a like/dislike', ['post' => $item]); return false; } @@ -925,7 +948,7 @@ class Post if ($conv) { // This will allow us to comment on wall-to-wall items owned by our friends - // and community forums even if somebody else wrote the post. + // and community groups even if somebody else wrote the post. // bug #517 - this fixes for conversation owner if ($conv->getMode() == 'profile' && $conv->getProfileOwner() == DI::userSession()->getLocalUserId()) { return true; @@ -1004,8 +1027,10 @@ class Post } $profile = Contact::getByURL($term['url'], false, ['addr', 'contact-type']); - if (!empty($profile['addr']) && (($profile['contact-type'] ?? Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) && - ($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr'])) { + if ( + !empty($profile['addr']) && (($profile['contact-type'] ?? Contact::TYPE_UNKNOWN) != Contact::TYPE_COMMUNITY) && + ($profile['addr'] != $owner['addr']) && !strstr($text, $profile['addr']) + ) { $text .= '@' . $profile['addr'] . ' '; } } @@ -1072,6 +1097,7 @@ class Post '$edbold' => DI::l10n()->t('Bold'), '$editalic' => DI::l10n()->t('Italic'), '$eduline' => DI::l10n()->t('Underline'), + '$contentwarn' => DI::l10n()->t('Content Warning'), '$edquote' => DI::l10n()->t('Quote'), '$edemojis' => DI::l10n()->t('Add emojis'), '$edcode' => DI::l10n()->t('Code'), @@ -1133,6 +1159,7 @@ class Post 'id' => $this->getDataValue('owner-id'), 'network' => $this->getDataValue('owner-network'), 'url' => $this->getDataValue('owner-link'), + 'alias' => $this->getDataValue('owner-alias'), ]; $this->owner_url = Contact::magicLinkByContact($owner); } diff --git a/src/Object/Thread.php b/src/Object/Thread.php index 84245ab6a..adc822b6a 100644 --- a/src/Object/Thread.php +++ b/src/Object/Thread.php @@ -190,13 +190,13 @@ class Thread * We should find a way to avoid using those arguments (at least most of them) * * @param array $conv_responses data - * @param string $formSecurityToken A security Token to avoid CSF attacks + * @param string $formSecurityToken A 'contact_action' form security token * * @return mixed The data requested on success * false on failure * @throws \Exception */ - public function getTemplateData($conv_responses, string $formSecurityToken) + public function getTemplateData(array $conv_responses, string $formSecurityToken) { $result = []; diff --git a/src/Profile/ProfileField/Entity/ProfileField.php b/src/Profile/ProfileField/Entity/ProfileField.php index a2a7c43ce..2461e02bd 100644 --- a/src/Profile/ProfileField/Entity/ProfileField.php +++ b/src/Profile/ProfileField/Entity/ProfileField.php @@ -34,6 +34,7 @@ use Friendica\Security\PermissionSet\Entity\PermissionSet; * * @property-read int|null $id * @property-read int $uid + * @property-read int $uriId * @property-read int $order * @property-read string $label * @property-read string $value @@ -50,6 +51,8 @@ class ProfileField extends BaseEntity /** @var int */ protected $uid; /** @var int */ + protected $uriId; + /** @var int */ protected $order; /** @var string */ protected $label; @@ -60,7 +63,7 @@ class ProfileField extends BaseEntity /** @var \DateTime */ protected $edited; - public function __construct(int $uid, int $order, string $label, string $value, \DateTime $created, \DateTime $edited, PermissionSet $permissionSet, int $id = null) + public function __construct(int $uid, int $order, string $label, string $value, \DateTime $created, \DateTime $edited, PermissionSet $permissionSet, int $id = null, int $uriId = null) { $this->permissionSet = $permissionSet; $this->uid = $uid; @@ -70,6 +73,7 @@ class ProfileField extends BaseEntity $this->created = $created; $this->edited = $edited; $this->id = $id; + $this->uriId = $uriId; } /** diff --git a/src/Profile/ProfileField/Factory/ProfileField.php b/src/Profile/ProfileField/Factory/ProfileField.php index cad542bc7..3c8e4673e 100644 --- a/src/Profile/ProfileField/Factory/ProfileField.php +++ b/src/Profile/ProfileField/Factory/ProfileField.php @@ -26,6 +26,7 @@ use Friendica\Profile\ProfileField\Exception\UnexpectedPermissionSetException; use Friendica\Security\PermissionSet\Factory\PermissionSet as PermissionSetFactory; use Friendica\Profile\ProfileField\Entity; use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Model\User; use Friendica\Security\PermissionSet\Entity\PermissionSet; use Psr\Log\LoggerInterface; @@ -54,6 +55,8 @@ class ProfileField extends BaseFactory implements ICanCreateFromTableRow throw new UnexpectedPermissionSetException('Either set the PermissionSet fields (join) or the PermissionSet itself'); } + $owner = User::getOwnerDataById($row['uid']); + return new Entity\ProfileField( $row['uid'], $row['order'], @@ -69,7 +72,8 @@ class ProfileField extends BaseFactory implements ICanCreateFromTableRow $row['deny_gid'], $row['psid'] ), - $row['id'] ?? null + $row['id'] ?? null, + $owner['uri-id'] ?? null ); } diff --git a/src/Protocol/ActivityPub.php b/src/Protocol/ActivityPub.php index d1177e0b0..4be88b341 100644 --- a/src/Protocol/ActivityPub.php +++ b/src/Protocol/ActivityPub.php @@ -23,7 +23,9 @@ namespace Friendica\Protocol; use Friendica\Core\Logger; use Friendica\Core\Protocol; +use Friendica\Core\System; use Friendica\Model\APContact; +use Friendica\Model\Contact; use Friendica\Model\User; use Friendica\Util\HTTPSignature; use Friendica\Util\JsonLD; @@ -52,33 +54,36 @@ use Friendica\Util\JsonLD; * - Polling the outboxes for missing content? * * Missing parts from DFRN: - * - Public Forum - * - Private Forum + * - Public Group + * - Private Group * - Relocation */ class ActivityPub { const PUBLIC_COLLECTION = 'https://www.w3.org/ns/activitystreams#Public'; - const CONTEXT = ['https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', - ['vcard' => 'http://www.w3.org/2006/vcard/ns#', - 'dfrn' => 'http://purl.org/macgirvin/dfrn/1.0/', - 'diaspora' => 'https://diasporafoundation.org/ns/', - 'litepub' => 'http://litepub.social/ns#', - 'toot' => 'http://joinmastodon.org/ns#', - 'featured' => [ - "@id" => "toot:featured", - "@type" => "@id", - ], - 'schema' => 'http://schema.org#', - 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', - 'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag', - 'quoteUrl' => 'as:quoteUrl', - 'conversation' => 'ostatus:conversation', - 'directMessage' => 'litepub:directMessage', - 'discoverable' => 'toot:discoverable', - 'PropertyValue' => 'schema:PropertyValue', - 'value' => 'schema:value', - ]]; + const CONTEXT = [ + 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', + [ + 'vcard' => 'http://www.w3.org/2006/vcard/ns#', + 'dfrn' => 'http://purl.org/macgirvin/dfrn/1.0/', + 'diaspora' => 'https://diasporafoundation.org/ns/', + 'litepub' => 'http://litepub.social/ns#', + 'toot' => 'http://joinmastodon.org/ns#', + 'featured' => [ + "@id" => "toot:featured", + "@type" => "@id", + ], + 'schema' => 'http://schema.org#', + 'manuallyApprovesFollowers' => 'as:manuallyApprovesFollowers', + 'sensitive' => 'as:sensitive', 'Hashtag' => 'as:Hashtag', + 'quoteUrl' => 'as:quoteUrl', + 'conversation' => 'ostatus:conversation', + 'directMessage' => 'litepub:directMessage', + 'discoverable' => 'toot:discoverable', + 'PropertyValue' => 'schema:PropertyValue', + 'value' => 'schema:value', + ] + ]; const ACCOUNT_TYPES = ['Person', 'Organization', 'Service', 'Group', 'Application', 'Tombstone']; /** * Checks if the web request is done for the AP protocol @@ -87,6 +92,8 @@ class ActivityPub */ public static function isRequest(): bool { + header('Vary: Accept', false); + $isrequest = stristr($_SERVER['HTTP_ACCEPT'] ?? '', 'application/activity+json') || stristr($_SERVER['HTTP_ACCEPT'] ?? '', 'application/json') || stristr($_SERVER['HTTP_ACCEPT'] ?? '', 'application/ld+json'); @@ -115,7 +122,7 @@ class ActivityPub { $accounttype = -1; - switch($apcontact['type']) { + switch ($apcontact['type']) { case 'Person': $accounttype = User::ACCOUNT_TYPE_PERSON; break; @@ -275,4 +282,38 @@ class ActivityPub { return !empty(APContact::getByURL($url, $update)); } + + public static function isAcceptedRequester(int $uid = 0): bool + { + $called_by = System::callstack(1); + + $signer = HTTPSignature::getSigner('', $_SERVER); + if (!$signer) { + Logger::debug('No signer or invalid signature', ['uid' => $uid, 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'called_by' => $called_by]); + return false; + } + + $apcontact = APContact::getByURL($signer); + if (empty($apcontact)) { + Logger::info('APContact not found', ['uid' => $uid, 'handle' => $signer, 'called_by' => $called_by]); + return false; + } + + if (empty($apcontact['gsid'] || empty($apcontact['baseurl']))) { + Logger::debug('No server found', ['uid' => $uid, 'signer' => $signer, 'called_by' => $called_by]); + return false; + } + + $contact = Contact::getByURL($signer, false, ['id', 'baseurl', 'gsid']); + if (!empty($contact) && Contact\User::isBlocked($contact['id'], $uid)) { + Logger::info('Requesting contact is blocked', ['uid' => $uid, 'id' => $contact['id'], 'signer' => $signer, 'baseurl' => $contact['baseurl'], 'called_by' => $called_by]); + return false; + } + + // @todo Look for user blocked domains + + Logger::debug('Server is an accepted requester', ['uid' => $uid, 'id' => $apcontact['gsid'], 'url' => $apcontact['baseurl'], 'signer' => $signer, 'called_by' => $called_by]); + + return true; + } } diff --git a/src/Protocol/ActivityPub/ClientToServer.php b/src/Protocol/ActivityPub/ClientToServer.php index ee162382b..2b52d17b7 100644 --- a/src/Protocol/ActivityPub/ClientToServer.php +++ b/src/Protocol/ActivityPub/ClientToServer.php @@ -28,7 +28,7 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\APContact; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\Item; use Friendica\Model\Post; use Friendica\Model\User; @@ -284,7 +284,7 @@ class ClientToServer $item['private'] = Item::UNLISTED; } elseif (!empty($object_data['target'][Receiver::TARGET_FOLLOWER])) { $item['allow_cid'] = ''; - $item['allow_gid'] = '<' . Group::FOLLOWERS . '>'; + $item['allow_gid'] = '<' . Circle::FOLLOWERS . '>'; $item['deny_cid'] = ''; $item['deny_gid'] = ''; $item['private'] = Item::PRIVATE; diff --git a/src/Protocol/ActivityPub/Delivery.php b/src/Protocol/ActivityPub/Delivery.php index ddf5816ed..04f5841c2 100644 --- a/src/Protocol/ActivityPub/Delivery.php +++ b/src/Protocol/ActivityPub/Delivery.php @@ -160,7 +160,7 @@ class Delivery if (!empty($actor)) { $drop = !ActivityPub\Transmitter::sendRelayFollow($actor); Logger::notice('Resubscribed to relay', ['url' => $actor, 'success' => !$drop]); - } elseif ($cmd = ProtocolDelivery::DELETION) { + } elseif ($cmd == ProtocolDelivery::DELETION) { // Remote systems not always accept our deletion requests, so we drop them if rejected. // Situation is: In Friendica we allow the thread owner to delete foreign comments to their thread. // Most AP systems don't allow this, so they will reject the deletion request. diff --git a/src/Protocol/ActivityPub/Processor.php b/src/Protocol/ActivityPub/Processor.php index b8d4005a6..3d020a747 100644 --- a/src/Protocol/ActivityPub/Processor.php +++ b/src/Protocol/ActivityPub/Processor.php @@ -42,6 +42,7 @@ use Friendica\Model\Mail; use Friendica\Model\Tag; use Friendica\Model\User; use Friendica\Model\Post; +use Friendica\Moderation\Entity\Report; use Friendica\Protocol\Activity; use Friendica\Protocol\ActivityPub; use Friendica\Protocol\Delivery; @@ -415,13 +416,13 @@ class Processor $item['post-type'] = Item::PT_NOTE; } - $item['isForum'] = false; + $item['isGroup'] = false; if (!empty($activity['thread-completion'])) { if ($activity['thread-completion'] != $item['owner-id']) { $actor = Contact::getById($activity['thread-completion'], ['url']); $item['causer-link'] = $actor['url']; - $item['causer-id'] = $activity['thread-completion']; + $item['causer-id'] = $activity['thread-completion']; Logger::info('Use inherited actor as causer.', ['id' => $item['owner-id'], 'activity' => $activity['thread-completion'], 'owner' => $item['owner-link'], 'actor' => $actor['url']]); } else { // Store the original actor in the "causer" fields to enable the check for ignored or blocked contacts @@ -431,10 +432,41 @@ class Processor } $item['owner-link'] = $item['author-link']; - $item['owner-id'] = $item['author-id']; + $item['owner-id'] = $item['author-id']; + } + + if (!$item['isGroup'] && !empty($activity['receiver_urls']['as:audience'])) { + foreach ($activity['receiver_urls']['as:audience'] as $audience) { + $actor = APContact::getByURL($audience, false); + if (($actor['type'] ?? 'Person') == 'Group') { + Logger::debug('Group post detected via audience.', ['audience' => $audience, 'actor' => $activity['actor'], 'author' => $activity['author']]); + $item['isGroup'] = true; + $item['group-link'] = $item['owner-link'] = $audience; + $item['owner-id'] = Contact::getIdForURL($audience); + break; + } + } } else { - $actor = APContact::getByURL($item['owner-link'], false); - $item['isForum'] = ($actor['type'] ?? 'Person') == 'Group'; + $owner = APContact::getByURL($item['owner-link'], false); + } + + if (!$item['isGroup'] && (($owner['type'] ?? 'Person') == 'Group')) { + Logger::debug('Group post detected via owner.', ['actor' => $activity['actor'], 'author' => $activity['author']]); + $item['isGroup'] = true; + $item['group-link'] = $item['owner-link']; + } elseif (!empty($item['causer-link'])) { + $causer = APContact::getByURL($item['causer-link'], false); + } + + if (!$item['isGroup'] && (($causer['type'] ?? 'Person') == 'Group')) { + Logger::debug('Group post detected via causer.', ['actor' => $activity['actor'], 'author' => $activity['author'], 'causer' => $item['causer-link']]); + $item['isGroup'] = true; + $item['group-link'] = $item['causer-link']; + } + + if (!empty($item['group-link']) && empty($item['causer-link'])) { + $item['causer-link'] = $item['group-link']; + $item['causer-id'] = Contact::getIdForURL($item['causer-link']); } $item['uri'] = $activity['id']; @@ -872,6 +904,19 @@ class Processor $item['raw-body'] = $item['body'] = $content; } + if (!empty($item['author-id']) && ($item['author-id'] == $item['owner-id'])) { + foreach (Tag::getFromBody($item['body'], Tag::TAG_CHARACTER[Tag::EXCLUSIVE_MENTION]) as $tag) { + $actor = APContact::getByURL($tag[2], false); + if (($actor['type'] ?? 'Person') == 'Group') { + Logger::debug('Group post detected via exclusive mention.', ['mention' => $actor['url'], 'actor' => $activity['actor'], 'author' => $activity['author']]); + $item['isGroup'] = true; + $item['group-link'] = $item['owner-link'] = $actor['url']; + $item['owner-id'] = Contact::getIdForURL($actor['url']); + break; + } + } + } + self::storeFromBody($item); self::storeTags($item['uri-id'], $activity['tags']); @@ -1059,10 +1104,10 @@ class Processor $item['causer-id'] = ($item['gravity'] == Item::GRAVITY_PARENT) ? $item['owner-id'] : $item['author-id']; } - if ($item['isForum'] ?? false) { - $item['contact-id'] = Contact::getIdForURL($activity['actor'], $receiver); + if ($item['isGroup']) { + $item['contact-id'] = Contact::getIdForURL($item['group-link'], $receiver); } else { - $item['contact-id'] = Contact::getIdForURL($activity['author'], $receiver); + $item['contact-id'] = Contact::getIdForURL($item['author-link'], $receiver); } if (($receiver != 0) && empty($item['contact-id'])) { @@ -1075,7 +1120,7 @@ class Processor } if (($receiver != 0) && ($item['gravity'] == Item::GRAVITY_PARENT) && !in_array($item['post-reason'], [Item::PR_FOLLOWER, Item::PR_TAG, item::PR_TO, Item::PR_CC, Item::PR_AUDIENCE])) { - if (!($item['isForum'] ?? false)) { + if (!$item['isGroup']) { if ($item['post-reason'] == Item::PR_BCC) { Logger::info('Top level post via BCC from a non sharer, ignoring', ['uid' => $receiver, 'contact' => $item['contact-id'], 'url' => $item['uri']]); continue; @@ -1089,16 +1134,16 @@ class Processor } } - $is_forum = false; + $isGroup = false; $user = User::getById($receiver, ['account-type']); if (!empty($user['account-type'])) { - $is_forum = ($user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY); + $isGroup = ($user['account-type'] == User::ACCOUNT_TYPE_COMMUNITY); } if ((DI::pConfig()->get($receiver, 'system', 'accept_only_sharer') == Item::COMPLETION_NONE) - && ((!$is_forum && !($item['isForum'] ?? false) && ($activity['type'] != 'as:Announce')) + && ((!$isGroup && !$item['isGroup'] && ($activity['type'] != 'as:Announce')) || !Contact::isSharingByURL($activity['actor'], $receiver))) { - Logger::info('Actor is a non sharer, is no forum or it is no announce', ['uid' => $receiver, 'actor' => $activity['actor'], 'url' => $item['uri'], 'type' => $activity['type']]); + Logger::info('Actor is a non sharer, is no group or it is no announce', ['uid' => $receiver, 'actor' => $activity['actor'], 'url' => $item['uri'], 'type' => $activity['type']]); continue; } @@ -1141,7 +1186,7 @@ class Processor // Store send a follow request for every reshare - but only when the item had been stored if ($stored && ($item['private'] != Item::PRIVATE) && ($item['gravity'] == Item::GRAVITY_PARENT) && !empty($item['author-link']) && ($item['author-link'] != $item['owner-link'])) { $author = APContact::getByURL($item['owner-link'], false); - // We send automatic follow requests for reshared messages. (We don't need though for forum posts) + // We send automatic follow requests for reshared messages. (We don't need though for group posts) if ($author['type'] != 'Group') { Logger::info('Send follow request', ['uri' => $item['uri'], 'stored' => $stored, 'to' => $item['author-link']]); ActivityPub\Transmitter::sendFollowObject($item['uri'], $item['author-link']); @@ -1533,6 +1578,7 @@ class Processor $activity['id'] = $object['id']; $activity['to'] = $object['to'] ?? []; $activity['cc'] = $object['cc'] ?? []; + $activity['audience'] = $object['audience'] ?? []; $activity['actor'] = $actor; $activity['object'] = $object; $activity['published'] = $published; @@ -1612,7 +1658,7 @@ class Processor $tags = Receiver::processTags(JsonLD::fetchElementArray($activity['as:object'], 'as:tag') ?? []); if (!empty($tags)) { foreach ($tags as $tag) { - if ($tag['type'] != 'Hashtag') { + if (($tag['type'] != 'Hashtag') && !strpos($tag['type'], ':Hashtag')) { continue; } $messageTags[] = ltrim(mb_strtolower($tag['name']), '#'); @@ -1848,8 +1894,8 @@ class Processor */ public static function ReportAccount(array $activity) { - $account_id = Contact::getIdForURL($activity['object_id']); - if (empty($account_id)) { + $account = Contact::getByURL($activity['object_id'], null, ['id', 'gsid']); + if (empty($account)) { Logger::info('Unknown account', ['activity' => $activity]); Queue::remove($activity); return; @@ -1870,10 +1916,10 @@ class Processor } } - $report = DI::reportFactory()->createFromReportsRequest($reporter_id, $account_id, $activity['content'], null, '', false, $uri_ids); + $report = DI::reportFactory()->createFromReportsRequest(System::getRules(true), $reporter_id, $account['id'], $account['gsid'], $activity['content'], 'other', false, $uri_ids); DI::report()->save($report); - Logger::info('Stored report', ['reporter' => $reporter_id, 'account_id' => $account_id, 'comment' => $activity['content'], 'object_ids' => $activity['object_ids']]); + Logger::info('Stored report', ['reporter' => $reporter_id, 'account' => $account, 'comment' => $activity['content'], 'object_ids' => $activity['object_ids']]); } /** diff --git a/src/Protocol/ActivityPub/Receiver.php b/src/Protocol/ActivityPub/Receiver.php index db4196abc..7a07e1a7f 100644 --- a/src/Protocol/ActivityPub/Receiver.php +++ b/src/Protocol/ActivityPub/Receiver.php @@ -291,16 +291,17 @@ class Receiver /** * Prepare the object array * - * @param array $activity Array with activity data - * @param integer $uid User ID - * @param boolean $push Message had been pushed to our system - * @param boolean $trust_source Do we trust the source? + * @param array $activity Array with activity data + * @param integer $uid User ID + * @param boolean $push Message had been pushed to our system + * @param boolean $trust_source Do we trust the source? + * @param string $original_actor Actor of the original activity. Used for receiver detection. (Optional) * * @return array with object data * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - public static function prepareObjectData(array $activity, int $uid, bool $push, bool &$trust_source): array + public static function prepareObjectData(array $activity, int $uid, bool $push, bool &$trust_source, string $original_actor = ''): array { $id = JsonLD::fetchElement($activity, '@id'); $type = JsonLD::fetchElement($activity, '@type'); @@ -319,7 +320,7 @@ class Receiver $fetched = false; if (!empty($id) && !$trust_source) { - $fetch_uid = $uid ?: self::getBestUserForActivity($activity); + $fetch_uid = $uid ?: self::getBestUserForActivity($activity, $original_actor); $fetched_activity = Processor::fetchCachedActivity($fetch_id, $fetch_uid); if (!empty($fetched_activity)) { @@ -355,7 +356,7 @@ class Receiver $type = JsonLD::fetchElement($activity, '@type'); // Fetch all receivers from to, cc, bto and bcc - $receiverdata = self::getReceivers($activity, $actor, [], false, $push || $fetched); + $receiverdata = self::getReceivers($activity, $original_actor ?: $actor, [], false, $push || $fetched); $receivers = $reception_types = []; foreach ($receiverdata as $key => $data) { $receivers[$key] = $data['uid']; @@ -379,7 +380,7 @@ class Receiver // We possibly need some user to fetch private content, // so we fetch one out of the receivers if no uid is provided. - $fetch_uid = $uid ?: self::getBestUserForActivity($activity); + $fetch_uid = $uid ?: self::getBestUserForActivity($activity, $original_actor); $object_id = JsonLD::fetchElement($activity, 'as:object', '@id'); if (empty($object_id)) { @@ -394,28 +395,6 @@ class Receiver $object_type = self::fetchObjectType($activity, $object_id, $fetch_uid); - // Fetch the activity on Lemmy "Announce" messages (announces of activities) - if (($type == 'as:Announce') && in_array($object_type, array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) { - Logger::debug('Fetch announced activity', ['object' => $object_id, 'uid' => $fetch_uid]); - $data = Processor::fetchCachedActivity($object_id, $fetch_uid); - if (!empty($data)) { - $type = $object_type; - $announced_activity = JsonLD::compact($data); - - // Some variables need to be refetched since the activity changed - $actor = JsonLD::fetchElement($announced_activity, 'as:actor', '@id'); - $announced_id = JsonLD::fetchElement($announced_activity, 'as:object', '@id'); - if (empty($announced_id)) { - Logger::warning('No object id in announced activity', ['id' => $object_id, 'activity' => $activity, 'announced' => $announced_activity]); - return []; - } else { - $activity = $announced_activity; - $object_id = $announced_id; - } - $object_type = self::fetchObjectType($activity, $object_id, $fetch_uid); - } - } - // Any activities on account types must not be altered if (in_array($type, ['as:Flag'])) { $object_data = []; @@ -454,7 +433,7 @@ class Receiver } elseif (in_array($type, array_merge(self::ACTIVITY_TYPES, ['as:Announce', 'as:Follow'])) && in_array($object_type, self::CONTENT_TYPES)) { // Create a mostly empty array out of the activity data (instead of the object). // This way we later don't have to check for the existence of each individual array element. - $object_data = self::processObject($activity); + $object_data = self::processObject($activity, $original_actor); $object_data['name'] = $type; $object_data['author'] = JsonLD::fetchElement($activity, 'as:actor', '@id'); $object_data['object_id'] = $object_id; @@ -598,18 +577,32 @@ class Receiver } } - // $trust_source is called by reference and is set to true if the content was retrieved successfully - $object_data = self::prepareObjectData($activity, $uid, $push, $trust_source); - if (empty($object_data)) { - Logger::info('No object data found', ['activity' => $activity]); - return true; + // Lemmy announces activities. + // To simplify the further processing, we modify the received object. + // For announced "create" activities we remove the middle layer. + // For the rest (like, dislike, update, ...) we just process the activity directly. + $original_actor = ''; + $object_type = JsonLD::fetchElement($activity['as:object'] ?? [], '@type'); + if (($type == 'as:Announce') && !empty($object_type) && !in_array($object_type, self::CONTENT_TYPES) && self::isGroup($actor)) { + $object_object_type = JsonLD::fetchElement($activity['as:object']['as:object'] ?? [], '@type'); + if (in_array($object_type, ['as:Create']) && in_array($object_object_type, self::CONTENT_TYPES)) { + Logger::debug('Replace "create" activity with inner object', ['type' => $object_type, 'object_type' => $object_object_type]); + $activity['as:object'] = $activity['as:object']['as:object']; + } elseif (in_array($object_type, array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) { + Logger::debug('Change announced activity to activity', ['type' => $object_type]); + $original_actor = $actor; + $type = $object_type; + $activity = $activity['as:object']; + } else { + Logger::info('Unhandled announced activity', ['type' => $object_type, 'object_type' => $object_object_type]); + } } - // Lemmy is announcing activities. - // We are changing the announces into regular activities. - if (($type == 'as:Announce') && in_array($object_data['type'] ?? '', array_merge(self::ACTIVITY_TYPES, ['as:Delete', 'as:Undo', 'as:Update']))) { - Logger::debug('Change type of announce to activity', ['type' => $object_data['type']]); - $type = $object_data['type']; + // $trust_source is called by reference and is set to true if the content was retrieved successfully + $object_data = self::prepareObjectData($activity, $uid, $push, $trust_source, $original_actor); + if (empty($object_data)) { + Logger::info('No object data found', ['activity' => $activity, 'callstack' => System::callstack(20)]); + return true; } if (!empty($body) && empty($object_data['raw'])) { @@ -688,6 +681,18 @@ class Receiver return true; } + /** + * Checks if the provided actor is a group account + * + * @param string $actor + * @return boolean + */ + private static function isGroup(string $actor): bool + { + $profile = APContact::getByURL($actor); + return ($profile['type'] ?? '') == 'Group'; + } + /** * Route activities * @@ -1009,10 +1014,10 @@ class Receiver * * @return int user id */ - public static function getBestUserForActivity(array $activity): int + public static function getBestUserForActivity(array $activity, string $actor = ''): int { $uid = 0; - $actor = JsonLD::fetchElement($activity, 'as:actor', '@id') ?? ''; + $actor = $actor ?: JsonLD::fetchElement($activity, 'as:actor', '@id') ?? ''; $receivers = self::getReceivers($activity, $actor, [], false, false); foreach ($receivers as $receiver) { @@ -1098,7 +1103,7 @@ class Receiver if (!empty($actor)) { $profile = APContact::getByURL($actor); $followers = $profile['followers'] ?? ''; - $is_forum = ($actor['type'] ?? '') == 'Group'; + $isGroup = ($profile['type'] ?? '') == 'Group'; if ($push) { Contact::updateByUrlIfNeeded($actor); } @@ -1106,7 +1111,7 @@ class Receiver } else { Logger::info('Empty actor', ['activity' => $activity]); $followers = ''; - $is_forum = false; + $isGroup = false; } // We have to prevent false follower assumptions upon thread completions @@ -1129,7 +1134,7 @@ class Receiver } // Fetch the receivers for the public and the followers collection - if ((($receiver == $followers) || (($receiver == self::PUBLIC_COLLECTION) && !$is_forum)) && !empty($actor)) { + if ((($receiver == $followers) || (($receiver == self::PUBLIC_COLLECTION) && !$isGroup) || ($isGroup && ($element == 'as:audience'))) && !empty($actor)) { $receivers = self::getReceiverForActor($actor, $tags, $receivers, $follower_target, $profile); continue; } @@ -1148,7 +1153,7 @@ class Receiver $condition = ['nurl' => Strings::normaliseLink($actor), 'rel' => [Contact::SHARING, Contact::FRIEND], 'network' => $networks, 'archive' => false, 'pending' => false, 'uid' => $contact['uid']]; - // Forum posts are only accepted from forum contacts + // Group posts are only accepted from group contacts if ($contact['contact-type'] == Contact::TYPE_COMMUNITY) { $condition['rel'] = [Contact::SHARING, Contact::FRIEND, Contact::FOLLOWER]; } @@ -1196,12 +1201,16 @@ class Receiver // "birdsitelive" is a service that mirrors tweets into the fediverse // These posts can be fetched without authentication, but are not marked as public // We treat them as unlisted posts to be able to handle them. + // We always process deletion activities. + $activity_type = JsonLD::fetchElement($activity, '@type'); if (empty($receivers) && $fetch_unlisted && Contact::isPlatform($actor, 'birdsitelive')) { $receivers[0] = ['uid' => 0, 'type' => self::TARGET_GLOBAL]; $receivers[-1] = ['uid' => -1, 'type' => self::TARGET_GLOBAL]; Logger::notice('Post from "birdsitelive" is set to "unlisted"', ['id' => JsonLD::fetchElement($activity, '@id')]); + } elseif (empty($receivers) && in_array($activity_type, ['as:Delete', 'as:Undo'])) { + $receivers[0] = ['uid' => 0, 'type' => self::TARGET_GLOBAL]; } elseif (empty($receivers)) { - Logger::notice('Post has got no receivers', ['fetch_unlisted' => $fetch_unlisted, 'actor' => $actor, 'id' => JsonLD::fetchElement($activity, '@id'), 'type' => JsonLD::fetchElement($activity, '@type')]); + Logger::notice('Post has got no receivers', ['fetch_unlisted' => $fetch_unlisted, 'actor' => $actor, 'id' => JsonLD::fetchElement($activity, '@id'), 'type' => $activity_type, 'callstack' => System::callstack(20)]); } return $receivers; @@ -1437,21 +1446,9 @@ class Receiver return false; } - // Lemmy is resharing "create" activities instead of content - // We fetch the content from the activity. - if (in_array($type, ['as:Create'])) { - $object = $object['as:object']; - $type = JsonLD::fetchElement($object, '@type'); - if (empty($type)) { - Logger::info('Empty type'); - return false; - } - $object_data = self::processObject($object); - } - // We currently don't handle 'pt:CacheFile', but with this step we avoid logging if (in_array($type, self::CONTENT_TYPES) || ($type == 'pt:CacheFile')) { - $object_data = self::processObject($object); + $object_data = self::processObject($object, ''); if (!empty($data)) { $object_data['raw-object'] = json_encode($data); @@ -1855,12 +1852,13 @@ class Receiver /** * Fetches data from the object part of an activity * - * @param array $object + * @param array $object + * @param string $actor * * @return array|bool Object data or FALSE if $object does not contain @id element * @throws \Exception */ - private static function processObject(array $object) + private static function processObject(array $object, string $actor) { if (!JsonLD::fetchElement($object, '@id')) { return false; @@ -1868,7 +1866,7 @@ class Receiver $object_data = self::getObjectDataFromActivity($object); - $receiverdata = self::getReceivers($object, $object_data['actor'] ?? '', $object_data['tags'], true, false); + $receiverdata = self::getReceivers($object, $actor ?: $object_data['actor'] ?? '', $object_data['tags'], true, false); $receivers = $reception_types = []; foreach ($receiverdata as $key => $data) { $receivers[$key] = $data['uid']; diff --git a/src/Protocol/ActivityPub/Transmitter.php b/src/Protocol/ActivityPub/Transmitter.php index 3d945180a..4b0450a0c 100644 --- a/src/Protocol/ActivityPub/Transmitter.php +++ b/src/Protocol/ActivityPub/Transmitter.php @@ -195,7 +195,7 @@ class Transmitter } // When we hide our friends we will only show the pure number but don't allow more. - $show_contacts = empty($owner['hide-friends']); + $show_contacts = ActivityPub::isAcceptedRequester($owner['uid']) && empty($owner['hide-friends']); // Allow fetching the contact list when the requester is part of the list. if (($owner['page-flags'] == User::PAGE_FLAGS_PRVGROUP) && !empty($requester)) { @@ -337,12 +337,13 @@ class Transmitter /** * Return the ActivityPub profile of the given user * - * @param int $uid User ID + * @param int $uid User ID + * @param bool $full If not full, only the basic information is returned * @return array with profile data * @throws HTTPException\NotFoundException * @throws HTTPException\InternalServerErrorException */ - public static function getProfile(int $uid): array + public static function getProfile(int $uid, bool $full = true): array { $owner = User::getOwnerDataById($uid); if (!isset($owner['id'])) { @@ -372,16 +373,16 @@ class Transmitter $data['preferredUsername'] = $owner['nick']; $data['name'] = $owner['name']; - if (!empty($owner['country-name'] . $owner['region'] . $owner['locality'])) { + if (!$full && !empty($owner['country-name'] . $owner['region'] . $owner['locality'])) { $data['vcard:hasAddress'] = ['@type' => 'vcard:Home', 'vcard:country-name' => $owner['country-name'], 'vcard:region' => $owner['region'], 'vcard:locality' => $owner['locality']]; } - if (!empty($owner['about'])) { + if ($full && !empty($owner['about'])) { $data['summary'] = BBCode::convertForUriId($owner['uri-id'] ?? 0, $owner['about'], BBCode::EXTERNAL); } - if (!empty($owner['xmpp']) || !empty($owner['matrix'])) { + if ($full && (!empty($owner['xmpp']) || !empty($owner['matrix']))) { $data['vcard:hasInstantMessage'] = []; if (!empty($owner['xmpp'])) { @@ -399,7 +400,7 @@ class Transmitter 'owner' => $owner['url'], 'publicKeyPem' => $owner['pubkey']]; $data['endpoints'] = ['sharedInbox' => DI::baseUrl() . '/inbox']; - if ($uid != 0) { + if ($full && $uid != 0) { $data['icon'] = ['type' => 'Image', 'url' => User::getAvatarUrl($owner)]; $resourceid = Photo::ridFromURI($owner['photo']); @@ -492,13 +493,12 @@ class Transmitter * Returns an array with permissions of the thread parent of the given item array * * @param array $item - * @param bool $is_forum_thread * * @return array with permissions * @throws \Friendica\Network\HTTPException\InternalServerErrorException * @throws \ImagickException */ - private static function fetchPermissionBlockFromThreadParent(array $item, bool $is_forum_thread): array + private static function fetchPermissionBlockFromThreadParent(array $item, bool $is_group_thread): array { if (empty($item['thr-parent-id'])) { return []; @@ -514,6 +514,7 @@ class Transmitter 'cc' => [], 'bto' => [], 'bcc' => [], + 'audience' => [], ]; $parent_profile = APContact::getByURL($parent['author-link']); @@ -525,10 +526,10 @@ class Transmitter $exclude[] = $item['owner-link']; } - $type = [Tag::TO => 'to', Tag::CC => 'cc', Tag::BTO => 'bto', Tag::BCC => 'bcc']; - foreach (Tag::getByURIId($item['thr-parent-id'], [Tag::TO, Tag::CC, Tag::BTO, Tag::BCC]) as $receiver) { + $type = [Tag::TO => 'to', Tag::CC => 'cc', Tag::BTO => 'bto', Tag::BCC => 'bcc', Tag::AUDIENCE => 'audience']; + foreach (Tag::getByURIId($item['thr-parent-id'], [Tag::TO, Tag::CC, Tag::BTO, Tag::BCC, Tag::AUDIENCE]) as $receiver) { if (!empty($parent_profile['followers']) && $receiver['url'] == $parent_profile['followers'] && !empty($item_profile['followers'])) { - if (!$is_forum_thread) { + if (!$is_group_thread) { $permissions[$type[$receiver['type']]][] = $item_profile['followers']; } } elseif (!in_array($receiver['url'], $exclude)) { @@ -573,15 +574,18 @@ class Transmitter } $always_bcc = false; - $is_forum = false; + $is_group = false; $follower = ''; + $exclusive = false; + $mention = false; + $audience = []; // Check if we should always deliver our stuff via BCC if (!empty($item['uid'])) { $owner = User::getOwnerDataById($item['uid']); if (!empty($owner)) { $always_bcc = $owner['hide-friends']; - $is_forum = ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY) && $owner['manually-approve']; + $is_group = ($owner['account-type'] == User::ACCOUNT_TYPE_COMMUNITY); $profile = APContact::getByURL($owner['url'], false); $follower = $profile['followers'] ?? ''; @@ -595,9 +599,48 @@ class Transmitter $parent = Post::selectFirst(['causer-link', 'post-reason'], ['id' => $item['parent']]); if (!empty($parent) && ($parent['post-reason'] == Item::PR_ANNOUNCEMENT) && !empty($parent['causer-link'])) { $profile = APContact::getByURL($parent['causer-link'], false); - $is_forum_thread = isset($profile['type']) && $profile['type'] == 'Group'; + $is_group_thread = isset($profile['type']) && $profile['type'] == 'Group'; } else { - $is_forum_thread = false; + $is_group_thread = false; + } + + if (!$is_group) { + $parent_tags = Tag::getByURIId($item['parent-uri-id'], [Tag::AUDIENCE, Tag::MENTION]); + if (!empty($parent_tags)) { + $is_group_thread = false; + foreach ($parent_tags as $tag) { + if ($tag['type'] != Tag::AUDIENCE) { + continue; + } + $profile = APContact::getByURL($tag['url'], false); + if (!empty($profile) && ($profile['type'] == 'Group')) { + $audience[] = $tag['url']; + $is_group_thread = true; + } + } + if ($is_group_thread) { + foreach ($parent_tags as $tag) { + if (($tag['type'] == Tag::MENTION) && in_array($tag['url'], $audience)) { + $mention = true; + } + } + $exclusive = !$mention; + } + } elseif ($is_group_thread) { + foreach (Tag::getByURIId($item['parent-uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $term) { + $profile = APContact::getByURL($term['url'], false); + if (!empty($profile) && ($profile['type'] == 'Group')) { + if ($term['type'] == Tag::EXCLUSIVE_MENTION) { + $audience[] = $term['url']; + $exclusive = true; + } elseif ($term['type'] == Tag::MENTION) { + $mention = true; + } + } + } + } + } else { + $audience[] = $owner['url']; } if (self::isAnnounce($item) || self::isAPPost($last_id)) { @@ -608,7 +651,7 @@ class Transmitter $networks = [Protocol::ACTIVITYPUB, Protocol::OSTATUS]; } - $data = ['to' => [], 'cc' => [], 'bcc' => [] , 'audience' => []]; + $data = ['to' => [], 'cc' => [], 'bcc' => [] , 'audience' => $audience]; if ($item['gravity'] == Item::GRAVITY_PARENT) { $actor_profile = APContact::getByURL($item['owner-link']); @@ -616,23 +659,7 @@ class Transmitter $actor_profile = APContact::getByURL($item['author-link']); } - $exclusive = false; - $mention = false; - - if ($is_forum_thread) { - foreach (Tag::getByURIId($item['parent-uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $term) { - $profile = APContact::getByURL($term['url'], false); - if (!empty($profile) && ($profile['type'] == 'Group')) { - if ($term['type'] == Tag::EXCLUSIVE_MENTION) { - $exclusive = true; - } elseif ($term['type'] == Tag::MENTION) { - $mention = true; - } - } - } - } - - $terms = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION]); + $terms = Tag::getByURIId($item['uri-id'], [Tag::MENTION, Tag::IMPLICIT_MENTION, Tag::EXCLUSIVE_MENTION, Tag::AUDIENCE]); if ($item['private'] != Item::PRIVATE) { // Directly mention the original author upon a quoted reshare. @@ -644,7 +671,9 @@ class Transmitter $data['cc'][] = $announce['actor']['url']; } - $data = array_merge($data, self::fetchPermissionBlockFromThreadParent($item, $is_forum_thread)); + if (!$exclusive) { + $data = array_merge_recursive($data, self::fetchPermissionBlockFromThreadParent($item, $is_group_thread)); + } // Check if the item is completely public or unlisted if ($item['private'] == Item::PUBLIC) { @@ -656,6 +685,9 @@ class Transmitter foreach ($terms as $term) { $profile = APContact::getByURL($term['url'], false); if (!empty($profile)) { + if (($term['type'] == Tag::AUDIENCE) && ($profile['type'] == 'Group')) { + $data['audience'][] = $profile['url']; + } if ($term['type'] == Tag::EXCLUSIVE_MENTION) { $exclusive = true; if (!empty($profile['followers']) && ($profile['type'] == 'Group')) { @@ -684,6 +716,9 @@ class Transmitter $profile = APContact::getByURL($term['url'], false); if (!empty($profile)) { + if (($term['type'] == Tag::AUDIENCE) && ($profile['type'] == 'Group')) { + $data['audience'][] = $profile['url']; + } if ($term['type'] == Tag::EXCLUSIVE_MENTION) { $exclusive = true; if (!empty($profile['followers']) && ($profile['type'] == 'Group')) { @@ -702,7 +737,7 @@ class Transmitter $exclusive = false; } - if ($is_forum && !$exclusive && !empty($follower)) { + if ($is_group && !$exclusive && !empty($follower)) { $data['cc'][] = $follower; } elseif (!$exclusive) { foreach ($receiver_list as $receiver) { @@ -727,7 +762,7 @@ class Transmitter } } - if (!empty($item['parent'])) { + if (!empty($item['parent']) && (!$exclusive || ($item['private'] == Item::PRIVATE))) { if ($item['private'] == Item::PRIVATE) { $condition = ['parent' => $item['parent'], 'uri-id' => $item['thr-parent-id']]; } else { @@ -739,19 +774,19 @@ class Transmitter $profile = APContact::getByURL($parent['owner-link'], false); if (!empty($profile)) { if ($item['gravity'] != Item::GRAVITY_PARENT) { - // Comments to forums are directed to the forum - // But comments to forums aren't directed to the followers collection - // This rule is only valid when the actor isn't the forum. - // The forum needs to transmit their content to their followers. + // Comments to groups are directed to the group + // But comments to groups aren't directed to the followers collection + // This rule is only valid when the actor isn't the group. + // The group needs to transmit their content to their followers. if (($profile['type'] == 'Group') && ($profile['url'] != ($actor_profile['url'] ?? ''))) { $data['to'][] = $profile['url']; } else { $data['cc'][] = $profile['url']; - if (($item['private'] != Item::PRIVATE) && !empty($actor_profile['followers']) && (!$exclusive || !$is_forum_thread)) { + if (($item['private'] != Item::PRIVATE) && !empty($actor_profile['followers']) && (!$exclusive || !$is_group_thread)) { $data['cc'][] = $actor_profile['followers']; } } - } elseif (!$exclusive && !$is_forum_thread) { + } elseif (!$exclusive && !$is_group_thread) { // Public thread parent post always are directed to the followers. if ($item['private'] != Item::PRIVATE) { $data['cc'][] = $actor_profile['followers']; @@ -794,10 +829,6 @@ class Transmitter unset($data['bcc'][$key]); } - if (($key = array_search($item['author-link'], $data['audience'])) !== false) { - unset($data['audience'][$key]); - } - foreach ($data['to'] as $to) { if (($key = array_search($to, $data['cc'])) !== false) { unset($data['cc'][$key]); @@ -814,20 +845,13 @@ class Transmitter } } - $receivers = ['to' => array_values($data['to']), 'cc' => array_values($data['cc']), 'bcc' => array_values($data['bcc'])]; - - if (!empty($data['audience'])) { - $receivers['audience'] = array_values($data['audience']); - if (count($receivers['audience']) == 1) { - $receivers['audience'] = $receivers['audience'][0]; - } - } + $receivers = ['to' => array_values($data['to']), 'cc' => array_values($data['cc']), 'bcc' => array_values($data['bcc']), 'audience' => array_values($data['audience'])]; if (!$blindcopy) { unset($receivers['bcc']); } - foreach (['to' => Tag::TO, 'cc' => Tag::CC, 'bcc' => Tag::BCC] as $element => $type) { + foreach (['to' => Tag::TO, 'cc' => Tag::CC, 'bcc' => Tag::BCC, 'audience' => Tag::AUDIENCE] as $element => $type) { if (!empty($receivers[$element])) { foreach ($receivers[$element] as $receiver) { if ($receiver == ActivityPub::PUBLIC_COLLECTION) { @@ -840,6 +864,12 @@ class Transmitter } } + if (!$blindcopy && count($receivers['audience']) == 1) { + $receivers['audience'] = $receivers['audience'][0]; + } elseif (!$receivers['audience']) { + unset($receivers['audience']); + } + return $receivers; } @@ -885,12 +915,11 @@ class Transmitter { $inboxes = []; - $isforum = false; - + $isGroup = false; if (!empty($item['uid'])) { $profile = User::getOwnerDataById($item['uid']); if (!empty($profile)) { - $isforum = $profile['account-type'] == User::ACCOUNT_TYPE_COMMUNITY; + $isGroup = $profile['account-type'] == User::ACCOUNT_TYPE_COMMUNITY; } } @@ -920,7 +949,7 @@ class Transmitter continue; } - if ($isforum && ($contact['network'] == Protocol::DFRN)) { + if ($isGroup && ($contact['network'] == Protocol::DFRN)) { continue; } @@ -977,7 +1006,7 @@ class Transmitter $profile_uid = User::getIdForURL($item_profile['url']); - foreach (['to', 'cc', 'bto', 'bcc'] as $element) { + foreach (['to', 'cc', 'bto', 'bcc', 'audience'] as $element) { if (empty($permissions[$element])) { continue; } @@ -990,7 +1019,7 @@ class Transmitter } if ($item_profile && ($receiver == $item_profile['followers']) && ($uid == $profile_uid)) { - $inboxes = array_merge($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id))); + $inboxes = array_merge_recursive($inboxes, self::fetchTargetInboxesforUser($uid, $personal, self::isAPPost($last_id))); } else { $profile = APContact::getByURL($receiver, false); if (!empty($profile)) { @@ -1001,7 +1030,7 @@ class Transmitter } else { $target = $profile['sharedinbox']; } - if (!self::archivedInbox($target)) { + if (!self::archivedInbox($target) && !in_array($contact['id'], $inboxes[$target] ?? [])) { $inboxes[$target][] = $contact['id'] ?? 0; } } @@ -1102,12 +1131,14 @@ class Transmitter unset($data['cc']); unset($data['bcc']); + unset($data['audience']); $object['to'] = $data['to']; $object['tag'] = [['type' => 'Mention', 'href' => $object['to'][0], 'name' => '']]; unset($object['cc']); unset($object['bcc']); + unset($object['audience']); $data['directMessage'] = true; @@ -1174,14 +1205,16 @@ class Transmitter /** * Creates the activity or fetches it from the cache * - * @param integer $item_id Item id - * @param boolean $force Force new cache entry + * @param integer $item_id Item id + * @param boolean $force Force new cache entry + * @param boolean $object_mode true = Create the object, false = create the activity with the object + * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link * @return array|false activity or false on failure * @throws \Exception */ - public static function createCachedActivityFromItem(int $item_id, bool $force = false, bool $object_mode = false) + public static function createCachedActivityFromItem(int $item_id, bool $force = false, bool $object_mode = false, $announce_activity = false) { - $cachekey = 'APDelivery:createActivity:' . $item_id . ':' . (int)$object_mode; + $cachekey = 'APDelivery:createActivity:' . $item_id . ':' . (int)$object_mode . ':' . (int)$announce_activity; if (!$force) { $data = DI::cache()->get($cachekey); @@ -1190,7 +1223,7 @@ class Transmitter } } - $data = self::createActivityFromItem($item_id, $object_mode); + $data = self::createActivityFromItem($item_id, $object_mode, false, $announce_activity); DI::cache()->set($cachekey, $data, Duration::QUARTER_HOUR); return $data; @@ -1200,12 +1233,13 @@ class Transmitter * Creates an activity array for a given item id * * @param integer $item_id - * @param boolean $object_mode Is the activity item is used inside another object? - * @param boolean $api_mode "true" if used for the API + * @param boolean $object_mode true = Create the object, false = create the activity with the object + * @param boolean $api_mode true = used for the API + * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link * @return false|array * @throws \Exception */ - public static function createActivityFromItem(int $item_id, bool $object_mode = false, $api_mode = false) + public static function createActivityFromItem(int $item_id, bool $object_mode = false, $api_mode = false, $announce_activity = false) { $condition = ['id' => $item_id]; if (!$api_mode) { @@ -1216,7 +1250,7 @@ class Transmitter if (!DBA::isResult($item)) { return false; } - return self::createActivityFromArray($item, $object_mode, $api_mode); + return self::createActivityFromArray($item, $object_mode, $api_mode, $announce_activity); } /** @@ -1224,12 +1258,13 @@ class Transmitter * * @param integer $uri_id * @param integer $uid - * @param boolean $object_mode Is the activity item is used inside another object? - * @param boolean $api_mode "true" if used for the API + * @param boolean $object_mode true = Create the object, false = create the activity with the object + * @param boolean $api_mode true = used for the API + * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link * @return false|array * @throws \Exception */ - public static function createActivityFromUriId(int $uri_id, int $uid, bool $object_mode = false, $api_mode = false) + public static function createActivityFromUriId(int $uri_id, int $uid, bool $object_mode = false, $api_mode = false, $announce_activity = false) { $condition = ['uri-id' => $uri_id, 'uid' => [0, $uid]]; if (!$api_mode) { @@ -1241,19 +1276,20 @@ class Transmitter return false; } - return self::createActivityFromArray($item, $object_mode, $api_mode); + return self::createActivityFromArray($item, $object_mode, $api_mode, $announce_activity); } /** * Creates an activity array for a given item id * * @param integer $item_id - * @param boolean $object_mode Is the activity item is used inside another object? - * @param boolean $api_mode "true" if used for the API + * @param boolean $object_mode true = Create the object, false = create the activity with the object + * @param boolean $api_mode true = used for the API + * @param boolean $announce_activity true = the announced object is the activity, false = we announce the object link * @return false|array * @throws \Exception */ - private static function createActivityFromArray(array $item, bool $object_mode = false, $api_mode = false) + private static function createActivityFromArray(array $item, bool $object_mode = false, $api_mode = false, $announce_activity = false) { if (!$api_mode && !$item['deleted'] && $item['network'] == Protocol::ACTIVITYPUB) { $data = Post\Activity::getByURIId($item['uri-id']); @@ -1323,7 +1359,13 @@ class Transmitter $data = self::createAddTag($item, $data); } elseif ($data['type'] == 'Announce') { if ($item['verb'] == ACTIVITY::ANNOUNCE) { - $data['object'] = $item['thr-parent']; + if ($announce_activity) { + $anounced_item = Post::selectFirst(['uid'], ['uri-id' => $item['thr-parent-id'], 'origin' => true]); + $data['object'] = self::createActivityFromUriId($item['thr-parent-id'], $anounced_item['uid'] ?? 0); + unset($data['object']['@context']); + } else { + $data['object'] = $item['thr-parent']; + } } else { $data = self::createAnnounce($item, $data, $api_mode); } diff --git a/src/Protocol/DFRN.php b/src/Protocol/DFRN.php index b29a3676a..1fcaaba7f 100644 --- a/src/Protocol/DFRN.php +++ b/src/Protocol/DFRN.php @@ -2220,8 +2220,8 @@ class DFRN GServer::setProtocol($importer['gsid'], Post\DeliveryData::DFRN); } - // is it a public forum? Private forums aren't exposed with this method - $forum = intval(XML::getFirstNodeValue($xpath, '/atom:feed/dfrn:community/text()')); + // is it a public group? Private groups aren't exposed with this method + $group = intval(XML::getFirstNodeValue($xpath, '/atom:feed/dfrn:community/text()')); // The account type is new since 3.5.1 if ($xpath->query('/atom:feed/dfrn:account_type')->length > 0) { @@ -2235,17 +2235,17 @@ class DFRN // Updating the public contact as well Contact::update(['contact-type' => $accounttype], ['uid' => 0, 'nurl' => $importer['nurl']]); } - // A forum contact can either have set "forum" or "prv" - but not both + // A group contact can either have set "forum" or "prv" - but not both if ($accounttype == User::ACCOUNT_TYPE_COMMUNITY) { - // It's a forum, so either set the public or private forum flag - $condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $forum, !$forum, $importer['id']]; - Contact::update(['forum' => $forum, 'prv' => !$forum], $condition); + // It's a group, so either set the public or private forum flag + $condition = ['(`forum` != ? OR `prv` != ?) AND `id` = ?', $group, !$group, $importer['id']]; + Contact::update(['forum' => $group, 'prv' => !$group], $condition); // Updating the public contact as well - $condition = ['(`forum` != ? OR `prv` != ?) AND `uid` = 0 AND `nurl` = ?', $forum, !$forum, $importer['nurl']]; - Contact::update(['forum' => $forum, 'prv' => !$forum], $condition); + $condition = ['(`forum` != ? OR `prv` != ?) AND `uid` = 0 AND `nurl` = ?', $group, !$group, $importer['nurl']]; + Contact::update(['forum' => $group, 'prv' => !$group], $condition); } else { - // It's not a forum, so remove the flags + // It's not a group, so remove the flags $condition = ['(`forum` OR `prv`) AND `id` = ?', $importer['id']]; Contact::update(['forum' => false, 'prv' => false], $condition); @@ -2253,13 +2253,13 @@ class DFRN $condition = ['(`forum` OR `prv`) AND `uid` = 0 AND `nurl` = ?', $importer['nurl']]; Contact::update(['forum' => false, 'prv' => false], $condition); } - } elseif ($forum != $importer['forum']) { // Deprecated since 3.5.1 - $condition = ['`forum` != ? AND `id` = ?', $forum, $importer['id']]; - Contact::update(['forum' => $forum], $condition); + } elseif ($group != $importer['forum']) { // Deprecated since 3.5.1 + $condition = ['`forum` != ? AND `id` = ?', $group, $importer['id']]; + Contact::update(['forum' => $group], $condition); // Updating the public contact as well - $condition = ['`forum` != ? AND `uid` = 0 AND `nurl` = ?', $forum, $importer['nurl']]; - Contact::update(['forum' => $forum], $condition); + $condition = ['`forum` != ? AND `uid` = 0 AND `nurl` = ?', $group, $importer['nurl']]; + Contact::update(['forum' => $group], $condition); } diff --git a/src/Protocol/Delivery.php b/src/Protocol/Delivery.php index c8039344e..9f8174e2d 100644 --- a/src/Protocol/Delivery.php +++ b/src/Protocol/Delivery.php @@ -404,7 +404,7 @@ class Delivery */ private static function deliverDiaspora(string $cmd, array $contact, array $owner, array $items, array $target_item, bool $public_message, bool $top_level, bool $followup): bool { - // We don't treat Forum posts as "wall-to-wall" to be able to post them via Diaspora + // We don't treat group posts as "wall-to-wall" to be able to post them via Diaspora $walltowall = $top_level && ($owner['id'] != $items[0]['contact-id']) & ($owner['account-type'] != User::ACCOUNT_TYPE_COMMUNITY); if ($public_message) { diff --git a/src/Protocol/Diaspora.php b/src/Protocol/Diaspora.php index affb3cf87..dd6c2115b 100644 --- a/src/Protocol/Diaspora.php +++ b/src/Protocol/Diaspora.php @@ -267,7 +267,7 @@ class Diaspora if ($no_exit) { return false; } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } } } else { @@ -281,7 +281,7 @@ class Diaspora if ($no_exit) { return false; } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } } @@ -307,7 +307,7 @@ class Diaspora if ($no_exit) { return false; } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } } @@ -322,7 +322,7 @@ class Diaspora if ($no_exit) { return false; } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } } @@ -332,7 +332,7 @@ class Diaspora if ($no_exit) { return false; } else { - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } } @@ -424,7 +424,7 @@ class Diaspora if (!$base) { Logger::notice('unable to locate salmon data in xml'); - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } @@ -444,14 +444,11 @@ class Diaspora $encoding = $base->encoding; $alg = $base->alg; - $signed_data = $data . '.' . Strings::base64UrlEncode($type) . '.' . Strings::base64UrlEncode($encoding) . '.' . Strings::base64UrlEncode($alg); - // decode the data $data = Strings::base64UrlDecode($data); - if ($public) { $inner_decrypted = $data; } else { @@ -467,14 +464,14 @@ class Diaspora $key = self::key($author); if (!$key) { Logger::notice('Could not retrieve author key.'); - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } $verify = Crypto::rsaVerify($signed_data, $signature, $key); if (!$verify) { Logger::notice('Message did not verify. Discarding.'); - throw new \Friendica\Network\HTTPException\BadRequestException(); + throw new HTTPException\BadRequestException(); } Logger::info('Message verified.'); @@ -499,8 +496,7 @@ class Diaspora */ public static function dispatchPublic(array $msg, int $direction) { - $enabled = intval(DI::config()->get('system', 'diaspora_enabled')); - if (!$enabled) { + if (!DI::config()->get('system', 'diaspora_enabled')) { Logger::notice('Diaspora is disabled'); return false; } @@ -940,7 +936,7 @@ class Diaspora { $item = Post::selectFirst(['id'], ['uid' => $uid, 'guid' => $guid]); if (DBA::isResult($item)) { - Logger::notice('Message ' . $guid . ' already exists for user ' . $uid); + Logger::notice('Message already exists.', ['uid' => $uid, 'guid' => $guid, 'id' => $item['id']]); return $item['id']; } @@ -951,6 +947,7 @@ class Diaspora * Checks for links to posts in a message * * @param array $item The item array + * * @return void */ private static function fetchGuid(array $item) @@ -2569,19 +2566,21 @@ class Diaspora * * @param int $uriid * @param object $photo + * * @return void */ private static function storePhotoAsMedia(int $uriid, $photo) { // @TODO Need to find object type, roland@f.haeder.net Logger::debug('photo=' . get_class($photo)); - $data = []; - $data['uri-id'] = $uriid; - $data['type'] = Post\Media::IMAGE; - $data['url'] = XML::unescape($photo->remote_photo_path) . XML::unescape($photo->remote_photo_name); - $data['height'] = (int)XML::unescape($photo->height ?? 0); - $data['width'] = (int)XML::unescape($photo->width ?? 0); - $data['description'] = XML::unescape($photo->text ?? ''); + $data = [ + 'uri-id' => $uriid, + 'type' => Post\Media::IMAGE, + 'url' => XML::unescape($photo->remote_photo_path) . XML::unescape($photo->remote_photo_name), + 'height' => (int)XML::unescape($photo->height ?? 0), + 'width' => (int)XML::unescape($photo->width ?? 0), + 'description' => XML::unescape($photo->text ?? ''), + ]; Post\Media::insert($data); } @@ -2653,11 +2652,32 @@ class Diaspora $raw_body = $body = Markdown::toBBCode($text); - $datarray = []; + $datarray = [ + 'guid' => $guid, + 'plink' => self::plink($author, $guid), + 'uid' => $importer['uid'], + 'contact-id' => $contact['id'], + 'network' => Protocol::DIASPORA, + 'author-link' => $contact['url'], + 'author-id' => Contact::getIdForURL($contact['url'], 0), + 'verb' => Activity::POST, + 'gravity' => Item::GRAVITY_PARENT, + 'protocol' => Conversation::PARCEL_DIASPORA, + 'source' => $xml, + 'body' => self::replacePeopleGuid($body, $contact['url']), + 'raw-body' => self::replacePeopleGuid($raw_body, $contact['url']), + 'private' => (($public == 'false') ? Item::PRIVATE : Item::PUBLIC), + // Default is note (aka. comment), later below is being checked the real type + 'object-type' => Activity\ObjectType::NOTE, + 'post-type' => Item::PT_NOTE, + ]; - $datarray['guid'] = $guid; - $datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author); - $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); + $datarray['uri'] = $datarray['thr-parent'] = self::getUriFromGuid($guid, $author); + $datarray['uri-id'] = ItemURI::insert(['uri' => $datarray['uri'], 'guid' => $datarray['guid']]); + $datarray['owner-link'] = $datarray['author-link']; + $datarray['owner-id'] = $datarray['author-id']; + + $datarray = self::setDirection($datarray, $direction); // Attach embedded pictures to the body if ($data->photo) { @@ -2668,11 +2688,7 @@ class Diaspora $datarray['object-type'] = Activity\ObjectType::IMAGE; $datarray['post-type'] = Item::PT_IMAGE; } elseif ($data->poll) { - $datarray['object-type'] = Activity\ObjectType::NOTE; $datarray['post-type'] = Item::PT_POLL; - } else { - $datarray['object-type'] = Activity\ObjectType::NOTE; - $datarray['post-type'] = Item::PT_NOTE; } /// @todo enable support for polls @@ -2684,27 +2700,6 @@ class Diaspora /// @todo enable support for events - $datarray['uid'] = $importer['uid']; - $datarray['contact-id'] = $contact['id']; - $datarray['network'] = Protocol::DIASPORA; - - $datarray['author-link'] = $contact['url']; - $datarray['author-id'] = Contact::getIdForURL($contact['url'], 0); - - $datarray['owner-link'] = $datarray['author-link']; - $datarray['owner-id'] = $datarray['author-id']; - - $datarray['verb'] = Activity::POST; - $datarray['gravity'] = Item::GRAVITY_PARENT; - - $datarray['protocol'] = Conversation::PARCEL_DIASPORA; - $datarray['source'] = $xml; - - $datarray = self::setDirection($datarray, $direction); - - $datarray['body'] = self::replacePeopleGuid($body, $contact['url']); - $datarray['raw-body'] = self::replacePeopleGuid($raw_body, $contact['url']); - self::storeMentions($datarray['uri-id'], $text); Tag::storeRawTagsFromBody($datarray['uri-id'], $datarray['body']); @@ -2717,8 +2712,6 @@ class Diaspora $datarray['app'] = $provider_display_name; } - $datarray['plink'] = self::plink($author, $guid); - $datarray['private'] = (($public == 'false') ? Item::PRIVATE : Item::PUBLIC); $datarray['changed'] = $datarray['created'] = $datarray['edited'] = $created_at; if (isset($address['address'])) { @@ -2839,7 +2832,7 @@ class Diaspora public static function buildMagicEnvelope(string $msg, array $user): string { $b64url_data = Strings::base64UrlEncode($msg); - $data = str_replace(["\n", "\r", " ", "\t"], ['', '', '', ''], $b64url_data); + $data = str_replace(["\n", "\r", ' ', "\t"], ['', '', '', ''], $b64url_data); $key_id = Strings::base64UrlEncode(self::myHandle($user)); $type = 'application/xml'; @@ -2857,11 +2850,11 @@ class Diaspora $xmldata = [ 'me:env' => [ - 'me:data' => $data, - '@attributes' => ['type' => $type], - 'me:encoding' => $encoding, - 'me:alg' => $alg, - 'me:sig' => $sig, + 'me:data' => $data, + '@attributes' => ['type' => $type], + 'me:encoding' => $encoding, + 'me:alg' => $alg, + 'me:sig' => $sig, '@attributes2' => ['key_id' => $key_id] ] ]; diff --git a/src/Protocol/Feed.php b/src/Protocol/Feed.php index fced3526d..fdfe9be7d 100644 --- a/src/Protocol/Feed.php +++ b/src/Protocol/Feed.php @@ -25,6 +25,7 @@ use DOMDocument; use DOMElement; use DOMXPath; use Friendica\App; +use Friendica\Contact\LocalRelationship\Entity\LocalRelationship; use Friendica\Content\PageInfo; use Friendica\Content\Text\BBCode; use Friendica\Content\Text\HTML; @@ -566,8 +567,10 @@ class Feed continue; } + $fetch_further_information = $contact['fetch_further_information'] ?? LocalRelationship::FFI_NONE; + $preview = ''; - if (!empty($contact['fetch_further_information']) && ($contact['fetch_further_information'] < 3)) { + if (in_array($fetch_further_information, [LocalRelationship::FFI_INFORMATION, LocalRelationship::FFI_BOTH])) { // Handle enclosures and treat them as preview picture foreach ($attachments as $attachment) { if ($attachment['mimetype'] == 'image/jpeg') { @@ -611,7 +614,12 @@ class Feed } } - $data = PageInfo::queryUrl($item['plink'], false, $preview, ($contact['fetch_further_information'] == 2), $contact['ffi_keyword_denylist'] ?? ''); + $data = PageInfo::queryUrl( + $item['plink'], + false, + $fetch_further_information == LocalRelationship::FFI_BOTH, + $contact['ffi_keyword_denylist'] ?? '' + ); if (!empty($data)) { // Take the data that was provided by the feed if the query is empty @@ -630,7 +638,7 @@ class Feed // We always strip the title since it will be added in the page information $item['title'] = ''; $item['body'] = $item['body'] . "\n" . PageInfo::getFooterFromData($data, false); - $taglist = $contact['fetch_further_information'] == 2 ? PageInfo::getTagsFromUrl($item['plink'], $preview, $contact['ffi_keyword_denylist'] ?? '') : []; + $taglist = $fetch_further_information == LocalRelationship::FFI_BOTH ? PageInfo::getTagsFromUrl($item['plink'], $preview, $contact['ffi_keyword_denylist'] ?? '') : []; $item['object-type'] = Activity\ObjectType::BOOKMARK; $attachments = []; @@ -662,7 +670,7 @@ class Feed $item['body'] = '[abstract]' . HTML::toBBCode($summary, $basepath) . "[/abstract]\n" . $item['body']; } - if (!empty($contact['fetch_further_information']) && ($contact['fetch_further_information'] == 3)) { + if ($fetch_further_information == LocalRelationship::FFI_KEYWORD) { if (empty($taglist)) { $taglist = PageInfo::getTagsFromUrl($item['plink'], $preview, $contact['ffi_keyword_denylist'] ?? ''); } diff --git a/src/Protocol/OStatus.php b/src/Protocol/OStatus.php index ff8fc3cbe..3d35394b9 100644 --- a/src/Protocol/OStatus.php +++ b/src/Protocol/OStatus.php @@ -385,12 +385,14 @@ class OStatus } } - $header = []; - $header['uid'] = $importer['uid']; - $header['network'] = Protocol::OSTATUS; - $header['wall'] = 0; - $header['origin'] = 0; - $header['gravity'] = Item::GRAVITY_COMMENT; + // Initial header elements + $header = [ + 'uid' => $importer['uid'], + 'network' => Protocol::OSTATUS, + 'wall' => 0, + 'origin' => 0, + 'gravity' => Item::GRAVITY_COMMENT, + ]; if (!is_object($doc->firstChild) || empty($doc->firstChild->tagName)) { return false; diff --git a/src/Protocol/Relay.php b/src/Protocol/Relay.php index d8b11cf95..2002aa9bb 100644 --- a/src/Protocol/Relay.php +++ b/src/Protocol/Relay.php @@ -135,6 +135,28 @@ class Relay } } + if (!self::isWantedLanguage($body)) { + Logger::info('Unwanted or Undetected language found - rejected', ['network' => $network, 'url' => $url, 'causer' => $causer, 'tags' => $tags]); + return false; + } + + if ($scope == self::SCOPE_ALL) { + Logger::info('Server accept all posts - accepted', ['network' => $network, 'url' => $url, 'causer' => $causer, 'tags' => $tags]); + return true; + } + + Logger::info('No matching hashtags found - rejected', ['network' => $network, 'url' => $url, 'causer' => $causer, 'tags' => $tags]); + return false; + } + + /** + * Detect the language of a post and decide if the post should be accepted + * + * @param string $body + * @return boolean + */ + public static function isWantedLanguage(string $body) + { $languages = []; foreach (Item::getLanguageArray($body, 10) as $language => $reliability) { if ($reliability > 0) { @@ -142,25 +164,19 @@ class Relay } } - Logger::debug('Got languages', ['languages' => $languages, 'body' => $body, 'causer' => $causer]); + Logger::debug('Got languages', ['languages' => $languages, 'body' => $body]); if (!empty($languages)) { - if (in_array($languages[0], $config->get('system', 'relay_deny_languages'))) { - Logger::info('Unwanted language found - rejected', ['language' => $languages[0], 'network' => $network, 'url' => $url, 'causer' => $causer]); + if (in_array($languages[0], DI::config()->get('system', 'relay_deny_languages'))) { + Logger::info('Unwanted language found', ['language' => $languages[0]]); return false; } - } elseif ($config->get('system', 'relay_deny_undetected_language')) { - Logger::info('Undetected language found - rejected', ['body' => $body, 'network' => $network, 'url' => $url, 'causer' => $causer]); + } elseif (DI::config()->get('system', 'relay_deny_undetected_language')) { + Logger::info('Undetected language found', ['body' => $body]); return false; } - if ($scope == self::SCOPE_ALL) { - Logger::info('Server accept all posts - accepted', ['network' => $network, 'url' => $url, 'causer' => $causer]); - return true; - } - - Logger::info('No matching hashtags found - rejected', ['network' => $network, 'url' => $url, 'causer' => $causer]); - return false; + return true; } /** @@ -338,7 +354,7 @@ class Relay public static function getList(array $fields = []): array { return DBA::selectToArray('apcontact', $fields, - ["`type` = ? AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 0, Contact::FRIEND]); + ["`type` IN (?, ?) AND `url` IN (SELECT `url` FROM `contact` WHERE `uid` = ? AND `rel` = ?)", 'Application', 'Service', 0, Contact::FRIEND]); } /** diff --git a/src/Render/FriendicaSmarty.php b/src/Render/FriendicaSmarty.php index 2ace5688a..1df1ffe4a 100644 --- a/src/Render/FriendicaSmarty.php +++ b/src/Render/FriendicaSmarty.php @@ -53,6 +53,10 @@ class FriendicaSmarty extends Smarty $this->setConfigDir($work_dir . '/'); $this->setCacheDir($work_dir . '/'); + $this->registerPlugin('modifier', 'is_string', function ($value) { + return is_string($value); + }); + /* * Enable sub-directory splitting for reducing directory descriptor * size. The default behavior is to put all compiled/cached files into diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php index 2fc8724f7..7655398b3 100644 --- a/src/Security/OAuth.php +++ b/src/Security/OAuth.php @@ -29,6 +29,7 @@ use Friendica\Model\Contact; use Friendica\Model\User; use Friendica\Module\BaseApi; use Friendica\Util\DateTimeFormat; +use GuzzleHttp\Psr7\Uri; /** * OAuth Server @@ -128,8 +129,11 @@ class OAuth if (!empty($client_secret)) { $condition['client_secret'] = $client_secret; } + if (!empty($redirect_uri)) { - $condition['redirect_uri'] = $redirect_uri; + $uri = new Uri($redirect_uri); + $redirect_uri = $uri->getScheme() . '://' . $uri->getHost() . $uri->getPath(); + $condition = DBA::mergeConditions($condition, ["`redirect_uri` LIKE ?", '%' . $redirect_uri . '%']); } $application = DBA::selectFirst('application', [], $condition); @@ -137,6 +141,12 @@ class OAuth Logger::warning('Application not found', $condition); return []; } + + // The redirect_uri could contain several URI that are separated by spaces. + if (($application['redirect_uri'] != $redirect_uri) && !in_array($redirect_uri, explode(' ', $application['redirect_uri']))) { + return []; + } + return $application; } @@ -187,7 +197,8 @@ class OAuth 'write' => (stripos($scope, BaseApi::SCOPE_WRITE) !== false), 'follow' => (stripos($scope, BaseApi::SCOPE_FOLLOW) !== false), 'push' => (stripos($scope, BaseApi::SCOPE_PUSH) !== false), - 'created_at' => DateTimeFormat::utcNow()]; + 'created_at' => DateTimeFormat::utcNow() + ]; foreach ([BaseApi::SCOPE_READ, BaseApi::SCOPE_WRITE, BaseApi::SCOPE_WRITE, BaseApi::SCOPE_PUSH] as $scope) { if ($fields[$scope] && !$application[$scope]) { diff --git a/src/Security/PermissionSet/Repository/PermissionSet.php b/src/Security/PermissionSet/Repository/PermissionSet.php index 76cd446c1..5abfb9305 100644 --- a/src/Security/PermissionSet/Repository/PermissionSet.php +++ b/src/Security/PermissionSet/Repository/PermissionSet.php @@ -25,7 +25,7 @@ use Exception; use Friendica\BaseRepository; use Friendica\Database\Database; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Network\HTTPException\NotFoundException; use Friendica\Security\PermissionSet\Exception\PermissionSetNotFoundException; use Friendica\Security\PermissionSet\Exception\PermissionSetPersistenceException; @@ -140,29 +140,29 @@ class PermissionSet extends BaseRepository $user_contact_str = ''; } - $groups = []; + $circle_ids = []; if (!empty($user_contact_str) && $this->db->exists('contact', [ 'id' => $cid, 'uid' => $uid, 'blocked' => false ])) { - $groups = Group::getIdsByContactId($cid); + $circle_ids = Circle::getIdsByContactId($cid); } - $group_str = '<<>>'; // should be impossible to match - foreach ($groups as $group_id) { - $group_str .= '|<' . preg_quote($group_id) . '>'; + $circle_str = '<<>>'; // should be impossible to match + foreach ($circle_ids as $circle_id) { + $circle_str .= '|<' . preg_quote($circle_id) . '>'; } if (!empty($user_contact_str)) { $condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR LOCATE(?, `deny_cid`) OR deny_gid REGEXP ?) AND (LOCATE(?, allow_cid) OR LOCATE(?, allow_cid) OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))", - $uid, $user_contact_str, $public_contact_str, $group_str, - $user_contact_str, $public_contact_str, $group_str]; + $uid, $user_contact_str, $public_contact_str, $circle_str, + $user_contact_str, $public_contact_str, $circle_str]; } else { $condition = ["`uid` = ? AND (NOT (LOCATE(?, `deny_cid`) OR deny_gid REGEXP ?) AND (LOCATE(?, allow_cid) OR allow_gid REGEXP ? OR (allow_cid = '' AND allow_gid = '')))", - $uid, $public_contact_str, $group_str, $public_contact_str, $group_str]; + $uid, $public_contact_str, $circle_str, $public_contact_str, $circle_str]; } return $this->select($condition); @@ -211,7 +211,7 @@ class PermissionSet extends BaseRepository } /** - * Selects or creates a PermissionSet based on it's fields + * Selects or creates a PermissionSet based on its fields * * @param Entity\PermissionSet $permissionSet * diff --git a/src/Security/Security.php b/src/Security/Security.php index bc1d98ac1..0774491d0 100644 --- a/src/Security/Security.php +++ b/src/Security/Security.php @@ -24,7 +24,7 @@ namespace Friendica\Security; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\User; /** @@ -117,17 +117,13 @@ class Security if ($local_user && $local_user == $owner_id) { $sql = ''; /* - * Authenticated visitor. Load the groups the visitor belongs to. + * Authenticated visitor. Load the circles the visitor belongs to. */ } elseif ($remote_contact) { - $gs = '<<>>'; // should be impossible to match + $circleIds = '<<>>'; // should be impossible to match - $groups = Group::getIdsByContactId($remote_contact); - - if (is_array($groups)) { - foreach ($groups as $g) { - $gs .= '|<' . intval($g) . '>'; - } + foreach (Circle::getIdsByContactId($remote_contact) as $circleId) { + $circleIds .= '|<' . intval($circleId) . '>'; } $sql = sprintf( @@ -135,9 +131,9 @@ class Security AND (allow_cid REGEXP '<%d>' OR allow_gid REGEXP '%s' OR (allow_cid = '' AND allow_gid = ''))" . $acc_sql . ") ", intval($remote_contact), - DBA::escape($gs), + DBA::escape($circleIds), intval($remote_contact), - DBA::escape($gs) + DBA::escape($circleIds) ); } return $sql; diff --git a/src/Security/TwoFactor/Model/AppSpecificPassword.php b/src/Security/TwoFactor/Model/AppSpecificPassword.php index 5c9cd5ead..affabb346 100644 --- a/src/Security/TwoFactor/Model/AppSpecificPassword.php +++ b/src/Security/TwoFactor/Model/AppSpecificPassword.php @@ -32,12 +32,12 @@ use PragmaRX\Random\Random; */ class AppSpecificPassword { - public static function countForUser($uid) + public static function countForUser(int $uid) { return DBA::count('2fa_app_specific_password', ['uid' => $uid]); } - public static function checkDuplicateForUser($uid, $description) + public static function checkDuplicateForUser(int $uid, string $description): bool { return DBA::exists('2fa_app_specific_password', ['uid' => $uid, 'description' => $description]); } @@ -50,7 +50,7 @@ class AppSpecificPassword * @return bool * @throws \Exception */ - public static function authenticateUser($uid, $plaintextPassword) + public static function authenticateUser(int $uid, string $plaintextPassword): bool { $appSpecificPasswords = self::getListForUser($uid); @@ -79,7 +79,7 @@ class AppSpecificPassword * @return array * @throws \Exception */ - public static function getListForUser($uid) + public static function getListForUser(int $uid): array { $appSpecificPasswordsStmt = DBA::select('2fa_app_specific_password', ['id', 'description', 'hashed_password', 'last_used'], ['uid' => $uid]); @@ -102,7 +102,7 @@ class AppSpecificPassword * @return array The new app-specific password data structure with the plaintext password added * @throws \Exception */ - public static function generateForUser(int $uid, $description) + public static function generateForUser(int $uid, string $description): array { $Random = (new Random())->size(40); @@ -111,10 +111,10 @@ class AppSpecificPassword $generated = DateTimeFormat::utcNow(); $fields = [ - 'uid' => $uid, - 'description' => $description, + 'uid' => $uid, + 'description' => $description, 'hashed_password' => User::hashPassword($plaintextPassword), - 'generated' => $generated, + 'generated' => $generated, ]; DBA::insert('2fa_app_specific_password', $fields); @@ -125,7 +125,7 @@ class AppSpecificPassword return $fields; } - private static function update($appSpecificPasswordId, $fields) + private static function update(int $appSpecificPasswordId, array $fields) { return DBA::update('2fa_app_specific_password', $fields, ['id' => $appSpecificPasswordId]); } diff --git a/src/Security/TwoFactor/Model/RecoveryCode.php b/src/Security/TwoFactor/Model/RecoveryCode.php index 2669ae18e..b3c197f98 100644 --- a/src/Security/TwoFactor/Model/RecoveryCode.php +++ b/src/Security/TwoFactor/Model/RecoveryCode.php @@ -35,10 +35,11 @@ class RecoveryCode * Returns the number of code the provided users can still use to replace a TOTP code * * @param int $uid User ID + * * @return int * @throws \Exception */ - public static function countValidForUser($uid) + public static function countValidForUser(int $uid): int { return DBA::count('2fa_recovery_codes', ['uid' => $uid, 'used' => null]); } @@ -46,12 +47,13 @@ class RecoveryCode /** * Checks the provided code is available to use for login by the provided user * - * @param int $uid User ID + * @param int $uid User ID * @param string $code + * * @return bool * @throws \Exception */ - public static function existsForUser($uid, $code) + public static function existsForUser(int $uid, string $code): bool { return DBA::exists('2fa_recovery_codes', ['uid' => $uid, 'code' => $code, 'used' => null]); } @@ -60,10 +62,11 @@ class RecoveryCode * Returns a complete list of all recovery codes for the provided user, including the used status * * @param int $uid User ID + * * @return array * @throws \Exception */ - public static function getListForUser($uid) + public static function getListForUser(int $uid): array { $codesStmt = DBA::select('2fa_recovery_codes', ['code', 'used'], ['uid' => $uid]); @@ -76,10 +79,11 @@ class RecoveryCode * * @param int $uid User ID * @param string $code + * * @return bool * @throws \Exception */ - public static function markUsedForUser($uid, $code) + public static function markUsedForUser(int $uid, string $code): bool { DBA::update('2fa_recovery_codes', ['used' => DateTimeFormat::utcNow()], ['uid' => $uid, 'code' => $code, 'used' => null]); @@ -91,9 +95,11 @@ class RecoveryCode * Generates 12 codes constituted of 2 blocks of 6 characters separated by a dash. * * @param int $uid User ID + * @return void + * * @throws \Exception */ - public static function generateForUser($uid) + public static function generateForUser(int $uid) { $Random = (new Random())->pattern('[a-z0-9]'); @@ -120,9 +126,11 @@ class RecoveryCode * Deletes all the recovery codes for the provided user. * * @param int $uid User ID + * @return void + * * @throws \Exception */ - public static function deleteForUser($uid) + public static function deleteForUser(int $uid) { DBA::delete('2fa_recovery_codes', ['uid' => $uid]); } @@ -131,9 +139,11 @@ class RecoveryCode * Replaces the existing recovery codes for the provided user by a freshly generated set. * * @param int $uid User ID + * @return void + * * @throws \Exception */ - public static function regenerateForUser($uid) + public static function regenerateForUser(int $uid) { self::deleteForUser($uid); self::generateForUser($uid); diff --git a/src/Security/TwoFactor/Repository/TrustedBrowser.php b/src/Security/TwoFactor/Repository/TrustedBrowser.php index a261d92ca..d913be3c9 100644 --- a/src/Security/TwoFactor/Repository/TrustedBrowser.php +++ b/src/Security/TwoFactor/Repository/TrustedBrowser.php @@ -143,6 +143,7 @@ class TrustedBrowser /** * @param int $local_user + * * @return bool */ public function removeAllForUser(int $local_user): bool diff --git a/src/Core/Hooks/Capabilities/IAmAStrategy.php b/src/User/Settings/Collection/UserGServers.php similarity index 79% rename from src/Core/Hooks/Capabilities/IAmAStrategy.php rename to src/User/Settings/Collection/UserGServers.php index 017cb56c4..689b801cf 100644 --- a/src/Core/Hooks/Capabilities/IAmAStrategy.php +++ b/src/User/Settings/Collection/UserGServers.php @@ -19,11 +19,12 @@ * */ -namespace Friendica\Core\Hooks\Capabilities; +namespace Friendica\User\Settings\Collection; -/** - * All classes, implementing this interface are valid Strategies for Hook calls - */ -interface IAmAStrategy +class UserGServers extends \Friendica\BaseCollection { + public function current(): \Friendica\User\Settings\Entity\UserGServer + { + return parent::current(); + } } diff --git a/src/User/Settings/Entity/UserGServer.php b/src/User/Settings/Entity/UserGServer.php new file mode 100644 index 000000000..e5afdc51e --- /dev/null +++ b/src/User/Settings/Entity/UserGServer.php @@ -0,0 +1,92 @@ +. + * + */ + +namespace Friendica\User\Settings\Entity; + +use Friendica\Federation\Entity\GServer; + +/** + * @property-read int $uid + * @property-read int $gsid + * @property-read bool $ignored + * @property-read ?GServer $gserver + */ +class UserGServer extends \Friendica\BaseEntity +{ + /** @var int User id */ + protected $uid; + /** @var int GServer id */ + protected $gsid; + /** @var bool Whether the user ignored this server */ + protected $ignored; + /** @var ?GServer */ + protected $gserver; + + public function __construct(int $uid, int $gsid, bool $ignored = false, ?GServer $gserver = null) + { + $this->uid = $uid; + $this->gsid = $gsid; + $this->ignored = $ignored; + $this->gserver = $gserver; + } + + /** + * Toggle the ignored property. + * + * Chainable. + * + * @return $this + */ + public function toggleIgnored(): UserGServer + { + $this->ignored = !$this->ignored; + + return $this; + } + + /** + * Set the ignored property. + * + * Chainable. + * + * @return $this + */ + public function ignore(): UserGServer + { + $this->ignored = true; + + return $this; + } + + /** + * Unset the ignored property. + * + * Chainable. + * + * @return $this + */ + public function unignore(): UserGServer + { + $this->ignored = false; + + return $this; + } +} diff --git a/src/User/Settings/Factory/UserGServer.php b/src/User/Settings/Factory/UserGServer.php new file mode 100644 index 000000000..61abe28cc --- /dev/null +++ b/src/User/Settings/Factory/UserGServer.php @@ -0,0 +1,60 @@ +. + * + */ + +namespace Friendica\User\Settings\Factory; + +use Friendica\Capabilities\ICanCreateFromTableRow; +use Friendica\Federation\Entity\GServer; +use Friendica\User\Settings\Entity; + +class UserGServer extends \Friendica\BaseFactory implements ICanCreateFromTableRow +{ + /** + * @param array $row `user-gserver` table row + * @param GServer|null $server Corresponding GServer entity + * @return Entity\UserGServer + */ + public function createFromTableRow(array $row, GServer $server = null): Entity\UserGServer + { + return new Entity\UserGServer( + $row['uid'], + $row['gsid'], + $row['ignored'], + $server, + ); + } + + /** + * @param int $uid + * @param int $gsid + * @param GServer|null $gserver Corresponding GServer entity + * @return Entity\UserGServer + */ + public function createFromUserAndServer(int $uid, int $gsid, GServer $gserver = null): Entity\UserGServer + { + return new Entity\UserGServer( + $uid, + $gsid, + false, + $gserver, + ); + } +} diff --git a/src/User/Settings/Repository/UserGServer.php b/src/User/Settings/Repository/UserGServer.php new file mode 100644 index 000000000..baf70095c --- /dev/null +++ b/src/User/Settings/Repository/UserGServer.php @@ -0,0 +1,156 @@ +. + * + */ + +namespace Friendica\User\Settings\Repository; + +use Exception; +use Friendica\BaseCollection; +use Friendica\BaseEntity; +use Friendica\Content\Pager; +use Friendica\Database\Database; +use Friendica\Federation\Repository\GServer; +use Friendica\Network\HTTPException\InternalServerErrorException; +use Friendica\Network\HTTPException\NotFoundException; +use Friendica\User\Settings\Collection; +use Friendica\User\Settings\Entity; +use Friendica\User\Settings\Factory; +use Psr\Log\LoggerInterface; + +class UserGServer extends \Friendica\BaseRepository +{ + protected static $table_name = 'user-gserver'; + + /** @var Factory\UserGServer */ + protected $factory; + /** @var GServer */ + protected $gserverRepository; + + public function __construct(GServer $gserverRepository, Database $database, LoggerInterface $logger, Factory\UserGServer $factory) + { + parent::__construct($database, $logger, $factory); + + $this->gserverRepository = $gserverRepository; + } + + /** + * Returns an existing UserGServer entity or create one on the fly + * + * @param int $uid + * @param int $gsid + * @param bool $hydrate Populate the related GServer entity + * @return Entity\UserGServer + */ + public function getOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + { + try { + return $this->selectOneByUserAndServer($uid, $gsid, $hydrate); + } catch (NotFoundException $e) { + return $this->factory->createFromUserAndServer($uid, $gsid, $hydrate ? $this->gserverRepository->selectOneById($gsid) : null); + } + } + + /** + * @param int $uid + * @param int $gsid + * @param bool $hydrate Populate the related GServer entity + * @return Entity\UserGServer + * @throws NotFoundException + */ + public function selectOneByUserAndServer(int $uid, int $gsid, bool $hydrate = true): Entity\UserGServer + { + return $this->_selectOne(['uid' => $uid, 'gsid' => $gsid], [], $hydrate); + } + + public function save(Entity\UserGServer $userGServer): Entity\UserGServer + { + $fields = [ + 'uid' => $userGServer->uid, + 'gsid' => $userGServer->gsid, + 'ignored' => $userGServer->ignored, + ]; + + $this->db->insert(static::$table_name, $fields, Database::INSERT_UPDATE); + + return $userGServer; + } + + public function selectByUserWithPagination(int $uid, Pager $pager): Collection\UserGServers + { + return $this->_select(['uid' => $uid], ['limit' => [$pager->getStart(), $pager->getItemsPerPage()]]); + } + + public function countByUser(int $uid): int + { + return $this->count(['uid' => $uid]); + } + + public function isIgnoredByUser(int $uid, int $gsid): bool + { + return $this->exists(['uid' => $uid, 'gsid' => $gsid, 'ignored' => 1]); + } + + /** + * @param Entity\UserGServer $userGServer + * @return bool + * @throws InternalServerErrorException in case the underlying storage cannot delete the record + */ + public function delete(Entity\UserGServer $userGServer): bool + { + try { + return $this->db->delete(self::$table_name, ['uid' => $userGServer->uid, 'gsid' => $userGServer->gsid]); + } catch (\Exception $exception) { + throw new InternalServerErrorException('Cannot delete the UserGServer', $exception); + } + } + + protected function _selectOne(array $condition, array $params = [], bool $hydrate = true): BaseEntity + { + $fields = $this->db->selectFirst(static::$table_name, [], $condition, $params); + if (!$this->db->isResult($fields)) { + throw new NotFoundException(); + } + + return $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); + } + + /** + * @param array $condition + * @param array $params + * @return Collection\UserGServers + * @throws Exception + */ + protected function _select(array $condition, array $params = [], bool $hydrate = true): BaseCollection + { + $rows = $this->db->selectToArray(static::$table_name, [], $condition, $params); + + $Entities = new Collection\UserGServers(); + foreach ($rows as $fields) { + $Entities[] = $this->factory->createFromTableRow($fields, $hydrate ? $this->gserverRepository->selectOneById($fields['gsid']) : null); + } + + return $Entities; + } + + public function listIgnoredByUser(int $uid): Collection\UserGServers + { + return $this->_select(['uid' => $uid, 'ignored' => 1], [], false); + } +} diff --git a/src/Util/ACLFormatter.php b/src/Util/ACLFormatter.php index 0351b27a6..cd398fc28 100644 --- a/src/Util/ACLFormatter.php +++ b/src/Util/ACLFormatter.php @@ -21,7 +21,7 @@ namespace Friendica\Util; -use Friendica\Model\Group; +use Friendica\Model\Circle; /** * Util class for ACL formatting @@ -29,13 +29,13 @@ use Friendica\Model\Group; final class ACLFormatter { /** - * Turn user/group ACLs stored as angle bracketed text into arrays + * Turn user/circle ACLs stored as angle bracketed text into arrays * * @param string|null $acl_string A angle-bracketed list of IDs * * @return array The array based on the IDs (empty in case there is no list) */ - public function expand(string $acl_string = null) + public function expand(string $acl_string = null): array { // In case there is no ID list, return empty array (=> no ACL set) if (empty($acl_string)) { @@ -44,7 +44,7 @@ final class ACLFormatter // turn string array of angle-bracketed elements into numeric array // e.g. "<1><2><3>" => array(1,2,3); - preg_match_all('/<(' . Group::FOLLOWERS . '|'. Group::MUTUALS . '|[0-9]+)>/', $acl_string, $matches, PREG_PATTERN_ORDER); + preg_match_all('/<(' . Circle::FOLLOWERS . '|'. Circle::MUTUALS . '|[0-9]+)>/', $acl_string, $matches, PREG_PATTERN_ORDER); return $matches[1]; } @@ -55,7 +55,7 @@ final class ACLFormatter * @param string|null $acl_string * @return string */ - public function sanitize(string $acl_string = null) + public function sanitize(string $acl_string = null): string { if (empty($acl_string)) { return ''; @@ -86,7 +86,7 @@ final class ACLFormatter if (intval($item)) { $item = '<' . intval($item) . '>'; // The item is a allowed ACL character - } elseif (in_array($item, [Group::FOLLOWERS, Group::MUTUALS])) { + } elseif (in_array($item, [Circle::FOLLOWERS, Circle::MUTUALS])) { $item = '<' . $item . '>'; // The item is already a ACL string } elseif (preg_match('/<\d+?>/', $item)) { @@ -107,10 +107,13 @@ final class ACLFormatter * * @return string */ - function toString($permissions) { + function toString($permissions): string + { $return = ''; if (is_array($permissions)) { $item = $permissions; + } elseif (empty($permissions)) { + return ''; } else { $item = explode(',', $permissions); } diff --git a/src/Util/EMailer/NotifyMailBuilder.php b/src/Util/EMailer/NotifyMailBuilder.php index b7e9c51d4..4191dbba2 100644 --- a/src/Util/EMailer/NotifyMailBuilder.php +++ b/src/Util/EMailer/NotifyMailBuilder.php @@ -179,7 +179,7 @@ class NotifyMailBuilder extends MailBuilder */ protected function getHtmlMessage() { - $htmlVersion = BBCode::convert($this->body); + $htmlVersion = BBCode::convertForUriId(0, $this->body, BBCode::EXTERNAL); // load the template for private message notifications $tpl = Renderer::getMarkupTemplate('email/notify/html.tpl'); diff --git a/src/Util/EMailer/SystemMailBuilder.php b/src/Util/EMailer/SystemMailBuilder.php index 3c50ba916..68e19ae83 100644 --- a/src/Util/EMailer/SystemMailBuilder.php +++ b/src/Util/EMailer/SystemMailBuilder.php @@ -100,7 +100,7 @@ class SystemMailBuilder extends MailBuilder '$preamble' => str_replace("\n", "
\n", $this->preamble), '$thanks' => $this->l10n->t('thanks'), '$site_admin' => $this->siteAdmin, - '$htmlversion' => BBCode::convert($this->body), + '$htmlversion' => BBCode::convertForUriId(0, $this->body, BBCode::EXTERNAL), ]); } diff --git a/src/Util/Emailer.php b/src/Util/Emailer.php index 5e4d98d4c..1accc574c 100644 --- a/src/Util/Emailer.php +++ b/src/Util/Emailer.php @@ -126,7 +126,7 @@ class Emailer * @return bool * @throws InternalServerErrorException */ - public function send(IEmail $email) + public function send(IEmail $email): bool { Hook::callAll('emailer_send_prepare', $email); @@ -151,7 +151,7 @@ class Emailer } $fromName = Email::encodeHeader(html_entity_decode($email->getFromName(), ENT_QUOTES, 'UTF-8'), 'UTF-8'); - $fromAddress = $email->getFromAddress(); + $fromAddress = $email->getFromAddress(); $replyTo = $email->getReplyTo(); $messageSubject = Email::encodeHeader(html_entity_decode($email->getSubject(), ENT_QUOTES, 'UTF-8'), 'UTF-8'); @@ -161,12 +161,17 @@ class Emailer . rand(100000000, 999999999) . '=:' . rand(10000, 99999); + $messageHeader = $email->getAdditionalMailHeaderString(); + if ($countMessageId === 0) { + $messageHeader .= 'Message-ID: baseUrl->getHost() . '>' . "\r\n"; + } + // generate a multipart/alternative message header - $messageHeader = $email->getAdditionalMailHeaderString() . - "From: $fromName <{$fromAddress}>\r\n" . - "Reply-To: $fromName <{$replyTo}>\r\n" . - "MIME-Version: 1.0\r\n" . - "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\""; + $messageHeader .= + "From: $fromName <{$fromAddress}>\r\n" . + "Reply-To: $fromName <{$replyTo}>\r\n" . + "MIME-Version: 1.0\r\n" . + "Content-Type: multipart/alternative; boundary=\"{$mimeBoundary}\""; // assemble the final multipart message body with the text and html types included $textBody = chunk_split(base64_encode($email->getMessage(true))); diff --git a/src/Util/JsonLD.php b/src/Util/JsonLD.php index 0a4d5a0b5..427205958 100644 --- a/src/Util/JsonLD.php +++ b/src/Util/JsonLD.php @@ -46,6 +46,12 @@ class JsonLD case 'https://w3id.org/security/v1': $url = DI::basePath() . '/static/security-v1.jsonld'; break; + case 'https://w3id.org/security/data-integrity/v1': + $url = DI::basePath() . '/static/security-data-integrity-v1.jsonld'; + break; + case 'https://w3id.org/security/multikey/v1': + $url = DI::basePath() . '/static/security-multikey-v1.jsonld'; + break; case 'https://w3id.org/identity/v1': $url = DI::basePath() . '/static/identity-v1.jsonld'; break; @@ -55,6 +61,12 @@ class JsonLD case 'https://funkwhale.audio/ns': $url = DI::basePath() . '/static/funkwhale.audio.jsonld'; break; + case 'http://schema.org': + $url = DI::basePath() . '/static/schema.jsonld'; + break; + case 'http://joinmastodon.org/ns': + $url = DI::basePath() . '/static/joinmastodon.jsonld'; + break; default: switch (parse_url($url, PHP_URL_PATH)) { case '/schemas/litepub-0.1.jsonld'; @@ -177,12 +189,6 @@ class JsonLD if (!in_array('https://w3id.org/security/v1', $json['@context'])) { $json['@context'][] = 'https://w3id.org/security/v1'; } - - // Issue 12419: Workaround for GoToSocial - $pos = array_search('http://joinmastodon.org/ns', $json['@context']); - if (is_int($pos)) { - $json['@context'][$pos] = ['toot' => 'http://joinmastodon.org/ns#']; - } } // Bookwyrm transmits "id" fields with "null", which isn't allowed. diff --git a/src/Util/Network.php b/src/Util/Network.php index f7ceab543..495510189 100644 --- a/src/Util/Network.php +++ b/src/Util/Network.php @@ -640,10 +640,11 @@ class Network * @param string $url * * @return bool + * @deprecated since 2023.09, please use BaseUrl->isLocalUrl or BaseUrl->isLocalUri instead. */ public static function isLocalLink(string $url): bool { - return (strpos(Strings::normaliseLink($url), Strings::normaliseLink(DI::baseUrl())) !== false); + return DI::baseUrl()->isLocalUrl($url); } /** diff --git a/src/Util/ReversedFileReader.php b/src/Util/ReversedFileReader.php index fdd15bec9..58fb2cb3f 100644 --- a/src/Util/ReversedFileReader.php +++ b/src/Util/ReversedFileReader.php @@ -89,7 +89,7 @@ class ReversedFileReader implements \Iterator * * @return string|null Depending on data being buffered */ - private function _readline() + private function _readline(): ?string { $buffer = & $this->buffer; while (true) { @@ -112,6 +112,7 @@ class ReversedFileReader implements \Iterator * @see Iterator::next() * @return void */ + #[\ReturnTypeWillChange] public function next() { ++$this->key; @@ -124,6 +125,7 @@ class ReversedFileReader implements \Iterator * @see Iterator::rewind() * @return void */ + #[\ReturnTypeWillChange] public function rewind() { if ($this->filesize > 0) { diff --git a/src/Util/Strings.php b/src/Util/Strings.php index 1ce1ac8c7..bc1a0e4be 100644 --- a/src/Util/Strings.php +++ b/src/Util/Strings.php @@ -561,4 +561,22 @@ class Strings return $shorthand; } + /** + * Converts an URL in a nicer format (without the scheme and possibly shortened) + * + * @param string $url URL that is about to be reformatted + * @return string reformatted link + */ + public static function getStyledURL(string $url): string + { + $parts = parse_url($url); + $scheme = [$parts['scheme'] . '://www.', $parts['scheme'] . '://']; + $styled_url = str_replace($scheme, '', $url); + + if (strlen($styled_url) > 30) { + $styled_url = substr($styled_url, 0, 30) . "…"; + } + + return $styled_url; + } } diff --git a/src/Util/XML.php b/src/Util/XML.php index e5fa4009f..c35f19b8a 100644 --- a/src/Util/XML.php +++ b/src/Util/XML.php @@ -118,7 +118,7 @@ class XML $namespace = null; } - $element->addAttribute($attr_key, $attr_value, $namespace); + $element->addAttribute($attr_key, $attr_value ?? '', $namespace); } continue; diff --git a/src/Worker/Cron.php b/src/Worker/Cron.php index 73d158070..607de5c0d 100644 --- a/src/Worker/Cron.php +++ b/src/Worker/Cron.php @@ -21,6 +21,7 @@ namespace Friendica\Worker; +use Friendica\Core\Addon; use Friendica\Core\Hook; use Friendica\Core\Logger; use Friendica\Core\Worker; @@ -103,6 +104,9 @@ class Cron // Clear cache entries Worker::add(Worker::PRIORITY_LOW, 'ClearCache'); + // Update interaction scores + Worker::add(Worker::PRIORITY_LOW, 'UpdateScores'); + DI::keyValue()->set('last_cron_hourly', time()); } @@ -146,6 +150,8 @@ class Cron // Update "blocked" status of servers Worker::add(Worker::PRIORITY_LOW, 'UpdateBlockedServers'); + Addon::reload(); + DI::keyValue()->set('last_cron_daily', time()); } diff --git a/src/Worker/ExpireAndRemoveUsers.php b/src/Worker/ExpireAndRemoveUsers.php index f29934596..c04741462 100644 --- a/src/Worker/ExpireAndRemoveUsers.php +++ b/src/Worker/ExpireAndRemoveUsers.php @@ -36,7 +36,7 @@ class ExpireAndRemoveUsers { public static function execute() { - // expire any expired regular accounts. Don't expire forums. + // expire any expired regular accounts. Don't expire groups. $condition = ["NOT `account_expired` AND `account_expires_on` > ? AND `account_expires_on` < ? AND `page-flags` = ? AND `uid` != ?", DBA::NULL_DATETIME, DateTimeFormat::utcNow(), User::PAGE_FLAGS_NORMAL, 0]; DBA::update('user', ['account_expired' => true], $condition); diff --git a/src/Worker/Notifier.php b/src/Worker/Notifier.php index 7c78896f3..e87a587f5 100644 --- a/src/Worker/Notifier.php +++ b/src/Worker/Notifier.php @@ -29,7 +29,7 @@ use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Contact; use Friendica\Model\Conversation; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Model\GServer; use Friendica\Model\Item; use Friendica\Model\Post; @@ -167,8 +167,8 @@ class Notifier // Do a PuSH $push_notify = false; - // Deliver directly to a forum, don't PuSH - $direct_forum_delivery = false; + // Deliver directly to a group, don't PuSH + $direct_group_delivery = false; $only_ap_delivery = false; @@ -249,15 +249,15 @@ class Notifier $relay_to_owner = false; } - // Special treatment for forum posts - if (Item::isForumPost($target_item['uri-id'])) { + // Special treatment for group posts + if (Item::isGroupPost($target_item['uri-id'])) { $relay_to_owner = true; - $direct_forum_delivery = true; + $direct_group_delivery = true; } - // Avoid that comments in a forum thread are sent to OStatus - if (Item::isForumPost($parent['uri-id'])) { - $direct_forum_delivery = true; + // Avoid that comments in a group thread are sent to OStatus + if (Item::isGroupPost($parent['uri-id'])) { + $direct_group_delivery = true; } $exclusive_delivery = false; @@ -303,7 +303,7 @@ class Notifier } } - if ($direct_forum_delivery) { + if ($direct_group_delivery) { $push_notify = false; } @@ -340,9 +340,9 @@ class Notifier $aclFormatter = DI::aclFormatter(); $allow_people = $aclFormatter->expand($parent['allow_cid']); - $allow_groups = Group::expand($uid, $aclFormatter->expand($parent['allow_gid']),true); + $allow_circles = Circle::expand($uid, $aclFormatter->expand($parent['allow_gid']),true); $deny_people = $aclFormatter->expand($parent['deny_cid']); - $deny_groups = Group::expand($uid, $aclFormatter->expand($parent['deny_gid'])); + $deny_circles = Circle::expand($uid, $aclFormatter->expand($parent['deny_gid'])); foreach ($items as $item) { $recipients[] = $item['contact-id']; @@ -363,8 +363,8 @@ class Notifier Logger::notice('Deliver', ['target' => $target_id, 'guid' => $target_item['guid'], 'recipients' => $url_recipients]); } - $recipients = array_unique(array_merge($recipients, $allow_people, $allow_groups)); - $deny = array_unique(array_merge($deny_people, $deny_groups)); + $recipients = array_unique(array_merge($recipients, $allow_people, $allow_circles)); + $deny = array_unique(array_merge($deny_people, $deny_circles)); $recipients = array_diff($recipients, $deny); // If this is a public message and pubmail is set on the parent, include all your email contacts @@ -793,11 +793,11 @@ class Notifier $uid = $target_item['contact-uid'] ?: $target_item['uid']; - // Update the locally stored follower list when we deliver to a forum + // Update the locally stored follower list when we deliver to a group foreach (Tag::getByURIId($target_item['uri-id'], [Tag::MENTION, Tag::EXCLUSIVE_MENTION]) as $tag) { $target_contact = Contact::getByURL(Strings::normaliseLink($tag['url']), null, [], $uid); if ($target_contact && $target_contact['contact-type'] == Contact::TYPE_COMMUNITY && $target_contact['manually-approve']) { - Group::updateMembersForForum($target_contact['id']); + Circle::updateMembersForGroup($target_contact['id']); } } @@ -822,7 +822,7 @@ class Notifier } Logger::info('Remote item will be distributed', ['id' => $target_item['id'], 'url' => $target_item['uri'], 'verb' => $target_item['verb']]); - $check_signature = ($target_item['gravity'] == Item::GRAVITY_ACTIVITY); + $check_signature = ($target_item['gravity'] == Item::GRAVITY_ACTIVITY); } else { Logger::info('Remote activity will not be distributed', ['id' => $target_item['id'], 'url' => $target_item['uri'], 'verb' => $target_item['verb']]); return ['count' => 0, 'contacts' => []]; diff --git a/src/Worker/PollContacts.php b/src/Worker/PollContacts.php index ba908cb8f..81ce0f8f0 100644 --- a/src/Worker/PollContacts.php +++ b/src/Worker/PollContacts.php @@ -45,10 +45,10 @@ class PollContacts if (!empty($abandon_days)) { $condition = DBA::mergeConditions($condition, - ["`uid` != ? AND `uid` IN (SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed` AND `last-activity` > ?)", 0, DateTimeFormat::utc('now - ' . $abandon_days . ' days')]); + ["`uid` != ? AND `uid` IN (SELECT `uid` FROM `user` WHERE NOT `blocked` AND NOT `account_expired` AND NOT `account_removed` AND `last-activity` > ?)", 0, DateTimeFormat::utc('now - ' . $abandon_days . ' days')]); } else { $condition = DBA::mergeConditions($condition, - ["`uid` != ? AND `uid` IN (SELECT `uid` FROM `user` WHERE NOT `account_expired` AND NOT `account_removed`)", 0]); + ["`uid` != ? AND `uid` IN (SELECT `uid` FROM `user` WHERE NOT `blocked` AND NOT `account_expired` AND NOT `account_removed`)", 0]); } $contacts = DBA::select('contact', ['id', 'nick', 'name', 'network', 'archive', 'last-update', 'priority', 'rating'], $condition); diff --git a/src/Worker/UpdateAllSuggestions.php b/src/Worker/UpdateAllSuggestions.php index 285cfe5bb..329fe25cf 100644 --- a/src/Worker/UpdateAllSuggestions.php +++ b/src/Worker/UpdateAllSuggestions.php @@ -32,7 +32,7 @@ class UpdateAllSuggestions { public static function execute() { - $users = DBA::select('user', ['uid'], ["`last-activity` > ?", DateTimeFormat::utc('now - 3 days', 'Y-m-d')]); + $users = DBA::select('user', ['uid'], ["`last-activity` > ? AND `uid` > ?", DateTimeFormat::utc('now - 3 days', 'Y-m-d'), 0]); while ($user = DBA::fetch($users)) { Contact\Relation::updateCachedSuggestions($user['uid']); } diff --git a/src/Worker/UpdateContact.php b/src/Worker/UpdateContact.php index c2e443282..23eb5ff4b 100644 --- a/src/Worker/UpdateContact.php +++ b/src/Worker/UpdateContact.php @@ -25,7 +25,6 @@ use Friendica\Core\Logger; use Friendica\Core\Worker; use Friendica\Model\Contact; use Friendica\Network\HTTPException\InternalServerErrorException; -use Friendica\Util\Network; class UpdateContact { diff --git a/src/Worker/UpdateScores.php b/src/Worker/UpdateScores.php new file mode 100644 index 000000000..66f776ad7 --- /dev/null +++ b/src/Worker/UpdateScores.php @@ -0,0 +1,46 @@ +. + * + */ + +namespace Friendica\Worker; + +use Friendica\Core\Logger; +use Friendica\Database\DBA; +use Friendica\Model\Contact\Relation; + +/** + * Update the interaction scores + */ +class UpdateScores +{ + public static function execute($param = '', $hook_function = '') + { + Logger::notice('Start score update'); + + $users = DBA::select('user', ['uid'], ["NOT `account_expired` AND NOT `account_removed` AND `uid` > ?", 0]); + while ($user = DBA::fetch($users)) { + Relation::calculateInteractionScore($user['uid']); + } + DBA::close($users); + + Logger::notice('Score update done'); + return; + } +} diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index ffb66d970..7520a1109 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -54,8 +54,9 @@ use Friendica\Database\DBA; +// This file is required several times during the test in DbaDefinition which justifies this condition if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1518); + define('DB_UPDATE_VERSION', 1530); } return [ @@ -158,6 +159,18 @@ return [ "email" => ["email(64)"], ] ], + "user-gserver" => [ + "comment" => "User settings about remote servers", + "fields" => [ + "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], + "gsid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["gserver" => "id"], "comment" => "Gserver id"], + "ignored" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "server accounts are ignored for the user"], + ], + "indexes" => [ + "PRIMARY" => ["uid", "gsid"], + "gsid" => ["gsid"] + ], + ], "item-uri" => [ "comment" => "URI and GUID for items", "fields" => [ @@ -217,8 +230,8 @@ return [ "archive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "unsearchable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact prefers to not be searchable"], "sensitive" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Contact posts sensitive content"], - "baseurl" => ["type" => "varbinary(383)", "default" => "", "comment" => "baseurl of the contact"], - "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID"], + "baseurl" => ["type" => "varbinary(383)", "default" => "", "comment" => "baseurl of the contact from the gserver record, can be missing"], + "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id", "on delete" => "restrict"], "comment" => "Global Server ID, can be missing"], "bd" => ["type" => "date", "not null" => "1", "default" => DBA::NULL_DATE, "comment" => ""], // User depending fields "reason" => ["type" => "text", "comment" => ""], @@ -249,7 +262,7 @@ return [ "confirm" => ["type" => "varbinary(383)", "comment" => ""], "poco" => ["type" => "varbinary(383)", "comment" => ""], "writable" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], - "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a forum. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead"], + "forum" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = false instead"], "prv" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "contact is a private group. Deprecated, use 'contact-type' = 'community' and 'manually-approve' = true instead"], "bdyear" => ["type" => "varchar(4)", "not null" => "1", "default" => "", "comment" => ""], // Deprecated fields that aren't in use anymore @@ -311,9 +324,9 @@ return [ "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner id of this permission set"], "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"], - "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], + "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed circles"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], - "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], + "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied circles"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -513,9 +526,9 @@ return [ "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "creation time"], "edited" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "last edit time"], "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>"], - "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], + "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed circles"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], - "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], + "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied circles"], "backend-class" => ["type" => "tinytext", "comment" => "Storage backend class"], "backend-ref" => ["type" => "text", "comment" => "Storage backend data reference"], ], @@ -558,6 +571,10 @@ return [ "last-interaction" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last interaction"], "follow-updated" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => "Date of the last update of the contact relationship"], "follows" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], + "score" => ["type" => "smallint unsigned", "comment" => "score for interactions of cid on relation-cid"], + "relation-score" => ["type" => "smallint unsigned", "comment" => "score for interactions of relation-cid on cid"], + "thread-score" => ["type" => "smallint unsigned", "comment" => "score for interactions of cid on threads of relation-cid"], + "relation-thread-score" => ["type" => "smallint unsigned", "comment" => "score for interactions of relation-cid on threads of cid"], ], "indexes" => [ "PRIMARY" => ["cid", "relation-cid"], @@ -715,9 +732,9 @@ return [ "nofinish" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "if event does have no end this is 1"], "ignore" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "0 or 1"], "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"], - "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], + "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed circles"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], - "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], + "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied circles"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -760,14 +777,14 @@ return [ ] ], "group" => [ - "comment" => "privacy groups, group info", + "comment" => "privacy circles, circle info", "fields" => [ "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], "uid" => ["type" => "mediumint unsigned", "not null" => "1", "default" => "0", "foreign" => ["user" => "uid"], "comment" => "Owner User id"], "visible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the member list is not private"], - "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the group has been deleted"], - "cid" => ["type" => "int unsigned", "foreign" => ["contact" => "id"], "comment" => "Contact id of forum. When this field is filled then the members are synced automatically."], - "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "human readable name of group"], + "deleted" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "1 indicates the circle has been deleted"], + "cid" => ["type" => "int unsigned", "foreign" => ["contact" => "id"], "comment" => "Contact id of group. When this field is filled then the members are synced automatically."], + "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "human readable name of circle"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -776,11 +793,11 @@ return [ ] ], "group_member" => [ - "comment" => "privacy groups, member info", + "comment" => "privacy circles, member info", "fields" => [ "id" => ["type" => "int unsigned", "not null" => "1", "extra" => "auto_increment", "primary" => "1", "comment" => "sequential ID"], - "gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["group" => "id"], "comment" => "groups.id of the associated group"], - "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => "contact.id of the member assigned to the associated group"], + "gid" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["group" => "id"], "comment" => "group.id of the associated circle"], + "contact-id" => ["type" => "int unsigned", "not null" => "1", "default" => "0", "foreign" => ["contact" => "id"], "comment" => "contact.id of the member assigned to the associated circle"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -1150,9 +1167,9 @@ return [ "scale" => ["type" => "tinyint unsigned", "not null" => "1", "default" => "0", "comment" => ""], "profile" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => ""], "allow_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed contact.id '<19><78>'"], - "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed groups"], + "allow_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of allowed circles"], "deny_cid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied contact.id"], - "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied groups"], + "deny_gid" => ["type" => "mediumtext", "comment" => "Access Control - list of denied circles"], "accessible" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Make photo publicly accessible, ignoring permissions"], "backend-class" => ["type" => "tinytext", "comment" => "Storage backend class"], "backend-ref" => ["type" => "text", "comment" => "Storage backend data reference"], @@ -1582,7 +1599,7 @@ return [ "profile-name" => ["type" => "varchar(255)", "comment" => "Deprecated"], "is-default" => ["type" => "boolean", "comment" => "Deprecated"], "hide-friends" => ["type" => "boolean", "not null" => "1", "default" => "0", "comment" => "Hide friend list from viewers of this profile"], - "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], + "name" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => "Unused in favor of user.username"], "pdesc" => ["type" => "varchar(255)", "comment" => "Deprecated"], "dob" => ["type" => "varchar(32)", "not null" => "1", "default" => "0000-00-00", "comment" => "Day of birth"], "address" => ["type" => "varchar(255)", "not null" => "1", "default" => "", "comment" => ""], @@ -1690,22 +1707,34 @@ return [ "uid" => ["type" => "mediumint unsigned", "foreign" => ["user" => "uid"], "comment" => "Reporting user"], "reporter-id" => ["type" => "int unsigned", "foreign" => ["contact" => "id"], "comment" => "Reporting contact"], "cid" => ["type" => "int unsigned", "not null" => "1", "foreign" => ["contact" => "id"], "comment" => "Reported contact"], + "gsid" => ["type" => "int unsigned", "foreign" => ["gserver" => "id"], "comment" => "Reported contact server"], "comment" => ["type" => "text", "comment" => "Report"], - "category" => ["type" => "varchar(20)", "comment" => "Category of the report (spam, violation, other)"], - "rules" => ["type" => "text", "comment" => "Violated rules"], + "category-id" => ["type" => "int unsigned", "not null" => 1, "default" => \Friendica\Moderation\Entity\Report::CATEGORY_OTHER, "comment" => "Report category, one of Entity\Report::CATEGORY_*"], "forward" => ["type" => "boolean", "comment" => "Forward the report to the remote server"], - "created" => ["type" => "datetime", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], - "status" => ["type" => "tinyint unsigned", "comment" => "Status of the report"], + "public-remarks" => ["type" => "text", "comment" => "Remarks shared with the reporter"], + "private-remarks" => ["type" => "text", "comment" => "Remarks shared with the moderation team"], + "last-editor-uid" => ["type" => "mediumint unsigned", "foreign" => ["user" => "uid"], "comment" => "Last editor user"], + "assigned-uid" => ["type" => "mediumint unsigned", "foreign" => ["user" => "uid"], "comment" => "Assigned moderator user"], + "status" => ["type" => "tinyint unsigned", "not null" => "1", "comment" => "Status of the report, one of Entity\Report::STATUS_*"], + "resolution" => ["type" => "tinyint unsigned", "comment" => "Resolution of the report, one of Entity\Report::RESOLUTION_*"], + "created" => ["type" => "datetime(6)", "not null" => "1", "default" => DBA::NULL_DATETIME, "comment" => ""], + "edited" => ["type" => "datetime(6)", "comment" => "Last time the report has been edited"], ], "indexes" => [ "PRIMARY" => ["id"], "uid" => ["uid"], "cid" => ["cid"], "reporter-id" => ["reporter-id"], + "gsid" => ["gsid"], + "last-editor-uid" => ["last-editor-uid"], + "assigned-uid" => ["assigned-uid"], + "status-resolution" => ["status", "resolution"], + "created" => ["created"], + "edited" => ["edited"], ] ], "report-post" => [ - "comment" => "", + "comment" => "Individual posts attached to a moderation report", "fields" => [ "rid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["report" => "id"], "comment" => "Report id"], "uri-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["item-uri" => "id"], "comment" => "Uri-id of the reported post"], @@ -1716,6 +1745,17 @@ return [ "uri-id" => ["uri-id"], ] ], + "report-rule" => [ + "comment" => "Terms of service rule lines relevant to a moderation report", + "fields" => [ + "rid" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "foreign" => ["report" => "id"], "comment" => "Report id"], + "line-id" => ["type" => "int unsigned", "not null" => "1", "primary" => "1", "comment" => "Terms of service rule line number, may become invalid after a TOS change."], + "text" => ["type" => "text", "not null" => "1", "comment" => "Terms of service rule text recorded at the time of the report"], + ], + "indexes" => [ + "PRIMARY" => ["rid", "line-id"], + ] + ], "search" => [ "comment" => "", "fields" => [ @@ -1802,8 +1842,8 @@ return [ "rel" => ["type" => "tinyint unsigned", "comment" => "The kind of the relation between the user and the contact"], "info" => ["type" => "mediumtext", "comment" => ""], "notify_new_posts" => ["type" => "boolean", "comment" => ""], - "remote_self" => ["type" => "boolean", "comment" => ""], - "fetch_further_information" => ["type" => "tinyint unsigned", "comment" => ""], + "remote_self" => ["type" => "tinyint unsigned", "comment" => "0 => No mirroring, 1-2 => Mirror as own post, 3 => Mirror as reshare"], + "fetch_further_information" => ["type" => "tinyint unsigned", "comment" => "0 => None, 1 => Fetch information, 3 => Fetch keywords, 2 => Fetch both"], "ffi_keyword_denylist" => ["type" => "text", "comment" => ""], "subhub" => ["type" => "boolean", "comment" => ""], "hub-verify" => ["type" => "varbinary(383)", "comment" => ""], diff --git a/static/dbview.config.php b/static/dbview.config.php index 76278c9a2..d688cef3f 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -58,12 +58,41 @@ "query" => "FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`" ], + "circle-member-view" => [ + "fields" => [ + "id" => ["group_member", "id"], + "uid" => ["group", "uid"], + "contact-id" => ["group_member", "contact-id"], + "contact-uri-id" => ["contact", "uri-id"], + "contact-link" => ["contact", "url"], + "contact-addr" => ["contact", "addr"], + "contact-name" => ["contact", "name"], + "contact-nick" => ["contact", "nick"], + "contact-avatar" => ["contact", "thumb"], + "contact-network" => ["contact", "network"], + "contact-blocked" => ["contact", "blocked"], + "contact-hidden" => ["contact", "hidden"], + "contact-readonly" => ["contact", "readonly"], + "contact-archive" => ["contact", "archive"], + "contact-pending" => ["contact", "pending"], + "contact-self" => ["contact", "self"], + "contact-rel" => ["contact", "rel"], + "contact-contact-type" => ["contact", "contact-type"], + "circle-id" => ["group_member", "gid"], + "circle-visible" => ["group", "visible"], + "circle-deleted" => ["group", "deleted"], + "circle-name" => ["group", "name"], + ], + "query" => "FROM `group_member` + INNER JOIN `contact` ON `group_member`.`contact-id` = `contact`.`id` + INNER JOIN `group` ON `group_member`.`gid` = `group`.`id`" + ], "post-user-view" => [ "fields" => [ "id" => ["post-user", "id"], "post-user-id" => ["post-user", "id"], "uid" => ["post-user", "uid"], - "parent" => ["parent-post", "id"], + "parent" => ["post-thread-user", "post-user-id"], "uri" => ["item-uri", "uri"], "uri-id" => ["post-user", "uri-id"], "parent-uri" => ["parent-item-uri", "uri"], @@ -149,23 +178,27 @@ "author-addr" => ["author", "addr"], "author-name" => "IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`)", "author-nick" => ["author", "nick"], + "author-alias" => ["author", "alias"], "author-avatar" => "IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`)", "author-network" => ["author", "network"], "author-blocked" => ["author", "blocked"], "author-hidden" => ["author", "hidden"], "author-updated" => ["author", "updated"], "author-gsid" => ["author", "gsid"], + "author-baseurl" => ["author", "baseurl"], "owner-id" => ["post-user", "owner-id"], "owner-uri-id" => ["owner", "uri-id"], "owner-link" => ["owner", "url"], "owner-addr" => ["owner", "addr"], "owner-name" => "IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`)", "owner-nick" => ["owner", "nick"], + "owner-alias" => ["owner", "alias"], "owner-avatar" => "IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`)", "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-user", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -173,10 +206,12 @@ "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], "causer-nick" => ["causer", "nick"], + "causer-alias" => ["causer", "alias"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "postopts" => ["post-delivery-data", "postopts"], "inform" => ["post-delivery-data", "inform"], @@ -206,15 +241,15 @@ "has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-user`.`uri-id`)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], - "parent-network" => ["parent-post", "network"], - "parent-author-id" => ["parent-post", "author-id"], + "parent-network" => ["post-thread-user", "network"], + "parent-author-id" => ["post-thread-user", "author-id"], "parent-author-link" => ["parent-post-author", "url"], "parent-author-name" => ["parent-post-author", "name"], "parent-author-nick" => ["parent-post-author", "nick"], "parent-author-network" => ["parent-post-author", "network"], ], "query" => "FROM `post-user` - STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-user`.`contact-id` STRAIGHT_JOIN `contact` AS `author` ON `author`.`id` = `post-user`.`author-id` STRAIGHT_JOIN `contact` AS `owner` ON `owner`.`id` = `post-user`.`owner-id` @@ -232,15 +267,14 @@ LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-user`.`uri-id` AND `post-user`.`origin` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-user`.`uri-id` LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-user`.`psid` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`" + LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `post-thread-user`.`author-id`" ], "post-thread-user-view" => [ "fields" => [ "id" => ["post-user", "id"], "post-user-id" => ["post-user", "id"], "uid" => ["post-thread-user", "uid"], - "parent" => ["parent-post", "id"], + "parent" => ["post-thread-user", "post-user-id"], "uri" => ["item-uri", "uri"], "uri-id" => ["post-thread-user", "uri-id"], "parent-uri" => ["parent-item-uri", "uri"], @@ -309,6 +343,7 @@ "contact-pending" => ["contact", "pending"], "contact-rel" => ["contact", "rel"], "contact-uid" => ["contact", "uid"], + "contact-gsid" => ["contact", "gsid"], "contact-contact-type" => ["contact", "contact-type"], "writable" => "IF (`post-user`.`network` IN ('apub', 'dfrn', 'dspr', 'stat'), true, `contact`.`writable`)", "self" => ["contact", "self"], @@ -325,6 +360,7 @@ "author-addr" => ["author", "addr"], "author-name" => "IF (`contact`.`url` = `author`.`url` AND `contact`.`name` != '', `contact`.`name`, `author`.`name`)", "author-nick" => ["author", "nick"], + "author-alias" => ["author", "alias"], "author-avatar" => "IF (`contact`.`url` = `author`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `author`.`thumb`)", "author-network" => ["author", "network"], "author-blocked" => ["author", "blocked"], @@ -337,11 +373,13 @@ "owner-addr" => ["owner", "addr"], "owner-name" => "IF (`contact`.`url` = `owner`.`url` AND `contact`.`name` != '', `contact`.`name`, `owner`.`name`)", "owner-nick" => ["owner", "nick"], + "owner-alias" => ["owner", "alias"], "owner-avatar" => "IF (`contact`.`url` = `owner`.`url` AND `contact`.`thumb` != '', `contact`.`thumb`, `owner`.`thumb`)", "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-thread-user", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -349,10 +387,12 @@ "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], "causer-nick" => ["causer", "nick"], + "causer-alias" => ["causer", "alias"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "postopts" => ["post-delivery-data", "postopts"], "inform" => ["post-delivery-data", "inform"], @@ -382,11 +422,12 @@ "has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post-thread-user`.`uri-id`)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], - "parent-network" => ["parent-post", "network"], - "parent-author-id" => ["parent-post", "author-id"], - "parent-author-link" => ["parent-post-author", "url"], - "parent-author-name" => ["parent-post-author", "name"], - "parent-author-network" => ["parent-post-author", "network"], + "parent-network" => ["post-thread-user", "network"], + "parent-author-id" => ["post-thread-user", "author-id"], + "parent-author-link" => ["author", "url"], + "parent-author-name" => ["author", "name"], + "parent-author-nick" => ["author", "nick"], + "parent-author-network" => ["author", "network"], ], "query" => "FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` @@ -406,9 +447,7 @@ LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` LEFT JOIN `post-delivery-data` ON `post-delivery-data`.`uri-id` = `post-thread-user`.`uri-id` AND `post-thread-user`.`origin` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread-user`.`uri-id` - LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-thread-user`.`uid` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`" + LEFT JOIN `permissionset` ON `permissionset`.`id` = `post-thread-user`.`psid`" ], "post-view" => [ "fields" => [ @@ -487,6 +526,7 @@ "author-addr" => ["author", "addr"], "author-name" => ["author", "name"], "author-nick" => ["author", "nick"], + "author-alias" => ["author", "alias"], "author-avatar" => ["author", "thumb"], "author-network" => ["author", "network"], "author-blocked" => ["author", "blocked"], @@ -499,23 +539,27 @@ "owner-addr" => ["owner", "addr"], "owner-name" => ["owner", "name"], "owner-nick" => ["owner", "nick"], + "owner-alias" => ["owner", "alias"], "owner-avatar" => ["owner", "thumb"], "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], "owner-contact-type" => ["owner", "contact-type"], + "owner-gsid" => ["owner", "gsid"], "causer-id" => ["post", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], "causer-link" => ["causer", "url"], "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], "causer-nick" => ["causer", "nick"], + "causer-alias" => ["causer", "alias"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], "causer-contact-type" => ["causer", "contact-type"], + "causer-gsid" => ["causer", "gsid"], "question-id" => ["post-question", "id"], "question-multiple" => ["post-question", "multiple"], "question-voters" => ["post-question", "voters"], @@ -524,10 +568,11 @@ "has-media" => "EXISTS(SELECT `id` FROM `post-media` WHERE `post-media`.`uri-id` = `post`.`uri-id`)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], - "parent-network" => ["parent-post", "network"], - "parent-author-id" => ["parent-post", "author-id"], + "parent-network" => ["post-thread", "network"], + "parent-author-id" => ["post-thread", "author-id"], "parent-author-link" => ["parent-post-author", "url"], "parent-author-name" => ["parent-post-author", "name"], + "parent-author-nick" => ["parent-post-author", "nick"], "parent-author-network" => ["parent-post-author", "network"], ], "query" => "FROM `post` @@ -545,8 +590,7 @@ LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post`.`uri-id` LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post`.`uri-id` - LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`" + LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `post-thread`.`author-id`" ], "post-thread-view" => [ "fields" => [ @@ -625,6 +669,7 @@ "author-addr" => ["author", "addr"], "author-name" => ["author", "name"], "author-nick" => ["author", "nick"], + "author-alias" => ["author", "alias"], "author-avatar" => ["author", "thumb"], "author-network" => ["author", "network"], "author-blocked" => ["author", "blocked"], @@ -637,11 +682,13 @@ "owner-addr" => ["owner", "addr"], "owner-name" => ["owner", "name"], "owner-nick" => ["owner", "nick"], + "owner-alias" => ["owner", "alias"], "owner-avatar" => ["owner", "thumb"], "owner-network" => ["owner", "network"], "owner-blocked" => ["owner", "blocked"], "owner-hidden" => ["owner", "hidden"], "owner-updated" => ["owner", "updated"], + "owner-gsid" => ["owner", "gsid"], "owner-contact-type" => ["owner", "contact-type"], "causer-id" => ["post-thread", "causer-id"], "causer-uri-id" => ["causer", "uri-id"], @@ -649,10 +696,12 @@ "causer-addr" => ["causer", "addr"], "causer-name" => ["causer", "name"], "causer-nick" => ["causer", "nick"], + "causer-alias" => ["causer", "alias"], "causer-avatar" => ["causer", "thumb"], "causer-network" => ["causer", "network"], "causer-blocked" => ["causer", "blocked"], "causer-hidden" => ["causer", "hidden"], + "causer-gsid" => ["causer", "gsid"], "causer-contact-type" => ["causer", "contact-type"], "question-id" => ["post-question", "id"], "question-multiple" => ["post-question", "multiple"], @@ -664,11 +713,12 @@ "total-actors" => "(SELECT COUNT(DISTINCT(`author-id`)) FROM `post` WHERE `parent-uri-id` = `post-thread`.`uri-id` AND `gravity` = 6)", "signed_text" => ["diaspora-interaction", "interaction"], "parent-guid" => ["parent-item-uri", "guid"], - "parent-network" => ["parent-post", "network"], - "parent-author-id" => ["parent-post", "author-id"], - "parent-author-link" => ["parent-post-author", "url"], - "parent-author-name" => ["parent-post-author", "name"], - "parent-author-network" => ["parent-post-author", "network"], + "parent-network" => ["post-thread", "network"], + "parent-author-id" => ["post-thread", "author-id"], + "parent-author-link" => ["author", "url"], + "parent-author-name" => ["author", "name"], + "parent-author-nick" => ["author", "nick"], + "parent-author-network" => ["author", "network"], ], "query" => "FROM `post-thread` INNER JOIN `post` ON `post`.`uri-id` = `post-thread`.`uri-id` @@ -684,9 +734,7 @@ LEFT JOIN `diaspora-interaction` ON `diaspora-interaction`.`uri-id` = `post-thread`.`uri-id` LEFT JOIN `post-content` ON `post-content`.`uri-id` = `post-thread`.`uri-id` LEFT JOIN `item-uri` AS `quote-item-uri` ON `quote-item-uri`.`id` = `post-content`.`quote-uri-id` - LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id` - LEFT JOIN `post` AS `parent-post` ON `parent-post`.`uri-id` = `post`.`parent-uri-id` - LEFT JOIN `contact` AS `parent-post-author` ON `parent-post-author`.`id` = `parent-post`.`author-id`" + LEFT JOIN `post-question` ON `post-question`.`uri-id` = `post-thread`.`uri-id`" ], "category-view" => [ "fields" => [ @@ -752,7 +800,7 @@ "network-item-view" => [ "fields" => [ "uri-id" => ["post-user", "uri-id"], - "parent" => ["parent-post", "id"], + "parent" => ["post-thread-user", "post-user-id"], "received" => ["post-user", "received"], "commented" => ["post-thread-user", "commented"], "created" => ["post-user", "created"], @@ -766,22 +814,21 @@ "contact-type" => ["ownercontact", "contact-type"], ], "query" => "FROM `post-user` - STRAIGHT_JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` - INNER JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` - INNER JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` + INNER JOIN `post-thread-user` ON `post-thread-user`.`uri-id` = `post-user`.`parent-uri-id` AND `post-thread-user`.`uid` = `post-user`.`uid` + STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` + STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-user`.`hidden` IS NULL OR NOT `post-user`.`hidden`) - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`)" + AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)" ], "network-thread-view" => [ "fields" => [ "uri-id" => ["post-thread-user", "uri-id"], - "parent" => ["parent-post", "id"], + "parent" => ["post-thread-user", "post-user-id"], "received" => ["post-thread-user", "received"], "commented" => ["post-thread-user", "commented"], "created" => ["post-thread-user", "created"], @@ -795,15 +842,14 @@ "query" => "FROM `post-thread-user` INNER JOIN `post-user` ON `post-user`.`id` = `post-thread-user`.`post-user-id` STRAIGHT_JOIN `contact` ON `contact`.`id` = `post-thread-user`.`contact-id` - LEFT JOIN `user-contact` AS `author` ON `author`.`uid` = `post-thread-user`.`uid` AND `author`.`cid` = `post-thread-user`.`author-id` - LEFT JOIN `user-contact` AS `owner` ON `owner`.`uid` = `post-thread-user`.`uid` AND `owner`.`cid` = `post-thread-user`.`owner-id` - LEFT JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` - LEFT JOIN `post-user` AS `parent-post` ON `parent-post`.`uri-id` = `post-user`.`parent-uri-id` AND `parent-post`.`uid` = `post-user`.`uid` + STRAIGHT_JOIN `contact` AS `authorcontact` ON `authorcontact`.`id` = `post-thread-user`.`author-id` + STRAIGHT_JOIN `contact` AS `ownercontact` ON `ownercontact`.`id` = `post-thread-user`.`owner-id` WHERE `post-user`.`visible` AND NOT `post-user`.`deleted` AND (NOT `contact`.`readonly` AND NOT `contact`.`blocked` AND NOT `contact`.`pending`) AND (`post-thread-user`.`hidden` IS NULL OR NOT `post-thread-user`.`hidden`) - AND (`author`.`blocked` IS NULL OR NOT `author`.`blocked`) - AND (`owner`.`blocked` IS NULL OR NOT `owner`.`blocked`)" + AND NOT `authorcontact`.`blocked` AND NOT `ownercontact`.`blocked` + AND NOT EXISTS(SELECT `cid` FROM `user-contact` WHERE `uid` = `post-thread-user`.`uid` AND `cid` IN (`authorcontact`.`id`, `ownercontact`.`id`) AND (`blocked` OR `ignored`)) + AND NOT EXISTS(SELECT `gsid` FROM `user-gserver` WHERE `uid` = `post-thread-user`.`uid` AND `gsid` IN (`authorcontact`.`gsid`, `ownercontact`.`gsid`) AND `ignored`)" ], "owner-view" => [ "fields" => [ diff --git a/static/defaults.config.php b/static/defaults.config.php index d0b8262ac..b13f3fd24 100644 --- a/static/defaults.config.php +++ b/static/defaults.config.php @@ -310,10 +310,10 @@ return [ // Number of "free" searches when system => permit_crawling is enabled. 'free_crawls' => 10, - // groupedit_image_limit (Integer) - // Number of contacts at which the group editor should switch from display the profile pictures of the contacts to only display the names. + // circle_edit_image_limit (Integer) + // Number of contacts at which the circle editor should switch from display the profile pictures of the contacts to only display the names. // This can alternatively be set on a per-account basis in the pconfig table. - 'groupedit_image_limit' => 400, + 'circle_edit_image_limit' => 400, // gserver_update_limit (Integer) // How many servers should be checked at a time? @@ -349,6 +349,10 @@ return [ // This has to be quite large to deal with embedded private photos. False to use the system value. 'ini_pcre_backtrack_limit' => 500000, + // interaction_score_days (Integer) + // Number of days that are used to calculate the interaction score. + 'interaction_score_days' => 30, + // invitation_only (Boolean) // If set true registration is only possible after a current member of the node has sent an invitation. 'invitation_only' => false, @@ -543,11 +547,11 @@ return [ 'pushpoll_frequency' => 3, // redis_host (String) - // Host name of the redis daemon. + // Host name or the path to the Unix domain socket of the Redis daemon. 'redis_host' => '127.0.0.1', - // redis_port (String) - // Port number of the redis daemon. + // redis_port (Integer) + // Port number of the Redis daemon, should be -1 for unix domain socket 'redis_port' => 6379, // redis_db (Integer) @@ -633,7 +637,7 @@ return [ 'throttle_limit_month' => 0, // transmit_pending_events (Boolean) - // Transmit pending events upon accepted contact request for forums + // Transmit pending events upon accepted contact request for groups 'transmit_pending_events' => false, // update_active_contacts (Boolean) @@ -781,4 +785,19 @@ return [ // By default the template cache is stored in several subdirectories. 'use_sub_dirs' => true, ], + 'api' => [ + // mastodon_banner (String) + // Default banner image for Mastodon API, must be a relative path from the base Friendica folder + // + // Default picture credits: + // Author: Lostinlight + // License: CC0 https://creativecommons.org/share-your-work/public-domain/cc0/ + // Link to original work: https://gitlab.com/lostinlight/per_aspera_ad_astra/-/blob/master/friendica-404/friendica-promo-bubbles.jpg + 'mastodon_banner' => '/images/friendica-banner.jpg', + ], + 'blocklist' => [ + // public (Boolean) + // Wether the blocklist is publicly listed under /about (or in any later API) + 'public' => true, + ], ]; diff --git a/static/dependencies.config.php b/static/dependencies.config.php index 089116642..3dfde6b5f 100644 --- a/static/dependencies.config.php +++ b/static/dependencies.config.php @@ -37,8 +37,9 @@ use Dice\Dice; use Friendica\App; use Friendica\Core\Cache; use Friendica\Core\Config; -use Friendica\Core\Hooks\Capabilities\ICanManageInstances; -use Friendica\Core\Hooks\Model\InstanceManager; +use Friendica\Core\Hooks\Capability\ICanCreateInstances; +use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; +use Friendica\Core\Hooks\Model\DiceInstanceManager; use Friendica\Core\PConfig; use Friendica\Core\L10n; use Friendica\Core\Lock; @@ -62,6 +63,13 @@ return [ // one instance for the whole execution 'shared' => true, ], + \Friendica\Core\Addon\Capability\ICanLoadAddons::class => [ + 'instanceOf' => \Friendica\Core\Addon\Model\AddonLoader::class, + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + [Dice::INSTANCE => Dice::SELF], + ], + ], '$basepath' => [ 'instanceOf' => Util\BasePath::class, 'call' => [ @@ -78,8 +86,27 @@ return [ $_SERVER ] ], - ICanManageInstances::class => [ - 'instanceOf' => InstanceManager::class, + DiceInstanceManager::class => [ + 'constructParams' => [ + [Dice::INSTANCE => Dice::SELF], + ] + ], + \Friendica\Core\Hooks\Util\StrategiesFileManager::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$basepath'], + ], + 'call' => [ + ['loadConfig'], + ], + ], + ICanRegisterStrategies::class => [ + 'instanceOf' => DiceInstanceManager::class, + 'constructParams' => [ + [Dice::INSTANCE => Dice::SELF], + ], + ], + ICanCreateInstances::class => [ + 'instanceOf' => DiceInstanceManager::class, 'constructParams' => [ [Dice::INSTANCE => Dice::SELF], ], @@ -151,45 +178,53 @@ return [ $_SERVER, ], ], + '$hostname' => [ + 'instanceOf' => App\BaseURL::class, + 'constructParams' => [ + $_SERVER, + ], + 'call' => [ + ['getHost', [], Dice::CHAIN_CALL], + ], + ], + Cache\Type\AbstractCache::class => [ + 'constructParams' => [ + [Dice::INSTANCE => '$hostname'], + ], + ], App\Page::class => [ 'constructParams' => [ [Dice::INSTANCE => '$basepath'], ], ], - /** - * Create a Logger, which implements the LoggerInterface - * - * Same as: - * $loggerFactory = new Factory\LoggerFactory(); - * $logger = $loggerFactory->create($channel, $configuration, $profiler); - * - * Attention1: We can use DICE for detecting dependencies inside "chained" calls too - * Attention2: The variable "$channel" is passed inside the creation of the dependencies per: - * $app = $dice->create(App::class, [], ['$channel' => 'index']); - * and is automatically passed as an argument with the same name - */ - LoggerInterface::class => [ + \Psr\Log\LoggerInterface::class => [ 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class, - 'constructParams' => [ - 'index', - ], 'call' => [ ['create', [], Dice::CHAIN_CALL], ], ], - '$devLogger' => [ - 'instanceOf' => \Friendica\Core\Logger\Factory\Logger::class, - 'constructParams' => [ - 'dev', + \Friendica\Core\Logger\Type\SyslogLogger::class => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\SyslogLogger::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], ], + ], + \Friendica\Core\Logger\Type\StreamLogger::class => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\StreamLogger::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], + ], + ], + \Friendica\Core\Logger\Capability\IHaveCallIntrospections::class => [ + 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, + 'constructParams' => [ + \Friendica\Core\Logger\Capability\IHaveCallIntrospections::IGNORE_CLASS_LIST, + ], + ], + '$devLogger' => [ + 'instanceOf' => \Friendica\Core\Logger\Factory\StreamLogger::class, 'call' => [ ['createDev', [], Dice::CHAIN_CALL], - ] - ], - \Friendica\Core\Logger\Capabilities\IHaveCallIntrospections::class => [ - 'instanceOf' => \Friendica\Core\Logger\Util\Introspection::class, - 'constructParams' => [ - \Friendica\Core\Logger\Util\Introspection::IGNORE_CLASS_LIST, ], ], Cache\Capability\ICanCache::class => [ @@ -255,8 +290,11 @@ return [ ['getBackend', [], Dice::CHAIN_CALL], ], ], - \Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs::class => [ - 'instanceOf' => \Friendica\Core\KeyValueStorage\Type\DBKeyValueStorage::class, + \Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs::class => [ + 'instanceOf' => \Friendica\Core\KeyValueStorage\Factory\KeyValueStorage::class, + 'call' => [ + ['create', [], Dice::CHAIN_CALL], + ], ], Network\HTTPClient\Capability\ICanSendHttpRequests::class => [ 'instanceOf' => Network\HTTPClient\Factory\HttpClient::class, diff --git a/static/joinmastodon.jsonld b/static/joinmastodon.jsonld new file mode 100644 index 000000000..0edd4ab0c --- /dev/null +++ b/static/joinmastodon.jsonld @@ -0,0 +1,44 @@ +{ + "@context":[ + "https://www.w3.org/ns/activitystreams", + "https://w3id.org/security/v1", + { + "manuallyApprovesFollowers":"as:manuallyApprovesFollowers", + "toot":"http://joinmastodon.org/ns#", + "featured":{"@id":"toot:featured","@type":"@id"}, + "featuredTags":{"@id":"toot:featuredTags","@type":"@id"}, + "alsoKnownAs":{"@id":"as:alsoKnownAs","@type":"@id"}, + "movedTo":{"@id":"as:movedTo","@type":"@id"}, + "schema":"http://schema.org#", + "PropertyValue":"schema:PropertyValue", + "value":"schema:value", + "discoverable":"toot:discoverable", + "Device":"toot:Device", + "Ed25519Signature":"toot:Ed25519Signature", + "Ed25519Key":"toot:Ed25519Key", + "Curve25519Key":"toot:Curve25519Key", + "EncryptedMessage":"toot:EncryptedMessage", + "publicKeyBase64":"toot:publicKeyBase64", + "deviceId":"toot:deviceId", + "claim":{"@type":"@id","@id":"toot:claim"}, + "fingerprintKey":{"@type":"@id","@id":"toot:fingerprintKey"}, + "identityKey":{"@type":"@id","@id":"toot:identityKey"}, + "devices":{"@type":"@id","@id":"toot:devices"}, + "messageFranking":"toot:messageFranking", + "messageType":"toot:messageType", + "cipherText":"toot:cipherText", + "suspended":"toot:suspended", + "focalPoint":{"@container":"@list","@id":"toot:focalPoint"}, + "ostatus":"http://ostatus.org#", + "atomUri":"ostatus:atomUri", + "inReplyToAtomUri":"ostatus:inReplyToAtomUri", + "conversation":"ostatus:conversation", + "sensitive":"as:sensitive", + "votersCount":"toot:votersCount", + "Hashtag":"as:Hashtag", + "quoteUrl":"as:quoteUrl", + "Emoji":"toot:Emoji", + "vcard":"http://www.w3.org/2006/vcard/ns#" + } + ] +} \ No newline at end of file diff --git a/static/routes.config.php b/static/routes.config.php index 0ff13224c..36ba2f249 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -89,12 +89,20 @@ $apiRoutes = [ '/direct_messages_setseen[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\DirectMessages\Setseen::class, [ R::POST]], '/direct_messages_search[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\DirectMessages\Search ::class, [R::GET ]], '/events[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Events\Index::class, [R::GET ]], - '/event_create[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Events\Create::class, [ R::POST]], - '/event_delete[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Events\Delete::class, [ R::POST]], - '/group_show[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Group\Show::class, [R::GET ]], - '/group_create[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Group\Create::class, [ R::POST]], - '/group_delete[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Group\Delete::class, [ R::POST]], - '/group_update[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Group\Update::class, [ R::POST]], + '/event_create[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Events\Create::class, [ R::POST]], + '/event_delete[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Events\Delete::class, [ R::POST]], + '/circle_show[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Show::class, [R::GET ]], + '/circle_create[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Create::class, [ R::POST]], + '/circle_delete[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Delete::class, [ R::POST]], + '/circle_update[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Update::class, [ R::POST]], + + // Backward compatibility + // @deprecated + '/group_show[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Show::class, [R::GET ]], + '/group_create[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Create::class, [ R::POST]], + '/group_delete[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Delete::class, [ R::POST]], + '/group_update[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Circle\Update::class, [ R::POST]], + '/profile/show[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Profile\Show::class, [R::GET ]], '/photoalbums[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Photoalbum\Index::class, [R::GET ]], '/photoalbum[.{extension:json|xml|rss|atom}]' => [Module\Api\Friendica\Photoalbum\Show::class, [R::GET ]], @@ -441,19 +449,19 @@ return [ '/follow_confirm' => [Module\FollowConfirm::class, [R::GET, R::POST]], '/followers/{nickname}' => [Module\ActivityPub\Followers::class, [R::GET]], '/following/{nickname}' => [Module\ActivityPub\Following::class, [R::GET]], - '/friendica[/json]' => [Module\Friendica::class, [R::GET]], + '/friendica[/{format:json}]' => [Module\Friendica::class, [R::GET]], '/friendica/inbox' => [Module\ActivityPub\Inbox::class, [R::GET, R::POST]], '/fsuggest/{contact:\d+}' => [Module\FriendSuggest::class, [R::GET, R::POST]], - '/group' => [ - '[/]' => [Module\Group::class, [R::GET, R::POST]], - '/{group:\d+}' => [Module\Group::class, [R::GET, R::POST]], - '/none' => [Module\Group::class, [R::GET, R::POST]], - '/new' => [Module\Group::class, [R::GET, R::POST]], - '/drop/{group:\d+}' => [Module\Group::class, [R::GET, R::POST]], - '/{group:\d+}/{contact:\d+}' => [Module\Group::class, [R::GET, R::POST]], - '/{group:\d+}/{command:add|remove}/{contact:\d+}' => [Module\Group::class, [R::GET, R::POST]], + '/circle' => [ + '[/]' => [Module\Circle::class, [R::GET, R::POST]], + '/{circle:\d+}' => [Module\Circle::class, [R::GET, R::POST]], + '/none' => [Module\Circle::class, [R::GET, R::POST]], + '/new' => [Module\Circle::class, [R::GET, R::POST]], + '/drop/{circle:\d+}' => [Module\Circle::class, [R::GET, R::POST]], + '/{circle:\d+}/{contact:\d+}' => [Module\Circle::class, [R::GET, R::POST]], + '/{circle:\d+}/{command:add|remove}/{contact:\d+}' => [Module\Circle::class, [R::GET, R::POST]], ], '/hashtag' => [Module\Hashtag::class, [R::GET]], '/help[/{doc:.+}]' => [Module\Help::class, [R::GET]], @@ -500,6 +508,8 @@ return [ '/item/delete' => [Module\Moderation\Item\Delete::class, [R::GET, R::POST]], '/item/source[/{guid}]' => [Module\Moderation\Item\Source::class, [R::GET, R::POST]], + '/report/create' => [Module\Moderation\Report\Create::class, [R::GET, R::POST]], + '/users[/{action}/{uid}]' => [Module\Moderation\Users\Index::class, [R::GET, R::POST]], '/users/active[/{action}/{uid}]' => [Module\Moderation\Users\Active::class, [R::GET, R::POST]], '/users/pending[/{action}/{uid}]' => [Module\Moderation\Users\Pending::class, [R::GET, R::POST]], @@ -511,7 +521,7 @@ return [ '/newmember' => [Module\Welcome::class, [R::GET]], '/nodeinfo/1.0' => [Module\NodeInfo110::class, [R::GET]], '/nodeinfo/2.0' => [Module\NodeInfo120::class, [R::GET]], - '/nogroup' => [Module\Group::class, [R::GET]], + '/nocircle' => [Module\Circle::class, [R::GET]], '/noscrape' => [ '/{nick}' => [Module\NoScrape::class, [R::GET]], @@ -629,6 +639,10 @@ return [ ], '/settings' => [ + '/server' => [ + '[/]' => [Module\Settings\Server\Index::class, [R::GET, R::POST]], + '/{gsid:\d+}/{action}' => [Module\Settings\Server\Action::class, [R::GET, R::POST]], + ], '[/]' => [Module\Settings\Account::class, [R::GET, R::POST]], '/account' => [ '[/]' => [Module\Settings\Account::class, [R::GET, R::POST]], @@ -659,8 +673,8 @@ return [ '/network' => [ '[/]' => [Module\Conversation\Network::class, [R::GET]], '/archive/{from:\d\d\d\d-\d\d-\d\d}[/{to:\d\d\d\d-\d\d-\d\d}]' => [Module\Conversation\Network::class, [R::GET]], - '/forum/{contact_id:\d+}' => [Module\Conversation\Network::class, [R::GET]], - '/group/{group_id:\d+}' => [Module\Conversation\Network::class, [R::GET]], + '/group/{contact_id:\d+}' => [Module\Conversation\Network::class, [R::GET]], + '/circle/{circle_id:\d+}' => [Module\Conversation\Network::class, [R::GET]], ], '/randprof' => [Module\RandomProfile::class, [R::GET]], @@ -679,8 +693,8 @@ return [ '/update_network' => [ '[/]' => [Module\Update\Network::class, [R::GET]], '/archive/{from:\d\d\d\d-\d\d-\d\d}[/{to:\d\d\d\d-\d\d-\d\d}]' => [Module\Update\Network::class, [R::GET]], - '/forum/{contact_id:\d+}' => [Module\Update\Network::class, [R::GET]], - '/group/{group_id:\d+}' => [Module\Update\Network::class, [R::GET]], + '/group/{contact_id:\d+}' => [Module\Update\Network::class, [R::GET]], + '/circle/{circle_id:\d+}' => [Module\Update\Network::class, [R::GET]], ], '/update_profile' => [Module\Update\Profile::class, [R::GET]], diff --git a/static/schema.jsonld b/static/schema.jsonld new file mode 100644 index 000000000..594013742 --- /dev/null +++ b/static/schema.jsonld @@ -0,0 +1,7 @@ +{ + "@context": { + "schema": "http://schema.org#", + "value": "schema:value", + "PropertyValue": "schema:PropertyValue" + } +} \ No newline at end of file diff --git a/static/security-data-integrity-v1.jsonld b/static/security-data-integrity-v1.jsonld new file mode 100644 index 000000000..24c054e39 --- /dev/null +++ b/static/security-data-integrity-v1.jsonld @@ -0,0 +1,72 @@ +{ + "@context": { + "id": "@id", + "type": "@type", + "proof": { + "@id": "https://w3id.org/security#proof", + "@type": "@id" + }, + "DataIntegrityProof": { + "@id": "https://w3id.org/security#DataIntegrityProof", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "challenge": "https://w3id.org/security#challenge", + "created": { + "@id": "http://purl.org/dc/terms/created", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "domain": "https://w3id.org/security#domain", + "expires": { + "@id": "https://w3id.org/security#expiration", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "nonce": "https://w3id.org/security#nonce", + "proofPurpose": { + "@id": "https://w3id.org/security#proofPurpose", + "@type": "@vocab", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "assertionMethod": { + "@id": "https://w3id.org/security#assertionMethod", + "@type": "@id", + "@container": "@set" + }, + "authentication": { + "@id": "https://w3id.org/security#authenticationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityInvocation": { + "@id": "https://w3id.org/security#capabilityInvocationMethod", + "@type": "@id", + "@container": "@set" + }, + "capabilityDelegation": { + "@id": "https://w3id.org/security#capabilityDelegationMethod", + "@type": "@id", + "@container": "@set" + }, + "keyAgreement": { + "@id": "https://w3id.org/security#keyAgreementMethod", + "@type": "@id", + "@container": "@set" + } + } + }, + "cryptosuite": "https://w3id.org/security#cryptosuite", + "proofValue": { + "@id": "https://w3id.org/security#proofValue", + "@type": "https://w3id.org/security#multibase" + }, + "verificationMethod": { + "@id": "https://w3id.org/security#verificationMethod", + "@type": "@id" + } + } + } + } +} \ No newline at end of file diff --git a/static/security-multikey-v1.jsonld b/static/security-multikey-v1.jsonld new file mode 100644 index 000000000..21f74601c --- /dev/null +++ b/static/security-multikey-v1.jsonld @@ -0,0 +1,30 @@ +{ + "@context": { + "id": "@id", + "type": "@type", + "Multikey": { + "@id": "https://w3id.org/security#Multikey", + "@context": { + "@protected": true, + "id": "@id", + "type": "@type", + "controller": { + "@id": "https://w3id.org/security#controller", + "@type": "@id" + }, + "revoked": { + "@id": "https://w3id.org/security#revoked", + "@type": "http://www.w3.org/2001/XMLSchema#dateTime" + }, + "publicKeyMultibase": { + "@id": "https://w3id.org/security#publicKeyMultibase", + "@type": "https://w3id.org/security#multibase" + }, + "secretKeyMultibase": { + "@id": "https://w3id.org/security#secretKeyMultibase", + "@type": "https://w3id.org/security#multibase" + } + } + } + } +} \ No newline at end of file diff --git a/static/settings.config.php b/static/settings.config.php index e17fa0442..335b70256 100644 --- a/static/settings.config.php +++ b/static/settings.config.php @@ -114,9 +114,9 @@ return [ // Default value comprises classic role names from RFC 2142. 'forbidden_nicknames' => 'info, marketing, sales, support, abuse, noc, security, postmaster, hostmaster, usenet, news, webmaster, www, uucp, ftp, root, sysop', - // compute_group_counts (Boolean) - // Compute contact group level when counting unseen network posts. - 'compute_group_counts' => true, + // compute_circle_counts (Boolean) + // Compute contact circle level when counting unseen network posts. + 'compute_circle_counts' => true, // jpeg_quality (Integer) // Sets the ImageMagick quality level for JPEG images. Values ranges from 50 (awful) to 100 (near perfect). @@ -164,6 +164,10 @@ return [ // Allow pseudonyms (true) or enforce a space between first name and last name in Full name, as an anti spam measure (false). 'no_regfullname' => true, + // no_oembed_rich_content (Boolean) + // If enabled, allow OEmbed for all URLs. Disabled by default. + 'no_oembed_rich_content' => true, + // optimize_tables (Boolean) // Periodically (once an hour) run an "optimize table" command for cache tables 'optimize_tables' => false, diff --git a/static/strategies.config.php b/static/strategies.config.php new file mode 100644 index 000000000..18872dc1d --- /dev/null +++ b/static/strategies.config.php @@ -0,0 +1,49 @@ +. + * + */ + +use Friendica\Core\Cache; +use Friendica\Core\Hooks\Util\StrategiesFileManager; +use Friendica\Core\Logger\Type; +use Friendica\Core\KeyValueStorage; +use Friendica\Core\PConfig; +use Psr\Log; + +return [ + Log\LoggerInterface::class => [ + Log\NullLogger::class => [StrategiesFileManager::STRATEGY_DEFAULT_KEY], + Type\SyslogLogger::class => [Type\SyslogLogger::NAME], + Type\StreamLogger::class => [Type\StreamLogger::NAME], + ], + Cache\Capability\ICanCache::class => [ + Cache\Type\DatabaseCache::class => [Cache\Type\DatabaseCache::NAME, StrategiesFileManager::STRATEGY_DEFAULT_KEY], + Cache\Type\APCuCache::class => [Cache\Type\APCuCache::NAME], + Cache\Type\MemcacheCache::class => [Cache\Type\MemcacheCache::NAME], + Cache\Type\MemcachedCache::class => [Cache\Type\MemcachedCache::NAME], + Cache\Type\RedisCache::class => [Cache\Type\RedisCache::NAME], + ], + KeyValueStorage\Capability\IManageKeyValuePairs::class => [ + KeyValueStorage\Type\DBKeyValueStorage::class => [KeyValueStorage\Type\DBKeyValueStorage::NAME, StrategiesFileManager::STRATEGY_DEFAULT_KEY], + ], + PConfig\Capability\IManagePersonalConfigValues::class => [ + PConfig\Type\JitPConfig::class => [PConfig\Type\JitPConfig::NAME], + PConfig\Type\PreloadPConfig::class => [PConfig\Type\PreloadPConfig::NAME, StrategiesFileManager::STRATEGY_DEFAULT_KEY], + ], +]; diff --git a/tests/Util/Database/StaticDatabase.php b/tests/Util/Database/StaticDatabase.php index be2ec99f0..3ae497e9a 100644 --- a/tests/Util/Database/StaticDatabase.php +++ b/tests/Util/Database/StaticDatabase.php @@ -60,7 +60,6 @@ class StaticDatabase extends Database $this->driver = 'pdo'; $this->connection = self::$staticConnection; $this->connected = true; - $this->emulate_prepares = false; return $this->connected; } diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstance.php b/tests/Util/Hooks/InstanceMocks/FakeInstance.php index ff99002f7..64fe2c5ad 100644 --- a/tests/Util/Hooks/InstanceMocks/FakeInstance.php +++ b/tests/Util/Hooks/InstanceMocks/FakeInstance.php @@ -21,9 +21,7 @@ namespace Friendica\Test\Util\Hooks\InstanceMocks; -use Friendica\Core\Hooks\Capabilities\IAmAStrategy; - -class FakeInstance implements IAmADecoratedInterface, IAmAStrategy +class FakeInstance implements IAmADecoratedInterface { protected $aText = null; protected $cBool = null; @@ -41,6 +39,8 @@ class FakeInstance implements IAmADecoratedInterface, IAmAStrategy $this->aText = $aText; $this->cBool = $cBool; $this->bText = $bText; + + return ''; } public function getAText(): ?string diff --git a/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php b/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php index af4db96c4..40ab78a25 100644 --- a/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php +++ b/tests/Util/Hooks/InstanceMocks/FakeInstanceDecorator.php @@ -25,14 +25,14 @@ class FakeInstanceDecorator implements IAmADecoratedInterface { public static $countInstance = 0; + const PREFIX = 'prefix1'; + /** @var IAmADecoratedInterface */ protected $orig; - protected $prefix = ''; - public function __construct(IAmADecoratedInterface $orig, string $prefix = '') + public function __construct(IAmADecoratedInterface $orig) { $this->orig = $orig; - $this->prefix = $prefix; self::$countInstance++; } @@ -44,16 +44,16 @@ class FakeInstanceDecorator implements IAmADecoratedInterface public function getAText(): ?string { - return $this->prefix . $this->orig->getAText(); + return static::PREFIX . $this->orig->getAText(); } public function getBText(): ?string { - return $this->prefix . $this->orig->getBText(); + return static::PREFIX . $this->orig->getBText(); } public function getCBool(): ?bool { - return $this->prefix . $this->orig->getCBool(); + return static::PREFIX . $this->orig->getCBool(); } } diff --git a/tests/Util/Intercept.php b/tests/Util/Intercept.php index 27b558fc5..483d274fc 100644 --- a/tests/Util/Intercept.php +++ b/tests/Util/Intercept.php @@ -37,7 +37,7 @@ class Intercept extends php_user_filter public static $cache = ''; /** @noinspection PhpMissingParentCallCommonInspection */ - public function filter($in, $out, &$consumed, $closing) + public function filter($in, $out, &$consumed, $closing): int { while ($bucket = stream_bucket_make_writeable($in)) { self::$cache .= $bucket->data; diff --git a/tests/functional/DependencyCheckTest.php b/tests/functional/DependencyCheckTest.php index 89b8f79a5..4488fe586 100644 --- a/tests/functional/DependencyCheckTest.php +++ b/tests/functional/DependencyCheckTest.php @@ -145,7 +145,7 @@ class DependencyCheckTest extends FixtureTest $config->set('system', 'dlogfile', $this->root->url() . '/friendica.log'); /** @var LoggerInterface $logger */ - $logger = $this->dice->create('$devLogger', [['$channel' => 'dev']]); + $logger = $this->dice->create('$devLogger', ['dev']); self::assertInstanceOf(LoggerInterface::class, $logger); } diff --git a/tests/phpunit-addons.xml b/tests/phpunit-addons.xml new file mode 100644 index 000000000..3793249ab --- /dev/null +++ b/tests/phpunit-addons.xml @@ -0,0 +1,24 @@ + + + + ../addon/*/tests/ + + + + + ../addon/ + + + ../addon/*/tests/ + ../addon/*/view/ + ../addon/*/vendor/ + + + diff --git a/tests/src/App/BaseURLTest.php b/tests/src/App/BaseURLTest.php index e45b30b20..fb79fd4d3 100644 --- a/tests/src/App/BaseURLTest.php +++ b/tests/src/App/BaseURLTest.php @@ -178,7 +178,7 @@ class BaseURLTest extends MockedTest public function testRedirectException() { self::expectException(InternalServerErrorException::class); - self::expectErrorMessage('https://friendica.other is not a relative path, please use System::externalRedirect'); + self::expectExceptionMessage('https://friendica.other is not a relative path, please use System::externalRedirect'); $config = new ReadOnlyFileConfig(new Cache([ 'system' => [ diff --git a/tests/src/Content/Text/BBCodeTest.php b/tests/src/Content/Text/BBCodeTest.php index 889b12caa..fc8fd4bff 100644 --- a/tests/src/Content/Text/BBCodeTest.php +++ b/tests/src/Content/Text/BBCodeTest.php @@ -28,6 +28,9 @@ use Friendica\Test\FixtureTest; class BBCodeTest extends FixtureTest { + /** @var \HTMLPurifier */ + public $HTMLPurifier; + protected function setUp(): void { parent::setUp(); diff --git a/tests/src/Core/Addon/Model/AddonLoaderTest.php b/tests/src/Core/Addon/Model/AddonLoaderTest.php new file mode 100644 index 000000000..f49333b32 --- /dev/null +++ b/tests/src/Core/Addon/Model/AddonLoaderTest.php @@ -0,0 +1,212 @@ +. + * + */ + +namespace Friendica\Test\src\Core\Addon\Model; + +use Friendica\Core\Addon\Exception\AddonInvalidConfigFileException; +use Friendica\Core\Addon\Model\AddonLoader; +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Test\MockedTest; +use Friendica\Test\Util\VFSTrait; +use org\bovigo\vfs\vfsStream; + +class AddonLoaderTest extends MockedTest +{ + use VFSTrait; + + protected $structure = [ + 'addon' => [ + 'testaddon1' => [ + 'static' => [], + ], + 'testaddon2' => [ + 'static' => [], + ], + 'testaddon3' => [], + ] + ]; + + protected $addons = [ + 'testaddon1', + 'testaddon2', + 'testaddon3', + ]; + + protected $content = << [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ], +]; +EOF; + + protected function setUp(): void + { + parent::setUp(); + + $this->setUpVfsDir(); + } + + public function dataHooks(): array + { + return [ + 'normal' => [ + 'structure' => $this->structure, + 'enabled' => $this->addons, + 'files' => [ + 'addon/testaddon1/static/hooks.config.php' => $this->content, + ], + 'assertion' => [ + \Friendica\Core\Hooks\Capability\BehavioralHookType::STRATEGY => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ], + ], + ], + 'double' => [ + 'structure' => $this->structure, + 'enabled' => $this->addons, + 'files' => [ + 'addon/testaddon1/static/hooks.config.php' => $this->content, + 'addon/testaddon2/static/hooks.config.php' => $this->content, + ], + 'assertion' => [ + \Friendica\Core\Hooks\Capability\BehavioralHookType::STRATEGY => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => ['', ''], + ], + ], + ], + ], + 'wrongName' => [ + 'structure' => $this->structure, + 'enabled' => $this->addons, + 'files' => [ + 'addon/testaddon1/static/wrong.config.php' => $this->content, + ], + 'assertion' => [ + ], + ], + 'doubleNutOnlyOneEnabled' => [ + 'structure' => $this->structure, + 'enabled' => ['testaddon1'], + 'files' => [ + 'addon/testaddon1/static/hooks.config.php' => $this->content, + 'addon/testaddon2/static/hooks.config.php' => $this->content, + ], + 'assertion' => [ + \Friendica\Core\Hooks\Capability\BehavioralHookType::STRATEGY => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ], + ], + ] + ]; + } + + /** + * @dataProvider dataHooks + */ + public function testAddonLoader(array $structure, array $enabledAddons, array $files, array $assertion) + { + vfsStream::create($structure)->at($this->root); + + foreach ($files as $file => $content) { + vfsStream::newFile($file) + ->withContent($content) + ->at($this->root); + } + + $configArray = []; + foreach ($enabledAddons as $enabledAddon) { + $configArray[$enabledAddon] = ['test' => []]; + } + + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get')->with('addons')->andReturn($configArray)->once(); + + $addonLoader = new AddonLoader($this->root->url(), $config); + + self::assertEquals($assertion, $addonLoader->getActiveAddonConfig('hooks')); + } + + /** + * Test the exception in case of a wrong addon content + */ + public function testWrongContent() + { + $filename = 'addon/testaddon1/static/hooks.config.php'; + $wrongContent = "structure)->at($this->root); + + vfsStream::newFile($filename) + ->withContent($wrongContent) + ->at($this->root); + + $configArray = []; + foreach ($this->addons as $enabledAddon) { + $configArray[$enabledAddon] = ['test' => []]; + } + + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get')->with('addons')->andReturn($configArray)->once(); + + $addonLoader = new AddonLoader($this->root->url(), $config); + + self::expectException(AddonInvalidConfigFileException::class); + self::expectExceptionMessage(sprintf('Error loading config file %s', $this->root->getChild($filename)->url())); + + $addonLoader->getActiveAddonConfig('hooks'); + } + + /** + * Test that nothing happens in case there are wrong addons files, but they're not used + */ + public function testNoHooksConfig() + { + $filename = 'addon/testaddon1/static/hooks.config.php'; + $wrongContent = "structure)->at($this->root); + + vfsStream::newFile($filename) + ->withContent($wrongContent) + ->at($this->root); + + $configArray = []; + foreach ($this->addons as $enabledAddon) { + $configArray[$enabledAddon] = ['test' => []]; + } + + $config = \Mockery::mock(IManageConfigValues::class); + $config->shouldReceive('get')->with('addons')->andReturn($configArray)->once(); + + $addonLoader = new AddonLoader($this->root->url(), $config); + self::assertEmpty($addonLoader->getActiveAddonConfig('anythingElse')); + } +} diff --git a/tests/src/Core/Cache/CacheTest.php b/tests/src/Core/Cache/CacheTest.php index 615a1095d..775a29374 100644 --- a/tests/src/Core/Cache/CacheTest.php +++ b/tests/src/Core/Cache/CacheTest.php @@ -23,6 +23,7 @@ namespace Friendica\Test\src\Core\Cache; use Friendica\Core\Cache\Capability\ICanCache; use Friendica\Core\Cache\Capability\ICanCacheInMemory; +use Friendica\Core\Cache\Type\AbstractCache; use Friendica\Test\MockedTest; use Friendica\Util\PidFile; @@ -246,4 +247,13 @@ abstract class CacheTest extends MockedTest self::assertTrue($this->instance->set('key space', 'value')); self::assertEquals('value', $this->instance->get('key space')); } + + public function testGetName() + { + if (defined(get_class($this->instance) . '::NAME')) { + self::assertEquals($this->instance::NAME, $this->instance->getName()); + } else { + self::expectNotToPerformAssertions(); + } + } } diff --git a/tests/src/Core/Cache/DatabaseCacheTest.php b/tests/src/Core/Cache/DatabaseCacheTest.php index 98afa9e24..63cc7e445 100644 --- a/tests/src/Core/Cache/DatabaseCacheTest.php +++ b/tests/src/Core/Cache/DatabaseCacheTest.php @@ -21,6 +21,7 @@ namespace Friendica\Test\src\Core\Cache; +use Friendica\App\BaseURL; use Friendica\Core\Cache; use Friendica\Test\DatabaseTestTrait; use Friendica\Test\Util\CreateDatabaseTrait; diff --git a/tests/src/Core/Hooks/Model/InstanceManagerTest.php b/tests/src/Core/Hooks/Model/InstanceManagerTest.php index 4e4c0135c..7c5bea802 100644 --- a/tests/src/Core/Hooks/Model/InstanceManagerTest.php +++ b/tests/src/Core/Hooks/Model/InstanceManagerTest.php @@ -22,25 +22,27 @@ namespace Friendica\Test\src\Core\Hooks\Model; use Dice\Dice; -use Friendica\Core\Hooks\Model\InstanceManager; +use Friendica\Core\Hooks\Exceptions\HookInstanceException; +use Friendica\Core\Hooks\Exceptions\HookRegisterArgumentException; +use Friendica\Core\Hooks\Model\DiceInstanceManager; +use Friendica\Core\Hooks\Util\StrategiesFileManager; use Friendica\Test\MockedTest; use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstance; use Friendica\Test\Util\Hooks\InstanceMocks\FakeInstanceDecorator; use Friendica\Test\Util\Hooks\InstanceMocks\IAmADecoratedInterface; +use Mockery\MockInterface; class InstanceManagerTest extends MockedTest { - public function testEqualButNotSameInstance() + /** @var StrategiesFileManager|MockInterface */ + protected $hookFileManager; + + protected function setUp(): void { - $instance = new InstanceManager(new Dice()); + parent::setUp(); - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class); - - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); - - self::assertEquals($getInstanceA, $getInstanceB); - self::assertNotSame($getInstanceA, $getInstanceB); + $this->hookFileManager = \Mockery::mock(StrategiesFileManager::class); + $this->hookFileManager->shouldReceive('setupStrategies')->withAnyArgs(); } protected function tearDown(): void @@ -50,6 +52,19 @@ class InstanceManagerTest extends MockedTest parent::tearDown(); } + public function testEqualButNotSameInstance() + { + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); + + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); + + $getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake'); + $getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake'); + + self::assertEquals($getInstanceA, $getInstanceB); + self::assertNotSame($getInstanceA, $getInstanceB); + } + public function dataTests(): array { return [ @@ -79,9 +94,9 @@ class InstanceManagerTest extends MockedTest /** * @dataProvider dataTests */ - public function testInstanceWithConstructorAnonymArgs(string $aString = null, bool $cBool = null, string $bString = null) + public function testInstanceWithArgs(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); $args = []; @@ -95,45 +110,12 @@ class InstanceManagerTest extends MockedTest $args[] = $cBool; } - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); + $getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake'); - - self::assertEquals($getInstanceA, $getInstanceB); - self::assertNotSame($getInstanceA, $getInstanceB); - self::assertEquals($aString, $getInstanceA->getAText()); - self::assertEquals($aString, $getInstanceB->getAText()); - self::assertEquals($bString, $getInstanceA->getBText()); - self::assertEquals($bString, $getInstanceB->getBText()); - self::assertEquals($cBool, $getInstanceA->getCBool()); - self::assertEquals($cBool, $getInstanceB->getCBool()); - } - - /** - * @dataProvider dataTests - */ - public function testInstanceConstructorAndGetInstanceWithNamedArgs(string $aString = null, bool $cBool = null, string $bString = null) - { - $instance = new InstanceManager(new Dice()); - - $args = []; - - if (isset($aString)) { - $args[] = $aString; - } - if (isset($cBool)) { - $args[] = $cBool; - } - - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); - - /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); - /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake', $args); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -150,24 +132,27 @@ class InstanceManagerTest extends MockedTest */ public function testInstanceWithTwoStrategies(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); $args = []; if (isset($aString)) { $args[] = $aString; } + if (isset($bString)) { + $args[] = $bString; + } if (isset($cBool)) { $args[] = $cBool; } - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake23'); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + $getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake23', $args); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); @@ -180,79 +165,94 @@ class InstanceManagerTest extends MockedTest } /** - * @dataProvider dataTests + * Test the exception in case the interface was already registered */ - public function testDecorator(string $aString = null, bool $cBool = null, string $bString = null) + public function testDoubleRegister() { - $instance = new InstanceManager(new Dice()); + self::expectException(HookRegisterArgumentException::class); + self::expectExceptionMessage(sprintf('A class with the name %s is already set for the interface %s', 'fake', IAmADecoratedInterface::class)); - $args = []; - - if (isset($aString)) { - $args[] = $aString; - } - if (isset($cBool)) { - $args[] = $cBool; - } - - $prefix = 'prefix1'; - - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); - $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); - - /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); - /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); - - self::assertEquals(2, FakeInstanceDecorator::$countInstance); - self::assertEquals($getInstanceA, $getInstanceB); - self::assertNotSame($getInstanceA, $getInstanceB); - self::assertEquals($prefix . $aString, $getInstanceA->getAText()); - self::assertEquals($prefix . $aString, $getInstanceB->getAText()); - self::assertEquals($prefix . $bString, $getInstanceA->getBText()); - self::assertEquals($prefix . $bString, $getInstanceB->getBText()); - self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); - self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); } /** + * Test the exception in case the name of the instance isn't registered + */ + public function testWrongInstanceName() + { + self::expectException(HookInstanceException::class ); + self::expectExceptionMessage(sprintf('The class with the name %s isn\'t registered for the class or interface %s', 'fake', IAmADecoratedInterface::class)); + + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); + $instance->create(IAmADecoratedInterface::class, 'fake'); + } + + /** + * Test in case there are already some rules + * * @dataProvider dataTests */ - public function testTwoDecoratorWithPrefix(string $aString = null, bool $cBool = null, string $bString = null) + public function testWithGivenRules(string $aString = null, bool $cBool = null, string $bString = null) { - $instance = new InstanceManager(new Dice()); - $args = []; if (isset($aString)) { $args[] = $aString; } + if (isset($bString)) { + $args[] = $bString; + } + + $dice = (new Dice())->addRules([ + FakeInstance::class => [ + 'constructParams' => $args, + ], + ]); + + $args = []; + if (isset($cBool)) { $args[] = $cBool; } - $prefix = 'prefix1'; + $instance = new DiceInstanceManager($dice, $this->hookFileManager); - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake', FakeInstance::class, $args); - $instance->registerStrategy(IAmADecoratedInterface::class, 'fake23', FakeInstance::class, $args); - $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class, [$prefix]); - $instance->registerDecorator(IAmADecoratedInterface::class, FakeInstanceDecorator::class); + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); /** @var IAmADecoratedInterface $getInstanceA */ - $getInstanceA = $instance->getInstance(IAmADecoratedInterface::class, 'fake', [$bString]); + $getInstanceA = $instance->create(IAmADecoratedInterface::class, 'fake', $args); /** @var IAmADecoratedInterface $getInstanceB */ - $getInstanceB = $instance->getInstance(IAmADecoratedInterface::class, 'fake23', [$bString]); + $getInstanceB = $instance->create(IAmADecoratedInterface::class, 'fake', $args); - self::assertEquals(4, FakeInstanceDecorator::$countInstance); self::assertEquals($getInstanceA, $getInstanceB); self::assertNotSame($getInstanceA, $getInstanceB); - self::assertEquals($prefix . $aString, $getInstanceA->getAText()); - self::assertEquals($prefix . $aString, $getInstanceB->getAText()); - self::assertEquals($prefix . $bString, $getInstanceA->getBText()); - self::assertEquals($prefix . $bString, $getInstanceB->getBText()); - self::assertEquals($prefix . $cBool, $getInstanceA->getCBool()); - self::assertEquals($prefix . $cBool, $getInstanceB->getCBool()); + self::assertEquals($aString, $getInstanceA->getAText()); + self::assertEquals($aString, $getInstanceB->getAText()); + self::assertEquals($bString, $getInstanceA->getBText()); + self::assertEquals($bString, $getInstanceB->getBText()); + self::assertEquals($cBool, $getInstanceA->getCBool()); + self::assertEquals($cBool, $getInstanceB->getCBool()); } + + /** + * @see https://github.com/friendica/friendica/issues/13318 + */ + public function testCaseInsensitiveNames() + { + $instance = new DiceInstanceManager(new Dice(), $this->hookFileManager); + + $instance->registerStrategy(IAmADecoratedInterface::class, FakeInstance::class, 'fake'); + + // CamelCase + self::assertInstanceOf(FakeInstance::class, $instance->create(IAmADecoratedInterface::class, 'Fake')); + // UPPER CASE + self::assertInstanceOf(FakeInstance::class, $instance->create(IAmADecoratedInterface::class, 'FAKE')); + // lower case + self::assertInstanceOf(FakeInstance::class, $instance->create(IAmADecoratedInterface::class, 'fake')); + // UnKnOwN + self::assertInstanceOf(FakeInstance::class, $instance->create(IAmADecoratedInterface::class, 'fAkE')); + } + } diff --git a/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php new file mode 100644 index 000000000..ebb213fa7 --- /dev/null +++ b/tests/src/Core/Hooks/Util/StrategiesFileManagerTest.php @@ -0,0 +1,202 @@ +. + * + */ + +namespace Friendica\Test\src\Core\Hooks\Util; + +use Friendica\Core\Addon\Capability\ICanLoadAddons; +use Friendica\Core\Hooks\Capability\ICanRegisterStrategies; +use Friendica\Core\Hooks\Exceptions\HookConfigException; +use Friendica\Core\Hooks\Util\StrategiesFileManager; +use Friendica\Test\MockedTest; +use Friendica\Test\Util\VFSTrait; +use org\bovigo\vfs\vfsStream; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +class StrategiesFileManagerTest extends MockedTest +{ + use VFSTrait; + + protected function setUp(): void + { + parent::setUp(); + + $this->setUpVfsDir(); + } + + public function dataHooks(): array + { + return [ + 'normal' => [ + 'content' => << [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [], + 'assertStrategies' => [ + [LoggerInterface::class, NullLogger::class, ''], + ], + ], + 'normalWithString' => [ + 'content' => << [ + \Psr\Log\NullLogger::class => '', + ], +]; +EOF, + 'addonsArray' => [], + 'assertStrategies' => [ + [LoggerInterface::class, NullLogger::class, ''], + ], + ], + 'withAddons' => [ + 'content' => << [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => ['null'], + ], + ], + 'assertStrategies' => [ + [LoggerInterface::class, NullLogger::class, ''], + [LoggerInterface::class, NullLogger::class, 'null'], + ], + ], + 'withAddonsWithString' => [ + 'content' => << [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => 'null', + ], + ], + 'assertStrategies' => [ + [LoggerInterface::class, NullLogger::class, ''], + [LoggerInterface::class, NullLogger::class, 'null'], + ], + ], + // This should work because unique name convention is part of the instance manager logic, not of the file-infrastructure layer + 'withAddonsDoubleNamed' => [ + 'content' => << [ + \Psr\Log\NullLogger::class => [''], + ], +]; +EOF, + 'addonsArray' => [ + \Psr\Log\LoggerInterface::class => [ + \Psr\Log\NullLogger::class => [''], + ], + ], + 'assertStrategies' => [ + [LoggerInterface::class, NullLogger::class, ''], + [LoggerInterface::class, NullLogger::class, ''], + ], + ], + ]; + } + + /** + * @dataProvider dataHooks + */ + public function testSetupHooks(string $content, array $addonsArray, array $assertStrategies) + { + vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') + ->withContent($content) + ->at($this->root); + + $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $addonLoader->shouldReceive('getActiveAddonConfig')->andReturn($addonsArray)->once(); + + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + + $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); + foreach ($assertStrategies as $assertStrategy) { + $instanceManager->shouldReceive('registerStrategy')->withArgs($assertStrategy)->once(); + } + + $hookFileManager->loadConfig(); + $hookFileManager->setupStrategies($instanceManager); + + self::expectNotToPerformAssertions(); + } + + /** + * Test the exception in case the strategies.config.php file is missing + */ + public function testMissingStrategiesFile() + { + $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + + self::expectException(HookConfigException::class); + self::expectExceptionMessage(sprintf('config file %s does not exist.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); + + $hookFileManager->loadConfig(); + } + + /** + * Test the exception in case the strategies.config.php file is wrong + */ + public function testWrongStrategiesFile() + { + $addonLoader = \Mockery::mock(ICanLoadAddons::class); + $instanceManager = \Mockery::mock(ICanRegisterStrategies::class); + $hookFileManager = new StrategiesFileManager($this->root->url(), $addonLoader); + + vfsStream::newFile(StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php') + ->withContent("at($this->root); + + self::expectException(HookConfigException::class); + self::expectExceptionMessage(sprintf('Error loading config file %s.', + $this->root->url() . '/' . StrategiesFileManager::STATIC_DIR . '/' . StrategiesFileManager::CONFIG_NAME . '.config.php')); + + $hookFileManager->loadConfig(); + } +} diff --git a/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php b/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php index 80a0f16de..3a3b25536 100644 --- a/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php +++ b/tests/src/Core/KeyValueStorage/DBKeyValueStorageTest.php @@ -21,7 +21,7 @@ namespace Friendica\Test\src\Core\KeyValueStorage; -use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Core\KeyValueStorage\Type\DBKeyValueStorage; use Friendica\Database\Database; use Friendica\Test\Util\CreateDatabaseTrait; diff --git a/tests/src/Core/KeyValueStorage/KeyValueStorageTest.php b/tests/src/Core/KeyValueStorage/KeyValueStorageTest.php index 6ccc0f5f4..ddb0acc4d 100644 --- a/tests/src/Core/KeyValueStorage/KeyValueStorageTest.php +++ b/tests/src/Core/KeyValueStorage/KeyValueStorageTest.php @@ -21,7 +21,7 @@ namespace Friendica\Test\src\Core\KeyValueStorage; -use Friendica\Core\KeyValueStorage\Capabilities\IManageKeyValuePairs; +use Friendica\Core\KeyValueStorage\Capability\IManageKeyValuePairs; use Friendica\Test\MockedTest; abstract class KeyValueStorageTest extends MockedTest diff --git a/tests/src/Core/Logger/StreamLoggerTest.php b/tests/src/Core/Logger/StreamLoggerTest.php index 1ddddf4c1..a1e0af5bb 100644 --- a/tests/src/Core/Logger/StreamLoggerTest.php +++ b/tests/src/Core/Logger/StreamLoggerTest.php @@ -22,9 +22,7 @@ namespace Friendica\Test\src\Core\Logger; use Friendica\Core\Logger\Exception\LoggerArgumentException; -use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; -use Friendica\Util\FileSystem; use Friendica\Test\Util\VFSTrait; use Friendica\Core\Logger\Type\StreamLogger; use org\bovigo\vfs\vfsStream; @@ -40,33 +38,26 @@ class StreamLoggerTest extends AbstractLoggerTest */ private $logfile; - /** - * @var Filesystem - */ - private $fileSystem; - protected function setUp(): void { parent::setUp(); $this->setUpVfsDir(); - - $this->fileSystem = new FileSystem(); } /** * {@@inheritdoc} */ - protected function getInstance($level = LogLevel::DEBUG) + protected function getInstance($level = LogLevel::DEBUG, $logfile = 'friendica.log') { - $this->logfile = vfsStream::newFile('friendica.log') + $this->logfile = vfsStream::newFile($logfile) ->at($this->root); $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($this->logfile->url())->once(); + $this->config->shouldReceive('get')->with('system', 'loglevel')->andReturn($level)->once(); - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, $level); - - return $logger; + $loggerFactory = new \Friendica\Core\Logger\Factory\StreamLogger($this->introspection, 'test'); + return $loggerFactory->create($this->config); } /** @@ -83,11 +74,12 @@ class StreamLoggerTest extends AbstractLoggerTest public function testNoUrl() { $this->expectException(LoggerArgumentException::class); - $this->expectExceptionMessage("Missing stream URL."); + $this->expectExceptionMessage(' is not a valid logfile'); $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('')->once(); - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); + $loggerFactory = new \Friendica\Core\Logger\Factory\StreamLogger($this->introspection, 'test'); + $logger = $loggerFactory->create($this->config); $logger->emergency('not working'); } @@ -104,7 +96,8 @@ class StreamLoggerTest extends AbstractLoggerTest $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); + $loggerFactory = new \Friendica\Core\Logger\Factory\StreamLogger($this->introspection, 'test'); + $logger = $loggerFactory->create($this->config); $logger->emergency('not working'); } @@ -119,7 +112,8 @@ class StreamLoggerTest extends AbstractLoggerTest static::markTestIncomplete('We need a platform independent way to set directory to readonly'); - $logger = new StreamLogger('test', '/$%/wrong/directory/file.txt', $this->introspection, $this->fileSystem); + $loggerFactory = new \Friendica\Core\Logger\Factory\StreamLogger($this->introspection, 'test'); + $logger = $loggerFactory->create($this->config); $logger->emergency('not working'); } @@ -132,9 +126,7 @@ class StreamLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn('file.text')->once(); - - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem, 'NOPE'); + $logger = $this->getInstance('NOPE'); } /** @@ -145,29 +137,11 @@ class StreamLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $logfile = vfsStream::newFile('friendica.log') - ->at($this->root); - - $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn($logfile->url())->once(); - - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); + $logger = $this->getInstance('NOPE'); $logger->log('NOPE', 'a test'); } - /** - * Test when the file is null - */ - public function testWrongFile() - { - $this->expectException(LoggerArgumentException::class); - $this->expectExceptionMessage("A stream must either be a resource or a string."); - - $this->config->shouldReceive('get')->with('system', 'logfile')->andReturn(null)->once(); - - $logger = new StreamLogger('test', $this->config, $this->introspection, $this->fileSystem); - } - /** * Test a relative path * @doesNotPerformAssertions diff --git a/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php b/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php new file mode 100644 index 000000000..63209cad3 --- /dev/null +++ b/tests/src/Core/Logger/SyslogLoggerFactoryWrapper.php @@ -0,0 +1,46 @@ +. + * + */ + +namespace Friendica\Test\src\Core\Logger; + +use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Exception\LogLevelException; +use Friendica\Core\Logger\Factory\SyslogLogger; +use Friendica\Core\Logger\Type\SyslogLogger as SyslogLoggerClass; +use Psr\Log\LoggerInterface; + +class SyslogLoggerFactoryWrapper extends SyslogLogger +{ + public function create(IManageConfigValues $config): LoggerInterface + { + $logOpts = $config->get('system', 'syslog_flags') ?? SyslogLoggerClass::DEFAULT_FLAGS; + $logFacility = $config->get('system', 'syslog_facility') ?? SyslogLoggerClass::DEFAULT_FACILITY; + $loglevel = SyslogLogger::mapLegacyConfigDebugLevel($config->get('system', 'loglevel')); + + if (array_key_exists($loglevel, SyslogLoggerClass::logLevels)) { + $loglevel = SyslogLoggerClass::logLevels[$loglevel]; + } else { + throw new LogLevelException(sprintf('The level "%s" is not valid.', $loglevel)); + } + + return new SyslogLoggerWrapper($this->channel, $this->introspection, $loglevel, $logOpts, $logFacility); + } +} diff --git a/tests/src/Core/Logger/SyslogLoggerTest.php b/tests/src/Core/Logger/SyslogLoggerTest.php index 53ace79c0..c22aecc10 100644 --- a/tests/src/Core/Logger/SyslogLoggerTest.php +++ b/tests/src/Core/Logger/SyslogLoggerTest.php @@ -21,8 +21,6 @@ namespace Friendica\Test\src\Core\Logger; -use Friendica\Core\Logger\Exception\LoggerArgumentException; -use Friendica\Core\Logger\Exception\LoggerException; use Friendica\Core\Logger\Exception\LogLevelException; use Friendica\Core\Logger\Type\SyslogLogger; use Psr\Log\LogLevel; @@ -58,7 +56,10 @@ class SyslogLoggerTest extends AbstractLoggerTest */ protected function getInstance($level = LogLevel::DEBUG) { - $this->logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, $level); + $this->config->shouldReceive('get')->with('system', 'loglevel')->andReturn($level); + + $loggerFactory = new SyslogLoggerFactoryWrapper($this->introspection, 'test'); + $this->logger = $loggerFactory->create($this->config); return $this->logger; } @@ -71,8 +72,8 @@ class SyslogLoggerTest extends AbstractLoggerTest { $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - - $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection, 'NOPE'); + + $logger = $this->getInstance('NOPE'); } /** @@ -83,7 +84,7 @@ class SyslogLoggerTest extends AbstractLoggerTest $this->expectException(LogLevelException::class); $this->expectExceptionMessageMatches("/The level \".*\" is not valid./"); - $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); + $logger = $this->getInstance(); $logger->log('NOPE', 'a test'); } @@ -94,7 +95,7 @@ class SyslogLoggerTest extends AbstractLoggerTest */ public function testClose() { - $logger = new SyslogLoggerWrapper('test', $this->config, $this->introspection); + $logger = $this->getInstance(); $logger->emergency('test'); $logger->close(); // Reopened itself diff --git a/tests/src/Core/Logger/SyslogLoggerWrapper.php b/tests/src/Core/Logger/SyslogLoggerWrapper.php index 9fd16706a..dce28b164 100644 --- a/tests/src/Core/Logger/SyslogLoggerWrapper.php +++ b/tests/src/Core/Logger/SyslogLoggerWrapper.php @@ -21,10 +21,8 @@ namespace Friendica\Test\src\Core\Logger; -use Friendica\Core\Config\Capability\IManageConfigValues; +use Friendica\Core\Logger\Capability\IHaveCallIntrospections; use Friendica\Core\Logger\Type\SyslogLogger; -use Friendica\Core\Logger\Util\Introspection; -use Psr\Log\LogLevel; /** * Wraps the SyslogLogger for replacing the syslog call with a string field. @@ -33,9 +31,9 @@ class SyslogLoggerWrapper extends SyslogLogger { private $content; - public function __construct($channel, IManageConfigValues $config, Introspection $introspection, $level = LogLevel::NOTICE) + public function __construct(string $channel, IHaveCallIntrospections $introspection, string $logLevel, string $logOptions, string $logFacility) { - parent::__construct($channel, $config, $introspection, $level); + parent::__construct($channel, $introspection, $logLevel, $logOptions, $logFacility); $this->content = ''; } diff --git a/tests/src/Database/DatabaseTest.php b/tests/src/Database/DatabaseTest.php index e90683461..c431a5294 100644 --- a/tests/src/Database/DatabaseTest.php +++ b/tests/src/Database/DatabaseTest.php @@ -30,6 +30,15 @@ class DatabaseTest extends FixtureTest { use CreateDatabaseTrait; + /** + * @var Cache + */ + protected $configCache; + /** + * @var ConfigFileManager + */ + protected $configFileManager; + protected function setUp(): void { $this->setUpVfsDir(); diff --git a/tests/src/Model/User/CookieTest.php b/tests/src/Model/User/CookieTest.php index 372645bf3..ebe78764b 100644 --- a/tests/src/Model/User/CookieTest.php +++ b/tests/src/Model/User/CookieTest.php @@ -231,11 +231,12 @@ class CookieTest extends MockedTest $data = json_decode(StaticCookie::$_COOKIE[Cookie::NAME]); - self::assertObjectHasAttribute('uid', $data); + self::assertIsObject($data); + self::assertTrue(property_exists($data, 'uid')); self::assertEquals($uid, $data->uid); - self::assertObjectHasAttribute('hash', $data); + self::assertTrue(property_exists($data, 'hash')); self::assertEquals($hash, $data->hash); - self::assertObjectHasAttribute('ip', $data); + self::assertTrue(property_exists($data, 'ip')); self::assertEquals($remoteIp, $data->ip); self::assertLessThanOrEqual(time() + Cookie::DEFAULT_EXPIRE * 24 * 60 * 60, StaticCookie::$_EXPIRE); diff --git a/tests/src/Model/UserTest.php b/tests/src/Model/UserTest.php index eb0cb9f32..939d28245 100644 --- a/tests/src/Model/UserTest.php +++ b/tests/src/Model/UserTest.php @@ -82,7 +82,7 @@ class UserTest extends MockedTest public function testIdentitiesAsParent() { $parentSelect = $this->parent; - $parentSelect['parent-uid'] = 0; + $parentSelect['parent-uid'] = null; // Select the user itself (=parent) $this->dbMock->shouldReceive('selectFirst')->with('user', diff --git a/tests/src/Moderation/Factory/ReportTest.php b/tests/src/Moderation/Factory/ReportTest.php index ab94643f4..35e3a5050 100644 --- a/tests/src/Moderation/Factory/ReportTest.php +++ b/tests/src/Moderation/Factory/ReportTest.php @@ -21,144 +21,242 @@ namespace Friendica\Test\src\Moderation\Factory; +use Friendica\Moderation\Collection; use Friendica\Moderation\Factory; use Friendica\Moderation\Entity; use Friendica\Test\MockedTest; +use Friendica\Util\Clock\FrozenClock; +use Friendica\Util\DateTimeFormat; +use Psr\Clock\ClockInterface; use Psr\Log\NullLogger; class ReportTest extends MockedTest { public function dataCreateFromTableRow(): array { + $clock = new FrozenClock(); + + // We need to strip the microseconds part to match database stored timestamps + $nowSeconds = $clock->now()->setTime( + $clock->now()->format('H'), + $clock->now()->format('i'), + $clock->now()->format('s') + ); + return [ 'default' => [ + 'clock' => $clock, 'row' => [ - 'id' => 11, - 'uid' => 12, - 'reporter-id' => 14, - 'cid' => 13, - 'comment' => '', - 'category' => null, - 'rules' => '', - 'forward' => false, - 'created' => null + 'id' => 11, + 'reporter-id' => 12, + 'uid' => null, + 'cid' => 13, + 'gsid' => 14, + 'comment' => '', + 'forward' => false, + 'category-id' => Entity\Report::CATEGORY_SPAM, + 'public-remarks' => '', + 'private-remarks' => '', + 'last-editor-uid' => null, + 'assigned-uid' => null, + 'status' => Entity\Report::STATUS_OPEN, + 'resolution' => null, + 'created' => $nowSeconds->format(DateTimeFormat::MYSQL), + 'edited' => null, ], - 'postUriIds' => [], + 'posts' => new Collection\Report\Posts(), + 'rules' => new Collection\Report\Rules(), 'assertion' => new Entity\Report( - 14, + 12, 13, - new \DateTime('now', new \DateTimeZone('UTC')), - '', + 14, + $nowSeconds, + Entity\Report::CATEGORY_SPAM, null, '', false, - [], - 12, - 11, + new Collection\Report\Posts(), + new Collection\Report\Rules(), + '', + '', + null, + Entity\Report::STATUS_OPEN, + null, + null, + null, + 11 ), ], 'full' => [ + 'clock' => $clock, 'row' => [ - 'id' => 11, - 'uid' => 12, - 'reporter-id' => 14, - 'cid' => 13, - 'comment' => 'Report', - 'category' => 'violation', - 'rules' => 'Rules', - 'forward' => true, - 'created' => '2021-10-12 12:23:00' + 'id' => 11, + 'reporter-id' => 42, + 'uid' => 12, + 'cid' => 13, + 'gsid' => 14, + 'comment' => 'Report', + 'forward' => true, + 'category-id' => Entity\Report::CATEGORY_VIOLATION, + 'public-remarks' => 'Public remarks', + 'private-remarks' => 'Private remarks', + 'last-editor-uid' => 15, + 'assigned-uid' => 16, + 'status' => Entity\Report::STATUS_CLOSED, + 'resolution' => Entity\Report::RESOLUTION_ACCEPTED, + 'created' => '2021-10-12 12:23:00', + 'edited' => '2021-12-10 21:08:00', ], - 'postUriIds' => [89, 90], + 'posts' => new Collection\Report\Posts([ + new Entity\Report\Post(89), + new Entity\Report\Post(90), + ]), + 'rules' => new Collection\Report\Rules([ + new Entity\Report\Rule(1, 'No hate speech'), + new Entity\Report\Rule(3, 'No commercial promotion'), + ]), 'assertion' => new Entity\Report( - 14, + 42, 13, - new \DateTime('2021-10-12 12:23:00', new \DateTimeZone('UTC')), - 'Report', - 'violation', - 'Rules', - true, - [89, 90], + 14, + new \DateTimeImmutable('2021-10-12 12:23:00', new \DateTimeZone('UTC')), + Entity\Report::CATEGORY_VIOLATION, 12, + 'Report', + true, + new Collection\Report\Posts([ + new Entity\Report\Post(89), + new Entity\Report\Post(90), + ]), + new Collection\Report\Rules([ + new Entity\Report\Rule(1, 'No hate speech'), + new Entity\Report\Rule(3, 'No commercial promotion'), + ]), + 'Public remarks', + 'Private remarks', + new \DateTimeImmutable('2021-12-10 21:08:00', new \DateTimeZone('UTC')), + Entity\Report::STATUS_CLOSED, + Entity\Report::RESOLUTION_ACCEPTED, + 16, + 15, 11 ), ], ]; } - public function assertReport(Entity\Report $assertion, Entity\Report $report) - { - self::assertEquals( - $assertion->id, - $report->id - ); - self::assertEquals($assertion->uid, $report->uid); - self::assertEquals($assertion->reporterId, $report->reporterId); - self::assertEquals($assertion->cid, $report->cid); - self::assertEquals($assertion->comment, $report->comment); - self::assertEquals($assertion->category, $report->category); - self::assertEquals($assertion->rules, $report->rules); - self::assertEquals($assertion->forward, $report->forward); - // No way to test "now" at the moment - //self::assertEquals($assertion->created, $report->created); - self::assertEquals($assertion->postUriIds, $report->postUriIds); - } - /** * @dataProvider dataCreateFromTableRow */ - public function testCreateFromTableRow(array $row, array $postUriIds, Entity\Report $assertion) + public function testCreateFromTableRow(ClockInterface $clock, array $row, Collection\Report\Posts $posts, Collection\Report\Rules $rules, Entity\Report $assertion) { - $factory = new Factory\Report(new NullLogger()); + $factory = new Factory\Report(new NullLogger(), $clock); - $this->assertReport($factory->createFromTableRow($row, $postUriIds), $assertion); + $this->assertEquals($factory->createFromTableRow($row, $posts, $rules), $assertion); } public function dataCreateFromReportsRequest(): array { + $clock = new FrozenClock(); + return [ 'default' => [ - 'reporter-id' => 14, - 'cid' => 13, - 'comment' => '', - 'category' => null, - 'rules' => '', - 'forward' => false, - 'postUriIds' => [], - 'uid' => 12, - 'assertion' => new Entity\Report( - 14, - 13, - new \DateTime('now', new \DateTimeZone('UTC')), - '', - null, - '', - false, - [], + 'clock' => $clock, + 'rules' => [], + 'reporterId' => 12, + 'cid' => 13, + 'gsid' => 14, + 'comment' => '', + 'category' => 'spam', + 'forward' => false, + 'postUriIds' => [], + 'ruleIds' => [], + 'uid' => null, + 'assertion' => new Entity\Report( 12, - null + 13, + 14, + $clock->now(), + Entity\Report::CATEGORY_SPAM, ), ], 'full' => [ - 'reporter-id' => 14, - 'cid' => 13, - 'comment' => 'Report', - 'category' => 'violation', - 'rules' => 'Rules', - 'forward' => true, - 'postUriIds' => [89, 90], - 'uid' => 12, - 'assertion' => new Entity\Report( - 14, - 13, - new \DateTime('now', new \DateTimeZone('UTC')), - 'Report', - 'violation', - 'Rules', - true, - [89, 90], + 'clock' => $clock, + 'rules' => ['', 'Rule 1', 'Rule 2', 'Rule 3'], + 'reporterId' => 12, + 'cid' => 13, + 'gsid' => 14, + 'comment' => 'Report', + 'category' => 'violation', + 'forward' => true, + 'postUriIds' => [89, 90], + 'ruleIds' => [1, 3], + 'uid' => 42, + 'assertion' => new Entity\Report( 12, - null + 13, + 14, + $clock->now(), + Entity\Report::CATEGORY_VIOLATION, + 42, + 'Report', + true, + new Collection\Report\Posts([ + new Entity\Report\Post(89), + new Entity\Report\Post(90) + ]), + new Collection\Report\Rules([ + new Entity\Report\Rule(1, 'Rule 1'), + new Entity\Report\Rule(3, 'Rule 3'), + ]), + ), + ], + 'forced-violation' => [ + 'clock' => $clock, + 'rules' => ['', 'Rule 1', 'Rule 2', 'Rule 3'], + 'reporterId' => 12, + 'cid' => 13, + 'gsid' => 14, + 'comment' => 'Report', + 'category' => 'other', + 'forward' => false, + 'postUriIds' => [], + 'ruleIds' => [2, 3], + 'uid' => null, + 'assertion' => new Entity\Report( + 12, + 13, + 14, + $clock->now(), + Entity\Report::CATEGORY_VIOLATION, + null, + 'Report', + false, + new Collection\Report\Posts(), + new Collection\Report\Rules([ + new Entity\Report\Rule(2, 'Rule 2'), + new Entity\Report\Rule(3, 'Rule 3'), + ]), + ), + ], + 'unknown-category' => [ + 'clock' => $clock, + 'rules' => ['', 'Rule 1', 'Rule 2', 'Rule 3'], + 'reporterId' => 12, + 'cid' => 13, + 'gsid' => 14, + 'comment' => '', + 'category' => 'unknown', + 'forward' => false, + 'postUriIds' => [], + 'ruleIds' => [], + 'uid' => null, + 'assertion' => new Entity\Report( + 12, + 13, + 14, + $clock->now(), + Entity\Report::CATEGORY_OTHER, ), ], ]; @@ -167,10 +265,10 @@ class ReportTest extends MockedTest /** * @dataProvider dataCreateFromReportsRequest */ - public function testCreateFromReportsRequest(int $reporter, int $cid, string $comment, string $category = null, string $rules = '', bool $forward, array $postUriIds, int $uid, Entity\Report $assertion) + public function testCreateFromReportsRequest(ClockInterface $clock, array $rules, int $reporterId, int $cid, int $gsid, string $comment, string $category, bool $forward, array $postUriIds, array $ruleIds, int $uid = null, Entity\Report $assertion) { - $factory = new Factory\Report(new NullLogger()); + $factory = new Factory\Report(new NullLogger(), $clock); - $this->assertReport($factory->createFromReportsRequest($reporter, $cid, $comment, $category, $rules, $forward, $postUriIds, $uid), $assertion); + $this->assertEquals($factory->createFromReportsRequest($rules, $reporterId, $cid, $gsid, $comment, $category, $forward, $postUriIds, $ruleIds, $uid), $assertion); } } diff --git a/tests/src/Util/ACLFormatterTest.php b/tests/src/Util/ACLFormatterTest.php index afbf435d8..93e1767dc 100644 --- a/tests/src/Util/ACLFormatterTest.php +++ b/tests/src/Util/ACLFormatterTest.php @@ -21,7 +21,7 @@ namespace Friendica\Test\src\Util; -use Friendica\Model\Group; +use Friendica\Model\Circle; use Friendica\Util\ACLFormatter; use PHPUnit\Framework\TestCase; @@ -56,8 +56,8 @@ class ACLFormatterTest extends TestCase { return [ 'normal' => [ - 'input' => '<1><2><3><' . Group::FOLLOWERS . '><' . Group::MUTUALS . '>', - 'assert' => ['1', '2', '3', Group::FOLLOWERS, Group::MUTUALS], + 'input' => '<1><2><3><' . Circle::FOLLOWERS . '><' . Circle::MUTUALS . '>', + 'assert' => ['1', '2', '3', Circle::FOLLOWERS, Circle::MUTUALS], ], 'nigNumber' => [ 'input' => '<1><' . PHP_INT_MAX . '><15>', @@ -128,12 +128,12 @@ class ACLFormatterTest extends TestCase $aclFormatter = new ACLFormatter(); $allow_people = $aclFormatter->expand(); - $allow_groups = $aclFormatter->expand(); + $allow_circles = $aclFormatter->expand(); self::assertEmpty($aclFormatter->expand(null)); self::assertEmpty($aclFormatter->expand()); - $recipients = array_unique(array_merge($allow_people, $allow_groups)); + $recipients = array_unique(array_merge($allow_people, $allow_circles)); self::assertEmpty($recipients); } @@ -165,13 +165,13 @@ class ACLFormatterTest extends TestCase 'input' => ["<40195>"], 'assert' => "<40195>", ], - Group::FOLLOWERS => [ - 'input' => [Group::FOLLOWERS, 1], - 'assert' => '<' . Group::FOLLOWERS . '><1>', + Circle::FOLLOWERS => [ + 'input' => [Circle::FOLLOWERS, 1], + 'assert' => '<' . Circle::FOLLOWERS . '><1>', ], - Group::MUTUALS => [ - 'input' => [Group::MUTUALS, 1], - 'assert' => '<' . Group::MUTUALS . '><1>', + Circle::MUTUALS => [ + 'input' => [Circle::MUTUALS, 1], + 'assert' => '<' . Circle::MUTUALS . '><1>', ], 'wrong-angle-brackets' => [ 'input' => ["","<123>"], diff --git a/tests/src/Util/HTTPSignatureTest.php b/tests/src/Util/HTTPSignatureTest.php index 03b0033fa..bc54a9318 100644 --- a/tests/src/Util/HTTPSignatureTest.php +++ b/tests/src/Util/HTTPSignatureTest.php @@ -124,8 +124,8 @@ G1vVmRgkLDqhc4+r3wDz3qy6JpV7tg== -----END PRIVATE KEY-----', 'keyId' => 'acct:admin@friendica.local', 'header' => [ - 'Accept' => ['application/x-dfrn+json', 'application/x-zot+json'], - 'X-Open-Web-Auth' => ['1dde649b855fd1aae542a91c4edd8c3a7a4c59d8eaf3136cdee05dfc16a30bac'], + 'Accept' => 'application/x-dfrn+json, application/x-zot+json', + 'X-Open-Web-Auth' => '1dde649b855fd1aae542a91c4edd8c3a7a4c59d8eaf3136cdee05dfc16a30bac' ], 'signature' => 'Signature keyId="acct:admin@friendica.local",algorithm="rsa-sha512",headers="accept x-open-web-auth",signature="cb09/wdmRdFhrQUczL0lR6LTkVh8qb/vYh70DFCW40QrzvuUYHzJ+GqqJW6tcCb2rXP4t+aobWKfZ4wFMBtVbejAiCgF01pzEBJfDevdyu7khlfKo+Gtw1CGk4/0so1QmqASeHdlG3ID3GnmuovqZn2v5f5D+1UAJ6Pu6mtAXrGRntoEM/oqYBAsRrMtDSDAE4tnOSDu2YfVJJLfyUX1ZWjUK0ejZXZ0YTDJwU8PqRcRX17NhBaDq82dEHlfhD7I/aOclwVbfKIi5Ud619XCxPq0sAAYso17MhUm40oBCJVze2x4pswJhv9IFYohtR5G/fKkz2eosu3xeRflvGicS4JdclhTRgCGWDy10DV76FiXiS5N2clLXreHItWEXlZKZx6m9zAZoEX92VRnc4BY4jDsRR89Pl88hELaxiNipviyHS7XYZTRnkLM+nvtOcxkHSCbEs7oGw+AX+pLHoU5otNOqy+ZbXQ1cUvFOBYZmYdX3DiWaLfBKraakPkslJuU3yJu95X1qYmQTpOZDR4Ma/yf5fmWJh5D9ywnXxxd6RaupoO6HTtIl6gmsfcsyZNi5hRbbgPI3BiQwGYVGF6qzJpEOMzEyHyAuFeanhicc8b+P+DCwXni5sjM7ntKwShbCBP80KHSdoumORin3/PYgHCmHZVv71N0HNlPZnyVzZw="', ] diff --git a/update.php b/update.php index 3cd0a45a7..59340eed8 100644 --- a/update.php +++ b/update.php @@ -1326,3 +1326,54 @@ function update_1518() return Update::SUCCESS; } + +function update_1520(): int +{ + DBA::update('user', ['parent-uid' => null], ['parent-uid' => 0]); + + return Update::SUCCESS; +} + +/** + * user-contact.remote_self was wrongly declared as boolean, possibly truncating integer values from contact.remote_self + * + * @return int + * @throws Exception + */ +function update_1524(): int +{ + $contacts = DBA::select('contact', ['uid', 'uri-id', 'remote_self'], ["`uid` != ?", 0]); + while ($contact = DBA::fetch($contacts)) { + Contact\User::insertForContactArray($contact); + } + + return Update::SUCCESS; +} + +function update_1525(): int +{ + // Use expected value for user.username + if (!DBA::e('UPDATE `user` u + JOIN `profile` p + ON p.`uid` = u.`uid` + SET u.`username` = p.`name` + WHERE p.`name` != ""')) { + return Update::FAILED; + } + + // Blank out deprecated field profile.name to avoid future confusion + if (!DBA::e('UPDATE `profile` p + SET p.`name` = ""')) { + return Update::FAILED; + } + + // Update users' self-contact name if needed + if (!DBA::e('UPDATE `contact` c + JOIN `user` u + ON u.`uid` = c.`uid` AND c.`self` = 1 + SET c.`name` = u.`username`')) { + return Update::FAILED; + } + + return Update::SUCCESS; +} diff --git a/view/global.css b/view/global.css index 5b701654a..714bb55db 100644 --- a/view/global.css +++ b/view/global.css @@ -452,14 +452,14 @@ td.federation-data { max-height: 80px; } -/* forumlist widget */ -.forumlist-img { +/* group list widget */ +.group-list-img { height: 20px; width: 20px; vertical-align: middle; } -#forum-widget-collapse { +#group-widget-collapse { opacity: 0.3; } @@ -479,7 +479,7 @@ aside .help-aside-wrapper h1 { color: #ffffff; } -#forum-widget-collapse:hover { +#group-widget-collapse:hover { opacity: 1.0; } diff --git a/view/js/autocomplete.js b/view/js/autocomplete.js index 7d5bd0656..dc649084a 100644 --- a/view/js/autocomplete.js +++ b/view/js/autocomplete.js @@ -24,8 +24,8 @@ function contact_search(term, callback, backend_url, type, mode) { for(var t in contact_search.cache[bt]) { if(lterm.indexOf(t) >= 0) { // A more broad search has been performed already, so use those results // Filter old results locally - var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because groups don't have one - matching.unshift({forum:false, text: term, replace: term}); + var matching = contact_search.cache[bt][t].filter(function (x) { return (x.name.toLowerCase().indexOf(lterm) >= 0 || (typeof x.nick !== 'undefined' && x.nick.toLowerCase().indexOf(lterm) >= 0)); }); // Need to check that nick exists because circles don't have one + matching.unshift({group: false, text: term, replace: term}); setTimeout(function() { callback(matching); } , 1); // Use "pseudo-thread" to avoid some problems return; } @@ -69,10 +69,10 @@ function contact_format(item) { // Show contact information if not explicitly told to show something else if(typeof item.text === 'undefined') { var desc = ((item.label) ? item.nick + ' ' + item.label : item.nick); - var forum = ((item.forum) ? 'forum' : ''); + var group = ((item.group) ? 'group' : ''); if(typeof desc === 'undefined') desc = ''; if(desc) desc = ' ('+desc+')'; - return "
{2}{3}
".format(forum, item.photo, item.name, desc, item.link); + return "
{2}{3}
".format(group, item.photo, item.name, desc, item.link); } else return "
" + item.text + "
"; @@ -258,8 +258,8 @@ function string2bb(element) { template: contact_format, }; - // Autocomplete forums - forums = { + // Autocomplete groups + groups = { match: /(^|\s)(!\!*)([^ \n]+)$/, index: 3, search: function(term, callback) { contact_search(term, callback, backend_url, 'f'); }, @@ -294,7 +294,7 @@ function string2bb(element) { }; this.attr('autocomplete','off'); - this.textcomplete([contacts, forums, smilies, tags], {dropdown: {className:'acpopup'}}); + this.textcomplete([contacts, groups, smilies, tags], {dropdown: {className:'acpopup'}}); this.fixTextcompleteEscape(); return this; @@ -310,7 +310,7 @@ function string2bb(element) { template: contact_format, }; - // Autocomplete forum accounts + // Autocomplete group accounts community = { match: /(^!)([^\n]{2,})$/, index: 2, diff --git a/view/js/country.js b/view/js/country.js index 83123e4cb..65497fdbf 100644 --- a/view/js/country.js +++ b/view/js/country.js @@ -260,7 +260,7 @@ aStates[233]="|Tuvalu"; aStates[234]="|Adjumani|Apac|Arua|Bugiri|Bundibugyo|Bushenyi|Busia|Gulu|Hoima|Iganga|Jinja|Kabale|Kabarole|Kalangala|Kampala|Kamuli|Kapchorwa|Kasese|Katakwi|Kibale|Kiboga|Kisoro|Kitgum|Kotido|Kumi|Lira|Luwero|Masaka|Masindi|Mbale|Mbarara|Moroto|Moyo|Mpigi|Mubende|Mukono|Nakasongola|Nebbi|Ntungamo|Pallisa|Rakai|Rukungiri|Sembabule|Soroti|Tororo"; aStates[235]="|Avtonomna Respublika Krym (Simferopol')|Cherkas'ka (Cherkasy)|Chernihivs'ka (Chernihiv)|Chernivets'ka (Chernivtsi)|Dnipropetrovs'ka (Dnipropetrovs'k)|Donets'ka (Donets'k)|Ivano-Frankivs'ka (Ivano-Frankivs'k)|Kharkivs'ka (Kharkiv)|Khersons'ka (Kherson)|Khmel'nyts'ka (Khmel'nyts'kyy)|Kirovohrads'ka (Kirovohrad)|Kyyiv|Kyyivs'ka (Kiev)|L'vivs'ka (L'viv)|Luhans'ka (Luhans'k)|Mykolayivs'ka (Mykolayiv)|Odes'ka (Odesa)|Poltavs'ka (Poltava)|Rivnens'ka (Rivne)|Sevastopol'|Sums'ka (Sumy)|Ternopil's'ka (Ternopil')|Vinnyts'ka (Vinnytsya)|Volyns'ka (Luts'k)|Zakarpats'ka (Uzhhorod)|Zaporiz'ka (Zaporizhzhya)|Zhytomyrs'ka (Zhytomyr)" aStates[236]="|'Ajman|Abu Zaby (Abu Dhabi)|Al Fujayrah|Ash Shariqah (Sharjah)|Dubayy (Dubai)|Ra's al Khaymah|Umm al Qaywayn"; -aStates[237]="|Aberdeen|Aberdeenshire|Anglesey|Angus|Antrim|Argyl|Armagh|Avon|Ayrshire|Banffshire|Bedfordshire|Belfast|Berwickshire|Brecknockshire|Bristol|Buckinghamshire|Bute|Caernarfonshire|Cardiganshire|Caithness|Cambridgeshire|Carmarthenshire|Chesire|Clackmannashire|Cleveland|Clwyd|Cornwall|Cromartyshire|Cumberland|Cumbria|Denbighshire|Derbyshire|Devon|Dfyed|Dorset|Down|Dumfriesshire|Dunbartonshire|Dundee|Durham|East Lothian|East Suffolk|Derry|East Sussex|Edinburgh|Essex|Fermanagh|Fife|Flintshire|Glasgow|Glamorgan|Gloucestershire|Greater London|Greater Manchester|Gwent|Gwynedd|Hampshire|Hereford and Worcester|Herefordshire|Inverness-shire|Hertfordshire|Humberside|Huntingdon and Peterborough|Huntingdonshire|Isle of Ely|Isle of Wight|Kent|Kincardineshire|Kincross-shire|Kirkcudbrightshire|Lanarkshire|Lancashire|Leicestershire|Lincolnshire|London|Londonderry|Merionethshire|Merseyside|Middlesex|Mid Glamorgan|Midlothian|Monmouthshire|Montgomeryshire|Moray|Nairnshire|Norfolk|Northamptonshire|Northumberland|North Humberside|North Yorkshire|Nottinghamshire|Orkney|Oxfordshire|Peeblesshire|Pembrokeshire|Perthshire|Powys|Radnorshire|Renfrewshire|Ross And Cromarty|Ross-shire|Roxburghshire|Selkirkshire|Shetland|Stirlingshire|Sutherland|Soke of Peterborough|Rutland|Shropshire|Somerset|South Glamorgan|South Humberside|South Yorkshire|Staffordshite|Suffolk|Surrey|Sussex|Tyne and Wear|Tyrone|Warwickshire|West Glamorgan|West Lothian|West Midlands|Westmorland|West Suffolk|West Sussex|West Yorkshire|Wigtownshire|Wiltshire|Worcestershire|Yorkshire"; +aStates[237]="|Aberdeen|Aberdeenshire|Anglesey|Angus|Antrim|Argyl|Armagh|Avon|Ayrshire|Banffshire|Bedfordshire|Belfast|Berwickshire|Brecknockshire|Bristol|Buckinghamshire|Bute|Caernarfonshire|Cardiganshire|Caithness|Cambridgeshire|Carmarthenshire|Cheshire|Clackmannashire|Cleveland|Clwyd|Cornwall|Cromartyshire|Cumberland|Cumbria|Denbighshire|Derbyshire|Devon|Dfyed|Dorset|Down|Dumfriesshire|Dunbartonshire|Dundee|Durham|East Lothian|East Suffolk|Derry|East Sussex|Edinburgh|Essex|Fermanagh|Fife|Flintshire|Glasgow|Glamorgan|Gloucestershire|Greater London|Greater Manchester|Gwent|Gwynedd|Hampshire|Hereford and Worcester|Herefordshire|Inverness-shire|Hertfordshire|Humberside|Huntingdon and Peterborough|Huntingdonshire|Isle of Ely|Isle of Wight|Kent|Kincardineshire|Kincross-shire|Kirkcudbrightshire|Lanarkshire|Lancashire|Leicestershire|Lincolnshire|London|Londonderry|Merionethshire|Merseyside|Middlesex|Mid Glamorgan|Midlothian|Monmouthshire|Montgomeryshire|Moray|Nairnshire|Norfolk|Northamptonshire|Northumberland|North Humberside|North Yorkshire|Nottinghamshire|Orkney|Oxfordshire|Peeblesshire|Pembrokeshire|Perthshire|Powys|Radnorshire|Renfrewshire|Ross And Cromarty|Ross-shire|Roxburghshire|Selkirkshire|Shetland|Stirlingshire|Sutherland|Soke of Peterborough|Rutland|Shropshire|Somerset|South Glamorgan|South Humberside|South Yorkshire|Staffordshite|Suffolk|Surrey|Sussex|Tyne and Wear|Tyrone|Warwickshire|West Glamorgan|West Lothian|West Midlands|Westmorland|West Suffolk|West Sussex|West Yorkshire|Wigtownshire|Wiltshire|Worcestershire|Yorkshire"; aStates[238]="|Artigas|Canelones|Cerro Largo|Colonia|Durazno|Flores|Florida|Lavalleja|Maldonado|Montevideo|Paysandu|Rio Negro|Rivera|Rocha|Salto|San Jose|Soriano|Tacuarembo|Treinta y Tres"; aStates[239]="|Alabama|Alaska|Arizona|Arkansas|California|Colorado|Connecticut|Delaware|District of Columbia|Florida|Georgia|Hawaii|Idaho|Illinois|Indiana|Iowa|Kansas|Kentucky|Louisiana|Maine|Maryland|Massachusetts|Michigan|Minnesota|Mississippi|Missouri|Montana|Nebraska|Nevada|New Hampshire|New Jersey|New Mexico|New York|North Carolina|North Dakota|Ohio|Oklahoma|Oregon|Pennsylvania|Rhode Island|South Carolina|South Dakota|Tennessee|Texas|Utah|Vermont|Virginia|Washington|West Virginia|Wisconsin|Wyoming"; aStates[240]="|Andijon Wiloyati|Bukhoro Wiloyati|Farghona Wiloyati|Jizzakh Wiloyati|Khorazm Wiloyati (Urganch)|Namangan Wiloyati|Nawoiy Wiloyati|Qashqadaryo Wiloyati (Qarshi)|Qoraqalpoghiston (Nukus)|Samarqand Wiloyati|Sirdaryo Wiloyati (Guliston)|Surkhondaryo Wiloyati (Termiz)|Toshkent Shahri|Toshkent Wiloyati"; diff --git a/view/js/main.js b/view/js/main.js index a1446bca5..3e0f8307a 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -289,18 +289,18 @@ $(function() { $('#mail-update-li').html(mail); - $(".sidebar-group-li .notify").removeClass("show"); - $(data.groups).each(function(key, group) { - var gid = group.id; - var gcount = group.count; - $(".group-"+gid+" .notify").addClass("show").text(gcount); + $(".sidebar-circle-li .notify").removeClass("show"); + $(data.circles).each(function(key, circle) { + var gid = circle.id; + var gcount = circle.count; + $(".circle-"+gid+" .notify").addClass("show").text(gcount); }); - $(".forum-widget-entry .notify").removeClass("show"); - $(data.forums).each(function(key, forum) { - var fid = forum.id; - var fcount = forum.count; - $(".forum-"+fid+" .notify").addClass("show").text(fcount); + $(".group-widget-entry .notify").removeClass("show"); + $(data.groups).each(function(key, group) { + var fid = group.id; + var fcount = group.count; + $(".group-"+fid+" .notify").addClass("show").text(fcount); }); if (data.notifications.length == 0) { @@ -946,21 +946,21 @@ function bin2hex(s) { return a.join(''); } -function groupChangeMember(gid, cid, sec_token) { +function circleChangeMember(gid, cid, sec_token) { $('body .fakelink').css('cursor', 'wait'); - $.get('group/' + gid + '/' + cid + "?t=" + sec_token, function(data) { - $('#group-update-wrapper').html(data); + $.get('circle/' + gid + '/' + cid + "?t=" + sec_token, function(data) { + $('#circle-update-wrapper').html(data); $('body .fakelink').css('cursor', 'auto'); }); } -function contactgroupChangeMember(checkbox, gid, cid) { +function contactCircleChangeMember(checkbox, gid, cid) { let url; // checkbox.checked is the checkbox state after the click if (checkbox.checked) { - url = 'group/' + gid + '/add/' + cid; + url = 'circle/' + gid + '/add/' + cid; } else { - url = 'group/' + gid + '/remove/' + cid; + url = 'circle/' + gid + '/remove/' + cid; } $('body').css('cursor', 'wait'); $.post(url) diff --git a/view/lang/C/messages.po b/view/lang/C/messages.po index 3abf2cedd..b758e68c0 100644 --- a/view/lang/C/messages.po +++ b/view/lang/C/messages.po @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: 2023.05-rc\n" +"Project-Id-Version: 2023.09-dev\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-05-21 17:30+0000\n" +"POT-Creation-Date: 2023-08-28 04:37+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -38,26 +38,26 @@ msgstr "" msgid "Empty post discarded." msgstr "" -#: mod/item.php:427 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:428 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:451 mod/message.php:67 mod/message.php:113 mod/notes.php:45 -#: mod/photos.php:152 mod/photos.php:667 src/Model/Event.php:522 +#: mod/item.php:452 mod/message.php:67 mod/message.php:113 mod/notes.php:45 +#: mod/photos.php:152 mod/photos.php:670 src/Model/Event.php:520 #: src/Module/Attach.php:55 src/Module/BaseApi.php:99 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 #: src/Module/Calendar/Export.php:82 src/Module/Calendar/Show.php:82 +#: src/Module/Circle.php:41 src/Module/Circle.php:84 #: src/Module/Contact/Advanced.php:60 src/Module/Contact/Follow.php:87 #: src/Module/Contact/Follow.php:160 src/Module/Contact/MatchInterests.php:86 #: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 #: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112 #: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38 -#: src/Module/FriendSuggest.php:57 src/Module/Group.php:40 -#: src/Module/Group.php:83 src/Module/Invite.php:42 src/Module/Invite.php:131 -#: src/Module/Notifications/Notification.php:76 +#: src/Module/FriendSuggest.php:57 src/Module/Invite.php:42 +#: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:107 #: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66 #: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:75 @@ -67,8 +67,8 @@ msgstr "" #: src/Module/Profile/UnkMail.php:132 src/Module/Register.php:77 #: src/Module/Register.php:90 src/Module/Register.php:206 #: src/Module/Register.php:245 src/Module/Search/Directory.php:37 -#: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:407 -#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:69 +#: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:408 +#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:71 #: src/Module/Settings/Display.php:69 src/Module/Settings/Display.php:151 #: src/Module/Settings/Profile/Photo/Crop.php:165 #: src/Module/Settings/Profile/Photo/Index.php:111 @@ -281,7 +281,7 @@ msgstr "" msgid "Your message:" msgstr "" -#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:360 +#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:367 #: src/Module/Post/Edit.php:131 msgid "Upload photo" msgstr "" @@ -291,18 +291,18 @@ msgstr "" msgid "Insert web link" msgstr "" -#: mod/message.php:201 mod/message.php:357 mod/photos.php:1289 -#: src/Content/Conversation.php:390 src/Content/Conversation.php:734 -#: src/Module/Item/Compose.php:205 src/Module/Post/Edit.php:145 -#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:557 +#: mod/message.php:201 mod/message.php:357 mod/photos.php:1301 +#: src/Content/Conversation.php:398 src/Content/Conversation.php:1534 +#: src/Module/Item/Compose.php:206 src/Module/Post/Edit.php:145 +#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:578 msgid "Please wait" msgstr "" -#: mod/message.php:202 mod/message.php:356 mod/photos.php:700 -#: mod/photos.php:817 mod/photos.php:1095 mod/photos.php:1136 -#: mod/photos.php:1192 mod/photos.php:1266 +#: mod/message.php:202 mod/message.php:356 mod/photos.php:705 +#: mod/photos.php:824 mod/photos.php:1101 mod/photos.php:1142 +#: mod/photos.php:1198 mod/photos.php:1278 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 -#: src/Module/Contact/Profile.php:339 +#: src/Module/Contact/Profile.php:358 #: src/Module/Debug/ActivityPubConversion.php:140 #: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 #: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 @@ -310,8 +310,13 @@ msgstr "" #: src/Module/Install.php:234 src/Module/Install.php:274 #: src/Module/Install.php:309 src/Module/Invite.php:178 #: src/Module/Item/Compose.php:189 src/Module/Moderation/Item/Source.php:79 +#: src/Module/Moderation/Report/Create.php:168 +#: src/Module/Moderation/Report/Create.php:183 +#: src/Module/Moderation/Report/Create.php:211 +#: src/Module/Moderation/Report/Create.php:263 #: src/Module/Profile/Profile.php:274 src/Module/Profile/UnkMail.php:155 -#: src/Module/Settings/Profile/Index.php:230 src/Object/Post.php:1070 +#: src/Module/Settings/Profile/Index.php:257 +#: src/Module/Settings/Server/Action.php:79 src/Object/Post.php:1095 #: view/theme/duepuntozero/config.php:85 view/theme/frio/config.php:171 #: view/theme/quattro/config.php:87 view/theme/vier/config.php:135 msgid "Submit" @@ -377,14 +382,14 @@ msgstr "" msgid "Personal notes are visible only by yourself." msgstr "" -#: mod/notes.php:57 src/Content/Text/HTML.php:856 +#: mod/notes.php:57 src/Content/Text/HTML.php:859 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:74 #: src/Module/Post/Edit.php:129 msgid "Save" msgstr "" -#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:575 -#: src/Model/Event.php:514 src/Model/Profile.php:234 +#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:578 +#: src/Model/Event.php:512 src/Model/Profile.php:232 #: src/Module/Calendar/Export.php:74 src/Module/Calendar/Show.php:74 #: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51 #: src/Module/Profile/Common.php:62 src/Module/Profile/Common.php:71 @@ -405,7 +410,7 @@ msgstr "" msgid "Recent Photos" msgstr "" -#: mod/photos.php:109 mod/photos.php:865 src/Module/Profile/Photos.php:382 +#: mod/photos.php:109 mod/photos.php:872 src/Module/Profile/Photos.php:382 #: src/Module/Profile/Photos.php:402 msgid "Upload New Photos" msgstr "" @@ -423,72 +428,72 @@ msgstr "" msgid "Album not found." msgstr "" -#: mod/photos.php:242 +#: mod/photos.php:244 msgid "Album successfully deleted" msgstr "" -#: mod/photos.php:244 +#: mod/photos.php:246 msgid "Album was empty." msgstr "" -#: mod/photos.php:276 +#: mod/photos.php:277 msgid "Failed to delete the photo." msgstr "" -#: mod/photos.php:542 +#: mod/photos.php:545 msgid "a photo" msgstr "" -#: mod/photos.php:542 +#: mod/photos.php:545 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "" -#: mod/photos.php:579 src/Module/Conversation/Community.php:188 +#: mod/photos.php:582 src/Module/Conversation/Community.php:188 #: src/Module/Directory.php:48 src/Module/Profile/Photos.php:295 #: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "" -#: mod/photos.php:584 +#: mod/photos.php:587 msgid "No photos selected" msgstr "" -#: mod/photos.php:716 +#: mod/photos.php:721 #, php-format msgid "The maximum accepted image size is %s" msgstr "" -#: mod/photos.php:723 +#: mod/photos.php:728 msgid "Upload Photos" msgstr "" -#: mod/photos.php:727 mod/photos.php:813 +#: mod/photos.php:732 mod/photos.php:820 msgid "New album name: " msgstr "" -#: mod/photos.php:728 +#: mod/photos.php:733 msgid "or select existing album:" msgstr "" -#: mod/photos.php:729 +#: mod/photos.php:734 msgid "Do not show a status post for this upload" msgstr "" -#: mod/photos.php:731 mod/photos.php:1091 src/Content/Conversation.php:392 +#: mod/photos.php:736 mod/photos.php:1097 src/Content/Conversation.php:400 #: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:183 msgid "Permissions" msgstr "" -#: mod/photos.php:794 +#: mod/photos.php:801 msgid "Do you really want to delete this photo album and all its photos?" msgstr "" -#: mod/photos.php:795 mod/photos.php:818 +#: mod/photos.php:802 mod/photos.php:825 msgid "Delete Album" msgstr "" -#: mod/photos.php:796 mod/photos.php:897 src/Content/Conversation.php:408 +#: mod/photos.php:803 mod/photos.php:903 src/Content/Conversation.php:416 #: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 #: src/Module/Contact/Unfollow.php:126 #: src/Module/Media/Attachment/Browser.php:77 @@ -498,154 +503,156 @@ msgstr "" msgid "Cancel" msgstr "" -#: mod/photos.php:822 +#: mod/photos.php:829 msgid "Edit Album" msgstr "" -#: mod/photos.php:823 +#: mod/photos.php:830 msgid "Drop Album" msgstr "" -#: mod/photos.php:827 +#: mod/photos.php:834 msgid "Show Newest First" msgstr "" -#: mod/photos.php:829 +#: mod/photos.php:836 msgid "Show Oldest First" msgstr "" -#: mod/photos.php:850 src/Module/Profile/Photos.php:350 +#: mod/photos.php:857 src/Module/Profile/Photos.php:350 msgid "View Photo" msgstr "" -#: mod/photos.php:883 +#: mod/photos.php:889 msgid "Permission denied. Access to this item may be restricted." msgstr "" -#: mod/photos.php:885 +#: mod/photos.php:891 msgid "Photo not available" msgstr "" -#: mod/photos.php:895 +#: mod/photos.php:901 msgid "Do you really want to delete this photo?" msgstr "" -#: mod/photos.php:896 mod/photos.php:1096 +#: mod/photos.php:902 mod/photos.php:1102 msgid "Delete Photo" msgstr "" -#: mod/photos.php:994 +#: mod/photos.php:1000 msgid "View photo" msgstr "" -#: mod/photos.php:996 +#: mod/photos.php:1002 msgid "Edit photo" msgstr "" -#: mod/photos.php:997 +#: mod/photos.php:1003 msgid "Delete photo" msgstr "" -#: mod/photos.php:998 +#: mod/photos.php:1004 msgid "Use as profile photo" msgstr "" -#: mod/photos.php:1005 +#: mod/photos.php:1011 msgid "Private Photo" msgstr "" -#: mod/photos.php:1011 +#: mod/photos.php:1017 msgid "View Full Size" msgstr "" -#: mod/photos.php:1064 +#: mod/photos.php:1070 msgid "Tags: " msgstr "" -#: mod/photos.php:1067 +#: mod/photos.php:1073 msgid "[Select tags to remove]" msgstr "" -#: mod/photos.php:1082 +#: mod/photos.php:1088 msgid "New album name" msgstr "" -#: mod/photos.php:1083 +#: mod/photos.php:1089 msgid "Caption" msgstr "" -#: mod/photos.php:1084 +#: mod/photos.php:1090 msgid "Add a Tag" msgstr "" -#: mod/photos.php:1084 +#: mod/photos.php:1090 msgid "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "" -#: mod/photos.php:1085 +#: mod/photos.php:1091 msgid "Do not rotate" msgstr "" -#: mod/photos.php:1086 +#: mod/photos.php:1092 msgid "Rotate CW (right)" msgstr "" -#: mod/photos.php:1087 +#: mod/photos.php:1093 msgid "Rotate CCW (left)" msgstr "" -#: mod/photos.php:1133 mod/photos.php:1189 mod/photos.php:1263 -#: src/Module/Contact.php:588 src/Module/Item/Compose.php:188 -#: src/Object/Post.php:1067 +#: mod/photos.php:1139 mod/photos.php:1195 mod/photos.php:1275 +#: src/Module/Contact.php:619 src/Module/Item/Compose.php:188 +#: src/Object/Post.php:1092 msgid "This is you" msgstr "" -#: mod/photos.php:1135 mod/photos.php:1191 mod/photos.php:1265 -#: src/Object/Post.php:551 src/Object/Post.php:1069 +#: mod/photos.php:1141 mod/photos.php:1197 mod/photos.php:1277 +#: src/Object/Post.php:572 src/Object/Post.php:1094 msgid "Comment" msgstr "" -#: mod/photos.php:1137 mod/photos.php:1193 mod/photos.php:1267 -#: src/Content/Conversation.php:405 src/Module/Calendar/Event/Form.php:248 -#: src/Module/Item/Compose.php:200 src/Module/Post/Edit.php:165 -#: src/Object/Post.php:1082 +#: mod/photos.php:1143 mod/photos.php:1199 mod/photos.php:1279 +#: src/Content/Conversation.php:413 src/Module/Calendar/Event/Form.php:248 +#: src/Module/Item/Compose.php:201 src/Module/Post/Edit.php:165 +#: src/Object/Post.php:1108 msgid "Preview" msgstr "" -#: mod/photos.php:1138 src/Content/Conversation.php:359 -#: src/Module/Post/Edit.php:130 src/Object/Post.php:1071 +#: mod/photos.php:1144 src/Content/Conversation.php:366 +#: src/Module/Post/Edit.php:130 src/Object/Post.php:1096 msgid "Loading..." msgstr "" -#: mod/photos.php:1224 src/Content/Conversation.php:650 src/Object/Post.php:258 +#: mod/photos.php:1236 src/Content/Conversation.php:1449 +#: src/Object/Post.php:260 msgid "Select" msgstr "" -#: mod/photos.php:1225 src/Content/Conversation.php:651 +#: mod/photos.php:1237 src/Content/Conversation.php:1450 #: 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:244 +#: src/Module/Settings/Server/Index.php:109 msgid "Delete" msgstr "" -#: mod/photos.php:1286 src/Object/Post.php:391 +#: mod/photos.php:1298 src/Object/Post.php:408 msgid "Like" msgstr "" -#: mod/photos.php:1287 src/Object/Post.php:391 +#: mod/photos.php:1299 src/Object/Post.php:408 msgid "I like this (toggle)" msgstr "" -#: mod/photos.php:1288 src/Object/Post.php:392 +#: mod/photos.php:1300 src/Object/Post.php:409 msgid "Dislike" msgstr "" -#: mod/photos.php:1290 src/Object/Post.php:392 +#: mod/photos.php:1302 src/Object/Post.php:409 msgid "I don't like this (toggle)" msgstr "" -#: mod/photos.php:1312 +#: mod/photos.php:1324 msgid "Map" msgstr "" @@ -657,97 +664,108 @@ 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:250 +#: src/App/Page.php:251 msgid "Collapse this author's posts?" msgstr "" #: src/App/Page.php:252 -msgid "Like not successful" +msgid "Ignore this author's server?" msgstr "" -#: src/App/Page.php:253 -msgid "Dislike not successful" -msgstr "" - -#: src/App/Page.php:254 -msgid "Sharing not successful" +#: src/App/Page.php:253 src/Module/Settings/Server/Action.php:61 +#: src/Module/Settings/Server/Index.php:108 +msgid "" +"You won't see any content from this server including reshares in your " +"Network page, the community pages and individual conversations." msgstr "" #: src/App/Page.php:255 -msgid "Attendance unsuccessful" +msgid "Like not successful" msgstr "" #: src/App/Page.php:256 -msgid "Backend error" +msgid "Dislike not successful" msgstr "" #: src/App/Page.php:257 -msgid "Network error" +msgid "Sharing not successful" +msgstr "" + +#: src/App/Page.php:258 +msgid "Attendance unsuccessful" +msgstr "" + +#: src/App/Page.php:259 +msgid "Backend error" msgstr "" #: src/App/Page.php:260 +msgid "Network error" +msgstr "" + +#: src/App/Page.php:263 msgid "Drop files here to upload" msgstr "" -#: src/App/Page.php:261 +#: src/App/Page.php:264 msgid "Your browser does not support drag and drop file uploads." msgstr "" -#: src/App/Page.php:262 +#: src/App/Page.php:265 msgid "" "Please use the fallback form below to upload your files like in the olden " "days." msgstr "" -#: src/App/Page.php:263 +#: src/App/Page.php:266 msgid "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB." msgstr "" -#: src/App/Page.php:264 +#: src/App/Page.php:267 msgid "You can't upload files of this type." msgstr "" -#: src/App/Page.php:265 +#: src/App/Page.php:268 msgid "Server responded with {{statusCode}} code." msgstr "" -#: src/App/Page.php:266 +#: src/App/Page.php:269 msgid "Cancel upload" msgstr "" -#: src/App/Page.php:267 +#: src/App/Page.php:270 msgid "Upload canceled." msgstr "" -#: src/App/Page.php:268 +#: src/App/Page.php:271 msgid "Are you sure you want to cancel this upload?" msgstr "" -#: src/App/Page.php:269 +#: src/App/Page.php:272 msgid "Remove file" msgstr "" -#: src/App/Page.php:270 +#: src/App/Page.php:273 msgid "You can't upload any more files." msgstr "" -#: src/App/Page.php:348 +#: src/App/Page.php:351 msgid "toggle mobile" msgstr "" @@ -764,31 +782,31 @@ msgstr "" msgid "You must be logged in to use addons. " msgstr "" -#: src/BaseModule.php:400 +#: src/BaseModule.php:401 msgid "" "The form security token was not correct. This probably happened because the " "form has been opened for too long (>3 hours) before submitting it." msgstr "" -#: src/BaseModule.php:427 +#: src/BaseModule.php:428 msgid "All contacts" msgstr "" -#: src/BaseModule.php:432 src/Content/Widget.php:243 src/Core/ACL.php:195 -#: src/Module/Contact.php:407 src/Module/PermissionTooltip.php:127 +#: src/BaseModule.php:433 src/Content/Widget.php:239 src/Core/ACL.php:195 +#: src/Module/Contact.php:415 src/Module/PermissionTooltip.php:127 #: src/Module/PermissionTooltip.php:149 msgid "Followers" msgstr "" -#: src/BaseModule.php:437 src/Content/Widget.php:244 src/Module/Contact.php:408 +#: src/BaseModule.php:438 src/Content/Widget.php:240 src/Module/Contact.php:418 msgid "Following" msgstr "" -#: src/BaseModule.php:442 src/Content/Widget.php:245 src/Module/Contact.php:409 +#: src/BaseModule.php:443 src/Content/Widget.php:241 src/Module/Contact.php:421 msgid "Mutual friends" msgstr "" -#: src/BaseModule.php:450 +#: src/BaseModule.php:451 msgid "Common" msgstr "" @@ -938,7 +956,7 @@ msgstr "" msgid "Enter user nickname: " msgstr "" -#: src/Console/User.php:182 src/Model/User.php:663 +#: src/Console/User.php:182 src/Model/User.php:693 #: src/Module/Api/Twitter/ContactEndpoint.php:74 #: src/Module/Moderation/Users/Active.php:71 #: src/Module/Moderation/Users/Blocked.php:71 @@ -1122,65 +1140,65 @@ msgstr "" msgid "%s (via %s)" msgstr "" -#: src/Content/Conversation.php:218 +#: src/Content/Conversation.php:225 msgid "and" msgstr "" -#: src/Content/Conversation.php:221 +#: src/Content/Conversation.php:228 #, php-format msgid "and %d other people" msgstr "" -#: src/Content/Conversation.php:227 +#: src/Content/Conversation.php:234 #, php-format msgid "%2$s likes this." msgid_plural "%2$s like this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:229 +#: src/Content/Conversation.php:236 #, php-format msgid "%2$s doesn't like this." msgid_plural "%2$s don't like this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:231 +#: src/Content/Conversation.php:238 #, php-format msgid "%2$s attends." msgid_plural "%2$s attend." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:233 +#: src/Content/Conversation.php:240 #, php-format msgid "%2$s doesn't attend." msgid_plural "%2$s don't attend." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:235 +#: src/Content/Conversation.php:242 #, php-format msgid "%2$s attends maybe." msgid_plural "%2$s attend maybe." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:237 +#: src/Content/Conversation.php:244 #, php-format msgid "%2$s reshared this." msgid_plural "%2$s reshared this." msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:266 +#: src/Content/Conversation.php:273 #, php-format msgid " likes this" msgid_plural " like this" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:269 +#: src/Content/Conversation.php:276 #, php-format msgid " doesn't like this" msgid_plural "" @@ -1188,302 +1206,312 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:272 +#: src/Content/Conversation.php:279 #, php-format msgid " attends" msgid_plural " attend" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:275 +#: src/Content/Conversation.php:282 #, php-format msgid " doesn't attend" msgid_plural " don't attend" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:278 +#: src/Content/Conversation.php:285 #, php-format msgid " attends maybe" msgid_plural " attend maybe" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:281 +#: src/Content/Conversation.php:288 #, php-format msgid " reshared this" msgid_plural " reshared this" msgstr[0] "" msgstr[1] "" -#: src/Content/Conversation.php:328 +#: src/Content/Conversation.php:335 msgid "Visible to everybody" msgstr "" -#: src/Content/Conversation.php:329 src/Module/Item/Compose.php:199 -#: src/Object/Post.php:1081 +#: src/Content/Conversation.php:336 src/Module/Item/Compose.php:200 +#: src/Object/Post.php:1107 msgid "Please enter a image/video/audio/webpage URL:" msgstr "" -#: src/Content/Conversation.php:330 +#: src/Content/Conversation.php:337 msgid "Tag term:" msgstr "" -#: src/Content/Conversation.php:331 src/Module/Filer/SaveTag.php:73 +#: src/Content/Conversation.php:338 src/Module/Filer/SaveTag.php:73 msgid "Save to Folder:" msgstr "" -#: src/Content/Conversation.php:332 +#: src/Content/Conversation.php:339 msgid "Where are you right now?" msgstr "" -#: src/Content/Conversation.php:333 +#: src/Content/Conversation.php:340 msgid "Delete item(s)?" msgstr "" -#: src/Content/Conversation.php:345 src/Module/Item/Compose.php:175 +#: src/Content/Conversation.php:352 src/Module/Item/Compose.php:175 msgid "Created at" msgstr "" -#: src/Content/Conversation.php:355 +#: src/Content/Conversation.php:362 msgid "New Post" msgstr "" -#: src/Content/Conversation.php:358 +#: src/Content/Conversation.php:365 msgid "Share" msgstr "" -#: src/Content/Conversation.php:361 src/Module/Post/Edit.php:132 +#: src/Content/Conversation.php:368 src/Module/Post/Edit.php:132 msgid "upload photo" msgstr "" -#: src/Content/Conversation.php:362 src/Module/Post/Edit.php:133 +#: src/Content/Conversation.php:369 src/Module/Post/Edit.php:133 msgid "Attach file" msgstr "" -#: src/Content/Conversation.php:363 src/Module/Post/Edit.php:134 +#: src/Content/Conversation.php:370 src/Module/Post/Edit.php:134 msgid "attach file" msgstr "" -#: src/Content/Conversation.php:364 src/Module/Item/Compose.php:190 -#: src/Module/Post/Edit.php:171 src/Object/Post.php:1072 +#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:190 +#: src/Module/Post/Edit.php:171 src/Object/Post.php:1097 msgid "Bold" msgstr "" -#: src/Content/Conversation.php:365 src/Module/Item/Compose.php:191 -#: src/Module/Post/Edit.php:172 src/Object/Post.php:1073 +#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:191 +#: src/Module/Post/Edit.php:172 src/Object/Post.php:1098 msgid "Italic" msgstr "" -#: src/Content/Conversation.php:366 src/Module/Item/Compose.php:192 -#: src/Module/Post/Edit.php:173 src/Object/Post.php:1074 +#: src/Content/Conversation.php:373 src/Module/Item/Compose.php:192 +#: src/Module/Post/Edit.php:173 src/Object/Post.php:1099 msgid "Underline" msgstr "" -#: src/Content/Conversation.php:367 src/Module/Item/Compose.php:193 -#: src/Module/Post/Edit.php:174 src/Object/Post.php:1075 +#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:193 +#: src/Module/Post/Edit.php:174 src/Object/Post.php:1101 msgid "Quote" msgstr "" -#: src/Content/Conversation.php:368 src/Module/Item/Compose.php:194 -#: src/Module/Post/Edit.php:175 src/Object/Post.php:1076 +#: src/Content/Conversation.php:375 src/Module/Item/Compose.php:194 +#: src/Module/Post/Edit.php:175 src/Object/Post.php:1102 msgid "Add emojis" msgstr "" -#: src/Content/Conversation.php:369 src/Module/Item/Compose.php:195 -#: src/Module/Post/Edit.php:176 src/Object/Post.php:1077 +#: src/Content/Conversation.php:376 src/Module/Item/Compose.php:195 +#: src/Object/Post.php:1100 +msgid "Content Warning" +msgstr "" + +#: src/Content/Conversation.php:377 src/Module/Item/Compose.php:196 +#: src/Module/Post/Edit.php:176 src/Object/Post.php:1103 msgid "Code" msgstr "" -#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:196 -#: src/Object/Post.php:1078 +#: src/Content/Conversation.php:378 src/Module/Item/Compose.php:197 +#: src/Object/Post.php:1104 msgid "Image" msgstr "" -#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:197 -#: src/Module/Post/Edit.php:177 src/Object/Post.php:1079 +#: src/Content/Conversation.php:379 src/Module/Item/Compose.php:198 +#: src/Module/Post/Edit.php:177 src/Object/Post.php:1105 msgid "Link" msgstr "" -#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:198 -#: src/Module/Post/Edit.php:178 src/Object/Post.php:1080 +#: src/Content/Conversation.php:380 src/Module/Item/Compose.php:199 +#: src/Module/Post/Edit.php:178 src/Object/Post.php:1106 msgid "Link or Media" msgstr "" -#: src/Content/Conversation.php:373 +#: src/Content/Conversation.php:381 msgid "Video" msgstr "" -#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:201 +#: src/Content/Conversation.php:382 src/Module/Item/Compose.php:202 #: src/Module/Post/Edit.php:141 msgid "Set your location" msgstr "" -#: src/Content/Conversation.php:375 src/Module/Post/Edit.php:142 +#: src/Content/Conversation.php:383 src/Module/Post/Edit.php:142 msgid "set location" msgstr "" -#: src/Content/Conversation.php:376 src/Module/Post/Edit.php:143 +#: src/Content/Conversation.php:384 src/Module/Post/Edit.php:143 msgid "Clear browser location" msgstr "" -#: src/Content/Conversation.php:377 src/Module/Post/Edit.php:144 +#: src/Content/Conversation.php:385 src/Module/Post/Edit.php:144 msgid "clear location" msgstr "" -#: src/Content/Conversation.php:379 src/Module/Item/Compose.php:206 +#: src/Content/Conversation.php:387 src/Module/Item/Compose.php:207 #: src/Module/Post/Edit.php:157 msgid "Set title" msgstr "" -#: src/Content/Conversation.php:381 src/Module/Item/Compose.php:207 +#: src/Content/Conversation.php:389 src/Module/Item/Compose.php:208 #: src/Module/Post/Edit.php:159 msgid "Categories (comma-separated list)" msgstr "" -#: src/Content/Conversation.php:386 src/Module/Item/Compose.php:223 +#: src/Content/Conversation.php:394 src/Module/Item/Compose.php:224 msgid "Scheduled at" msgstr "" -#: src/Content/Conversation.php:391 src/Module/Post/Edit.php:146 +#: src/Content/Conversation.php:399 src/Module/Post/Edit.php:146 msgid "Permission settings" msgstr "" -#: src/Content/Conversation.php:401 src/Module/Post/Edit.php:155 +#: src/Content/Conversation.php:409 src/Module/Post/Edit.php:155 msgid "Public post" msgstr "" -#: src/Content/Conversation.php:415 src/Content/Widget/VCard.php:113 -#: src/Model/Profile.php:469 src/Module/Admin/Logs/View.php:92 +#: src/Content/Conversation.php:423 src/Content/Widget/VCard.php:120 +#: src/Model/Profile.php:467 src/Module/Admin/Logs/View.php:92 #: src/Module/Post/Edit.php:181 msgid "Message" msgstr "" -#: src/Content/Conversation.php:416 src/Module/Post/Edit.php:182 +#: src/Content/Conversation.php:424 src/Module/Post/Edit.php:182 #: src/Module/Settings/TwoFactor/Trusted.php:140 msgid "Browser" msgstr "" -#: src/Content/Conversation.php:418 src/Module/Post/Edit.php:185 +#: src/Content/Conversation.php:426 src/Module/Post/Edit.php:185 msgid "Open Compose page" msgstr "" -#: src/Content/Conversation.php:678 src/Object/Post.php:244 -msgid "Pinned item" -msgstr "" - -#: src/Content/Conversation.php:694 src/Object/Post.php:502 -#: src/Object/Post.php:503 -#, php-format -msgid "View %s's profile @ %s" -msgstr "" - -#: src/Content/Conversation.php:707 src/Object/Post.php:490 -msgid "Categories:" -msgstr "" - -#: src/Content/Conversation.php:708 src/Object/Post.php:491 -msgid "Filed under:" -msgstr "" - -#: src/Content/Conversation.php:716 src/Object/Post.php:516 -#, php-format -msgid "%s from %s" -msgstr "" - -#: src/Content/Conversation.php:732 -msgid "View in context" -msgstr "" - -#: src/Content/Conversation.php:797 +#: src/Content/Conversation.php:581 msgid "remove" msgstr "" -#: src/Content/Conversation.php:801 +#: src/Content/Conversation.php:585 msgid "Delete Selected Items" msgstr "" -#: src/Content/Conversation.php:866 src/Content/Conversation.php:869 -#: src/Content/Conversation.php:872 src/Content/Conversation.php:875 -#: src/Content/Conversation.php:878 +#: src/Content/Conversation.php:740 src/Content/Conversation.php:743 +#: src/Content/Conversation.php:746 src/Content/Conversation.php:749 +#: src/Content/Conversation.php:752 #, php-format msgid "You had been addressed (%s)." msgstr "" -#: src/Content/Conversation.php:881 +#: src/Content/Conversation.php:755 #, php-format msgid "You are following %s." msgstr "" -#: src/Content/Conversation.php:884 +#: src/Content/Conversation.php:760 +#, php-format +msgid "You subscribed to %s." +msgstr "" + +#: src/Content/Conversation.php:762 msgid "You subscribed to one or more tags in this post." msgstr "" -#: src/Content/Conversation.php:897 +#: src/Content/Conversation.php:782 #, php-format msgid "%s reshared this." msgstr "" -#: src/Content/Conversation.php:899 +#: src/Content/Conversation.php:784 msgid "Reshared" msgstr "" -#: src/Content/Conversation.php:899 +#: src/Content/Conversation.php:784 #, php-format msgid "Reshared by %s <%s>" msgstr "" -#: src/Content/Conversation.php:902 +#: src/Content/Conversation.php:787 #, php-format msgid "%s is participating in this thread." msgstr "" -#: src/Content/Conversation.php:905 +#: src/Content/Conversation.php:790 msgid "Stored for general reasons" msgstr "" -#: src/Content/Conversation.php:908 +#: src/Content/Conversation.php:793 msgid "Global post" msgstr "" -#: src/Content/Conversation.php:911 +#: src/Content/Conversation.php:796 msgid "Sent via an relay server" msgstr "" -#: src/Content/Conversation.php:911 +#: src/Content/Conversation.php:796 #, php-format msgid "Sent via the relay server %s <%s>" msgstr "" -#: src/Content/Conversation.php:914 +#: src/Content/Conversation.php:799 msgid "Fetched" msgstr "" -#: src/Content/Conversation.php:914 +#: src/Content/Conversation.php:799 #, php-format msgid "Fetched because of %s <%s>" msgstr "" -#: src/Content/Conversation.php:917 +#: src/Content/Conversation.php:802 msgid "Stored because of a child post to complete this thread." msgstr "" -#: src/Content/Conversation.php:920 +#: src/Content/Conversation.php:805 msgid "Local delivery" msgstr "" -#: src/Content/Conversation.php:923 +#: src/Content/Conversation.php:808 msgid "Stored because of your activity (like, comment, star, ...)" msgstr "" -#: src/Content/Conversation.php:926 +#: src/Content/Conversation.php:811 msgid "Distributed" msgstr "" -#: src/Content/Conversation.php:929 +#: src/Content/Conversation.php:814 msgid "Pushed to us" msgstr "" +#: src/Content/Conversation.php:1477 src/Object/Post.php:247 +msgid "Pinned item" +msgstr "" + +#: src/Content/Conversation.php:1494 src/Object/Post.php:521 +#: src/Object/Post.php:522 +#, php-format +msgid "View %s's profile @ %s" +msgstr "" + +#: src/Content/Conversation.php:1507 src/Object/Post.php:509 +msgid "Categories:" +msgstr "" + +#: src/Content/Conversation.php:1508 src/Object/Post.php:510 +msgid "Filed under:" +msgstr "" + +#: src/Content/Conversation.php:1516 src/Object/Post.php:535 +#, php-format +msgid "%s from %s" +msgstr "" + +#: src/Content/Conversation.php:1532 +msgid "View in context" +msgstr "" + #: src/Content/Feature.php:96 msgid "General Features" msgstr "" @@ -1513,12 +1541,12 @@ msgid "Post Composition Features" msgstr "" #: src/Content/Feature.php:105 -msgid "Auto-mention Forums" +msgid "Auto-mention Groups" msgstr "" #: src/Content/Feature.php:105 msgid "" -"Add/remove mention when a forum page is selected/deselected in ACL window." +"Add/remove mention when a group page is selected/deselected in ACL window." msgstr "" #: src/Content/Feature.php:106 @@ -1559,11 +1587,11 @@ msgid "Advanced Profile Settings" msgstr "" #: src/Content/Feature.php:119 -msgid "List Forums" +msgid "List Groups" msgstr "" #: src/Content/Feature.php:119 -msgid "Show visitors public community forums at the Advanced Profile Page" +msgid "Show visitors public groups at the Advanced Profile Page" msgstr "" #: src/Content/Feature.php:120 @@ -1596,106 +1624,116 @@ msgid "" "Contact birthday events are private to you." msgstr "" -#: src/Content/ForumManager.php:151 src/Content/Nav.php:276 -#: src/Content/Text/HTML.php:877 src/Content/Widget.php:532 -msgid "Forums" +#: src/Content/GroupManager.php:152 src/Content/Nav.php:276 +#: src/Content/Text/HTML.php:880 src/Content/Widget.php:537 +#: src/Model/User.php:1255 +msgid "Groups" msgstr "" -#: src/Content/ForumManager.php:153 -msgid "External link to forum" +#: src/Content/GroupManager.php:154 +msgid "External link to group" msgstr "" -#: src/Content/ForumManager.php:156 src/Content/Widget.php:511 +#: src/Content/GroupManager.php:158 src/Content/Widget.php:512 msgid "show less" msgstr "" -#: src/Content/ForumManager.php:157 src/Content/Widget.php:413 -#: src/Content/Widget.php:512 +#: src/Content/GroupManager.php:159 src/Content/Widget.php:410 +#: src/Content/Widget.php:513 msgid "show more" msgstr "" -#: src/Content/Item.php:327 src/Model/Item.php:2927 +#: src/Content/GroupManager.php:160 +msgid "Create new group" +msgstr "" + +#: src/Content/Item.php:331 src/Model/Item.php:3002 msgid "event" msgstr "" -#: src/Content/Item.php:330 src/Content/Item.php:340 +#: src/Content/Item.php:334 src/Content/Item.php:344 msgid "status" msgstr "" -#: src/Content/Item.php:336 src/Model/Item.php:2929 +#: src/Content/Item.php:340 src/Model/Item.php:3004 #: src/Module/Post/Tag/Add.php:123 msgid "photo" msgstr "" -#: src/Content/Item.php:350 src/Module/Post/Tag/Add.php:141 +#: src/Content/Item.php:354 src/Module/Post/Tag/Add.php:141 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "" -#: src/Content/Item.php:418 view/theme/frio/theme.php:262 +#: src/Content/Item.php:428 view/theme/frio/theme.php:262 msgid "Follow Thread" msgstr "" -#: src/Content/Item.php:419 src/Model/Contact.php:1199 +#: src/Content/Item.php:429 src/Model/Contact.php:1211 msgid "View Status" msgstr "" -#: src/Content/Item.php:420 src/Content/Item.php:440 src/Model/Contact.php:1148 -#: src/Model/Contact.php:1191 src/Model/Contact.php:1200 -#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:233 +#: src/Content/Item.php:430 src/Content/Item.php:451 src/Model/Contact.php:1160 +#: src/Model/Contact.php:1203 src/Model/Contact.php:1212 +#: src/Module/Directory.php:157 src/Module/Settings/Profile/Index.php:259 msgid "View Profile" msgstr "" -#: src/Content/Item.php:421 src/Model/Contact.php:1201 +#: src/Content/Item.php:431 src/Model/Contact.php:1213 msgid "View Photos" msgstr "" -#: src/Content/Item.php:422 src/Model/Contact.php:1192 -#: src/Model/Contact.php:1202 +#: src/Content/Item.php:432 src/Model/Contact.php:1204 +#: src/Model/Contact.php:1214 msgid "Network Posts" msgstr "" -#: src/Content/Item.php:423 src/Model/Contact.php:1193 -#: src/Model/Contact.php:1203 +#: src/Content/Item.php:433 src/Model/Contact.php:1205 +#: src/Model/Contact.php:1215 msgid "View Contact" msgstr "" -#: src/Content/Item.php:424 src/Model/Contact.php:1204 +#: src/Content/Item.php:434 src/Model/Contact.php:1216 msgid "Send PM" msgstr "" -#: src/Content/Item.php:425 src/Module/Contact.php:439 -#: src/Module/Contact/Profile.php:477 +#: src/Content/Item.php:435 src/Module/Contact.php:468 +#: src/Module/Contact/Profile.php:498 #: src/Module/Moderation/Blocklist/Contact.php:116 #: src/Module/Moderation/Users/Active.php:137 #: src/Module/Moderation/Users/Index.php:152 msgid "Block" msgstr "" -#: src/Content/Item.php:426 src/Module/Contact.php:440 -#: src/Module/Contact/Profile.php:485 +#: src/Content/Item.php:436 src/Module/Contact.php:469 +#: src/Module/Contact/Profile.php:506 #: src/Module/Notifications/Introductions.php:134 #: src/Module/Notifications/Introductions.php:206 #: src/Module/Notifications/Notification.php:89 msgid "Ignore" msgstr "" -#: src/Content/Item.php:427 src/Module/Contact.php:441 -#: src/Module/Contact/Profile.php:493 +#: src/Content/Item.php:437 src/Module/Contact.php:470 +#: src/Module/Contact/Profile.php:514 msgid "Collapse" msgstr "" -#: src/Content/Item.php:431 src/Object/Post.php:471 +#: src/Content/Item.php:438 src/Object/Post.php:288 +#, php-format +msgid "Ignore %s server" +msgstr "" + +#: src/Content/Item.php:442 src/Object/Post.php:490 msgid "Languages" msgstr "" -#: src/Content/Item.php:437 src/Content/Widget.php:80 -#: src/Model/Contact.php:1194 src/Model/Contact.php:1205 +#: src/Content/Item.php:448 src/Content/Widget.php:80 +#: src/Model/Contact.php:1206 src/Model/Contact.php:1217 #: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:195 msgid "Connect/Follow" msgstr "" -#: src/Content/Item.php:862 +#: src/Content/Item.php:882 msgid "Unable to fetch user." msgstr "" @@ -1711,8 +1749,8 @@ msgstr "" msgid "Clear notifications" msgstr "" -#: src/Content/Nav.php:126 src/Content/Text/HTML.php:864 -msgid "@name, !forum, #tags, content" +#: src/Content/Nav.php:126 src/Content/Text/HTML.php:867 +msgid "@name, !group, #tags, content" msgstr "" #: src/Content/Nav.php:220 src/Module/Security/Login.php:157 @@ -1733,7 +1771,7 @@ msgid "Sign in" msgstr "" #: src/Content/Nav.php:227 src/Module/BaseProfile.php:57 -#: src/Module/Contact.php:483 +#: src/Module/Contact.php:512 msgid "Conversations" msgstr "" @@ -1742,8 +1780,8 @@ msgid "Conversations you started" msgstr "" #: src/Content/Nav.php:228 src/Module/BaseProfile.php:49 -#: src/Module/BaseSettings.php:100 src/Module/Contact.php:475 -#: src/Module/Contact/Profile.php:392 src/Module/Profile/Profile.php:268 +#: src/Module/BaseSettings.php:100 src/Module/Contact.php:504 +#: src/Module/Contact/Profile.php:413 src/Module/Profile/Profile.php:268 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:230 msgid "Profile" msgstr "" @@ -1762,7 +1800,7 @@ msgid "Your photos" msgstr "" #: src/Content/Nav.php:230 src/Module/BaseProfile.php:73 -#: src/Module/BaseProfile.php:76 src/Module/Contact.php:499 +#: src/Module/BaseProfile.php:76 src/Module/Contact.php:528 #: view/theme/frio/theme.php:235 msgid "Media" msgstr "" @@ -1828,7 +1866,7 @@ msgstr "" msgid "Addon applications, utilities, games" msgstr "" -#: src/Content/Nav.php:267 src/Content/Text/HTML.php:862 +#: src/Content/Nav.php:267 src/Content/Text/HTML.php:865 #: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:112 msgid "Search" msgstr "" @@ -1837,19 +1875,19 @@ msgstr "" msgid "Search site content" msgstr "" -#: src/Content/Nav.php:270 src/Content/Text/HTML.php:871 +#: src/Content/Nav.php:270 src/Content/Text/HTML.php:874 msgid "Full Text" msgstr "" -#: src/Content/Nav.php:271 src/Content/Text/HTML.php:872 +#: src/Content/Nav.php:271 src/Content/Text/HTML.php:875 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "" #: src/Content/Nav.php:272 src/Content/Nav.php:327 -#: src/Content/Text/HTML.php:873 src/Module/BaseProfile.php:127 -#: src/Module/BaseProfile.php:130 src/Module/Contact.php:410 -#: src/Module/Contact.php:506 view/theme/frio/theme.php:243 +#: src/Content/Text/HTML.php:876 src/Module/BaseProfile.php:127 +#: src/Module/BaseProfile.php:130 src/Module/Contact.php:427 +#: src/Module/Contact.php:536 view/theme/frio/theme.php:243 msgid "Contacts" msgstr "" @@ -1880,7 +1918,7 @@ msgstr "" #: src/Content/Nav.php:299 src/Module/Admin/Tos.php:78 #: src/Module/BaseAdmin.php:95 src/Module/Register.php:176 -#: src/Module/Tos.php:100 +#: src/Module/Tos.php:101 msgid "Terms of Service" msgstr "" @@ -1946,7 +1984,7 @@ msgid "Manage other pages" msgstr "" #: src/Content/Nav.php:325 src/Module/Admin/Addons/Details.php:114 -#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:170 +#: src/Module/Admin/Themes/Details.php:93 src/Module/BaseSettings.php:177 #: src/Module/Welcome.php:52 view/theme/frio/theme.php:242 msgid "Settings" msgstr "" @@ -1993,11 +2031,11 @@ msgstr "" msgid "Site map" msgstr "" -#: src/Content/OEmbed.php:317 +#: src/Content/OEmbed.php:316 msgid "Embedding disabled" msgstr "" -#: src/Content/OEmbed.php:441 +#: src/Content/OEmbed.php:440 msgid "Embedded content" msgstr "" @@ -2017,52 +2055,52 @@ msgstr "" msgid "last" msgstr "" -#: src/Content/Text/BBCode.php:713 src/Content/Text/BBCode.php:1619 -#: src/Content/Text/BBCode.php:1620 +#: src/Content/Text/BBCode.php:696 src/Content/Text/BBCode.php:1636 +#: src/Content/Text/BBCode.php:1637 msgid "Image/photo" msgstr "" -#: src/Content/Text/BBCode.php:931 +#: src/Content/Text/BBCode.php:914 #, php-format msgid "" "%2$s %3$s" msgstr "" -#: src/Content/Text/BBCode.php:956 src/Model/Item.php:3645 -#: src/Model/Item.php:3651 src/Model/Item.php:3652 +#: src/Content/Text/BBCode.php:939 src/Model/Item.php:3744 +#: src/Model/Item.php:3750 src/Model/Item.php:3751 msgid "Link to source" msgstr "" -#: src/Content/Text/BBCode.php:1526 src/Content/Text/HTML.php:901 +#: src/Content/Text/BBCode.php:1543 src/Content/Text/HTML.php:904 msgid "Click to open/close" msgstr "" -#: src/Content/Text/BBCode.php:1559 +#: src/Content/Text/BBCode.php:1576 msgid "$1 wrote:" msgstr "" -#: src/Content/Text/BBCode.php:1624 src/Content/Text/BBCode.php:1625 +#: src/Content/Text/BBCode.php:1641 src/Content/Text/BBCode.php:1642 msgid "Encrypted content" msgstr "" -#: src/Content/Text/BBCode.php:1889 +#: src/Content/Text/BBCode.php:1897 msgid "Invalid source protocol" msgstr "" -#: src/Content/Text/BBCode.php:1908 +#: src/Content/Text/BBCode.php:1916 msgid "Invalid link protocol" msgstr "" -#: src/Content/Text/HTML.php:779 +#: src/Content/Text/HTML.php:782 msgid "Loading more entries..." msgstr "" -#: src/Content/Text/HTML.php:780 +#: src/Content/Text/HTML.php:783 msgid "The end" msgstr "" -#: src/Content/Text/HTML.php:856 src/Content/Widget/VCard.php:109 -#: src/Model/Profile.php:463 src/Module/Contact/Profile.php:437 +#: src/Content/Text/HTML.php:859 src/Content/Widget/VCard.php:116 +#: src/Model/Profile.php:461 src/Module/Contact/Profile.php:458 msgid "Follow" msgstr "" @@ -2101,7 +2139,7 @@ msgstr "" msgid "Examples: Robert Morgenstein, Fishing" msgstr "" -#: src/Content/Widget.php:82 src/Module/Contact.php:432 +#: src/Content/Widget.php:82 src/Module/Contact.php:461 #: src/Module/Directory.php:96 view/theme/vier/theme.php:197 msgid "Find" msgstr "" @@ -2132,72 +2170,80 @@ msgstr "" msgid "Local Directory" msgstr "" -#: src/Content/Widget.php:219 src/Model/Group.php:596 -#: src/Module/Contact.php:394 src/Module/Welcome.php:76 -msgid "Groups" +#: src/Content/Widget.php:215 src/Model/Circle.php:600 +#: src/Module/Contact.php:401 src/Module/Welcome.php:76 +msgid "Circles" msgstr "" -#: src/Content/Widget.php:221 +#: src/Content/Widget.php:217 msgid "Everyone" msgstr "" -#: src/Content/Widget.php:250 +#: src/Content/Widget.php:242 src/Module/Contact.php:424 +msgid "No relationship" +msgstr "" + +#: src/Content/Widget.php:247 msgid "Relationships" msgstr "" -#: src/Content/Widget.php:252 src/Module/Contact.php:338 -#: src/Module/Group.php:291 +#: src/Content/Widget.php:249 src/Module/Circle.php:292 +#: src/Module/Contact.php:345 msgid "All Contacts" msgstr "" -#: src/Content/Widget.php:291 +#: src/Content/Widget.php:288 msgid "Protocols" msgstr "" -#: src/Content/Widget.php:293 +#: src/Content/Widget.php:290 msgid "All Protocols" msgstr "" -#: src/Content/Widget.php:321 +#: src/Content/Widget.php:318 msgid "Saved Folders" msgstr "" -#: src/Content/Widget.php:323 src/Content/Widget.php:354 +#: src/Content/Widget.php:320 src/Content/Widget.php:351 msgid "Everything" msgstr "" -#: src/Content/Widget.php:352 +#: src/Content/Widget.php:349 msgid "Categories" msgstr "" -#: src/Content/Widget.php:409 +#: src/Content/Widget.php:406 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "" msgstr[1] "" -#: src/Content/Widget.php:505 +#: src/Content/Widget.php:506 msgid "Archives" msgstr "" -#: src/Content/Widget.php:529 +#: src/Content/Widget.php:514 +msgid "On this date" +msgstr "" + +#: src/Content/Widget.php:534 msgid "Persons" msgstr "" -#: src/Content/Widget.php:530 +#: src/Content/Widget.php:535 msgid "Organisations" msgstr "" -#: src/Content/Widget.php:531 src/Model/Contact.php:1651 +#: src/Content/Widget.php:536 src/Model/Contact.php:1681 msgid "News" msgstr "" -#: src/Content/Widget.php:535 src/Module/Settings/Account.php:453 +#: src/Content/Widget.php:542 src/Module/Settings/Account.php:454 msgid "Account Types" msgstr "" -#: src/Content/Widget.php:536 src/Module/Moderation/BaseUsers.php:69 +#: src/Content/Widget.php:544 src/Module/Moderation/BaseUsers.php:69 msgid "All" msgstr "" @@ -2247,32 +2293,32 @@ msgstr[1] "" msgid "More Trending Tags" msgstr "" -#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:378 -#: src/Module/Contact/Profile.php:381 src/Module/Profile/Profile.php:199 +#: src/Content/Widget/VCard.php:109 src/Model/Profile.php:376 +#: src/Module/Contact/Profile.php:402 src/Module/Profile/Profile.php:199 msgid "XMPP:" msgstr "" -#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:379 -#: src/Module/Contact/Profile.php:383 src/Module/Profile/Profile.php:203 +#: src/Content/Widget/VCard.php:110 src/Model/Profile.php:377 +#: src/Module/Contact/Profile.php:404 src/Module/Profile/Profile.php:203 msgid "Matrix:" msgstr "" -#: src/Content/Widget/VCard.php:104 src/Model/Event.php:82 -#: src/Model/Event.php:109 src/Model/Event.php:473 src/Model/Event.php:958 -#: src/Model/Profile.php:373 src/Module/Contact/Profile.php:379 +#: src/Content/Widget/VCard.php:111 src/Model/Event.php:82 +#: src/Model/Event.php:109 src/Model/Event.php:471 src/Model/Event.php:963 +#: src/Model/Profile.php:371 src/Module/Contact/Profile.php:400 #: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187 #: src/Module/Profile/Profile.php:221 msgid "Location:" msgstr "" -#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:476 +#: src/Content/Widget/VCard.php:114 src/Model/Profile.php:474 #: src/Module/Notifications/Introductions.php:201 msgid "Network:" msgstr "" -#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1195 -#: src/Model/Contact.php:1206 src/Model/Profile.php:465 -#: src/Module/Contact/Profile.php:429 +#: src/Content/Widget/VCard.php:118 src/Model/Contact.php:1207 +#: src/Model/Contact.php:1218 src/Model/Profile.php:463 +#: src/Module/Contact/Profile.php:450 msgid "Unfollow" msgstr "" @@ -2313,8 +2359,8 @@ msgstr "" #: src/Core/ACL.php:324 msgid "" -"Start typing the name of a contact or a group to show a filtered list. You " -"can also mention the special groups \"Followers\" and \"Mutuals\"." +"Start typing the name of a contact or a circle to show a filtered list. You " +"can also mention the special circles \"Followers\" and \"Mutuals\"." msgstr "" #: src/Core/ACL.php:325 @@ -2655,142 +2701,142 @@ msgstr "" msgid "Could not connect to database." msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:432 +#: src/Core/L10n.php:408 src/Model/Event.php:430 #: src/Module/Settings/Display.php:222 msgid "Monday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:433 +#: src/Core/L10n.php:408 src/Model/Event.php:431 #: src/Module/Settings/Display.php:223 msgid "Tuesday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:434 +#: src/Core/L10n.php:408 src/Model/Event.php:432 #: src/Module/Settings/Display.php:224 msgid "Wednesday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:435 +#: src/Core/L10n.php:408 src/Model/Event.php:433 #: src/Module/Settings/Display.php:225 msgid "Thursday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:436 +#: src/Core/L10n.php:408 src/Model/Event.php:434 #: src/Module/Settings/Display.php:226 msgid "Friday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:437 +#: src/Core/L10n.php:408 src/Model/Event.php:435 #: src/Module/Settings/Display.php:227 msgid "Saturday" msgstr "" -#: src/Core/L10n.php:408 src/Model/Event.php:431 +#: src/Core/L10n.php:408 src/Model/Event.php:429 #: src/Module/Settings/Display.php:221 msgid "Sunday" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:452 +#: src/Core/L10n.php:412 src/Model/Event.php:450 msgid "January" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:453 +#: src/Core/L10n.php:412 src/Model/Event.php:451 msgid "February" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:454 +#: src/Core/L10n.php:412 src/Model/Event.php:452 msgid "March" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:455 +#: src/Core/L10n.php:412 src/Model/Event.php:453 msgid "April" msgstr "" -#: src/Core/L10n.php:412 src/Core/L10n.php:431 src/Model/Event.php:443 +#: src/Core/L10n.php:412 src/Core/L10n.php:431 src/Model/Event.php:441 msgid "May" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:456 +#: src/Core/L10n.php:412 src/Model/Event.php:454 msgid "June" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:457 +#: src/Core/L10n.php:412 src/Model/Event.php:455 msgid "July" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:458 +#: src/Core/L10n.php:412 src/Model/Event.php:456 msgid "August" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:459 +#: src/Core/L10n.php:412 src/Model/Event.php:457 msgid "September" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:460 +#: src/Core/L10n.php:412 src/Model/Event.php:458 msgid "October" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:461 +#: src/Core/L10n.php:412 src/Model/Event.php:459 msgid "November" msgstr "" -#: src/Core/L10n.php:412 src/Model/Event.php:462 +#: src/Core/L10n.php:412 src/Model/Event.php:460 msgid "December" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:424 +#: src/Core/L10n.php:427 src/Model/Event.php:422 msgid "Mon" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:425 +#: src/Core/L10n.php:427 src/Model/Event.php:423 msgid "Tue" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:426 +#: src/Core/L10n.php:427 src/Model/Event.php:424 msgid "Wed" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:427 +#: src/Core/L10n.php:427 src/Model/Event.php:425 msgid "Thu" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:428 +#: src/Core/L10n.php:427 src/Model/Event.php:426 msgid "Fri" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:429 +#: src/Core/L10n.php:427 src/Model/Event.php:427 msgid "Sat" msgstr "" -#: src/Core/L10n.php:427 src/Model/Event.php:423 +#: src/Core/L10n.php:427 src/Model/Event.php:421 msgid "Sun" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:439 +#: src/Core/L10n.php:431 src/Model/Event.php:437 msgid "Jan" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:440 +#: src/Core/L10n.php:431 src/Model/Event.php:438 msgid "Feb" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:441 +#: src/Core/L10n.php:431 src/Model/Event.php:439 msgid "Mar" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:442 +#: src/Core/L10n.php:431 src/Model/Event.php:440 msgid "Apr" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:444 +#: src/Core/L10n.php:431 src/Model/Event.php:442 msgid "Jun" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:445 +#: src/Core/L10n.php:431 src/Model/Event.php:443 msgid "Jul" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:446 +#: src/Core/L10n.php:431 src/Model/Event.php:444 msgid "Aug" msgstr "" @@ -2798,18 +2844,28 @@ msgstr "" msgid "Sep" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:448 +#: src/Core/L10n.php:431 src/Model/Event.php:446 msgid "Oct" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:449 +#: src/Core/L10n.php:431 src/Model/Event.php:447 msgid "Nov" msgstr "" -#: src/Core/L10n.php:431 src/Model/Event.php:450 +#: src/Core/L10n.php:431 src/Model/Event.php:448 msgid "Dec" msgstr "" +#: src/Core/Logger/Util/LoggerSettingsCheck.php:60 +#, php-format +msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" +msgstr "" + +#: src/Core/Logger/Util/LoggerSettingsCheck.php:85 +#, php-format +msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')" +msgstr "" + #: src/Core/Renderer.php:89 src/Core/Renderer.php:118 src/Core/Renderer.php:147 #: src/Core/Renderer.php:181 src/Render/FriendicaSmartyEngine.php:60 msgid "" @@ -2974,82 +3030,122 @@ msgstr "" msgid "Legacy module file not found: %s" msgstr "" -#: src/Model/Contact.php:1212 src/Module/Moderation/Users/Pending.php:102 +#: src/Model/Circle.php:106 +msgid "" +"A deleted circle with this name was revived. Existing item permissions " +"may apply to this circle and any future members. If this is " +"not what you intended, please create another circle with a different name." +msgstr "" + +#: src/Model/Circle.php:543 +msgid "Everybody" +msgstr "" + +#: src/Model/Circle.php:562 +msgid "edit" +msgstr "" + +#: src/Model/Circle.php:599 +msgid "add" +msgstr "" + +#: src/Model/Circle.php:604 +msgid "Edit circle" +msgstr "" + +#: src/Model/Circle.php:605 src/Module/Circle.php:193 +msgid "Contacts not in any circle" +msgstr "" + +#: src/Model/Circle.php:607 +msgid "Create a new circle" +msgstr "" + +#: src/Model/Circle.php:608 src/Module/Circle.php:178 src/Module/Circle.php:201 +#: src/Module/Circle.php:276 +msgid "Circle Name: " +msgstr "" + +#: src/Model/Circle.php:609 +msgid "Edit circles" +msgstr "" + +#: src/Model/Contact.php:1224 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:1647 +#: src/Model/Contact.php:1677 msgid "Organisation" msgstr "" -#: src/Model/Contact.php:1655 -msgid "Forum" +#: src/Model/Contact.php:1685 +msgid "Group" msgstr "" -#: src/Model/Contact.php:2951 +#: src/Model/Contact.php:2988 msgid "Disallowed profile URL." msgstr "" -#: src/Model/Contact.php:2956 src/Module/Friendica.php:83 +#: src/Model/Contact.php:2993 src/Module/Friendica.php:101 msgid "Blocked domain" msgstr "" -#: src/Model/Contact.php:2961 +#: src/Model/Contact.php:2998 msgid "Connect URL missing." msgstr "" -#: src/Model/Contact.php:2970 +#: src/Model/Contact.php:3007 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "" -#: src/Model/Contact.php:2988 +#: src/Model/Contact.php:3025 #, php-format msgid "Expected network %s does not match actual network %s" msgstr "" -#: src/Model/Contact.php:3005 +#: src/Model/Contact.php:3042 msgid "The profile address specified does not provide adequate information." msgstr "" -#: src/Model/Contact.php:3007 +#: src/Model/Contact.php:3044 msgid "No compatible communication protocols or feeds were discovered." msgstr "" -#: src/Model/Contact.php:3010 +#: src/Model/Contact.php:3047 msgid "An author or name was not found." msgstr "" -#: src/Model/Contact.php:3013 +#: src/Model/Contact.php:3050 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:3016 +#: src/Model/Contact.php:3053 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:3017 +#: src/Model/Contact.php:3054 msgid "Use mailto: in front of address to force email check." msgstr "" -#: src/Model/Contact.php:3023 +#: src/Model/Contact.php:3060 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "" -#: src/Model/Contact.php:3028 +#: src/Model/Contact.php:3065 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "" -#: src/Model/Contact.php:3093 +#: src/Model/Contact.php:3131 msgid "Unable to retrieve contact information." msgstr "" @@ -3057,54 +3153,54 @@ msgstr "" msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" msgstr "" -#: src/Model/Event.php:75 src/Model/Event.php:92 src/Model/Event.php:471 -#: src/Model/Event.php:940 +#: src/Model/Event.php:75 src/Model/Event.php:92 src/Model/Event.php:469 +#: src/Model/Event.php:945 msgid "Starts:" msgstr "" -#: src/Model/Event.php:78 src/Model/Event.php:98 src/Model/Event.php:472 -#: src/Model/Event.php:944 +#: src/Model/Event.php:78 src/Model/Event.php:98 src/Model/Event.php:470 +#: src/Model/Event.php:949 msgid "Finishes:" msgstr "" -#: src/Model/Event.php:421 +#: src/Model/Event.php:419 msgid "all-day" msgstr "" -#: src/Model/Event.php:447 +#: src/Model/Event.php:445 msgid "Sept" msgstr "" -#: src/Model/Event.php:464 src/Module/Calendar/Show.php:128 +#: src/Model/Event.php:462 src/Module/Calendar/Show.php:128 #: src/Util/Temporal.php:343 msgid "today" msgstr "" -#: src/Model/Event.php:465 src/Module/Calendar/Show.php:129 +#: src/Model/Event.php:463 src/Module/Calendar/Show.php:129 #: src/Module/Settings/Display.php:232 src/Util/Temporal.php:353 msgid "month" msgstr "" -#: src/Model/Event.php:466 src/Module/Calendar/Show.php:130 +#: src/Model/Event.php:464 src/Module/Calendar/Show.php:130 #: src/Module/Settings/Display.php:233 src/Util/Temporal.php:354 msgid "week" msgstr "" -#: src/Model/Event.php:467 src/Module/Calendar/Show.php:131 +#: src/Model/Event.php:465 src/Module/Calendar/Show.php:131 #: src/Module/Settings/Display.php:234 src/Util/Temporal.php:355 msgid "day" msgstr "" -#: src/Model/Event.php:469 +#: src/Model/Event.php:467 msgid "No events to display" msgstr "" -#: src/Model/Event.php:518 src/Module/DFRN/Poll.php:47 src/Module/Feed.php:69 +#: src/Model/Event.php:516 src/Module/DFRN/Poll.php:47 src/Module/Feed.php:69 #: src/Module/Update/Profile.php:56 msgid "Access to this profile has been restricted." msgstr "" -#: src/Model/Event.php:559 src/Module/Calendar/Event/Show.php:67 +#: src/Model/Event.php:558 src/Module/Calendar/Event/Show.php:67 msgid "Event not found." msgstr "" @@ -3136,143 +3232,99 @@ msgstr "" msgid "g:i A" msgstr "" -#: src/Model/Event.php:959 src/Model/Event.php:961 +#: src/Model/Event.php:964 src/Model/Event.php:966 msgid "Show map" msgstr "" -#: src/Model/Event.php:960 +#: src/Model/Event.php:965 msgid "Hide map" msgstr "" -#: src/Model/Event.php:1053 +#: src/Model/Event.php:1058 #, php-format msgid "%s's birthday" msgstr "" -#: src/Model/Event.php:1054 +#: src/Model/Event.php:1059 #, php-format msgid "Happy Birthday %s" msgstr "" -#: src/Model/Group.php:105 -msgid "" -"A deleted group with this name was revived. Existing item permissions " -"may apply to this group and any future members. If this is " -"not what you intended, please create another group with a different name." -msgstr "" - -#: src/Model/Group.php:512 -msgid "Default privacy group for new contacts" -msgstr "" - -#: src/Model/Group.php:544 -msgid "Everybody" -msgstr "" - -#: src/Model/Group.php:563 -msgid "edit" -msgstr "" - -#: src/Model/Group.php:595 -msgid "add" -msgstr "" - -#: src/Model/Group.php:600 -msgid "Edit group" -msgstr "" - -#: src/Model/Group.php:601 src/Module/Group.php:192 -msgid "Contacts not in any group" -msgstr "" - -#: src/Model/Group.php:603 -msgid "Create a new group" -msgstr "" - -#: src/Model/Group.php:604 src/Module/Group.php:177 src/Module/Group.php:200 -#: src/Module/Group.php:275 -msgid "Group Name: " -msgstr "" - -#: src/Model/Group.php:605 -msgid "Edit groups" -msgstr "" - -#: src/Model/Item.php:2023 +#: src/Model/Item.php:2061 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "" -#: src/Model/Item.php:2931 +#: src/Model/Item.php:3006 msgid "activity" msgstr "" -#: src/Model/Item.php:2933 +#: src/Model/Item.php:3008 msgid "comment" msgstr "" -#: src/Model/Item.php:2936 src/Module/Post/Tag/Add.php:123 +#: src/Model/Item.php:3011 src/Module/Post/Tag/Add.php:123 msgid "post" msgstr "" -#: src/Model/Item.php:3105 +#: src/Model/Item.php:3181 #, php-format msgid "%s is blocked" msgstr "" -#: src/Model/Item.php:3107 +#: src/Model/Item.php:3183 #, php-format msgid "%s is ignored" msgstr "" -#: src/Model/Item.php:3109 +#: src/Model/Item.php:3185 #, php-format msgid "Content from %s is collapsed" msgstr "" -#: src/Model/Item.php:3113 +#: src/Model/Item.php:3189 #, php-format msgid "Content warning: %s" msgstr "" -#: src/Model/Item.php:3557 +#: src/Model/Item.php:3651 msgid "bytes" msgstr "" -#: src/Model/Item.php:3588 +#: src/Model/Item.php:3682 #, 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:3590 +#: src/Model/Item.php:3684 #, php-format msgid "%2$s (%1$d vote)" msgid_plural "%2$s (%1$d votes)" msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3595 +#: src/Model/Item.php:3689 #, php-format msgid "%d voter. Poll end: %s" msgid_plural "%d voters. Poll end: %s" msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3597 +#: src/Model/Item.php:3691 #, php-format msgid "%d voter." msgid_plural "%d voters." msgstr[0] "" msgstr[1] "" -#: src/Model/Item.php:3599 +#: src/Model/Item.php:3693 #, php-format msgid "Poll end: %s" msgstr "" -#: src/Model/Item.php:3633 src/Model/Item.php:3634 +#: src/Model/Item.php:3727 src/Model/Item.php:3728 msgid "View on separate page" msgstr "" @@ -3280,294 +3332,295 @@ msgstr "" msgid "[no subject]" msgstr "" -#: src/Model/Photo.php:1184 src/Module/Media/Photo/Upload.php:170 +#: src/Model/Photo.php:1190 src/Module/Media/Photo/Upload.php:170 msgid "Wall Photos" msgstr "" -#: src/Model/Profile.php:361 src/Module/Profile/Profile.php:283 +#: src/Model/Profile.php:359 src/Module/Profile/Profile.php:283 #: src/Module/Profile/Profile.php:285 msgid "Edit profile" msgstr "" -#: src/Model/Profile.php:363 +#: src/Model/Profile.php:361 msgid "Change profile photo" msgstr "" -#: src/Model/Profile.php:376 src/Module/Directory.php:152 +#: src/Model/Profile.php:374 src/Module/Directory.php:152 #: src/Module/Profile/Profile.php:209 msgid "Homepage:" msgstr "" -#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:385 +#: src/Model/Profile.php:375 src/Module/Contact/Profile.php:406 #: src/Module/Notifications/Introductions.php:189 msgid "About:" msgstr "" -#: src/Model/Profile.php:467 +#: src/Model/Profile.php:465 msgid "Atom feed" msgstr "" -#: src/Model/Profile.php:474 +#: src/Model/Profile.php:472 msgid "This website has been verified to belong to the same person." msgstr "" -#: src/Model/Profile.php:511 +#: src/Model/Profile.php:509 msgid "F d" msgstr "" -#: src/Model/Profile.php:575 src/Model/Profile.php:664 +#: src/Model/Profile.php:573 src/Model/Profile.php:662 msgid "[today]" msgstr "" -#: src/Model/Profile.php:584 +#: src/Model/Profile.php:582 msgid "Birthday Reminders" msgstr "" -#: src/Model/Profile.php:585 +#: src/Model/Profile.php:583 msgid "Birthdays this week:" msgstr "" -#: src/Model/Profile.php:613 +#: src/Model/Profile.php:611 msgid "g A l F d" msgstr "" -#: src/Model/Profile.php:651 +#: src/Model/Profile.php:649 msgid "[No description]" msgstr "" -#: src/Model/Profile.php:677 +#: src/Model/Profile.php:675 msgid "Event Reminders" msgstr "" -#: src/Model/Profile.php:678 +#: src/Model/Profile.php:676 msgid "Upcoming events the next 7 days:" msgstr "" -#: src/Model/Profile.php:875 +#: src/Model/Profile.php:873 #, php-format msgid "OpenWebAuth: %1$s welcomes %2$s" msgstr "" -#: src/Model/Profile.php:1015 +#: src/Model/Profile.php:1013 msgid "Hometown:" msgstr "" -#: src/Model/Profile.php:1016 +#: src/Model/Profile.php:1014 msgid "Marital Status:" msgstr "" -#: src/Model/Profile.php:1017 +#: src/Model/Profile.php:1015 msgid "With:" msgstr "" -#: src/Model/Profile.php:1018 +#: src/Model/Profile.php:1016 msgid "Since:" msgstr "" -#: src/Model/Profile.php:1019 +#: src/Model/Profile.php:1017 msgid "Sexual Preference:" msgstr "" -#: src/Model/Profile.php:1020 +#: src/Model/Profile.php:1018 msgid "Political Views:" msgstr "" -#: src/Model/Profile.php:1021 +#: src/Model/Profile.php:1019 msgid "Religious Views:" msgstr "" -#: src/Model/Profile.php:1022 +#: src/Model/Profile.php:1020 msgid "Likes:" msgstr "" -#: src/Model/Profile.php:1023 +#: src/Model/Profile.php:1021 msgid "Dislikes:" msgstr "" -#: src/Model/Profile.php:1024 +#: src/Model/Profile.php:1022 msgid "Title/Description:" msgstr "" -#: src/Model/Profile.php:1025 src/Module/Admin/Summary.php:221 +#: src/Model/Profile.php:1023 src/Module/Admin/Summary.php:197 +#: src/Module/Moderation/Report/Create.php:280 #: src/Module/Moderation/Summary.php:77 msgid "Summary" msgstr "" -#: src/Model/Profile.php:1026 +#: src/Model/Profile.php:1024 msgid "Musical interests" msgstr "" -#: src/Model/Profile.php:1027 +#: src/Model/Profile.php:1025 msgid "Books, literature" msgstr "" -#: src/Model/Profile.php:1028 +#: src/Model/Profile.php:1026 msgid "Television" msgstr "" -#: src/Model/Profile.php:1029 +#: src/Model/Profile.php:1027 msgid "Film/dance/culture/entertainment" msgstr "" -#: src/Model/Profile.php:1030 +#: src/Model/Profile.php:1028 msgid "Hobbies/Interests" msgstr "" -#: src/Model/Profile.php:1031 +#: src/Model/Profile.php:1029 msgid "Love/romance" msgstr "" -#: src/Model/Profile.php:1032 +#: src/Model/Profile.php:1030 msgid "Work/employment" msgstr "" -#: src/Model/Profile.php:1033 +#: src/Model/Profile.php:1031 msgid "School/education" msgstr "" -#: src/Model/Profile.php:1034 +#: src/Model/Profile.php:1032 msgid "Contact information and Social Networks" msgstr "" -#: src/Model/User.php:214 src/Model/User.php:1120 +#: src/Model/User.php:226 src/Model/User.php:1168 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "" -#: src/Model/User.php:572 src/Model/User.php:605 +#: src/Model/User.php:602 src/Model/User.php:635 msgid "Login failed" msgstr "" -#: src/Model/User.php:637 +#: src/Model/User.php:667 msgid "Not enough information to authenticate" msgstr "" -#: src/Model/User.php:754 +#: src/Model/User.php:788 msgid "Password can't be empty" msgstr "" -#: src/Model/User.php:796 +#: src/Model/User.php:830 msgid "Empty passwords are not allowed." msgstr "" -#: src/Model/User.php:800 +#: src/Model/User.php:834 msgid "" "The new password has been exposed in a public data dump, please choose " "another." msgstr "" -#: src/Model/User.php:804 +#: src/Model/User.php:838 msgid "The password length is limited to 72 characters." msgstr "" -#: src/Model/User.php:808 +#: src/Model/User.php:842 msgid "The password can't contain white spaces nor accentuated letters" msgstr "" -#: src/Model/User.php:1003 +#: src/Model/User.php:1051 msgid "Passwords do not match. Password unchanged." msgstr "" -#: src/Model/User.php:1010 +#: src/Model/User.php:1058 msgid "An invitation is required." msgstr "" -#: src/Model/User.php:1014 +#: src/Model/User.php:1062 msgid "Invitation could not be verified." msgstr "" -#: src/Model/User.php:1022 +#: src/Model/User.php:1070 msgid "Invalid OpenID url" msgstr "" -#: src/Model/User.php:1035 src/Security/Authentication.php:241 +#: src/Model/User.php:1083 src/Security/Authentication.php:241 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "" -#: src/Model/User.php:1035 src/Security/Authentication.php:241 +#: src/Model/User.php:1083 src/Security/Authentication.php:241 msgid "The error message was:" msgstr "" -#: src/Model/User.php:1041 +#: src/Model/User.php:1089 msgid "Please enter the required information." msgstr "" -#: src/Model/User.php:1055 +#: src/Model/User.php:1103 #, php-format msgid "" "system.username_min_length (%s) and system.username_max_length (%s) are " "excluding each other, swapping values." msgstr "" -#: src/Model/User.php:1062 +#: src/Model/User.php:1110 #, php-format msgid "Username should be at least %s character." msgid_plural "Username should be at least %s characters." msgstr[0] "" msgstr[1] "" -#: src/Model/User.php:1066 +#: src/Model/User.php:1114 #, php-format msgid "Username should be at most %s character." msgid_plural "Username should be at most %s characters." msgstr[0] "" msgstr[1] "" -#: src/Model/User.php:1074 +#: src/Model/User.php:1122 msgid "That doesn't appear to be your full (First Last) name." msgstr "" -#: src/Model/User.php:1079 +#: src/Model/User.php:1127 msgid "Your email domain is not among those allowed on this site." msgstr "" -#: src/Model/User.php:1083 +#: src/Model/User.php:1131 msgid "Not a valid email address." msgstr "" -#: src/Model/User.php:1086 +#: src/Model/User.php:1134 msgid "The nickname was blocked from registration by the nodes admin." msgstr "" -#: src/Model/User.php:1090 src/Model/User.php:1096 +#: src/Model/User.php:1138 src/Model/User.php:1144 msgid "Cannot use that email." msgstr "" -#: src/Model/User.php:1102 +#: src/Model/User.php:1150 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "" -#: src/Model/User.php:1110 src/Model/User.php:1167 +#: src/Model/User.php:1158 src/Model/User.php:1215 msgid "Nickname is already registered. Please choose another." msgstr "" -#: src/Model/User.php:1154 src/Model/User.php:1158 +#: src/Model/User.php:1202 src/Model/User.php:1206 msgid "An error occurred during registration. Please try again." msgstr "" -#: src/Model/User.php:1181 +#: src/Model/User.php:1229 msgid "An error occurred creating your default profile. Please try again." msgstr "" -#: src/Model/User.php:1188 +#: src/Model/User.php:1236 msgid "An error occurred creating your self contact. Please try again." msgstr "" -#: src/Model/User.php:1193 +#: src/Model/User.php:1241 msgid "Friends" msgstr "" -#: src/Model/User.php:1197 +#: src/Model/User.php:1245 msgid "" -"An error occurred creating your default contact group. Please try again." +"An error occurred creating your default contact circle. Please try again." msgstr "" -#: src/Model/User.php:1236 +#: src/Model/User.php:1289 msgid "Profile Photos" msgstr "" -#: src/Model/User.php:1431 +#: src/Model/User.php:1469 #, php-format msgid "" "\n" @@ -3575,7 +3628,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "" -#: src/Model/User.php:1434 +#: src/Model/User.php:1472 #, php-format msgid "" "\n" @@ -3613,12 +3666,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "" -#: src/Model/User.php:1467 src/Model/User.php:1574 +#: src/Model/User.php:1505 src/Model/User.php:1612 #, php-format msgid "Registration details for %s" msgstr "" -#: src/Model/User.php:1487 +#: src/Model/User.php:1525 #, php-format msgid "" "\n" @@ -3634,12 +3687,12 @@ msgid "" "\t\t" msgstr "" -#: src/Model/User.php:1506 +#: src/Model/User.php:1544 #, php-format msgid "Registration at %s" msgstr "" -#: src/Model/User.php:1530 +#: src/Model/User.php:1568 #, php-format msgid "" "\n" @@ -3648,7 +3701,7 @@ msgid "" "\t\t\t" msgstr "" -#: src/Model/User.php:1538 +#: src/Model/User.php:1576 #, php-format msgid "" "\n" @@ -3712,10 +3765,10 @@ msgid "Enable" msgstr "" #: src/Module/Admin/Addons/Details.php:111 src/Module/Admin/Addons/Index.php:67 -#: src/Module/Admin/Federation.php:209 src/Module/Admin/Logs/Settings.php:85 +#: src/Module/Admin/Federation.php:214 src/Module/Admin/Logs/Settings.php:85 #: src/Module/Admin/Logs/View.php:83 src/Module/Admin/Queue.php:72 #: src/Module/Admin/Site.php:398 src/Module/Admin/Storage.php:138 -#: src/Module/Admin/Summary.php:220 src/Module/Admin/Themes/Details.php:90 +#: src/Module/Admin/Summary.php:196 src/Module/Admin/Themes/Details.php:90 #: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:77 #: src/Module/Moderation/Users/Create.php:61 #: src/Module/Moderation/Users/Pending.php:96 @@ -3754,10 +3807,10 @@ msgstr "" #: src/Module/Admin/Addons/Index.php:69 src/Module/Admin/Features.php:86 #: src/Module/Admin/Logs/Settings.php:87 src/Module/Admin/Site.php:401 #: src/Module/Admin/Themes/Index.php:113 src/Module/Admin/Tos.php:86 -#: src/Module/Settings/Account.php:560 src/Module/Settings/Addons.php:78 +#: src/Module/Settings/Account.php:561 src/Module/Settings/Addons.php:78 #: src/Module/Settings/Connectors.php:160 #: src/Module/Settings/Connectors.php:246 -#: src/Module/Settings/Delegation.php:169 src/Module/Settings/Display.php:247 +#: src/Module/Settings/Delegation.php:171 src/Module/Settings/Display.php:247 #: src/Module/Settings/Features.php:76 msgid "Save Settings" msgstr "" @@ -3842,75 +3895,77 @@ msgstr "" msgid "Manage Additional Features" msgstr "" -#: src/Module/Admin/Federation.php:75 +#: src/Module/Admin/Federation.php:76 +#: src/Module/Moderation/Report/Create.php:191 +#: src/Module/Moderation/Report/Create.php:316 msgid "Other" msgstr "" -#: src/Module/Admin/Federation.php:149 src/Module/Admin/Federation.php:398 +#: src/Module/Admin/Federation.php:154 src/Module/Admin/Federation.php:403 msgid "unknown" msgstr "" -#: src/Module/Admin/Federation.php:182 +#: src/Module/Admin/Federation.php:187 #, php-format msgid "%2$s total system" msgid_plural "%2$s total systems" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:183 +#: src/Module/Admin/Federation.php:188 #, php-format msgid "%2$s active user last month" msgid_plural "%2$s active users last month" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:184 +#: src/Module/Admin/Federation.php:189 #, php-format msgid "%2$s active user last six months" msgid_plural "%2$s active users last six months" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:185 +#: src/Module/Admin/Federation.php:190 #, php-format msgid "%2$s registered user" msgid_plural "%2$s registered users" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:186 +#: src/Module/Admin/Federation.php:191 #, php-format msgid "%2$s locally created post or comment" msgid_plural "%2$s locally created posts and comments" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:189 +#: src/Module/Admin/Federation.php:194 #, php-format msgid "%2$s post per user" msgid_plural "%2$s posts per user" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:194 +#: src/Module/Admin/Federation.php:199 #, php-format msgid "%2$s user per system" msgid_plural "%2$s users per system" msgstr[0] "" msgstr[1] "" -#: src/Module/Admin/Federation.php:204 +#: src/Module/Admin/Federation.php:209 msgid "" "This page offers you some numbers to the known part of the federated social " "network your Friendica node is part of. These numbers are not complete but " "only reflect the part of the network your node is aware of." msgstr "" -#: src/Module/Admin/Federation.php:210 src/Module/BaseAdmin.php:87 +#: src/Module/Admin/Federation.php:215 src/Module/BaseAdmin.php:87 msgid "Federation Statistics" msgstr "" -#: src/Module/Admin/Federation.php:214 +#: src/Module/Admin/Federation.php:219 #, php-format msgid "" "Currently this node is aware of %2$s node (%3$s active users last month, " @@ -4209,7 +4264,7 @@ msgid "Policies" msgstr "" #: src/Module/Admin/Site.php:406 src/Module/Calendar/Event/Form.php:252 -#: src/Module/Contact.php:516 src/Module/Profile/Profile.php:276 +#: src/Module/Contact.php:547 src/Module/Profile/Profile.php:276 msgid "Advanced" msgstr "" @@ -4543,7 +4598,7 @@ msgstr "" #: src/Module/Admin/Site.php:455 msgid "" "Set default post permissions for all new members to the default privacy " -"group rather than public." +"circle rather than public." msgstr "" #: src/Module/Admin/Site.php:456 @@ -4957,12 +5012,12 @@ msgid "On large systems the text search can slow down the system extremely." msgstr "" #: src/Module/Admin/Site.php:507 -msgid "Generate counts per contact group when calculating network count" +msgid "Generate counts per contact circle when calculating network count" msgstr "" #: src/Module/Admin/Site.php:507 msgid "" -"On systems with users that heavily use contact groups the query can be very " +"On systems with users that heavily use contact circles the query can be very " "expensive." msgstr "" @@ -5007,7 +5062,7 @@ msgid "" "received." msgstr "" -#: src/Module/Admin/Site.php:513 src/Module/Contact/Profile.php:286 +#: src/Module/Admin/Site.php:513 src/Module/Contact/Profile.php:305 #: src/Module/Settings/TwoFactor/Index.php:125 msgid "Disabled" msgstr "" @@ -5202,50 +5257,40 @@ msgid "" "href=\"%s\">the installation page for help." msgstr "" -#: src/Module/Admin/Summary.php:142 -#, php-format -msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" -msgstr "" - -#: src/Module/Admin/Summary.php:156 -#, php-format -msgid "The debug logfile '%s' is not usable. No logging possible (error: '%s')" -msgstr "" - -#: src/Module/Admin/Summary.php:172 +#: src/Module/Admin/Summary.php:148 #, php-format msgid "" "Friendica's system.basepath was updated from '%s' to '%s'. Please remove the " "system.basepath from your db to avoid differences." msgstr "" -#: src/Module/Admin/Summary.php:180 +#: src/Module/Admin/Summary.php:156 #, php-format msgid "" "Friendica's current system.basepath '%s' is wrong and the config file '%s' " "isn't used." msgstr "" -#: src/Module/Admin/Summary.php:188 +#: src/Module/Admin/Summary.php:164 #, php-format msgid "" "Friendica's current system.basepath '%s' is not equal to the config file " "'%s'. Please fix your configuration." msgstr "" -#: src/Module/Admin/Summary.php:199 +#: src/Module/Admin/Summary.php:175 msgid "Message queues" msgstr "" -#: src/Module/Admin/Summary.php:205 +#: src/Module/Admin/Summary.php:181 msgid "Server Settings" msgstr "" -#: src/Module/Admin/Summary.php:223 +#: src/Module/Admin/Summary.php:199 msgid "Version" msgstr "" -#: src/Module/Admin/Summary.php:227 +#: src/Module/Admin/Summary.php:203 msgid "Active addons" msgstr "" @@ -5398,11 +5443,11 @@ msgstr "" msgid "Please login to continue." msgstr "" -#: src/Module/BaseAdmin.php:63 src/Module/BaseModeration.php:86 +#: src/Module/BaseAdmin.php:63 msgid "You don't have access to administration pages." msgstr "" -#: src/Module/BaseAdmin.php:67 src/Module/BaseModeration.php:90 +#: src/Module/BaseAdmin.php:67 msgid "" "Submanaged account can't access the administration pages. Please log back in " "as the main account." @@ -5495,6 +5540,16 @@ msgid_plural "" msgstr[0] "" msgstr[1] "" +#: src/Module/BaseModeration.php:86 +msgid "You don't have access to moderation pages." +msgstr "" + +#: src/Module/BaseModeration.php:90 +msgid "" +"Submanaged account can't access the moderation pages. Please log back in as " +"the main account." +msgstr "" + #: src/Module/BaseModeration.php:112 src/Module/Moderation/Users/Index.php:148 #: src/Module/Moderation/Users/Index.php:158 msgid "Users" @@ -5520,7 +5575,7 @@ msgstr "" msgid "Item Source" msgstr "" -#: src/Module/BaseProfile.php:52 src/Module/Contact.php:478 +#: src/Module/BaseProfile.php:52 src/Module/Contact.php:507 msgid "Profile Details" msgstr "" @@ -5551,7 +5606,7 @@ msgstr "" #: src/Module/BaseSearch.php:75 #, php-format -msgid "Forum Search - %s" +msgid "Group Search - %s" msgstr "" #: src/Module/BaseSearch.php:121 src/Module/Contact/MatchInterests.php:139 @@ -5588,7 +5643,7 @@ msgstr "" msgid "Social Networks" msgstr "" -#: src/Module/BaseSettings.php:141 src/Module/Settings/Delegation.php:170 +#: src/Module/BaseSettings.php:141 src/Module/Settings/Delegation.php:172 msgid "Manage Accounts" msgstr "" @@ -5596,11 +5651,15 @@ msgstr "" msgid "Connected apps" msgstr "" -#: src/Module/BaseSettings.php:155 src/Module/Settings/UserExport.php:98 +#: src/Module/BaseSettings.php:155 +msgid "Remote servers" +msgstr "" + +#: src/Module/BaseSettings.php:162 src/Module/Settings/UserExport.php:98 msgid "Export personal data" msgstr "" -#: src/Module/BaseSettings.php:162 +#: src/Module/BaseSettings.php:169 msgid "Remove account" msgstr "" @@ -5724,6 +5783,108 @@ msgstr "" msgid "list" msgstr "" +#: src/Module/Circle.php:57 +msgid "Could not create circle." +msgstr "" + +#: src/Module/Circle.php:68 src/Module/Circle.php:214 src/Module/Circle.php:238 +msgid "Circle not found." +msgstr "" + +#: src/Module/Circle.php:74 +msgid "Circle name was not changed." +msgstr "" + +#: src/Module/Circle.php:92 +msgid "Unknown circle." +msgstr "" + +#: src/Module/Circle.php:98 src/Module/Circle.php:107 +#: src/Module/Contact/Advanced.php:70 src/Module/Contact/Advanced.php:109 +#: src/Module/Contact/Contacts.php:71 src/Module/Contact/Conversations.php:84 +#: src/Module/Contact/Conversations.php:89 +#: src/Module/Contact/Conversations.php:94 src/Module/Contact/Media.php:43 +#: src/Module/Contact/Posts.php:78 src/Module/Contact/Posts.php:83 +#: src/Module/Contact/Posts.php:88 src/Module/Contact/Profile.php:150 +#: src/Module/Contact/Profile.php:155 src/Module/Contact/Profile.php:160 +#: src/Module/Contact/Redir.php:94 src/Module/Contact/Redir.php:140 +#: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109 +msgid "Contact not found." +msgstr "" + +#: src/Module/Circle.php:102 src/Module/Contact/Contacts.php:66 +#: src/Module/Conversation/Network.php:189 +msgid "Invalid contact." +msgstr "" + +#: src/Module/Circle.php:111 src/Module/Contact/Revoke.php:73 +msgid "Contact is deleted." +msgstr "" + +#: src/Module/Circle.php:117 +msgid "Unable to add the contact to the circle." +msgstr "" + +#: src/Module/Circle.php:120 +msgid "Contact successfully added to circle." +msgstr "" + +#: src/Module/Circle.php:124 +msgid "Unable to remove the contact from the circle." +msgstr "" + +#: src/Module/Circle.php:127 +msgid "Contact successfully removed from circle." +msgstr "" + +#: src/Module/Circle.php:131 +msgid "Bad request." +msgstr "" + +#: src/Module/Circle.php:170 +msgid "Save Circle" +msgstr "" + +#: src/Module/Circle.php:171 +msgid "Filter" +msgstr "" + +#: src/Module/Circle.php:177 +msgid "Create a circle of contacts/friends." +msgstr "" + +#: src/Module/Circle.php:219 +msgid "Unable to remove circle." +msgstr "" + +#: src/Module/Circle.php:270 +msgid "Delete Circle" +msgstr "" + +#: src/Module/Circle.php:280 +msgid "Edit Circle Name" +msgstr "" + +#: src/Module/Circle.php:290 +msgid "Members" +msgstr "" + +#: src/Module/Circle.php:293 +msgid "Circle is empty" +msgstr "" + +#: src/Module/Circle.php:306 +msgid "Remove contact from circle" +msgstr "" + +#: src/Module/Circle.php:329 +msgid "Click on a contact to add or remove." +msgstr "" + +#: src/Module/Circle.php:343 +msgid "Add contact to circle" +msgstr "" + #: src/Module/Contact.php:97 #, php-format msgid "%d contact edited." @@ -5731,159 +5892,146 @@ msgid_plural "%d contacts edited." msgstr[0] "" msgstr[1] "" -#: src/Module/Contact.php:341 +#: src/Module/Contact.php:348 msgid "Show all contacts" msgstr "" -#: src/Module/Contact.php:346 src/Module/Contact.php:414 +#: src/Module/Contact.php:353 src/Module/Contact.php:432 #: src/Module/Moderation/BaseUsers.php:85 msgid "Pending" msgstr "" -#: src/Module/Contact.php:349 +#: src/Module/Contact.php:356 msgid "Only show pending contacts" msgstr "" -#: src/Module/Contact.php:354 src/Module/Contact.php:415 +#: src/Module/Contact.php:361 src/Module/Contact.php:435 #: src/Module/Moderation/BaseUsers.php:93 msgid "Blocked" msgstr "" -#: src/Module/Contact.php:357 +#: src/Module/Contact.php:364 msgid "Only show blocked contacts" msgstr "" -#: src/Module/Contact.php:362 src/Module/Contact.php:417 -#: src/Object/Post.php:351 +#: src/Module/Contact.php:369 src/Module/Contact.php:441 +#: src/Module/Settings/Server/Index.php:107 src/Object/Post.php:368 msgid "Ignored" msgstr "" -#: src/Module/Contact.php:365 +#: src/Module/Contact.php:372 msgid "Only show ignored contacts" msgstr "" -#: src/Module/Contact.php:370 src/Module/Contact.php:418 +#: src/Module/Contact.php:377 src/Module/Contact.php:444 msgid "Collapsed" msgstr "" -#: src/Module/Contact.php:373 +#: src/Module/Contact.php:380 msgid "Only show collapsed contacts" msgstr "" -#: src/Module/Contact.php:378 src/Module/Contact.php:419 +#: src/Module/Contact.php:385 src/Module/Contact.php:447 msgid "Archived" msgstr "" -#: src/Module/Contact.php:381 +#: src/Module/Contact.php:388 msgid "Only show archived contacts" msgstr "" -#: src/Module/Contact.php:386 src/Module/Contact.php:416 +#: src/Module/Contact.php:393 src/Module/Contact.php:438 msgid "Hidden" msgstr "" -#: src/Module/Contact.php:389 +#: src/Module/Contact.php:396 msgid "Only show hidden contacts" msgstr "" -#: src/Module/Contact.php:397 -msgid "Organize your contact groups" +#: src/Module/Contact.php:404 +msgid "Organize your contact circles" msgstr "" -#: src/Module/Contact.php:430 +#: src/Module/Contact.php:459 msgid "Search your contacts" msgstr "" -#: src/Module/Contact.php:431 src/Module/Search/Index.php:207 +#: src/Module/Contact.php:460 src/Module/Search/Index.php:207 #, php-format msgid "Results for: %s" msgstr "" -#: src/Module/Contact.php:438 +#: src/Module/Contact.php:467 msgid "Update" msgstr "" -#: src/Module/Contact.php:439 src/Module/Contact/Profile.php:477 +#: src/Module/Contact.php:468 src/Module/Contact/Profile.php:498 #: src/Module/Moderation/Blocklist/Contact.php:117 #: src/Module/Moderation/Users/Blocked.php:138 #: src/Module/Moderation/Users/Index.php:154 msgid "Unblock" msgstr "" -#: src/Module/Contact.php:440 src/Module/Contact/Profile.php:485 +#: src/Module/Contact.php:469 src/Module/Contact/Profile.php:506 msgid "Unignore" msgstr "" -#: src/Module/Contact.php:441 src/Module/Contact/Profile.php:493 +#: src/Module/Contact.php:470 src/Module/Contact/Profile.php:514 msgid "Uncollapse" msgstr "" -#: src/Module/Contact.php:443 +#: src/Module/Contact.php:472 msgid "Batch Actions" msgstr "" -#: src/Module/Contact.php:486 +#: src/Module/Contact.php:515 msgid "Conversations started by this contact" msgstr "" -#: src/Module/Contact.php:491 +#: src/Module/Contact.php:520 msgid "Posts and Comments" msgstr "" -#: src/Module/Contact.php:494 +#: src/Module/Contact.php:523 msgid "Individual Posts and Replies" msgstr "" -#: src/Module/Contact.php:502 +#: src/Module/Contact.php:531 msgid "Posts containing media objects" msgstr "" -#: src/Module/Contact.php:509 +#: src/Module/Contact.php:539 msgid "View all known contacts" msgstr "" -#: src/Module/Contact.php:519 +#: src/Module/Contact.php:550 msgid "Advanced Contact Settings" msgstr "" -#: src/Module/Contact.php:555 +#: src/Module/Contact.php:586 msgid "Mutual Friendship" msgstr "" -#: src/Module/Contact.php:559 +#: src/Module/Contact.php:590 msgid "is a fan of yours" msgstr "" -#: src/Module/Contact.php:563 +#: src/Module/Contact.php:594 msgid "you are a fan of" msgstr "" -#: src/Module/Contact.php:581 +#: src/Module/Contact.php:612 msgid "Pending outgoing contact request" msgstr "" -#: src/Module/Contact.php:583 +#: src/Module/Contact.php:614 msgid "Pending incoming contact request" msgstr "" -#: src/Module/Contact.php:596 src/Module/Contact/Profile.php:346 +#: src/Module/Contact.php:627 src/Module/Contact/Profile.php:365 #, php-format msgid "Visit %s's profile [%s]" msgstr "" -#: src/Module/Contact/Advanced.php:70 src/Module/Contact/Advanced.php:109 -#: src/Module/Contact/Contacts.php:71 src/Module/Contact/Conversations.php:84 -#: src/Module/Contact/Conversations.php:89 -#: src/Module/Contact/Conversations.php:94 src/Module/Contact/Media.php:43 -#: src/Module/Contact/Posts.php:78 src/Module/Contact/Posts.php:83 -#: src/Module/Contact/Posts.php:88 src/Module/Contact/Profile.php:142 -#: src/Module/Contact/Profile.php:147 src/Module/Contact/Profile.php:152 -#: src/Module/Contact/Redir.php:94 src/Module/Contact/Redir.php:140 -#: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109 -#: src/Module/Group.php:97 src/Module/Group.php:106 -msgid "Contact not found." -msgstr "" - #: src/Module/Contact/Advanced.php:99 msgid "Contact update failed." msgstr "" @@ -5920,11 +6068,6 @@ msgstr "" msgid "New photo from this URL" msgstr "" -#: src/Module/Contact/Contacts.php:66 src/Module/Conversation/Network.php:189 -#: src/Module/Group.php:101 -msgid "Invalid contact." -msgstr "" - #: src/Module/Contact/Contacts.php:89 msgid "No known contacts." msgstr "" @@ -6019,7 +6162,7 @@ msgstr "" msgid "Your Identity Address:" msgstr "" -#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:375 +#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:396 #: src/Module/Contact/Unfollow.php:129 #: src/Module/Moderation/Blocklist/Contact.php:133 #: src/Module/Notifications/Introductions.php:129 @@ -6027,7 +6170,7 @@ msgstr "" msgid "Profile URL" msgstr "" -#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:387 +#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:408 #: src/Module/Notifications/Introductions.php:191 #: src/Module/Profile/Profile.php:234 msgid "Tags:" @@ -6066,248 +6209,257 @@ msgstr "" msgid "Profile Match" msgstr "" -#: src/Module/Contact/Profile.php:128 +#: src/Module/Contact/Profile.php:136 msgid "Failed to update contact record." msgstr "" -#: src/Module/Contact/Profile.php:178 +#: src/Module/Contact/Profile.php:186 msgid "Contact has been unblocked" msgstr "" -#: src/Module/Contact/Profile.php:182 +#: src/Module/Contact/Profile.php:190 msgid "Contact has been blocked" msgstr "" -#: src/Module/Contact/Profile.php:194 +#: src/Module/Contact/Profile.php:202 msgid "Contact has been unignored" msgstr "" -#: src/Module/Contact/Profile.php:198 +#: src/Module/Contact/Profile.php:206 msgid "Contact has been ignored" msgstr "" -#: src/Module/Contact/Profile.php:210 +#: src/Module/Contact/Profile.php:218 msgid "Contact has been uncollapsed" msgstr "" -#: src/Module/Contact/Profile.php:214 +#: src/Module/Contact/Profile.php:222 msgid "Contact has been collapsed" msgstr "" -#: src/Module/Contact/Profile.php:242 +#: src/Module/Contact/Profile.php:250 #, php-format msgid "You are mutual friends with %s" msgstr "" -#: src/Module/Contact/Profile.php:243 +#: src/Module/Contact/Profile.php:251 #, php-format msgid "You are sharing with %s" msgstr "" -#: src/Module/Contact/Profile.php:244 +#: src/Module/Contact/Profile.php:252 #, php-format msgid "%s is sharing with you" msgstr "" -#: src/Module/Contact/Profile.php:260 +#: src/Module/Contact/Profile.php:268 msgid "Private communications are not available for this contact." msgstr "" -#: src/Module/Contact/Profile.php:262 +#: src/Module/Contact/Profile.php:278 +msgid "This contact is on a server you ignored." +msgstr "" + +#: src/Module/Contact/Profile.php:281 msgid "Never" msgstr "" -#: src/Module/Contact/Profile.php:265 +#: src/Module/Contact/Profile.php:284 msgid "(Update was not successful)" msgstr "" -#: src/Module/Contact/Profile.php:265 +#: src/Module/Contact/Profile.php:284 msgid "(Update was successful)" msgstr "" -#: src/Module/Contact/Profile.php:267 src/Module/Contact/Profile.php:448 +#: src/Module/Contact/Profile.php:286 src/Module/Contact/Profile.php:469 msgid "Suggest friends" msgstr "" -#: src/Module/Contact/Profile.php:271 +#: src/Module/Contact/Profile.php:290 #, php-format msgid "Network type: %s" msgstr "" -#: src/Module/Contact/Profile.php:276 +#: src/Module/Contact/Profile.php:295 msgid "Communications lost with this contact!" msgstr "" -#: src/Module/Contact/Profile.php:282 +#: src/Module/Contact/Profile.php:301 msgid "Fetch further information for feeds" msgstr "" -#: src/Module/Contact/Profile.php:284 +#: src/Module/Contact/Profile.php:303 msgid "" "Fetch information like preview pictures, title and teaser from the feed " "item. You can activate this if the feed doesn't contain much text. Keywords " "are taken from the meta header in the feed item and are posted as hash tags." msgstr "" -#: src/Module/Contact/Profile.php:287 +#: src/Module/Contact/Profile.php:306 msgid "Fetch information" msgstr "" -#: src/Module/Contact/Profile.php:288 +#: src/Module/Contact/Profile.php:307 msgid "Fetch keywords" msgstr "" -#: src/Module/Contact/Profile.php:289 +#: src/Module/Contact/Profile.php:308 msgid "Fetch information and keywords" msgstr "" -#: src/Module/Contact/Profile.php:299 src/Module/Contact/Profile.php:304 -#: src/Module/Contact/Profile.php:309 src/Module/Contact/Profile.php:315 +#: src/Module/Contact/Profile.php:318 src/Module/Contact/Profile.php:323 +#: src/Module/Contact/Profile.php:328 src/Module/Contact/Profile.php:334 msgid "No mirroring" msgstr "" -#: src/Module/Contact/Profile.php:300 src/Module/Contact/Profile.php:310 -#: src/Module/Contact/Profile.php:316 +#: src/Module/Contact/Profile.php:319 src/Module/Contact/Profile.php:329 +#: src/Module/Contact/Profile.php:335 msgid "Mirror as my own posting" msgstr "" -#: src/Module/Contact/Profile.php:305 src/Module/Contact/Profile.php:311 +#: src/Module/Contact/Profile.php:324 src/Module/Contact/Profile.php:330 msgid "Native reshare" msgstr "" -#: src/Module/Contact/Profile.php:328 +#: src/Module/Contact/Profile.php:347 msgid "Contact Information / Notes" msgstr "" -#: src/Module/Contact/Profile.php:329 +#: src/Module/Contact/Profile.php:348 msgid "Contact Settings" msgstr "" -#: src/Module/Contact/Profile.php:337 +#: src/Module/Contact/Profile.php:356 msgid "Contact" msgstr "" -#: src/Module/Contact/Profile.php:341 +#: src/Module/Contact/Profile.php:360 msgid "Their personal note" msgstr "" -#: src/Module/Contact/Profile.php:343 +#: src/Module/Contact/Profile.php:362 msgid "Edit contact notes" msgstr "" -#: src/Module/Contact/Profile.php:347 +#: src/Module/Contact/Profile.php:366 msgid "Block/Unblock contact" msgstr "" -#: src/Module/Contact/Profile.php:348 +#: src/Module/Contact/Profile.php:367 +#: src/Module/Moderation/Report/Create.php:293 msgid "Ignore contact" msgstr "" -#: src/Module/Contact/Profile.php:349 +#: src/Module/Contact/Profile.php:368 msgid "View conversations" msgstr "" -#: src/Module/Contact/Profile.php:354 +#: src/Module/Contact/Profile.php:373 msgid "Last update:" msgstr "" -#: src/Module/Contact/Profile.php:356 +#: src/Module/Contact/Profile.php:375 msgid "Update public posts" msgstr "" -#: src/Module/Contact/Profile.php:358 src/Module/Contact/Profile.php:458 +#: src/Module/Contact/Profile.php:377 src/Module/Contact/Profile.php:479 msgid "Update now" msgstr "" -#: src/Module/Contact/Profile.php:360 +#: src/Module/Contact/Profile.php:379 msgid "Awaiting connection acknowledge" msgstr "" -#: src/Module/Contact/Profile.php:361 +#: src/Module/Contact/Profile.php:380 msgid "Currently blocked" msgstr "" -#: src/Module/Contact/Profile.php:362 +#: src/Module/Contact/Profile.php:381 msgid "Currently ignored" msgstr "" -#: src/Module/Contact/Profile.php:363 +#: src/Module/Contact/Profile.php:382 msgid "Currently collapsed" msgstr "" -#: src/Module/Contact/Profile.php:364 +#: src/Module/Contact/Profile.php:383 msgid "Currently archived" msgstr "" -#: src/Module/Contact/Profile.php:367 +#: src/Module/Contact/Profile.php:386 +msgid "Manage remote servers" +msgstr "" + +#: src/Module/Contact/Profile.php:388 #: src/Module/Notifications/Introductions.php:192 msgid "Hide this contact from others" msgstr "" -#: src/Module/Contact/Profile.php:367 +#: src/Module/Contact/Profile.php:388 msgid "" "Replies/likes to your public posts may still be visible" msgstr "" -#: src/Module/Contact/Profile.php:368 +#: src/Module/Contact/Profile.php:389 msgid "Notification for new posts" msgstr "" -#: src/Module/Contact/Profile.php:368 +#: src/Module/Contact/Profile.php:389 msgid "Send a notification of every new post of this contact" msgstr "" -#: src/Module/Contact/Profile.php:370 +#: src/Module/Contact/Profile.php:391 msgid "Keyword Deny List" msgstr "" -#: src/Module/Contact/Profile.php:370 +#: src/Module/Contact/Profile.php:391 msgid "" "Comma separated list of keywords that should not be converted to hashtags, " "when \"Fetch information and keywords\" is selected" msgstr "" -#: src/Module/Contact/Profile.php:388 +#: src/Module/Contact/Profile.php:409 #: src/Module/Settings/TwoFactor/Index.php:139 msgid "Actions" msgstr "" -#: src/Module/Contact/Profile.php:390 +#: src/Module/Contact/Profile.php:411 #: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229 msgid "Status" msgstr "" -#: src/Module/Contact/Profile.php:396 +#: src/Module/Contact/Profile.php:417 msgid "Mirror postings from this contact" msgstr "" -#: src/Module/Contact/Profile.php:398 +#: src/Module/Contact/Profile.php:419 msgid "" "Mark this contact as remote_self, this will cause friendica to repost new " "entries from this contact." msgstr "" -#: src/Module/Contact/Profile.php:468 +#: src/Module/Contact/Profile.php:489 msgid "Refetch contact data" msgstr "" -#: src/Module/Contact/Profile.php:479 +#: src/Module/Contact/Profile.php:500 msgid "Toggle Blocked status" msgstr "" -#: src/Module/Contact/Profile.php:487 +#: src/Module/Contact/Profile.php:508 msgid "Toggle Ignored status" msgstr "" -#: src/Module/Contact/Profile.php:495 +#: src/Module/Contact/Profile.php:516 msgid "Toggle Collapsed status" msgstr "" -#: src/Module/Contact/Profile.php:502 src/Module/Contact/Revoke.php:106 +#: src/Module/Contact/Profile.php:523 src/Module/Contact/Revoke.php:106 msgid "Revoke Follow" msgstr "" -#: src/Module/Contact/Profile.php:504 +#: src/Module/Contact/Profile.php:525 msgid "Revoke the follow from this contact" msgstr "" @@ -6319,10 +6471,6 @@ msgstr "" msgid "Unknown contact." msgstr "" -#: src/Module/Contact/Revoke.php:73 src/Module/Group.php:110 -msgid "Contact is deleted." -msgstr "" - #: src/Module/Contact/Revoke.php:77 msgid "Contact is being deleted." msgstr "" @@ -6418,12 +6566,12 @@ msgid "Not available." msgstr "" #: src/Module/Conversation/Network.php:175 -msgid "No such group" +msgid "No such circle" msgstr "" #: src/Module/Conversation/Network.php:179 #, php-format -msgid "Group: %s" +msgid "Circle: %s" msgstr "" #: src/Module/Conversation/Network.php:257 @@ -6451,7 +6599,7 @@ msgid "Sort by post creation date" msgstr "" #: src/Module/Conversation/Network.php:281 -#: src/Module/Settings/Profile/Index.php:235 +#: src/Module/Settings/Profile/Index.php:260 msgid "Personal" msgstr "" @@ -6459,7 +6607,7 @@ msgstr "" msgid "Posts that mention or involve you" msgstr "" -#: src/Module/Conversation/Network.php:289 src/Object/Post.php:363 +#: src/Module/Conversation/Network.php:289 src/Object/Post.php:380 msgid "Starred" msgstr "" @@ -6683,7 +6831,7 @@ msgid "Twitter Source / Tweet URL (requires API key)" msgstr "" #: src/Module/Debug/Feed.php:52 src/Module/Filer/SaveTag.php:47 -#: src/Module/Settings/Profile/Index.php:144 +#: src/Module/Settings/Profile/Index.php:177 msgid "You must be logged in to use this module" msgstr "" @@ -6812,139 +6960,59 @@ msgstr "" msgid "Suggest a friend for %s" msgstr "" -#: src/Module/Friendica.php:64 +#: src/Module/Friendica.php:82 msgid "Installed addons/apps:" msgstr "" -#: src/Module/Friendica.php:69 +#: src/Module/Friendica.php:87 msgid "No installed addons/apps" msgstr "" -#: src/Module/Friendica.php:74 +#: src/Module/Friendica.php:92 #, php-format msgid "Read about the Terms of Service of this node." msgstr "" -#: src/Module/Friendica.php:81 +#: src/Module/Friendica.php:99 msgid "On this server the following remote servers are blocked." msgstr "" -#: src/Module/Friendica.php:84 +#: src/Module/Friendica.php:102 #: src/Module/Moderation/Blocklist/Server/Index.php:87 #: src/Module/Moderation/Blocklist/Server/Index.php:111 msgid "Reason for the block" msgstr "" -#: src/Module/Friendica.php:86 +#: src/Module/Friendica.php:104 msgid "Download this list in CSV format" msgstr "" -#: src/Module/Friendica.php:100 +#: src/Module/Friendica.php:118 #, php-format msgid "" "This is Friendica, version %s that is running at the web location %s. The " "database version is %s, the post update version is %s." msgstr "" -#: src/Module/Friendica.php:105 +#: src/Module/Friendica.php:123 msgid "" "Please visit Friendi.ca to learn more " "about the Friendica project." msgstr "" -#: src/Module/Friendica.php:106 +#: src/Module/Friendica.php:124 msgid "Bug reports and issues: please visit" msgstr "" -#: src/Module/Friendica.php:106 +#: src/Module/Friendica.php:124 msgid "the bugtracker at github" msgstr "" -#: src/Module/Friendica.php:107 +#: src/Module/Friendica.php:125 msgid "" "Suggestions, praise, etc. - please email \"info\" at \"friendi - dot - ca" msgstr "" -#: src/Module/Group.php:56 -msgid "Could not create group." -msgstr "" - -#: src/Module/Group.php:67 src/Module/Group.php:213 src/Module/Group.php:237 -msgid "Group not found." -msgstr "" - -#: src/Module/Group.php:73 -msgid "Group name was not changed." -msgstr "" - -#: src/Module/Group.php:91 -msgid "Unknown group." -msgstr "" - -#: src/Module/Group.php:116 -msgid "Unable to add the contact to the group." -msgstr "" - -#: src/Module/Group.php:119 -msgid "Contact successfully added to group." -msgstr "" - -#: src/Module/Group.php:123 -msgid "Unable to remove the contact from the group." -msgstr "" - -#: src/Module/Group.php:126 -msgid "Contact successfully removed from group." -msgstr "" - -#: src/Module/Group.php:130 -msgid "Bad request." -msgstr "" - -#: src/Module/Group.php:169 -msgid "Save Group" -msgstr "" - -#: src/Module/Group.php:170 -msgid "Filter" -msgstr "" - -#: src/Module/Group.php:176 -msgid "Create a group of contacts/friends." -msgstr "" - -#: src/Module/Group.php:218 -msgid "Unable to remove group." -msgstr "" - -#: src/Module/Group.php:269 -msgid "Delete Group" -msgstr "" - -#: src/Module/Group.php:279 -msgid "Edit Group Name" -msgstr "" - -#: src/Module/Group.php:289 -msgid "Members" -msgstr "" - -#: src/Module/Group.php:292 -msgid "Group is empty" -msgstr "" - -#: src/Module/Group.php:305 -msgid "Remove contact from group" -msgstr "" - -#: src/Module/Group.php:326 -msgid "Click on a contact to add or remove." -msgstr "" - -#: src/Module/Group.php:340 -msgid "Add contact to group" -msgstr "" - #: src/Module/HCard.php:45 msgid "No profile" msgstr "" @@ -7235,30 +7303,26 @@ msgstr "" msgid "Visibility" msgstr "" -#: src/Module/Item/Compose.php:202 +#: src/Module/Item/Compose.php:203 msgid "Clear the location" msgstr "" -#: src/Module/Item/Compose.php:203 +#: src/Module/Item/Compose.php:204 msgid "Location services are unavailable on your device" msgstr "" -#: src/Module/Item/Compose.php:204 +#: src/Module/Item/Compose.php:205 msgid "" "Location services are disabled. Please check the website's permissions on " "your device" msgstr "" -#: src/Module/Item/Compose.php:210 +#: src/Module/Item/Compose.php:211 msgid "" "You can make this page always open when you use the New Post button in the " "Theme Customization settings." msgstr "" -#: src/Module/Item/Display.php:136 src/Module/Update/Display.php:55 -msgid "The requested item doesn't exist or has been deleted." -msgstr "" - #: src/Module/Item/Feed.php:86 msgid "The feed for this item is unavailable." msgstr "" @@ -7353,40 +7417,40 @@ msgstr "" msgid "List of pending user deletions" msgstr "" -#: src/Module/Moderation/BaseUsers.php:119 src/Module/Settings/Account.php:491 +#: src/Module/Moderation/BaseUsers.php:119 src/Module/Settings/Account.php:492 msgid "Normal Account Page" msgstr "" -#: src/Module/Moderation/BaseUsers.php:120 src/Module/Settings/Account.php:498 +#: src/Module/Moderation/BaseUsers.php:120 src/Module/Settings/Account.php:499 msgid "Soapbox Page" msgstr "" -#: src/Module/Moderation/BaseUsers.php:121 src/Module/Settings/Account.php:505 -msgid "Public Forum" +#: src/Module/Moderation/BaseUsers.php:121 src/Module/Settings/Account.php:506 +msgid "Public Group" msgstr "" -#: src/Module/Moderation/BaseUsers.php:122 src/Module/Settings/Account.php:512 +#: src/Module/Moderation/BaseUsers.php:122 src/Module/Settings/Account.php:513 msgid "Automatic Friend Page" msgstr "" #: src/Module/Moderation/BaseUsers.php:123 -msgid "Private Forum" +msgid "Private Group" msgstr "" -#: src/Module/Moderation/BaseUsers.php:126 src/Module/Settings/Account.php:463 +#: src/Module/Moderation/BaseUsers.php:126 src/Module/Settings/Account.php:464 msgid "Personal Page" msgstr "" -#: src/Module/Moderation/BaseUsers.php:127 src/Module/Settings/Account.php:470 +#: src/Module/Moderation/BaseUsers.php:127 src/Module/Settings/Account.php:471 msgid "Organisation Page" msgstr "" -#: src/Module/Moderation/BaseUsers.php:128 src/Module/Settings/Account.php:477 +#: src/Module/Moderation/BaseUsers.php:128 src/Module/Settings/Account.php:478 msgid "News Page" msgstr "" -#: src/Module/Moderation/BaseUsers.php:129 src/Module/Settings/Account.php:484 -msgid "Community Forum" +#: src/Module/Moderation/BaseUsers.php:129 src/Module/Settings/Account.php:485 +msgid "Community Group" msgstr "" #: src/Module/Moderation/BaseUsers.php:130 @@ -7517,6 +7581,8 @@ msgid "Matching known servers" msgstr "" #: src/Module/Moderation/Blocklist/Server/Add.php:130 +#: src/Module/Settings/Server/Action.php:76 +#: src/Module/Settings/Server/Index.php:106 msgid "Server Name" msgstr "" @@ -7799,6 +7865,209 @@ msgstr "" msgid "Item Guid" msgstr "" +#: src/Module/Moderation/Report/Create.php:95 +msgid "Contact not found or their server is already blocked on this node." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:136 +msgid "Please login to access this page." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:165 +#: src/Module/Moderation/Report/Create.php:180 +#: src/Module/Moderation/Report/Create.php:208 +#: src/Module/Moderation/Report/Create.php:260 +#: src/Module/Moderation/Report/Create.php:279 +msgid "Create Moderation Report" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:166 +msgid "Pick Contact" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:167 +msgid "" +"Please enter below the contact address or profile URL you would like to " +"create a moderation report about." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:171 +msgid "Contact address/URL" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:181 +msgid "Pick Category" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:182 +msgid "Please pick below the category of your report." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:186 +#: src/Module/Moderation/Report/Create.php:311 +msgid "Spam" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:186 +msgid "" +"This contact is publishing many repeated/overly long posts/replies or " +"advertising their product/websites in otherwise irrelevant conversations." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:187 +#: src/Module/Moderation/Report/Create.php:312 +msgid "Illegal Content" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:187 +msgid "" +"This contact is publishing content that is considered illegal in this node's " +"hosting juridiction." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:188 +#: src/Module/Moderation/Report/Create.php:313 +msgid "Community Safety" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:188 +msgid "" +"This contact aggravated you or other people, by being provocative or " +"insensitive, intentionally or not. This includes disclosing people's private " +"information (doxxing), posting threats or offensive pictures in posts or " +"replies." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:189 +#: src/Module/Moderation/Report/Create.php:314 +msgid "Unwanted Content/Behavior" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:189 +msgid "" +"This contact has repeatedly published content irrelevant to the node's theme " +"or is openly criticizing the node's administration/moderation without " +"directly engaging with the relevant people for example or repeatedly " +"nitpicking on a sensitive topic." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:190 +#: src/Module/Moderation/Report/Create.php:315 +msgid "Rules Violation" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:190 +msgid "" +"This contact violated one or more rules of this node. You will be able to " +"pick which one(s) in the next step." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:191 +msgid "" +"Please elaborate below why you submitted this report. The more details you " +"provide, the better your report can be handled." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:193 +msgid "Additional Information" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:193 +msgid "" +"Please provide any additional information relevant to this particular " +"report. You will be able to attach posts by this contact in the next step, " +"but any context is welcome." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:209 +msgid "Pick Rules" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:210 +msgid "Please pick below the node rules you believe this contact violated." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:261 +msgid "Pick Posts" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:262 +msgid "Please optionally pick posts to attach to your report." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:281 +msgid "Submit Report" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:282 +msgid "Further Action" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:283 +msgid "" +"You can also perform one of the following action on the contact you reported:" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:291 +msgid "Nothing" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:292 +msgid "Collapse contact" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:292 +msgid "" +"Their posts and replies will keep appearing in your Network page but their " +"content will be collapsed by default." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:293 +msgid "" +"Their posts won't appear in your Network page anymore, but their replies can " +"appear in forum threads. They still can follow you." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:294 +msgid "Block contact" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:294 +msgid "" +"Their posts won't appear in your Network page anymore, but their replies can " +"appear in forum threads, with their content collapsed by default. They " +"cannot follow you but still can have access to your public posts by other " +"means." +msgstr "" + +#: src/Module/Moderation/Report/Create.php:297 +msgid "Forward report" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:297 +msgid "Would you ike to forward this report to the remote server?" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:330 +msgid "1. Pick a contact" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:331 +msgid "2. Pick a category" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:332 +msgid "2a. Pick rules" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:333 +msgid "2b. Add comment" +msgstr "" + +#: src/Module/Moderation/Report/Create.php:334 +msgid "3. Pick posts" +msgstr "" + #: src/Module/Moderation/Summary.php:53 msgid "Normal Account" msgstr "" @@ -7808,7 +8077,7 @@ msgid "Automatic Follower Account" msgstr "" #: src/Module/Moderation/Summary.php:55 -msgid "Public Forum Account" +msgid "Public Group Account" msgstr "" #: src/Module/Moderation/Summary.php:56 @@ -7820,7 +8089,7 @@ msgid "Blog Account" msgstr "" #: src/Module/Moderation/Summary.php:58 -msgid "Private Forum Account" +msgid "Private Group Account" msgstr "" #: src/Module/Moderation/Summary.php:78 @@ -8121,11 +8390,11 @@ msgstr "" msgid "Show unread" msgstr "" -#: src/Module/Notifications/Ping.php:245 +#: src/Module/Notifications/Ping.php:246 msgid "{0} requested registration" msgstr "" -#: src/Module/Notifications/Ping.php:254 +#: src/Module/Notifications/Ping.php:255 #, php-format msgid "{0} and %d others requested registration" msgstr "" @@ -8144,7 +8413,7 @@ msgstr "" msgid "Unsupported or missing response type" msgstr "" -#: src/Module/OAuth/Authorize.php:59 src/Module/OAuth/Token.php:77 +#: src/Module/OAuth/Authorize.php:59 src/Module/OAuth/Token.php:78 msgid "Incomplete request data" msgstr "" @@ -8155,11 +8424,11 @@ msgid "" "close this window: %s" msgstr "" -#: src/Module/OAuth/Token.php:82 +#: src/Module/OAuth/Token.php:83 msgid "Invalid data or unknown client" msgstr "" -#: src/Module/OAuth/Token.php:104 +#: src/Module/OAuth/Token.php:108 msgid "Unsupported or missing grant type" msgstr "" @@ -8284,21 +8553,21 @@ msgstr "" msgid "Attributed To: %s
" msgstr "" -#: src/Module/Photo.php:129 +#: src/Module/Photo.php:130 msgid "The Photo is not available." msgstr "" -#: src/Module/Photo.php:154 +#: src/Module/Photo.php:155 #, php-format msgid "The Photo with id %s is not available." msgstr "" -#: src/Module/Photo.php:191 +#: src/Module/Photo.php:192 #, php-format msgid "Invalid external resource with url %s." msgstr "" -#: src/Module/Photo.php:193 +#: src/Module/Photo.php:194 #, php-format msgid "Invalid photo with id %s." msgstr "" @@ -8339,7 +8608,7 @@ msgstr "" msgid "Select a tag to remove: " msgstr "" -#: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:178 +#: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:180 #: src/Module/Settings/TwoFactor/Trusted.php:144 msgid "Remove" msgstr "" @@ -8350,20 +8619,20 @@ msgstr "" #: src/Module/Profile/Conversations.php:106 #: src/Module/Profile/Conversations.php:109 src/Module/Profile/Profile.php:351 -#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1092 -#: src/Protocol/OStatus.php:1007 +#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1098 +#: src/Protocol/OStatus.php:1009 #, php-format msgid "%s's timeline" msgstr "" #: src/Module/Profile/Conversations.php:107 src/Module/Profile/Profile.php:352 -#: src/Protocol/Feed.php:1096 src/Protocol/OStatus.php:1012 +#: src/Protocol/Feed.php:1102 src/Protocol/OStatus.php:1014 #, php-format msgid "%s's posts" msgstr "" #: src/Module/Profile/Conversations.php:108 src/Module/Profile/Profile.php:353 -#: src/Protocol/Feed.php:1099 src/Protocol/OStatus.php:1016 +#: src/Protocol/Feed.php:1105 src/Protocol/OStatus.php:1018 #, php-format msgid "%s's comments" msgstr "" @@ -8408,7 +8677,7 @@ msgid "" "\"btn btn-sm pull-right\">Cancel" msgstr "" -#: src/Module/Profile/Profile.php:167 src/Module/Settings/Account.php:575 +#: src/Module/Profile/Profile.php:167 msgid "Full Name:" msgstr "" @@ -8428,12 +8697,12 @@ msgstr "" msgid "Birthday:" msgstr "" -#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:253 +#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:291 #: src/Util/Temporal.php:170 msgid "Age: " msgstr "" -#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:253 +#: src/Module/Profile/Profile.php:190 src/Module/Settings/Profile/Index.php:291 #: src/Util/Temporal.php:170 #, php-format msgid "%d year old" @@ -8441,12 +8710,12 @@ msgid_plural "%d years old" msgstr[0] "" msgstr[1] "" -#: src/Module/Profile/Profile.php:195 src/Module/Settings/Profile/Index.php:246 +#: src/Module/Profile/Profile.php:195 src/Module/Settings/Profile/Index.php:284 msgid "Description:" msgstr "" #: src/Module/Profile/Profile.php:261 -msgid "Forums:" +msgid "Groups:" msgstr "" #: src/Module/Profile/Profile.php:273 @@ -8617,7 +8886,7 @@ msgid "Please repeat your e-mail address:" msgstr "" #: src/Module/Register.php:162 src/Module/Security/PasswordTooLong.php:100 -#: src/Module/Settings/Account.php:566 +#: src/Module/Settings/Account.php:567 msgid "New Password:" msgstr "" @@ -8626,7 +8895,7 @@ msgid "Leave empty for an auto generated password." msgstr "" #: src/Module/Register.php:163 src/Module/Security/PasswordTooLong.php:101 -#: src/Module/Settings/Account.php:567 +#: src/Module/Settings/Account.php:568 msgid "Confirm:" msgstr "" @@ -8653,11 +8922,11 @@ msgstr "" msgid "Note: This node explicitly contains adult content" msgstr "" -#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:154 +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 msgid "Parent Password:" msgstr "" -#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:154 +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 msgid "" "Please enter the password of the parent account to legitimize your request." msgstr "" @@ -8844,24 +9113,24 @@ msgid "Update Password" msgstr "" #: src/Module/Security/PasswordTooLong.php:99 -#: src/Module/Settings/Account.php:568 +#: src/Module/Settings/Account.php:569 msgid "Current Password:" msgstr "" #: src/Module/Security/PasswordTooLong.php:99 -#: src/Module/Settings/Account.php:568 +#: src/Module/Settings/Account.php:569 msgid "Your current password to confirm the changes" msgstr "" #: src/Module/Security/PasswordTooLong.php:100 -#: src/Module/Settings/Account.php:552 +#: src/Module/Settings/Account.php:553 msgid "" "Allowed characters are a-z, A-Z, 0-9 and special characters except white " "spaces and accentuated letters." msgstr "" #: src/Module/Security/PasswordTooLong.php:100 -#: src/Module/Settings/Account.php:553 +#: src/Module/Settings/Account.php:554 msgid "Password length is limited to 72 characters." msgstr "" @@ -8986,99 +9255,99 @@ msgstr "" msgid "Cannot change to that email." msgstr "" -#: src/Module/Settings/Account.php:146 src/Module/Settings/Account.php:198 -#: src/Module/Settings/Account.php:218 src/Module/Settings/Account.php:302 -#: src/Module/Settings/Account.php:351 +#: src/Module/Settings/Account.php:146 src/Module/Settings/Account.php:199 +#: src/Module/Settings/Account.php:219 src/Module/Settings/Account.php:303 +#: src/Module/Settings/Account.php:352 msgid "Settings were not updated." msgstr "" -#: src/Module/Settings/Account.php:363 +#: src/Module/Settings/Account.php:364 msgid "Contact CSV file upload error" msgstr "" -#: src/Module/Settings/Account.php:382 +#: src/Module/Settings/Account.php:383 msgid "Importing Contacts done" msgstr "" -#: src/Module/Settings/Account.php:395 +#: src/Module/Settings/Account.php:396 msgid "Relocate message has been send to your contacts" msgstr "" -#: src/Module/Settings/Account.php:412 +#: src/Module/Settings/Account.php:413 msgid "Unable to find your profile. Please contact your admin." msgstr "" -#: src/Module/Settings/Account.php:454 +#: src/Module/Settings/Account.php:455 msgid "Personal Page Subtypes" msgstr "" -#: src/Module/Settings/Account.php:455 -msgid "Community Forum Subtypes" +#: src/Module/Settings/Account.php:456 +msgid "Community Group Subtypes" msgstr "" -#: src/Module/Settings/Account.php:465 +#: src/Module/Settings/Account.php:466 msgid "Account for a personal profile." msgstr "" -#: src/Module/Settings/Account.php:472 +#: src/Module/Settings/Account.php:473 msgid "" "Account for an organisation that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: src/Module/Settings/Account.php:479 +#: src/Module/Settings/Account.php:480 msgid "" "Account for a news reflector that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: src/Module/Settings/Account.php:486 +#: src/Module/Settings/Account.php:487 msgid "Account for community discussions." msgstr "" -#: src/Module/Settings/Account.php:493 +#: src/Module/Settings/Account.php:494 msgid "" "Account for a regular personal profile that requires manual approval of " "\"Friends\" and \"Followers\"." msgstr "" -#: src/Module/Settings/Account.php:500 +#: src/Module/Settings/Account.php:501 msgid "" "Account for a public profile that automatically approves contact requests as " "\"Followers\"." msgstr "" -#: src/Module/Settings/Account.php:507 +#: src/Module/Settings/Account.php:508 msgid "Automatically approves all contact requests." msgstr "" -#: src/Module/Settings/Account.php:514 +#: src/Module/Settings/Account.php:515 msgid "" "Account for a popular profile that automatically approves contact requests " "as \"Friends\"." msgstr "" -#: src/Module/Settings/Account.php:519 -msgid "Private Forum [Experimental]" +#: src/Module/Settings/Account.php:520 +msgid "Private Group [Experimental]" msgstr "" -#: src/Module/Settings/Account.php:521 +#: src/Module/Settings/Account.php:522 msgid "Requires manual approval of contact requests." msgstr "" -#: src/Module/Settings/Account.php:530 +#: src/Module/Settings/Account.php:531 msgid "OpenID:" msgstr "" -#: src/Module/Settings/Account.php:530 +#: src/Module/Settings/Account.php:531 msgid "(Optional) Allow this OpenID to login to this account." msgstr "" -#: src/Module/Settings/Account.php:538 +#: src/Module/Settings/Account.php:539 msgid "Publish your profile in your local site directory?" msgstr "" -#: src/Module/Settings/Account.php:538 +#: src/Module/Settings/Account.php:539 #, php-format msgid "" "Your profile will be published in this node's local " @@ -9086,89 +9355,94 @@ msgid "" "system settings." msgstr "" -#: src/Module/Settings/Account.php:544 +#: src/Module/Settings/Account.php:545 #, php-format msgid "" "Your profile will also be published in the global friendica directories (e." "g. %s)." msgstr "" -#: src/Module/Settings/Account.php:557 +#: src/Module/Settings/Account.php:558 msgid "Account Settings" msgstr "" -#: src/Module/Settings/Account.php:558 +#: src/Module/Settings/Account.php:559 #, php-format msgid "Your Identity Address is '%s' or '%s'." msgstr "" -#: src/Module/Settings/Account.php:565 +#: src/Module/Settings/Account.php:566 msgid "Password Settings" msgstr "" -#: src/Module/Settings/Account.php:567 +#: src/Module/Settings/Account.php:568 msgid "Leave password fields blank unless changing" msgstr "" -#: src/Module/Settings/Account.php:569 +#: src/Module/Settings/Account.php:570 msgid "Password:" msgstr "" -#: src/Module/Settings/Account.php:569 +#: src/Module/Settings/Account.php:570 msgid "Your current password to confirm the changes of the email address" msgstr "" -#: src/Module/Settings/Account.php:572 +#: src/Module/Settings/Account.php:573 msgid "Delete OpenID URL" msgstr "" -#: src/Module/Settings/Account.php:574 +#: src/Module/Settings/Account.php:575 msgid "Basic Settings" msgstr "" #: src/Module/Settings/Account.php:576 -msgid "Email Address:" +#: src/Module/Settings/Profile/Index.php:283 +msgid "Display name:" msgstr "" #: src/Module/Settings/Account.php:577 +msgid "Email Address:" +msgstr "" + +#: src/Module/Settings/Account.php:578 msgid "Your Timezone:" msgstr "" -#: src/Module/Settings/Account.php:578 +#: src/Module/Settings/Account.php:579 msgid "Your Language:" msgstr "" -#: src/Module/Settings/Account.php:578 +#: src/Module/Settings/Account.php:579 msgid "" "Set the language we use to show you friendica interface and to send you " "emails" msgstr "" -#: src/Module/Settings/Account.php:579 +#: src/Module/Settings/Account.php:580 msgid "Default Post Location:" msgstr "" -#: src/Module/Settings/Account.php:580 +#: src/Module/Settings/Account.php:581 msgid "Use Browser Location:" msgstr "" -#: src/Module/Settings/Account.php:582 +#: src/Module/Settings/Account.php:583 msgid "Security and Privacy Settings" msgstr "" -#: src/Module/Settings/Account.php:584 +#: src/Module/Settings/Account.php:585 msgid "Maximum Friend Requests/Day:" msgstr "" -#: src/Module/Settings/Account.php:584 src/Module/Settings/Account.php:594 +#: src/Module/Settings/Account.php:585 src/Module/Settings/Account.php:595 msgid "(to prevent spam abuse)" msgstr "" -#: src/Module/Settings/Account.php:586 +#: src/Module/Settings/Account.php:587 msgid "Allow your profile to be searchable globally?" msgstr "" -#: src/Module/Settings/Account.php:586 +#: src/Module/Settings/Account.php:587 msgid "" "Activate this setting if you want others to easily find and follow you. Your " "profile will be searchable on remote systems. This setting also determines " @@ -9176,43 +9450,43 @@ msgid "" "indexed or not." msgstr "" -#: src/Module/Settings/Account.php:587 +#: src/Module/Settings/Account.php:588 msgid "Hide your contact/friend list from viewers of your profile?" msgstr "" -#: src/Module/Settings/Account.php:587 +#: src/Module/Settings/Account.php:588 msgid "" "A list of your contacts is displayed on your profile page. Activate this " "option to disable the display of your contact list." msgstr "" -#: src/Module/Settings/Account.php:588 +#: src/Module/Settings/Account.php:589 msgid "Hide your public content from anonymous viewers" msgstr "" -#: src/Module/Settings/Account.php:588 +#: src/Module/Settings/Account.php:589 msgid "" "Anonymous visitors will only see your basic profile details. Your public " "posts and replies will still be freely accessible on the remote servers of " "your followers and through relays." msgstr "" -#: src/Module/Settings/Account.php:589 +#: src/Module/Settings/Account.php:590 msgid "Make public posts unlisted" msgstr "" -#: src/Module/Settings/Account.php:589 +#: src/Module/Settings/Account.php:590 msgid "" "Your public posts will not appear on the community pages or in search " "results, nor be sent to relay servers. However they can still appear on " "public feeds on remote servers." msgstr "" -#: src/Module/Settings/Account.php:590 +#: src/Module/Settings/Account.php:591 msgid "Make all posted pictures accessible" msgstr "" -#: src/Module/Settings/Account.php:590 +#: src/Module/Settings/Account.php:591 msgid "" "This option makes every posted picture accessible via the direct link. This " "is a workaround for the problem that most other networks can't handle " @@ -9220,233 +9494,241 @@ msgid "" "public on your photo albums though." msgstr "" -#: src/Module/Settings/Account.php:591 +#: src/Module/Settings/Account.php:592 msgid "Allow friends to post to your profile page?" msgstr "" -#: src/Module/Settings/Account.php:591 +#: src/Module/Settings/Account.php:592 msgid "" "Your contacts may write posts on your profile wall. These posts will be " "distributed to your contacts" msgstr "" -#: src/Module/Settings/Account.php:592 +#: src/Module/Settings/Account.php:593 msgid "Allow friends to tag your posts?" msgstr "" -#: src/Module/Settings/Account.php:592 +#: src/Module/Settings/Account.php:593 msgid "Your contacts can add additional tags to your posts." msgstr "" -#: src/Module/Settings/Account.php:593 +#: src/Module/Settings/Account.php:594 msgid "Permit unknown people to send you private mail?" msgstr "" -#: src/Module/Settings/Account.php:593 +#: src/Module/Settings/Account.php:594 msgid "" "Friendica network users may send you private messages even if they are not " "in your contact list." msgstr "" -#: src/Module/Settings/Account.php:594 +#: src/Module/Settings/Account.php:595 msgid "Maximum private messages per day from unknown people:" msgstr "" #: src/Module/Settings/Account.php:596 +msgid "Default privacy circle for new contacts" +msgstr "" + +#: src/Module/Settings/Account.php:597 +msgid "Default privacy circle for new group contacts" +msgstr "" + +#: src/Module/Settings/Account.php:598 msgid "Default Post Permissions" msgstr "" -#: src/Module/Settings/Account.php:600 +#: src/Module/Settings/Account.php:602 msgid "Expiration settings" msgstr "" -#: src/Module/Settings/Account.php:601 +#: src/Module/Settings/Account.php:603 msgid "Automatically expire posts after this many days:" msgstr "" -#: src/Module/Settings/Account.php:601 +#: src/Module/Settings/Account.php:603 msgid "If empty, posts will not expire. Expired posts will be deleted" msgstr "" -#: src/Module/Settings/Account.php:602 +#: src/Module/Settings/Account.php:604 msgid "Expire posts" msgstr "" -#: src/Module/Settings/Account.php:602 +#: src/Module/Settings/Account.php:604 msgid "When activated, posts and comments will be expired." msgstr "" -#: src/Module/Settings/Account.php:603 +#: src/Module/Settings/Account.php:605 msgid "Expire personal notes" msgstr "" -#: src/Module/Settings/Account.php:603 +#: src/Module/Settings/Account.php:605 msgid "" "When activated, the personal notes on your profile page will be expired." msgstr "" -#: src/Module/Settings/Account.php:604 +#: src/Module/Settings/Account.php:606 msgid "Expire starred posts" msgstr "" -#: src/Module/Settings/Account.php:604 +#: src/Module/Settings/Account.php:606 msgid "" "Starring posts keeps them from being expired. That behaviour is overwritten " "by this setting." msgstr "" -#: src/Module/Settings/Account.php:605 +#: src/Module/Settings/Account.php:607 msgid "Only expire posts by others" msgstr "" -#: src/Module/Settings/Account.php:605 +#: src/Module/Settings/Account.php:607 msgid "" "When activated, your own posts never expire. Then the settings above are " "only valid for posts you received." msgstr "" -#: src/Module/Settings/Account.php:608 +#: src/Module/Settings/Account.php:610 msgid "Notification Settings" msgstr "" -#: src/Module/Settings/Account.php:609 +#: src/Module/Settings/Account.php:611 msgid "Send a notification email when:" msgstr "" -#: src/Module/Settings/Account.php:610 +#: src/Module/Settings/Account.php:612 msgid "You receive an introduction" msgstr "" -#: src/Module/Settings/Account.php:611 +#: src/Module/Settings/Account.php:613 msgid "Your introductions are confirmed" msgstr "" -#: src/Module/Settings/Account.php:612 +#: src/Module/Settings/Account.php:614 msgid "Someone writes on your profile wall" msgstr "" -#: src/Module/Settings/Account.php:613 +#: src/Module/Settings/Account.php:615 msgid "Someone writes a followup comment" msgstr "" -#: src/Module/Settings/Account.php:614 +#: src/Module/Settings/Account.php:616 msgid "You receive a private message" msgstr "" -#: src/Module/Settings/Account.php:615 +#: src/Module/Settings/Account.php:617 msgid "You receive a friend suggestion" msgstr "" -#: src/Module/Settings/Account.php:616 +#: src/Module/Settings/Account.php:618 msgid "You are tagged in a post" msgstr "" -#: src/Module/Settings/Account.php:618 +#: src/Module/Settings/Account.php:620 msgid "Create a desktop notification when:" msgstr "" -#: src/Module/Settings/Account.php:619 +#: src/Module/Settings/Account.php:621 msgid "Someone tagged you" msgstr "" -#: src/Module/Settings/Account.php:620 +#: src/Module/Settings/Account.php:622 msgid "Someone directly commented on your post" msgstr "" -#: src/Module/Settings/Account.php:621 +#: src/Module/Settings/Account.php:623 msgid "Someone liked your content" msgstr "" -#: src/Module/Settings/Account.php:621 src/Module/Settings/Account.php:622 +#: src/Module/Settings/Account.php:623 src/Module/Settings/Account.php:624 msgid "Can only be enabled, when the direct comment notification is enabled." msgstr "" -#: src/Module/Settings/Account.php:622 +#: src/Module/Settings/Account.php:624 msgid "Someone shared your content" msgstr "" -#: src/Module/Settings/Account.php:623 +#: src/Module/Settings/Account.php:625 msgid "Someone commented in your thread" msgstr "" -#: src/Module/Settings/Account.php:624 +#: src/Module/Settings/Account.php:626 msgid "Someone commented in a thread where you commented" msgstr "" -#: src/Module/Settings/Account.php:625 +#: src/Module/Settings/Account.php:627 msgid "Someone commented in a thread where you interacted" msgstr "" -#: src/Module/Settings/Account.php:627 +#: src/Module/Settings/Account.php:629 msgid "Activate desktop notifications" msgstr "" -#: src/Module/Settings/Account.php:627 +#: src/Module/Settings/Account.php:629 msgid "Show desktop popup on new notifications" msgstr "" -#: src/Module/Settings/Account.php:631 +#: src/Module/Settings/Account.php:633 msgid "Text-only notification emails" msgstr "" -#: src/Module/Settings/Account.php:633 +#: src/Module/Settings/Account.php:635 msgid "Send text only notification emails, without the html part" msgstr "" -#: src/Module/Settings/Account.php:637 +#: src/Module/Settings/Account.php:639 msgid "Show detailled notifications" msgstr "" -#: src/Module/Settings/Account.php:639 +#: src/Module/Settings/Account.php:641 msgid "" "Per default, notifications are condensed to a single notification per item. " "When enabled every notification is displayed." msgstr "" -#: src/Module/Settings/Account.php:643 +#: src/Module/Settings/Account.php:645 msgid "Show notifications of ignored contacts" msgstr "" -#: src/Module/Settings/Account.php:645 +#: src/Module/Settings/Account.php:647 msgid "" "You don't see posts from ignored contacts. But you still see their comments. " "This setting controls if you want to still receive regular notifications " "that are caused by ignored contacts or not." msgstr "" -#: src/Module/Settings/Account.php:648 +#: src/Module/Settings/Account.php:650 msgid "Advanced Account/Page Type Settings" msgstr "" -#: src/Module/Settings/Account.php:649 +#: src/Module/Settings/Account.php:651 msgid "Change the behaviour of this account for special situations" msgstr "" -#: src/Module/Settings/Account.php:652 +#: src/Module/Settings/Account.php:654 msgid "Import Contacts" msgstr "" -#: src/Module/Settings/Account.php:653 +#: src/Module/Settings/Account.php:655 msgid "" "Upload a CSV file that contains the handle of your followed accounts in the " "first column you exported from the old account." msgstr "" -#: src/Module/Settings/Account.php:654 +#: src/Module/Settings/Account.php:656 msgid "Upload File" msgstr "" -#: src/Module/Settings/Account.php:657 +#: src/Module/Settings/Account.php:659 msgid "Relocate" msgstr "" -#: src/Module/Settings/Account.php:658 +#: src/Module/Settings/Account.php:660 msgid "" "If you have moved this profile from another server, and some of your " "contacts don't receive your updates, try pushing this button." msgstr "" -#: src/Module/Settings/Account.php:659 +#: src/Module/Settings/Account.php:661 msgid "Resend relocate message to contacts" msgstr "" @@ -9654,80 +9936,80 @@ msgstr "" msgid "Move to folder:" msgstr "" -#: src/Module/Settings/Delegation.php:52 +#: src/Module/Settings/Delegation.php:54 msgid "Delegation successfully granted." msgstr "" -#: src/Module/Settings/Delegation.php:54 +#: src/Module/Settings/Delegation.php:56 msgid "Parent user not found, unavailable or password doesn't match." msgstr "" -#: src/Module/Settings/Delegation.php:58 +#: src/Module/Settings/Delegation.php:60 msgid "Delegation successfully revoked." msgstr "" -#: src/Module/Settings/Delegation.php:80 src/Module/Settings/Delegation.php:102 +#: src/Module/Settings/Delegation.php:82 src/Module/Settings/Delegation.php:104 msgid "" "Delegated administrators can view but not change delegation permissions." msgstr "" -#: src/Module/Settings/Delegation.php:94 +#: src/Module/Settings/Delegation.php:96 msgid "Delegate user not found." msgstr "" -#: src/Module/Settings/Delegation.php:142 +#: src/Module/Settings/Delegation.php:144 msgid "No parent user" msgstr "" -#: src/Module/Settings/Delegation.php:153 -#: src/Module/Settings/Delegation.php:164 +#: src/Module/Settings/Delegation.php:155 +#: src/Module/Settings/Delegation.php:166 msgid "Parent User" msgstr "" -#: src/Module/Settings/Delegation.php:161 +#: src/Module/Settings/Delegation.php:163 msgid "Additional Accounts" msgstr "" -#: src/Module/Settings/Delegation.php:162 +#: src/Module/Settings/Delegation.php:164 msgid "" "Register additional accounts that are automatically connected to your " "existing account so you can manage them from this account." msgstr "" -#: src/Module/Settings/Delegation.php:163 +#: src/Module/Settings/Delegation.php:165 msgid "Register an additional account" msgstr "" -#: src/Module/Settings/Delegation.php:167 +#: src/Module/Settings/Delegation.php:169 msgid "" "Parent users have total control about this account, including the account " "settings. Please double check whom you give this access." msgstr "" -#: src/Module/Settings/Delegation.php:171 +#: src/Module/Settings/Delegation.php:173 msgid "Delegates" msgstr "" -#: src/Module/Settings/Delegation.php:173 +#: src/Module/Settings/Delegation.php:175 msgid "" "Delegates are able to manage all aspects of this account/page except for " "basic account settings. Please do not delegate your personal account to " "anybody that you do not trust completely." msgstr "" -#: src/Module/Settings/Delegation.php:174 +#: src/Module/Settings/Delegation.php:176 msgid "Existing Page Delegates" msgstr "" -#: src/Module/Settings/Delegation.php:176 +#: src/Module/Settings/Delegation.php:178 msgid "Potential Delegates" msgstr "" -#: src/Module/Settings/Delegation.php:179 +#: src/Module/Settings/Delegation.php:181 msgid "Add" msgstr "" -#: src/Module/Settings/Delegation.php:180 +#: src/Module/Settings/Delegation.php:182 msgid "No entries." msgstr "" @@ -9882,146 +10164,85 @@ msgstr "" msgid "Remove authorization" msgstr "" -#: src/Module/Settings/Profile/Index.php:84 -msgid "Profile Name is required." +#: src/Module/Settings/Profile/Index.php:116 +msgid "Display Name is required." msgstr "" -#: src/Module/Settings/Profile/Index.php:134 +#: src/Module/Settings/Profile/Index.php:167 msgid "Profile couldn't be updated." msgstr "" -#: src/Module/Settings/Profile/Index.php:175 -#: src/Module/Settings/Profile/Index.php:195 +#: src/Module/Settings/Profile/Index.php:205 +#: src/Module/Settings/Profile/Index.php:226 msgid "Label:" msgstr "" -#: src/Module/Settings/Profile/Index.php:176 -#: src/Module/Settings/Profile/Index.php:196 +#: src/Module/Settings/Profile/Index.php:206 +#: src/Module/Settings/Profile/Index.php:227 msgid "Value:" msgstr "" -#: src/Module/Settings/Profile/Index.php:186 -#: src/Module/Settings/Profile/Index.php:206 +#: src/Module/Settings/Profile/Index.php:217 +#: src/Module/Settings/Profile/Index.php:238 msgid "Field Permissions" msgstr "" -#: src/Module/Settings/Profile/Index.php:187 -#: src/Module/Settings/Profile/Index.php:207 +#: src/Module/Settings/Profile/Index.php:218 +#: src/Module/Settings/Profile/Index.php:239 msgid "(click to open/close)" msgstr "" -#: src/Module/Settings/Profile/Index.php:193 +#: src/Module/Settings/Profile/Index.php:224 msgid "Add a new profile field" msgstr "" -#: src/Module/Settings/Profile/Index.php:216 +#: src/Module/Settings/Profile/Index.php:247 msgid "" "The homepage is verified. A rel=\"me\" link back to your Friendica profile " "page was found on the homepage." msgstr "" -#: src/Module/Settings/Profile/Index.php:218 +#: src/Module/Settings/Profile/Index.php:249 #, php-format msgid "" "To verify your homepage, add a rel=\"me\" link to it, pointing to your " "profile URL (%s)." msgstr "" -#: src/Module/Settings/Profile/Index.php:228 +#: src/Module/Settings/Profile/Index.php:255 msgid "Profile Actions" msgstr "" -#: src/Module/Settings/Profile/Index.php:229 +#: src/Module/Settings/Profile/Index.php:256 msgid "Edit Profile Details" msgstr "" -#: src/Module/Settings/Profile/Index.php:231 +#: src/Module/Settings/Profile/Index.php:258 msgid "Change Profile Photo" msgstr "" -#: src/Module/Settings/Profile/Index.php:236 +#: src/Module/Settings/Profile/Index.php:261 msgid "Profile picture" msgstr "" -#: src/Module/Settings/Profile/Index.php:237 +#: src/Module/Settings/Profile/Index.php:262 msgid "Location" msgstr "" -#: src/Module/Settings/Profile/Index.php:238 src/Util/Temporal.php:97 +#: src/Module/Settings/Profile/Index.php:263 src/Util/Temporal.php:97 #: src/Util/Temporal.php:99 msgid "Miscellaneous" msgstr "" -#: src/Module/Settings/Profile/Index.php:239 +#: src/Module/Settings/Profile/Index.php:264 msgid "Custom Profile Fields" msgstr "" -#: src/Module/Settings/Profile/Index.php:241 src/Module/Welcome.php:58 +#: src/Module/Settings/Profile/Index.php:265 src/Module/Welcome.php:58 msgid "Upload Profile Photo" msgstr "" -#: src/Module/Settings/Profile/Index.php:245 -msgid "Display name:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:248 -msgid "Street Address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:249 -msgid "Locality/City:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:250 -msgid "Region/State:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:251 -msgid "Postal/Zip Code:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:252 -msgid "Country:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:254 -msgid "XMPP (Jabber) address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:254 -msgid "The XMPP address will be published so that people can follow you there." -msgstr "" - -#: src/Module/Settings/Profile/Index.php:255 -msgid "Matrix (Element) address:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:255 -msgid "" -"The Matrix address will be published so that people can follow you there." -msgstr "" - -#: src/Module/Settings/Profile/Index.php:256 -msgid "Homepage URL:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:257 -msgid "Public Keywords:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:257 -msgid "(Used for suggesting potential friends, can be seen by others)" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:258 -msgid "Private Keywords:" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:258 -msgid "(Used for searching profiles, never shown to others)" -msgstr "" - -#: src/Module/Settings/Profile/Index.php:259 +#: src/Module/Settings/Profile/Index.php:266 #, php-format msgid "" "

Custom fields appear on your profile page.

\n" @@ -10029,7 +10250,64 @@ msgid "" "\t\t\t\t

Reorder by dragging the field title.

\n" "\t\t\t\t

Empty the label field to remove a custom field.

\n" "\t\t\t\t

Non-public fields can only be seen by the selected Friendica " -"contacts or the Friendica contacts in the selected groups.

" +"contacts or the Friendica contacts in the selected circles.

" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:286 +msgid "Street Address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:287 +msgid "Locality/City:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:288 +msgid "Region/State:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:289 +msgid "Postal/Zip Code:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:290 +msgid "Country:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:292 +msgid "XMPP (Jabber) address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:292 +msgid "The XMPP address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:293 +msgid "Matrix (Element) address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:293 +msgid "" +"The Matrix address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:294 +msgid "Homepage URL:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:295 +msgid "Public Keywords:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:295 +msgid "(Used for suggesting potential friends, can be seen by others)" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:296 +msgid "Private Keywords:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:296 +msgid "(Used for searching profiles, never shown to others)" msgstr "" #: src/Module/Settings/Profile/Photo/Crop.php:107 @@ -10142,6 +10420,42 @@ msgstr "" msgid "Please enter your password for verification:" msgstr "" +#: src/Module/Settings/Server/Action.php:60 +msgid "Do you want to ignore this server?" +msgstr "" + +#: src/Module/Settings/Server/Action.php:64 +msgid "Do you want to unignore this server?" +msgstr "" + +#: src/Module/Settings/Server/Action.php:74 +#: src/Module/Settings/Server/Index.php:104 +msgid "Remote server settings" +msgstr "" + +#: src/Module/Settings/Server/Action.php:77 +msgid "Server URL" +msgstr "" + +#: src/Module/Settings/Server/Index.php:78 +msgid "Settings saved" +msgstr "" + +#: src/Module/Settings/Server/Index.php:105 +msgid "" +"Here you can find all the remote servers you have taken individual " +"moderation actions against. For a list of servers your node has blocked, " +"please check out the Information page." +msgstr "" + +#: src/Module/Settings/Server/Index.php:110 +msgid "Delete all your settings for the remote server" +msgstr "" + +#: src/Module/Settings/Server/Index.php:111 +msgid "Save changes" +msgstr "" + #: src/Module/Settings/TwoFactor/AppSpecific.php:66 #: src/Module/Settings/TwoFactor/Recovery.php:64 #: src/Module/Settings/TwoFactor/Trusted.php:67 @@ -10462,22 +10776,41 @@ msgid "" "e.g. Mastodon." msgstr "" +#: src/Module/Special/DisplayNotFound.php:35 +msgid "The top-level post isn't visible." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:36 +msgid "The top-level post was deleted." +msgstr "" + #: src/Module/Special/DisplayNotFound.php:37 -msgid "Not Found" +msgid "" +"This node has blocked the top-level author or the author of the shared post." msgstr "" #: src/Module/Special/DisplayNotFound.php:38 msgid "" -"

Unfortunately, the requested conversation isn't available to you.

\n" -"

Possible reasons include:

\n" -"
    \n" -"\t
  • The top-level post isn't visible.
  • \n" -"\t
  • The top-level post was deleted.
  • \n" -"\t
  • The node has blocked the top-level author or the author of the shared " -"post.
  • \n" -"\t
  • You have ignored or blocked the top-level author or the author of the " -"shared post.
  • \n" -"
" +"You have ignored or blocked the top-level author or the author of the shared " +"post." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:39 +msgid "" +"You have ignored the top-level author's server or the shared post author's " +"server." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:45 +msgid "Conversation Not Found" +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:46 +msgid "Unfortunately, the requested conversation isn't available to you." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:47 +msgid "Possible reasons include:" msgstr "" #: src/Module/Special/HTTPException.php:78 @@ -10489,7 +10822,7 @@ msgstr "" msgid "Exception thrown in %s:%d" msgstr "" -#: src/Module/Tos.php:57 src/Module/Tos.php:106 +#: src/Module/Tos.php:58 src/Module/Tos.php:107 msgid "" "At the time of registration, and for providing communications between the " "user account and their contacts, the user has to provide a display name (pen " @@ -10502,14 +10835,14 @@ msgid "" "settings, it is not necessary for communication." msgstr "" -#: src/Module/Tos.php:58 src/Module/Tos.php:107 +#: src/Module/Tos.php:59 src/Module/Tos.php:108 msgid "" "This data is required for communication and is passed on to the nodes of the " "communication partners and is stored there. Users can enter additional " "private data that may be transmitted to the communication partners accounts." msgstr "" -#: src/Module/Tos.php:59 src/Module/Tos.php:108 +#: src/Module/Tos.php:60 src/Module/Tos.php:109 #, php-format msgid "" "At any point in time a logged in user can export their account data from the " @@ -10520,11 +10853,11 @@ msgid "" "communication partners." msgstr "" -#: src/Module/Tos.php:62 src/Module/Tos.php:105 +#: src/Module/Tos.php:63 src/Module/Tos.php:106 msgid "Privacy Statement" msgstr "" -#: src/Module/Tos.php:102 +#: src/Module/Tos.php:103 msgid "Rules" msgstr "" @@ -10532,6 +10865,10 @@ msgstr "" msgid "Parameter uri_id is missing." msgstr "" +#: src/Module/Update/Display.php:55 +msgid "The requested item doesn't exist or has been deleted." +msgstr "" + #: src/Module/User/Import.php:103 msgid "User imports on closed servers can only be done by an administrator." msgstr "" @@ -10580,22 +10917,22 @@ msgstr "" msgid "User '%s' already exists on this server!" msgstr "" -#: src/Module/User/Import.php:263 +#: src/Module/User/Import.php:267 msgid "User creation error" msgstr "" -#: src/Module/User/Import.php:312 +#: src/Module/User/Import.php:316 #, php-format msgid "%d contact not imported" msgid_plural "%d contacts not imported" msgstr[0] "" msgstr[1] "" -#: src/Module/User/Import.php:361 +#: src/Module/User/Import.php:365 msgid "User profile creation error" msgstr "" -#: src/Module/User/Import.php:412 +#: src/Module/User/Import.php:416 msgid "Done. You can now login with your username and password" msgstr "" @@ -10729,14 +11066,14 @@ msgid "" msgstr "" #: src/Module/Welcome.php:77 -msgid "Group Your Contacts" +msgid "Add Your Contacts To Circle" msgstr "" #: src/Module/Welcome.php:78 msgid "" "Once you have made some friends, organize them into private conversation " -"groups from the sidebar of your Contacts page and then you can interact with " -"each group privately on your Network page." +"circles from the sidebar of your Contacts page and then you can interact " +"with each circle privately on your Network page." msgstr "" #: src/Module/Welcome.php:80 @@ -11242,254 +11579,258 @@ msgstr "" msgid "%s posted an update." msgstr "" -#: src/Object/Post.php:135 +#: src/Object/Post.php:138 msgid "Private Message" msgstr "" -#: src/Object/Post.php:139 +#: src/Object/Post.php:142 msgid "Public Message" msgstr "" -#: src/Object/Post.php:143 +#: src/Object/Post.php:146 msgid "Unlisted Message" msgstr "" -#: src/Object/Post.php:178 +#: src/Object/Post.php:181 msgid "This entry was edited" msgstr "" -#: src/Object/Post.php:206 +#: src/Object/Post.php:209 msgid "Connector Message" msgstr "" -#: src/Object/Post.php:222 src/Object/Post.php:224 +#: src/Object/Post.php:225 src/Object/Post.php:227 msgid "Edit" msgstr "" -#: src/Object/Post.php:248 +#: src/Object/Post.php:261 msgid "Delete globally" msgstr "" -#: src/Object/Post.php:248 +#: src/Object/Post.php:261 msgid "Remove locally" msgstr "" -#: src/Object/Post.php:266 +#: src/Object/Post.php:268 #, php-format msgid "Block %s" msgstr "" -#: src/Object/Post.php:271 +#: src/Object/Post.php:273 #, php-format msgid "Ignore %s" msgstr "" -#: src/Object/Post.php:276 +#: src/Object/Post.php:278 #, php-format msgid "Collapse %s" msgstr "" -#: src/Object/Post.php:281 +#: src/Object/Post.php:282 +msgid "Report post" +msgstr "" + +#: src/Object/Post.php:293 msgid "Save to folder" msgstr "" -#: src/Object/Post.php:316 +#: src/Object/Post.php:333 msgid "I will attend" msgstr "" -#: src/Object/Post.php:316 +#: src/Object/Post.php:333 msgid "I will not attend" msgstr "" -#: src/Object/Post.php:316 +#: src/Object/Post.php:333 msgid "I might attend" msgstr "" -#: src/Object/Post.php:346 +#: src/Object/Post.php:363 msgid "Ignore thread" msgstr "" -#: src/Object/Post.php:347 +#: src/Object/Post.php:364 msgid "Unignore thread" msgstr "" -#: src/Object/Post.php:348 +#: src/Object/Post.php:365 msgid "Toggle ignore status" msgstr "" -#: src/Object/Post.php:358 +#: src/Object/Post.php:375 msgid "Add star" msgstr "" -#: src/Object/Post.php:359 +#: src/Object/Post.php:376 msgid "Remove star" msgstr "" -#: src/Object/Post.php:360 +#: src/Object/Post.php:377 msgid "Toggle star status" msgstr "" -#: src/Object/Post.php:371 +#: src/Object/Post.php:388 msgid "Pin" msgstr "" -#: src/Object/Post.php:372 +#: src/Object/Post.php:389 msgid "Unpin" msgstr "" -#: src/Object/Post.php:373 +#: src/Object/Post.php:390 msgid "Toggle pin status" msgstr "" -#: src/Object/Post.php:376 +#: src/Object/Post.php:393 msgid "Pinned" msgstr "" -#: src/Object/Post.php:381 +#: src/Object/Post.php:398 msgid "Add tag" msgstr "" -#: src/Object/Post.php:394 +#: src/Object/Post.php:411 msgid "Quote share this" msgstr "" -#: src/Object/Post.php:394 +#: src/Object/Post.php:411 msgid "Quote Share" msgstr "" -#: src/Object/Post.php:397 +#: src/Object/Post.php:414 msgid "Reshare this" msgstr "" -#: src/Object/Post.php:397 +#: src/Object/Post.php:414 msgid "Reshare" msgstr "" -#: src/Object/Post.php:398 +#: src/Object/Post.php:415 msgid "Cancel your Reshare" msgstr "" -#: src/Object/Post.php:398 +#: src/Object/Post.php:415 msgid "Unshare" msgstr "" -#: src/Object/Post.php:449 +#: src/Object/Post.php:466 #, php-format msgid "%s (Received %s)" msgstr "" -#: src/Object/Post.php:454 +#: src/Object/Post.php:472 msgid "Comment this item on your system" msgstr "" -#: src/Object/Post.php:454 +#: src/Object/Post.php:472 msgid "Remote comment" msgstr "" -#: src/Object/Post.php:475 +#: src/Object/Post.php:494 msgid "Share via ..." msgstr "" -#: src/Object/Post.php:475 +#: src/Object/Post.php:494 msgid "Share via external services" msgstr "" -#: src/Object/Post.php:504 +#: src/Object/Post.php:523 msgid "to" msgstr "" -#: src/Object/Post.php:505 +#: src/Object/Post.php:524 msgid "via" msgstr "" -#: src/Object/Post.php:506 +#: src/Object/Post.php:525 msgid "Wall-to-Wall" msgstr "" -#: src/Object/Post.php:507 +#: src/Object/Post.php:526 msgid "via Wall-To-Wall:" msgstr "" -#: src/Object/Post.php:552 +#: src/Object/Post.php:573 #, php-format msgid "Reply to %s" msgstr "" -#: src/Object/Post.php:555 +#: src/Object/Post.php:576 msgid "More" msgstr "" -#: src/Object/Post.php:573 +#: src/Object/Post.php:595 msgid "Notifier task is pending" msgstr "" -#: src/Object/Post.php:574 +#: src/Object/Post.php:596 msgid "Delivery to remote servers is pending" msgstr "" -#: src/Object/Post.php:575 +#: src/Object/Post.php:597 msgid "Delivery to remote servers is underway" msgstr "" -#: src/Object/Post.php:576 +#: src/Object/Post.php:598 msgid "Delivery to remote servers is mostly done" msgstr "" -#: src/Object/Post.php:577 +#: src/Object/Post.php:599 msgid "Delivery to remote servers is done" msgstr "" -#: src/Object/Post.php:597 +#: src/Object/Post.php:619 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "" msgstr[1] "" -#: src/Object/Post.php:598 +#: src/Object/Post.php:620 msgid "Show more" msgstr "" -#: src/Object/Post.php:599 +#: src/Object/Post.php:621 msgid "Show fewer" msgstr "" -#: src/Object/Post.php:635 +#: src/Object/Post.php:657 #, php-format msgid "Reshared by: %s" msgstr "" -#: src/Object/Post.php:640 +#: src/Object/Post.php:662 #, php-format msgid "Viewed by: %s" msgstr "" -#: src/Object/Post.php:645 +#: src/Object/Post.php:667 #, php-format msgid "Liked by: %s" msgstr "" -#: src/Object/Post.php:650 +#: src/Object/Post.php:672 #, php-format msgid "Disliked by: %s" msgstr "" -#: src/Object/Post.php:655 +#: src/Object/Post.php:677 #, php-format msgid "Attended by: %s" msgstr "" -#: src/Object/Post.php:660 +#: src/Object/Post.php:682 #, php-format msgid "Maybe attended by: %s" msgstr "" -#: src/Object/Post.php:665 +#: src/Object/Post.php:687 #, php-format msgid "Not attended by: %s" msgstr "" -#: src/Object/Post.php:670 +#: src/Object/Post.php:692 #, php-format msgid "Reacted with %s by: %s" msgstr "" @@ -11498,21 +11839,21 @@ msgstr "" msgid "(no subject)" msgstr "" -#: src/Protocol/OStatus.php:1388 +#: src/Protocol/OStatus.php:1390 #, php-format msgid "%s is now following %s." msgstr "" -#: src/Protocol/OStatus.php:1389 +#: src/Protocol/OStatus.php:1391 msgid "following" msgstr "" -#: src/Protocol/OStatus.php:1392 +#: src/Protocol/OStatus.php:1394 #, php-format msgid "%s stopped following %s." msgstr "" -#: src/Protocol/OStatus.php:1393 +#: src/Protocol/OStatus.php:1395 msgid "stopped following" msgstr "" @@ -11870,7 +12211,7 @@ msgid "Textareas font size" msgstr "" #: view/theme/vier/config.php:91 -msgid "Comma separated list of helper forums" +msgid "Comma separated list of helper groups" msgstr "" #: view/theme/vier/config.php:131 diff --git a/view/lang/de/messages.po b/view/lang/de/messages.po index 24f0cf619..1c3d54c23 100644 --- a/view/lang/de/messages.po +++ b/view/lang/de/messages.po @@ -11,12 +11,13 @@ # Copiis Praeesse , 2018-2020,2023 # David Rabel , 2016 # Erkan Yilmaz , 2011 -# F1per 3y, 2023 +# Raroun, 2023 # Fabian Dost , 2012 # foss , 2014,2016-2017,2020,2022 # Frank Dieckmann , 2015 # Fabian Dost , 2012 # greeneyedred , 2012 +# haheute , 2023 # Hauke , 2012,2018 # Herbert Thielen , 2017 # hoergen , 2018-2019 @@ -35,6 +36,7 @@ # foss , 2022 # rabuzarus , 2016-2019 # Ralf Thees , 2019 +# Raroun, 2023 # René Wagner , 2019-2020 # a4e12f943b784a073d5fd49662354257_daaba5c , 2013 # a4e12f943b784a073d5fd49662354257_daaba5c , 2012-2013 @@ -52,9 +54,9 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-04-23 21:21+0000\n" +"POT-Creation-Date: 2023-06-01 19:00-0400\n" "PO-Revision-Date: 2011-05-05 10:19+0000\n" -"Last-Translator: F1per 3y, 2023\n" +"Last-Translator: Tobias Diekershoff , 2016-2023\n" "Language-Team: German (http://app.transifex.com/Friendica/friendica/language/de/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -82,26 +84,26 @@ msgstr "Eintrag konnte nicht geholt werden." msgid "Empty post discarded." msgstr "Leerer Beitrag wurde verworfen." -#: mod/item.php:411 src/Module/Admin/Themes/Details.php:39 +#: mod/item.php:427 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 "Beitrag nicht gefunden." -#: mod/item.php:435 mod/message.php:68 mod/message.php:114 mod/notes.php:45 -#: mod/photos.php:152 mod/photos.php:669 src/Model/Event.php:522 +#: mod/item.php:451 mod/message.php:67 mod/message.php:113 mod/notes.php:45 +#: mod/photos.php:152 mod/photos.php:667 src/Model/Event.php:522 #: src/Module/Attach.php:55 src/Module/BaseApi.php:99 #: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 #: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 #: src/Module/Calendar/Export.php:82 src/Module/Calendar/Show.php:82 +#: src/Module/Circle.php:40 src/Module/Circle.php:83 #: src/Module/Contact/Advanced.php:60 src/Module/Contact/Follow.php:87 #: src/Module/Contact/Follow.php:160 src/Module/Contact/MatchInterests.php:86 #: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 #: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112 #: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38 -#: src/Module/FriendSuggest.php:57 src/Module/Group.php:40 -#: src/Module/Group.php:83 src/Module/Invite.php:42 src/Module/Invite.php:131 -#: src/Module/Notifications/Notification.php:76 +#: src/Module/FriendSuggest.php:57 src/Module/Invite.php:42 +#: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76 #: src/Module/Notifications/Notification.php:107 #: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66 #: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:75 @@ -112,7 +114,7 @@ msgstr "Beitrag nicht gefunden." #: src/Module/Register.php:90 src/Module/Register.php:206 #: src/Module/Register.php:245 src/Module/Search/Directory.php:37 #: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:407 -#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:69 +#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:71 #: src/Module/Settings/Display.php:69 src/Module/Settings/Display.php:151 #: src/Module/Settings/Profile/Photo/Crop.php:165 #: src/Module/Settings/Profile/Photo/Index.php:111 @@ -259,88 +261,88 @@ msgstr "\nDie Anmeldedaten sind die folgenden:\n\nAdresse der Seite: %1$s\nLogin msgid "Your password has been changed at %s" msgstr "Auf %s wurde dein Passwort geändert" -#: mod/message.php:46 mod/message.php:129 src/Content/Nav.php:319 +#: mod/message.php:46 mod/message.php:128 src/Content/Nav.php:319 msgid "New Message" msgstr "Neue Nachricht" -#: mod/message.php:83 src/Module/Profile/UnkMail.php:100 +#: mod/message.php:82 src/Module/Profile/UnkMail.php:100 msgid "No recipient selected." msgstr "Kein Empfänger gewählt." -#: mod/message.php:88 +#: mod/message.php:87 msgid "Unable to locate contact information." msgstr "Konnte die Kontaktinformationen nicht finden." -#: mod/message.php:92 src/Module/Profile/UnkMail.php:106 +#: mod/message.php:91 src/Module/Profile/UnkMail.php:106 msgid "Message could not be sent." msgstr "Nachricht konnte nicht gesendet werden." -#: mod/message.php:96 src/Module/Profile/UnkMail.php:109 +#: mod/message.php:95 src/Module/Profile/UnkMail.php:109 msgid "Message collection failure." msgstr "Konnte Nachrichten nicht abrufen." -#: mod/message.php:123 src/Module/Notifications/Introductions.php:135 +#: mod/message.php:122 src/Module/Notifications/Introductions.php:135 #: src/Module/Notifications/Introductions.php:170 #: src/Module/Notifications/Notification.php:85 msgid "Discard" msgstr "Verwerfen" -#: mod/message.php:136 src/Content/Nav.php:316 view/theme/frio/theme.php:241 +#: mod/message.php:135 src/Content/Nav.php:316 view/theme/frio/theme.php:241 msgid "Messages" msgstr "Nachrichten" -#: mod/message.php:149 +#: mod/message.php:148 msgid "Conversation not found." msgstr "Unterhaltung nicht gefunden." -#: mod/message.php:154 +#: mod/message.php:153 msgid "Message was not deleted." msgstr "Nachricht wurde nicht gelöscht" -#: mod/message.php:169 +#: mod/message.php:168 msgid "Conversation was not removed." msgstr "Unterhaltung wurde nicht entfernt" -#: mod/message.php:182 mod/message.php:287 src/Module/Profile/UnkMail.php:145 +#: mod/message.php:181 mod/message.php:286 src/Module/Profile/UnkMail.php:145 msgid "Please enter a link URL:" msgstr "Bitte gib die URL des Links ein:" -#: mod/message.php:191 src/Module/Profile/UnkMail.php:151 +#: mod/message.php:190 src/Module/Profile/UnkMail.php:151 msgid "Send Private Message" msgstr "Private Nachricht senden" -#: mod/message.php:192 mod/message.php:347 +#: mod/message.php:191 mod/message.php:346 msgid "To:" msgstr "An:" -#: mod/message.php:193 mod/message.php:348 +#: mod/message.php:192 mod/message.php:347 msgid "Subject:" msgstr "Betreff:" -#: mod/message.php:197 mod/message.php:351 src/Module/Invite.php:171 +#: mod/message.php:196 mod/message.php:350 src/Module/Invite.php:171 msgid "Your message:" msgstr "Deine Nachricht:" -#: mod/message.php:200 mod/message.php:355 src/Content/Conversation.php:360 +#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:360 #: src/Module/Post/Edit.php:131 msgid "Upload photo" msgstr "Foto hochladen" -#: mod/message.php:201 mod/message.php:356 src/Module/Post/Edit.php:135 +#: mod/message.php:200 mod/message.php:355 src/Module/Post/Edit.php:135 #: src/Module/Profile/UnkMail.php:153 msgid "Insert web link" msgstr "Einen Link einfügen" -#: mod/message.php:202 mod/message.php:358 mod/photos.php:1291 -#: src/Content/Conversation.php:389 src/Content/Conversation.php:733 -#: src/Module/Item/Compose.php:204 src/Module/Post/Edit.php:145 -#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:550 +#: mod/message.php:201 mod/message.php:357 mod/photos.php:1289 +#: src/Content/Conversation.php:390 src/Content/Conversation.php:734 +#: src/Module/Item/Compose.php:205 src/Module/Post/Edit.php:145 +#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:557 msgid "Please wait" msgstr "Bitte warten" -#: mod/message.php:203 mod/message.php:357 mod/photos.php:702 -#: mod/photos.php:819 mod/photos.php:1097 mod/photos.php:1138 -#: mod/photos.php:1194 mod/photos.php:1268 +#: mod/message.php:202 mod/message.php:356 mod/photos.php:700 +#: mod/photos.php:817 mod/photos.php:1095 mod/photos.php:1136 +#: mod/photos.php:1192 mod/photos.php:1266 #: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 #: src/Module/Contact/Profile.php:339 #: src/Module/Debug/ActivityPubConversion.php:140 @@ -351,58 +353,58 @@ msgstr "Bitte warten" #: src/Module/Install.php:309 src/Module/Invite.php:178 #: src/Module/Item/Compose.php:189 src/Module/Moderation/Item/Source.php:79 #: src/Module/Profile/Profile.php:274 src/Module/Profile/UnkMail.php:155 -#: src/Module/Settings/Profile/Index.php:230 src/Object/Post.php:1063 +#: src/Module/Settings/Profile/Index.php:230 src/Object/Post.php:1070 #: view/theme/duepuntozero/config.php:85 view/theme/frio/config.php:171 #: view/theme/quattro/config.php:87 view/theme/vier/config.php:135 msgid "Submit" msgstr "Senden" -#: mod/message.php:224 +#: mod/message.php:223 msgid "No messages." msgstr "Keine Nachrichten." -#: mod/message.php:280 +#: mod/message.php:279 msgid "Message not available." msgstr "Nachricht nicht verfügbar." -#: mod/message.php:324 +#: mod/message.php:323 msgid "Delete message" msgstr "Nachricht löschen" -#: mod/message.php:326 mod/message.php:457 +#: mod/message.php:325 mod/message.php:456 msgid "D, d M Y - g:i A" msgstr "D, d. M Y - H:i" -#: mod/message.php:341 mod/message.php:454 +#: mod/message.php:340 mod/message.php:453 msgid "Delete conversation" msgstr "Unterhaltung löschen" -#: mod/message.php:343 +#: mod/message.php:342 msgid "" "No secure communications available. You may be able to " "respond from the sender's profile page." msgstr "Sichere Kommunikation ist nicht verfügbar. Eventuell kannst du auf der Profilseite des Absenders antworten." -#: mod/message.php:346 +#: mod/message.php:345 msgid "Send Reply" msgstr "Antwort senden" -#: mod/message.php:428 +#: mod/message.php:427 #, php-format msgid "Unknown sender - %s" msgstr "Unbekannter Absender - %s" -#: mod/message.php:430 +#: mod/message.php:429 #, php-format msgid "You and %s" msgstr "Du und %s" -#: mod/message.php:432 +#: mod/message.php:431 #, php-format msgid "%s and You" msgstr "%s und du" -#: mod/message.php:460 +#: mod/message.php:459 #, php-format msgid "%d message" msgid_plural "%d messages" @@ -417,13 +419,13 @@ msgstr "Persönliche Notizen" msgid "Personal notes are visible only by yourself." msgstr "Persönliche Notizen sind nur für dich sichtbar." -#: mod/notes.php:57 src/Content/Text/HTML.php:857 +#: mod/notes.php:57 src/Content/Text/HTML.php:856 #: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:74 #: src/Module/Post/Edit.php:129 msgid "Save" msgstr "Speichern" -#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:577 +#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:575 #: src/Model/Event.php:514 src/Model/Profile.php:234 #: src/Module/Calendar/Export.php:74 src/Module/Calendar/Show.php:74 #: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51 @@ -436,22 +438,22 @@ msgid "User not found." msgstr "Benutzer nicht gefunden." #: mod/photos.php:106 src/Module/BaseProfile.php:68 -#: src/Module/Profile/Photos.php:399 +#: src/Module/Profile/Photos.php:379 msgid "Photo Albums" msgstr "Fotoalben" -#: mod/photos.php:107 src/Module/Profile/Photos.php:400 -#: src/Module/Profile/Photos.php:420 +#: mod/photos.php:107 src/Module/Profile/Photos.php:380 +#: src/Module/Profile/Photos.php:400 msgid "Recent Photos" msgstr "Neueste Fotos" -#: mod/photos.php:109 mod/photos.php:867 src/Module/Profile/Photos.php:402 -#: src/Module/Profile/Photos.php:422 +#: mod/photos.php:109 mod/photos.php:865 src/Module/Profile/Photos.php:382 +#: src/Module/Profile/Photos.php:402 msgid "Upload New Photos" msgstr "Neue Fotos hochladen" #: mod/photos.php:121 src/Module/BaseSettings.php:74 -#: src/Module/Profile/Photos.php:383 +#: src/Module/Profile/Photos.php:363 msgid "everybody" msgstr "jeder" @@ -475,60 +477,60 @@ msgstr "Album ist leer." msgid "Failed to delete the photo." msgstr "Das Foto konnte nicht gelöscht werden." -#: mod/photos.php:544 +#: mod/photos.php:542 msgid "a photo" msgstr "einem Foto" -#: mod/photos.php:544 +#: mod/photos.php:542 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "%1$s wurde von %3$s in %2$s getaggt" -#: mod/photos.php:581 src/Module/Conversation/Community.php:188 -#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:315 +#: mod/photos.php:579 src/Module/Conversation/Community.php:188 +#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:295 #: src/Module/Search/Index.php:65 msgid "Public access denied." msgstr "Öffentlicher Zugriff verweigert." -#: mod/photos.php:586 +#: mod/photos.php:584 msgid "No photos selected" msgstr "Keine Bilder ausgewählt" -#: mod/photos.php:718 +#: mod/photos.php:716 #, php-format msgid "The maximum accepted image size is %s" msgstr "Die maximale erlaubte Größe von Bildern beträgt %s" -#: mod/photos.php:725 +#: mod/photos.php:723 msgid "Upload Photos" msgstr "Bilder hochladen" -#: mod/photos.php:729 mod/photos.php:815 +#: mod/photos.php:727 mod/photos.php:813 msgid "New album name: " msgstr "Name des neuen Albums: " -#: mod/photos.php:730 +#: mod/photos.php:728 msgid "or select existing album:" msgstr "oder wähle ein bestehendes Album:" -#: mod/photos.php:731 +#: mod/photos.php:729 msgid "Do not show a status post for this upload" msgstr "Keine Status-Mitteilung für diesen Beitrag anzeigen" -#: mod/photos.php:733 mod/photos.php:1093 src/Content/Conversation.php:391 -#: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:182 +#: mod/photos.php:731 mod/photos.php:1091 src/Content/Conversation.php:392 +#: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:183 msgid "Permissions" msgstr "Berechtigungen" -#: mod/photos.php:796 +#: mod/photos.php:794 msgid "Do you really want to delete this photo album and all its photos?" msgstr "Möchtest du wirklich dieses Foto-Album und all seine Foto löschen?" -#: mod/photos.php:797 mod/photos.php:820 +#: mod/photos.php:795 mod/photos.php:818 msgid "Delete Album" msgstr "Album löschen" -#: mod/photos.php:798 mod/photos.php:899 src/Content/Conversation.php:407 +#: mod/photos.php:796 mod/photos.php:897 src/Content/Conversation.php:408 #: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 #: src/Module/Contact/Unfollow.php:126 #: src/Module/Media/Attachment/Browser.php:77 @@ -538,132 +540,132 @@ msgstr "Album löschen" msgid "Cancel" msgstr "Abbrechen" -#: mod/photos.php:824 +#: mod/photos.php:822 msgid "Edit Album" msgstr "Album bearbeiten" -#: mod/photos.php:825 +#: mod/photos.php:823 msgid "Drop Album" msgstr "Album löschen" -#: mod/photos.php:829 +#: mod/photos.php:827 msgid "Show Newest First" msgstr "Zeige neueste zuerst" -#: mod/photos.php:831 +#: mod/photos.php:829 msgid "Show Oldest First" msgstr "Zeige älteste zuerst" -#: mod/photos.php:852 src/Module/Profile/Photos.php:370 +#: mod/photos.php:850 src/Module/Profile/Photos.php:350 msgid "View Photo" msgstr "Foto betrachten" -#: mod/photos.php:885 +#: mod/photos.php:883 msgid "Permission denied. Access to this item may be restricted." msgstr "Zugriff verweigert. Zugriff zu diesem Eintrag könnte eingeschränkt sein." -#: mod/photos.php:887 +#: mod/photos.php:885 msgid "Photo not available" msgstr "Foto nicht verfügbar" -#: mod/photos.php:897 +#: mod/photos.php:895 msgid "Do you really want to delete this photo?" msgstr "Möchtest du wirklich dieses Foto löschen?" -#: mod/photos.php:898 mod/photos.php:1098 +#: mod/photos.php:896 mod/photos.php:1096 msgid "Delete Photo" msgstr "Foto löschen" -#: mod/photos.php:996 +#: mod/photos.php:994 msgid "View photo" msgstr "Fotos ansehen" -#: mod/photos.php:998 +#: mod/photos.php:996 msgid "Edit photo" msgstr "Foto bearbeiten" -#: mod/photos.php:999 +#: mod/photos.php:997 msgid "Delete photo" msgstr "Foto löschen" -#: mod/photos.php:1000 +#: mod/photos.php:998 msgid "Use as profile photo" msgstr "Als Profilbild verwenden" -#: mod/photos.php:1007 +#: mod/photos.php:1005 msgid "Private Photo" msgstr "Privates Foto" -#: mod/photos.php:1013 +#: mod/photos.php:1011 msgid "View Full Size" msgstr "Betrachte Originalgröße" -#: mod/photos.php:1066 +#: mod/photos.php:1064 msgid "Tags: " msgstr "Tags: " -#: mod/photos.php:1069 +#: mod/photos.php:1067 msgid "[Select tags to remove]" msgstr "[Zu entfernende Tags auswählen]" -#: mod/photos.php:1084 +#: mod/photos.php:1082 msgid "New album name" msgstr "Name des neuen Albums" -#: mod/photos.php:1085 +#: mod/photos.php:1083 msgid "Caption" msgstr "Bildunterschrift" -#: mod/photos.php:1086 +#: mod/photos.php:1084 msgid "Add a Tag" msgstr "Tag hinzufügen" -#: mod/photos.php:1086 +#: mod/photos.php:1084 msgid "" "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "Beispiel: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" -#: mod/photos.php:1087 +#: mod/photos.php:1085 msgid "Do not rotate" msgstr "Nicht rotieren" -#: mod/photos.php:1088 +#: mod/photos.php:1086 msgid "Rotate CW (right)" msgstr "Drehen US (rechts)" -#: mod/photos.php:1089 +#: mod/photos.php:1087 msgid "Rotate CCW (left)" msgstr "Drehen EUS (links)" -#: mod/photos.php:1135 mod/photos.php:1191 mod/photos.php:1265 -#: src/Module/Contact.php:588 src/Module/Item/Compose.php:188 -#: src/Object/Post.php:1060 +#: mod/photos.php:1133 mod/photos.php:1189 mod/photos.php:1263 +#: src/Module/Contact.php:597 src/Module/Item/Compose.php:188 +#: src/Object/Post.php:1067 msgid "This is you" msgstr "Das bist du" -#: mod/photos.php:1137 mod/photos.php:1193 mod/photos.php:1267 -#: src/Object/Post.php:544 src/Object/Post.php:1062 +#: mod/photos.php:1135 mod/photos.php:1191 mod/photos.php:1265 +#: src/Object/Post.php:551 src/Object/Post.php:1069 msgid "Comment" msgstr "Kommentar" -#: mod/photos.php:1139 mod/photos.php:1195 mod/photos.php:1269 -#: src/Content/Conversation.php:404 src/Module/Calendar/Event/Form.php:248 -#: src/Module/Item/Compose.php:199 src/Module/Post/Edit.php:165 -#: src/Object/Post.php:1074 +#: mod/photos.php:1137 mod/photos.php:1193 mod/photos.php:1267 +#: src/Content/Conversation.php:405 src/Module/Calendar/Event/Form.php:248 +#: src/Module/Item/Compose.php:200 src/Module/Post/Edit.php:165 +#: src/Object/Post.php:1082 msgid "Preview" msgstr "Vorschau" -#: mod/photos.php:1140 src/Content/Conversation.php:359 -#: src/Module/Post/Edit.php:130 src/Object/Post.php:1064 +#: mod/photos.php:1138 src/Content/Conversation.php:359 +#: src/Module/Post/Edit.php:130 src/Object/Post.php:1071 msgid "Loading..." msgstr "lädt..." -#: mod/photos.php:1226 src/Content/Conversation.php:649 -#: src/Object/Post.php:257 +#: mod/photos.php:1224 src/Content/Conversation.php:650 +#: src/Object/Post.php:258 msgid "Select" msgstr "Auswählen" -#: mod/photos.php:1227 src/Content/Conversation.php:650 +#: mod/photos.php:1225 src/Content/Conversation.php:651 #: src/Module/Moderation/Users/Active.php:136 #: src/Module/Moderation/Users/Blocked.php:136 #: src/Module/Moderation/Users/Index.php:151 @@ -671,31 +673,31 @@ msgstr "Auswählen" msgid "Delete" msgstr "Löschen" -#: mod/photos.php:1288 src/Object/Post.php:385 +#: mod/photos.php:1286 src/Object/Post.php:391 msgid "Like" msgstr "Mag ich" -#: mod/photos.php:1289 src/Object/Post.php:385 +#: mod/photos.php:1287 src/Object/Post.php:391 msgid "I like this (toggle)" msgstr "Ich mag das (toggle)" -#: mod/photos.php:1290 src/Object/Post.php:386 +#: mod/photos.php:1288 src/Object/Post.php:392 msgid "Dislike" msgstr "Mag ich nicht" -#: mod/photos.php:1292 src/Object/Post.php:386 +#: mod/photos.php:1290 src/Object/Post.php:392 msgid "I don't like this (toggle)" msgstr "Ich mag das nicht (toggle)" -#: mod/photos.php:1314 +#: mod/photos.php:1312 msgid "Map" msgstr "Karte" -#: src/App.php:470 +#: src/App.php:473 msgid "No system theme config value set." msgstr "Es wurde kein Konfigurationswert für das systemweite Theme gesetzt." -#: src/App.php:574 +#: src/App.php:577 msgid "Apologies but the website is unavailable at the moment." msgstr "Entschuldigung, aber die Webseite ist derzeit nicht erreichbar." @@ -715,77 +717,81 @@ msgid "" "notifications." msgstr "Diesen Autor ignorieren? Du wirst seine Beiträge und Benachrichtigungen nicht mehr sehen können." -#: src/App/Page.php:251 +#: src/App/Page.php:250 +msgid "Collapse this author's posts?" +msgstr "Beiträge dieses Autors zusammenklappen?" + +#: src/App/Page.php:252 msgid "Like not successful" msgstr "Das \"Mag ich\" war nicht erfolgreich" -#: src/App/Page.php:252 +#: src/App/Page.php:253 msgid "Dislike not successful" msgstr "Das \"Mag ich nicht\" war nicht erfolgreich" -#: src/App/Page.php:253 +#: src/App/Page.php:254 msgid "Sharing not successful" msgstr "Das Teilen war nicht erfolgreich" -#: src/App/Page.php:254 +#: src/App/Page.php:255 msgid "Attendance unsuccessful" msgstr "Die Teilnahme war nicht erfolgreich" -#: src/App/Page.php:255 +#: src/App/Page.php:256 msgid "Backend error" msgstr "Fehler im Backend" -#: src/App/Page.php:256 +#: src/App/Page.php:257 msgid "Network error" msgstr "Netzwerkfehler" -#: src/App/Page.php:259 +#: src/App/Page.php:260 msgid "Drop files here to upload" msgstr "Ziehe Dateien hierher, um sie hochzuladen" -#: src/App/Page.php:260 +#: src/App/Page.php:261 msgid "Your browser does not support drag and drop file uploads." msgstr "Ihr Browser unterstützt das Hochladen von Dateien per Drag & Drop nicht." -#: src/App/Page.php:261 +#: src/App/Page.php:262 msgid "" "Please use the fallback form below to upload your files like in the olden " "days." msgstr "Bitte verwenden Sie das untenstehende Formular, um Ihre Dateien wie früher hochzuladen." -#: src/App/Page.php:262 +#: src/App/Page.php:263 msgid "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB." msgstr "Datei ist zu groß ({{filesize}}MiB). Maximale Dateigröße: {{maxFilesize}}MiB." -#: src/App/Page.php:263 +#: src/App/Page.php:264 msgid "You can't upload files of this type." msgstr "Sie können keine Dateien dieses Typs hochladen." -#: src/App/Page.php:264 +#: src/App/Page.php:265 msgid "Server responded with {{statusCode}} code." msgstr "Der Server antwortete mit Status-Code {{statusCode}} " -#: src/App/Page.php:265 +#: src/App/Page.php:266 msgid "Cancel upload" msgstr "Hochladen abbrechen" -#: src/App/Page.php:266 +#: src/App/Page.php:267 msgid "Upload canceled." msgstr "Hochladen abgebrochen" -#: src/App/Page.php:267 +#: src/App/Page.php:268 msgid "Are you sure you want to cancel this upload?" msgstr "Sind Sie sicher, dass Sie diesen Upload abbrechen möchten?" -#: src/App/Page.php:268 +#: src/App/Page.php:269 msgid "Remove file" msgstr "Datei entfernen" -#: src/App/Page.php:269 +#: src/App/Page.php:270 msgid "You can't upload any more files." msgstr "Sie können keine weiteren Dateien hochladen." -#: src/App/Page.php:347 +#: src/App/Page.php:348 msgid "toggle mobile" msgstr "mobile Ansicht umschalten" @@ -812,19 +818,19 @@ msgstr "Das Sicherheitsmerkmal war nicht korrekt. Das passiert meistens, wenn da msgid "All contacts" msgstr "Alle Kontakte" -#: src/BaseModule.php:432 src/Content/Widget.php:239 src/Core/ACL.php:195 -#: src/Module/Contact.php:407 src/Module/PermissionTooltip.php:127 +#: src/BaseModule.php:432 src/Content/Widget.php:243 src/Core/ACL.php:195 +#: src/Module/Contact.php:415 src/Module/PermissionTooltip.php:127 #: src/Module/PermissionTooltip.php:149 msgid "Followers" msgstr "Folgende" -#: src/BaseModule.php:437 src/Content/Widget.php:240 -#: src/Module/Contact.php:408 +#: src/BaseModule.php:437 src/Content/Widget.php:244 +#: src/Module/Contact.php:416 msgid "Following" msgstr "Gefolgte" -#: src/BaseModule.php:442 src/Content/Widget.php:241 -#: src/Module/Contact.php:409 +#: src/BaseModule.php:442 src/Content/Widget.php:245 +#: src/Module/Contact.php:417 msgid "Mutual friends" msgstr "Beidseitige Freundschaft" @@ -1153,7 +1159,11 @@ msgstr "pnut" msgid "Tumblr" msgstr "Tumblr" -#: src/Content/ContactSelector.php:179 +#: src/Content/ContactSelector.php:144 +msgid "Bluesky" +msgstr "Bluesky" + +#: src/Content/ContactSelector.php:180 #, php-format msgid "%s (via %s)" msgstr "%s (via %s)" @@ -1255,8 +1265,8 @@ msgstr[1] " teilten dies ern msgid "Visible to everybody" msgstr "Für jedermann sichtbar" -#: src/Content/Conversation.php:329 src/Module/Item/Compose.php:198 -#: src/Object/Post.php:1073 +#: src/Content/Conversation.php:329 src/Module/Item/Compose.php:199 +#: src/Object/Post.php:1081 msgid "Please enter a image/video/audio/webpage URL:" msgstr "Bitte gib eine Bild/Video/Audio/Webseiten-URL ein:" @@ -1301,216 +1311,221 @@ msgid "attach file" msgstr "Datei anhängen" #: src/Content/Conversation.php:364 src/Module/Item/Compose.php:190 -#: src/Module/Post/Edit.php:171 src/Object/Post.php:1065 +#: src/Module/Post/Edit.php:171 src/Object/Post.php:1072 msgid "Bold" msgstr "Fett" #: src/Content/Conversation.php:365 src/Module/Item/Compose.php:191 -#: src/Module/Post/Edit.php:172 src/Object/Post.php:1066 +#: src/Module/Post/Edit.php:172 src/Object/Post.php:1073 msgid "Italic" msgstr "Kursiv" #: src/Content/Conversation.php:366 src/Module/Item/Compose.php:192 -#: src/Module/Post/Edit.php:173 src/Object/Post.php:1067 +#: src/Module/Post/Edit.php:173 src/Object/Post.php:1074 msgid "Underline" msgstr "Unterstrichen" #: src/Content/Conversation.php:367 src/Module/Item/Compose.php:193 -#: src/Module/Post/Edit.php:174 src/Object/Post.php:1068 +#: src/Module/Post/Edit.php:174 src/Object/Post.php:1075 msgid "Quote" msgstr "Zitat" #: src/Content/Conversation.php:368 src/Module/Item/Compose.php:194 -#: src/Module/Post/Edit.php:175 src/Object/Post.php:1069 +#: src/Module/Post/Edit.php:175 src/Object/Post.php:1076 +msgid "Add emojis" +msgstr "Emojis hinzufügen" + +#: src/Content/Conversation.php:369 src/Module/Item/Compose.php:195 +#: src/Module/Post/Edit.php:176 src/Object/Post.php:1077 msgid "Code" msgstr "Code" -#: src/Content/Conversation.php:369 src/Module/Item/Compose.php:195 -#: src/Object/Post.php:1070 +#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:196 +#: src/Object/Post.php:1078 msgid "Image" msgstr "Bild" -#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:196 -#: src/Module/Post/Edit.php:176 src/Object/Post.php:1071 +#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:197 +#: src/Module/Post/Edit.php:177 src/Object/Post.php:1079 msgid "Link" msgstr "Link" -#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:197 -#: src/Module/Post/Edit.php:177 src/Object/Post.php:1072 +#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:198 +#: src/Module/Post/Edit.php:178 src/Object/Post.php:1080 msgid "Link or Media" msgstr "Link oder Mediendatei" -#: src/Content/Conversation.php:372 +#: src/Content/Conversation.php:373 msgid "Video" msgstr "Video" -#: src/Content/Conversation.php:373 src/Module/Item/Compose.php:200 +#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:201 #: src/Module/Post/Edit.php:141 msgid "Set your location" msgstr "Deinen Standort festlegen" -#: src/Content/Conversation.php:374 src/Module/Post/Edit.php:142 +#: src/Content/Conversation.php:375 src/Module/Post/Edit.php:142 msgid "set location" msgstr "Ort setzen" -#: src/Content/Conversation.php:375 src/Module/Post/Edit.php:143 +#: src/Content/Conversation.php:376 src/Module/Post/Edit.php:143 msgid "Clear browser location" msgstr "Browser-Standort leeren" -#: src/Content/Conversation.php:376 src/Module/Post/Edit.php:144 +#: src/Content/Conversation.php:377 src/Module/Post/Edit.php:144 msgid "clear location" msgstr "Ort löschen" -#: src/Content/Conversation.php:378 src/Module/Item/Compose.php:205 +#: src/Content/Conversation.php:379 src/Module/Item/Compose.php:206 #: src/Module/Post/Edit.php:157 msgid "Set title" msgstr "Titel setzen" -#: src/Content/Conversation.php:380 src/Module/Item/Compose.php:206 +#: src/Content/Conversation.php:381 src/Module/Item/Compose.php:207 #: src/Module/Post/Edit.php:159 msgid "Categories (comma-separated list)" msgstr "Kategorien (kommasepariert)" -#: src/Content/Conversation.php:385 src/Module/Item/Compose.php:222 +#: src/Content/Conversation.php:386 src/Module/Item/Compose.php:223 msgid "Scheduled at" msgstr "Geplant für" -#: src/Content/Conversation.php:390 src/Module/Post/Edit.php:146 +#: src/Content/Conversation.php:391 src/Module/Post/Edit.php:146 msgid "Permission settings" msgstr "Berechtigungseinstellungen" -#: src/Content/Conversation.php:400 src/Module/Post/Edit.php:155 +#: src/Content/Conversation.php:401 src/Module/Post/Edit.php:155 msgid "Public post" msgstr "Öffentlicher Beitrag" -#: src/Content/Conversation.php:414 src/Content/Widget/VCard.php:113 +#: src/Content/Conversation.php:415 src/Content/Widget/VCard.php:113 #: src/Model/Profile.php:469 src/Module/Admin/Logs/View.php:92 -#: src/Module/Post/Edit.php:180 +#: src/Module/Post/Edit.php:181 msgid "Message" msgstr "Nachricht" -#: src/Content/Conversation.php:415 src/Module/Post/Edit.php:181 +#: src/Content/Conversation.php:416 src/Module/Post/Edit.php:182 #: src/Module/Settings/TwoFactor/Trusted.php:140 msgid "Browser" msgstr "Browser" -#: src/Content/Conversation.php:417 src/Module/Post/Edit.php:184 +#: src/Content/Conversation.php:418 src/Module/Post/Edit.php:185 msgid "Open Compose page" msgstr "Composer Seite öffnen" -#: src/Content/Conversation.php:677 src/Object/Post.php:244 +#: src/Content/Conversation.php:678 src/Object/Post.php:244 msgid "Pinned item" msgstr "Angehefteter Beitrag" -#: src/Content/Conversation.php:693 src/Object/Post.php:496 -#: src/Object/Post.php:497 +#: src/Content/Conversation.php:694 src/Object/Post.php:502 +#: src/Object/Post.php:503 #, php-format msgid "View %s's profile @ %s" msgstr "Das Profil von %s auf %s betrachten." -#: src/Content/Conversation.php:706 src/Object/Post.php:484 +#: src/Content/Conversation.php:707 src/Object/Post.php:490 msgid "Categories:" msgstr "Kategorien:" -#: src/Content/Conversation.php:707 src/Object/Post.php:485 +#: src/Content/Conversation.php:708 src/Object/Post.php:491 msgid "Filed under:" msgstr "Abgelegt unter:" -#: src/Content/Conversation.php:715 src/Object/Post.php:510 +#: src/Content/Conversation.php:716 src/Object/Post.php:516 #, php-format msgid "%s from %s" msgstr "%s von %s" -#: src/Content/Conversation.php:731 +#: src/Content/Conversation.php:732 msgid "View in context" msgstr "Im Zusammenhang betrachten" -#: src/Content/Conversation.php:796 +#: src/Content/Conversation.php:797 msgid "remove" msgstr "löschen" -#: src/Content/Conversation.php:800 +#: src/Content/Conversation.php:801 msgid "Delete Selected Items" msgstr "Lösche die markierten Beiträge" -#: src/Content/Conversation.php:865 src/Content/Conversation.php:868 -#: src/Content/Conversation.php:871 src/Content/Conversation.php:874 -#: src/Content/Conversation.php:877 +#: src/Content/Conversation.php:866 src/Content/Conversation.php:869 +#: src/Content/Conversation.php:872 src/Content/Conversation.php:875 +#: src/Content/Conversation.php:878 #, php-format msgid "You had been addressed (%s)." msgstr "Du wurdest angeschrieben (%s)." -#: src/Content/Conversation.php:880 +#: src/Content/Conversation.php:881 #, php-format msgid "You are following %s." msgstr "Du folgst %s." -#: src/Content/Conversation.php:883 +#: src/Content/Conversation.php:884 msgid "You subscribed to one or more tags in this post." msgstr "Du folgst einem oder mehreren Hashtags dieses Beitrags." -#: src/Content/Conversation.php:896 +#: src/Content/Conversation.php:897 #, php-format msgid "%s reshared this." msgstr "%s hat dies geteilt" -#: src/Content/Conversation.php:898 +#: src/Content/Conversation.php:899 msgid "Reshared" msgstr "Geteilt" -#: src/Content/Conversation.php:898 +#: src/Content/Conversation.php:899 #, php-format msgid "Reshared by %s <%s>" msgstr "Geteilt von %s <%s>" -#: src/Content/Conversation.php:901 +#: src/Content/Conversation.php:902 #, php-format msgid "%s is participating in this thread." msgstr "%s ist an der Unterhaltung beteiligt." -#: src/Content/Conversation.php:904 +#: src/Content/Conversation.php:905 msgid "Stored for general reasons" msgstr "Aus allgemeinen Gründen aufbewahrt" -#: src/Content/Conversation.php:907 +#: src/Content/Conversation.php:908 msgid "Global post" msgstr "Globaler Beitrag" -#: src/Content/Conversation.php:910 +#: src/Content/Conversation.php:911 msgid "Sent via an relay server" msgstr "Über einen Relay-Server gesendet" -#: src/Content/Conversation.php:910 +#: src/Content/Conversation.php:911 #, php-format msgid "Sent via the relay server %s <%s>" msgstr "Über den Relay-Server %s <%s> gesendet" -#: src/Content/Conversation.php:913 +#: src/Content/Conversation.php:914 msgid "Fetched" msgstr "Abgerufen" -#: src/Content/Conversation.php:913 +#: src/Content/Conversation.php:914 #, php-format msgid "Fetched because of %s <%s>" msgstr "Wegen %s <%s> abgerufen" -#: src/Content/Conversation.php:916 +#: src/Content/Conversation.php:917 msgid "Stored because of a child post to complete this thread." msgstr "Gespeichert wegen eines untergeordneten Beitrags zur Vervollständigung dieses Themas." -#: src/Content/Conversation.php:919 +#: src/Content/Conversation.php:920 msgid "Local delivery" msgstr "Lokale Zustellung" -#: src/Content/Conversation.php:922 +#: src/Content/Conversation.php:923 msgid "Stored because of your activity (like, comment, star, ...)" msgstr "Gespeichert aufgrund Ihrer Aktivität (Like, Kommentar, Stern, ...)" -#: src/Content/Conversation.php:925 +#: src/Content/Conversation.php:926 msgid "Distributed" msgstr "Verteilt" -#: src/Content/Conversation.php:928 +#: src/Content/Conversation.php:929 msgid "Pushed to us" msgstr "Zu uns gepusht" @@ -1543,13 +1558,13 @@ msgid "Post Composition Features" msgstr "Beitragserstellung-Features" #: src/Content/Feature.php:105 -msgid "Auto-mention Forums" -msgstr "Foren automatisch erwähnen" +msgid "Auto-mention Groups" +msgstr "Gruppen automatisch erwähnen" #: src/Content/Feature.php:105 msgid "" -"Add/remove mention when a forum page is selected/deselected in ACL window." -msgstr "Automatisch eine @-Erwähnung eines Forums einfügen/entfehrnen, wenn dieses im ACL Fenster de-/markiert wurde." +"Add/remove mention when a group page is selected/deselected in ACL window." +msgstr "Automatisch eine @-Erwähnung einer Gruppe einfügen/entfernen, wenn dieses im ACL Fenster de-/markiert wurde." #: src/Content/Feature.php:106 msgid "Explicit Mentions" @@ -1589,12 +1604,12 @@ msgid "Advanced Profile Settings" msgstr "Erweiterte Profil-Einstellungen" #: src/Content/Feature.php:119 -msgid "List Forums" -msgstr "Zeige Foren" +msgid "List Groups" +msgstr "Zeige Gruppen" #: src/Content/Feature.php:119 -msgid "Show visitors public community forums at the Advanced Profile Page" -msgstr "Zeige Besuchern öffentliche Gemeinschafts-Foren auf der Erweiterten Profil-Seite" +msgid "Show visitors public groups at the Advanced Profile Page" +msgstr "Zeige Besuchern öffentliche Gruppen auf der Erweiterten Profil-Seite" #: src/Content/Feature.php:120 msgid "Tag Cloud" @@ -1626,76 +1641,76 @@ msgid "" "Contact birthday events are private to you." msgstr "Anonyme Besucher können deinen Kalender öffnen und dort deine öffentliche Ereignisse einsehen. Geburtstage deiner Kontakte sind nicht öffentlich." -#: src/Content/ForumManager.php:151 src/Content/Nav.php:276 -#: src/Content/Text/HTML.php:878 src/Content/Widget.php:528 -msgid "Forums" -msgstr "Foren" +#: src/Content/GroupManager.php:151 src/Content/Nav.php:276 +#: src/Content/Text/HTML.php:877 src/Content/Widget.php:533 +msgid "Groups" +msgstr "Gruppen" -#: src/Content/ForumManager.php:153 -msgid "External link to forum" -msgstr "Externer Link zum Forum" +#: src/Content/GroupManager.php:153 +msgid "External link to group" +msgstr "Externer Link zur Gruppe" -#: src/Content/ForumManager.php:156 src/Content/Widget.php:507 +#: src/Content/GroupManager.php:156 src/Content/Widget.php:512 msgid "show less" msgstr "weniger anzeigen" -#: src/Content/ForumManager.php:157 src/Content/Widget.php:409 -#: src/Content/Widget.php:508 +#: src/Content/GroupManager.php:157 src/Content/Widget.php:414 +#: src/Content/Widget.php:513 msgid "show more" msgstr "mehr anzeigen" -#: src/Content/Item.php:326 src/Model/Item.php:2922 +#: src/Content/Item.php:327 src/Model/Item.php:2931 msgid "event" msgstr "Veranstaltung" -#: src/Content/Item.php:329 src/Content/Item.php:339 +#: src/Content/Item.php:330 src/Content/Item.php:340 msgid "status" msgstr "Status" -#: src/Content/Item.php:335 src/Model/Item.php:2924 +#: src/Content/Item.php:336 src/Model/Item.php:2933 #: src/Module/Post/Tag/Add.php:123 msgid "photo" msgstr "Foto" -#: src/Content/Item.php:349 src/Module/Post/Tag/Add.php:141 +#: src/Content/Item.php:350 src/Module/Post/Tag/Add.php:141 #, php-format msgid "%1$s tagged %2$s's %3$s with %4$s" msgstr "%1$s hat %2$ss %3$s mit %4$s getaggt" -#: src/Content/Item.php:419 view/theme/frio/theme.php:262 +#: src/Content/Item.php:418 view/theme/frio/theme.php:262 msgid "Follow Thread" msgstr "Folge der Unterhaltung" -#: src/Content/Item.php:420 src/Model/Contact.php:1204 +#: src/Content/Item.php:419 src/Model/Contact.php:1199 msgid "View Status" msgstr "Status anschauen" -#: src/Content/Item.php:421 src/Content/Item.php:441 -#: src/Model/Contact.php:1148 src/Model/Contact.php:1196 -#: src/Model/Contact.php:1205 src/Module/Directory.php:157 +#: src/Content/Item.php:420 src/Content/Item.php:440 +#: src/Model/Contact.php:1148 src/Model/Contact.php:1191 +#: src/Model/Contact.php:1200 src/Module/Directory.php:157 #: src/Module/Settings/Profile/Index.php:233 msgid "View Profile" msgstr "Profil anschauen" -#: src/Content/Item.php:422 src/Model/Contact.php:1206 +#: src/Content/Item.php:421 src/Model/Contact.php:1201 msgid "View Photos" msgstr "Bilder anschauen" -#: src/Content/Item.php:423 src/Model/Contact.php:1197 -#: src/Model/Contact.php:1207 +#: src/Content/Item.php:422 src/Model/Contact.php:1192 +#: src/Model/Contact.php:1202 msgid "Network Posts" msgstr "Netzwerkbeiträge" -#: src/Content/Item.php:424 src/Model/Contact.php:1198 -#: src/Model/Contact.php:1208 +#: src/Content/Item.php:423 src/Model/Contact.php:1193 +#: src/Model/Contact.php:1203 msgid "View Contact" msgstr "Kontakt anzeigen" -#: src/Content/Item.php:425 src/Model/Contact.php:1209 +#: src/Content/Item.php:424 src/Model/Contact.php:1204 msgid "Send PM" msgstr "Private Nachricht senden" -#: src/Content/Item.php:426 src/Module/Contact.php:439 +#: src/Content/Item.php:425 src/Module/Contact.php:448 #: src/Module/Contact/Profile.php:477 #: src/Module/Moderation/Blocklist/Contact.php:116 #: src/Module/Moderation/Users/Active.php:137 @@ -1703,7 +1718,7 @@ msgstr "Private Nachricht senden" msgid "Block" msgstr "Sperren" -#: src/Content/Item.php:427 src/Module/Contact.php:440 +#: src/Content/Item.php:426 src/Module/Contact.php:449 #: src/Module/Contact/Profile.php:485 #: src/Module/Notifications/Introductions.php:134 #: src/Module/Notifications/Introductions.php:206 @@ -1711,22 +1726,22 @@ msgstr "Sperren" msgid "Ignore" msgstr "Ignorieren" -#: src/Content/Item.php:428 src/Module/Contact.php:441 +#: src/Content/Item.php:427 src/Module/Contact.php:450 #: src/Module/Contact/Profile.php:493 msgid "Collapse" msgstr "Zuklappen" -#: src/Content/Item.php:432 src/Object/Post.php:465 +#: src/Content/Item.php:431 src/Object/Post.php:471 msgid "Languages" msgstr "Sprachen" -#: src/Content/Item.php:438 src/Content/Widget.php:80 -#: src/Model/Contact.php:1199 src/Model/Contact.php:1210 -#: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:196 +#: src/Content/Item.php:437 src/Content/Widget.php:80 +#: src/Model/Contact.php:1194 src/Model/Contact.php:1205 +#: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:195 msgid "Connect/Follow" msgstr "Verbinden/Folgen" -#: src/Content/Item.php:863 +#: src/Content/Item.php:862 msgid "Unable to fetch user." msgstr "Benutzer kann nicht abgerufen werden." @@ -1742,9 +1757,9 @@ msgstr "Geh zurück" msgid "Clear notifications" msgstr "Bereinige Benachrichtigungen" -#: src/Content/Nav.php:126 src/Content/Text/HTML.php:865 -msgid "@name, !forum, #tags, content" -msgstr "@name, !forum, #tags, content" +#: src/Content/Nav.php:126 src/Content/Text/HTML.php:864 +msgid "@name, !group, #tags, content" +msgstr "@name, !gruppe, #tags, content" #: src/Content/Nav.php:220 src/Module/Security/Login.php:157 msgid "Logout" @@ -1764,7 +1779,7 @@ msgid "Sign in" msgstr "Anmelden" #: src/Content/Nav.php:227 src/Module/BaseProfile.php:57 -#: src/Module/Contact.php:483 +#: src/Module/Contact.php:492 msgid "Conversations" msgstr "Unterhaltungen" @@ -1773,7 +1788,7 @@ msgid "Conversations you started" msgstr "Unterhaltungen die du begonnen hast" #: src/Content/Nav.php:228 src/Module/BaseProfile.php:49 -#: src/Module/BaseSettings.php:100 src/Module/Contact.php:475 +#: src/Module/BaseSettings.php:100 src/Module/Contact.php:484 #: src/Module/Contact/Profile.php:392 src/Module/Profile/Profile.php:268 #: src/Module/Welcome.php:57 view/theme/frio/theme.php:230 msgid "Profile" @@ -1793,7 +1808,7 @@ msgid "Your photos" msgstr "Deine Fotos" #: src/Content/Nav.php:230 src/Module/BaseProfile.php:73 -#: src/Module/BaseProfile.php:76 src/Module/Contact.php:499 +#: src/Module/BaseProfile.php:76 src/Module/Contact.php:508 #: view/theme/frio/theme.php:235 msgid "Media" msgstr "Medien" @@ -1843,7 +1858,7 @@ msgstr "Nutzerkonto erstellen" #: src/Module/Settings/TwoFactor/AppSpecific.php:129 #: src/Module/Settings/TwoFactor/Index.php:118 #: src/Module/Settings/TwoFactor/Recovery.php:107 -#: src/Module/Settings/TwoFactor/Verify.php:146 view/theme/vier/theme.php:241 +#: src/Module/Settings/TwoFactor/Verify.php:146 view/theme/vier/theme.php:240 msgid "Help" msgstr "Hilfe" @@ -1859,7 +1874,7 @@ msgstr "Apps" msgid "Addon applications, utilities, games" msgstr "Zusätzliche Anwendungen, Dienstprogramme, Spiele" -#: src/Content/Nav.php:267 src/Content/Text/HTML.php:863 +#: src/Content/Nav.php:267 src/Content/Text/HTML.php:862 #: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:112 msgid "Search" msgstr "Suche" @@ -1868,19 +1883,19 @@ msgstr "Suche" msgid "Search site content" msgstr "Inhalt der Seite durchsuchen" -#: src/Content/Nav.php:270 src/Content/Text/HTML.php:872 +#: src/Content/Nav.php:270 src/Content/Text/HTML.php:871 msgid "Full Text" msgstr "Volltext" -#: src/Content/Nav.php:271 src/Content/Text/HTML.php:873 +#: src/Content/Nav.php:271 src/Content/Text/HTML.php:872 #: src/Content/Widget/TagCloud.php:68 msgid "Tags" msgstr "Tags" #: src/Content/Nav.php:272 src/Content/Nav.php:327 -#: src/Content/Text/HTML.php:874 src/Module/BaseProfile.php:127 -#: src/Module/BaseProfile.php:130 src/Module/Contact.php:410 -#: src/Module/Contact.php:506 view/theme/frio/theme.php:243 +#: src/Content/Text/HTML.php:873 src/Module/BaseProfile.php:127 +#: src/Module/BaseProfile.php:130 src/Module/Contact.php:419 +#: src/Module/Contact.php:515 view/theme/frio/theme.php:243 msgid "Contacts" msgstr "Kontakte" @@ -2048,50 +2063,50 @@ msgstr "nächste" msgid "last" msgstr "letzte" -#: src/Content/Text/BBCode.php:713 src/Content/Text/BBCode.php:1599 -#: src/Content/Text/BBCode.php:1600 +#: src/Content/Text/BBCode.php:694 src/Content/Text/BBCode.php:1600 +#: src/Content/Text/BBCode.php:1601 msgid "Image/photo" msgstr "Bild/Foto" -#: src/Content/Text/BBCode.php:931 +#: src/Content/Text/BBCode.php:912 #, php-format msgid "%2$s %3$s" msgstr "%2$s%3$s" -#: src/Content/Text/BBCode.php:956 src/Model/Item.php:3607 -#: src/Model/Item.php:3613 src/Model/Item.php:3614 +#: src/Content/Text/BBCode.php:937 src/Model/Item.php:3649 +#: src/Model/Item.php:3655 src/Model/Item.php:3656 msgid "Link to source" msgstr "Link zum Originalbeitrag" -#: src/Content/Text/BBCode.php:1506 src/Content/Text/HTML.php:902 +#: src/Content/Text/BBCode.php:1507 src/Content/Text/HTML.php:901 msgid "Click to open/close" msgstr "Zum Öffnen/Schließen klicken" -#: src/Content/Text/BBCode.php:1539 +#: src/Content/Text/BBCode.php:1540 msgid "$1 wrote:" msgstr "$1 hat geschrieben:" -#: src/Content/Text/BBCode.php:1604 src/Content/Text/BBCode.php:1605 +#: src/Content/Text/BBCode.php:1605 src/Content/Text/BBCode.php:1606 msgid "Encrypted content" msgstr "Verschlüsselter Inhalt" -#: src/Content/Text/BBCode.php:1869 +#: src/Content/Text/BBCode.php:1870 msgid "Invalid source protocol" msgstr "Ungültiges Quell-Protokoll" -#: src/Content/Text/BBCode.php:1888 +#: src/Content/Text/BBCode.php:1889 msgid "Invalid link protocol" msgstr "Ungültiges Link-Protokoll" -#: src/Content/Text/HTML.php:780 +#: src/Content/Text/HTML.php:779 msgid "Loading more entries..." msgstr "lade weitere Einträge..." -#: src/Content/Text/HTML.php:781 +#: src/Content/Text/HTML.php:780 msgid "The end" msgstr "Das Ende" -#: src/Content/Text/HTML.php:857 src/Content/Widget/VCard.php:109 +#: src/Content/Text/HTML.php:856 src/Content/Widget/VCard.php:109 #: src/Model/Profile.php:463 src/Module/Contact/Profile.php:437 msgid "Follow" msgstr "Folge" @@ -2119,115 +2134,119 @@ msgid_plural "%d invitations available" msgstr[0] "%d Einladung verfügbar" msgstr[1] "%d Einladungen verfügbar" -#: src/Content/Widget.php:78 view/theme/vier/theme.php:194 +#: src/Content/Widget.php:78 view/theme/vier/theme.php:193 msgid "Find People" msgstr "Leute finden" -#: src/Content/Widget.php:79 view/theme/vier/theme.php:195 +#: src/Content/Widget.php:79 view/theme/vier/theme.php:194 msgid "Enter name or interest" msgstr "Name oder Interessen eingeben" -#: src/Content/Widget.php:81 view/theme/vier/theme.php:197 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:196 msgid "Examples: Robert Morgenstein, Fishing" msgstr "Beispiel: Robert Morgenstein, Angeln" -#: src/Content/Widget.php:82 src/Module/Contact.php:432 -#: src/Module/Directory.php:96 view/theme/vier/theme.php:198 +#: src/Content/Widget.php:82 src/Module/Contact.php:441 +#: src/Module/Directory.php:96 view/theme/vier/theme.php:197 msgid "Find" msgstr "Finde" #: src/Content/Widget.php:83 src/Module/Contact/Suggestions.php:73 -#: view/theme/vier/theme.php:199 +#: view/theme/vier/theme.php:198 msgid "Friend Suggestions" msgstr "Kontaktvorschläge" -#: src/Content/Widget.php:84 view/theme/vier/theme.php:200 +#: src/Content/Widget.php:84 view/theme/vier/theme.php:199 msgid "Similar Interests" msgstr "Ähnliche Interessen" -#: src/Content/Widget.php:85 view/theme/vier/theme.php:201 +#: src/Content/Widget.php:85 view/theme/vier/theme.php:200 msgid "Random Profile" msgstr "Zufälliges Profil" -#: src/Content/Widget.php:86 view/theme/vier/theme.php:202 +#: src/Content/Widget.php:86 view/theme/vier/theme.php:201 msgid "Invite Friends" msgstr "Freunde einladen" #: src/Content/Widget.php:87 src/Module/Directory.php:88 -#: view/theme/vier/theme.php:203 +#: view/theme/vier/theme.php:202 msgid "Global Directory" msgstr "Weltweites Verzeichnis" -#: src/Content/Widget.php:89 view/theme/vier/theme.php:205 +#: src/Content/Widget.php:89 view/theme/vier/theme.php:204 msgid "Local Directory" msgstr "Lokales Verzeichnis" -#: src/Content/Widget.php:215 src/Model/Group.php:587 -#: src/Module/Contact.php:394 src/Module/Welcome.php:76 -msgid "Groups" -msgstr "Gruppen" +#: src/Content/Widget.php:219 src/Model/Circle.php:596 +#: src/Module/Contact.php:402 src/Module/Welcome.php:76 +msgid "Circles" +msgstr "Circles" -#: src/Content/Widget.php:217 +#: src/Content/Widget.php:221 msgid "Everyone" msgstr "Jeder" -#: src/Content/Widget.php:246 +#: src/Content/Widget.php:246 src/Module/Contact.php:418 +msgid "No relationship" +msgstr "Keine Beziehung" + +#: src/Content/Widget.php:251 msgid "Relationships" msgstr "Beziehungen" -#: src/Content/Widget.php:248 src/Module/Contact.php:338 -#: src/Module/Group.php:291 +#: src/Content/Widget.php:253 src/Module/Circle.php:293 +#: src/Module/Contact.php:346 msgid "All Contacts" msgstr "Alle Kontakte" -#: src/Content/Widget.php:287 +#: src/Content/Widget.php:292 msgid "Protocols" msgstr "Protokolle" -#: src/Content/Widget.php:289 +#: src/Content/Widget.php:294 msgid "All Protocols" msgstr "Alle Protokolle" -#: src/Content/Widget.php:317 +#: src/Content/Widget.php:322 msgid "Saved Folders" msgstr "Gespeicherte Ordner" -#: src/Content/Widget.php:319 src/Content/Widget.php:350 +#: src/Content/Widget.php:324 src/Content/Widget.php:355 msgid "Everything" msgstr "Alles" -#: src/Content/Widget.php:348 +#: src/Content/Widget.php:353 msgid "Categories" msgstr "Kategorien" -#: src/Content/Widget.php:405 +#: src/Content/Widget.php:410 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "%d gemeinsamer Kontakt" msgstr[1] "%d gemeinsame Kontakte" -#: src/Content/Widget.php:501 +#: src/Content/Widget.php:506 msgid "Archives" msgstr "Archiv" -#: src/Content/Widget.php:525 +#: src/Content/Widget.php:530 msgid "Persons" msgstr "Personen" -#: src/Content/Widget.php:526 +#: src/Content/Widget.php:531 msgid "Organisations" msgstr "Organisationen" -#: src/Content/Widget.php:527 src/Model/Contact.php:1656 +#: src/Content/Widget.php:532 src/Model/Contact.php:1651 msgid "News" msgstr "Nachrichten" -#: src/Content/Widget.php:531 src/Module/Settings/Account.php:453 +#: src/Content/Widget.php:536 src/Module/Settings/Account.php:453 msgid "Account Types" msgstr "Kontenarten" -#: src/Content/Widget.php:532 src/Module/Moderation/BaseUsers.php:69 +#: src/Content/Widget.php:537 src/Module/Moderation/BaseUsers.php:69 msgid "All" msgstr "Alle" @@ -2300,8 +2319,8 @@ msgstr "Ort:" msgid "Network:" msgstr "Netzwerk:" -#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1200 -#: src/Model/Contact.php:1211 src/Model/Profile.php:465 +#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1195 +#: src/Model/Contact.php:1206 src/Model/Profile.php:465 #: src/Module/Contact/Profile.php:429 msgid "Unfollow" msgstr "Entfolgen" @@ -2343,9 +2362,9 @@ msgstr "Dieser Inhalt wird außschließlich den Kontakten gezeigt, die du in der #: src/Core/ACL.php:324 msgid "" -"Start typing the name of a contact or a group to show a filtered list. You " -"can also mention the special groups \"Followers\" and \"Mutuals\"." -msgstr "Fange an den Namen eines Kontakts oder einer Gruppe zu schreiben, diese werden dir dann in einer Liste angezeigt. Außerdem kannst du spezielle Gruppen wie \"Folgende\" oder \"Beidseitige Freundschaft\" verwenden." +"Start typing the name of a contact or a circle to show a filtered list. You " +"can also mention the special circles \"Followers\" and \"Mutuals\"." +msgstr "Geben Sie den Namen eines Kontakts oder eines Circles ein, um eine gefilterte Liste anzuzeigen. Sie können auch die speziellen Kreise \"folgende\" und \"beidseitige Freundschaft\" erwähnen." #: src/Core/ACL.php:325 msgid "Show to:" @@ -2885,22 +2904,22 @@ msgid "" " to version 2021.01 and wait until the postupdate finished version 1383." msgstr "Aktualisierungen von der Postupdate Version %s werden nicht unterstützt. Bitte aktualisiere zunächst auf die Friendica Version 2021.01 und warte bis das Postupdate 1383 abgeschlossen ist." -#: src/Core/Update.php:197 +#: src/Core/Update.php:183 #, php-format msgid "%s: executing pre update %d" msgstr "%s: Pre-Update %d wird ausgeführt" -#: src/Core/Update.php:239 +#: src/Core/Update.php:225 #, php-format msgid "%s: executing post update %d" msgstr "%s: Post-Update %d wird ausgeführt" -#: src/Core/Update.php:313 +#: src/Core/Update.php:299 #, php-format msgid "Update %s failed. See error logs." msgstr "Update %s fehlgeschlagen. Bitte Fehlerprotokoll überprüfen." -#: src/Core/Update.php:353 +#: src/Core/Update.php:339 #, php-format msgid "" "\n" @@ -2910,16 +2929,16 @@ msgid "" "\t\t\t\tfriendica developer if you can not help me on your own. My database might be invalid." msgstr "\nDie Friendica-Entwickler haben vor kurzem das Update %s veröffentlicht, aber bei der Installation ging etwas schrecklich schief.\n\nDas Problem sollte so schnell wie möglich gelöst werden, aber ich schaffe es nicht alleine. Bitte kontaktiere einen Friendica-Entwickler, falls du mir nicht alleine helfen kannst. Meine Datenbank könnte ungültig sein." -#: src/Core/Update.php:359 +#: src/Core/Update.php:345 #, php-format msgid "The error message is\\n[pre]%s[/pre]" msgstr "Die Fehlermeldung lautet [pre]%s[/pre]" -#: src/Core/Update.php:363 src/Core/Update.php:391 +#: src/Core/Update.php:349 src/Core/Update.php:377 msgid "[Friendica Notify] Database update" msgstr "[Friendica-Benachrichtigung]: Datenbank Update" -#: src/Core/Update.php:385 +#: src/Core/Update.php:371 #, php-format msgid "" "\n" @@ -2931,28 +2950,28 @@ msgstr "\n\t\t\t\tDie Friendica Datenbank wurde erfolgreich von %s auf %s aktual msgid "The database version had been set to %s." msgstr "Die Datenbank Version wurde auf %s gesetzt." -#: src/Database/DBStructure.php:70 +#: src/Database/DBStructure.php:82 #, php-format msgid "" "The post update is at version %d, it has to be at %d to safely drop the " "tables." msgstr "Das post-update ist auf der Version %d. Damit die Tabellen sicher entfernt werden können muss es die Version %d haben." -#: src/Database/DBStructure.php:83 +#: src/Database/DBStructure.php:95 msgid "No unused tables found." msgstr "Keine Tabellen gefunden die nicht verwendet werden." -#: src/Database/DBStructure.php:88 +#: src/Database/DBStructure.php:100 msgid "" "These tables are not used for friendica and will be deleted when you execute" " \"dbstructure drop -e\":" msgstr "Diese Tabellen werden nicht von Friendica verwendet. Sie werden gelöscht, wenn du \"dbstructure drop -e\" ausführst." -#: src/Database/DBStructure.php:126 +#: src/Database/DBStructure.php:137 msgid "There are no tables on MyISAM or InnoDB with the Antelope file format." msgstr "Es gibt keine MyISAM oder InnoDB Tabellem mit dem Antelope Dateiformat." -#: src/Database/DBStructure.php:150 +#: src/Database/DBStructure.php:161 #, php-format msgid "" "\n" @@ -2960,20 +2979,20 @@ msgid "" "%s\n" msgstr "\nFehler %d beim Update der Datenbank aufgetreten\n%s\n" -#: src/Database/DBStructure.php:153 +#: src/Database/DBStructure.php:164 msgid "Errors encountered performing database changes: " msgstr "Fehler beim Ändern der Datenbank aufgetreten" -#: src/Database/DBStructure.php:221 +#: src/Database/DBStructure.php:232 msgid "Another database update is currently running." msgstr "Es läuft bereits ein anderes Datenbank Update" -#: src/Database/DBStructure.php:225 +#: src/Database/DBStructure.php:236 #, php-format msgid "%s: Database update" msgstr "%s: Datenbank Aktualisierung" -#: src/Database/DBStructure.php:482 +#: src/Database/DBStructure.php:493 #, php-format msgid "%s: updating %s table." msgstr "%s: aktualisiere Tabelle %s" @@ -3004,82 +3023,126 @@ msgstr "Interner Serverfehler" msgid "Legacy module file not found: %s" msgstr "Legacy-Moduldatei nicht gefunden: %s" -#: src/Model/Contact.php:1217 src/Module/Moderation/Users/Pending.php:102 +#: src/Model/Circle.php:105 +msgid "" +"A deleted circle with this name was revived. Existing item permissions " +"may apply to this circle and any future members. If this is" +" not what you intended, please create another circle with a different name." +msgstr "Ein gelöschter Circle mit diesem Namen wurde wiederhergestellt. Bestehende Objektberechtigungen können für diesen Circle und alle zukünftigen Mitglieder gelten. Wenn dies nicht das ist, was Sie beabsichtigen, erstellen Sie bitte einen neuen Circle mit einem anderen Namen." + +#: src/Model/Circle.php:512 +msgid "Default privacy circle for new contacts" +msgstr "Voreingestellter Circle für neue Kontakte" + +#: src/Model/Circle.php:544 +msgid "Everybody" +msgstr "Alle Kontakte" + +#: src/Model/Circle.php:563 +msgid "edit" +msgstr "bearbeiten" + +#: src/Model/Circle.php:595 +msgid "add" +msgstr "hinzufügen" + +#: src/Model/Circle.php:600 +msgid "Edit circle" +msgstr "Circle ändern" + +#: src/Model/Circle.php:601 src/Module/Circle.php:194 +msgid "Contacts not in any circle" +msgstr "Kontakte die keinem Circle zugeordnet sind" + +#: src/Model/Circle.php:603 +msgid "Create a new circle" +msgstr "Erstelle neuen Cricle" + +#: src/Model/Circle.php:604 src/Module/Circle.php:179 +#: src/Module/Circle.php:202 src/Module/Circle.php:277 +msgid "Circle Name: " +msgstr "Circle Name: " + +#: src/Model/Circle.php:605 +msgid "Edit circles" +msgstr "Circles bearbeiten" + +#: src/Model/Contact.php:1212 src/Module/Moderation/Users/Pending.php:102 #: src/Module/Notifications/Introductions.php:132 #: src/Module/Notifications/Introductions.php:204 msgid "Approve" msgstr "Genehmigen" -#: src/Model/Contact.php:1652 +#: src/Model/Contact.php:1647 msgid "Organisation" msgstr "Organisation" -#: src/Model/Contact.php:1660 -msgid "Forum" -msgstr "Forum" +#: src/Model/Contact.php:1655 +msgid "Group" +msgstr "Gruppe" -#: src/Model/Contact.php:2947 +#: src/Model/Contact.php:2951 msgid "Disallowed profile URL." msgstr "Nicht erlaubte Profil-URL." -#: src/Model/Contact.php:2952 src/Module/Friendica.php:83 +#: src/Model/Contact.php:2956 src/Module/Friendica.php:83 msgid "Blocked domain" msgstr "Blockierte Domain" -#: src/Model/Contact.php:2957 +#: src/Model/Contact.php:2961 msgid "Connect URL missing." msgstr "Connect-URL fehlt" -#: src/Model/Contact.php:2966 +#: src/Model/Contact.php:2970 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "Der Kontakt konnte nicht hinzugefügt werden. Bitte überprüfe die Einstellungen unter Einstellungen -> Soziale Netzwerke" -#: src/Model/Contact.php:2984 +#: src/Model/Contact.php:2988 #, php-format msgid "Expected network %s does not match actual network %s" msgstr "Erwartetes Netzwerk %s stimmt nicht mit dem tatsächlichen Netzwerk überein %s" -#: src/Model/Contact.php:3001 +#: src/Model/Contact.php:3005 msgid "The profile address specified does not provide adequate information." msgstr "Die angegebene Profiladresse liefert unzureichende Informationen." -#: src/Model/Contact.php:3003 +#: src/Model/Contact.php:3007 msgid "No compatible communication protocols or feeds were discovered." msgstr "Es wurden keine kompatiblen Kommunikationsprotokolle oder Feeds gefunden." -#: src/Model/Contact.php:3006 +#: src/Model/Contact.php:3010 msgid "An author or name was not found." msgstr "Es wurde kein Autor oder Name gefunden." -#: src/Model/Contact.php:3009 +#: src/Model/Contact.php:3013 msgid "No browser URL could be matched to this address." msgstr "Zu dieser Adresse konnte keine passende Browser-URL gefunden werden." -#: src/Model/Contact.php:3012 +#: src/Model/Contact.php:3016 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "Konnte die @-Adresse mit keinem der bekannten Protokolle oder Email-Kontakte abgleichen." -#: src/Model/Contact.php:3013 +#: src/Model/Contact.php:3017 msgid "Use mailto: in front of address to force email check." msgstr "Verwende mailto: vor der E-Mail-Adresse, um eine Überprüfung der E-Mail-Adresse zu erzwingen." -#: src/Model/Contact.php:3019 +#: src/Model/Contact.php:3023 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "Die Adresse dieses Profils gehört zu einem Netzwerk, mit dem die Kommunikation auf dieser Seite ausgeschaltet wurde." -#: src/Model/Contact.php:3024 +#: src/Model/Contact.php:3028 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "Eingeschränktes Profil. Diese Person wird keine direkten/privaten Nachrichten von dir erhalten können." -#: src/Model/Contact.php:3089 +#: src/Model/Contact.php:3093 msgid "Unable to retrieve contact information." msgstr "Konnte die Kontaktinformationen nicht empfangen." @@ -3184,125 +3247,81 @@ msgstr "%ss Geburtstag" msgid "Happy Birthday %s" msgstr "Herzlichen Glückwunsch, %s" -#: src/Model/Group.php:105 -msgid "" -"A deleted group with this name was revived. Existing item permissions " -"may apply to this group and any future members. If this is " -"not what you intended, please create another group with a different name." -msgstr "Eine gelöschte Gruppe mit diesem Namen wurde wiederbelebt. Bestehende Berechtigungseinstellungen könnten auf diese Gruppe oder zukünftige Mitglieder angewandt werden. Falls du dies nicht möchtest, erstelle bitte eine andere Gruppe mit einem anderen Namen." - -#: src/Model/Group.php:503 -msgid "Default privacy group for new contacts" -msgstr "Voreingestellte Gruppe für neue Kontakte" - -#: src/Model/Group.php:535 -msgid "Everybody" -msgstr "Alle Kontakte" - -#: src/Model/Group.php:554 -msgid "edit" -msgstr "bearbeiten" - -#: src/Model/Group.php:586 -msgid "add" -msgstr "hinzufügen" - -#: src/Model/Group.php:591 -msgid "Edit group" -msgstr "Gruppe bearbeiten" - -#: src/Model/Group.php:592 src/Module/Group.php:192 -msgid "Contacts not in any group" -msgstr "Kontakte in keiner Gruppe" - -#: src/Model/Group.php:594 -msgid "Create a new group" -msgstr "Neue Gruppe erstellen" - -#: src/Model/Group.php:595 src/Module/Group.php:177 src/Module/Group.php:200 -#: src/Module/Group.php:275 -msgid "Group Name: " -msgstr "Gruppenname:" - -#: src/Model/Group.php:596 -msgid "Edit groups" -msgstr "Gruppen bearbeiten" - #: src/Model/Item.php:2023 #, php-format msgid "Detected languages in this post:\\n%s" msgstr "Erkannte Sprachen in diesem Beitrag:\\n%s" -#: src/Model/Item.php:2926 +#: src/Model/Item.php:2935 msgid "activity" msgstr "Aktivität" -#: src/Model/Item.php:2928 +#: src/Model/Item.php:2937 msgid "comment" msgstr "Kommentar" -#: src/Model/Item.php:2931 src/Module/Post/Tag/Add.php:123 +#: src/Model/Item.php:2940 src/Module/Post/Tag/Add.php:123 msgid "post" msgstr "Beitrag" -#: src/Model/Item.php:3093 +#: src/Model/Item.php:3109 #, php-format msgid "%s is blocked" msgstr "%s ist blockiert" -#: src/Model/Item.php:3095 +#: src/Model/Item.php:3111 #, php-format msgid "%s is ignored" msgstr "%s ist ignoriert" -#: src/Model/Item.php:3097 +#: src/Model/Item.php:3113 #, php-format msgid "Content from %s is collapsed" msgstr "Inhalt vom %s ist zugeklappt" -#: src/Model/Item.php:3101 +#: src/Model/Item.php:3117 #, php-format msgid "Content warning: %s" msgstr "Inhaltswarnung: %s" -#: src/Model/Item.php:3519 +#: src/Model/Item.php:3561 msgid "bytes" msgstr "Byte" -#: src/Model/Item.php:3550 +#: src/Model/Item.php:3592 #, php-format msgid "%2$s (%3$d%%, %1$d vote)" msgid_plural "%2$s (%3$d%%, %1$d votes)" msgstr[0] "%2$s (%3$d%%, %1$d Stimme)" msgstr[1] "%2$s (%3$d%%, %1$d Stimmen)" -#: src/Model/Item.php:3552 +#: src/Model/Item.php:3594 #, php-format msgid "%2$s (%1$d vote)" msgid_plural "%2$s (%1$d votes)" msgstr[0] "%2$s (%1$d Stimme)" msgstr[1] "%2$s (%1$d Stimmen)" -#: src/Model/Item.php:3557 +#: src/Model/Item.php:3599 #, php-format msgid "%d voter. Poll end: %s" msgid_plural "%d voters. Poll end: %s" msgstr[0] "%d Stimme, Abstimmung endet: %s" msgstr[1] "%d Stimmen, Abstimmung endet: %s" -#: src/Model/Item.php:3559 +#: src/Model/Item.php:3601 #, php-format msgid "%d voter." msgid_plural "%d voters." msgstr[0] "%d Stimme." msgstr[1] "%d Stimmen." -#: src/Model/Item.php:3561 +#: src/Model/Item.php:3603 #, php-format msgid "Poll end: %s" msgstr "Abstimmung endet: %s" -#: src/Model/Item.php:3595 src/Model/Item.php:3596 +#: src/Model/Item.php:3637 src/Model/Item.php:3638 msgid "View on separate page" msgstr "Auf separater Seite ansehen" @@ -3310,7 +3329,7 @@ msgstr "Auf separater Seite ansehen" msgid "[no subject]" msgstr "[kein Betreff]" -#: src/Model/Photo.php:1189 src/Module/Media/Photo/Upload.php:197 +#: src/Model/Photo.php:1184 src/Module/Media/Photo/Upload.php:170 msgid "Wall Photos" msgstr "Pinnwand-Bilder" @@ -3459,7 +3478,7 @@ msgstr "Schule/Ausbildung" msgid "Contact information and Social Networks" msgstr "Kontaktinformationen und Soziale Netzwerke" -#: src/Model/User.php:214 src/Model/User.php:1120 +#: src/Model/User.php:214 src/Model/User.php:1124 msgid "SERIOUS ERROR: Generation of security keys failed." msgstr "FATALER FEHLER: Sicherheitsschlüssel konnten nicht erzeugt werden." @@ -3471,133 +3490,133 @@ msgstr "Anmeldung fehlgeschlagen" msgid "Not enough information to authenticate" msgstr "Nicht genügend Informationen für die Authentifizierung" -#: src/Model/User.php:754 +#: src/Model/User.php:758 msgid "Password can't be empty" msgstr "Das Passwort kann nicht leer sein" -#: src/Model/User.php:796 +#: src/Model/User.php:800 msgid "Empty passwords are not allowed." msgstr "Leere Passwörter sind nicht erlaubt." -#: src/Model/User.php:800 +#: src/Model/User.php:804 msgid "" "The new password has been exposed in a public data dump, please choose " "another." msgstr "Das neue Passwort wurde in einem öffentlichen Daten-Dump veröffentlicht. Bitte verwende ein anderes Passwort." -#: src/Model/User.php:804 +#: src/Model/User.php:808 msgid "The password length is limited to 72 characters." msgstr "Die Länge des Passworts ist auf 72 Zeichen begrenzt." -#: src/Model/User.php:808 +#: src/Model/User.php:812 msgid "The password can't contain white spaces nor accentuated letters" msgstr "Das Passwort kann weder Leerzeichen noch akzentuierte Zeichen beinhalten." -#: src/Model/User.php:1003 +#: src/Model/User.php:1007 msgid "Passwords do not match. Password unchanged." msgstr "Die Passwörter stimmen nicht überein. Das Passwort bleibt unverändert." -#: src/Model/User.php:1010 +#: src/Model/User.php:1014 msgid "An invitation is required." msgstr "Du benötigst eine Einladung." -#: src/Model/User.php:1014 +#: src/Model/User.php:1018 msgid "Invitation could not be verified." msgstr "Die Einladung konnte nicht überprüft werden." -#: src/Model/User.php:1022 +#: src/Model/User.php:1026 msgid "Invalid OpenID url" msgstr "Ungültige OpenID URL" -#: src/Model/User.php:1035 src/Security/Authentication.php:241 +#: src/Model/User.php:1039 src/Security/Authentication.php:241 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "Beim Versuch, dich mit der von dir angegebenen OpenID anzumelden, trat ein Problem auf. Bitte überprüfe, dass du die OpenID richtig geschrieben hast." -#: src/Model/User.php:1035 src/Security/Authentication.php:241 +#: src/Model/User.php:1039 src/Security/Authentication.php:241 msgid "The error message was:" msgstr "Die Fehlermeldung lautete:" -#: src/Model/User.php:1041 +#: src/Model/User.php:1045 msgid "Please enter the required information." msgstr "Bitte trage die erforderlichen Informationen ein." -#: src/Model/User.php:1055 +#: src/Model/User.php:1059 #, php-format msgid "" "system.username_min_length (%s) and system.username_max_length (%s) are " "excluding each other, swapping values." msgstr "system.username_min_length (%s) and system.username_max_length (%s) schließen sich gegenseitig aus, tausche Werte aus." -#: src/Model/User.php:1062 +#: src/Model/User.php:1066 #, php-format msgid "Username should be at least %s character." msgid_plural "Username should be at least %s characters." msgstr[0] "Der Benutzername sollte aus mindestens %s Zeichen bestehen." msgstr[1] "Der Benutzername sollte aus mindestens %s Zeichen bestehen." -#: src/Model/User.php:1066 +#: src/Model/User.php:1070 #, php-format msgid "Username should be at most %s character." msgid_plural "Username should be at most %s characters." msgstr[0] "Der Benutzername sollte aus maximal %s Zeichen bestehen." msgstr[1] "Der Benutzername sollte aus maximal %s Zeichen bestehen." -#: src/Model/User.php:1074 +#: src/Model/User.php:1078 msgid "That doesn't appear to be your full (First Last) name." msgstr "Das scheint nicht dein kompletter Name (Vor- und Nachname) zu sein." -#: src/Model/User.php:1079 +#: src/Model/User.php:1083 msgid "Your email domain is not among those allowed on this site." msgstr "Die Domain Deiner E-Mail-Adresse ist auf dieser Seite nicht erlaubt." -#: src/Model/User.php:1083 +#: src/Model/User.php:1087 msgid "Not a valid email address." msgstr "Keine gültige E-Mail-Adresse." -#: src/Model/User.php:1086 +#: src/Model/User.php:1090 msgid "The nickname was blocked from registration by the nodes admin." msgstr "Der Admin des Knotens hat den Spitznamen für die Registrierung gesperrt." -#: src/Model/User.php:1090 src/Model/User.php:1096 +#: src/Model/User.php:1094 src/Model/User.php:1100 msgid "Cannot use that email." msgstr "Konnte diese E-Mail-Adresse nicht verwenden." -#: src/Model/User.php:1102 +#: src/Model/User.php:1106 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "Dein Spitzname darf nur aus Buchstaben und Zahlen (\"a-z\",\"0-9\" und \"_\") bestehen." -#: src/Model/User.php:1110 src/Model/User.php:1167 +#: src/Model/User.php:1114 src/Model/User.php:1171 msgid "Nickname is already registered. Please choose another." msgstr "Dieser Spitzname ist bereits vergeben. Bitte wähle einen anderen." -#: src/Model/User.php:1154 src/Model/User.php:1158 +#: src/Model/User.php:1158 src/Model/User.php:1162 msgid "An error occurred during registration. Please try again." msgstr "Während der Anmeldung ist ein Fehler aufgetreten. Bitte versuche es noch einmal." -#: src/Model/User.php:1181 +#: src/Model/User.php:1185 msgid "An error occurred creating your default profile. Please try again." msgstr "Bei der Erstellung des Standardprofils ist ein Fehler aufgetreten. Bitte versuche es noch einmal." -#: src/Model/User.php:1188 +#: src/Model/User.php:1192 msgid "An error occurred creating your self contact. Please try again." msgstr "Bei der Erstellung deines self-Kontakts ist ein Fehler aufgetreten. Bitte versuche es erneut." -#: src/Model/User.php:1193 +#: src/Model/User.php:1197 msgid "Friends" msgstr "Kontakte" -#: src/Model/User.php:1197 +#: src/Model/User.php:1201 msgid "" -"An error occurred creating your default contact group. Please try again." -msgstr "Bei der Erstellung deiner Standardgruppe für Kontakte ist ein Fehler aufgetreten. Bitte versuche es erneut." +"An error occurred creating your default contact circle. Please try again." +msgstr "Beim Erstellen Ihres Circles ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." -#: src/Model/User.php:1236 +#: src/Model/User.php:1240 msgid "Profile Photos" msgstr "Profilbilder" -#: src/Model/User.php:1431 +#: src/Model/User.php:1435 #, php-format msgid "" "\n" @@ -3605,7 +3624,7 @@ msgid "" "\t\t\tthe administrator of %2$s has set up an account for you." msgstr "\nHallo %1$s\nein Admin von %2$s hat dir ein Nutzerkonto angelegt." -#: src/Model/User.php:1434 +#: src/Model/User.php:1438 #, php-format msgid "" "\n" @@ -3637,12 +3656,12 @@ msgid "" "\t\tThank you and welcome to %4$s." msgstr "\nNachfolgend die Anmeldedetails:\n\nAdresse der Seite: %1$s\nBenutzername: %2$s\nPasswort: %3$s\n\nDu kannst dein Passwort unter \"Einstellungen\" ändern, sobald du dich angemeldet hast.Bitte nimm dir ein paar Minuten, um die anderen Einstellungen auf dieser Seite zu kontrollieren.Eventuell magst du ja auch einige Informationen über dich in deinem Profil veröffentlichen, damit andere Leute dich einfacher finden können.Bearbeite hierfür einfach dein Standard-Profil (über die Profil-Seite).Wir empfehlen dir, deinen kompletten Namen anzugeben und ein zu dir passendes Profilbild zu wählen, damit dich alte Bekannte wiederfinden.Außerdem ist es nützlich, wenn du auf deinem Profil Schlüsselwörter angibst. Das erleichtert es, Leute zu finden, die deine Interessen teilen.Wir respektieren deine Privatsphäre - keine dieser Angaben ist nötig.Wenn du neu im Netzwerk bist und noch niemanden kennst, dann können sie allerdings dabei helfen, neue und interessante Kontakte zu knüpfen.\n\nDu kannst dein Nutzerkonto jederzeit unter %1$s/settings/removeme wieder löschen.\n\nDanke und willkommen auf %4$s." -#: src/Model/User.php:1467 src/Model/User.php:1574 +#: src/Model/User.php:1471 src/Model/User.php:1578 #, php-format msgid "Registration details for %s" msgstr "Details der Registration von %s" -#: src/Model/User.php:1487 +#: src/Model/User.php:1491 #, php-format msgid "" "\n" @@ -3657,12 +3676,12 @@ msgid "" "\t\t" msgstr "\n\t\t\tHallo %1$s,\n\t\t\t\tdanke für deine Registrierung auf %2$s. Dein Account muss noch vom Admin des Knotens freigeschaltet werden.\n\n\t\t\tDeine Zugangsdaten lauten wie folgt:\n\n\t\t\tSeitenadresse:\t%3$s\n\t\t\tAnmeldename:\t\t%4$s\n\t\t\tPasswort:\t\t%5$s\n\t\t" -#: src/Model/User.php:1506 +#: src/Model/User.php:1510 #, php-format msgid "Registration at %s" msgstr "Registrierung als %s" -#: src/Model/User.php:1530 +#: src/Model/User.php:1534 #, php-format msgid "" "\n" @@ -3671,7 +3690,7 @@ msgid "" "\t\t\t" msgstr "\n\t\t\t\tHallo %1$s,\n\t\t\t\tDanke für die Registrierung auf %2$s. Dein Account wurde angelegt.\n\t\t\t" -#: src/Model/User.php:1538 +#: src/Model/User.php:1542 #, php-format msgid "" "\n" @@ -3775,7 +3794,7 @@ msgstr "Addon %s konnte nicht installiert werden" #: src/Module/Settings/Account.php:560 src/Module/Settings/Addons.php:78 #: src/Module/Settings/Connectors.php:160 #: src/Module/Settings/Connectors.php:246 -#: src/Module/Settings/Delegation.php:169 src/Module/Settings/Display.php:247 +#: src/Module/Settings/Delegation.php:171 src/Module/Settings/Display.php:247 #: src/Module/Settings/Features.php:76 msgid "Save Settings" msgstr "Einstellungen speichern" @@ -4228,7 +4247,7 @@ msgid "Policies" msgstr "Regeln" #: src/Module/Admin/Site.php:406 src/Module/Calendar/Event/Form.php:252 -#: src/Module/Contact.php:516 src/Module/Profile/Profile.php:276 +#: src/Module/Contact.php:525 src/Module/Profile/Profile.php:276 msgid "Advanced" msgstr "Erweitert" @@ -4558,8 +4577,8 @@ msgstr "Private Beiträge als Standard für neue Nutzer" #: src/Module/Admin/Site.php:455 msgid "" "Set default post permissions for all new members to the default privacy " -"group rather than public." -msgstr "Die Standard-Zugriffsrechte für neue Nutzer werden so gesetzt, dass als Voreinstellung in die private Gruppe gepostet wird anstelle von öffentlichen Beiträgen." +"circle rather than public." +msgstr "Die Standard-Zugriffsrechte für neue Nutzer werden so gesetzt, dass als Voreinstellung in den privaten Circle gepostet wird anstelle von öffentlichen." #: src/Module/Admin/Site.php:456 msgid "Don't include post content in email notifications" @@ -4973,14 +4992,14 @@ msgid "On large systems the text search can slow down the system extremely." msgstr "Auf großen Knoten kann die Volltext-Suche das System ausbremsen." #: src/Module/Admin/Site.php:507 -msgid "Generate counts per contact group when calculating network count" -msgstr "Erstelle Zählungen je Kontaktgruppe bei der Berechnung der Netzwerkanzahl" +msgid "Generate counts per contact circle when calculating network count" +msgstr "Erstelle Zählungen je Circle bei der Berechnung der Netzwerkanzahl" #: src/Module/Admin/Site.php:507 msgid "" -"On systems with users that heavily use contact groups the query can be very " -"expensive." -msgstr "Auf Systemen mit Benutzern, die häufig Kontaktgruppen verwenden, kann die Abfrage sehr aufwändig sein." +"On systems with users that heavily use contact circles the query can be very" +" expensive." +msgstr "Auf Systemen mit Benutzern, die häufig Circles verwenden, kann die Abfrage sehr aufwändig sein." #: src/Module/Admin/Site.php:509 msgid "Maximum number of parallel workers" @@ -5538,7 +5557,7 @@ msgstr "Eintrag löschen" msgid "Item Source" msgstr "Beitrags Quelle" -#: src/Module/BaseProfile.php:52 src/Module/Contact.php:478 +#: src/Module/BaseProfile.php:52 src/Module/Contact.php:487 msgid "Profile Details" msgstr "Profildetails" @@ -5562,15 +5581,15 @@ msgstr "Beiträge die für einen späteren Zeitpunkt für die Veröffentlichung msgid "Tips for New Members" msgstr "Tipps für neue Nutzer" -#: src/Module/BaseSearch.php:69 +#: src/Module/BaseSearch.php:71 #, php-format msgid "People Search - %s" msgstr "Personensuche - %s" -#: src/Module/BaseSearch.php:79 +#: src/Module/BaseSearch.php:75 #, php-format -msgid "Forum Search - %s" -msgstr "Forensuche - %s" +msgid "Group Search - %s" +msgstr "Gruppensuche - %s" #: src/Module/BaseSearch.php:121 src/Module/Contact/MatchInterests.php:139 msgid "No matches" @@ -5606,7 +5625,7 @@ msgstr "Anzeige" msgid "Social Networks" msgstr "Soziale Netzwerke" -#: src/Module/BaseSettings.php:141 src/Module/Settings/Delegation.php:170 +#: src/Module/BaseSettings.php:141 src/Module/Settings/Delegation.php:172 msgid "Manage Accounts" msgstr "Accounts Verwalten" @@ -5742,153 +5761,24 @@ msgstr "Neue Veranstaltung erstellen" msgid "list" msgstr "Liste" -#: src/Module/Contact.php:97 -#, php-format -msgid "%d contact edited." -msgid_plural "%d contacts edited." -msgstr[0] "%d Kontakt bearbeitet." -msgstr[1] "%d Kontakte bearbeitet." +#: src/Module/Circle.php:56 +msgid "Could not create circle." +msgstr "Der Circle konnte nicht erstellt werden." -#: src/Module/Contact.php:341 -msgid "Show all contacts" -msgstr "Alle Kontakte anzeigen" +#: src/Module/Circle.php:67 src/Module/Circle.php:215 +#: src/Module/Circle.php:239 +msgid "Circle not found." +msgstr "Circle nicht gefunden." -#: src/Module/Contact.php:346 src/Module/Contact.php:414 -#: src/Module/Moderation/BaseUsers.php:85 -msgid "Pending" -msgstr "Ausstehend" +#: src/Module/Circle.php:73 +msgid "Circle name was not changed." +msgstr "Der Name des Circles wurde nicht geändert." -#: src/Module/Contact.php:349 -msgid "Only show pending contacts" -msgstr "Zeige nur noch ausstehende Kontakte." - -#: src/Module/Contact.php:354 src/Module/Contact.php:415 -#: src/Module/Moderation/BaseUsers.php:93 -msgid "Blocked" -msgstr "Geblockt" - -#: src/Module/Contact.php:357 -msgid "Only show blocked contacts" -msgstr "Nur blockierte Kontakte anzeigen" - -#: src/Module/Contact.php:362 src/Module/Contact.php:417 -#: src/Object/Post.php:345 -msgid "Ignored" -msgstr "Ignoriert" - -#: src/Module/Contact.php:365 -msgid "Only show ignored contacts" -msgstr "Nur ignorierte Kontakte anzeigen" - -#: src/Module/Contact.php:370 src/Module/Contact.php:418 -msgid "Collapsed" -msgstr "Zugeklappt" - -#: src/Module/Contact.php:373 -msgid "Only show collapsed contacts" -msgstr "Zeige nur zugeklappte Kontakte" - -#: src/Module/Contact.php:378 src/Module/Contact.php:419 -msgid "Archived" -msgstr "Archiviert" - -#: src/Module/Contact.php:381 -msgid "Only show archived contacts" -msgstr "Nur archivierte Kontakte anzeigen" - -#: src/Module/Contact.php:386 src/Module/Contact.php:416 -msgid "Hidden" -msgstr "Verborgen" - -#: src/Module/Contact.php:389 -msgid "Only show hidden contacts" -msgstr "Nur verborgene Kontakte anzeigen" - -#: src/Module/Contact.php:397 -msgid "Organize your contact groups" -msgstr "Verwalte deine Kontaktgruppen" - -#: src/Module/Contact.php:430 -msgid "Search your contacts" -msgstr "Suche in deinen Kontakten" - -#: src/Module/Contact.php:431 src/Module/Search/Index.php:207 -#, php-format -msgid "Results for: %s" -msgstr "Ergebnisse für: %s" - -#: src/Module/Contact.php:438 -msgid "Update" -msgstr "Aktualisierungen" - -#: src/Module/Contact.php:439 src/Module/Contact/Profile.php:477 -#: src/Module/Moderation/Blocklist/Contact.php:117 -#: src/Module/Moderation/Users/Blocked.php:138 -#: src/Module/Moderation/Users/Index.php:154 -msgid "Unblock" -msgstr "Entsperren" - -#: src/Module/Contact.php:440 src/Module/Contact/Profile.php:485 -msgid "Unignore" -msgstr "Ignorieren aufheben" - -#: src/Module/Contact.php:441 src/Module/Contact/Profile.php:493 -msgid "Uncollapse" -msgstr "Aufklappen" - -#: src/Module/Contact.php:443 -msgid "Batch Actions" -msgstr "Stapelverarbeitung" - -#: src/Module/Contact.php:486 -msgid "Conversations started by this contact" -msgstr "Unterhaltungen, die von diesem Kontakt begonnen wurden" - -#: src/Module/Contact.php:491 -msgid "Posts and Comments" -msgstr "Statusnachrichten und Kommentare" - -#: src/Module/Contact.php:494 -msgid "Individual Posts and Replies" -msgstr "Individuelle Beiträge und Antworten" - -#: src/Module/Contact.php:502 -msgid "Posts containing media objects" -msgstr "Beiträge die Medien Objekte beinhalten" - -#: src/Module/Contact.php:509 -msgid "View all known contacts" -msgstr "Alle bekannten Kontakte anzeigen" - -#: src/Module/Contact.php:519 -msgid "Advanced Contact Settings" -msgstr "Fortgeschrittene Kontakteinstellungen" - -#: src/Module/Contact.php:555 -msgid "Mutual Friendship" -msgstr "Beidseitige Freundschaft" - -#: src/Module/Contact.php:559 -msgid "is a fan of yours" -msgstr "ist ein Fan von dir" - -#: src/Module/Contact.php:563 -msgid "you are a fan of" -msgstr "Du bist Fan von" - -#: src/Module/Contact.php:581 -msgid "Pending outgoing contact request" -msgstr "Ausstehende ausgehende Kontaktanfrage" - -#: src/Module/Contact.php:583 -msgid "Pending incoming contact request" -msgstr "Ausstehende eingehende Kontaktanfrage" - -#: src/Module/Contact.php:596 src/Module/Contact/Profile.php:346 -#, php-format -msgid "Visit %s's profile [%s]" -msgstr "Besuche %ss Profil [%s]" +#: src/Module/Circle.php:91 +msgid "Unknown circle." +msgstr "Unbekannter Circle." +#: src/Module/Circle.php:97 src/Module/Circle.php:106 #: src/Module/Contact/Advanced.php:70 src/Module/Contact/Advanced.php:109 #: src/Module/Contact/Contacts.php:71 src/Module/Contact/Conversations.php:84 #: src/Module/Contact/Conversations.php:89 @@ -5898,10 +5788,229 @@ msgstr "Besuche %ss Profil [%s]" #: src/Module/Contact/Profile.php:147 src/Module/Contact/Profile.php:152 #: src/Module/Contact/Redir.php:94 src/Module/Contact/Redir.php:140 #: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109 -#: src/Module/Group.php:97 src/Module/Group.php:106 msgid "Contact not found." msgstr "Kontakt nicht gefunden." +#: src/Module/Circle.php:101 src/Module/Contact/Contacts.php:66 +#: src/Module/Conversation/Network.php:189 +msgid "Invalid contact." +msgstr "Ungültiger Kontakt." + +#: src/Module/Circle.php:110 src/Module/Contact/Revoke.php:73 +msgid "Contact is deleted." +msgstr "Kontakt wurde gelöscht" + +#: src/Module/Circle.php:116 +msgid "Unable to add the contact to the circle." +msgstr "Es ist nicht möglich, den Kontakt zum Circle hinzuzufügen." + +#: src/Module/Circle.php:119 +msgid "Contact successfully added to circle." +msgstr "Der Kontakt wurde erfolgreich dem Circle hinzugefügt." + +#: src/Module/Circle.php:123 +msgid "Unable to remove the contact from the circle." +msgstr "Es ist nicht möglich, den Kontakt aus dem Circle zu entfernen." + +#: src/Module/Circle.php:126 +msgid "Contact successfully removed from circle." +msgstr "Kontakt erfolgreich aus dem Circle entfernt." + +#: src/Module/Circle.php:130 +msgid "Bad request." +msgstr "Ungültige Anfrage." + +#: src/Module/Circle.php:171 +msgid "Save Circle" +msgstr "Circle speichern" + +#: src/Module/Circle.php:172 +msgid "Filter" +msgstr "Filter" + +#: src/Module/Circle.php:178 +msgid "Create a circle of contacts/friends." +msgstr "Erstelle einen Circle aus Kontakten/Freunden" + +#: src/Module/Circle.php:220 +msgid "Unable to remove circle." +msgstr "Der Circle kann nicht entfernt werden." + +#: src/Module/Circle.php:271 +msgid "Delete Circle" +msgstr "Circle löschen" + +#: src/Module/Circle.php:281 +msgid "Edit Circle Name" +msgstr "Name des Circles ändern" + +#: src/Module/Circle.php:291 +msgid "Members" +msgstr "Mitglieder" + +#: src/Module/Circle.php:294 +msgid "Circle is empty" +msgstr "Dieser Circle ist leer" + +#: src/Module/Circle.php:307 +msgid "Remove contact from circle" +msgstr "Kontakt aus Circle entfernen" + +#: src/Module/Circle.php:328 +msgid "Click on a contact to add or remove." +msgstr "Klicke einen Kontakt an, um ihn hinzuzufügen oder zu entfernen" + +#: src/Module/Circle.php:342 +msgid "Add contact to circle" +msgstr "Kontakt zu Circle hinzufügen" + +#: src/Module/Contact.php:97 +#, php-format +msgid "%d contact edited." +msgid_plural "%d contacts edited." +msgstr[0] "%d Kontakt bearbeitet." +msgstr[1] "%d Kontakte bearbeitet." + +#: src/Module/Contact.php:349 +msgid "Show all contacts" +msgstr "Alle Kontakte anzeigen" + +#: src/Module/Contact.php:354 src/Module/Contact.php:423 +#: src/Module/Moderation/BaseUsers.php:85 +msgid "Pending" +msgstr "Ausstehend" + +#: src/Module/Contact.php:357 +msgid "Only show pending contacts" +msgstr "Zeige nur noch ausstehende Kontakte." + +#: src/Module/Contact.php:362 src/Module/Contact.php:424 +#: src/Module/Moderation/BaseUsers.php:93 +msgid "Blocked" +msgstr "Geblockt" + +#: src/Module/Contact.php:365 +msgid "Only show blocked contacts" +msgstr "Nur blockierte Kontakte anzeigen" + +#: src/Module/Contact.php:370 src/Module/Contact.php:426 +#: src/Object/Post.php:351 +msgid "Ignored" +msgstr "Ignoriert" + +#: src/Module/Contact.php:373 +msgid "Only show ignored contacts" +msgstr "Nur ignorierte Kontakte anzeigen" + +#: src/Module/Contact.php:378 src/Module/Contact.php:427 +msgid "Collapsed" +msgstr "Zugeklappt" + +#: src/Module/Contact.php:381 +msgid "Only show collapsed contacts" +msgstr "Zeige nur zugeklappte Kontakte" + +#: src/Module/Contact.php:386 src/Module/Contact.php:428 +msgid "Archived" +msgstr "Archiviert" + +#: src/Module/Contact.php:389 +msgid "Only show archived contacts" +msgstr "Nur archivierte Kontakte anzeigen" + +#: src/Module/Contact.php:394 src/Module/Contact.php:425 +msgid "Hidden" +msgstr "Verborgen" + +#: src/Module/Contact.php:397 +msgid "Only show hidden contacts" +msgstr "Nur verborgene Kontakte anzeigen" + +#: src/Module/Contact.php:405 +msgid "Organize your contact circles" +msgstr "Verwalte Deine Circles" + +#: src/Module/Contact.php:439 +msgid "Search your contacts" +msgstr "Suche in deinen Kontakten" + +#: src/Module/Contact.php:440 src/Module/Search/Index.php:207 +#, php-format +msgid "Results for: %s" +msgstr "Ergebnisse für: %s" + +#: src/Module/Contact.php:447 +msgid "Update" +msgstr "Aktualisierungen" + +#: src/Module/Contact.php:448 src/Module/Contact/Profile.php:477 +#: src/Module/Moderation/Blocklist/Contact.php:117 +#: src/Module/Moderation/Users/Blocked.php:138 +#: src/Module/Moderation/Users/Index.php:154 +msgid "Unblock" +msgstr "Entsperren" + +#: src/Module/Contact.php:449 src/Module/Contact/Profile.php:485 +msgid "Unignore" +msgstr "Ignorieren aufheben" + +#: src/Module/Contact.php:450 src/Module/Contact/Profile.php:493 +msgid "Uncollapse" +msgstr "Aufklappen" + +#: src/Module/Contact.php:452 +msgid "Batch Actions" +msgstr "Stapelverarbeitung" + +#: src/Module/Contact.php:495 +msgid "Conversations started by this contact" +msgstr "Unterhaltungen, die von diesem Kontakt begonnen wurden" + +#: src/Module/Contact.php:500 +msgid "Posts and Comments" +msgstr "Statusnachrichten und Kommentare" + +#: src/Module/Contact.php:503 +msgid "Individual Posts and Replies" +msgstr "Individuelle Beiträge und Antworten" + +#: src/Module/Contact.php:511 +msgid "Posts containing media objects" +msgstr "Beiträge die Medien Objekte beinhalten" + +#: src/Module/Contact.php:518 +msgid "View all known contacts" +msgstr "Alle bekannten Kontakte anzeigen" + +#: src/Module/Contact.php:528 +msgid "Advanced Contact Settings" +msgstr "Fortgeschrittene Kontakteinstellungen" + +#: src/Module/Contact.php:564 +msgid "Mutual Friendship" +msgstr "Beidseitige Freundschaft" + +#: src/Module/Contact.php:568 +msgid "is a fan of yours" +msgstr "ist ein Fan von dir" + +#: src/Module/Contact.php:572 +msgid "you are a fan of" +msgstr "Du bist Fan von" + +#: src/Module/Contact.php:590 +msgid "Pending outgoing contact request" +msgstr "Ausstehende ausgehende Kontaktanfrage" + +#: src/Module/Contact.php:592 +msgid "Pending incoming contact request" +msgstr "Ausstehende eingehende Kontaktanfrage" + +#: src/Module/Contact.php:605 src/Module/Contact/Profile.php:346 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Besuche %ss Profil [%s]" + #: src/Module/Contact/Advanced.php:99 msgid "Contact update failed." msgstr "Konnte den Kontakt nicht aktualisieren." @@ -5938,11 +6047,6 @@ msgstr "Pull/Feed-URL" msgid "New photo from this URL" msgstr "Neues Foto von dieser URL" -#: src/Module/Contact/Contacts.php:66 src/Module/Conversation/Network.php:189 -#: src/Module/Group.php:101 -msgid "Invalid contact." -msgstr "Ungültiger Kontakt." - #: src/Module/Contact/Contacts.php:89 msgid "No known contacts." msgstr "Keine bekannten Kontakte." @@ -6071,8 +6175,8 @@ msgstr "Der Kontakt konnte nicht hinzugefügt werden." #: src/Module/Contact/MatchInterests.php:94 #: src/Module/Media/Attachment/Upload.php:77 #: src/Module/Media/Attachment/Upload.php:82 -#: src/Module/Media/Photo/Upload.php:82 src/Module/Media/Photo/Upload.php:87 -#: src/Module/Media/Photo/Upload.php:136 +#: src/Module/Media/Photo/Upload.php:81 src/Module/Media/Photo/Upload.php:86 +#: src/Module/Media/Photo/Upload.php:135 msgid "Invalid request." msgstr "Ungültige Anfrage" @@ -6337,10 +6441,6 @@ msgstr "Ungültige Anfrage." msgid "Unknown contact." msgstr "Unbekannter Kontakt." -#: src/Module/Contact/Revoke.php:73 src/Module/Group.php:110 -msgid "Contact is deleted." -msgstr "Kontakt wurde gelöscht" - #: src/Module/Contact/Revoke.php:77 msgid "Contact is being deleted." msgstr "Kontakt wurde gelöscht." @@ -6436,13 +6536,13 @@ msgid "Not available." msgstr "Nicht verfügbar." #: src/Module/Conversation/Network.php:175 -msgid "No such group" -msgstr "Es gibt keine solche Gruppe" +msgid "No such circle" +msgstr "Circle ist nicht vorhanden" #: src/Module/Conversation/Network.php:179 #, php-format -msgid "Group: %s" -msgstr "Gruppe: %s" +msgid "Circle: %s" +msgstr "Circle: %s" #: src/Module/Conversation/Network.php:257 msgid "Latest Activity" @@ -6477,7 +6577,7 @@ msgstr "Persönlich" msgid "Posts that mention or involve you" msgstr "Beiträge, in denen es um dich geht" -#: src/Module/Conversation/Network.php:289 src/Object/Post.php:357 +#: src/Module/Conversation/Network.php:289 src/Object/Post.php:363 msgid "Starred" msgstr "Markierte" @@ -6882,86 +6982,6 @@ msgstr "den Bugtracker auf github" msgid "Suggestions, praise, etc. - please email \"info\" at \"friendi - dot - ca" msgstr "Vorschläge, Lob usw.: E-Mail an \"Info\" at \"Friendi - dot ca\"" -#: src/Module/Group.php:56 -msgid "Could not create group." -msgstr "Konnte die Gruppe nicht erstellen." - -#: src/Module/Group.php:67 src/Module/Group.php:213 src/Module/Group.php:237 -msgid "Group not found." -msgstr "Gruppe nicht gefunden." - -#: src/Module/Group.php:73 -msgid "Group name was not changed." -msgstr "Der Name der Gruppe wurde nicht verändert." - -#: src/Module/Group.php:91 -msgid "Unknown group." -msgstr "Unbekannte Gruppe" - -#: src/Module/Group.php:116 -msgid "Unable to add the contact to the group." -msgstr "Konnte den Kontakt nicht zur Gruppe hinzufügen" - -#: src/Module/Group.php:119 -msgid "Contact successfully added to group." -msgstr "Kontakt zur Gruppe hinzugefügt" - -#: src/Module/Group.php:123 -msgid "Unable to remove the contact from the group." -msgstr "Konnte den Kontakt nicht aus der Gruppe entfernen" - -#: src/Module/Group.php:126 -msgid "Contact successfully removed from group." -msgstr "Kontakt aus Gruppe entfernt" - -#: src/Module/Group.php:130 -msgid "Bad request." -msgstr "Ungültige Anfrage." - -#: src/Module/Group.php:169 -msgid "Save Group" -msgstr "Gruppe speichern" - -#: src/Module/Group.php:170 -msgid "Filter" -msgstr "Filter" - -#: src/Module/Group.php:176 -msgid "Create a group of contacts/friends." -msgstr "Eine Kontaktgruppe anlegen." - -#: src/Module/Group.php:218 -msgid "Unable to remove group." -msgstr "Konnte die Gruppe nicht entfernen." - -#: src/Module/Group.php:269 -msgid "Delete Group" -msgstr "Gruppe löschen" - -#: src/Module/Group.php:279 -msgid "Edit Group Name" -msgstr "Gruppen Name bearbeiten" - -#: src/Module/Group.php:289 -msgid "Members" -msgstr "Mitglieder" - -#: src/Module/Group.php:292 -msgid "Group is empty" -msgstr "Gruppe ist leer" - -#: src/Module/Group.php:305 -msgid "Remove contact from group" -msgstr "Entferne den Kontakt aus der Gruppe" - -#: src/Module/Group.php:326 -msgid "Click on a contact to add or remove." -msgstr "Klicke einen Kontakt an, um ihn hinzuzufügen oder zu entfernen" - -#: src/Module/Group.php:340 -msgid "Add contact to group" -msgstr "Füge den Kontakt zur Gruppe hinzu" - #: src/Module/HCard.php:45 msgid "No profile" msgstr "Kein Profil" @@ -7253,21 +7273,21 @@ msgstr "Neuen Beitrag verfassen" msgid "Visibility" msgstr "Sichtbarkeit" -#: src/Module/Item/Compose.php:201 +#: src/Module/Item/Compose.php:202 msgid "Clear the location" msgstr "Ort löschen" -#: src/Module/Item/Compose.php:202 +#: src/Module/Item/Compose.php:203 msgid "Location services are unavailable on your device" msgstr "Ortungsdienste sind auf Ihrem Gerät nicht verfügbar" -#: src/Module/Item/Compose.php:203 +#: src/Module/Item/Compose.php:204 msgid "" "Location services are disabled. Please check the website's permissions on " "your device" msgstr "Ortungsdienste sind deaktiviert. Bitte überprüfe die Berechtigungen der Website auf deinem Gerät" -#: src/Module/Item/Compose.php:209 +#: src/Module/Item/Compose.php:210 msgid "" "You can make this page always open when you use the New Post button in the " "Theme Customization settings." @@ -7332,20 +7352,13 @@ msgstr "Die Datei ist größer als das erlaubte Limit von %s" msgid "File upload failed." msgstr "Hochladen der Datei fehlgeschlagen." -#: src/Module/Media/Photo/Upload.php:153 src/Module/Media/Photo/Upload.php:154 +#: src/Module/Media/Photo/Upload.php:152 src/Module/Media/Photo/Upload.php:153 #: src/Module/Profile/Photos.php:217 #: src/Module/Settings/Profile/Photo/Index.php:68 msgid "Unable to process image." msgstr "Konnte das Bild nicht bearbeiten." -#: src/Module/Media/Photo/Upload.php:187 src/Module/Profile/Photos.php:164 -#: src/Module/Profile/Photos.php:167 src/Module/Profile/Photos.php:194 -#: src/Module/Settings/Profile/Photo/Index.php:59 -#, php-format -msgid "Image exceeds size limit of %s" -msgstr "Bildgröße überschreitet das Limit von %s" - -#: src/Module/Media/Photo/Upload.php:205 src/Module/Profile/Photos.php:243 +#: src/Module/Media/Photo/Upload.php:178 src/Module/Profile/Photos.php:237 #: src/Module/Settings/Profile/Photo/Index.php:95 msgid "Image upload failed." msgstr "Hochladen des Bildes gescheitert." @@ -7387,16 +7400,16 @@ msgid "Soapbox Page" msgstr "Marktschreier-Konto" #: src/Module/Moderation/BaseUsers.php:121 src/Module/Settings/Account.php:505 -msgid "Public Forum" -msgstr "Öffentliches Forum" +msgid "Public Group" +msgstr "Öffentliche Gruppe" #: src/Module/Moderation/BaseUsers.php:122 src/Module/Settings/Account.php:512 msgid "Automatic Friend Page" msgstr "Automatische Freunde-Seite" #: src/Module/Moderation/BaseUsers.php:123 -msgid "Private Forum" -msgstr "Privates Forum" +msgid "Private Group" +msgstr "Private Gruppe" #: src/Module/Moderation/BaseUsers.php:126 src/Module/Settings/Account.php:463 msgid "Personal Page" @@ -7411,8 +7424,8 @@ msgid "News Page" msgstr "Nachrichtenseite" #: src/Module/Moderation/BaseUsers.php:129 src/Module/Settings/Account.php:484 -msgid "Community Forum" -msgstr "Gemeinschaftsforum" +msgid "Community Group" +msgstr "Gemeinschaftsgruppe" #: src/Module/Moderation/BaseUsers.php:130 msgid "Relay" @@ -7832,8 +7845,8 @@ msgid "Automatic Follower Account" msgstr "Automatisch folgendes Konto (Marktschreier)" #: src/Module/Moderation/Summary.php:55 -msgid "Public Forum Account" -msgstr "Öffentliches Forum-Konto" +msgid "Public Group Account" +msgstr "Öffentliches Gruppen-Konto" #: src/Module/Moderation/Summary.php:56 msgid "Automatic Friend Account" @@ -7844,8 +7857,8 @@ msgid "Blog Account" msgstr "Blog-Konto" #: src/Module/Moderation/Summary.php:58 -msgid "Private Forum Account" -msgstr "Privates Forum-Konto" +msgid "Private Group Account" +msgstr "Privates Gruppen-Konto" #: src/Module/Moderation/Summary.php:78 msgid "Registered users" @@ -8301,12 +8314,12 @@ msgstr "BCC: %s
" #: src/Module/PermissionTooltip.php:240 #, php-format msgid "Audience: %s
" -msgstr "" +msgstr "Addressaten: %s
" #: src/Module/PermissionTooltip.php:243 #, php-format msgid "Attributed To: %s
" -msgstr "" +msgstr "Zurückzuführen auf: %s
" #: src/Module/Photo.php:129 msgid "The Photo is not available." @@ -8363,7 +8376,7 @@ msgstr "Gegenstands-Tag entfernen" msgid "Select a tag to remove: " msgstr "Wähle ein Tag zum Entfernen aus: " -#: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:178 +#: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:180 #: src/Module/Settings/TwoFactor/Trusted.php:144 msgid "Remove" msgstr "Entfernen" @@ -8374,24 +8387,31 @@ msgstr "Keine Kontakte." #: src/Module/Profile/Conversations.php:106 #: src/Module/Profile/Conversations.php:109 src/Module/Profile/Profile.php:351 -#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1032 +#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1090 #: src/Protocol/OStatus.php:1007 #, php-format msgid "%s's timeline" msgstr "Timeline von %s" #: src/Module/Profile/Conversations.php:107 src/Module/Profile/Profile.php:352 -#: src/Protocol/Feed.php:1036 src/Protocol/OStatus.php:1012 +#: src/Protocol/Feed.php:1094 src/Protocol/OStatus.php:1012 #, php-format msgid "%s's posts" msgstr "Beiträge von %s" #: src/Module/Profile/Conversations.php:108 src/Module/Profile/Profile.php:353 -#: src/Protocol/Feed.php:1039 src/Protocol/OStatus.php:1016 +#: src/Protocol/Feed.php:1097 src/Protocol/OStatus.php:1016 #, php-format msgid "%s's comments" msgstr "Kommentare von %s" +#: src/Module/Profile/Photos.php:164 src/Module/Profile/Photos.php:167 +#: src/Module/Profile/Photos.php:194 +#: src/Module/Settings/Profile/Photo/Index.php:59 +#, php-format +msgid "Image exceeds size limit of %s" +msgstr "Bildgröße überschreitet das Limit von %s" + #: src/Module/Profile/Photos.php:170 msgid "Image upload didn't complete, please try again" msgstr "Der Upload des Bildes war nicht vollständig. Bitte versuche es erneut." @@ -8410,7 +8430,7 @@ msgstr "Der Server kann derzeit keine neuen Datei-Uploads akzeptieren. Bitte kon msgid "Image file is empty." msgstr "Bilddatei ist leer." -#: src/Module/Profile/Photos.php:376 +#: src/Module/Profile/Photos.php:356 msgid "View Album" msgstr "Album betrachten" @@ -8464,8 +8484,8 @@ msgid "Description:" msgstr "Beschreibung" #: src/Module/Profile/Profile.php:261 -msgid "Forums:" -msgstr "Foren:" +msgid "Groups:" +msgstr "Gruppen:" #: src/Module/Profile/Profile.php:273 msgid "View profile as:" @@ -8671,11 +8691,11 @@ msgstr "Importiere dein Profil auf diese Friendica-Instanz" msgid "Note: This node explicitly contains adult content" msgstr "Hinweis: Dieser Knoten enthält explizit Inhalte für Erwachsene" -#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:154 +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 msgid "Parent Password:" msgstr "Passwort des Verwalters" -#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:154 +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 msgid "" "Please enter the password of the parent account to legitimize your request." msgstr "Bitte gib das Passwort des Verwalters ein, um deine Anfrage zu bestätigen." @@ -9030,8 +9050,8 @@ msgid "Personal Page Subtypes" msgstr "Unterarten der persönlichen Seite" #: src/Module/Settings/Account.php:455 -msgid "Community Forum Subtypes" -msgstr "Unterarten des Gemeinschaftsforums" +msgid "Community Group Subtypes" +msgstr "Unterarten der Gemeinschaftsgruppen" #: src/Module/Settings/Account.php:465 msgid "Account for a personal profile." @@ -9076,8 +9096,8 @@ msgid "" msgstr "Konto für ein gefragtes Profil, das Kontaktanfragen automatisch als \"Friend\" annimmt." #: src/Module/Settings/Account.php:519 -msgid "Private Forum [Experimental]" -msgstr "Privates Forum [Versuchsstadium]" +msgid "Private Group [Experimental]" +msgstr "Private Gruppe [experimentell]" #: src/Module/Settings/Account.php:521 msgid "Requires manual approval of contact requests." @@ -9672,81 +9692,81 @@ msgstr "In einen Ordner verschieben" msgid "Move to folder:" msgstr "In diesen Ordner verschieben:" -#: src/Module/Settings/Delegation.php:52 +#: src/Module/Settings/Delegation.php:54 msgid "Delegation successfully granted." msgstr "Delegierung erfolgreich eingerichtet." -#: src/Module/Settings/Delegation.php:54 +#: src/Module/Settings/Delegation.php:56 msgid "Parent user not found, unavailable or password doesn't match." msgstr "Der angegebene Nutzer konnte nicht gefunden werden, ist nicht verfügbar oder das angegebene Passwort ist nicht richtig." -#: src/Module/Settings/Delegation.php:58 +#: src/Module/Settings/Delegation.php:60 msgid "Delegation successfully revoked." msgstr "Delegation erfolgreich aufgehoben." -#: src/Module/Settings/Delegation.php:80 -#: src/Module/Settings/Delegation.php:102 +#: src/Module/Settings/Delegation.php:82 +#: src/Module/Settings/Delegation.php:104 msgid "" "Delegated administrators can view but not change delegation permissions." msgstr "Verwalter können die Berechtigungen der Delegationen einsehen, sie aber nicht ändern." -#: src/Module/Settings/Delegation.php:94 +#: src/Module/Settings/Delegation.php:96 msgid "Delegate user not found." msgstr "Delegierter Nutzer nicht gefunden" -#: src/Module/Settings/Delegation.php:142 +#: src/Module/Settings/Delegation.php:144 msgid "No parent user" msgstr "Kein Verwalter" -#: src/Module/Settings/Delegation.php:153 -#: src/Module/Settings/Delegation.php:164 +#: src/Module/Settings/Delegation.php:155 +#: src/Module/Settings/Delegation.php:166 msgid "Parent User" msgstr "Verwalter" -#: src/Module/Settings/Delegation.php:161 +#: src/Module/Settings/Delegation.php:163 msgid "Additional Accounts" msgstr "Zusätzliche Accounts" -#: src/Module/Settings/Delegation.php:162 +#: src/Module/Settings/Delegation.php:164 msgid "" "Register additional accounts that are automatically connected to your " "existing account so you can manage them from this account." msgstr "Zusätzliche Accounts registrieren, die automatisch mit deinem bestehenden Account verknüpft werden, damit du sie anschließend verwalten kannst." -#: src/Module/Settings/Delegation.php:163 +#: src/Module/Settings/Delegation.php:165 msgid "Register an additional account" msgstr "Einen zusätzlichen Account registrieren" -#: src/Module/Settings/Delegation.php:167 +#: src/Module/Settings/Delegation.php:169 msgid "" "Parent users have total control about this account, including the account " "settings. Please double check whom you give this access." msgstr "Verwalter haben Zugriff auf alle Funktionen dieses Benutzerkontos und können dessen Einstellungen ändern." -#: src/Module/Settings/Delegation.php:171 +#: src/Module/Settings/Delegation.php:173 msgid "Delegates" msgstr "Bevollmächtigte" -#: src/Module/Settings/Delegation.php:173 +#: src/Module/Settings/Delegation.php:175 msgid "" "Delegates are able to manage all aspects of this account/page except for " "basic account settings. Please do not delegate your personal account to " "anybody that you do not trust completely." msgstr "Bevollmächtigte sind in der Lage, alle Aspekte dieses Kontos/dieser Seite zu verwalten, abgesehen von den Grundeinstellungen des Kontos. Bitte gib niemandem eine Bevollmächtigung für Deinen privaten Account, dem du nicht absolut vertraust!" -#: src/Module/Settings/Delegation.php:174 +#: src/Module/Settings/Delegation.php:176 msgid "Existing Page Delegates" msgstr "Vorhandene Bevollmächtigte für die Seite" -#: src/Module/Settings/Delegation.php:176 +#: src/Module/Settings/Delegation.php:178 msgid "Potential Delegates" msgstr "Potentielle Bevollmächtigte" -#: src/Module/Settings/Delegation.php:179 +#: src/Module/Settings/Delegation.php:181 msgid "Add" msgstr "Hinzufügen" -#: src/Module/Settings/Delegation.php:180 +#: src/Module/Settings/Delegation.php:182 msgid "No entries." msgstr "Keine Einträge." @@ -10049,8 +10069,8 @@ msgid "" "\t\t\t\t

You can use BBCodes in the field values.

\n" "\t\t\t\t

Reorder by dragging the field title.

\n" "\t\t\t\t

Empty the label field to remove a custom field.

\n" -"\t\t\t\t

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected groups.

" -msgstr "

Die benutzerdefinierten Felder erscheinen auf deiner Profil-Seite

.\n\n

BBCode kann verwendet werden

\n

Die Reihenfolge der Felder kann durch Ziehen des Feld-Titels mit der Maus angepasst werden.

\n

Wird die Bezeichnung des Felds geleert, wird das Feld beim Speichern aus dem Profil entfernt.

\n

Nicht öffentliche Felder können nur von den ausgewählten Friendica Kontakte gesehen werden.

" +"\t\t\t\t

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

" +msgstr "

Die benutzerdefinierten Felder erscheinen auf deiner Profil-Seite

.\n\n

BBCode kann verwendet werden

\n

Die Reihenfolge der Felder kann durch Ziehen des Feld-Titels mit der Maus angepasst werden.

\n

Wird die Bezeichnung des Felds geleert, wird das Feld beim Speichern aus dem Profil entfernt.

\n

Nicht öffentliche Felder können nur von den ausgewählten Friendica Circles gesehen werden.

" #: src/Module/Settings/Profile/Photo/Crop.php:107 #: src/Module/Settings/Profile/Photo/Crop.php:125 @@ -10599,22 +10619,22 @@ msgstr "Fehler! Keine Versionsdaten in der Datei! Ist das wirklich eine Friendic msgid "User '%s' already exists on this server!" msgstr "Nutzer '%s' existiert bereits auf diesem Server!" -#: src/Module/User/Import.php:263 +#: src/Module/User/Import.php:267 msgid "User creation error" msgstr "Fehler beim Anlegen des Nutzer-Accounts aufgetreten" -#: src/Module/User/Import.php:312 +#: src/Module/User/Import.php:316 #, php-format msgid "%d contact not imported" msgid_plural "%d contacts not imported" msgstr[0] "%d Kontakt nicht importiert" msgstr[1] "%d Kontakte nicht importiert" -#: src/Module/User/Import.php:361 +#: src/Module/User/Import.php:365 msgid "User profile creation error" msgstr "Fehler beim Anlegen des Nutzer-Profils" -#: src/Module/User/Import.php:412 +#: src/Module/User/Import.php:416 msgid "Done. You can now login with your username and password" msgstr "Erledigt. Du kannst dich jetzt mit deinem Nutzernamen und Passwort anmelden" @@ -10748,15 +10768,15 @@ msgid "" msgstr "Im seitlichen Bedienfeld der Kontakteseite gibt es diverse Werkzeuge, um neue Personen zu finden. Wir können Menschen mit den gleichen Interessen finden, anhand von Namen oder Interessen suchen oder aber aufgrund vorhandener Kontakte neue Leute vorschlagen.\nAuf einer brandneuen - soeben erstellten - Seite starten die Kontaktvorschläge innerhalb von 24 Stunden." #: src/Module/Welcome.php:77 -msgid "Group Your Contacts" -msgstr "Gruppiere deine Kontakte" +msgid "Add Your Contacts To Circle" +msgstr "Kontakte zum Circle hinzufügen" #: src/Module/Welcome.php:78 msgid "" "Once you have made some friends, organize them into private conversation " -"groups from the sidebar of your Contacts page and then you can interact with" -" each group privately on your Network page." -msgstr "Sobald du einige Kontakte gefunden hast, organisiere sie in Gruppen zur privaten Kommunikation im Seitenmenü der Kontakte-Seite. Du kannst dann mit jeder dieser Gruppen von der Netzwerkseite aus privat interagieren." +"circles from the sidebar of your Contacts page and then you can interact " +"with each circle privately on your Network page." +msgstr "Sobald Sie einige Freunde gefunden haben, können Sie diese in der Seitenleiste Ihrer Kontaktseite in private Circles einteilen und dann mit jedem Circle auf Ihrer Netzwerkseite privat interagieren." #: src/Module/Welcome.php:80 msgid "Why Aren't My Posts Public?" @@ -11295,217 +11315,222 @@ msgstr "Global löschen" msgid "Remove locally" msgstr "Lokal entfernen" -#: src/Object/Post.php:265 +#: src/Object/Post.php:266 #, php-format msgid "Block %s" msgstr "Blockiere %s" -#: src/Object/Post.php:270 +#: src/Object/Post.php:271 #, php-format msgid "Ignore %s" -msgstr "Ignorieren %s" +msgstr "Ignoriere %s" -#: src/Object/Post.php:275 +#: src/Object/Post.php:276 +#, php-format +msgid "Collapse %s" +msgstr "Verberge %s" + +#: src/Object/Post.php:281 msgid "Save to folder" msgstr "In Ordner speichern" -#: src/Object/Post.php:310 +#: src/Object/Post.php:316 msgid "I will attend" msgstr "Ich werde teilnehmen" -#: src/Object/Post.php:310 +#: src/Object/Post.php:316 msgid "I will not attend" msgstr "Ich werde nicht teilnehmen" -#: src/Object/Post.php:310 +#: src/Object/Post.php:316 msgid "I might attend" msgstr "Ich werde eventuell teilnehmen" -#: src/Object/Post.php:340 +#: src/Object/Post.php:346 msgid "Ignore thread" msgstr "Thread ignorieren" -#: src/Object/Post.php:341 +#: src/Object/Post.php:347 msgid "Unignore thread" msgstr "Thread nicht mehr ignorieren" -#: src/Object/Post.php:342 +#: src/Object/Post.php:348 msgid "Toggle ignore status" msgstr "Ignoriert-Status ein-/ausschalten" -#: src/Object/Post.php:352 +#: src/Object/Post.php:358 msgid "Add star" msgstr "Markieren" -#: src/Object/Post.php:353 +#: src/Object/Post.php:359 msgid "Remove star" msgstr "Markierung entfernen" -#: src/Object/Post.php:354 +#: src/Object/Post.php:360 msgid "Toggle star status" msgstr "Markierung umschalten" -#: src/Object/Post.php:365 +#: src/Object/Post.php:371 msgid "Pin" msgstr "Anheften" -#: src/Object/Post.php:366 +#: src/Object/Post.php:372 msgid "Unpin" msgstr "Losmachen" -#: src/Object/Post.php:367 +#: src/Object/Post.php:373 msgid "Toggle pin status" msgstr "Angeheftet Status ändern" -#: src/Object/Post.php:370 +#: src/Object/Post.php:376 msgid "Pinned" msgstr "Angeheftet" -#: src/Object/Post.php:375 +#: src/Object/Post.php:381 msgid "Add tag" msgstr "Tag hinzufügen" -#: src/Object/Post.php:388 +#: src/Object/Post.php:394 msgid "Quote share this" msgstr "Teile und zitiere dies" -#: src/Object/Post.php:388 +#: src/Object/Post.php:394 msgid "Quote Share" msgstr "Zitat teilen" -#: src/Object/Post.php:391 +#: src/Object/Post.php:397 msgid "Reshare this" msgstr "Teile dies" -#: src/Object/Post.php:391 +#: src/Object/Post.php:397 msgid "Reshare" msgstr "Teilen" -#: src/Object/Post.php:392 +#: src/Object/Post.php:398 msgid "Cancel your Reshare" msgstr "Teilen aufheben" -#: src/Object/Post.php:392 +#: src/Object/Post.php:398 msgid "Unshare" msgstr "Nicht mehr teilen" -#: src/Object/Post.php:443 +#: src/Object/Post.php:449 #, php-format msgid "%s (Received %s)" msgstr "%s (Empfangen %s)" -#: src/Object/Post.php:448 +#: src/Object/Post.php:454 msgid "Comment this item on your system" msgstr "Kommentiere diesen Beitrag von deinem System aus" -#: src/Object/Post.php:448 +#: src/Object/Post.php:454 msgid "Remote comment" msgstr "Entfernter Kommentar" -#: src/Object/Post.php:469 +#: src/Object/Post.php:475 msgid "Share via ..." msgstr "Teile mit..." -#: src/Object/Post.php:469 +#: src/Object/Post.php:475 msgid "Share via external services" msgstr "Teile mit einem externen Dienst" -#: src/Object/Post.php:498 +#: src/Object/Post.php:504 msgid "to" msgstr "zu" -#: src/Object/Post.php:499 +#: src/Object/Post.php:505 msgid "via" msgstr "via" -#: src/Object/Post.php:500 +#: src/Object/Post.php:506 msgid "Wall-to-Wall" msgstr "Wall-to-Wall" -#: src/Object/Post.php:501 +#: src/Object/Post.php:507 msgid "via Wall-To-Wall:" msgstr "via Wall-To-Wall:" -#: src/Object/Post.php:545 +#: src/Object/Post.php:552 #, php-format msgid "Reply to %s" msgstr "Antworte %s" -#: src/Object/Post.php:548 +#: src/Object/Post.php:555 msgid "More" msgstr "Mehr" -#: src/Object/Post.php:566 +#: src/Object/Post.php:573 msgid "Notifier task is pending" msgstr "Die Benachrichtigungsaufgabe ist ausstehend" -#: src/Object/Post.php:567 +#: src/Object/Post.php:574 msgid "Delivery to remote servers is pending" msgstr "Die Auslieferung an Remote-Server steht noch aus" -#: src/Object/Post.php:568 +#: src/Object/Post.php:575 msgid "Delivery to remote servers is underway" msgstr "Die Auslieferung an Remote-Server ist unterwegs" -#: src/Object/Post.php:569 +#: src/Object/Post.php:576 msgid "Delivery to remote servers is mostly done" msgstr "Die Zustellung an Remote-Server ist fast erledigt" -#: src/Object/Post.php:570 +#: src/Object/Post.php:577 msgid "Delivery to remote servers is done" msgstr "Die Zustellung an die Remote-Server ist erledigt" -#: src/Object/Post.php:590 +#: src/Object/Post.php:597 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "%d Kommentar" msgstr[1] "%d Kommentare" -#: src/Object/Post.php:591 +#: src/Object/Post.php:598 msgid "Show more" msgstr "Zeige mehr" -#: src/Object/Post.php:592 +#: src/Object/Post.php:599 msgid "Show fewer" msgstr "Zeige weniger" -#: src/Object/Post.php:628 +#: src/Object/Post.php:635 #, php-format msgid "Reshared by: %s" -msgstr "Weitergeteilt von: %s" +msgstr "Geteilt von: %s" -#: src/Object/Post.php:633 +#: src/Object/Post.php:640 #, php-format msgid "Viewed by: %s" msgstr "Gesehen von: %s" -#: src/Object/Post.php:638 +#: src/Object/Post.php:645 #, php-format msgid "Liked by: %s" -msgstr "Gemocht von: %s" +msgstr "Diese Menschen mögen das: %s" -#: src/Object/Post.php:643 +#: src/Object/Post.php:650 #, php-format msgid "Disliked by: %s" msgstr "Unbeliebt bei: %s" -#: src/Object/Post.php:648 +#: src/Object/Post.php:655 #, php-format msgid "Attended by: %s" msgstr "Besucht von: %s" -#: src/Object/Post.php:653 +#: src/Object/Post.php:660 #, php-format msgid "Maybe attended by: %s" msgstr "Vielleicht besucht von: %s" -#: src/Object/Post.php:658 +#: src/Object/Post.php:665 #, php-format msgid "Not attended by: %s" msgstr "Nicht besucht von: %s" -#: src/Object/Post.php:663 +#: src/Object/Post.php:670 #, php-format msgid "Reacted with %s by: %s" msgstr "Reagierte mit %s von: %s" @@ -11886,8 +11911,8 @@ msgid "Textareas font size" msgstr "Schriftgröße in Eingabefeldern" #: view/theme/vier/config.php:91 -msgid "Comma separated list of helper forums" -msgstr "Komma-separierte Liste der Helfer-Foren" +msgid "Comma separated list of helper groups" +msgstr "Komma-separierte Liste der Helfer-Gruppen" #: view/theme/vier/config.php:131 msgid "don't show" @@ -11905,7 +11930,7 @@ msgstr "Stil auswählen" msgid "Community Pages" msgstr "Gemeinschaftsseiten" -#: view/theme/vier/config.php:139 view/theme/vier/theme.php:149 +#: view/theme/vier/config.php:139 view/theme/vier/theme.php:148 msgid "Community Profiles" msgstr "Gemeinschaftsprofile" @@ -11913,7 +11938,7 @@ msgstr "Gemeinschaftsprofile" msgid "Help or @NewHere ?" msgstr "Hilfe oder @NewHere" -#: view/theme/vier/config.php:141 view/theme/vier/theme.php:320 +#: view/theme/vier/config.php:141 view/theme/vier/theme.php:319 msgid "Connect Services" msgstr "Verbinde Dienste" @@ -11921,10 +11946,10 @@ msgstr "Verbinde Dienste" msgid "Find Friends" msgstr "Kontakte finden" -#: view/theme/vier/config.php:143 view/theme/vier/theme.php:176 +#: view/theme/vier/config.php:143 view/theme/vier/theme.php:175 msgid "Last users" msgstr "Letzte Nutzer" -#: view/theme/vier/theme.php:235 +#: view/theme/vier/theme.php:234 msgid "Quick Start" msgstr "Schnell-Start" diff --git a/view/lang/de/strings.php b/view/lang/de/strings.php index 6266e8001..f20617d0b 100644 --- a/view/lang/de/strings.php +++ b/view/lang/de/strings.php @@ -198,6 +198,7 @@ $a->strings['Apologies but the website is unavailable at the moment.'] = 'Entsch $a->strings['Delete this item?'] = 'Diesen Beitrag löschen?'; $a->strings['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.'] = 'Soll dieser Autor geblockt werden? Sie werden nicht in der Lage sein, dir zu folgen oder deine öffentlichen Beiträge zu sehen. Außerdem wirst du nicht in der Lage sein ihre Beiträge und Benachrichtigungen zu lesen.'; $a->strings['Ignore this author? You won\'t be able to see their posts and their notifications.'] = 'Diesen Autor ignorieren? Du wirst seine Beiträge und Benachrichtigungen nicht mehr sehen können.'; +$a->strings['Collapse this author\'s posts?'] = 'Beiträge dieses Autors zusammenklappen?'; $a->strings['Like not successful'] = 'Das "Mag ich" war nicht erfolgreich'; $a->strings['Dislike not successful'] = 'Das "Mag ich nicht" war nicht erfolgreich'; $a->strings['Sharing not successful'] = 'Das Teilen war nicht erfolgreich'; @@ -297,6 +298,7 @@ $a->strings['GNU Social Connector'] = 'GNU Social Connector'; $a->strings['ActivityPub'] = 'ActivityPub'; $a->strings['pnut'] = 'pnut'; $a->strings['Tumblr'] = 'Tumblr'; +$a->strings['Bluesky'] = 'Bluesky'; $a->strings['%s (via %s)'] = '%s (via %s)'; $a->strings['and'] = 'und'; $a->strings['and %d other people'] = 'und %dandere'; @@ -364,6 +366,7 @@ $a->strings['Bold'] = 'Fett'; $a->strings['Italic'] = 'Kursiv'; $a->strings['Underline'] = 'Unterstrichen'; $a->strings['Quote'] = 'Zitat'; +$a->strings['Add emojis'] = 'Emojis hinzufügen'; $a->strings['Code'] = 'Code'; $a->strings['Image'] = 'Bild'; $a->strings['Link'] = 'Link'; @@ -413,8 +416,8 @@ $a->strings['Photo metadata is normally stripped. This extracts the location (if $a->strings['Trending Tags'] = 'Trending Tags'; $a->strings['Show a community page widget with a list of the most popular tags in recent public posts.'] = 'Auf der Gemeinschaftsseite ein Widget mit den meist benutzten Tags in öffentlichen Beiträgen anzeigen.'; $a->strings['Post Composition Features'] = 'Beitragserstellung-Features'; -$a->strings['Auto-mention Forums'] = 'Foren automatisch erwähnen'; -$a->strings['Add/remove mention when a forum page is selected/deselected in ACL window.'] = 'Automatisch eine @-Erwähnung eines Forums einfügen/entfehrnen, wenn dieses im ACL Fenster de-/markiert wurde.'; +$a->strings['Auto-mention Groups'] = 'Gruppen automatisch erwähnen'; +$a->strings['Add/remove mention when a group page is selected/deselected in ACL window.'] = 'Automatisch eine @-Erwähnung einer Gruppe einfügen/entfernen, wenn dieses im ACL Fenster de-/markiert wurde.'; $a->strings['Explicit Mentions'] = 'Explizite Erwähnungen'; $a->strings['Add explicit mentions to comment box for manual control over who gets mentioned in replies.'] = 'Füge Erwähnungen zum Kommentarfeld hinzu, um manuell über die explizite Erwähnung von Gesprächsteilnehmern zu entscheiden.'; $a->strings['Add an abstract from ActivityPub content warnings'] = 'Abstract aus Inhaltswarnungen von ActivityPub zu Beiträgen hinzufügen'; @@ -423,8 +426,8 @@ $a->strings['Post/Comment Tools'] = 'Werkzeuge für Beiträge und Kommentare'; $a->strings['Post Categories'] = 'Beitragskategorien'; $a->strings['Add categories to your posts'] = 'Eigene Beiträge mit Kategorien versehen'; $a->strings['Advanced Profile Settings'] = 'Erweiterte Profil-Einstellungen'; -$a->strings['List Forums'] = 'Zeige Foren'; -$a->strings['Show visitors public community forums at the Advanced Profile Page'] = 'Zeige Besuchern öffentliche Gemeinschafts-Foren auf der Erweiterten Profil-Seite'; +$a->strings['List Groups'] = 'Zeige Gruppen'; +$a->strings['Show visitors public groups at the Advanced Profile Page'] = 'Zeige Besuchern öffentliche Gruppen auf der Erweiterten Profil-Seite'; $a->strings['Tag Cloud'] = 'Schlagwortwolke'; $a->strings['Provide a personal tag cloud on your profile page'] = 'Wortwolke aus den von dir verwendeten Schlagwörtern im Profil anzeigen'; $a->strings['Display Membership Date'] = 'Mitgliedschaftsdatum anzeigen'; @@ -432,8 +435,8 @@ $a->strings['Display membership date in profile'] = 'Das Datum der Registrierung $a->strings['Advanced Calendar Settings'] = 'Erweiterte Kalender Einstellungen'; $a->strings['Allow anonymous access to your calendar'] = 'Erlaube anonymen Zugriff auf deinen Kalender'; $a->strings['Allows anonymous visitors to consult your calendar and your public events. Contact birthday events are private to you.'] = 'Anonyme Besucher können deinen Kalender öffnen und dort deine öffentliche Ereignisse einsehen. Geburtstage deiner Kontakte sind nicht öffentlich.'; -$a->strings['Forums'] = 'Foren'; -$a->strings['External link to forum'] = 'Externer Link zum Forum'; +$a->strings['Groups'] = 'Gruppen'; +$a->strings['External link to group'] = 'Externer Link zur Gruppe'; $a->strings['show less'] = 'weniger anzeigen'; $a->strings['show more'] = 'mehr anzeigen'; $a->strings['event'] = 'Veranstaltung'; @@ -456,7 +459,7 @@ $a->strings['Unable to fetch user.'] = 'Benutzer kann nicht abgerufen werden.'; $a->strings['Nothing new here'] = 'Keine Neuigkeiten'; $a->strings['Go back'] = 'Geh zurück'; $a->strings['Clear notifications'] = 'Bereinige Benachrichtigungen'; -$a->strings['@name, !forum, #tags, content'] = '@name, !forum, #tags, content'; +$a->strings['@name, !group, #tags, content'] = '@name, !gruppe, #tags, content'; $a->strings['Logout'] = 'Abmelden'; $a->strings['End this session'] = 'Diese Sitzung beenden'; $a->strings['Login'] = 'Anmeldung'; @@ -552,8 +555,9 @@ $a->strings['Random Profile'] = 'Zufälliges Profil'; $a->strings['Invite Friends'] = 'Freunde einladen'; $a->strings['Global Directory'] = 'Weltweites Verzeichnis'; $a->strings['Local Directory'] = 'Lokales Verzeichnis'; -$a->strings['Groups'] = 'Gruppen'; +$a->strings['Circles'] = 'Circles'; $a->strings['Everyone'] = 'Jeder'; +$a->strings['No relationship'] = 'Keine Beziehung'; $a->strings['Relationships'] = 'Beziehungen'; $a->strings['All Contacts'] = 'Alle Kontakte'; $a->strings['Protocols'] = 'Protokolle'; @@ -599,7 +603,7 @@ $a->strings['Public'] = 'Öffentlich'; $a->strings['This content will be shown to all your followers and can be seen in the community pages and by anyone with its link.'] = 'Dieser Inhalt wird all deine Abonenten sowie auf der Gemeinschaftsseite angezeigt. Außerdem kann ihn jeder sehen, der den Link kennt.'; $a->strings['Limited/Private'] = 'Begrenzt/Privat'; $a->strings['This content will be shown only to the people in the first box, to the exception of the people mentioned in the second box. It won\'t appear anywhere public.'] = 'Dieser Inhalt wird außschließlich den Kontakten gezeigt, die du in der ersten Box ausgewählt hast, mit den Ausnahmen derer die du in der zweiten Box auflistest. Er wird nicht öffentlich zugänglich sein.'; -$a->strings['Start typing the name of a contact or a group to show a filtered list. You can also mention the special groups "Followers" and "Mutuals".'] = 'Fange an den Namen eines Kontakts oder einer Gruppe zu schreiben, diese werden dir dann in einer Liste angezeigt. Außerdem kannst du spezielle Gruppen wie "Folgende" oder "Beidseitige Freundschaft" verwenden.'; +$a->strings['Start typing the name of a contact or a circle to show a filtered list. You can also mention the special circles "Followers" and "Mutuals".'] = 'Geben Sie den Namen eines Kontakts oder eines Circles ein, um eine gefilterte Liste anzuzeigen. Sie können auch die speziellen Kreise "folgende" und "beidseitige Freundschaft" erwähnen.'; $a->strings['Show to:'] = 'Sichtbar für:'; $a->strings['Except to:'] = 'Ausgenommen:'; $a->strings['CC: email addresses'] = 'Cc: E-Mail-Addressen'; @@ -756,9 +760,19 @@ $a->strings['Unauthorized'] = 'Nicht autorisiert'; $a->strings['Token is not authorized with a valid user or is missing a required scope'] = 'Token ist nicht durch einen gültigen Benutzer autorisiert oder es fehlt ein erforderlicher Geltungsbereich'; $a->strings['Internal Server Error'] = 'Interner Serverfehler'; $a->strings['Legacy module file not found: %s'] = 'Legacy-Moduldatei nicht gefunden: %s'; +$a->strings['A deleted circle with this name was revived. Existing item permissions may apply to this circle and any future members. If this is not what you intended, please create another circle with a different name.'] = 'Ein gelöschter Circle mit diesem Namen wurde wiederhergestellt. Bestehende Objektberechtigungen können für diesen Circle und alle zukünftigen Mitglieder gelten. Wenn dies nicht das ist, was Sie beabsichtigen, erstellen Sie bitte einen neuen Circle mit einem anderen Namen.'; +$a->strings['Default privacy circle for new contacts'] = 'Voreingestellter Circle für neue Kontakte'; +$a->strings['Everybody'] = 'Alle Kontakte'; +$a->strings['edit'] = 'bearbeiten'; +$a->strings['add'] = 'hinzufügen'; +$a->strings['Edit circle'] = 'Circle ändern'; +$a->strings['Contacts not in any circle'] = 'Kontakte die keinem Circle zugeordnet sind'; +$a->strings['Create a new circle'] = 'Erstelle neuen Cricle'; +$a->strings['Circle Name: '] = 'Circle Name: '; +$a->strings['Edit circles'] = 'Circles bearbeiten'; $a->strings['Approve'] = 'Genehmigen'; $a->strings['Organisation'] = 'Organisation'; -$a->strings['Forum'] = 'Forum'; +$a->strings['Group'] = 'Gruppe'; $a->strings['Disallowed profile URL.'] = 'Nicht erlaubte Profil-URL.'; $a->strings['Blocked domain'] = 'Blockierte Domain'; $a->strings['Connect URL missing.'] = 'Connect-URL fehlt'; @@ -796,16 +810,6 @@ $a->strings['Show map'] = 'Karte anzeigen'; $a->strings['Hide map'] = 'Karte verbergen'; $a->strings['%s\'s birthday'] = '%ss Geburtstag'; $a->strings['Happy Birthday %s'] = 'Herzlichen Glückwunsch, %s'; -$a->strings['A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name.'] = 'Eine gelöschte Gruppe mit diesem Namen wurde wiederbelebt. Bestehende Berechtigungseinstellungen könnten auf diese Gruppe oder zukünftige Mitglieder angewandt werden. Falls du dies nicht möchtest, erstelle bitte eine andere Gruppe mit einem anderen Namen.'; -$a->strings['Default privacy group for new contacts'] = 'Voreingestellte Gruppe für neue Kontakte'; -$a->strings['Everybody'] = 'Alle Kontakte'; -$a->strings['edit'] = 'bearbeiten'; -$a->strings['add'] = 'hinzufügen'; -$a->strings['Edit group'] = 'Gruppe bearbeiten'; -$a->strings['Contacts not in any group'] = 'Kontakte in keiner Gruppe'; -$a->strings['Create a new group'] = 'Neue Gruppe erstellen'; -$a->strings['Group Name: '] = 'Gruppenname:'; -$a->strings['Edit groups'] = 'Gruppen bearbeiten'; $a->strings['Detected languages in this post:\n%s'] = 'Erkannte Sprachen in diesem Beitrag:\n%s'; $a->strings['activity'] = 'Aktivität'; $a->strings['comment'] = 'Kommentar'; @@ -905,7 +909,7 @@ $a->strings['An error occurred during registration. Please try again.'] = 'Währ $a->strings['An error occurred creating your default profile. Please try again.'] = 'Bei der Erstellung des Standardprofils ist ein Fehler aufgetreten. Bitte versuche es noch einmal.'; $a->strings['An error occurred creating your self contact. Please try again.'] = 'Bei der Erstellung deines self-Kontakts ist ein Fehler aufgetreten. Bitte versuche es erneut.'; $a->strings['Friends'] = 'Kontakte'; -$a->strings['An error occurred creating your default contact group. Please try again.'] = 'Bei der Erstellung deiner Standardgruppe für Kontakte ist ein Fehler aufgetreten. Bitte versuche es erneut.'; +$a->strings['An error occurred creating your default contact circle. Please try again.'] = 'Beim Erstellen Ihres Circles ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut.'; $a->strings['Profile Photos'] = 'Profilbilder'; $a->strings[' Dear %1$s, @@ -1235,7 +1239,7 @@ $a->strings['Enabling this may violate privacy laws like the GDPR'] = 'Wenn du d $a->strings['Global directory URL'] = 'URL des weltweiten Verzeichnisses'; $a->strings['URL to the global directory. If this is not set, the global directory is completely unavailable to the application.'] = 'URL des weltweiten Verzeichnisses. Wenn diese nicht gesetzt ist, ist das Verzeichnis für die Applikation nicht erreichbar.'; $a->strings['Private posts by default for new users'] = 'Private Beiträge als Standard für neue Nutzer'; -$a->strings['Set default post permissions for all new members to the default privacy group rather than public.'] = 'Die Standard-Zugriffsrechte für neue Nutzer werden so gesetzt, dass als Voreinstellung in die private Gruppe gepostet wird anstelle von öffentlichen Beiträgen.'; +$a->strings['Set default post permissions for all new members to the default privacy circle rather than public.'] = 'Die Standard-Zugriffsrechte für neue Nutzer werden so gesetzt, dass als Voreinstellung in den privaten Circle gepostet wird anstelle von öffentlichen.'; $a->strings['Don\'t include post content in email notifications'] = 'Inhalte von Beiträgen nicht in E-Mail-Benachrichtigungen versenden'; $a->strings['Don\'t include the content of a post/comment/private message/etc. in the email notifications that are sent out from this site, as a privacy measure.'] = 'Inhalte von Beiträgen/Kommentaren/privaten Nachrichten/usw. zum Datenschutz nicht in E-Mail-Benachrichtigungen einbinden.'; $a->strings['Disallow public access to addons listed in the apps menu.'] = 'Öffentlichen Zugriff auf Addons im Apps Menü verbieten.'; @@ -1319,8 +1323,8 @@ $a->strings['Temp path'] = 'Temp-Pfad'; $a->strings['If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.'] = 'Solltest du ein eingeschränktes System haben, auf dem der Webserver nicht auf das temp-Verzeichnis des Systems zugreifen kann, setze hier einen anderen Pfad.'; $a->strings['Only search in tags'] = 'Nur in Tags suchen'; $a->strings['On large systems the text search can slow down the system extremely.'] = 'Auf großen Knoten kann die Volltext-Suche das System ausbremsen.'; -$a->strings['Generate counts per contact group when calculating network count'] = 'Erstelle Zählungen je Kontaktgruppe bei der Berechnung der Netzwerkanzahl'; -$a->strings['On systems with users that heavily use contact groups the query can be very expensive.'] = 'Auf Systemen mit Benutzern, die häufig Kontaktgruppen verwenden, kann die Abfrage sehr aufwändig sein.'; +$a->strings['Generate counts per contact circle when calculating network count'] = 'Erstelle Zählungen je Circle bei der Berechnung der Netzwerkanzahl'; +$a->strings['On systems with users that heavily use contact circles the query can be very expensive.'] = 'Auf Systemen mit Benutzern, die häufig Circles verwenden, kann die Abfrage sehr aufwändig sein.'; $a->strings['Maximum number of parallel workers'] = 'Maximale Anzahl parallel laufender Worker'; $a->strings['On shared hosters set this to %d. On larger systems, values of %d are great. Default value is %d.'] = 'Wenn dein Knoten bei einem Shared Hoster ist, setze diesen Wert auf %d. Auf größeren Systemen funktioniert ein Wert von %d recht gut. Standardeinstellung sind %d.'; $a->strings['Enable fastlane'] = 'Aktiviere Fastlane'; @@ -1449,7 +1453,7 @@ $a->strings['Scheduled Posts'] = 'Geplante Beiträge'; $a->strings['Posts that are scheduled for publishing'] = 'Beiträge die für einen späteren Zeitpunkt für die Veröffentlichung geplant sind'; $a->strings['Tips for New Members'] = 'Tipps für neue Nutzer'; $a->strings['People Search - %s'] = 'Personensuche - %s'; -$a->strings['Forum Search - %s'] = 'Forensuche - %s'; +$a->strings['Group Search - %s'] = 'Gruppensuche - %s'; $a->strings['No matches'] = 'Keine Übereinstimmungen'; $a->strings['%d result was filtered out because your node blocks the domain it is registered on. You can review the list of domains your node is currently blocking in the About page.'] = [ 0 => '%d Ergebnis wurde herausgefiltert, weil Ihr Knoten die Domäne blockiert, auf der das Ergebnis registriert ist. Sie können die Liste aller Domänen, die Ihr Knoten derzeit blockiert, auf der Info-Seite einsehen.', @@ -1487,6 +1491,29 @@ $a->strings['Events'] = 'Veranstaltungen'; $a->strings['View'] = 'Ansehen'; $a->strings['Create New Event'] = 'Neue Veranstaltung erstellen'; $a->strings['list'] = 'Liste'; +$a->strings['Could not create circle.'] = 'Der Circle konnte nicht erstellt werden.'; +$a->strings['Circle not found.'] = 'Circle nicht gefunden.'; +$a->strings['Circle name was not changed.'] = 'Der Name des Circles wurde nicht geändert.'; +$a->strings['Unknown circle.'] = 'Unbekannter Circle.'; +$a->strings['Contact not found.'] = 'Kontakt nicht gefunden.'; +$a->strings['Invalid contact.'] = 'Ungültiger Kontakt.'; +$a->strings['Contact is deleted.'] = 'Kontakt wurde gelöscht'; +$a->strings['Unable to add the contact to the circle.'] = 'Es ist nicht möglich, den Kontakt zum Circle hinzuzufügen.'; +$a->strings['Contact successfully added to circle.'] = 'Der Kontakt wurde erfolgreich dem Circle hinzugefügt.'; +$a->strings['Unable to remove the contact from the circle.'] = 'Es ist nicht möglich, den Kontakt aus dem Circle zu entfernen.'; +$a->strings['Contact successfully removed from circle.'] = 'Kontakt erfolgreich aus dem Circle entfernt.'; +$a->strings['Bad request.'] = 'Ungültige Anfrage.'; +$a->strings['Save Circle'] = 'Circle speichern'; +$a->strings['Filter'] = 'Filter'; +$a->strings['Create a circle of contacts/friends.'] = 'Erstelle einen Circle aus Kontakten/Freunden'; +$a->strings['Unable to remove circle.'] = 'Der Circle kann nicht entfernt werden.'; +$a->strings['Delete Circle'] = 'Circle löschen'; +$a->strings['Edit Circle Name'] = 'Name des Circles ändern'; +$a->strings['Members'] = 'Mitglieder'; +$a->strings['Circle is empty'] = 'Dieser Circle ist leer'; +$a->strings['Remove contact from circle'] = 'Kontakt aus Circle entfernen'; +$a->strings['Click on a contact to add or remove.'] = 'Klicke einen Kontakt an, um ihn hinzuzufügen oder zu entfernen'; +$a->strings['Add contact to circle'] = 'Kontakt zu Circle hinzufügen'; $a->strings['%d contact edited.'] = [ 0 => '%d Kontakt bearbeitet.', 1 => '%d Kontakte bearbeitet.', @@ -1504,7 +1531,7 @@ $a->strings['Archived'] = 'Archiviert'; $a->strings['Only show archived contacts'] = 'Nur archivierte Kontakte anzeigen'; $a->strings['Hidden'] = 'Verborgen'; $a->strings['Only show hidden contacts'] = 'Nur verborgene Kontakte anzeigen'; -$a->strings['Organize your contact groups'] = 'Verwalte deine Kontaktgruppen'; +$a->strings['Organize your contact circles'] = 'Verwalte Deine Circles'; $a->strings['Search your contacts'] = 'Suche in deinen Kontakten'; $a->strings['Results for: %s'] = 'Ergebnisse für: %s'; $a->strings['Update'] = 'Aktualisierungen'; @@ -1524,7 +1551,6 @@ $a->strings['you are a fan of'] = 'Du bist Fan von'; $a->strings['Pending outgoing contact request'] = 'Ausstehende ausgehende Kontaktanfrage'; $a->strings['Pending incoming contact request'] = 'Ausstehende eingehende Kontaktanfrage'; $a->strings['Visit %s\'s profile [%s]'] = 'Besuche %ss Profil [%s]'; -$a->strings['Contact not found.'] = 'Kontakt nicht gefunden.'; $a->strings['Contact update failed.'] = 'Konnte den Kontakt nicht aktualisieren.'; $a->strings['Return to contact editor'] = 'Zurück zum Kontakteditor'; $a->strings['Name'] = 'Name'; @@ -1532,7 +1558,6 @@ $a->strings['Account Nickname'] = 'Konto-Spitzname'; $a->strings['Account URL'] = 'Konto-URL'; $a->strings['Poll/Feed URL'] = 'Pull/Feed-URL'; $a->strings['New photo from this URL'] = 'Neues Foto von dieser URL'; -$a->strings['Invalid contact.'] = 'Ungültiger Kontakt.'; $a->strings['No known contacts.'] = 'Keine bekannten Kontakte.'; $a->strings['No common contacts.'] = 'Keine gemeinsamen Kontakte.'; $a->strings['Follower (%s)'] = [ @@ -1633,7 +1658,6 @@ $a->strings['Revoke Follow'] = 'Folgen widerrufen'; $a->strings['Revoke the follow from this contact'] = 'Widerruft das Folgen dieses Kontaktes'; $a->strings['Bad Request.'] = 'Ungültige Anfrage.'; $a->strings['Unknown contact.'] = 'Unbekannter Kontakt.'; -$a->strings['Contact is deleted.'] = 'Kontakt wurde gelöscht'; $a->strings['Contact is being deleted.'] = 'Kontakt wurde gelöscht.'; $a->strings['Follow was successfully revoked.'] = 'Folgen wurde erfolgreich widerrufen.'; $a->strings['Do you really want to revoke this contact\'s follow? This cannot be undone and they will have to manually follow you back again.'] = 'Willst du das Folgen dieses Kontakt wirklich widerrufen? Dies kann nicht rückgängig gemacht werden und der Kontakt muss Ihnen manuell wieder folgen.'; @@ -1655,8 +1679,8 @@ $a->strings['Hide'] = 'Verbergen'; $a->strings['No results.'] = 'Keine Ergebnisse.'; $a->strings['Community option not available.'] = 'Optionen für die Gemeinschaftsseite nicht verfügbar.'; $a->strings['Not available.'] = 'Nicht verfügbar.'; -$a->strings['No such group'] = 'Es gibt keine solche Gruppe'; -$a->strings['Group: %s'] = 'Gruppe: %s'; +$a->strings['No such circle'] = 'Circle ist nicht vorhanden'; +$a->strings['Circle: %s'] = 'Circle: %s'; $a->strings['Latest Activity'] = 'Neu - Aktivität'; $a->strings['Sort by latest activity'] = 'Sortiere nach neueste Aktivität'; $a->strings['Latest Posts'] = 'Neu - Empfangen'; @@ -1763,26 +1787,6 @@ $a->strings['Please visit Friendi.ca to learn m $a->strings['Bug reports and issues: please visit'] = 'Probleme oder Fehler gefunden? Bitte besuche'; $a->strings['the bugtracker at github'] = 'den Bugtracker auf github'; $a->strings['Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'] = 'Vorschläge, Lob usw.: E-Mail an "Info" at "Friendi - dot ca"'; -$a->strings['Could not create group.'] = 'Konnte die Gruppe nicht erstellen.'; -$a->strings['Group not found.'] = 'Gruppe nicht gefunden.'; -$a->strings['Group name was not changed.'] = 'Der Name der Gruppe wurde nicht verändert.'; -$a->strings['Unknown group.'] = 'Unbekannte Gruppe'; -$a->strings['Unable to add the contact to the group.'] = 'Konnte den Kontakt nicht zur Gruppe hinzufügen'; -$a->strings['Contact successfully added to group.'] = 'Kontakt zur Gruppe hinzugefügt'; -$a->strings['Unable to remove the contact from the group.'] = 'Konnte den Kontakt nicht aus der Gruppe entfernen'; -$a->strings['Contact successfully removed from group.'] = 'Kontakt aus Gruppe entfernt'; -$a->strings['Bad request.'] = 'Ungültige Anfrage.'; -$a->strings['Save Group'] = 'Gruppe speichern'; -$a->strings['Filter'] = 'Filter'; -$a->strings['Create a group of contacts/friends.'] = 'Eine Kontaktgruppe anlegen.'; -$a->strings['Unable to remove group.'] = 'Konnte die Gruppe nicht entfernen.'; -$a->strings['Delete Group'] = 'Gruppe löschen'; -$a->strings['Edit Group Name'] = 'Gruppen Name bearbeiten'; -$a->strings['Members'] = 'Mitglieder'; -$a->strings['Group is empty'] = 'Gruppe ist leer'; -$a->strings['Remove contact from group'] = 'Entferne den Kontakt aus der Gruppe'; -$a->strings['Click on a contact to add or remove.'] = 'Klicke einen Kontakt an, um ihn hinzuzufügen oder zu entfernen'; -$a->strings['Add contact to group'] = 'Füge den Kontakt zur Gruppe hinzu'; $a->strings['No profile'] = 'Kein Profil'; $a->strings['Method Not Allowed.'] = 'Methode nicht erlaubt.'; $a->strings['Help:'] = 'Hilfe:'; @@ -1864,7 +1868,6 @@ $a->strings['Or - did you try to upload an empty file?'] = 'Oder - hast du versu $a->strings['File exceeds size limit of %s'] = 'Die Datei ist größer als das erlaubte Limit von %s'; $a->strings['File upload failed.'] = 'Hochladen der Datei fehlgeschlagen.'; $a->strings['Unable to process image.'] = 'Konnte das Bild nicht bearbeiten.'; -$a->strings['Image exceeds size limit of %s'] = 'Bildgröße überschreitet das Limit von %s'; $a->strings['Image upload failed.'] = 'Hochladen des Bildes gescheitert.'; $a->strings['List of all users'] = 'Liste aller Benutzerkonten'; $a->strings['Active'] = 'Aktive'; @@ -1875,13 +1878,13 @@ $a->strings['Deleted'] = 'Gelöscht'; $a->strings['List of pending user deletions'] = 'Liste der auf Löschung wartenden Benutzer'; $a->strings['Normal Account Page'] = 'Normales Konto'; $a->strings['Soapbox Page'] = 'Marktschreier-Konto'; -$a->strings['Public Forum'] = 'Öffentliches Forum'; +$a->strings['Public Group'] = 'Öffentliche Gruppe'; $a->strings['Automatic Friend Page'] = 'Automatische Freunde-Seite'; -$a->strings['Private Forum'] = 'Privates Forum'; +$a->strings['Private Group'] = 'Private Gruppe'; $a->strings['Personal Page'] = 'Persönliche Seite'; $a->strings['Organisation Page'] = 'Organisationsseite'; $a->strings['News Page'] = 'Nachrichtenseite'; -$a->strings['Community Forum'] = 'Gemeinschaftsforum'; +$a->strings['Community Group'] = 'Gemeinschaftsgruppe'; $a->strings['Relay'] = 'Relais'; $a->strings['You can\'t block a local contact, please block the user instead'] = 'Lokale Kontakte können nicht geblockt werden. Bitte blocke den Nutzer stattdessen.'; $a->strings['%s contact unblocked'] = [ @@ -1997,10 +2000,10 @@ $a->strings['Please make sure the debug.store_source config key is $a->strings['Item Guid'] = 'Beitrags-Guid'; $a->strings['Normal Account'] = 'Normales Konto'; $a->strings['Automatic Follower Account'] = 'Automatisch folgendes Konto (Marktschreier)'; -$a->strings['Public Forum Account'] = 'Öffentliches Forum-Konto'; +$a->strings['Public Group Account'] = 'Öffentliches Gruppen-Konto'; $a->strings['Automatic Friend Account'] = 'Automatische Freunde-Seite'; $a->strings['Blog Account'] = 'Blog-Konto'; -$a->strings['Private Forum Account'] = 'Privates Forum-Konto'; +$a->strings['Private Group Account'] = 'Privates Gruppen-Konto'; $a->strings['Registered users'] = 'Registrierte Personen'; $a->strings['Pending registrations'] = 'Anstehende Anmeldungen'; $a->strings['%s user blocked'] = [ @@ -2108,6 +2111,8 @@ $a->strings['%d more'] = '%d weitere'; $a->strings['To: %s
'] = 'To: %s
'; $a->strings['CC: %s
'] = 'CC: %s
'; $a->strings['BCC: %s
'] = 'BCC: %s
'; +$a->strings['Audience: %s
'] = 'Addressaten: %s
'; +$a->strings['Attributed To: %s
'] = 'Zurückzuführen auf: %s
'; $a->strings['The Photo is not available.'] = 'Das Foto ist nicht verfügbar.'; $a->strings['The Photo with id %s is not available.'] = 'Das Bild mit ID %s ist nicht verfügbar.'; $a->strings['Invalid external resource with url %s.'] = 'Ungültige externe Ressource mit der URL %s'; @@ -2126,6 +2131,7 @@ $a->strings['No contacts.'] = 'Keine Kontakte.'; $a->strings['%s\'s timeline'] = 'Timeline von %s'; $a->strings['%s\'s posts'] = 'Beiträge von %s'; $a->strings['%s\'s comments'] = 'Kommentare von %s'; +$a->strings['Image exceeds size limit of %s'] = 'Bildgröße überschreitet das Limit von %s'; $a->strings['Image upload didn\'t complete, please try again'] = 'Der Upload des Bildes war nicht vollständig. Bitte versuche es erneut.'; $a->strings['Image file is missing'] = 'Bilddatei konnte nicht gefunden werden.'; $a->strings['Server can\'t accept new file upload at this time, please contact your administrator'] = 'Der Server kann derzeit keine neuen Datei-Uploads akzeptieren. Bitte kontaktiere deinen Administrator.'; @@ -2144,7 +2150,7 @@ $a->strings['%d year old'] = [ 1 => '%d Jahre alt', ]; $a->strings['Description:'] = 'Beschreibung'; -$a->strings['Forums:'] = 'Foren:'; +$a->strings['Groups:'] = 'Gruppen:'; $a->strings['View profile as:'] = 'Das Profil aus der Sicht von jemandem anderen betrachten:'; $a->strings['View as'] = 'Betrachten als'; $a->strings['Profile unavailable.'] = 'Profil nicht verfügbar.'; @@ -2272,7 +2278,7 @@ $a->strings['Importing Contacts done'] = 'Kontakte wurden importiert.'; $a->strings['Relocate message has been send to your contacts'] = 'Die Umzugsbenachrichtigung wurde an Deine Kontakte versendet.'; $a->strings['Unable to find your profile. Please contact your admin.'] = 'Konnte dein Profil nicht finden. Bitte kontaktiere den Admin.'; $a->strings['Personal Page Subtypes'] = 'Unterarten der persönlichen Seite'; -$a->strings['Community Forum Subtypes'] = 'Unterarten des Gemeinschaftsforums'; +$a->strings['Community Group Subtypes'] = 'Unterarten der Gemeinschaftsgruppen'; $a->strings['Account for a personal profile.'] = 'Konto für ein persönliches Profil.'; $a->strings['Account for an organisation that automatically approves contact requests as "Followers".'] = 'Konto für eine Organisation, das Kontaktanfragen automatisch als "Follower" annimmt.'; $a->strings['Account for a news reflector that automatically approves contact requests as "Followers".'] = 'Konto für einen Feedspiegel, das Kontaktanfragen automatisch als "Follower" annimmt.'; @@ -2281,7 +2287,7 @@ $a->strings['Account for a regular personal profile that requires manual approva $a->strings['Account for a public profile that automatically approves contact requests as "Followers".'] = 'Konto für ein öffentliches Profil, das Kontaktanfragen automatisch als "Follower" annimmt.'; $a->strings['Automatically approves all contact requests.'] = 'Bestätigt alle Kontaktanfragen automatisch.'; $a->strings['Account for a popular profile that automatically approves contact requests as "Friends".'] = 'Konto für ein gefragtes Profil, das Kontaktanfragen automatisch als "Friend" annimmt.'; -$a->strings['Private Forum [Experimental]'] = 'Privates Forum [Versuchsstadium]'; +$a->strings['Private Group [Experimental]'] = 'Private Gruppe [experimentell]'; $a->strings['Requires manual approval of contact requests.'] = 'Kontaktanfragen müssen manuell bestätigt werden.'; $a->strings['OpenID:'] = 'OpenID:'; $a->strings['(Optional) Allow this OpenID to login to this account.'] = '(Optional) Erlaube die Anmeldung für dieses Konto mit dieser OpenID.'; @@ -2501,12 +2507,12 @@ $a->strings['

Custom fields appear on your profile page.

You can use BBCodes in the field values.

Reorder by dragging the field title.

Empty the label field to remove a custom field.

-

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected groups.

'] = '

Die benutzerdefinierten Felder erscheinen auf deiner Profil-Seite

. +

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

'] = '

Die benutzerdefinierten Felder erscheinen auf deiner Profil-Seite

.

BBCode kann verwendet werden

Die Reihenfolge der Felder kann durch Ziehen des Feld-Titels mit der Maus angepasst werden.

Wird die Bezeichnung des Felds geleert, wird das Feld beim Speichern aus dem Profil entfernt.

-

Nicht öffentliche Felder können nur von den ausgewählten Friendica Kontakte gesehen werden.

'; +

Nicht öffentliche Felder können nur von den ausgewählten Friendica Circles gesehen werden.

'; $a->strings['Image size reduction [%s] failed.'] = 'Verkleinern der Bildgröße von [%s] scheiterte.'; $a->strings['Shift-reload the page or clear browser cache if the new photo does not display immediately.'] = 'Drücke Umschalt+Neu Laden oder leere den Browser-Cache, falls das neue Foto nicht gleich angezeigt wird.'; $a->strings['Unable to process image'] = 'Bild konnte nicht verarbeitet werden'; @@ -2691,8 +2697,8 @@ $a->strings['The Directory page lets you find other people in this network or ot $a->strings['Finding New People'] = 'Neue Leute kennenlernen'; $a->strings['On the side panel of the Contacts page are several tools to find new friends. We can match people by interest, look up people by name or interest, and provide suggestions based on network relationships. On a brand new site, friend suggestions will usually begin to be populated within 24 hours.'] = 'Im seitlichen Bedienfeld der Kontakteseite gibt es diverse Werkzeuge, um neue Personen zu finden. Wir können Menschen mit den gleichen Interessen finden, anhand von Namen oder Interessen suchen oder aber aufgrund vorhandener Kontakte neue Leute vorschlagen. Auf einer brandneuen - soeben erstellten - Seite starten die Kontaktvorschläge innerhalb von 24 Stunden.'; -$a->strings['Group Your Contacts'] = 'Gruppiere deine Kontakte'; -$a->strings['Once you have made some friends, organize them into private conversation groups from the sidebar of your Contacts page and then you can interact with each group privately on your Network page.'] = 'Sobald du einige Kontakte gefunden hast, organisiere sie in Gruppen zur privaten Kommunikation im Seitenmenü der Kontakte-Seite. Du kannst dann mit jeder dieser Gruppen von der Netzwerkseite aus privat interagieren.'; +$a->strings['Add Your Contacts To Circle'] = 'Kontakte zum Circle hinzufügen'; +$a->strings['Once you have made some friends, organize them into private conversation circles from the sidebar of your Contacts page and then you can interact with each circle privately on your Network page.'] = 'Sobald Sie einige Freunde gefunden haben, können Sie diese in der Seitenleiste Ihrer Kontaktseite in private Circles einteilen und dann mit jedem Circle auf Ihrer Netzwerkseite privat interagieren.'; $a->strings['Why Aren\'t My Posts Public?'] = 'Warum sind meine Beiträge nicht öffentlich?'; $a->strings['Friendica respects your privacy. By default, your posts will only show up to people you\'ve added as friends. For more information, see the help section from the link above.'] = 'Friendica respektiert Deine Privatsphäre. Mit der Grundeinstellung werden Deine Beiträge ausschließlich Deinen Kontakten angezeigt. Für weitere Informationen diesbezüglich lies dir bitte den entsprechenden Abschnitt in der Hilfe unter dem obigen Link durch.'; $a->strings['Getting Help'] = 'Hilfe bekommen'; @@ -2803,7 +2809,8 @@ $a->strings['Edit'] = 'Bearbeiten'; $a->strings['Delete globally'] = 'Global löschen'; $a->strings['Remove locally'] = 'Lokal entfernen'; $a->strings['Block %s'] = 'Blockiere %s'; -$a->strings['Ignore %s'] = 'Ignorieren %s'; +$a->strings['Ignore %s'] = 'Ignoriere %s'; +$a->strings['Collapse %s'] = 'Verberge %s'; $a->strings['Save to folder'] = 'In Ordner speichern'; $a->strings['I will attend'] = 'Ich werde teilnehmen'; $a->strings['I will not attend'] = 'Ich werde nicht teilnehmen'; @@ -2847,9 +2854,9 @@ $a->strings['%d comment'] = [ ]; $a->strings['Show more'] = 'Zeige mehr'; $a->strings['Show fewer'] = 'Zeige weniger'; -$a->strings['Reshared by: %s'] = 'Weitergeteilt von: %s'; +$a->strings['Reshared by: %s'] = 'Geteilt von: %s'; $a->strings['Viewed by: %s'] = 'Gesehen von: %s'; -$a->strings['Liked by: %s'] = 'Gemocht von: %s'; +$a->strings['Liked by: %s'] = 'Diese Menschen mögen das: %s'; $a->strings['Disliked by: %s'] = 'Unbeliebt bei: %s'; $a->strings['Attended by: %s'] = 'Besucht von: %s'; $a->strings['Maybe attended by: %s'] = 'Vielleicht besucht von: %s'; @@ -2943,7 +2950,7 @@ $a->strings['Center'] = 'Mitte'; $a->strings['Color scheme'] = 'Farbschema'; $a->strings['Posts font size'] = 'Schriftgröße in Beiträgen'; $a->strings['Textareas font size'] = 'Schriftgröße in Eingabefeldern'; -$a->strings['Comma separated list of helper forums'] = 'Komma-separierte Liste der Helfer-Foren'; +$a->strings['Comma separated list of helper groups'] = 'Komma-separierte Liste der Helfer-Gruppen'; $a->strings['don\'t show'] = 'nicht zeigen'; $a->strings['show'] = 'zeigen'; $a->strings['Set style'] = 'Stil auswählen'; diff --git a/view/lang/fi-fi/messages.po b/view/lang/fi-fi/messages.po index a08ee4f37..535bc3ba9 100644 --- a/view/lang/fi-fi/messages.po +++ b/view/lang/fi-fi/messages.po @@ -1,8 +1,9 @@ # FRIENDICA Distributed Social Network -# Copyright (C) 2010-2022, the Friendica project +# Copyright (C) 2010-2023, the Friendica project # This file is distributed under the same license as the Friendica package. # # Translators: +# Henrik Härkönen, 2023 # Ilmari , 2013 # Kris, 2018 # Kris, 2018 @@ -15,2706 +16,88 @@ msgid "" msgstr "" "Project-Id-Version: friendica\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-06-02 08:49+0200\n" -"PO-Revision-Date: 2018-06-06 15:02+0000\n" -"Last-Translator: Kris\n" -"Language-Team: Finnish (Finland) (http://www.transifex.com/Friendica/friendica/language/fi_FI/)\n" +"POT-Creation-Date: 2023-06-01 19:00-0400\n" +"PO-Revision-Date: 2011-05-05 10:19+0000\n" +"Last-Translator: Henrik Härkönen, 2023\n" +"Language-Team: Finnish (Finland) (http://app.transifex.com/Friendica/friendica/language/fi_FI/)\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Language: fi_FI\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: include/enotify.php:31 -msgid "Friendica Notification" -msgstr "Friendica-huomautus" +#: mod/item.php:100 mod/item.php:103 mod/item.php:170 mod/item.php:173 +msgid "Unable to locate original post." +msgstr "Alkuperäinen julkaisu ei löydy." -#: include/enotify.php:34 -msgid "Thank You," -msgstr "Kiitos," - -#: include/enotify.php:37 -#, php-format -msgid "%s Administrator" -msgstr "%s Ylläpitäjä" - -#: include/enotify.php:39 -#, php-format -msgid "%1$s, %2$s Administrator" -msgstr "%1$s, %2$s Ylläpitäjä" - -#: include/enotify.php:95 -#, php-format -msgid "[Friendica:Notify] New mail received at %s" -msgstr "[Friendica:Notify] Uusi viesti, katso %s" - -#: include/enotify.php:97 -#, php-format -msgid "%1$s sent you a new private message at %2$s." -msgstr "%1$s lähetti sinulle uuden yksityisviestin kohteessa %2$s." - -#: include/enotify.php:98 -msgid "a private message" -msgstr "yksityisviesti" - -#: include/enotify.php:98 -#, php-format -msgid "%1$s sent you %2$s." -msgstr "%1$s lähetti sinulle %2$s." - -#: include/enotify.php:100 -#, php-format -msgid "Please visit %s to view and/or reply to your private messages." -msgstr "Katso yksityisviestisi kohteessa %s." - -#: include/enotify.php:138 -#, php-format -msgid "%1$s commented on [url=%2$s]a %3$s[/url]" -msgstr "%1$s kommentoi [url=%2$s] %3$s[/url]" - -#: include/enotify.php:146 -#, php-format -msgid "%1$s commented on [url=%2$s]%3$s's %4$s[/url]" +#: mod/item.php:138 +msgid "Post updated." msgstr "" -#: include/enotify.php:156 -#, php-format -msgid "%1$s commented on [url=%2$s]your %3$s[/url]" +#: mod/item.php:203 mod/item.php:207 +msgid "Item wasn't stored." msgstr "" -#: include/enotify.php:168 -#, php-format -msgid "[Friendica:Notify] Comment to conversation #%1$d by %2$s" -msgstr "[Friendica:Notify] %2$s kommentoi keskustelussa #%1$d" - -#: include/enotify.php:170 -#, php-format -msgid "%s commented on an item/conversation you have been following." -msgstr "%s kommentoi kohteessa/keskustelussa jota seuraat." - -#: include/enotify.php:173 include/enotify.php:188 include/enotify.php:203 -#: include/enotify.php:218 include/enotify.php:237 include/enotify.php:252 -#, php-format -msgid "Please visit %s to view and/or reply to the conversation." -msgstr "Käy %s nähdäksesi keskustelun ja/tai vastataksesi siihen" - -#: include/enotify.php:180 -#, php-format -msgid "[Friendica:Notify] %s posted to your profile wall" -msgstr "[Friendica:Notify] %s kirjoitti profiiliseinällesi" - -#: include/enotify.php:182 -#, php-format -msgid "%1$s posted to your profile wall at %2$s" -msgstr "%1$s kirjoitti seinällesi kohteessa %2$s" - -#: include/enotify.php:183 -#, php-format -msgid "%1$s posted to [url=%2$s]your wall[/url]" -msgstr "%1$s kirjoitti [url=%2$s]seinällesi[/url]" - -#: include/enotify.php:195 -#, php-format -msgid "[Friendica:Notify] %s tagged you" -msgstr "[Friendica:Notify] %s merkitsi sinut" - -#: include/enotify.php:197 -#, php-format -msgid "%1$s tagged you at %2$s" -msgstr "%1$s merkitsi sinut kohteessa %2$s" - -#: include/enotify.php:198 -#, php-format -msgid "%1$s [url=%2$s]tagged you[/url]." -msgstr "%1$s [url=%2$s]merkitsi sinut[/url]." - -#: include/enotify.php:210 -#, php-format -msgid "[Friendica:Notify] %s shared a new post" -msgstr "[Friendica:Notify] %s jakoi uuden julkaisun" - -#: include/enotify.php:212 -#, php-format -msgid "%1$s shared a new post at %2$s" -msgstr "%1$s jakoi uuden julkaisun %2$s" - -#: include/enotify.php:213 -#, php-format -msgid "%1$s [url=%2$s]shared a post[/url]." -msgstr "%1$s [url=%2$s]jakoi julkaisun[/url]." - -#: include/enotify.php:225 -#, php-format -msgid "[Friendica:Notify] %1$s poked you" -msgstr "[Friendica:Notify] %1$s tökkäsi sinua." - -#: include/enotify.php:227 -#, php-format -msgid "%1$s poked you at %2$s" -msgstr "%1$s tökkäsi sinua kohteessa %2$s" - -#: include/enotify.php:228 -#, php-format -msgid "%1$s [url=%2$s]poked you[/url]." -msgstr "%1$s [url=%2$s]tökkasi sinua[/url]." - -#: include/enotify.php:244 -#, php-format -msgid "[Friendica:Notify] %s tagged your post" -msgstr "[Friendica:Notify] %s merkitsi julkaisusi" - -#: include/enotify.php:246 -#, php-format -msgid "%1$s tagged your post at %2$s" -msgstr "%1$s merkitsi julkaisusi kohteessa %2$s" - -#: include/enotify.php:247 -#, php-format -msgid "%1$s tagged [url=%2$s]your post[/url]" -msgstr "%1$s merkitsi [url=%2$s]julkaisusi[/url]" - -#: include/enotify.php:259 -msgid "[Friendica:Notify] Introduction received" -msgstr "[Friendica:Notify] Esittely vastaanotettu" - -#: include/enotify.php:261 -#, php-format -msgid "You've received an introduction from '%1$s' at %2$s" -msgstr "Olet vastaanottanut kaverikutsun henkilöltä '%1$s' kohteessa %2$s" - -#: include/enotify.php:262 -#, php-format -msgid "You've received [url=%1$s]an introduction[/url] from %2$s." -msgstr "Olet vastaanottanut [url=%1$s]kaverikutsun[/url] henkilöltä %2$s." - -#: include/enotify.php:267 include/enotify.php:313 -#, php-format -msgid "You may visit their profile at %s" -msgstr "Voit vierailla hänen profiilissaan kohteessa %s" - -#: include/enotify.php:269 -#, php-format -msgid "Please visit %s to approve or reject the introduction." -msgstr "Hyväksy tai hylkää esittely %s-sivustossa" - -#: include/enotify.php:277 -msgid "[Friendica:Notify] A new person is sharing with you" -msgstr "[Friendica:Notify] Uusi henkilö jakaa päivityksensä kanssasi" - -#: include/enotify.php:279 include/enotify.php:280 -#, php-format -msgid "%1$s is sharing with you at %2$s" -msgstr "%1$s jakaa päivityksensä kanssasi kohteessa %2$s" - -#: include/enotify.php:287 -msgid "[Friendica:Notify] You have a new follower" -msgstr "[Friendica:Notify] Sinulla on uusi seuraaja" - -#: include/enotify.php:289 include/enotify.php:290 -#, php-format -msgid "You have a new follower at %2$s : %1$s" -msgstr "Sinulla on uusi seuraaja sivustolla %2$s : %1$s" - -#: include/enotify.php:302 -msgid "[Friendica:Notify] Friend suggestion received" -msgstr "[Friendica:Notify] Kaveripyyntö vastaanotettu" - -#: include/enotify.php:304 -#, php-format -msgid "You've received a friend suggestion from '%1$s' at %2$s" -msgstr "Sait kaverikutsun henkilöltä '%1$s' (%2$s)" - -#: include/enotify.php:305 -#, php-format -msgid "" -"You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." -msgstr "Sait [url=%1$s] kaveriehdotuksen[/url] %2$s käyttäjältä %3$s." - -#: include/enotify.php:311 -msgid "Name:" -msgstr "Nimi:" - -#: include/enotify.php:312 -msgid "Photo:" -msgstr "Kuva:" - -#: include/enotify.php:315 -#, php-format -msgid "Please visit %s to approve or reject the suggestion." -msgstr "Hyväksy tai hylkää ehdotus %s-sivustossa" - -#: include/enotify.php:323 include/enotify.php:338 -msgid "[Friendica:Notify] Connection accepted" -msgstr "[Friendica:Notify] Yhteys hyväksytty" - -#: include/enotify.php:325 include/enotify.php:340 -#, php-format -msgid "'%1$s' has accepted your connection request at %2$s" -msgstr "'%1$s' on hyväksynyt kaverikutsusi kohteessa %2$s" - -#: include/enotify.php:326 include/enotify.php:341 -#, php-format -msgid "%2$s has accepted your [url=%1$s]connection request[/url]." -msgstr "%2$s hyväksyi [url=%1$s]kaverikutsusi[/url]." - -#: include/enotify.php:331 -msgid "" -"You are now mutual friends and may exchange status updates, photos, and " -"email without restriction." -msgstr "Olette nyt yhteiset ystävät ja voitte lähettää toisillenne tilapäivityksiä, kuvia ja sähköposteja ilman rajoituksia." - -#: include/enotify.php:333 -#, php-format -msgid "Please visit %s if you wish to make any changes to this relationship." -msgstr "Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta." - -#: include/enotify.php:346 -#, php-format -msgid "" -"'%1$s' has chosen to accept you a fan, which restricts some forms of " -"communication - such as private messaging and some profile interactions. If " -"this is a celebrity or community page, these settings were applied " -"automatically." -msgstr "'%1$s' on hyväksynyt sinut faniksi. Tämä rajoittaa joitain kommunikointitapoja - kuten yksityisviestiettely ja joitain profiilitoimintoja. Jos tämä on julkisuuden henkilö tai yhteisösivu, asetukset on valittu automaattisesti." - -#: include/enotify.php:348 -#, php-format -msgid "" -"'%1$s' may choose to extend this into a two-way or more permissive " -"relationship in the future." -msgstr "'%1$s' voi halutessaan laajentaa suhteenne kahdenväliseksi." - -#: include/enotify.php:350 -#, php-format -msgid "Please visit %s if you wish to make any changes to this relationship." -msgstr "Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta." - -#: include/enotify.php:360 mod/removeme.php:45 -msgid "[Friendica System Notify]" -msgstr "[Friendica Järjestelmäilmoitus]" - -#: include/enotify.php:360 -msgid "registration request" -msgstr "rekisteröintipyyntö" - -#: include/enotify.php:362 -#, php-format -msgid "You've received a registration request from '%1$s' at %2$s" -msgstr "Olet vastaanottanut rekisteröintipyynnön henkilöltä '%1$s' kohteessa %2$s" - -#: include/enotify.php:363 -#, php-format -msgid "You've received a [url=%1$s]registration request[/url] from %2$s." -msgstr "Olet vastaanottanut [url=%1$s]rekisteröintipyynnön[/url] henkilöltä %2$s." - -#: include/enotify.php:368 -#, php-format -msgid "Full Name:\t%1$s\\nSite Location:\t%2$s\\nLogin Name:\t%3$s (%4$s)" -msgstr "Koko nimi:\t%1$s\\nSivusto:\t%2$s\\nKäyttäjätunnus:\t%3$s (%4$s)" - -#: include/enotify.php:374 -#, php-format -msgid "Please visit %s to approve or reject the request." -msgstr "Hyväksy tai hylkää pyyntö %s-sivustossa." - -#: include/api.php:1202 -#, php-format -msgid "Daily posting limit of %d post reached. The post was rejected." -msgid_plural "Daily posting limit of %d posts reached. The post was rejected." -msgstr[0] "Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." -msgstr[1] "Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." - -#: include/api.php:1226 -#, php-format -msgid "Weekly posting limit of %d post reached. The post was rejected." -msgid_plural "" -"Weekly posting limit of %d posts reached. The post was rejected." -msgstr[0] "Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." -msgstr[1] "Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." - -#: include/api.php:1250 -#, php-format -msgid "Monthly posting limit of %d post reached. The post was rejected." -msgstr "Kuukausittainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." - -#: include/api.php:4521 mod/profile_photo.php:85 mod/profile_photo.php:93 -#: mod/profile_photo.php:101 mod/profile_photo.php:211 -#: mod/profile_photo.php:302 mod/profile_photo.php:312 mod/photos.php:88 -#: mod/photos.php:194 mod/photos.php:710 mod/photos.php:1137 -#: mod/photos.php:1154 mod/photos.php:1678 src/Model/User.php:555 -#: src/Model/User.php:563 src/Model/User.php:571 -msgid "Profile Photos" -msgstr "Profiilin valokuvat" - -#: include/conversation.php:144 include/conversation.php:279 -#: include/text.php:1749 src/Model/Item.php:2002 -msgid "event" -msgstr "tapahtuma" - -#: include/conversation.php:147 include/conversation.php:157 -#: include/conversation.php:282 include/conversation.php:291 -#: mod/subthread.php:101 mod/tagger.php:72 src/Model/Item.php:2000 -#: src/Protocol/Diaspora.php:1957 -msgid "status" -msgstr "tila" - -#: include/conversation.php:152 include/conversation.php:287 -#: include/text.php:1751 mod/subthread.php:101 mod/tagger.php:72 -#: src/Model/Item.php:2000 -msgid "photo" -msgstr "kuva" - -#: include/conversation.php:164 src/Model/Item.php:1873 -#: src/Protocol/Diaspora.php:1953 -#, php-format -msgid "%1$s likes %2$s's %3$s" -msgstr "%1$s tykkää käyttäjän %2$s %3$s" - -#: include/conversation.php:166 src/Model/Item.php:1878 -#, php-format -msgid "%1$s doesn't like %2$s's %3$s" +#: mod/item.php:217 +msgid "Item couldn't be fetched." msgstr "" -#: include/conversation.php:168 -#, php-format -msgid "%1$s attends %2$s's %3$s" -msgstr "%1$s osallistuu tapahtumaan %3$s, jonka järjestää %2$s" +#: mod/item.php:255 mod/item.php:259 +msgid "Empty post discarded." +msgstr "Tyhjä julkaisu hylätty." -#: include/conversation.php:170 -#, php-format -msgid "%1$s doesn't attend %2$s's %3$s" -msgstr "%1$s ei osallistu tapahtumaan %3$s, jonka järjestää %2$s" - -#: include/conversation.php:172 -#, php-format -msgid "%1$s attends maybe %2$s's %3$s" -msgstr "%1$s ehkä osallistuu tapahtumaan %3$s, jonka järjestää %2$s" - -#: include/conversation.php:206 -#, php-format -msgid "%1$s is now friends with %2$s" -msgstr "%1$s ja %2$s ovat kavereita" - -#: include/conversation.php:247 -#, php-format -msgid "%1$s poked %2$s" -msgstr "%1$s tökkäsi %2$s" - -#: include/conversation.php:301 mod/tagger.php:110 -#, php-format -msgid "%1$s tagged %2$s's %3$s with %4$s" -msgstr "" - -#: include/conversation.php:328 -msgid "post/item" -msgstr "julkaisu/kohde" - -#: include/conversation.php:329 -#, php-format -msgid "%1$s marked %2$s's %3$s as favorite" -msgstr "" - -#: include/conversation.php:609 mod/photos.php:1495 mod/profiles.php:355 -msgid "Likes" -msgstr "Tykkäyksiä" - -#: include/conversation.php:609 mod/photos.php:1495 mod/profiles.php:359 -msgid "Dislikes" -msgstr "Inhokit" - -#: include/conversation.php:610 include/conversation.php:1638 -#: mod/photos.php:1496 -msgid "Attending" -msgid_plural "Attending" -msgstr[0] "Osallistuu" -msgstr[1] "Osallistuu" - -#: include/conversation.php:610 mod/photos.php:1496 -msgid "Not attending" -msgstr "Ei osallistu" - -#: include/conversation.php:610 mod/photos.php:1496 -msgid "Might attend" -msgstr "Ehkä" - -#: include/conversation.php:722 mod/photos.php:1563 src/Object/Post.php:192 -msgid "Select" -msgstr "Valitse" - -#: include/conversation.php:723 mod/contacts.php:830 mod/contacts.php:1035 -#: mod/admin.php:1832 mod/photos.php:1564 mod/settings.php:730 -msgid "Delete" -msgstr "Poista" - -#: include/conversation.php:761 src/Object/Post.php:371 -#: src/Object/Post.php:372 -#, php-format -msgid "View %s's profile @ %s" -msgstr "Katso %s-henkilön profiilia @ %s" - -#: include/conversation.php:773 src/Object/Post.php:359 -msgid "Categories:" -msgstr "Luokat:" - -#: include/conversation.php:774 src/Object/Post.php:360 -msgid "Filed under:" -msgstr "Arkistoitu kansioon:" - -#: include/conversation.php:781 src/Object/Post.php:385 -#, php-format -msgid "%s from %s" -msgstr "%s sovelluksesta %s" - -#: include/conversation.php:796 -msgid "View in context" -msgstr "Näytä kontekstissa" - -#: include/conversation.php:798 include/conversation.php:1313 -#: mod/wallmessage.php:145 mod/editpost.php:125 mod/message.php:245 -#: mod/message.php:414 mod/photos.php:1467 src/Object/Post.php:410 -msgid "Please wait" -msgstr "Odota" - -#: include/conversation.php:869 -msgid "remove" -msgstr "poista" - -#: include/conversation.php:873 -msgid "Delete Selected Items" -msgstr "Poista valitut kohteet" - -#: include/conversation.php:1018 view/theme/frio/theme.php:352 -msgid "Follow Thread" -msgstr "Seuraa ketjua" - -#: include/conversation.php:1019 src/Model/Contact.php:662 -msgid "View Status" -msgstr "Näytä tila" - -#: include/conversation.php:1020 include/conversation.php:1036 -#: mod/allfriends.php:73 mod/suggest.php:82 mod/match.php:89 -#: mod/directory.php:159 mod/dirfind.php:217 src/Model/Contact.php:602 -#: src/Model/Contact.php:615 src/Model/Contact.php:663 -msgid "View Profile" -msgstr "Näytä profiilia" - -#: include/conversation.php:1021 src/Model/Contact.php:664 -msgid "View Photos" -msgstr "Näytä kuvia" - -#: include/conversation.php:1022 src/Model/Contact.php:665 -msgid "Network Posts" -msgstr "Uutisvirtajulkaisut" - -#: include/conversation.php:1023 src/Model/Contact.php:666 -msgid "View Contact" -msgstr "Näytä kontaktia" - -#: include/conversation.php:1024 src/Model/Contact.php:668 -msgid "Send PM" -msgstr "Lähetä yksityisviesti" - -#: include/conversation.php:1028 src/Model/Contact.php:669 -msgid "Poke" -msgstr "Tökkää" - -#: include/conversation.php:1033 mod/allfriends.php:74 mod/suggest.php:83 -#: mod/match.php:90 mod/contacts.php:596 mod/dirfind.php:218 -#: mod/follow.php:143 view/theme/vier/theme.php:201 src/Content/Widget.php:61 -#: src/Model/Contact.php:616 -msgid "Connect/Follow" -msgstr "Yhdistä/Seuraa" - -#: include/conversation.php:1152 -#, php-format -msgid "%s likes this." -msgstr "%s tykkää tästä." - -#: include/conversation.php:1155 -#, php-format -msgid "%s doesn't like this." -msgstr "%s ei tykkää tästä." - -#: include/conversation.php:1158 -#, php-format -msgid "%s attends." -msgstr "%s osallistuu." - -#: include/conversation.php:1161 -#, php-format -msgid "%s doesn't attend." -msgstr "%s ei osallistu." - -#: include/conversation.php:1164 -#, php-format -msgid "%s attends maybe." -msgstr "%s ehkä osallistuu." - -#: include/conversation.php:1175 -msgid "and" -msgstr "ja" - -#: include/conversation.php:1181 -#, php-format -msgid "and %d other people" -msgstr "ja %d muuta ihmistä" - -#: include/conversation.php:1190 -#, php-format -msgid "%2$d people like this" -msgstr "%2$d ihmistä tykkää tästä" - -#: include/conversation.php:1191 -#, php-format -msgid "%s like this." -msgstr "%s tykkää tästä." - -#: include/conversation.php:1194 -#, php-format -msgid "%2$d people don't like this" -msgstr "%2$d ihmistä ei tykkää tästä." - -#: include/conversation.php:1195 -#, php-format -msgid "%s don't like this." -msgstr "%s ei tykkää tästä." - -#: include/conversation.php:1198 -#, php-format -msgid "%2$d people attend" -msgstr "%2$d ihmistä osallistuu" - -#: include/conversation.php:1199 -#, php-format -msgid "%s attend." -msgstr "%s osallistuu." - -#: include/conversation.php:1202 -#, php-format -msgid "%2$d people don't attend" -msgstr "%2$d ihmistä ei osallistu" - -#: include/conversation.php:1203 -#, php-format -msgid "%s don't attend." -msgstr "%s ei osallistu." - -#: include/conversation.php:1206 -#, php-format -msgid "%2$d people attend maybe" -msgstr "%2$d ihmistä ehkä osallistuu" - -#: include/conversation.php:1207 -#, php-format -msgid "%s attend maybe." -msgstr "%s ehkä osallistuu." - -#: include/conversation.php:1237 include/conversation.php:1253 -msgid "Visible to everybody" -msgstr "Näkyy kaikille" - -#: include/conversation.php:1238 include/conversation.php:1254 -#: mod/wallmessage.php:120 mod/wallmessage.php:127 mod/message.php:181 -#: mod/message.php:188 mod/message.php:324 mod/message.php:331 -msgid "Please enter a link URL:" -msgstr "Lisää URL-linkki:" - -#: include/conversation.php:1239 include/conversation.php:1255 -msgid "Please enter a video link/URL:" -msgstr "Lisää video URL-linkki:" - -#: include/conversation.php:1240 include/conversation.php:1256 -msgid "Please enter an audio link/URL:" -msgstr "Lisää ääni URL-linkki:" - -#: include/conversation.php:1241 include/conversation.php:1257 -msgid "Tag term:" -msgstr "Tunniste:" - -#: include/conversation.php:1242 include/conversation.php:1258 -#: mod/filer.php:34 -msgid "Save to Folder:" -msgstr "Tallenna kansioon:" - -#: include/conversation.php:1243 include/conversation.php:1259 -msgid "Where are you right now?" -msgstr "Mikä on sijaintisi?" - -#: include/conversation.php:1244 -msgid "Delete item(s)?" -msgstr "Poista kohde/kohteet?" - -#: include/conversation.php:1291 -msgid "New Post" -msgstr "Uusi julkaisu" - -#: include/conversation.php:1294 -msgid "Share" -msgstr "Jaa" - -#: include/conversation.php:1295 mod/wallmessage.php:143 mod/editpost.php:111 -#: mod/message.php:243 mod/message.php:411 -msgid "Upload photo" -msgstr "Lähetä kuva" - -#: include/conversation.php:1296 mod/editpost.php:112 -msgid "upload photo" -msgstr "lähetä kuva" - -#: include/conversation.php:1297 mod/editpost.php:113 -msgid "Attach file" -msgstr "Liitä tiedosto" - -#: include/conversation.php:1298 mod/editpost.php:114 -msgid "attach file" -msgstr "liitä tiedosto" - -#: include/conversation.php:1299 mod/wallmessage.php:144 mod/editpost.php:115 -#: mod/message.php:244 mod/message.php:412 -msgid "Insert web link" -msgstr "Lisää linkki" - -#: include/conversation.php:1300 mod/editpost.php:116 -msgid "web link" -msgstr "WWW-linkki" - -#: include/conversation.php:1301 mod/editpost.php:117 -msgid "Insert video link" -msgstr "Lisää videolinkki" - -#: include/conversation.php:1302 mod/editpost.php:118 -msgid "video link" -msgstr "videolinkki" - -#: include/conversation.php:1303 mod/editpost.php:119 -msgid "Insert audio link" -msgstr "Lisää äänilinkki" - -#: include/conversation.php:1304 mod/editpost.php:120 -msgid "audio link" -msgstr "äänilinkki" - -#: include/conversation.php:1305 mod/editpost.php:121 -msgid "Set your location" -msgstr "Aseta sijaintisi" - -#: include/conversation.php:1306 mod/editpost.php:122 -msgid "set location" -msgstr "aseta sijainti" - -#: include/conversation.php:1307 mod/editpost.php:123 -msgid "Clear browser location" -msgstr "Tyhjennä selaimen sijainti" - -#: include/conversation.php:1308 mod/editpost.php:124 -msgid "clear location" -msgstr "tyhjennä sijainti" - -#: include/conversation.php:1310 mod/editpost.php:138 -msgid "Set title" -msgstr "Aseta otsikko" - -#: include/conversation.php:1312 mod/editpost.php:140 -msgid "Categories (comma-separated list)" -msgstr "Luokat (pilkuilla eroteltu luettelo)" - -#: include/conversation.php:1314 mod/editpost.php:126 -msgid "Permission settings" -msgstr "Käyttöoikeusasetukset" - -#: include/conversation.php:1315 mod/editpost.php:155 -msgid "permissions" -msgstr "käyttöoikeudet" - -#: include/conversation.php:1323 mod/editpost.php:135 -msgid "Public post" -msgstr "Julkinen viesti" - -#: include/conversation.php:1327 mod/editpost.php:146 mod/events.php:529 -#: mod/photos.php:1486 mod/photos.php:1525 mod/photos.php:1598 -#: src/Object/Post.php:813 -msgid "Preview" -msgstr "Esikatselu" - -#: include/conversation.php:1331 include/items.php:388 mod/fbrowser.php:103 -#: mod/fbrowser.php:134 mod/suggest.php:41 mod/tagrm.php:19 mod/tagrm.php:99 -#: mod/editpost.php:149 mod/contacts.php:475 mod/unfollow.php:117 -#: mod/follow.php:161 mod/message.php:141 mod/dfrn_request.php:658 -#: mod/photos.php:248 mod/photos.php:317 mod/settings.php:670 -#: mod/settings.php:696 mod/videos.php:147 -msgid "Cancel" -msgstr "Peru" - -#: include/conversation.php:1336 -msgid "Post to Groups" -msgstr "Lähetä ryhmiin" - -#: include/conversation.php:1337 -msgid "Post to Contacts" -msgstr "Lähetä kontakteille" - -#: include/conversation.php:1338 -msgid "Private post" -msgstr "Yksityinen julkaisu" - -#: include/conversation.php:1343 mod/editpost.php:153 -#: src/Model/Profile.php:338 -msgid "Message" -msgstr "Viesti" - -#: include/conversation.php:1344 mod/editpost.php:154 -msgid "Browser" -msgstr "Selain" - -#: include/conversation.php:1609 -msgid "View all" -msgstr "Näytä kaikki" - -#: include/conversation.php:1632 -msgid "Like" -msgid_plural "Likes" -msgstr[0] "Tykkäys" -msgstr[1] "Tykkäyksiä" - -#: include/conversation.php:1635 -msgid "Dislike" -msgid_plural "Dislikes" -msgstr[0] "Inhokki" -msgstr[1] "Inhokit" - -#: include/conversation.php:1641 -msgid "Not Attending" -msgid_plural "Not Attending" -msgstr[0] "Ei osallistu" -msgstr[1] "Ei osallistu" - -#: include/conversation.php:1644 src/Content/ContactSelector.php:125 -msgid "Undecided" -msgid_plural "Undecided" -msgstr[0] "En ole varma" -msgstr[1] "En ole varma" - -#: include/items.php:343 mod/notice.php:22 mod/viewsrc.php:21 -#: mod/admin.php:277 mod/admin.php:1888 mod/admin.php:2136 mod/display.php:72 -#: mod/display.php:255 mod/display.php:356 +#: mod/item.php:427 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 "Kohdetta ei löytynyt." -#: include/items.php:383 -msgid "Do you really want to delete this item?" -msgstr "Haluatko varmasti poistaa tämän kohteen?" - -#: include/items.php:385 mod/api.php:110 mod/suggest.php:38 -#: mod/contacts.php:472 mod/follow.php:150 mod/message.php:138 -#: mod/dfrn_request.php:648 mod/profiles.php:543 mod/profiles.php:546 -#: mod/profiles.php:568 mod/register.php:238 mod/settings.php:1094 -#: mod/settings.php:1100 mod/settings.php:1107 mod/settings.php:1111 -#: mod/settings.php:1115 mod/settings.php:1119 mod/settings.php:1123 -#: mod/settings.php:1127 mod/settings.php:1147 mod/settings.php:1148 -#: mod/settings.php:1149 mod/settings.php:1150 mod/settings.php:1151 -msgid "Yes" -msgstr "Kyllä" - -#: include/items.php:402 mod/allfriends.php:21 mod/api.php:35 mod/api.php:40 -#: mod/attach.php:38 mod/common.php:26 mod/nogroup.php:28 -#: mod/repair_ostatus.php:13 mod/suggest.php:60 mod/uimport.php:28 -#: mod/manage.php:131 mod/wall_attach.php:74 mod/wall_attach.php:77 -#: mod/poke.php:150 mod/regmod.php:108 mod/viewcontacts.php:57 -#: mod/wall_upload.php:103 mod/wall_upload.php:106 mod/wallmessage.php:16 -#: mod/wallmessage.php:40 mod/wallmessage.php:79 mod/wallmessage.php:103 -#: mod/editpost.php:18 mod/fsuggest.php:80 mod/cal.php:304 -#: mod/contacts.php:386 mod/delegate.php:25 mod/delegate.php:43 -#: mod/delegate.php:54 mod/ostatus_subscribe.php:16 mod/profile_photo.php:30 -#: mod/profile_photo.php:176 mod/profile_photo.php:187 -#: mod/profile_photo.php:200 mod/unfollow.php:15 mod/unfollow.php:57 -#: mod/unfollow.php:90 mod/dirfind.php:25 mod/follow.php:17 mod/follow.php:54 -#: mod/follow.php:118 mod/invite.php:20 mod/invite.php:111 mod/crepair.php:98 -#: mod/message.php:59 mod/message.php:104 mod/dfrn_confirm.php:68 -#: mod/events.php:194 mod/group.php:26 mod/item.php:160 mod/network.php:32 -#: mod/notes.php:30 mod/notifications.php:73 mod/photos.php:174 -#: mod/photos.php:1039 mod/profiles.php:182 mod/profiles.php:513 -#: mod/register.php:54 mod/settings.php:43 mod/settings.php:142 -#: mod/settings.php:659 index.php:436 +#: mod/item.php:451 mod/message.php:67 mod/message.php:113 mod/notes.php:45 +#: mod/photos.php:152 mod/photos.php:667 src/Model/Event.php:522 +#: src/Module/Attach.php:55 src/Module/BaseApi.php:99 +#: src/Module/BaseNotifications.php:98 src/Module/BaseSettings.php:52 +#: src/Module/Calendar/Event/API.php:88 src/Module/Calendar/Event/Form.php:84 +#: src/Module/Calendar/Export.php:82 src/Module/Calendar/Show.php:82 +#: src/Module/Circle.php:40 src/Module/Circle.php:83 +#: src/Module/Contact/Advanced.php:60 src/Module/Contact/Follow.php:87 +#: src/Module/Contact/Follow.php:160 src/Module/Contact/MatchInterests.php:86 +#: src/Module/Contact/Suggestions.php:54 src/Module/Contact/Unfollow.php:66 +#: src/Module/Contact/Unfollow.php:80 src/Module/Contact/Unfollow.php:112 +#: src/Module/Delegation.php:118 src/Module/FollowConfirm.php:38 +#: src/Module/FriendSuggest.php:57 src/Module/Invite.php:42 +#: src/Module/Invite.php:131 src/Module/Notifications/Notification.php:76 +#: src/Module/Notifications/Notification.php:107 +#: src/Module/OStatus/Repair.php:60 src/Module/OStatus/Subscribe.php:66 +#: src/Module/Post/Edit.php:76 src/Module/Profile/Common.php:75 +#: src/Module/Profile/Contacts.php:78 src/Module/Profile/Photos.php:92 +#: src/Module/Profile/Schedule.php:39 src/Module/Profile/Schedule.php:56 +#: src/Module/Profile/UnkMail.php:69 src/Module/Profile/UnkMail.php:121 +#: src/Module/Profile/UnkMail.php:132 src/Module/Register.php:77 +#: src/Module/Register.php:90 src/Module/Register.php:206 +#: src/Module/Register.php:245 src/Module/Search/Directory.php:37 +#: src/Module/Settings/Account.php:50 src/Module/Settings/Account.php:407 +#: src/Module/Settings/Delegation.php:41 src/Module/Settings/Delegation.php:71 +#: src/Module/Settings/Display.php:69 src/Module/Settings/Display.php:151 +#: src/Module/Settings/Profile/Photo/Crop.php:165 +#: src/Module/Settings/Profile/Photo/Index.php:111 +#: src/Module/Settings/RemoveMe.php:117 src/Module/Settings/UserExport.php:80 +#: src/Module/Settings/UserExport.php:114 +#: src/Module/Settings/UserExport.php:215 +#: src/Module/Settings/UserExport.php:235 +#: src/Module/Settings/UserExport.php:300 src/Module/User/Import.php:84 +#: src/Module/User/Import.php:91 msgid "Permission denied." msgstr "Käyttöoikeus evätty." -#: include/items.php:472 src/Content/Feature.php:96 -msgid "Archives" -msgstr "Arkisto" - -#: include/items.php:478 view/theme/vier/theme.php:258 -#: src/Content/ForumManager.php:130 src/Content/Widget.php:317 -#: src/Object/Post.php:438 src/App.php:527 -msgid "show more" -msgstr "näytä lisää" - -#: include/security.php:81 -msgid "Welcome " -msgstr "Tervetuloa" - -#: include/security.php:82 -msgid "Please upload a profile photo." -msgstr "Lataa profiilikuva." - -#: include/security.php:84 -msgid "Welcome back " -msgstr "Tervetuloa takaisin" - -#: include/security.php:449 -msgid "" -"The form security token was not correct. This probably happened because the " -"form has been opened for too long (>3 hours) before submitting it." -msgstr "Lomakkeen turvallisuusavain oli väärin. Tämä voi johtua siitä, että lomake on ollut avoinna liian kauan (>3 tuntia) ennen sen lähettämistä." - -#: include/text.php:302 -msgid "newer" -msgstr "uudempi" - -#: include/text.php:303 -msgid "older" -msgstr "vanhempi" - -#: include/text.php:308 -msgid "first" -msgstr "ensimmäinen" - -#: include/text.php:309 -msgid "prev" -msgstr "edellinen" - -#: include/text.php:343 -msgid "next" -msgstr "seuraava" - -#: include/text.php:344 -msgid "last" -msgstr "viimeinen" - -#: include/text.php:398 -msgid "Loading more entries..." -msgstr "Merkinnät ladataan..." - -#: include/text.php:399 -msgid "The end" -msgstr "Loppu" - -#: include/text.php:884 -msgid "No contacts" -msgstr "Ei kontakteja" - -#: include/text.php:908 -#, php-format -msgid "%d Contact" -msgid_plural "%d Contacts" -msgstr[0] "%d kontakti" -msgstr[1] "%d kontakteja" - -#: include/text.php:921 -msgid "View Contacts" -msgstr "Näytä kontaktit" - -#: include/text.php:1010 mod/filer.php:35 mod/editpost.php:110 -#: mod/notes.php:67 -msgid "Save" -msgstr "Tallenna" - -#: include/text.php:1010 -msgid "Follow" -msgstr "Seuraa" - -#: include/text.php:1016 mod/search.php:155 src/Content/Nav.php:142 -msgid "Search" -msgstr "Haku" - -#: include/text.php:1019 src/Content/Nav.php:58 -msgid "@name, !forum, #tags, content" -msgstr "@nimi, !foorumi, #tunnisteet, sisältö" - -#: include/text.php:1025 src/Content/Nav.php:145 -msgid "Full Text" -msgstr "Koko teksti" - -#: include/text.php:1026 src/Content/Widget/TagCloud.php:54 -#: src/Content/Nav.php:146 -msgid "Tags" -msgstr "Tunnisteet" - -#: include/text.php:1027 mod/viewcontacts.php:131 mod/contacts.php:814 -#: mod/contacts.php:875 view/theme/frio/theme.php:270 src/Content/Nav.php:147 -#: src/Content/Nav.php:213 src/Model/Profile.php:955 src/Model/Profile.php:958 -msgid "Contacts" -msgstr "Yhteystiedot" - -#: include/text.php:1030 view/theme/vier/theme.php:253 -#: src/Content/ForumManager.php:125 src/Content/Nav.php:151 -msgid "Forums" -msgstr "Foorumit" - -#: include/text.php:1074 -msgid "poke" -msgstr "töki" - -#: include/text.php:1074 -msgid "poked" -msgstr "tökkäsi" - -#: include/text.php:1075 -msgid "ping" -msgstr "pingaa" - -#: include/text.php:1075 -msgid "pinged" -msgstr "pingasi" - -#: include/text.php:1076 -msgid "prod" -msgstr "töki" - -#: include/text.php:1076 -msgid "prodded" -msgstr "tökkäsi" - -#: include/text.php:1077 -msgid "slap" -msgstr "läimäytä" - -#: include/text.php:1077 -msgid "slapped" -msgstr "läimäsi" - -#: include/text.php:1078 -msgid "finger" -msgstr "näytä keskisormea" - -#: include/text.php:1078 -msgid "fingered" -msgstr "näytti keskisormea" - -#: include/text.php:1079 -msgid "rebuff" -msgstr "torju" - -#: include/text.php:1079 -msgid "rebuffed" -msgstr "torjui" - -#: include/text.php:1093 mod/settings.php:935 src/Model/Event.php:379 -msgid "Monday" -msgstr "Maanantai" - -#: include/text.php:1093 src/Model/Event.php:380 -msgid "Tuesday" -msgstr "Tiistai" - -#: include/text.php:1093 src/Model/Event.php:381 -msgid "Wednesday" -msgstr "Keskiviikko" - -#: include/text.php:1093 src/Model/Event.php:382 -msgid "Thursday" -msgstr "Torstai" - -#: include/text.php:1093 src/Model/Event.php:383 -msgid "Friday" -msgstr "Perjantai" - -#: include/text.php:1093 src/Model/Event.php:384 -msgid "Saturday" -msgstr "Lauantai" - -#: include/text.php:1093 mod/settings.php:935 src/Model/Event.php:378 -msgid "Sunday" -msgstr "Sunnuntai" - -#: include/text.php:1097 src/Model/Event.php:399 -msgid "January" -msgstr "Tammikuu" - -#: include/text.php:1097 src/Model/Event.php:400 -msgid "February" -msgstr "Helmikuu" - -#: include/text.php:1097 src/Model/Event.php:401 -msgid "March" -msgstr "Maaliskuu" - -#: include/text.php:1097 src/Model/Event.php:402 -msgid "April" -msgstr "Huhtikuu" - -#: include/text.php:1097 include/text.php:1114 src/Model/Event.php:390 -#: src/Model/Event.php:403 -msgid "May" -msgstr "Toukokuu" - -#: include/text.php:1097 src/Model/Event.php:404 -msgid "June" -msgstr "Kesäkuu" - -#: include/text.php:1097 src/Model/Event.php:405 -msgid "July" -msgstr "Heinäkuu" - -#: include/text.php:1097 src/Model/Event.php:406 -msgid "August" -msgstr "Elokuu" - -#: include/text.php:1097 src/Model/Event.php:407 -msgid "September" -msgstr "Syyskuu" - -#: include/text.php:1097 src/Model/Event.php:408 -msgid "October" -msgstr "Lokakuu" - -#: include/text.php:1097 src/Model/Event.php:409 -msgid "November" -msgstr "Marraskuu" - -#: include/text.php:1097 src/Model/Event.php:410 -msgid "December" -msgstr "Joulukuu" - -#: include/text.php:1111 src/Model/Event.php:371 -msgid "Mon" -msgstr "Ma" - -#: include/text.php:1111 src/Model/Event.php:372 -msgid "Tue" -msgstr "Ti" - -#: include/text.php:1111 src/Model/Event.php:373 -msgid "Wed" -msgstr "Ke" - -#: include/text.php:1111 src/Model/Event.php:374 -msgid "Thu" -msgstr "To" - -#: include/text.php:1111 src/Model/Event.php:375 -msgid "Fri" -msgstr "Pe" - -#: include/text.php:1111 src/Model/Event.php:376 -msgid "Sat" -msgstr "La" - -#: include/text.php:1111 src/Model/Event.php:370 -msgid "Sun" -msgstr "Su" - -#: include/text.php:1114 src/Model/Event.php:386 -msgid "Jan" -msgstr "Tam." - -#: include/text.php:1114 src/Model/Event.php:387 -msgid "Feb" -msgstr "Hel." - -#: include/text.php:1114 src/Model/Event.php:388 -msgid "Mar" -msgstr "Maa." - -#: include/text.php:1114 src/Model/Event.php:389 -msgid "Apr" -msgstr "Huh." - -#: include/text.php:1114 src/Model/Event.php:392 -msgid "Jul" -msgstr "Tou." - -#: include/text.php:1114 src/Model/Event.php:393 -msgid "Aug" -msgstr "Elo." - -#: include/text.php:1114 -msgid "Sep" -msgstr "Syy." - -#: include/text.php:1114 src/Model/Event.php:395 -msgid "Oct" -msgstr "Lok." - -#: include/text.php:1114 src/Model/Event.php:396 -msgid "Nov" -msgstr "Mar." - -#: include/text.php:1114 src/Model/Event.php:397 -msgid "Dec" -msgstr "Jou." - -#: include/text.php:1254 -#, php-format -msgid "Content warning: %s" -msgstr "Sisältövaroitus: %s" - -#: include/text.php:1324 mod/videos.php:380 -msgid "View Video" -msgstr "Katso video" - -#: include/text.php:1341 -msgid "bytes" -msgstr "tavua" - -#: include/text.php:1374 include/text.php:1385 include/text.php:1418 -msgid "Click to open/close" -msgstr "Klikkaa auki/kiinni" - -#: include/text.php:1533 -msgid "View on separate page" -msgstr "Katso erillisellä sivulla" - -#: include/text.php:1534 -msgid "view on separate page" -msgstr "katso erillisellä sivulla" - -#: include/text.php:1539 include/text.php:1546 src/Model/Event.php:594 -msgid "link to source" -msgstr "linkki lähteeseen" - -#: include/text.php:1753 -msgid "activity" -msgstr "toiminta" - -#: include/text.php:1755 src/Object/Post.php:437 src/Object/Post.php:449 -msgid "comment" -msgid_plural "comments" -msgstr[0] "kommentoi" -msgstr[1] "kommentoi" - -#: include/text.php:1758 -msgid "post" -msgstr "julkaisu" - -#: include/text.php:1916 -msgid "Item filed" -msgstr "Kohde arkistoitu" - -#: mod/allfriends.php:51 -msgid "No friends to display." -msgstr "Ei näytettäviä kavereita." - -#: mod/allfriends.php:90 mod/suggest.php:101 mod/match.php:105 -#: mod/dirfind.php:215 src/Content/Widget.php:37 src/Model/Profile.php:293 -msgid "Connect" -msgstr "Yhdistä" - -#: mod/api.php:85 mod/api.php:107 -msgid "Authorize application connection" -msgstr "Vahvista sovellusyhteys" - -#: mod/api.php:86 -msgid "Return to your app and insert this Securty Code:" -msgstr "Palaa takaisin sovellukseen ja lisää tämä turvakoodi:" - -#: mod/api.php:95 -msgid "Please login to continue." -msgstr "Ole hyvä ja kirjaudu jatkaaksesi." - -#: mod/api.php:109 -msgid "" -"Do you want to authorize this application to access your posts and contacts," -" and/or create new posts for you?" -msgstr "Haluatko antaa tälle sovellukselle luvan hakea viestejäsi ja yhteystietojasi ja/tai luoda uusia viestejä?" - -#: mod/api.php:111 mod/follow.php:150 mod/dfrn_request.php:648 -#: mod/profiles.php:543 mod/profiles.php:547 mod/profiles.php:568 -#: mod/register.php:239 mod/settings.php:1094 mod/settings.php:1100 -#: mod/settings.php:1107 mod/settings.php:1111 mod/settings.php:1115 -#: mod/settings.php:1119 mod/settings.php:1123 mod/settings.php:1127 -#: mod/settings.php:1147 mod/settings.php:1148 mod/settings.php:1149 -#: mod/settings.php:1150 mod/settings.php:1151 -msgid "No" -msgstr "Ei" - -#: mod/apps.php:14 index.php:265 -msgid "You must be logged in to use addons. " -msgstr "Sinun pitää kirjautua sisään, jotta voit käyttää lisäosia" - -#: mod/apps.php:19 -msgid "Applications" -msgstr "Sovellukset" - -#: mod/apps.php:22 -msgid "No installed applications." -msgstr "Ei asennettuja sovelluksia." - -#: mod/attach.php:15 -msgid "Item not available." -msgstr "Kohde ei saatavilla." - -#: mod/attach.php:25 -msgid "Item was not found." -msgstr "Kohdetta ei löytynyt." - -#: mod/common.php:91 -msgid "No contacts in common." -msgstr "Ei yhteisiä kontakteja." - -#: mod/common.php:140 mod/contacts.php:886 -msgid "Common Friends" -msgstr "Yhteisiä kavereita" - -#: mod/credits.php:18 -msgid "Credits" -msgstr "Lopputekstit" - -#: mod/credits.php:19 -msgid "" -"Friendica is a community project, that would not be possible without the " -"help of many people. Here is a list of those who have contributed to the " -"code or the translation of Friendica. Thank you all!" -msgstr "" - -#: mod/fbrowser.php:34 view/theme/frio/theme.php:261 src/Content/Nav.php:102 -#: src/Model/Profile.php:902 -msgid "Photos" -msgstr "Kuvat" - -#: mod/fbrowser.php:43 mod/fbrowser.php:68 mod/photos.php:194 -#: mod/photos.php:1050 mod/photos.php:1137 mod/photos.php:1154 -#: mod/photos.php:1653 mod/photos.php:1667 src/Model/Photo.php:244 -#: src/Model/Photo.php:253 -msgid "Contact Photos" -msgstr "Kontaktin valokuvat" - -#: mod/fbrowser.php:105 mod/fbrowser.php:136 mod/profile_photo.php:250 -msgid "Upload" -msgstr "Lähetä" - -#: mod/fbrowser.php:131 -msgid "Files" -msgstr "Tiedostot" - -#: mod/fetch.php:16 mod/fetch.php:52 mod/fetch.php:65 mod/p.php:21 -#: mod/p.php:48 mod/p.php:57 mod/help.php:60 index.php:312 -msgid "Not Found" -msgstr "Ei löydetty" - -#: mod/hcard.php:18 -msgid "No profile" -msgstr "Ei profiilia" - -#: mod/home.php:39 -#, php-format -msgid "Welcome to %s" -msgstr "Tervetuloa %s" - -#: mod/lockview.php:38 mod/lockview.php:46 -msgid "Remote privacy information not available." -msgstr "Yksityisyyden etätietoja ei saatavilla." - -#: mod/lockview.php:55 -msgid "Visible to:" -msgstr "Näkyvissä:" - -#: mod/maintenance.php:24 -msgid "System down for maintenance" -msgstr "Järjestelmä poiskytketty huoltoa varten" - -#: mod/newmember.php:11 -msgid "Welcome to Friendica" -msgstr "Tervetuloa Friendicaan" - -#: mod/newmember.php:12 -msgid "New Member Checklist" -msgstr "Uuden jäsenen tarkistuslista" - -#: mod/newmember.php:14 -msgid "" -"We would like to offer some tips and links to help make your experience " -"enjoyable. Click any item to visit the relevant page. A link to this page " -"will be visible from your home page for two weeks after your initial " -"registration and then will quietly disappear." -msgstr "" - -#: mod/newmember.php:15 -msgid "Getting Started" -msgstr "Ensiaskeleet" - -#: mod/newmember.php:17 -msgid "Friendica Walk-Through" -msgstr "Friendica -läpikäynti" - -#: mod/newmember.php:17 -msgid "" -"On your Quick Start page - find a brief introduction to your " -"profile and network tabs, make some new connections, and find some groups to" -" join." -msgstr "" - -#: mod/newmember.php:19 mod/admin.php:1940 mod/admin.php:2210 -#: mod/settings.php:124 view/theme/frio/theme.php:269 src/Content/Nav.php:207 -msgid "Settings" -msgstr "Asetukset" - -#: mod/newmember.php:21 -msgid "Go to Your Settings" -msgstr "Omat Asetukset" - -#: mod/newmember.php:21 -msgid "" -"On your Settings page - change your initial password. Also make a " -"note of your Identity Address. This looks just like an email address - and " -"will be useful in making friends on the free social web." -msgstr "" - -#: mod/newmember.php:22 -msgid "" -"Review the other settings, particularly the privacy settings. An unpublished" -" directory listing is like having an unlisted phone number. In general, you " -"should probably publish your listing - unless all of your friends and " -"potential friends know exactly how to find you." -msgstr "" - -#: mod/newmember.php:24 mod/profperm.php:113 mod/contacts.php:671 -#: mod/contacts.php:863 view/theme/frio/theme.php:260 src/Content/Nav.php:101 -#: src/Model/Profile.php:728 src/Model/Profile.php:861 -#: src/Model/Profile.php:894 -msgid "Profile" -msgstr "Profiili" - -#: mod/newmember.php:26 mod/profile_photo.php:249 mod/profiles.php:598 -msgid "Upload Profile Photo" -msgstr "Lataa profiilikuva" - -#: mod/newmember.php:26 -msgid "" -"Upload a profile photo if you have not done so already. Studies have shown " -"that people with real photos of themselves are ten times more likely to make" -" friends than people who do not." -msgstr "" - -#: mod/newmember.php:27 -msgid "Edit Your Profile" -msgstr "Muokkaa profiilisi" - -#: mod/newmember.php:27 -msgid "" -"Edit your default profile to your liking. Review the " -"settings for hiding your list of friends and hiding the profile from unknown" -" visitors." -msgstr "" - -#: mod/newmember.php:28 -msgid "Profile Keywords" -msgstr "Profiilin avainsanat" - -#: mod/newmember.php:28 -msgid "" -"Set some public keywords for your default profile which describe your " -"interests. We may be able to find other people with similar interests and " -"suggest friendships." -msgstr "" - -#: mod/newmember.php:30 -msgid "Connecting" -msgstr "Yhdistetään" - -#: mod/newmember.php:36 -msgid "Importing Emails" -msgstr "Sähköpostin tuominen" - -#: mod/newmember.php:36 -msgid "" -"Enter your email access information on your Connector Settings page if you " -"wish to import and interact with friends or mailing lists from your email " -"INBOX" -msgstr "" - -#: mod/newmember.php:39 -msgid "Go to Your Contacts Page" -msgstr "Näytä minun kontaktit" - -#: mod/newmember.php:39 -msgid "" -"Your Contacts page is your gateway to managing friendships and connecting " -"with friends on other networks. Typically you enter their address or site " -"URL in the Add New Contact dialog." -msgstr "" - -#: mod/newmember.php:40 -msgid "Go to Your Site's Directory" -msgstr "Näytä oman sivuston luettelo" - -#: mod/newmember.php:40 -msgid "" -"The Directory page lets you find other people in this network or other " -"federated sites. Look for a Connect or Follow link on " -"their profile page. Provide your own Identity Address if requested." -msgstr "" - -#: mod/newmember.php:41 -msgid "Finding New People" -msgstr "Kavereiden hankkiminen" - -#: mod/newmember.php:41 -msgid "" -"On the side panel of the Contacts page are several tools to find new " -"friends. We can match people by interest, look up people by name or " -"interest, and provide suggestions based on network relationships. On a brand" -" new site, friend suggestions will usually begin to be populated within 24 " -"hours." -msgstr "" - -#: mod/newmember.php:43 src/Model/Group.php:414 -msgid "Groups" -msgstr "Ryhmät" - -#: mod/newmember.php:45 -msgid "Group Your Contacts" -msgstr "Järjestä kontaktit ryhmiin" - -#: mod/newmember.php:45 -msgid "" -"Once you have made some friends, organize them into private conversation " -"groups from the sidebar of your Contacts page and then you can interact with" -" each group privately on your Network page." -msgstr "" - -#: mod/newmember.php:48 -msgid "Why Aren't My Posts Public?" -msgstr "Miksi julkaisuni eivät ole julkisia?" - -#: mod/newmember.php:48 -msgid "" -"Friendica respects your privacy. By default, your posts will only show up to" -" people you've added as friends. For more information, see the help section " -"from the link above." -msgstr "" - -#: mod/newmember.php:52 -msgid "Getting Help" -msgstr "Avun saaminen" - -#: mod/newmember.php:54 -msgid "Go to the Help Section" -msgstr "Näytä ohjeet" - -#: mod/newmember.php:54 -msgid "" -"Our help pages may be consulted for detail on other program" -" features and resources." -msgstr "" - -#: mod/nogroup.php:42 mod/viewcontacts.php:112 mod/contacts.php:619 -#: mod/contacts.php:959 -#, php-format -msgid "Visit %s's profile [%s]" -msgstr "Näytä %s-käyttäjän profiili [%s]" - -#: mod/nogroup.php:43 mod/contacts.php:960 -msgid "Edit contact" -msgstr "Muokkaa kontaktia" - -#: mod/nogroup.php:63 -msgid "Contacts who are not members of a group" -msgstr "Kontaktit jotka eivät kuulu ryhmään" - -#: mod/p.php:14 -msgid "Not Extended" -msgstr "Ei laajennettu" - -#: mod/repair_ostatus.php:18 -msgid "Resubscribing to OStatus contacts" -msgstr "OStatus -kontaktien uudelleentilaus" - -#: mod/repair_ostatus.php:34 -msgid "Error" -msgstr "Virhe" - -#: mod/repair_ostatus.php:48 mod/ostatus_subscribe.php:64 -msgid "Done" -msgstr "Valmis" - -#: mod/repair_ostatus.php:54 mod/ostatus_subscribe.php:88 -msgid "Keep this window open until done." -msgstr "Pidä tämä ikkuna auki kunnes kaikki tehtävät on suoritettu." - -#: mod/suggest.php:36 -msgid "Do you really want to delete this suggestion?" -msgstr "Haluatko varmasti poistaa ehdotuksen?" - -#: mod/suggest.php:73 -msgid "" -"No suggestions available. If this is a new site, please try again in 24 " -"hours." -msgstr "Ehdotuksia ei löydy. Jos tämä on uusi sivusto, kokeile uudelleen vuorokauden kuluttua." - -#: mod/suggest.php:84 mod/suggest.php:104 -msgid "Ignore/Hide" -msgstr "Jätä huomiotta/piilota" - -#: mod/suggest.php:114 view/theme/vier/theme.php:204 src/Content/Widget.php:64 -msgid "Friend Suggestions" -msgstr "Ystäväehdotukset" - -#: mod/uimport.php:55 mod/register.php:192 -msgid "" -"This site has exceeded the number of allowed daily account registrations. " -"Please try again tomorrow." -msgstr "Sivuston päivittäinen rekisteröintiraja ylitetty. Yritä uudelleen huomenna." - -#: mod/uimport.php:70 mod/register.php:288 -msgid "Import" -msgstr "Tuo" - -#: mod/uimport.php:72 -msgid "Move account" -msgstr "Siirrä tili" - -#: mod/uimport.php:73 -msgid "You can import an account from another Friendica server." -msgstr "Voit tuoda käyttäjätilin toiselta Friendica -palvelimelta." - -#: mod/uimport.php:74 -msgid "" -"You need to export your account from the old server and upload it here. We " -"will recreate your old account here with all your contacts. We will try also" -" to inform your friends that you moved here." -msgstr "" - -#: mod/uimport.php:75 -msgid "" -"This feature is experimental. We can't import contacts from the OStatus " -"network (GNU Social/Statusnet) or from Diaspora" -msgstr "Tämä on kokeellinen ominaisuus. Emme voi tuoda kontakteja OStatus-verkolta (GNU social/Statusnet) tai Diasporalta." - -#: mod/uimport.php:76 -msgid "Account file" -msgstr "Tilitiedosto" - -#: mod/uimport.php:76 -msgid "" -"To export your account, go to \"Settings->Export your personal data\" and " -"select \"Export account\"" -msgstr "" - -#: mod/match.php:48 -msgid "No keywords to match. Please add keywords to your default profile." -msgstr "Avainsanat puuttuu. Lisää avainsanoja oletusprofiiliisi." - -#: mod/match.php:104 -msgid "is interested in:" -msgstr "on kiinnostunut seuraavista aiheista:" - -#: mod/match.php:120 -msgid "Profile Match" -msgstr "Vastaavien profiilien haku" - -#: mod/match.php:125 mod/dirfind.php:253 -msgid "No matches" -msgstr "Ei täsmääviä profiileja" - -#: mod/manage.php:180 -msgid "Manage Identities and/or Pages" -msgstr "Hallitse identiteetit ja/tai sivut" - -#: mod/manage.php:181 -msgid "" -"Toggle between different identities or community/group pages which share " -"your account details or which you have been granted \"manage\" permissions" -msgstr "" - -#: mod/manage.php:182 -msgid "Select an identity to manage: " -msgstr "Valitse identiteetti hallitavaksi:" - -#: mod/manage.php:184 mod/localtime.php:56 mod/poke.php:199 -#: mod/fsuggest.php:114 mod/contacts.php:610 mod/invite.php:154 -#: mod/crepair.php:148 mod/install.php:198 mod/install.php:237 -#: mod/message.php:246 mod/message.php:413 mod/events.php:531 -#: mod/photos.php:1068 mod/photos.php:1148 mod/photos.php:1439 -#: mod/photos.php:1485 mod/photos.php:1524 mod/photos.php:1597 -#: mod/profiles.php:579 view/theme/duepuntozero/config.php:71 -#: view/theme/frio/config.php:118 view/theme/quattro/config.php:73 -#: view/theme/vier/config.php:119 src/Object/Post.php:804 -msgid "Submit" -msgstr "Lähetä" - -#: mod/wall_attach.php:24 mod/wall_attach.php:32 mod/wall_attach.php:83 -#: mod/wall_upload.php:38 mod/wall_upload.php:54 mod/wall_upload.php:112 -#: mod/wall_upload.php:155 mod/wall_upload.php:158 -msgid "Invalid request." -msgstr "Virheellinen pyyntö." - -#: mod/wall_attach.php:101 -msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" -msgstr "" - -#: mod/wall_attach.php:101 -msgid "Or - did you try to upload an empty file?" -msgstr "Yrititkö ladata tyhjän tiedoston?" - -#: mod/wall_attach.php:112 -#, php-format -msgid "File exceeds size limit of %s" -msgstr "Tiedosto ylittää kokorajoituksen %s" - -#: mod/wall_attach.php:136 mod/wall_attach.php:152 -msgid "File upload failed." -msgstr "Tiedoston lähettäminen epäonnistui." - -#: mod/filer.php:34 -msgid "- select -" -msgstr "- valitse -" - -#: mod/localtime.php:19 src/Model/Event.php:36 src/Model/Event.php:814 -msgid "l F d, Y \\@ g:i A" -msgstr "l j.n.Y \\@ H:i" - -#: mod/localtime.php:33 -msgid "Time Conversion" -msgstr "Aikamuunnos" - -#: mod/localtime.php:35 -msgid "" -"Friendica provides this service for sharing events with other networks and " -"friends in unknown timezones." -msgstr "" - -#: mod/localtime.php:39 -#, php-format -msgid "UTC time: %s" -msgstr "UTC-aika: %s" - -#: mod/localtime.php:42 -#, php-format -msgid "Current timezone: %s" -msgstr "Aikavyöhyke: %s" - -#: mod/localtime.php:46 -#, php-format -msgid "Converted localtime: %s" -msgstr "Muunnettu paikallisaika: %s" - -#: mod/localtime.php:52 -msgid "Please select your timezone:" -msgstr "Valitse aikavyöhykkeesi:" - -#: mod/notify.php:77 -msgid "No more system notifications." -msgstr "Ei enää järjestelmäilmoituksia." - -#: mod/notify.php:81 mod/notifications.php:113 -msgid "System Notifications" -msgstr "Järjestelmäilmoitukset" - -#: mod/ping.php:292 -msgid "{0} wants to be your friend" -msgstr "{0} lähetti kaveripyynnön" - -#: mod/ping.php:307 -msgid "{0} sent you a message" -msgstr "{0} lähetti sinulle viestin" - -#: mod/ping.php:322 -msgid "{0} requested registration" -msgstr "{0} jätti rekisteröintipyynnön" - -#: mod/poke.php:192 -msgid "Poke/Prod" -msgstr "Tökkää" - -#: mod/poke.php:193 -msgid "poke, prod or do other things to somebody" -msgstr "" - -#: mod/poke.php:194 -msgid "Recipient" -msgstr "Vastaanottaja" - -#: mod/poke.php:195 -msgid "Choose what you wish to do to recipient" -msgstr "Valitse mitä haluat tehdä vastaanottajalle" - -#: mod/poke.php:198 -msgid "Make this post private" -msgstr "Muuta julkaisu yksityiseksi" - -#: mod/probe.php:13 mod/viewcontacts.php:45 mod/webfinger.php:16 -#: mod/directory.php:42 mod/community.php:27 mod/dfrn_request.php:602 -#: mod/display.php:203 mod/photos.php:920 mod/search.php:98 mod/search.php:104 -#: mod/videos.php:199 -msgid "Public access denied." -msgstr "Julkinen käyttö estetty." - -#: mod/probe.php:14 mod/webfinger.php:17 -msgid "Only logged in users are permitted to perform a probing." -msgstr "" - -#: mod/profperm.php:28 mod/group.php:83 index.php:435 -msgid "Permission denied" -msgstr "Käyttöoikeus evätty" - -#: mod/profperm.php:34 mod/profperm.php:65 -msgid "Invalid profile identifier." -msgstr "Virheellinen profiilitunniste." - -#: mod/profperm.php:111 -msgid "Profile Visibility Editor" -msgstr "Profiilin näkyvyyden muokkaaminen" - -#: mod/profperm.php:115 mod/group.php:265 -msgid "Click on a contact to add or remove." -msgstr "Valitse kontakti, jota haluat poistaa tai lisätä." - -#: mod/profperm.php:124 -msgid "Visible To" -msgstr "Näkyvyys" - -#: mod/profperm.php:140 -msgid "All Contacts (with secure profile access)" -msgstr "" - -#: mod/regmod.php:68 -msgid "Account approved." -msgstr "Tili hyväksytty." - -#: mod/regmod.php:93 -#, php-format -msgid "Registration revoked for %s" -msgstr "" - -#: mod/regmod.php:102 -msgid "Please login." -msgstr "Ole hyvä ja kirjaudu." - -#: mod/tagrm.php:47 -msgid "Tag removed" -msgstr "Tägi poistettiin" - -#: mod/tagrm.php:85 -msgid "Remove Item Tag" -msgstr "Poista tägi" - -#: mod/tagrm.php:87 -msgid "Select a tag to remove: " -msgstr "Valitse tägi poistamista varten:" - -#: mod/tagrm.php:98 mod/delegate.php:177 -msgid "Remove" -msgstr "Poista" - -#: mod/uexport.php:44 -msgid "Export account" -msgstr "Vie tili" - -#: mod/uexport.php:44 -msgid "" -"Export your account info and contacts. Use this to make a backup of your " -"account and/or to move it to another server." -msgstr "Vie tilin tiedot ja yhteystiedot. Käytä tätä tilisi varmuuskopiointiin ja/tai siirtämiseen toiselle palvelimelle." - -#: mod/uexport.php:45 -msgid "Export all" -msgstr "Vie kaikki" - -#: mod/uexport.php:45 -msgid "" -"Export your accout info, contacts and all your items as json. Could be a " -"very big file, and could take a lot of time. Use this to make a full backup " -"of your account (photos are not exported)" -msgstr "Vie tilin tiedot, yhteystiedot ja kaikki nimikkeesi json-muodossa. Saattaa luoda hyvin suuren tiedoston ja kestää todella pitkään. Tämän avulla voit ottaa täydellisen varmuuskopion tilistäsi (valokuvia ei viedä)" - -#: mod/uexport.php:52 mod/settings.php:108 -msgid "Export personal data" -msgstr "Vie henkilökohtaiset tiedot" - -#: mod/viewcontacts.php:87 -msgid "No contacts." -msgstr "Ei kontakteja." - -#: mod/viewsrc.php:12 mod/community.php:34 -msgid "Access denied." -msgstr "Käyttö estetty." - -#: mod/wall_upload.php:186 mod/profile_photo.php:153 mod/photos.php:751 -#: mod/photos.php:754 mod/photos.php:783 -#, php-format -msgid "Image exceeds size limit of %s" -msgstr "Kuva ylittää kokorajoituksen %s" - -#: mod/wall_upload.php:200 mod/profile_photo.php:162 mod/photos.php:806 -msgid "Unable to process image." -msgstr "Kuvan käsitteleminen epäonnistui." - -#: mod/wall_upload.php:231 mod/item.php:471 src/Object/Image.php:953 -#: src/Object/Image.php:969 src/Object/Image.php:977 src/Object/Image.php:1002 -msgid "Wall Photos" -msgstr "Seinäkuvat" - -#: mod/wall_upload.php:239 mod/profile_photo.php:307 mod/photos.php:835 -msgid "Image upload failed." -msgstr "Kuvan lähettäminen epäonnistui." - -#: mod/wallmessage.php:49 mod/wallmessage.php:112 -#, php-format -msgid "Number of daily wall messages for %s exceeded. Message failed." -msgstr "%s-käyttäjän päivittäinen seinäviestiraja ylitetty. Viestin lähettäminen epäonnistui." - -#: mod/wallmessage.php:57 mod/message.php:73 -msgid "No recipient selected." -msgstr "Vastaanottaja puuttuu." - -#: mod/wallmessage.php:60 -msgid "Unable to check your home location." -msgstr "Kotisijaintisi ei voitu tarkistaa." - -#: mod/wallmessage.php:63 mod/message.php:80 -msgid "Message could not be sent." -msgstr "Viestiä ei voitu lähettää." - -#: mod/wallmessage.php:66 mod/message.php:83 -msgid "Message collection failure." -msgstr "Viestin noutaminen epäonnistui." - -#: mod/wallmessage.php:69 mod/message.php:86 -msgid "Message sent." -msgstr "Viesti lähetetty." - -#: mod/wallmessage.php:86 mod/wallmessage.php:95 -msgid "No recipient." -msgstr "Vastaanottaja puuttuu." - -#: mod/wallmessage.php:132 mod/message.php:231 -msgid "Send Private Message" -msgstr "Lähetä yksityisviesti" - -#: mod/wallmessage.php:133 -#, php-format -msgid "" -"If you wish for %s to respond, please check that the privacy settings on " -"your site allow private mail from unknown senders." -msgstr "" - -#: mod/wallmessage.php:134 mod/message.php:232 mod/message.php:402 -msgid "To:" -msgstr "Vastaanottaja:" - -#: mod/wallmessage.php:135 mod/message.php:236 mod/message.php:404 -msgid "Subject:" -msgstr "Aihe:" - -#: mod/wallmessage.php:141 mod/invite.php:149 mod/message.php:240 -#: mod/message.php:407 -msgid "Your message:" -msgstr "Viestisi:" - -#: mod/bookmarklet.php:23 src/Content/Nav.php:114 src/Module/Login.php:313 -msgid "Login" -msgstr "Kirjaudu sisään" - -#: mod/bookmarklet.php:51 -msgid "The post was created" -msgstr "Julkaisu luotu" - -#: mod/editpost.php:25 mod/editpost.php:35 -msgid "Item not found" -msgstr "Kohdetta ei löytynyt" - -#: mod/editpost.php:42 -msgid "Edit post" -msgstr "Muokkaa viestiä" - -#: mod/editpost.php:134 src/Core/ACL.php:315 -msgid "CC: email addresses" -msgstr "Kopio: sähköpostiosoitteet" - -#: mod/editpost.php:141 src/Core/ACL.php:316 -msgid "Example: bob@example.com, mary@example.com" -msgstr "Esimerkki: bob@example.com, mary@example.com" - -#: mod/fsuggest.php:30 mod/fsuggest.php:96 mod/crepair.php:110 -#: mod/dfrn_confirm.php:129 -msgid "Contact not found." -msgstr "Kontaktia ei ole." - -#: mod/fsuggest.php:72 -msgid "Friend suggestion sent." -msgstr "Ystäväehdotus lähetettiin." - -#: mod/fsuggest.php:101 -msgid "Suggest Friends" -msgstr "Ehdota ystäviä" - -#: mod/fsuggest.php:103 -#, php-format -msgid "Suggest a friend for %s" -msgstr "Ehdota ystävää ystävälle %s" - -#: mod/cal.php:142 mod/display.php:316 mod/profile.php:174 -msgid "Access to this profile has been restricted." -msgstr "Pääsy tähän profiiliin on rajoitettu" - -#: mod/cal.php:274 mod/events.php:391 view/theme/frio/theme.php:263 -#: view/theme/frio/theme.php:267 src/Content/Nav.php:104 -#: src/Content/Nav.php:170 src/Model/Profile.php:922 src/Model/Profile.php:933 -msgid "Events" -msgstr "Tapahtumat" - -#: mod/cal.php:275 mod/events.php:392 -msgid "View" -msgstr "Katso" - -#: mod/cal.php:276 mod/events.php:394 -msgid "Previous" -msgstr "Edellinen" - -#: mod/cal.php:277 mod/install.php:156 mod/events.php:395 -msgid "Next" -msgstr "Seuraava" - -#: mod/cal.php:280 mod/events.php:400 src/Model/Event.php:412 -msgid "today" -msgstr "tänään" - -#: mod/cal.php:281 mod/events.php:401 src/Util/Temporal.php:304 -#: src/Model/Event.php:413 -msgid "month" -msgstr "kuukausi" - -#: mod/cal.php:282 mod/events.php:402 src/Util/Temporal.php:305 -#: src/Model/Event.php:414 -msgid "week" -msgstr "viikko" - -#: mod/cal.php:283 mod/events.php:403 src/Util/Temporal.php:306 -#: src/Model/Event.php:415 -msgid "day" -msgstr "päivä" - -#: mod/cal.php:284 mod/events.php:404 -msgid "list" -msgstr "luettelo" - -#: mod/cal.php:297 src/Core/Console/NewPassword.php:73 src/Model/User.php:214 -msgid "User not found" -msgstr "Käyttäjää ei löydy" - -#: mod/cal.php:313 -msgid "This calendar format is not supported" -msgstr "Tätä kalenteriformaattia ei tueta" - -#: mod/cal.php:315 -msgid "No exportable data found" -msgstr "Vientikelpoista dataa ei löytynyt" - -#: mod/cal.php:332 -msgid "calendar" -msgstr "kalenteri" - -#: mod/contacts.php:71 mod/notifications.php:259 src/Model/Profile.php:516 -msgid "Network:" -msgstr "Uutisvirta:" - -#: mod/contacts.php:157 -#, php-format -msgid "%d contact edited." -msgid_plural "%d contacts edited." -msgstr[0] "%d kontakti muokattu" -msgstr[1] "%d kontakteja muokattu" - -#: mod/contacts.php:184 mod/contacts.php:400 -msgid "Could not access contact record." -msgstr "Yhteystietoon ei päästä käsiksi." - -#: mod/contacts.php:194 -msgid "Could not locate selected profile." -msgstr "Valittua profiilia ei löydy." - -#: mod/contacts.php:228 -msgid "Contact updated." -msgstr "Yhteystietopäivitys onnistui." - -#: mod/contacts.php:230 mod/dfrn_request.php:415 -msgid "Failed to update contact record." -msgstr "Kontaktitietojen päivitys epäonnistui." - -#: mod/contacts.php:421 -msgid "Contact has been blocked" -msgstr "Henkilö on estetty" - -#: mod/contacts.php:421 -msgid "Contact has been unblocked" -msgstr "Henkilö on jälleen sallittu" - -#: mod/contacts.php:432 -msgid "Contact has been ignored" -msgstr "Henkilöä ei enää huomioida" - -#: mod/contacts.php:432 -msgid "Contact has been unignored" -msgstr "Henkilö on jälleen huomioituna." - -#: mod/contacts.php:443 -msgid "Contact has been archived" -msgstr "Henkilö on arkistoitu." - -#: mod/contacts.php:443 -msgid "Contact has been unarchived" -msgstr "Henkilö on otettu pois arkistosta." - -#: mod/contacts.php:467 -msgid "Drop contact" -msgstr "Poista kontakti" - -#: mod/contacts.php:470 mod/contacts.php:823 -msgid "Do you really want to delete this contact?" -msgstr "Haluatko todella poistaa tämän yhteystiedon?" - -#: mod/contacts.php:488 -msgid "Contact has been removed." -msgstr "Yhteystieto on poistettu." - -#: mod/contacts.php:519 -#, php-format -msgid "You are mutual friends with %s" -msgstr "Olet kaveri %s kanssa." - -#: mod/contacts.php:523 -#, php-format -msgid "You are sharing with %s" -msgstr "Olet jakanut jotakin %s:n kanssa" - -#: mod/contacts.php:527 -#, php-format -msgid "%s is sharing with you" -msgstr "%s jakaa sinulle jotakin." - -#: mod/contacts.php:547 -msgid "Private communications are not available for this contact." -msgstr "Yksityiskeskustelu ei ole käytettävissä tälle henkilölle." - -#: mod/contacts.php:549 -msgid "Never" -msgstr "Ei koskaan" - -#: mod/contacts.php:552 -msgid "(Update was successful)" -msgstr "(Päivitys onnistui)" - -#: mod/contacts.php:552 -msgid "(Update was not successful)" -msgstr "(Päivitys epäonnistui)" - -#: mod/contacts.php:554 mod/contacts.php:992 -msgid "Suggest friends" -msgstr "Ehdota ystäviä" - -#: mod/contacts.php:558 -#, php-format -msgid "Network type: %s" -msgstr "Verkkotyyppi: %s" - -#: mod/contacts.php:563 -msgid "Communications lost with this contact!" -msgstr "Yhteys tähän henkilöön menetettiin!" - -#: mod/contacts.php:569 -msgid "Fetch further information for feeds" -msgstr "" - -#: mod/contacts.php:571 -msgid "" -"Fetch information like preview pictures, title and teaser from the feed " -"item. You can activate this if the feed doesn't contain much text. Keywords " -"are taken from the meta header in the feed item and are posted as hash tags." -msgstr "" - -#: mod/contacts.php:572 mod/admin.php:1284 mod/admin.php:1449 -#: mod/admin.php:1459 -msgid "Disabled" -msgstr "Pois käytöstä" - -#: mod/contacts.php:573 -msgid "Fetch information" -msgstr "Nouda tiedot" - -#: mod/contacts.php:574 -msgid "Fetch keywords" -msgstr "Nouda avainsanat" - -#: mod/contacts.php:575 -msgid "Fetch information and keywords" -msgstr "Nouda tiedot ja avainsanat" - -#: mod/contacts.php:599 mod/unfollow.php:100 -msgid "Disconnect/Unfollow" -msgstr "Katkaise / Lopeta seuraaminen" - -#: mod/contacts.php:608 -msgid "Contact" -msgstr "Kontakti" - -#: mod/contacts.php:611 -msgid "Profile Visibility" -msgstr "Profiilin näkyvyys" - -#: mod/contacts.php:612 -#, php-format -msgid "" -"Please choose the profile you would like to display to %s when viewing your " -"profile securely." -msgstr "Valitse profiili, jonka haluat näyttää %s:lle, kun hän haluaa katsoa profiiliasi turvallisesti." - -#: mod/contacts.php:613 -msgid "Contact Information / Notes" -msgstr "Yhteystiedot / Muistiinpanot" - -#: mod/contacts.php:614 -msgid "Their personal note" -msgstr "" - -#: mod/contacts.php:616 -msgid "Edit contact notes" -msgstr "Muokkaa yhteystietojen muistiinpanoja" - -#: mod/contacts.php:620 -msgid "Block/Unblock contact" -msgstr "Estä/salli henkilö" - -#: mod/contacts.php:621 -msgid "Ignore contact" -msgstr "Jätä henkilö huomiotta" - -#: mod/contacts.php:622 -msgid "Repair URL settings" -msgstr "Korjaa URL-asetukset" - -#: mod/contacts.php:623 -msgid "View conversations" -msgstr "Katso keskusteluja" - -#: mod/contacts.php:628 -msgid "Last update:" -msgstr "Viimeksi päivitetty:" - -#: mod/contacts.php:630 -msgid "Update public posts" -msgstr "Päivitä julkiset postaukset" - -#: mod/contacts.php:632 mod/contacts.php:1002 -msgid "Update now" -msgstr "Päivitä nyt" - -#: mod/contacts.php:637 mod/contacts.php:827 mod/contacts.php:1011 -#: mod/admin.php:489 mod/admin.php:1834 -msgid "Unblock" -msgstr "Salli" - -#: mod/contacts.php:637 mod/contacts.php:827 mod/contacts.php:1011 -#: mod/admin.php:488 mod/admin.php:1833 -msgid "Block" -msgstr "Estä" - -#: mod/contacts.php:638 mod/contacts.php:828 mod/contacts.php:1019 -msgid "Unignore" -msgstr "Ota huomioon" - -#: mod/contacts.php:638 mod/contacts.php:828 mod/contacts.php:1019 -#: mod/notifications.php:62 mod/notifications.php:181 -#: mod/notifications.php:264 -msgid "Ignore" -msgstr "Jätä huomiotta" - -#: mod/contacts.php:642 -msgid "Currently blocked" -msgstr "Estetty tällä hetkellä" - -#: mod/contacts.php:643 -msgid "Currently ignored" -msgstr "Jätetty huomiotta tällä hetkellä" - -#: mod/contacts.php:644 -msgid "Currently archived" -msgstr "Arkistoitu tällä hetkellä" - -#: mod/contacts.php:645 -msgid "Awaiting connection acknowledge" -msgstr "Odotetaan yhteyden kuittausta" - -#: mod/contacts.php:646 mod/notifications.php:175 mod/notifications.php:253 -msgid "Hide this contact from others" -msgstr "Piilota kontakti muilta" - -#: mod/contacts.php:646 -msgid "" -"Replies/likes to your public posts may still be visible" -msgstr "" - -#: mod/contacts.php:647 -msgid "Notification for new posts" -msgstr "Uusien postausten ilmoitus" - -#: mod/contacts.php:647 -msgid "Send a notification of every new post of this contact" -msgstr "Lähetä ilmoitus tälle henkilölle kaikista uusista postauksista" - -#: mod/contacts.php:650 -msgid "Blacklisted keywords" -msgstr "Kielletyt avainsanat" - -#: mod/contacts.php:650 -msgid "" -"Comma separated list of keywords that should not be converted to hashtags, " -"when \"Fetch information and keywords\" is selected" -msgstr "" - -#: mod/contacts.php:656 mod/unfollow.php:122 mod/follow.php:166 -#: mod/admin.php:494 mod/admin.php:504 mod/notifications.php:256 -msgid "Profile URL" -msgstr "Profiilin URL" - -#: mod/contacts.php:660 mod/directory.php:148 mod/events.php:519 -#: mod/notifications.php:246 src/Model/Event.php:60 src/Model/Event.php:85 -#: src/Model/Event.php:421 src/Model/Event.php:900 src/Model/Profile.php:413 -msgid "Location:" -msgstr "Sijainti:" - -#: mod/contacts.php:662 src/Model/Profile.php:420 -msgid "XMPP:" -msgstr "XMPP:" - -#: mod/contacts.php:664 mod/directory.php:154 mod/notifications.php:248 -#: src/Model/Profile.php:419 src/Model/Profile.php:804 -msgid "About:" -msgstr "Lisätietoja:" - -#: mod/contacts.php:666 mod/follow.php:174 mod/notifications.php:250 -#: src/Model/Profile.php:792 -msgid "Tags:" -msgstr "Tunnisteet:" - -#: mod/contacts.php:667 -msgid "Actions" -msgstr "Toimenpiteet" - -#: mod/contacts.php:669 mod/contacts.php:855 view/theme/frio/theme.php:259 -#: src/Content/Nav.php:100 src/Model/Profile.php:886 -msgid "Status" -msgstr "Tila" - -#: mod/contacts.php:670 -msgid "Contact Settings" -msgstr "Yhteystietoasetukset" - -#: mod/contacts.php:711 -msgid "Suggestions" -msgstr "Ehdotukset" - -#: mod/contacts.php:714 -msgid "Suggest potential friends" -msgstr "Ehdota mahdollisille ystäville" - -#: mod/contacts.php:719 mod/group.php:215 -msgid "All Contacts" -msgstr "Kaikki yhteystiedot" - -#: mod/contacts.php:722 -msgid "Show all contacts" -msgstr "Näytä kaikki yhteystiedot" - -#: mod/contacts.php:727 -msgid "Unblocked" -msgstr "Sallittu" - -#: mod/contacts.php:730 -msgid "Only show unblocked contacts" -msgstr "Näytä vain sallitut henkilöt" - -#: mod/contacts.php:735 -msgid "Blocked" -msgstr "Estetty" - -#: mod/contacts.php:738 -msgid "Only show blocked contacts" -msgstr "Näytä vain estetyt henkilöt" - -#: mod/contacts.php:743 -msgid "Ignored" -msgstr "Jätetty huomiotta" - -#: mod/contacts.php:746 -msgid "Only show ignored contacts" -msgstr "Näytä vain henkilöt, jotka jätetty huomiotta" - -#: mod/contacts.php:751 -msgid "Archived" -msgstr "Arkistoitu" - -#: mod/contacts.php:754 -msgid "Only show archived contacts" -msgstr "Näytä vain arkistoidut henkilöt" - -#: mod/contacts.php:759 -msgid "Hidden" -msgstr "Piilotettu" - -#: mod/contacts.php:762 -msgid "Only show hidden contacts" -msgstr "Näytä vain piilotetut henkilöt" - -#: mod/contacts.php:818 -msgid "Search your contacts" -msgstr "Etsi henkilöitä" - -#: mod/contacts.php:819 mod/search.php:236 -#, php-format -msgid "Results for: %s" -msgstr "Tulokset haulla: %s" - -#: mod/contacts.php:820 mod/directory.php:209 view/theme/vier/theme.php:203 -#: src/Content/Widget.php:63 -msgid "Find" -msgstr "Etsi" - -#: mod/contacts.php:826 mod/settings.php:169 mod/settings.php:695 -msgid "Update" -msgstr "Päivitä" - -#: mod/contacts.php:829 mod/contacts.php:1027 -msgid "Archive" -msgstr "Arkistoi" - -#: mod/contacts.php:829 mod/contacts.php:1027 -msgid "Unarchive" -msgstr "Poista arkistosta" - -#: mod/contacts.php:832 -msgid "Batch Actions" -msgstr "" - -#: mod/contacts.php:858 mod/unfollow.php:132 mod/follow.php:186 -#: src/Model/Profile.php:889 -msgid "Status Messages and Posts" -msgstr "Statusviestit ja postaukset" - -#: mod/contacts.php:866 src/Model/Profile.php:897 -msgid "Profile Details" -msgstr "Profiilitiedot" - -#: mod/contacts.php:878 -msgid "View all contacts" -msgstr "Näytä kaikki kontaktit" - -#: mod/contacts.php:889 -msgid "View all common friends" -msgstr "Näytä kaikki yhteiset kaverit" - -#: mod/contacts.php:895 mod/admin.php:1362 mod/events.php:533 -#: src/Model/Profile.php:863 -msgid "Advanced" -msgstr "" - -#: mod/contacts.php:898 -msgid "Advanced Contact Settings" -msgstr "Kontakti-lisäasetukset" - -#: mod/contacts.php:930 -msgid "Mutual Friendship" -msgstr "Yhteinen kaveruus" - -#: mod/contacts.php:934 -msgid "is a fan of yours" -msgstr "on fanisi" - -#: mod/contacts.php:938 -msgid "you are a fan of" -msgstr "fanitat" - -#: mod/contacts.php:953 mod/photos.php:1482 mod/photos.php:1521 -#: mod/photos.php:1594 src/Object/Post.php:801 -msgid "This is you" -msgstr "Tämä olet sinä" - -#: mod/contacts.php:1013 -msgid "Toggle Blocked status" -msgstr "Estetty tila päälle/pois" - -#: mod/contacts.php:1021 -msgid "Toggle Ignored status" -msgstr "Sivuuta/seuraa" - -#: mod/contacts.php:1029 -msgid "Toggle Archive status" -msgstr "Arkistotila päälle/pois" - -#: mod/contacts.php:1037 -msgid "Delete contact" -msgstr "Poista kontakti" - -#: mod/delegate.php:37 -msgid "Parent user not found." -msgstr "" - -#: mod/delegate.php:144 -msgid "No parent user" -msgstr "" - -#: mod/delegate.php:159 -msgid "Parent Password:" -msgstr "" - -#: mod/delegate.php:159 -msgid "" -"Please enter the password of the parent account to legitimize your request." -msgstr "" - -#: mod/delegate.php:164 -msgid "Parent User" -msgstr "" - -#: mod/delegate.php:167 -msgid "" -"Parent users have total control about this account, including the account " -"settings. Please double check whom you give this access." -msgstr "" - -#: mod/delegate.php:168 mod/admin.php:311 mod/admin.php:1357 -#: mod/admin.php:1999 mod/admin.php:2253 mod/admin.php:2327 mod/admin.php:2474 -#: mod/settings.php:669 mod/settings.php:776 mod/settings.php:864 -#: mod/settings.php:953 mod/settings.php:1183 -msgid "Save Settings" -msgstr "Tallenna asetukset" - -#: mod/delegate.php:169 src/Content/Nav.php:205 -msgid "Delegate Page Management" -msgstr "Delegoi sivunhallinta" - -#: mod/delegate.php:170 -msgid "Delegates" -msgstr "Valtuutetut" - -#: mod/delegate.php:172 -msgid "" -"Delegates are able to manage all aspects of this account/page except for " -"basic account settings. Please do not delegate your personal account to " -"anybody that you do not trust completely." -msgstr "" - -#: mod/delegate.php:173 -msgid "Existing Page Delegates" -msgstr "Sivun valtuutetut" - -#: mod/delegate.php:175 -msgid "Potential Delegates" -msgstr "Mahdolliset valtuutetut" - -#: mod/delegate.php:178 -msgid "Add" -msgstr "Lisää" - -#: mod/delegate.php:179 -msgid "No entries." -msgstr "Ei kohteita." - -#: mod/feedtest.php:20 -msgid "You must be logged in to use this module" -msgstr "Sinun pitää kirjautua sisään, jotta voit käyttää tätä moduulia" - -#: mod/feedtest.php:48 -msgid "Source URL" -msgstr "Lähde URL" - -#: mod/oexchange.php:30 -msgid "Post successful." -msgstr "Viestin lähetys onnistui." - -#: mod/ostatus_subscribe.php:21 -msgid "Subscribing to OStatus contacts" -msgstr "OStatus -kontaktien tilaaminen" - -#: mod/ostatus_subscribe.php:33 -msgid "No contact provided." -msgstr "Kontakti puuttuu." - -#: mod/ostatus_subscribe.php:40 -msgid "Couldn't fetch information for contact." -msgstr "Kontaktin tietoja ei voitu hakea." - -#: mod/ostatus_subscribe.php:50 -msgid "Couldn't fetch friends for contact." -msgstr "Ei voitu hakea kontaktin kaverit." - -#: mod/ostatus_subscribe.php:78 -msgid "success" -msgstr "onnistui" - -#: mod/ostatus_subscribe.php:80 -msgid "failed" -msgstr "epäonnistui" - -#: mod/ostatus_subscribe.php:83 src/Object/Post.php:287 -msgid "ignored" -msgstr "ohitettu" - -#: mod/profile_photo.php:55 -msgid "Image uploaded but image cropping failed." -msgstr "Kuva ladattu mutta kuvan rajaus epäonnistui." - -#: mod/profile_photo.php:88 mod/profile_photo.php:96 mod/profile_photo.php:104 -#: mod/profile_photo.php:315 -#, php-format -msgid "Image size reduction [%s] failed." -msgstr "Kuvan pienentäminen [%s] epäonnistui." - -#: mod/profile_photo.php:125 -msgid "" -"Shift-reload the page or clear browser cache if the new photo does not " -"display immediately." -msgstr "Jos kuva ei näy heti, lataa sivu uudelleen tai tyhjennä selaimen välimuisti." - -#: mod/profile_photo.php:134 -msgid "Unable to process image" -msgstr "Kuvan käsitteleminen epäonnistui" - -#: mod/profile_photo.php:247 -msgid "Upload File:" -msgstr "Lähetä tiedosto:" - -#: mod/profile_photo.php:248 -msgid "Select a profile:" -msgstr "Valitse profiili:" - -#: mod/profile_photo.php:253 -msgid "or" -msgstr "tai" - -#: mod/profile_photo.php:253 -msgid "skip this step" -msgstr "ohita tämä vaihe" - -#: mod/profile_photo.php:253 -msgid "select a photo from your photo albums" -msgstr "valitse kuva albumeistasi" - -#: mod/profile_photo.php:266 -msgid "Crop Image" -msgstr "Rajaa kuva" - -#: mod/profile_photo.php:267 -msgid "Please adjust the image cropping for optimum viewing." -msgstr "Rajaa kuva sopivasti." - -#: mod/profile_photo.php:269 -msgid "Done Editing" -msgstr "Lopeta muokkaus" - -#: mod/profile_photo.php:305 -msgid "Image uploaded successfully." -msgstr "Kuvan lähettäminen onnistui." - -#: mod/unfollow.php:34 -msgid "Contact wasn't found or can't be unfollowed." -msgstr "" - -#: mod/unfollow.php:47 -msgid "Contact unfollowed" -msgstr "Kontaktia ei enää seurata" - -#: mod/unfollow.php:65 mod/follow.php:62 mod/dfrn_request.php:657 -msgid "Submit Request" -msgstr "Lähetä pyyntö" - -#: mod/unfollow.php:73 -msgid "You aren't a friend of this contact." -msgstr "Et ole kontaktin kaveri." - -#: mod/unfollow.php:79 -msgid "Unfollowing is currently not supported by your network." -msgstr "Seuraamisen lopettaminen ei tällä hetkellä tueta verkossasi." - -#: mod/unfollow.php:113 mod/follow.php:157 mod/dfrn_request.php:655 -msgid "Your Identity Address:" -msgstr "Identiteettisi osoite:" - -#: mod/directory.php:151 mod/notifications.php:252 src/Model/Profile.php:416 -#: src/Model/Profile.php:743 -msgid "Gender:" -msgstr "Sukupuoli:" - -#: mod/directory.php:152 src/Model/Profile.php:417 src/Model/Profile.php:767 -msgid "Status:" -msgstr "Tila:" - -#: mod/directory.php:153 src/Model/Profile.php:418 src/Model/Profile.php:784 -msgid "Homepage:" -msgstr "Kotisivu:" - -#: mod/directory.php:202 view/theme/vier/theme.php:208 -#: src/Content/Widget.php:68 -msgid "Global Directory" -msgstr "Maailmanlaajuinen hakemisto" - -#: mod/directory.php:204 -msgid "Find on this site" -msgstr "" - -#: mod/directory.php:206 -msgid "Results for:" -msgstr "Tulokset haulla:" - -#: mod/directory.php:208 -msgid "Site Directory" -msgstr "Sivuston luettelo" - -#: mod/directory.php:213 -msgid "No entries (some entries may be hidden)." -msgstr "" - -#: mod/dirfind.php:49 -#, php-format -msgid "People Search - %s" -msgstr "Käyttäjähaku - %s" - -#: mod/dirfind.php:60 -#, php-format -msgid "Forum Search - %s" -msgstr "Foorumihaku - %s" - -#: mod/follow.php:45 -msgid "The contact could not be added." -msgstr "Kontaktia ei voitu lisätä." - -#: mod/follow.php:73 -msgid "You already added this contact." -msgstr "Olet jo lisännyt tämän kontaktin." - -#: mod/follow.php:83 -msgid "Diaspora support isn't enabled. Contact can't be added." -msgstr "Diaspora -tuki ei ole käytössä. Kontaktia ei voi lisätä." - -#: mod/follow.php:90 -msgid "OStatus support is disabled. Contact can't be added." -msgstr "OStatus -tuki ei ole käytössä. Kontaktia ei voi lisätä." - -#: mod/follow.php:97 -msgid "The network type couldn't be detected. Contact can't be added." -msgstr "Verkkotyyppiä ei voitu havaita. Kontaktia ei voitu lisätä." - -#: mod/follow.php:149 mod/dfrn_request.php:647 -msgid "Please answer the following:" -msgstr "Vastaa seuraavaan:" - -#: mod/follow.php:150 mod/dfrn_request.php:648 -#, php-format -msgid "Does %s know you?" -msgstr "Tunteeko %s sinut?" - -#: mod/follow.php:151 mod/dfrn_request.php:649 -msgid "Add a personal note:" -msgstr "Lisää oma merkintä:" - -#: mod/lostpass.php:27 +#: mod/lostpass.php:40 msgid "No valid account found." msgstr "Voimassa olevaa tiliä ei löytynyt." -#: mod/lostpass.php:39 +#: mod/lostpass.php:52 msgid "Password reset request issued. Check your email." msgstr "Salasanan nollauspyyntö lähetetty. Tarkista sähköpostisi." -#: mod/lostpass.php:45 +#: mod/lostpass.php:58 #, php-format msgid "" "\n" @@ -2730,7 +113,7 @@ msgid "" "\t\tissued this request." msgstr "" -#: mod/lostpass.php:56 +#: mod/lostpass.php:69 #, php-format msgid "" "\n" @@ -2747,66 +130,70 @@ msgid "" "\t\tLogin Name:\t%3$s" msgstr "" -#: mod/lostpass.php:73 +#: mod/lostpass.php:84 #, php-format msgid "Password reset requested at %s" msgstr "Salasanan nollauspyyntö kohteessa %s" -#: mod/lostpass.php:89 +#: mod/lostpass.php:100 msgid "" "Request could not be verified. (You may have previously submitted it.) " "Password reset failed." msgstr "Pyyntöä ei voitu vahvistaa. (Saatoit lähettää pyyntöä aikaisemmin.) Salasanan nollaus epäonnistui." -#: mod/lostpass.php:102 +#: mod/lostpass.php:113 msgid "Request has expired, please make a new one." msgstr "Pyyntö on vanhentunut, tehkää uusi pyyntö." -#: mod/lostpass.php:117 +#: mod/lostpass.php:128 msgid "Forgot your Password?" msgstr "Unohditko salasanasi?" -#: mod/lostpass.php:118 +#: mod/lostpass.php:129 msgid "" "Enter your email address and submit to have your password reset. Then check " "your email for further instructions." msgstr "Syötä sähköpostiosoitteesi salasanan nollausta varten. Lisäohjeet lähetetään sähköpostitse." -#: mod/lostpass.php:119 src/Module/Login.php:315 +#: mod/lostpass.php:130 src/Module/Security/Login.php:160 msgid "Nickname or Email: " msgstr "Lempinimi tai sähköposti:" -#: mod/lostpass.php:120 +#: mod/lostpass.php:131 msgid "Reset" msgstr "Nollaus" -#: mod/lostpass.php:136 src/Module/Login.php:327 +#: mod/lostpass.php:146 src/Module/Security/Login.php:172 msgid "Password Reset" msgstr "Salasanan nollaus" -#: mod/lostpass.php:137 +#: mod/lostpass.php:147 msgid "Your password has been reset as requested." msgstr "Salasanasi on nollattu pyynnöstäsi." -#: mod/lostpass.php:138 +#: mod/lostpass.php:148 msgid "Your new password is" msgstr "Uusi salasanasi on" -#: mod/lostpass.php:139 +#: mod/lostpass.php:149 msgid "Save or copy your new password - and then" msgstr "Tallenna tai kopioi uusi salasanasi, ja sitten" -#: mod/lostpass.php:140 +#: mod/lostpass.php:150 msgid "click here to login" msgstr "kirjaudu klikkaamalla tästä" -#: mod/lostpass.php:141 +#: mod/lostpass.php:151 msgid "" "Your password may be changed from the Settings page after " "successful login." msgstr "Salsanaa voi vaihtaa asetussivulta kirjautumisen jälkeen." -#: mod/lostpass.php:149 +#: mod/lostpass.php:155 +msgid "Your password has been reset." +msgstr "" + +#: mod/lostpass.php:158 #, php-format msgid "" "\n" @@ -2817,7 +204,7 @@ msgid "" "\t\t" msgstr "" -#: mod/lostpass.php:155 +#: mod/lostpass.php:164 #, php-format msgid "" "\n" @@ -2831,5976 +218,2670 @@ msgid "" "\t\t" msgstr "\n\t\t\tKäyttäjätilisi tiedot:\n\n\t\t\tSivuston osoite:\t%1$s\n\t\t\tKäyttäjätunnus:\t%2$s\n\t\t\tSalasana:\t%3$s\n\n\t\t\tVoit vaihtaa salasanasi kirjautumisen jälkeen asetussivulta.\n\t\t" -#: mod/lostpass.php:169 +#: mod/lostpass.php:176 #, php-format msgid "Your password has been changed at %s" msgstr "Salasanasi on vaihdettu sivustolla %s" -#: mod/babel.php:22 -msgid "Source input" -msgstr "" - -#: mod/babel.php:28 -msgid "BBCode::toPlaintext" -msgstr "BBCode::toPlaintext" - -#: mod/babel.php:34 -msgid "BBCode::convert (raw HTML)" -msgstr "BBCode::convert (raaka HTML)" - -#: mod/babel.php:39 -msgid "BBCode::convert" -msgstr "BBCode::convert" - -#: mod/babel.php:45 -msgid "BBCode::convert => HTML::toBBCode" -msgstr "BBCode::convert => HTML::toBBCode" - -#: mod/babel.php:51 -msgid "BBCode::toMarkdown" -msgstr "BBCode::toMarkdown" - -#: mod/babel.php:57 -msgid "BBCode::toMarkdown => Markdown::convert" -msgstr "BBCode::toMarkdown => Markdown::convert" - -#: mod/babel.php:63 -msgid "BBCode::toMarkdown => Markdown::toBBCode" -msgstr "BBCode::toMarkdown => Markdown::toBBCode" - -#: mod/babel.php:69 -msgid "BBCode::toMarkdown => Markdown::convert => HTML::toBBCode" -msgstr "BBCode::toMarkdown => Markdown::convert => HTML::toBBCode" - -#: mod/babel.php:76 -msgid "Source input \\x28Diaspora format\\x29" -msgstr "" - -#: mod/babel.php:82 -msgid "Markdown::toBBCode" -msgstr "Markdown::toBBCode" - -#: mod/babel.php:89 -msgid "Raw HTML input" -msgstr "Raaka HTML-syöte" - -#: mod/babel.php:94 -msgid "HTML Input" -msgstr "HTML-syöte" - -#: mod/babel.php:100 -msgid "HTML::toBBCode" -msgstr "HTML::toBBCode" - -#: mod/babel.php:106 -msgid "HTML::toPlaintext" -msgstr "HTML::toPlaintext" - -#: mod/babel.php:114 -msgid "Source text" -msgstr "Lähdeteksti" - -#: mod/babel.php:115 -msgid "BBCode" -msgstr "BBCode" - -#: mod/babel.php:116 -msgid "Markdown" -msgstr "Markdown" - -#: mod/babel.php:117 -msgid "HTML" -msgstr "HTML" - -#: mod/friendica.php:77 -msgid "This is Friendica, version" -msgstr "Tämä on Friendica, versio" - -#: mod/friendica.php:78 -msgid "running at web location" -msgstr "käynnissä osoitteessa" - -#: mod/friendica.php:82 -msgid "" -"Please visit Friendi.ca to learn more " -"about the Friendica project." -msgstr "Vieraile osoitteessa Friendi.ca saadaksesi lisätietoja Friendica- projektista." - -#: mod/friendica.php:86 -msgid "Bug reports and issues: please visit" -msgstr "Bugiraportit ja kysymykset: vieraile osoitteessa" - -#: mod/friendica.php:86 -msgid "the bugtracker at github" -msgstr "githubin bugtrackeri" - -#: mod/friendica.php:89 -msgid "Suggestions, praise, etc. - please email \"info\" at \"friendi - dot - ca" -msgstr "Ehdotukset ja palaute: lähetä sähköposti osoitteeseen \"info\" at \"friendi - piste - ca" - -#: mod/friendica.php:103 -msgid "Installed addons/apps:" -msgstr "Asennettu lisäosat/sovellukset:" - -#: mod/friendica.php:117 -msgid "No installed addons/apps" -msgstr "Ei asennettuja lisäosia/sovelluksia" - -#: mod/friendica.php:122 -#, php-format -msgid "Read about the Terms of Service of this node." -msgstr "Lue tämän solmun käyttöehdot." - -#: mod/friendica.php:127 -msgid "On this server the following remote servers are blocked." -msgstr "Tällä palvelimella seuraavat etäpalvelimet ovat estetty." - -#: mod/friendica.php:128 mod/admin.php:357 mod/admin.php:375 -#: mod/dfrn_request.php:347 src/Model/Contact.php:1281 -msgid "Blocked domain" -msgstr "Estetty verkkotunnus" - -#: mod/friendica.php:128 mod/admin.php:358 mod/admin.php:376 -msgid "Reason for the block" -msgstr "Eston syy" - -#: mod/invite.php:33 -msgid "Total invitation limit exceeded." -msgstr "Kutsuraja ylitetty." - -#: mod/invite.php:55 -#, php-format -msgid "%s : Not a valid email address." -msgstr "%s : Virheellinen sähköpostiosoite." - -#: mod/invite.php:87 -msgid "Please join us on Friendica" -msgstr "Tervetuloa Friendicaan" - -#: mod/invite.php:96 -msgid "Invitation limit exceeded. Please contact your site administrator." -msgstr "Kutsuraja ylitetty. Ota yhteyttä ylläpitäjään." - -#: mod/invite.php:100 -#, php-format -msgid "%s : Message delivery failed." -msgstr "%s : Viestin toimitus epäonnistui." - -#: mod/invite.php:104 -#, php-format -msgid "%d message sent." -msgid_plural "%d messages sent." -msgstr[0] "%d viesti lähetetty." -msgstr[1] "%d viestiä lähetetty." - -#: mod/invite.php:122 -msgid "You have no more invitations available" -msgstr "Sinulla ei ole kutsuja jäljellä" - -#: mod/invite.php:130 -#, php-format -msgid "" -"Visit %s for a list of public sites that you can join. Friendica members on " -"other sites can all connect with each other, as well as with members of many" -" other social networks." -msgstr "" - -#: mod/invite.php:132 -#, php-format -msgid "" -"To accept this invitation, please visit and register at %s or any other " -"public Friendica website." -msgstr "Hyväksyäksesi tämän kutsun, rekisteröidy sivustolla %s tai millä tahansa muulla Friendica -sivustolla." - -#: mod/invite.php:133 -#, php-format -msgid "" -"Friendica sites all inter-connect to create a huge privacy-enhanced social " -"web that is owned and controlled by its members. They can also connect with " -"many traditional social networks. See %s for a list of alternate Friendica " -"sites you can join." -msgstr "" - -#: mod/invite.php:137 -msgid "" -"Our apologies. This system is not currently configured to connect with other" -" public sites or invite members." -msgstr "" - -#: mod/invite.php:141 -msgid "" -"Friendica sites all inter-connect to create a huge privacy-enhanced social " -"web that is owned and controlled by its members. They can also connect with " -"many traditional social networks." -msgstr "" - -#: mod/invite.php:140 -#, php-format -msgid "To accept this invitation, please visit and register at %s." -msgstr "Hyväksyäksesi tämän kutsun, rekisteröidy sivustolla %s." - -#: mod/invite.php:147 -msgid "Send invitations" -msgstr "Lähetä kutsut" - -#: mod/invite.php:148 -msgid "Enter email addresses, one per line:" -msgstr "Syötä sähköpostiosoitteet, yksi riviä kohden:" - -#: mod/invite.php:149 -msgid "" -"You are cordially invited to join me and other close friends on Friendica - " -"and help us to create a better social web." -msgstr "" - -#: mod/invite.php:151 -msgid "You will need to supply this invitation code: $invite_code" -msgstr "" - -#: mod/invite.php:151 -msgid "" -"Once you have registered, please connect with me via my profile page at:" -msgstr "Kun olet rekisteröitynyt, lähetä minulle kaverikutsun profiilisivuni kautta:" - -#: mod/invite.php:153 -msgid "" -"For more information about the Friendica project and why we feel it is " -"important, please visit http://friendi.ca" -msgstr "" - -#: mod/crepair.php:87 -msgid "Contact settings applied." -msgstr "Kontaktiasetukset tallennettu." - -#: mod/crepair.php:89 -msgid "Contact update failed." -msgstr "Kontaktipäivitys epäonnistui." - -#: mod/crepair.php:114 -msgid "" -"WARNING: This is highly advanced and if you enter incorrect" -" information your communications with this contact may stop working." -msgstr "VAROITUS: Tämä on erittäin vaativaa ja jos kirjoitat virheellisiä tietoja, viestintäsi tämän henkilön kanssa voi lakata toimimasta." - -#: mod/crepair.php:115 -msgid "" -"Please use your browser 'Back' button now if you are " -"uncertain what to do on this page." -msgstr "Ole hyvä ja paina selaimesi 'Takaisin'-painiketta nyt, jos olet epävarma tämän sivun toiminnoista." - -#: mod/crepair.php:129 mod/crepair.php:131 -msgid "No mirroring" -msgstr "Ei peilausta" - -#: mod/crepair.php:129 -msgid "Mirror as forwarded posting" -msgstr "Peilaa välitettynä julkaisuna" - -#: mod/crepair.php:129 mod/crepair.php:131 -msgid "Mirror as my own posting" -msgstr "Peilaa omana julkaisuna" - -#: mod/crepair.php:144 -msgid "Return to contact editor" -msgstr "Palaa kontaktin muokkaamiseen" - -#: mod/crepair.php:146 -msgid "Refetch contact data" -msgstr "" - -#: mod/crepair.php:149 -msgid "Remote Self" -msgstr "" - -#: mod/crepair.php:152 -msgid "Mirror postings from this contact" -msgstr "Peilaa tämän kontaktin julkaisut" - -#: mod/crepair.php:154 -msgid "" -"Mark this contact as remote_self, this will cause friendica to repost new " -"entries from this contact." -msgstr "" - -#: mod/crepair.php:158 mod/admin.php:494 mod/admin.php:1816 mod/admin.php:1827 -#: mod/admin.php:1840 mod/admin.php:1856 mod/settings.php:671 -#: mod/settings.php:697 -msgid "Name" -msgstr "Nimi" - -#: mod/crepair.php:159 -msgid "Account Nickname" -msgstr "Tilin lempinimi" - -#: mod/crepair.php:160 -msgid "@Tagname - overrides Name/Nickname" -msgstr "@Tagname - ohittaa Nimen/Nimimerkin" - -#: mod/crepair.php:161 -msgid "Account URL" -msgstr "Tilin URL-osoite" - -#: mod/crepair.php:162 -msgid "Friend Request URL" -msgstr "URL kaveripyyntöä varten" - -#: mod/crepair.php:163 -msgid "Friend Confirm URL" -msgstr "URL kaverin vahvistusta varten" - -#: mod/crepair.php:164 -msgid "Notification Endpoint URL" -msgstr "URL huomautuksia varten" - -#: mod/crepair.php:165 -msgid "Poll/Feed URL" -msgstr "URL äänestyksiä/syötteitä varten" - -#: mod/crepair.php:166 -msgid "New photo from this URL" -msgstr "Uusi kuva osoitteesta" - -#: mod/dfrn_poll.php:123 mod/dfrn_poll.php:539 -#, php-format -msgid "%1$s welcomes %2$s" -msgstr "%1$s toivottaa tervetulleeksi ystävän %2$s" - -#: mod/help.php:48 -msgid "Help:" -msgstr "Ohje:" - -#: mod/help.php:54 view/theme/vier/theme.php:297 src/Content/Nav.php:134 -msgid "Help" -msgstr "Ohje" - -#: mod/help.php:63 index.php:317 -msgid "Page not found." -msgstr "Sivua ei löytynyt." - -#: mod/install.php:87 -msgid "Friendica Communications Server - Setup" -msgstr "Friendica viestinnän palvelin - asetukset" - -#: mod/install.php:93 -msgid "Could not connect to database." -msgstr "Tietokantaan ei saada yhteyttä." - -#: mod/install.php:97 -msgid "Could not create table." -msgstr "Taulun luominen epäonnistui." - -#: mod/install.php:103 -msgid "Your Friendica site database has been installed." -msgstr "Friendica-sivustosi tietokanta on asennettu." - -#: mod/install.php:108 -msgid "" -"You may need to import the file \"database.sql\" manually using phpmyadmin " -"or mysql." -msgstr "Sinun on ehkä tuotava tiedosto \"database.sql\" manuaalisesti käyttämällä phpMyAdminia tai MySQL:ää." - -#: mod/install.php:109 mod/install.php:155 mod/install.php:267 -msgid "Please see the file \"INSTALL.txt\"." -msgstr "Lue tiedosto \"INSTALL.txt\"." - -#: mod/install.php:121 -msgid "Database already in use." -msgstr "Tietokanta on jo käytössä." - -#: mod/install.php:152 -msgid "System check" -msgstr "Järjestelmän tarkistus" - -#: mod/install.php:157 -msgid "Check again" -msgstr "Tarkista uudelleen" - -#: mod/install.php:177 -msgid "Database connection" -msgstr "Tietokantayhteys" - -#: mod/install.php:178 -msgid "" -"In order to install Friendica we need to know how to connect to your " -"database." -msgstr "Jotta voit asentaa Friendican, tarvitaan tieto siitä, miten tietokantaasi saa yhteyden." - -#: mod/install.php:179 -msgid "" -"Please contact your hosting provider or site administrator if you have " -"questions about these settings." -msgstr "Ota yhteyttä web-palveluntarjoajaasi tai sivuston ylläpitäjään, jos sinulla on näihin asetuksiin liittyviä kysymyksiä." - -#: mod/install.php:180 -msgid "" -"The database you specify below should already exist. If it does not, please " -"create it before continuing." -msgstr "Alla määritetyn tietokannan tulisi olla jo olemassa. Jos se ei ole, luo se ennen kuin jatkat." - -#: mod/install.php:184 -msgid "Database Server Name" -msgstr "Tietokannan palvelimen nimi" - -#: mod/install.php:185 -msgid "Database Login Name" -msgstr "Tietokannan käyttäjän nimi" - -#: mod/install.php:186 -msgid "Database Login Password" -msgstr "Tietokannan käyttäjän salasana" - -#: mod/install.php:186 -msgid "For security reasons the password must not be empty" -msgstr "Turvallisuussyistä salasanakenttä ei saa olla tyhjä" - -#: mod/install.php:187 -msgid "Database Name" -msgstr "Tietokannan nimi" - -#: mod/install.php:188 mod/install.php:228 -msgid "Site administrator email address" -msgstr "Sivuston ylläpitäjän sähköpostiosoite" - -#: mod/install.php:188 mod/install.php:228 -msgid "" -"Your account email address must match this in order to use the web admin " -"panel." -msgstr "Tilisi sähköpostiosoitteen on vastattava tätä, jotta voit käyttää ylläpitokäyttöliittymää." - -#: mod/install.php:192 mod/install.php:231 -msgid "Please select a default timezone for your website" -msgstr "Valitse oletusaikavyöhyke sivustollesi" - -#: mod/install.php:218 -msgid "Site settings" -msgstr "Sivuston asetukset" - -#: mod/install.php:232 -msgid "System Language:" -msgstr "Järjestelmän kieli:" - -#: mod/install.php:232 -msgid "" -"Set the default language for your Friendica installation interface and to " -"send emails." -msgstr "Valitse Friendica-sivustosi oletuskieli." - -#: mod/install.php:248 -msgid "" -"The database configuration file \".htconfig.php\" could not be written. " -"Please use the enclosed text to create a configuration file in your web " -"server root." -msgstr "Tietokannan asetustiedostoa \".htconfig.php\" ei pystytty kirjoittamaan. Käytä mukaanliitettyä tekstiä luomaan asetustiedosto web-palvelimesi juureen." - -#: mod/install.php:265 -msgid "

What next

" -msgstr "

Mitä seuraavaksi

" - -#: mod/install.php:266 -msgid "" -"IMPORTANT: You will need to [manually] setup a scheduled task for the " -"worker." -msgstr "TÄRKEÄÄ: Sinun pitää asettaa [manuaalisesti] ajastettu tehtävä Workerille." - -#: mod/install.php:269 -#, php-format -msgid "" -"Go to your new Friendica node registration page " -"and register as new user. Remember to use the same email you have entered as" -" administrator email. This will allow you to enter the site admin panel." -msgstr "" - -#: mod/message.php:30 src/Content/Nav.php:199 +#: mod/message.php:46 mod/message.php:128 src/Content/Nav.php:319 msgid "New Message" msgstr "Uusi viesti" -#: mod/message.php:77 +#: mod/message.php:82 src/Module/Profile/UnkMail.php:100 +msgid "No recipient selected." +msgstr "Vastaanottaja puuttuu." + +#: mod/message.php:87 msgid "Unable to locate contact information." msgstr "Kontaktin tiedot ei löydy." -#: mod/message.php:112 view/theme/frio/theme.php:268 src/Content/Nav.php:196 +#: mod/message.php:91 src/Module/Profile/UnkMail.php:106 +msgid "Message could not be sent." +msgstr "Viestiä ei voitu lähettää." + +#: mod/message.php:95 src/Module/Profile/UnkMail.php:109 +msgid "Message collection failure." +msgstr "Viestin noutaminen epäonnistui." + +#: mod/message.php:122 src/Module/Notifications/Introductions.php:135 +#: src/Module/Notifications/Introductions.php:170 +#: src/Module/Notifications/Notification.php:85 +msgid "Discard" +msgstr "Hylkää" + +#: mod/message.php:135 src/Content/Nav.php:316 view/theme/frio/theme.php:241 msgid "Messages" msgstr "Viestit" -#: mod/message.php:136 -msgid "Do you really want to delete this message?" -msgstr "Haluatko varmasti poistaa viestin?" +#: mod/message.php:148 +msgid "Conversation not found." +msgstr "" -#: mod/message.php:152 -msgid "Message deleted." -msgstr "Viesti poistettu." +#: mod/message.php:153 +msgid "Message was not deleted." +msgstr "" -#: mod/message.php:166 -msgid "Conversation removed." -msgstr "Keskustelu poistettu." +#: mod/message.php:168 +msgid "Conversation was not removed." +msgstr "" -#: mod/message.php:272 +#: mod/message.php:181 mod/message.php:286 src/Module/Profile/UnkMail.php:145 +msgid "Please enter a link URL:" +msgstr "Lisää URL-linkki:" + +#: mod/message.php:190 src/Module/Profile/UnkMail.php:151 +msgid "Send Private Message" +msgstr "Lähetä yksityisviesti" + +#: mod/message.php:191 mod/message.php:346 +msgid "To:" +msgstr "Vastaanottaja:" + +#: mod/message.php:192 mod/message.php:347 +msgid "Subject:" +msgstr "Aihe:" + +#: mod/message.php:196 mod/message.php:350 src/Module/Invite.php:171 +msgid "Your message:" +msgstr "Viestisi:" + +#: mod/message.php:199 mod/message.php:354 src/Content/Conversation.php:360 +#: src/Module/Post/Edit.php:131 +msgid "Upload photo" +msgstr "Lähetä kuva" + +#: mod/message.php:200 mod/message.php:355 src/Module/Post/Edit.php:135 +#: src/Module/Profile/UnkMail.php:153 +msgid "Insert web link" +msgstr "Lisää linkki" + +#: mod/message.php:201 mod/message.php:357 mod/photos.php:1289 +#: src/Content/Conversation.php:390 src/Content/Conversation.php:734 +#: src/Module/Item/Compose.php:205 src/Module/Post/Edit.php:145 +#: src/Module/Profile/UnkMail.php:154 src/Object/Post.php:557 +msgid "Please wait" +msgstr "Odota" + +#: mod/message.php:202 mod/message.php:356 mod/photos.php:700 +#: mod/photos.php:817 mod/photos.php:1095 mod/photos.php:1136 +#: mod/photos.php:1192 mod/photos.php:1266 +#: src/Module/Calendar/Event/Form.php:250 src/Module/Contact/Advanced.php:132 +#: src/Module/Contact/Profile.php:339 +#: src/Module/Debug/ActivityPubConversion.php:140 +#: src/Module/Debug/Babel.php:313 src/Module/Debug/Localtime.php:64 +#: src/Module/Debug/Probe.php:54 src/Module/Debug/WebFinger.php:51 +#: src/Module/Delegation.php:147 src/Module/FriendSuggest.php:145 +#: src/Module/Install.php:234 src/Module/Install.php:274 +#: src/Module/Install.php:309 src/Module/Invite.php:178 +#: src/Module/Item/Compose.php:189 src/Module/Moderation/Item/Source.php:79 +#: src/Module/Profile/Profile.php:274 src/Module/Profile/UnkMail.php:155 +#: src/Module/Settings/Profile/Index.php:230 src/Object/Post.php:1070 +#: view/theme/duepuntozero/config.php:85 view/theme/frio/config.php:171 +#: view/theme/quattro/config.php:87 view/theme/vier/config.php:135 +msgid "Submit" +msgstr "Lähetä" + +#: mod/message.php:223 msgid "No messages." msgstr "Ei viestejä." -#: mod/message.php:311 +#: mod/message.php:279 msgid "Message not available." msgstr "Viesti ei saatavilla." -#: mod/message.php:378 +#: mod/message.php:323 msgid "Delete message" msgstr "Poista viesti" -#: mod/message.php:380 mod/message.php:481 +#: mod/message.php:325 mod/message.php:456 msgid "D, d M Y - g:i A" msgstr "D, j.n.Y - H:i" -#: mod/message.php:395 mod/message.php:478 +#: mod/message.php:340 mod/message.php:453 msgid "Delete conversation" msgstr "Poista keskustelu" -#: mod/message.php:397 +#: mod/message.php:342 msgid "" "No secure communications available. You may be able to " "respond from the sender's profile page." msgstr "" -#: mod/message.php:401 +#: mod/message.php:345 msgid "Send Reply" msgstr "Lähetä vastaus" -#: mod/message.php:452 +#: mod/message.php:427 #, php-format msgid "Unknown sender - %s" msgstr "Tuntematon lähettäjä - %s" -#: mod/message.php:454 +#: mod/message.php:429 #, php-format msgid "You and %s" msgstr "Sinä ja %s" -#: mod/message.php:456 +#: mod/message.php:431 #, php-format msgid "%s and You" msgstr "%s ja sinä" -#: mod/message.php:484 +#: mod/message.php:459 #, php-format msgid "%d message" msgid_plural "%d messages" msgstr[0] "%d viesti" msgstr[1] "%d viestiä" -#: mod/admin.php:107 -msgid "Theme settings updated." -msgstr "Teeman asetukset päivitetty." - -#: mod/admin.php:180 src/Content/Nav.php:175 -msgid "Information" -msgstr "Tietoja" - -#: mod/admin.php:181 -msgid "Overview" -msgstr "Yleiskatsaus" - -#: mod/admin.php:182 mod/admin.php:717 -msgid "Federation Statistics" -msgstr "Liiton tilastotiedot" - -#: mod/admin.php:183 -msgid "Configuration" -msgstr "Kokoonpano" - -#: mod/admin.php:184 mod/admin.php:1356 -msgid "Site" -msgstr "Sivusto" - -#: mod/admin.php:185 mod/admin.php:1285 mod/admin.php:1822 mod/admin.php:1838 -msgid "Users" -msgstr "Käyttäjät" - -#: mod/admin.php:186 mod/admin.php:1938 mod/admin.php:1998 mod/settings.php:87 -msgid "Addons" -msgstr "Lisäosat" - -#: mod/admin.php:187 mod/admin.php:2208 mod/admin.php:2252 -msgid "Themes" -msgstr "Teemat" - -#: mod/admin.php:188 mod/settings.php:65 -msgid "Additional features" -msgstr "Lisäominaisuuksia" - -#: mod/admin.php:189 mod/admin.php:304 mod/register.php:291 -#: src/Content/Nav.php:178 src/Module/Tos.php:70 -msgid "Terms of Service" -msgstr "Käyttöehdot" - -#: mod/admin.php:190 -msgid "Database" -msgstr "Tietokanta" - -#: mod/admin.php:191 -msgid "DB updates" -msgstr "Tietokannan päivitykset" - -#: mod/admin.php:192 mod/admin.php:752 -msgid "Inspect Queue" -msgstr "Tarkista jono" - -#: mod/admin.php:193 -msgid "Tools" -msgstr "Työkalut" - -#: mod/admin.php:194 -msgid "Contact Blocklist" -msgstr "Kontaktien estolista" - -#: mod/admin.php:195 mod/admin.php:366 -msgid "Server Blocklist" -msgstr "Palvelimien estolista" - -#: mod/admin.php:196 mod/admin.php:525 -msgid "Delete Item" -msgstr "Poista kohde" - -#: mod/admin.php:197 mod/admin.php:198 mod/admin.php:2326 -msgid "Logs" -msgstr "Lokit" - -#: mod/admin.php:199 mod/admin.php:2393 -msgid "View Logs" -msgstr "Katso lokit" - -#: mod/admin.php:201 -msgid "Diagnostics" -msgstr "Diagnostiikka" - -#: mod/admin.php:202 -msgid "PHP Info" -msgstr "PHP tietoja" - -#: mod/admin.php:203 -msgid "probe address" -msgstr "" - -#: mod/admin.php:204 -msgid "check webfinger" -msgstr "Tarkista webfinger" - -#: mod/admin.php:223 src/Content/Nav.php:218 -msgid "Admin" -msgstr "Ylläpitäjä" - -#: mod/admin.php:224 -msgid "Addon Features" -msgstr "Lisäosaominaisuudet" - -#: mod/admin.php:225 -msgid "User registrations waiting for confirmation" -msgstr "Käyttäjärekisteröinnit odottavat hyväksyntää" - -#: mod/admin.php:303 mod/admin.php:365 mod/admin.php:482 mod/admin.php:524 -#: mod/admin.php:716 mod/admin.php:751 mod/admin.php:847 mod/admin.php:1355 -#: mod/admin.php:1821 mod/admin.php:1937 mod/admin.php:1997 mod/admin.php:2207 -#: mod/admin.php:2251 mod/admin.php:2325 mod/admin.php:2392 -msgid "Administration" -msgstr "Ylläpito" - -#: mod/admin.php:305 -msgid "Display Terms of Service" -msgstr "Näytä käyttöehdot" - -#: mod/admin.php:305 -msgid "" -"Enable the Terms of Service page. If this is enabled a link to the terms " -"will be added to the registration form and the general information page." -msgstr "" - -#: mod/admin.php:306 -msgid "Display Privacy Statement" -msgstr "Näytä tietosuojalausunto" - -#: mod/admin.php:306 -#, php-format -msgid "" -"Show some informations regarding the needed information to operate the node " -"according e.g. to EU-GDPR." -msgstr "" - -#: mod/admin.php:307 -msgid "Privacy Statement Preview" -msgstr "" - -#: mod/admin.php:309 -msgid "The Terms of Service" -msgstr "Käyttöehdot" - -#: mod/admin.php:309 -msgid "" -"Enter the Terms of Service for your node here. You can use BBCode. Headers " -"of sections should be [h2] and below." -msgstr "" - -#: mod/admin.php:357 -msgid "The blocked domain" -msgstr "Estetty verkkotunnus" - -#: mod/admin.php:358 mod/admin.php:371 -msgid "The reason why you blocked this domain." -msgstr "Verkkotunnuksen estosyy." - -#: mod/admin.php:359 -msgid "Delete domain" -msgstr "Poista verkkotunnus" - -#: mod/admin.php:359 -msgid "Check to delete this entry from the blocklist" -msgstr "Laita rasti poistaaksesi kohde estolistalta" - -#: mod/admin.php:367 -msgid "" -"This page can be used to define a black list of servers from the federated " -"network that are not allowed to interact with your node. For all entered " -"domains you should also give a reason why you have blocked the remote " -"server." -msgstr "" - -#: mod/admin.php:368 -msgid "" -"The list of blocked servers will be made publically available on the " -"/friendica page so that your users and people investigating communication " -"problems can find the reason easily." -msgstr "" - -#: mod/admin.php:369 -msgid "Add new entry to block list" -msgstr "Lisää uusi kohde estolistaan" - -#: mod/admin.php:370 -msgid "Server Domain" -msgstr "Palvelimen verkkotunnus" - -#: mod/admin.php:370 -msgid "" -"The domain of the new server to add to the block list. Do not include the " -"protocol." -msgstr "" - -#: mod/admin.php:371 -msgid "Block reason" -msgstr "Estosyy" - -#: mod/admin.php:372 -msgid "Add Entry" -msgstr "Lisää merkintä" - -#: mod/admin.php:373 -msgid "Save changes to the blocklist" -msgstr "Tallenna muutoksia estolistaan" - -#: mod/admin.php:374 -msgid "Current Entries in the Blocklist" -msgstr "Nykyinen estolista" - -#: mod/admin.php:377 -msgid "Delete entry from blocklist" -msgstr "Poista kohde estolistalta" - -#: mod/admin.php:380 -msgid "Delete entry from blocklist?" -msgstr "Poista kohde estolistalta?" - -#: mod/admin.php:406 -msgid "Server added to blocklist." -msgstr "Palvelin lisätty estolistalle" - -#: mod/admin.php:422 -msgid "Site blocklist updated." -msgstr "Sivuston estolista päivitetty." - -#: mod/admin.php:445 src/Core/Console/GlobalCommunityBlock.php:72 -msgid "The contact has been blocked from the node" -msgstr "Kontakti on estetty tällä solmulla" - -#: mod/admin.php:447 src/Core/Console/GlobalCommunityBlock.php:69 -#, php-format -msgid "Could not find any contact entry for this URL (%s)" -msgstr "" - -#: mod/admin.php:454 -#, php-format -msgid "%s contact unblocked" -msgid_plural "%s contacts unblocked" -msgstr[0] "%s kontakti poistettu estolistalta" -msgstr[1] "%s kontaktia poistettu estolistalta" - -#: mod/admin.php:483 -msgid "Remote Contact Blocklist" -msgstr "Etäkontakti estolista" - -#: mod/admin.php:484 -msgid "" -"This page allows you to prevent any message from a remote contact to reach " -"your node." -msgstr "" - -#: mod/admin.php:485 -msgid "Block Remote Contact" -msgstr "Estä etäkontakti" - -#: mod/admin.php:486 mod/admin.php:1824 -msgid "select all" -msgstr "valitse kaikki" - -#: mod/admin.php:487 -msgid "select none" -msgstr "älä valitse mitään" - -#: mod/admin.php:490 -msgid "No remote contact is blocked from this node." -msgstr "" - -#: mod/admin.php:492 -msgid "Blocked Remote Contacts" -msgstr "Estetty etäkontaktit" - -#: mod/admin.php:493 -msgid "Block New Remote Contact" -msgstr "Estä uusi etäkontakti" - -#: mod/admin.php:494 -msgid "Photo" -msgstr "Kuva" - -#: mod/admin.php:494 mod/profiles.php:394 -msgid "Address" -msgstr "Osoite" - -#: mod/admin.php:502 -#, php-format -msgid "%s total blocked contact" -msgid_plural "%s total blocked contacts" -msgstr[0] "Yhteensä %s estetty kontakti" -msgstr[1] "Yhteensä %s estettyjä kontakteja" - -#: mod/admin.php:504 -msgid "URL of the remote contact to block." -msgstr "Estettävän etäkontaktin URL-osoite" - -#: mod/admin.php:526 -msgid "Delete this Item" -msgstr "Poista tämä kohde" - -#: mod/admin.php:527 -msgid "" -"On this page you can delete an item from your node. If the item is a top " -"level posting, the entire thread will be deleted." -msgstr "" - -#: mod/admin.php:528 -msgid "" -"You need to know the GUID of the item. You can find it e.g. by looking at " -"the display URL. The last part of http://example.com/display/123456 is the " -"GUID, here 123456." -msgstr "" - -#: mod/admin.php:529 -msgid "GUID" -msgstr "GUID" - -#: mod/admin.php:529 -msgid "The GUID of the item you want to delete." -msgstr "Poistettavan kohteen GUID." - -#: mod/admin.php:563 -msgid "Item marked for deletion." -msgstr "Kohde merkitty poistettavaksi." - -#: mod/admin.php:634 -msgid "unknown" -msgstr "tuntematon" - -#: mod/admin.php:710 -msgid "" -"This page offers you some numbers to the known part of the federated social " -"network your Friendica node is part of. These numbers are not complete but " -"only reflect the part of the network your node is aware of." -msgstr "" - -#: mod/admin.php:711 -msgid "" -"The Auto Discovered Contact Directory feature is not enabled, it " -"will improve the data displayed here." -msgstr "" - -#: mod/admin.php:723 -#, php-format -msgid "" -"Currently this node is aware of %d nodes with %d registered users from the " -"following platforms:" -msgstr "Tällä hetkellä tämä solmu havaitsee %d muita solmuja joissa %d rekisteröityneitä käyttäjiä. Tarkemmat tiedot:" - -#: mod/admin.php:754 -msgid "ID" -msgstr "" - -#: mod/admin.php:755 -msgid "Recipient Name" -msgstr "Vastaanottajan nimi" - -#: mod/admin.php:756 -msgid "Recipient Profile" -msgstr "Vastaanottajan profiili" - -#: mod/admin.php:757 view/theme/frio/theme.php:266 -#: src/Core/NotificationsManager.php:178 src/Content/Nav.php:183 -msgid "Network" -msgstr "Uutisvirta" - -#: mod/admin.php:758 -msgid "Created" -msgstr "Luotu" - -#: mod/admin.php:759 -msgid "Last Tried" -msgstr "Viimeksi yritetty" - -#: mod/admin.php:760 -msgid "" -"This page lists the content of the queue for outgoing postings. These are " -"postings the initial delivery failed for. They will be resend later and " -"eventually deleted if the delivery fails permanently." -msgstr "" - -#: mod/admin.php:784 -#, php-format -msgid "" -"Your DB still runs with MyISAM tables. You should change the engine type to " -"InnoDB. As Friendica will use InnoDB only features in the future, you should" -" change this! See here for a guide that may be helpful " -"converting the table engines. You may also use the command php " -"bin/console.php dbstructure toinnodb of your Friendica installation for" -" an automatic conversion.
" -msgstr "" - -#: mod/admin.php:791 -#, php-format -msgid "" -"There is a new version of Friendica available for download. Your current " -"version is %1$s, upstream version is %2$s" -msgstr "" - -#: mod/admin.php:801 -msgid "" -"The database update failed. Please run \"php bin/console.php dbstructure " -"update\" from the command line and have a look at the errors that might " -"appear." -msgstr "Tietokannan päivitys epäonnistui. Suorita komento \"php bin/console.php dbstructure update\" komentoriviltä ja lue mahdolliset virheviestit." - -#: mod/admin.php:807 -msgid "The worker was never executed. Please check your database structure!" -msgstr "Workeriä ei ole otettu käyttöön. Tarkista tietokantasi rakenne!" - -#: mod/admin.php:810 -#, php-format -msgid "" -"The last worker execution was on %s UTC. This is older than one hour. Please" -" check your crontab settings." -msgstr "Viimeisin worker -käynnistys tapahtui klo %s UTC, eli yli tunti sitten. Tarkista crontab -asetukset." - -#: mod/admin.php:815 -msgid "Normal Account" -msgstr "Perustili" - -#: mod/admin.php:816 -msgid "Automatic Follower Account" -msgstr "Automaattinen seuraajatili" - -#: mod/admin.php:817 -msgid "Public Forum Account" -msgstr "Julkinen foorumitili" - -#: mod/admin.php:818 -msgid "Automatic Friend Account" -msgstr "Automaattinen kaveritili" - -#: mod/admin.php:819 -msgid "Blog Account" -msgstr "Blogitili" - -#: mod/admin.php:820 -msgid "Private Forum Account" -msgstr "Yksityinen foorumitili" - -#: mod/admin.php:842 -msgid "Message queues" -msgstr "Viestijonot" - -#: mod/admin.php:848 -msgid "Summary" -msgstr "Yhteenveto" - -#: mod/admin.php:850 -msgid "Registered users" -msgstr "Rekisteröityneet käyttäjät" - -#: mod/admin.php:852 -msgid "Pending registrations" -msgstr "Vireillä olevat rekisteröinnit" - -#: mod/admin.php:853 -msgid "Version" -msgstr "Versio" - -#: mod/admin.php:858 -msgid "Active addons" -msgstr "Käytössäolevat lisäosat" - -#: mod/admin.php:889 -msgid "Can not parse base url. Must have at least ://" -msgstr "Ei voitu jäsentää perusosoitetta. Täytyy sisältää ainakin ://" - -#: mod/admin.php:1220 -msgid "Site settings updated." -msgstr "Sivuston asetukset päivitettiin." - -#: mod/admin.php:1247 mod/settings.php:897 -msgid "No special theme for mobile devices" -msgstr "Ei mobiiliteemaa" - -#: mod/admin.php:1276 -msgid "No community page for local users" -msgstr "" - -#: mod/admin.php:1277 -msgid "No community page" -msgstr "Ei yhteisösivua" - -#: mod/admin.php:1278 -msgid "Public postings from users of this site" -msgstr "Julkiset julkaisut tämän sivuston käyttäjiltä" - -#: mod/admin.php:1279 -msgid "Public postings from the federated network" -msgstr "Julkiset julkaisut liittoutuneelta verkolta" - -#: mod/admin.php:1280 -msgid "Public postings from local users and the federated network" -msgstr "Julkiset julkaisut tältä sivustolta ja liittoutuneelta verkolta" - -#: mod/admin.php:1286 -msgid "Users, Global Contacts" -msgstr "Käyttäjät, maailmanlaajuiset kontaktit" - -#: mod/admin.php:1287 -msgid "Users, Global Contacts/fallback" -msgstr "" - -#: mod/admin.php:1291 -msgid "One month" -msgstr "Yksi kuukausi" - -#: mod/admin.php:1292 -msgid "Three months" -msgstr "Kolme kuukautta" - -#: mod/admin.php:1293 -msgid "Half a year" -msgstr "Puoli vuotta" - -#: mod/admin.php:1294 -msgid "One year" -msgstr "Yksi vuosi" - -#: mod/admin.php:1299 -msgid "Multi user instance" -msgstr "Monen käyttäjän instanssi" - -#: mod/admin.php:1325 -msgid "Closed" -msgstr "Suljettu" - -#: mod/admin.php:1326 -msgid "Requires approval" -msgstr "Edellyttää hyväksyntää" - -#: mod/admin.php:1327 -msgid "Open" -msgstr "Avoin" - -#: mod/admin.php:1331 -msgid "No SSL policy, links will track page SSL state" -msgstr "" - -#: mod/admin.php:1332 -msgid "Force all links to use SSL" -msgstr "Pakota kaikki linkit käyttämään SSL-yhteyttä" - -#: mod/admin.php:1333 -msgid "Self-signed certificate, use SSL for local links only (discouraged)" -msgstr "" - -#: mod/admin.php:1337 -msgid "Don't check" -msgstr "Älä tarkista" - -#: mod/admin.php:1338 -msgid "check the stable version" -msgstr "" - -#: mod/admin.php:1339 -msgid "check the development version" -msgstr "" - -#: mod/admin.php:1358 -msgid "Republish users to directory" -msgstr "" - -#: mod/admin.php:1359 mod/register.php:267 -msgid "Registration" -msgstr "Rekisteröityminen" - -#: mod/admin.php:1360 -msgid "File upload" -msgstr "Tiedoston lataus" - -#: mod/admin.php:1361 -msgid "Policies" -msgstr "Käytännöt" - -#: mod/admin.php:1363 -msgid "Auto Discovered Contact Directory" -msgstr "" - -#: mod/admin.php:1364 -msgid "Performance" -msgstr "Suoritus" - -#: mod/admin.php:1365 -msgid "Worker" -msgstr "Worker" - -#: mod/admin.php:1366 -msgid "Message Relay" -msgstr "Viestirele" - -#: mod/admin.php:1367 -msgid "" -"Relocate - WARNING: advanced function. Could make this server unreachable." -msgstr "" - -#: mod/admin.php:1370 -msgid "Site name" -msgstr "Sivuston nimi" - -#: mod/admin.php:1371 -msgid "Host name" -msgstr "Palvelimen nimi" - -#: mod/admin.php:1372 -msgid "Sender Email" -msgstr "Lähettäjän sähköposti" - -#: mod/admin.php:1372 -msgid "" -"The email address your server shall use to send notification emails from." -msgstr "Lähettäjän sähköpostiosoite palvelimen ilmoitussähköposteissa." - -#: mod/admin.php:1373 -msgid "Banner/Logo" -msgstr "Banneri/logo" - -#: mod/admin.php:1374 -msgid "Shortcut icon" -msgstr "Pikakuvake" - -#: mod/admin.php:1374 -msgid "Link to an icon that will be used for browsers." -msgstr "Linkki kuvakkeeseen jota selaimet saa käyttää." - -#: mod/admin.php:1375 -msgid "Touch icon" -msgstr "Kosketusnäyttökuvake" - -#: mod/admin.php:1375 -msgid "Link to an icon that will be used for tablets and mobiles." -msgstr "Linkki kuvakkeeseen jota tabletit ja matkapuhelimet saa käyttää." - -#: mod/admin.php:1376 -msgid "Additional Info" -msgstr "Lisätietoja" - -#: mod/admin.php:1376 -#, php-format -msgid "" -"For public servers: you can add additional information here that will be " -"listed at %s/servers." -msgstr "" - -#: mod/admin.php:1377 -msgid "System language" -msgstr "Järjestelmän kieli" - -#: mod/admin.php:1378 -msgid "System theme" -msgstr "Järjestelmäteema" - -#: mod/admin.php:1378 -msgid "" -"Default system theme - may be over-ridden by user profiles - change theme settings" -msgstr "" - -#: mod/admin.php:1379 -msgid "Mobile system theme" -msgstr "Mobiili järjestelmäteema" - -#: mod/admin.php:1379 -msgid "Theme for mobile devices" -msgstr "Mobiiliteema" - -#: mod/admin.php:1380 -msgid "SSL link policy" -msgstr "SSL-linkkikäytäntö" - -#: mod/admin.php:1380 -msgid "Determines whether generated links should be forced to use SSL" -msgstr "Määrittää pakotetaanko tuotetut linkit käyttämään SSL-yhteyttä." - -#: mod/admin.php:1381 -msgid "Force SSL" -msgstr "Pakoita SSL-yhteyden käyttöä" - -#: mod/admin.php:1381 -msgid "" -"Force all Non-SSL requests to SSL - Attention: on some systems it could lead" -" to endless loops." -msgstr "" - -#: mod/admin.php:1382 -msgid "Hide help entry from navigation menu" -msgstr "" - -#: mod/admin.php:1382 -msgid "" -"Hides the menu entry for the Help pages from the navigation menu. You can " -"still access it calling /help directly." -msgstr "" - -#: mod/admin.php:1383 -msgid "Single user instance" -msgstr "Yksittäisen käyttäjän instanssi" - -#: mod/admin.php:1383 -msgid "Make this instance multi-user or single-user for the named user" -msgstr "" - -#: mod/admin.php:1384 -msgid "Maximum image size" -msgstr "Suurin kuvakoko" - -#: mod/admin.php:1384 -msgid "" -"Maximum size in bytes of uploaded images. Default is 0, which means no " -"limits." -msgstr "Ladattavan kuvatiedoston enimmäiskoko tavuina. Oletusarvo on 0, eli ei enimmäiskokoa." - -#: mod/admin.php:1385 -msgid "Maximum image length" -msgstr "Suurin kuvapituus" - -#: mod/admin.php:1385 -msgid "" -"Maximum length in pixels of the longest side of uploaded images. Default is " -"-1, which means no limits." -msgstr "Ladattavan kuvatiedoston enimmäispituus pikseleinä. Oletusarvo on -1, eli ei enimmäispituutta." - -#: mod/admin.php:1386 -msgid "JPEG image quality" -msgstr "JPEG-kuvanlaatu" - -#: mod/admin.php:1386 -msgid "" -"Uploaded JPEGS will be saved at this quality setting [0-100]. Default is " -"100, which is full quality." -msgstr "Ladatut JPEG-kuvat tallennetaan tällä laatuasetuksella [0-100]. Oletus on 100, eli korkein laatu." - -#: mod/admin.php:1388 -msgid "Register policy" -msgstr "Rekisteröintipolitiikka" - -#: mod/admin.php:1389 -msgid "Maximum Daily Registrations" -msgstr "Päivittäinen rekisteröitymisraja" - -#: mod/admin.php:1389 -msgid "" -"If registration is permitted above, this sets the maximum number of new user" -" registrations to accept per day. If register is set to closed, this " -"setting has no effect." -msgstr "Mikäli rekisteröityminen on sallittu, tämä asettaa enimmäismäärä uusia rekisteröitymisiä päivässä. Jos reksiteröityminen ei ole sallittu, tällä asetuksella ei ole vaikutusta." - -#: mod/admin.php:1390 -msgid "Register text" -msgstr "Rekisteröitymisteksti" - -#: mod/admin.php:1390 -msgid "" -"Will be displayed prominently on the registration page. You can use BBCode " -"here." -msgstr "Näkyvästi esillä rekisteröitymissivulla. Voit käyttää BBCodeia." - -#: mod/admin.php:1391 -msgid "Accounts abandoned after x days" -msgstr "Käyttäjätilit hylätään X päivän jälkeen" - -#: mod/admin.php:1391 -msgid "" -"Will not waste system resources polling external sites for abandonded " -"accounts. Enter 0 for no time limit." -msgstr "" - -#: mod/admin.php:1392 -msgid "Allowed friend domains" -msgstr "Sallittuja kaveri-verkkotunnuksia" - -#: mod/admin.php:1392 -msgid "" -"Comma separated list of domains which are allowed to establish friendships " -"with this site. Wildcards are accepted. Empty to allow any domains" -msgstr "" - -#: mod/admin.php:1393 -msgid "Allowed email domains" -msgstr "Sallittuja sähköposti-verkkotunnuksia" - -#: mod/admin.php:1393 -msgid "" -"Comma separated list of domains which are allowed in email addresses for " -"registrations to this site. Wildcards are accepted. Empty to allow any " -"domains" -msgstr "" - -#: mod/admin.php:1394 -msgid "No OEmbed rich content" -msgstr "" - -#: mod/admin.php:1394 -msgid "" -"Don't show the rich content (e.g. embedded PDF), except from the domains " -"listed below." -msgstr "" - -#: mod/admin.php:1395 -msgid "Allowed OEmbed domains" -msgstr "Sallittuja OEmbed -verkkotunnuksia" - -#: mod/admin.php:1395 -msgid "" -"Comma separated list of domains which oembed content is allowed to be " -"displayed. Wildcards are accepted." -msgstr "" - -#: mod/admin.php:1396 -msgid "Block public" -msgstr "Estä vierailijat" - -#: mod/admin.php:1396 -msgid "" -"Check to block public access to all otherwise public personal pages on this " -"site unless you are currently logged in." -msgstr "" - -#: mod/admin.php:1397 -msgid "Force publish" -msgstr "" - -#: mod/admin.php:1397 -msgid "" -"Check to force all profiles on this site to be listed in the site directory." -msgstr "" - -#: mod/admin.php:1397 -msgid "Enabling this may violate privacy laws like the GDPR" -msgstr "" - -#: mod/admin.php:1398 -msgid "Global directory URL" -msgstr "Maailmanlaajuisen hakemiston URL-osoite" - -#: mod/admin.php:1398 -msgid "" -"URL to the global directory. If this is not set, the global directory is " -"completely unavailable to the application." -msgstr "" - -#: mod/admin.php:1399 -msgid "Private posts by default for new users" -msgstr "" - -#: mod/admin.php:1399 -msgid "" -"Set default post permissions for all new members to the default privacy " -"group rather than public." -msgstr "" - -#: mod/admin.php:1400 -msgid "Don't include post content in email notifications" -msgstr "Älä lisää julkaisun sisältö sähköposti-ilmoitukseen" - -#: mod/admin.php:1400 -msgid "" -"Don't include the content of a post/comment/private message/etc. in the " -"email notifications that are sent out from this site, as a privacy measure." -msgstr "" - -#: mod/admin.php:1401 -msgid "Disallow public access to addons listed in the apps menu." -msgstr "" - -#: mod/admin.php:1401 -msgid "" -"Checking this box will restrict addons listed in the apps menu to members " -"only." -msgstr "" - -#: mod/admin.php:1402 -msgid "Don't embed private images in posts" -msgstr "Älä upota yksityisiä kuvia julkaisuissa" - -#: mod/admin.php:1402 -msgid "" -"Don't replace locally-hosted private photos in posts with an embedded copy " -"of the image. This means that contacts who receive posts containing private " -"photos will have to authenticate and load each image, which may take a " -"while." -msgstr "" - -#: mod/admin.php:1403 -msgid "Allow Users to set remote_self" -msgstr "" - -#: mod/admin.php:1403 -msgid "" -"With checking this, every user is allowed to mark every contact as a " -"remote_self in the repair contact dialog. Setting this flag on a contact " -"causes mirroring every posting of that contact in the users stream." -msgstr "" - -#: mod/admin.php:1404 -msgid "Block multiple registrations" -msgstr "" - -#: mod/admin.php:1404 -msgid "Disallow users to register additional accounts for use as pages." -msgstr "" - -#: mod/admin.php:1405 -msgid "OpenID support" -msgstr "OpenID-tuki" - -#: mod/admin.php:1405 -msgid "OpenID support for registration and logins." -msgstr "OpenID-tuki rekisteröitymiseen ja kirjautumiseen" - -#: mod/admin.php:1406 -msgid "Fullname check" -msgstr "Koko nimi tarkistus" - -#: mod/admin.php:1406 -msgid "" -"Force users to register with a space between firstname and lastname in Full " -"name, as an antispam measure" -msgstr "" - -#: mod/admin.php:1407 -msgid "Community pages for visitors" -msgstr "Yhteisösivu vieraille" - -#: mod/admin.php:1407 -msgid "" -"Which community pages should be available for visitors. Local users always " -"see both pages." -msgstr "" - -#: mod/admin.php:1408 -msgid "Posts per user on community page" -msgstr "" - -#: mod/admin.php:1408 -msgid "" -"The maximum number of posts per user on the community page. (Not valid for " -"'Global Community')" -msgstr "Enimmäismäärä julkaisuja käyttäjää kohden yhteisösivulla. (Ei koske maailmanlaajuista yhteisösivua.)" - -#: mod/admin.php:1409 -msgid "Enable OStatus support" -msgstr "Salli OStatus-tuki" - -#: mod/admin.php:1409 -msgid "" -"Provide built-in OStatus (StatusNet, GNU Social etc.) compatibility. All " -"communications in OStatus are public, so privacy warnings will be " -"occasionally displayed." -msgstr "" - -#: mod/admin.php:1410 -msgid "Only import OStatus threads from our contacts" -msgstr "Ainoastaan tuo OStatus -ketjuja kontakteiltamme" - -#: mod/admin.php:1410 -msgid "" -"Normally we import every content from our OStatus contacts. With this option" -" we only store threads that are started by a contact that is known on our " -"system." -msgstr "" - -#: mod/admin.php:1411 -msgid "OStatus support can only be enabled if threading is enabled." -msgstr "OStatus-tuki voidaan ottaa käyttöön ainoastaan jos ketjuttaminen on jo otettu käyttöön." - -#: mod/admin.php:1413 -msgid "" -"Diaspora support can't be enabled because Friendica was installed into a sub" -" directory." -msgstr "Diaspora -tukea ei voitu ottaa käyttöön koska Friendica on asennettu alihakemistoon." - -#: mod/admin.php:1414 -msgid "Enable Diaspora support" -msgstr "Salli Diaspora-tuki" - -#: mod/admin.php:1414 -msgid "Provide built-in Diaspora network compatibility." -msgstr "Ota käyttöön Diaspora-yhteensopivuus" - -#: mod/admin.php:1415 -msgid "Only allow Friendica contacts" -msgstr "Salli ainoastaan Friendica -kontakteja" - -#: mod/admin.php:1415 -msgid "" -"All contacts must use Friendica protocols. All other built-in communication " -"protocols disabled." -msgstr "Kaikkien kontaktien on käytettävä Friendica-protokollaa. Kaikki muut protokollat poistetaan käytöstä." - -#: mod/admin.php:1416 -msgid "Verify SSL" -msgstr "Vahvista SSL" - -#: mod/admin.php:1416 -msgid "" -"If you wish, you can turn on strict certificate checking. This will mean you" -" cannot connect (at all) to self-signed SSL sites." -msgstr "" - -#: mod/admin.php:1417 -msgid "Proxy user" -msgstr "Välityspalvelimen käyttäjä" - -#: mod/admin.php:1418 -msgid "Proxy URL" -msgstr "Välityspalvelimen osoite" - -#: mod/admin.php:1419 -msgid "Network timeout" -msgstr "Verkon aikakatkaisu" - -#: mod/admin.php:1419 -msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." -msgstr "" - -#: mod/admin.php:1420 -msgid "Maximum Load Average" -msgstr "Kuorman enimmäiskeksiarvo" - -#: mod/admin.php:1420 -msgid "" -"Maximum system load before delivery and poll processes are deferred - " -"default 50." -msgstr "Järjestelmäkuormitus jolloin lähetys- ja kyselyprosessit lykätään (oletusarvo 50)." - -#: mod/admin.php:1421 -msgid "Maximum Load Average (Frontend)" -msgstr "Kuorman enimmäiskeskiarvo (Frontend)" - -#: mod/admin.php:1421 -msgid "Maximum system load before the frontend quits service - default 50." -msgstr "Järjestelmäkuormitus jolloin Frontend poistetaan käytöstä (oletusarvo 50)." - -#: mod/admin.php:1422 -msgid "Minimal Memory" -msgstr "" - -#: mod/admin.php:1422 -msgid "" -"Minimal free memory in MB for the worker. Needs access to /proc/meminfo - " -"default 0 (deactivated)." -msgstr "" - -#: mod/admin.php:1423 -msgid "Maximum table size for optimization" -msgstr "Taulukon enimmäiskoko optimointia varten" - -#: mod/admin.php:1423 -msgid "" -"Maximum table size (in MB) for the automatic optimization. Enter -1 to " -"disable it." -msgstr "" - -#: mod/admin.php:1424 -msgid "Minimum level of fragmentation" -msgstr "" - -#: mod/admin.php:1424 -msgid "" -"Minimum fragmenation level to start the automatic optimization - default " -"value is 30%." -msgstr "" - -#: mod/admin.php:1426 -msgid "Periodical check of global contacts" -msgstr "" - -#: mod/admin.php:1426 -msgid "" -"If enabled, the global contacts are checked periodically for missing or " -"outdated data and the vitality of the contacts and servers." -msgstr "" - -#: mod/admin.php:1427 -msgid "Days between requery" -msgstr "" - -#: mod/admin.php:1427 -msgid "Number of days after which a server is requeried for his contacts." -msgstr "" - -#: mod/admin.php:1428 -msgid "Discover contacts from other servers" -msgstr "Etsi kontakteja muilta palvelimilta" - -#: mod/admin.php:1428 -msgid "" -"Periodically query other servers for contacts. You can choose between " -"'users': the users on the remote system, 'Global Contacts': active contacts " -"that are known on the system. The fallback is meant for Redmatrix servers " -"and older friendica servers, where global contacts weren't available. The " -"fallback increases the server load, so the recommened setting is 'Users, " -"Global Contacts'." -msgstr "" - -#: mod/admin.php:1429 -msgid "Timeframe for fetching global contacts" -msgstr "" - -#: mod/admin.php:1429 -msgid "" -"When the discovery is activated, this value defines the timeframe for the " -"activity of the global contacts that are fetched from other servers." -msgstr "" - -#: mod/admin.php:1430 -msgid "Search the local directory" -msgstr "Paikallisluettelohaku" - -#: mod/admin.php:1430 -msgid "" -"Search the local directory instead of the global directory. When searching " -"locally, every search will be executed on the global directory in the " -"background. This improves the search results when the search is repeated." -msgstr "" - -#: mod/admin.php:1432 -msgid "Publish server information" -msgstr "Julkaise palvelintiedot" - -#: mod/admin.php:1432 -msgid "" -"If enabled, general server and usage data will be published. The data " -"contains the name and version of the server, number of users with public " -"profiles, number of posts and the activated protocols and connectors. See the-federation.info for details." -msgstr "" - -#: mod/admin.php:1434 -msgid "Check upstream version" -msgstr "" - -#: mod/admin.php:1434 -msgid "" -"Enables checking for new Friendica versions at github. If there is a new " -"version, you will be informed in the admin panel overview." -msgstr "" - -#: mod/admin.php:1435 -msgid "Suppress Tags" -msgstr "Piilota tunnisteet" - -#: mod/admin.php:1435 -msgid "Suppress showing a list of hashtags at the end of the posting." -msgstr "Piilota tunnistelista julkaisun lopussa." - -#: mod/admin.php:1436 -msgid "Clean database" -msgstr "Siivoa tietokanta" - -#: mod/admin.php:1436 -msgid "" -"Remove old remote items, orphaned database records and old content from some" -" other helper tables." -msgstr "" - -#: mod/admin.php:1437 -msgid "Lifespan of remote items" -msgstr "" - -#: mod/admin.php:1437 -msgid "" -"When the database cleanup is enabled, this defines the days after which " -"remote items will be deleted. Own items, and marked or filed items are " -"always kept. 0 disables this behaviour." -msgstr "" - -#: mod/admin.php:1438 -msgid "Lifespan of unclaimed items" -msgstr "" - -#: mod/admin.php:1438 -msgid "" -"When the database cleanup is enabled, this defines the days after which " -"unclaimed remote items (mostly content from the relay) will be deleted. " -"Default value is 90 days. Defaults to the general lifespan value of remote " -"items if set to 0." -msgstr "" - -#: mod/admin.php:1439 -msgid "Path to item cache" -msgstr "" - -#: mod/admin.php:1439 -msgid "The item caches buffers generated bbcode and external images." -msgstr "" - -#: mod/admin.php:1440 -msgid "Cache duration in seconds" -msgstr "Välimuistin kesto sekunteina" - -#: mod/admin.php:1440 -msgid "" -"How long should the cache files be hold? Default value is 86400 seconds (One" -" day). To disable the item cache, set the value to -1." -msgstr "" - -#: mod/admin.php:1441 -msgid "Maximum numbers of comments per post" -msgstr "Julkaisun kommentiraja" - -#: mod/admin.php:1441 -msgid "How much comments should be shown for each post? Default value is 100." -msgstr "" - -#: mod/admin.php:1442 -msgid "Temp path" -msgstr "Väliaikaistiedostojen polku" - -#: mod/admin.php:1442 -msgid "" -"If you have a restricted system where the webserver can't access the system " -"temp path, enter another path here." -msgstr "Mikäli verkkopalvelimesi ei voi käyttää järjestelmän väliaikaistiedostojen polkua, syötä toinen polku tähän." - -#: mod/admin.php:1443 -msgid "Base path to installation" -msgstr "Asennuksen peruspolku" - -#: mod/admin.php:1443 -msgid "" -"If the system cannot detect the correct path to your installation, enter the" -" correct path here. This setting should only be set if you are using a " -"restricted system and symbolic links to your webroot." -msgstr "" - -#: mod/admin.php:1444 -msgid "Disable picture proxy" -msgstr "" - -#: mod/admin.php:1444 -msgid "" -"The picture proxy increases performance and privacy. It shouldn't be used on" -" systems with very low bandwidth." -msgstr "" - -#: mod/admin.php:1445 -msgid "Only search in tags" -msgstr "Tunnistehaku" - -#: mod/admin.php:1445 -msgid "On large systems the text search can slow down the system extremely." -msgstr "" - -#: mod/admin.php:1447 -msgid "New base url" -msgstr "Uusi perusosoite" - -#: mod/admin.php:1447 -msgid "" -"Change base url for this server. Sends relocate message to all Friendica and" -" Diaspora* contacts of all users." -msgstr "Vaihtaa tämän palvelimen perus-URL-osoitteen. Lähettää uudelleensijoitusviestit käyttäjien kaikille kontakteille Friendicassa ja Diasporassa*." - -#: mod/admin.php:1449 -msgid "RINO Encryption" -msgstr "RINO-salaus" - -#: mod/admin.php:1449 -msgid "Encryption layer between nodes." -msgstr "Salauskerros solmujen välillä." - -#: mod/admin.php:1449 -msgid "Enabled" -msgstr "Käytössä" - -#: mod/admin.php:1451 -msgid "Maximum number of parallel workers" -msgstr "Enimmäismäärä rinnakkaisia workereitä" - -#: mod/admin.php:1451 -msgid "" -"On shared hosters set this to 2. On larger systems, values of 10 are great. " -"Default value is 4." -msgstr "" - -#: mod/admin.php:1452 -msgid "Don't use 'proc_open' with the worker" -msgstr "" - -#: mod/admin.php:1452 -msgid "" -"Enable this if your system doesn't allow the use of 'proc_open'. This can " -"happen on shared hosters. If this is enabled you should increase the " -"frequency of worker calls in your crontab." -msgstr "" - -#: mod/admin.php:1453 -msgid "Enable fastlane" -msgstr "Käytä fastlane" - -#: mod/admin.php:1453 -msgid "" -"When enabed, the fastlane mechanism starts an additional worker if processes" -" with higher priority are blocked by processes of lower priority." -msgstr "" - -#: mod/admin.php:1454 -msgid "Enable frontend worker" -msgstr "Ota Frontend Worker käyttöön" - -#: mod/admin.php:1454 -#, php-format -msgid "" -"When enabled the Worker process is triggered when backend access is " -"performed \\x28e.g. messages being delivered\\x29. On smaller sites you " -"might want to call %s/worker on a regular basis via an external cron job. " -"You should only enable this option if you cannot utilize cron/scheduled jobs" -" on your server." -msgstr "" - -#: mod/admin.php:1456 -msgid "Subscribe to relay" -msgstr "Relen tilaus" - -#: mod/admin.php:1456 -msgid "" -"Enables the receiving of public posts from the relay. They will be included " -"in the search, subscribed tags and on the global community page." -msgstr "" - -#: mod/admin.php:1457 -msgid "Relay server" -msgstr "Relepalvelin" - -#: mod/admin.php:1457 -msgid "" -"Address of the relay server where public posts should be send to. For " -"example https://relay.diasp.org" -msgstr "" - -#: mod/admin.php:1458 -msgid "Direct relay transfer" -msgstr "Suora releen siirto" - -#: mod/admin.php:1458 -msgid "" -"Enables the direct transfer to other servers without using the relay servers" -msgstr "" - -#: mod/admin.php:1459 -msgid "Relay scope" -msgstr "Relen soveltamisala" - -#: mod/admin.php:1459 -msgid "" -"Can be 'all' or 'tags'. 'all' means that every public post should be " -"received. 'tags' means that only posts with selected tags should be " -"received." -msgstr "" - -#: mod/admin.php:1459 -msgid "all" -msgstr "kaikki" - -#: mod/admin.php:1459 -msgid "tags" -msgstr "tunnisteet" - -#: mod/admin.php:1460 -msgid "Server tags" -msgstr "palvelintunnisteet" - -#: mod/admin.php:1460 -msgid "Comma separated list of tags for the 'tags' subscription." -msgstr "Pilkulla erotettu tunnistelista tunnistetilausta varten." - -#: mod/admin.php:1461 -msgid "Allow user tags" -msgstr "Salli käyttäjien tunnisteet" - -#: mod/admin.php:1461 -msgid "" -"If enabled, the tags from the saved searches will used for the 'tags' " -"subscription in addition to the 'relay_server_tags'." -msgstr "Jos otettu käyttöön, tunnisteet tallennetuista hauista käytetään tunnistetilaukseen 'relay_server_tags'in lisäksi." - -#: mod/admin.php:1489 -msgid "Update has been marked successful" -msgstr "" - -#: mod/admin.php:1496 -#, php-format -msgid "Database structure update %s was successfully applied." -msgstr "Tietokannan rakenteen %s-päivitys onnistui." - -#: mod/admin.php:1499 -#, php-format -msgid "Executing of database structure update %s failed with error: %s" -msgstr "Tietokannan rakennepäivitys %s epäonnistui virheviestillä %s" - -#: mod/admin.php:1515 -#, php-format -msgid "Executing %s failed with error: %s" -msgstr "" - -#: mod/admin.php:1517 -#, php-format -msgid "Update %s was successfully applied." -msgstr "%s-päivitys onnistui." - -#: mod/admin.php:1520 -#, php-format -msgid "Update %s did not return a status. Unknown if it succeeded." -msgstr "" - -#: mod/admin.php:1523 -#, php-format -msgid "There was no additional update function %s that needed to be called." -msgstr "" - -#: mod/admin.php:1546 -msgid "No failed updates." -msgstr "Ei epäonnistuineita päivityksiä." - -#: mod/admin.php:1547 -msgid "Check database structure" -msgstr "Tarkista tietokannan rakenne" - -#: mod/admin.php:1552 -msgid "Failed Updates" -msgstr "Epäonnistuineita päivityksiä" - -#: mod/admin.php:1553 -msgid "" -"This does not include updates prior to 1139, which did not return a status." -msgstr "" - -#: mod/admin.php:1554 -msgid "Mark success (if update was manually applied)" -msgstr "" - -#: mod/admin.php:1555 -msgid "Attempt to execute this update step automatically" -msgstr "" - -#: mod/admin.php:1594 -#, php-format -msgid "" -"\n" -"\t\t\tDear %1$s,\n" -"\t\t\t\tthe administrator of %2$s has set up an account for you." -msgstr "" - -#: mod/admin.php:1597 -#, php-format -msgid "" -"\n" -"\t\t\tThe login details are as follows:\n" -"\n" -"\t\t\tSite Location:\t%1$s\n" -"\t\t\tLogin Name:\t\t%2$s\n" -"\t\t\tPassword:\t\t%3$s\n" -"\n" -"\t\t\tYou may change your password from your account \"Settings\" page after logging\n" -"\t\t\tin.\n" -"\n" -"\t\t\tPlease take a few moments to review the other account settings on that page.\n" -"\n" -"\t\t\tYou may also wish to add some basic information to your default profile\n" -"\t\t\t(on the \"Profiles\" page) so that other people can easily find you.\n" -"\n" -"\t\t\tWe recommend setting your full name, adding a profile photo,\n" -"\t\t\tadding some profile \"keywords\" (very useful in making new friends) - and\n" -"\t\t\tperhaps what country you live in; if you do not wish to be more specific\n" -"\t\t\tthan that.\n" -"\n" -"\t\t\tWe fully respect your right to privacy, and none of these items are necessary.\n" -"\t\t\tIf you are new and do not know anybody here, they may help\n" -"\t\t\tyou to make some new and interesting friends.\n" -"\n" -"\t\t\tIf you ever want to delete your account, you can do so at %1$s/removeme\n" -"\n" -"\t\t\tThank you and welcome to %4$s." -msgstr "" - -#: mod/admin.php:1631 src/Model/User.php:665 -#, php-format -msgid "Registration details for %s" -msgstr "" - -#: mod/admin.php:1641 -#, php-format -msgid "%s user blocked/unblocked" -msgid_plural "%s users blocked/unblocked" -msgstr[0] "%s käyttäjä estetty / poistettu estolistalta" -msgstr[1] "%s käyttäjää estetty / poistettu estolistalta" - -#: mod/admin.php:1647 -#, php-format -msgid "%s user deleted" -msgid_plural "%s users deleted" -msgstr[0] "%s käyttäjä poistettu" -msgstr[1] "%s käyttäjää poistettu" - -#: mod/admin.php:1694 -#, php-format -msgid "User '%s' deleted" -msgstr "Käyttäjä '%s' poistettu" - -#: mod/admin.php:1702 -#, php-format -msgid "User '%s' unblocked" -msgstr "Käyttäjä '%s' poistettu estolistalta" - -#: mod/admin.php:1702 -#, php-format -msgid "User '%s' blocked" -msgstr "Käyttäjä '%s' estetty" - -#: mod/admin.php:1759 mod/settings.php:1058 -msgid "Normal Account Page" -msgstr "Tavallinen käyttäjätili" - -#: mod/admin.php:1760 mod/settings.php:1062 -msgid "Soapbox Page" -msgstr "Saarnatuoli sivu" - -#: mod/admin.php:1761 mod/settings.php:1066 -msgid "Public Forum" -msgstr "Julkinen foorumi" - -#: mod/admin.php:1762 mod/settings.php:1070 -msgid "Automatic Friend Page" -msgstr "" - -#: mod/admin.php:1763 -msgid "Private Forum" -msgstr "Yksityisfoorumi" - -#: mod/admin.php:1766 mod/settings.php:1042 -msgid "Personal Page" -msgstr "Henkilökohtainen sivu" - -#: mod/admin.php:1767 mod/settings.php:1046 -msgid "Organisation Page" -msgstr "Järjestön sivu" - -#: mod/admin.php:1768 mod/settings.php:1050 -msgid "News Page" -msgstr "Uutissivu" - -#: mod/admin.php:1769 mod/settings.php:1054 -msgid "Community Forum" -msgstr "Yhteisöfoorumi" - -#: mod/admin.php:1816 mod/admin.php:1827 mod/admin.php:1840 mod/admin.php:1858 -#: src/Content/ContactSelector.php:82 -msgid "Email" -msgstr "Sähköposti" - -#: mod/admin.php:1816 mod/admin.php:1840 -msgid "Register date" -msgstr "Rekisteripäivämäärä" - -#: mod/admin.php:1816 mod/admin.php:1840 -msgid "Last login" -msgstr "Viimeisin kirjautuminen" - -#: mod/admin.php:1816 mod/admin.php:1840 -msgid "Last item" -msgstr "Viimeisin kohde" - -#: mod/admin.php:1816 -msgid "Type" -msgstr "Tyyppi" - -#: mod/admin.php:1823 -msgid "Add User" -msgstr "Lisää käyttäjä" - -#: mod/admin.php:1825 -msgid "User registrations waiting for confirm" -msgstr "" - -#: mod/admin.php:1826 -msgid "User waiting for permanent deletion" -msgstr "" - -#: mod/admin.php:1827 -msgid "Request date" -msgstr "Pyynnön päivämäärä" - -#: mod/admin.php:1828 -msgid "No registrations." -msgstr "Ei rekisteröintejä." - -#: mod/admin.php:1829 -msgid "Note from the user" -msgstr "" - -#: mod/admin.php:1830 mod/notifications.php:178 mod/notifications.php:262 -msgid "Approve" -msgstr "Hyväksy" - -#: mod/admin.php:1831 -msgid "Deny" -msgstr "Kieltäydy" - -#: mod/admin.php:1835 -msgid "Site admin" -msgstr "Sivuston ylläpito" - -#: mod/admin.php:1836 -msgid "Account expired" -msgstr "Tili vanhentunut" - -#: mod/admin.php:1839 -msgid "New User" -msgstr "Uusi käyttäjä" - -#: mod/admin.php:1840 -msgid "Deleted since" -msgstr "Poistettu" - -#: mod/admin.php:1845 -msgid "" -"Selected users will be deleted!\\n\\nEverything these users had posted on " -"this site will be permanently deleted!\\n\\nAre you sure?" -msgstr "" - -#: mod/admin.php:1846 -msgid "" -"The user {0} will be deleted!\\n\\nEverything this user has posted on this " -"site will be permanently deleted!\\n\\nAre you sure?" -msgstr "" - -#: mod/admin.php:1856 -msgid "Name of the new user." -msgstr "Uuden käyttäjän nimi." - -#: mod/admin.php:1857 -msgid "Nickname" -msgstr "Lempinimi" - -#: mod/admin.php:1857 -msgid "Nickname of the new user." -msgstr "Uuden käyttäjän lempinimi" - -#: mod/admin.php:1858 -msgid "Email address of the new user." -msgstr "Uuden käyttäjän sähköpostiosoite." - -#: mod/admin.php:1900 -#, php-format -msgid "Addon %s disabled." -msgstr "Lisäosa %s poistettu käytöstä." - -#: mod/admin.php:1904 -#, php-format -msgid "Addon %s enabled." -msgstr "Lisäosa %s käytössä." - -#: mod/admin.php:1914 mod/admin.php:2163 -msgid "Disable" -msgstr "Poista käytöstä" - -#: mod/admin.php:1917 mod/admin.php:2166 -msgid "Enable" -msgstr "Ota käyttöön" - -#: mod/admin.php:1939 mod/admin.php:2209 -msgid "Toggle" -msgstr "Vaihda" - -#: mod/admin.php:1947 mod/admin.php:2218 -msgid "Author: " -msgstr "Tekijä" - -#: mod/admin.php:1948 mod/admin.php:2219 -msgid "Maintainer: " -msgstr "Ylläpitäjä:" - -#: mod/admin.php:2000 -msgid "Reload active addons" -msgstr "" - -#: mod/admin.php:2005 -#, php-format -msgid "" -"There are currently no addons available on your node. You can find the " -"official addon repository at %1$s and might find other interesting addons in" -" the open addon registry at %2$s" -msgstr "" - -#: mod/admin.php:2125 -msgid "No themes found." -msgstr "Teemoja ei löytynyt." - -#: mod/admin.php:2200 -msgid "Screenshot" -msgstr "Kuvakaappaus" - -#: mod/admin.php:2254 -msgid "Reload active themes" -msgstr "Lataa aktiiviset teemat uudelleen" - -#: mod/admin.php:2259 -#, php-format -msgid "No themes found on the system. They should be placed in %1$s" -msgstr "Teemoja ei löytynyt järjestelmästä. Teemat tulisi laittaa kansioon %1$s" - -#: mod/admin.php:2260 -msgid "[Experimental]" -msgstr "[Kokeellinen]" - -#: mod/admin.php:2261 -msgid "[Unsupported]" -msgstr "[Ei tueta]" - -#: mod/admin.php:2285 -msgid "Log settings updated." -msgstr "Lokiasetukset päivitetty." - -#: mod/admin.php:2317 -msgid "PHP log currently enabled." -msgstr "PHP-loki käytössä" - -#: mod/admin.php:2319 -msgid "PHP log currently disabled." -msgstr "PHP-loki pois käytöstä" - -#: mod/admin.php:2328 -msgid "Clear" -msgstr "Tyhjennä" - -#: mod/admin.php:2332 -msgid "Enable Debugging" -msgstr "Ota virheenkorjaustila käyttöön" - -#: mod/admin.php:2333 -msgid "Log file" -msgstr "Lokitiedosto" - -#: mod/admin.php:2333 -msgid "" -"Must be writable by web server. Relative to your Friendica top-level " -"directory." -msgstr "" - -#: mod/admin.php:2334 -msgid "Log level" -msgstr "Lokitaso" - -#: mod/admin.php:2336 -msgid "PHP logging" -msgstr "PHP-loki" - -#: mod/admin.php:2337 -msgid "" -"To enable logging of PHP errors and warnings you can add the following to " -"the .htconfig.php file of your installation. The filename set in the " -"'error_log' line is relative to the friendica top-level directory and must " -"be writeable by the web server. The option '1' for 'log_errors' and " -"'display_errors' is to enable these options, set to '0' to disable them." -msgstr "" - -#: mod/admin.php:2368 -#, php-format -msgid "" -"Error trying to open %1$s log file.\\r\\n
Check to see " -"if file %1$s exist and is readable." -msgstr "" - -#: mod/admin.php:2372 -#, php-format -msgid "" -"Couldn't open %1$s log file.\\r\\n
Check to see if file" -" %1$s is readable." -msgstr "" - -#: mod/admin.php:2463 mod/admin.php:2464 mod/settings.php:767 -msgid "Off" -msgstr "Pois päältä" - -#: mod/admin.php:2463 mod/admin.php:2464 mod/settings.php:767 -msgid "On" -msgstr "Päällä" - -#: mod/admin.php:2464 -#, php-format -msgid "Lock feature %s" -msgstr "Lukitse ominaisuus %s" - -#: mod/admin.php:2472 -msgid "Manage Additional Features" -msgstr "Hallitse lisäominaisuudet" - -#: mod/community.php:51 -msgid "Community option not available." -msgstr "Yhteisö vaihtoehto ei saatavilla." - -#: mod/community.php:68 -msgid "Not available." -msgstr "Ei saatavilla." - -#: mod/community.php:81 -msgid "Local Community" -msgstr "Paikallinen yhteisö" - -#: mod/community.php:84 -msgid "Posts from local users on this server" -msgstr "Tämän palvelimen julkaisut" - -#: mod/community.php:92 -msgid "Global Community" -msgstr "Maailmanlaajuinen yhteisö" - -#: mod/community.php:95 -msgid "Posts from users of the whole federated network" -msgstr "Maailmanlaajuisen verkon julkaisut" - -#: mod/community.php:141 mod/search.php:228 -msgid "No results." -msgstr "Ei tuloksia." - -#: mod/community.php:185 -msgid "" -"This community stream shows all public posts received by this node. They may" -" not reflect the opinions of this node’s users." -msgstr "" - -#: mod/dfrn_confirm.php:74 mod/profiles.php:39 mod/profiles.php:149 -#: mod/profiles.php:196 mod/profiles.php:525 -msgid "Profile not found." -msgstr "Profiilia ei löytynyt." - -#: mod/dfrn_confirm.php:130 -msgid "" -"This may occasionally happen if contact was requested by both persons and it" -" has already been approved." -msgstr "" - -#: mod/dfrn_confirm.php:240 -msgid "Response from remote site was not understood." -msgstr "Etäsivuston vastaus oli epäselvä." - -#: mod/dfrn_confirm.php:247 mod/dfrn_confirm.php:252 -msgid "Unexpected response from remote site: " -msgstr "Odottamaton vastaus etäsivustolta:" - -#: mod/dfrn_confirm.php:261 -msgid "Confirmation completed successfully." -msgstr "Vahvistus onnistui." - -#: mod/dfrn_confirm.php:273 -msgid "Temporary failure. Please wait and try again." -msgstr "Tilapäinen vika. Yritä myöhemmin uudelleen." - -#: mod/dfrn_confirm.php:276 -msgid "Introduction failed or was revoked." -msgstr "Kaverikutsu epäonnistui tai oli peruutettu." - -#: mod/dfrn_confirm.php:281 -msgid "Remote site reported: " -msgstr "" - -#: mod/dfrn_confirm.php:392 -msgid "Unable to set contact photo." -msgstr "Kontaktin kuvaa ei voitu asettaa" - -#: mod/dfrn_confirm.php:450 -#, php-format -msgid "No user record found for '%s' " -msgstr "" - -#: mod/dfrn_confirm.php:460 -msgid "Our site encryption key is apparently messed up." -msgstr "Sivustomme salausavain on sekaisin." - -#: mod/dfrn_confirm.php:471 -msgid "Empty site URL was provided or URL could not be decrypted by us." -msgstr "" - -#: mod/dfrn_confirm.php:487 -msgid "Contact record was not found for you on our site." -msgstr "" - -#: mod/dfrn_confirm.php:501 -#, php-format -msgid "Site public key not available in contact record for URL %s." -msgstr "" - -#: mod/dfrn_confirm.php:517 -msgid "" -"The ID provided by your system is a duplicate on our system. It should work " -"if you try again." -msgstr "" - -#: mod/dfrn_confirm.php:528 -msgid "Unable to set your contact credentials on our system." -msgstr "" - -#: mod/dfrn_confirm.php:583 -msgid "Unable to update your contact profile details on our system" -msgstr "" - -#: mod/dfrn_confirm.php:613 mod/dfrn_request.php:564 -#: src/Model/Contact.php:1578 -msgid "[Name Withheld]" -msgstr "[Nimi jätetty pois]" - -#: mod/dfrn_request.php:94 -msgid "This introduction has already been accepted." -msgstr "Tämä esittely on jo hyväksytty." - -#: mod/dfrn_request.php:112 mod/dfrn_request.php:355 -msgid "Profile location is not valid or does not contain profile information." -msgstr "Profiilin sijainti on viallinen tai se ei sisällä profiilitietoja." - -#: mod/dfrn_request.php:116 mod/dfrn_request.php:359 -msgid "Warning: profile location has no identifiable owner name." -msgstr "Varoitus: profiilin sijainnissa ei ole tunnistettavaa omistajan nimeä." - -#: mod/dfrn_request.php:119 mod/dfrn_request.php:362 -msgid "Warning: profile location has no profile photo." -msgstr "Varoitus: profiilin sijainnissa ei ole profiilikuvaa." - -#: mod/dfrn_request.php:123 mod/dfrn_request.php:366 -#, php-format -msgid "%d required parameter was not found at the given location" -msgid_plural "%d required parameters were not found at the given location" -msgstr[0] "" -msgstr[1] "" - -#: mod/dfrn_request.php:162 -msgid "Introduction complete." -msgstr "Esittely valmis." - -#: mod/dfrn_request.php:199 -msgid "Unrecoverable protocol error." -msgstr "Vakava protokollavirhe." - -#: mod/dfrn_request.php:226 -msgid "Profile unavailable." -msgstr "Profiili ei saatavilla." - -#: mod/dfrn_request.php:248 -#, php-format -msgid "%s has received too many connection requests today." -msgstr "%s on saanut liikaa yhteyspyyntöjä tänään." - -#: mod/dfrn_request.php:249 -msgid "Spam protection measures have been invoked." -msgstr "Roskapostisuojaukset otettu käyttöön." - -#: mod/dfrn_request.php:250 -msgid "Friends are advised to please try again in 24 hours." -msgstr "Ystäviä suositellaan yrittämään uudelleen vuorokauden sisällä." - -#: mod/dfrn_request.php:276 -msgid "Invalid locator" -msgstr "Viallinen paikannin" - -#: mod/dfrn_request.php:312 -msgid "You have already introduced yourself here." -msgstr "Olet jo esitellyt itsesi täällä." - -#: mod/dfrn_request.php:315 -#, php-format -msgid "Apparently you are already friends with %s." -msgstr "Ilmeisesti olet jo ystävystynyt henkilön %s kanssa." - -#: mod/dfrn_request.php:335 -msgid "Invalid profile URL." -msgstr "Viallinen profiiliosoite." - -#: mod/dfrn_request.php:341 src/Model/Contact.php:1276 -msgid "Disallowed profile URL." -msgstr "Kielletty profiiliosoite." - -#: mod/dfrn_request.php:435 -msgid "Your introduction has been sent." -msgstr "Esittelysi lähetettiin." - -#: mod/dfrn_request.php:473 -msgid "" -"Remote subscription can't be done for your network. Please subscribe " -"directly on your system." -msgstr "" - -#: mod/dfrn_request.php:489 -msgid "Please login to confirm introduction." -msgstr "Kirjaudu vahvistaaksesi esittelysi." - -#: mod/dfrn_request.php:497 -msgid "" -"Incorrect identity currently logged in. Please login to " -"this profile." -msgstr "Väärä identiteetti kirjautuneena sisään. Kirjaudu tähän profiiliin." - -#: mod/dfrn_request.php:511 mod/dfrn_request.php:528 -msgid "Confirm" -msgstr "Vahvista" - -#: mod/dfrn_request.php:523 -msgid "Hide this contact" -msgstr "Piilota kontakti" - -#: mod/dfrn_request.php:526 -#, php-format -msgid "Welcome home %s." -msgstr "Tervetuloa kotiin %s." - -#: mod/dfrn_request.php:527 -#, php-format -msgid "Please confirm your introduction/connection request to %s." -msgstr "Vahvista esittelysi/yhteyspyyntösi henkilölle %s." - -#: mod/dfrn_request.php:637 -msgid "" -"Please enter your 'Identity Address' from one of the following supported " -"communications networks:" -msgstr "Anna \"henkilöllisyysosoitteesi\" joissakin seuraavista tuetuista viestintäverkoista:" - -#: mod/dfrn_request.php:640 -#, php-format -msgid "" -"If you are not yet a member of the free social web, follow " -"this link to find a public Friendica site and join us today." -msgstr "" - -#: mod/dfrn_request.php:645 -msgid "Friend/Connection Request" -msgstr "Ystävä/yhteyspyyntö" - -#: mod/dfrn_request.php:646 -msgid "" -"Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, " -"testuser@gnusocial.de" -msgstr "Esim. jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@gnusocial.de" - -#: mod/dfrn_request.php:651 src/Content/ContactSelector.php:79 -msgid "Friendica" -msgstr "Friendica" - -#: mod/dfrn_request.php:652 -msgid "GNU Social (Pleroma, Mastodon)" -msgstr "GNU Social (Pleroma, Mastodon)" - -#: mod/dfrn_request.php:653 -msgid "Diaspora (Socialhome, Hubzilla)" -msgstr "Diaspora (Socialhome, Hubzilla)" - -#: mod/dfrn_request.php:654 -#, php-format -msgid "" -" - please do not use this form. Instead, enter %s into your Diaspora search" -" bar." -msgstr " - älä käytä tätä lomaketta. Kirjoita sen sijaan %s Diaspora-hakupalkkiisi." - -#: mod/events.php:105 mod/events.php:107 -msgid "Event can not end before it has started." -msgstr "Tapahtuma ei voi päättyä ennen kuin on alkanut." - -#: mod/events.php:114 mod/events.php:116 -msgid "Event title and start time are required." -msgstr "Tapahtuman nimi ja alkamisaika vaaditaan." - -#: mod/events.php:393 -msgid "Create New Event" -msgstr "Luo uusi tapahtuma" - -#: mod/events.php:507 -msgid "Event details" -msgstr "Tapahtuman tiedot" - -#: mod/events.php:508 -msgid "Starting date and Title are required." -msgstr "Aloituspvm ja otsikko vaaditaan." - -#: mod/events.php:509 mod/events.php:510 -msgid "Event Starts:" -msgstr "Tapahtuma alkaa:" - -#: mod/events.php:509 mod/events.php:521 mod/profiles.php:607 -msgid "Required" -msgstr "Vaaditaan" - -#: mod/events.php:511 mod/events.php:527 -msgid "Finish date/time is not known or not relevant" -msgstr "Päättymispvm ja kellonaika ei ole tiedossa tai niillä ei ole merkitystä" - -#: mod/events.php:513 mod/events.php:514 -msgid "Event Finishes:" -msgstr "Tapahtuma päättyy:" - -#: mod/events.php:515 mod/events.php:528 -msgid "Adjust for viewer timezone" -msgstr "Ota huomioon katsojan aikavyöhyke" - -#: mod/events.php:517 -msgid "Description:" -msgstr "Kuvaus:" - -#: mod/events.php:521 mod/events.php:523 -msgid "Title:" -msgstr "Otsikko:" - -#: mod/events.php:524 mod/events.php:525 -msgid "Share this event" -msgstr "Jaa tämä tapahtuma" - -#: mod/events.php:532 src/Model/Profile.php:862 -msgid "Basic" -msgstr "" - -#: mod/events.php:534 mod/photos.php:1086 mod/photos.php:1435 -#: src/Core/ACL.php:318 -msgid "Permissions" -msgstr "Käyttöoikeudet" - -#: mod/events.php:553 -msgid "Failed to remove event" -msgstr "Tapahtuman poisto epäonnistui" - -#: mod/events.php:555 -msgid "Event removed" -msgstr "Tapahtuma poistettu" - -#: mod/group.php:36 -msgid "Group created." -msgstr "Ryhmä luotu." - -#: mod/group.php:42 -msgid "Could not create group." -msgstr "Ryhmää ei voitu luoda." - -#: mod/group.php:56 mod/group.php:157 -msgid "Group not found." -msgstr "Ryhmää ei löytynyt." - -#: mod/group.php:70 -msgid "Group name changed." -msgstr "Ryhmän nimi muutettu." - -#: mod/group.php:97 -msgid "Save Group" -msgstr "Tallenna ryhmä" - -#: mod/group.php:102 -msgid "Create a group of contacts/friends." -msgstr "Luo kontakti/kaveriryhmä" - -#: mod/group.php:103 mod/group.php:199 src/Model/Group.php:421 -msgid "Group Name: " -msgstr "Ryhmän nimi:" - -#: mod/group.php:127 -msgid "Group removed." -msgstr "Ryhmä poistettu." - -#: mod/group.php:129 -msgid "Unable to remove group." -msgstr "Ryhmää ei voida poistaa." - -#: mod/group.php:192 -msgid "Delete Group" -msgstr "Poista ryhmä" - -#: mod/group.php:198 -msgid "Group Editor" -msgstr "Ryhmien muokkausta" - -#: mod/group.php:203 -msgid "Edit Group Name" -msgstr "Muokkaa ryhmän nimeä" - -#: mod/group.php:213 -msgid "Members" -msgstr "Jäsenet" - -#: mod/group.php:216 mod/network.php:639 -msgid "Group is empty" -msgstr "Ryhmä on tyhjä" - -#: mod/group.php:229 -msgid "Remove contact from group" -msgstr "Poista kontakti ryhmästä" - -#: mod/group.php:253 -msgid "Add contact to group" -msgstr "Lisää kontakti ryhmään" - -#: mod/item.php:114 -msgid "Unable to locate original post." -msgstr "Alkuperäinen julkaisu ei löydy." - -#: mod/item.php:274 -msgid "Empty post discarded." -msgstr "Tyhjä julkaisu hylätty." - -#: mod/item.php:804 -#, php-format -msgid "" -"This message was sent to you by %s, a member of the Friendica social " -"network." -msgstr "Viestin lähetti %s Friendica sosiaaliverkoston kautta." - -#: mod/item.php:806 -#, php-format -msgid "You may visit them online at %s" -msgstr "" - -#: mod/item.php:807 -msgid "" -"Please contact the sender by replying to this post if you do not wish to " -"receive these messages." -msgstr "" - -#: mod/item.php:811 -#, php-format -msgid "%s posted an update." -msgstr "%s julkaisi päivityksen." - -#: mod/network.php:194 mod/search.php:37 -msgid "Remove term" -msgstr "Poista kohde" - -#: mod/network.php:201 mod/search.php:46 src/Content/Feature.php:100 -msgid "Saved Searches" -msgstr "Tallennetut haut" - -#: mod/network.php:202 src/Model/Group.php:413 -msgid "add" -msgstr "lisää" - -#: mod/network.php:547 -#, php-format -msgid "" -"Warning: This group contains %s member from a network that doesn't allow non" -" public messages." -msgid_plural "" -"Warning: This group contains %s members from a network that doesn't allow " -"non public messages." -msgstr[0] "" -msgstr[1] "" - -#: mod/network.php:550 -msgid "Messages in this group won't be send to these receivers." -msgstr "" - -#: mod/network.php:618 -msgid "No such group" -msgstr "Ryhmä ei ole olemassa" - -#: mod/network.php:643 -#, php-format -msgid "Group: %s" -msgstr "Ryhmä: %s" - -#: mod/network.php:669 -msgid "Private messages to this person are at risk of public disclosure." -msgstr "Yksityisviestit lähetetty tälle henkilölle saattaa näkyä muillekin." - -#: mod/network.php:672 -msgid "Invalid contact." -msgstr "Virheellinen kontakti." - -#: mod/network.php:943 -msgid "Commented Order" -msgstr "Järjestä viimeisimpien kommenttien mukaan" - -#: mod/network.php:946 -msgid "Sort by Comment Date" -msgstr "Kommentit päivämäärän mukaan" - -#: mod/network.php:951 -msgid "Posted Order" -msgstr "Järjestä julkaisupäivämäärän mukaan" - -#: mod/network.php:954 -msgid "Sort by Post Date" -msgstr "Julkaisut päivämäärän mukaan" - -#: mod/network.php:962 mod/profiles.php:594 -#: src/Core/NotificationsManager.php:185 -msgid "Personal" -msgstr "Henkilökohtainen" - -#: mod/network.php:965 -msgid "Posts that mention or involve you" -msgstr "Julkaisut jotka liittyvät sinuun" - -#: mod/network.php:973 -msgid "New" -msgstr "Uusi" - -#: mod/network.php:976 -msgid "Activity Stream - by date" -msgstr "" - -#: mod/network.php:984 -msgid "Shared Links" -msgstr "Jaetut linkit" - -#: mod/network.php:987 -msgid "Interesting Links" -msgstr "Kiinnostavat linkit" - -#: mod/network.php:995 -msgid "Starred" -msgstr "Tähtimerkitty" - -#: mod/network.php:998 -msgid "Favourite Posts" -msgstr "Lempijulkaisut" - -#: mod/notes.php:52 src/Model/Profile.php:944 +#: mod/notes.php:52 src/Module/BaseProfile.php:108 msgid "Personal Notes" msgstr "Henkilökohtaiset tiedot" -#: mod/notifications.php:37 -msgid "Invalid request identifier." -msgstr "Virheellinen pyyntötunniste." - -#: mod/notifications.php:46 mod/notifications.php:182 -#: mod/notifications.php:229 -msgid "Discard" -msgstr "Hylkää" - -#: mod/notifications.php:98 src/Content/Nav.php:191 -msgid "Notifications" -msgstr "Huomautukset" - -#: mod/notifications.php:107 -msgid "Network Notifications" -msgstr "Uutisvirtailmoitukset" - -#: mod/notifications.php:119 -msgid "Personal Notifications" -msgstr "Henkilökohtaiset ilmoitukset" - -#: mod/notifications.php:125 -msgid "Home Notifications" -msgstr "Koti-ilmoitukset" - -#: mod/notifications.php:155 -msgid "Show Ignored Requests" -msgstr "Näytä ohitetut pyynnöt" - -#: mod/notifications.php:155 -msgid "Hide Ignored Requests" -msgstr "Piilota ohitetut pyynnöt" - -#: mod/notifications.php:167 mod/notifications.php:236 -msgid "Notification type: " -msgstr "Ilmoitustyyppi:" - -#: mod/notifications.php:170 -#, php-format -msgid "suggested by %s" -msgstr "ehdottaa %s" - -#: mod/notifications.php:197 -msgid "Claims to be known to you: " -msgstr "Väittää tuntevansa sinut:" - -#: mod/notifications.php:198 -msgid "yes" -msgstr "kyllä" - -#: mod/notifications.php:198 -msgid "no" -msgstr "ei" - -#: mod/notifications.php:199 mod/notifications.php:204 -msgid "Shall your connection be bidirectional or not?" -msgstr "Kaksisuuntainen yhteys?" - -#: mod/notifications.php:200 mod/notifications.php:205 -#, php-format -msgid "" -"Accepting %s as a friend allows %s to subscribe to your posts, and you will " -"also receive updates from them in your news feed." +#: mod/notes.php:56 +msgid "Personal notes are visible only by yourself." msgstr "" -#: mod/notifications.php:201 -#, php-format -msgid "" -"Accepting %s as a subscriber allows them to subscribe to your posts, but you" -" will not receive updates from them in your news feed." +#: mod/notes.php:57 src/Content/Text/HTML.php:856 +#: src/Module/Admin/Storage.php:142 src/Module/Filer/SaveTag.php:74 +#: src/Module/Post/Edit.php:129 +msgid "Save" +msgstr "Tallenna" + +#: mod/photos.php:67 mod/photos.php:132 mod/photos.php:575 +#: src/Model/Event.php:514 src/Model/Profile.php:234 +#: src/Module/Calendar/Export.php:74 src/Module/Calendar/Show.php:74 +#: src/Module/DFRN/Poll.php:43 src/Module/Feed.php:65 src/Module/HCard.php:51 +#: src/Module/Profile/Common.php:62 src/Module/Profile/Common.php:71 +#: src/Module/Profile/Contacts.php:64 src/Module/Profile/Contacts.php:72 +#: src/Module/Profile/Conversations.php:91 src/Module/Profile/Media.php:38 +#: src/Module/Profile/Photos.php:83 src/Module/Profile/RemoteFollow.php:71 +#: src/Module/Register.php:267 +msgid "User not found." msgstr "" -#: mod/notifications.php:206 -#, php-format -msgid "" -"Accepting %s as a sharer allows them to subscribe to your posts, but you " -"will not receive updates from them in your news feed." -msgstr "" - -#: mod/notifications.php:217 -msgid "Friend" -msgstr "Kaveri" - -#: mod/notifications.php:218 -msgid "Sharer" -msgstr "Jakaja" - -#: mod/notifications.php:218 -msgid "Subscriber" -msgstr "Tilaaja" - -#: mod/notifications.php:273 -msgid "No introductions." -msgstr "Ei esittelyjä." - -#: mod/notifications.php:314 -msgid "Show unread" -msgstr "Näytä lukemattomat" - -#: mod/notifications.php:314 -msgid "Show all" -msgstr "Näytä kaikki" - -#: mod/notifications.php:320 -#, php-format -msgid "No more %s notifications." -msgstr "Ei muita %s ilmoituksia." - -#: mod/openid.php:29 -msgid "OpenID protocol error. No ID returned." -msgstr "OpenID -protokollavirhe. Tunnusta ei vastaanotettu." - -#: mod/openid.php:66 -msgid "" -"Account not found and OpenID registration is not permitted on this site." -msgstr "Käyttäjätiliä ei löytynyt. Rekisteröityminen OpenID:n kautta ei ole sallittua tällä sivustolla." - -#: mod/openid.php:116 src/Module/Login.php:86 src/Module/Login.php:135 -msgid "Login failed." -msgstr "Kirjautuminen epäonnistui" - -#: mod/photos.php:108 src/Model/Profile.php:905 +#: mod/photos.php:106 src/Module/BaseProfile.php:68 +#: src/Module/Profile/Photos.php:379 msgid "Photo Albums" msgstr "Valokuva-albumit" -#: mod/photos.php:109 mod/photos.php:1708 +#: mod/photos.php:107 src/Module/Profile/Photos.php:380 +#: src/Module/Profile/Photos.php:400 msgid "Recent Photos" msgstr "Viimeaikaisia kuvia" -#: mod/photos.php:112 mod/photos.php:1198 mod/photos.php:1710 +#: mod/photos.php:109 mod/photos.php:865 src/Module/Profile/Photos.php:382 +#: src/Module/Profile/Photos.php:402 msgid "Upload New Photos" msgstr "Lähetä uusia kuvia" -#: mod/photos.php:126 mod/settings.php:51 +#: mod/photos.php:121 src/Module/BaseSettings.php:74 +#: src/Module/Profile/Photos.php:363 msgid "everybody" msgstr "kaikki" -#: mod/photos.php:184 +#: mod/photos.php:159 msgid "Contact information unavailable" msgstr "Kontaktin tietoja ei saatavilla" -#: mod/photos.php:204 +#: mod/photos.php:188 msgid "Album not found." msgstr "Albumia ei ole." -#: mod/photos.php:234 mod/photos.php:245 mod/photos.php:1149 -msgid "Delete Album" -msgstr "Poista albumi" +#: mod/photos.php:242 +msgid "Album successfully deleted" +msgstr "" -#: mod/photos.php:243 -msgid "Do you really want to delete this photo album and all its photos?" -msgstr "Haluatko varmasti poistaa tämän albumin ja kaikki sen kuvat?" +#: mod/photos.php:244 +msgid "Album was empty." +msgstr "" -#: mod/photos.php:303 mod/photos.php:314 mod/photos.php:1440 -msgid "Delete Photo" -msgstr "Poista valokuva" +#: mod/photos.php:276 +msgid "Failed to delete the photo." +msgstr "" -#: mod/photos.php:312 -msgid "Do you really want to delete this photo?" -msgstr "Haluatko varmasti poistaa kuvan?" - -#: mod/photos.php:655 +#: mod/photos.php:542 msgid "a photo" msgstr "valokuva" -#: mod/photos.php:655 +#: mod/photos.php:542 #, php-format msgid "%1$s was tagged in %2$s by %3$s" msgstr "%1$s merkattiin kuvaan %2$s ystävän %3$s toimesta" -#: mod/photos.php:757 -msgid "Image upload didn't complete, please try again" -msgstr "Kuvan lataus ei onnistunut, yritä uudelleen" +#: mod/photos.php:579 src/Module/Conversation/Community.php:188 +#: src/Module/Directory.php:48 src/Module/Profile/Photos.php:295 +#: src/Module/Search/Index.php:65 +msgid "Public access denied." +msgstr "Julkinen käyttö estetty." -#: mod/photos.php:760 -msgid "Image file is missing" -msgstr "Kuvatiedosto puuttuu" - -#: mod/photos.php:765 -msgid "" -"Server can't accept new file upload at this time, please contact your " -"administrator" -msgstr "" - -#: mod/photos.php:791 -msgid "Image file is empty." -msgstr "Kuvatiedosto on tyhjä." - -#: mod/photos.php:928 +#: mod/photos.php:584 msgid "No photos selected" msgstr "Ei valittuja kuvia" -#: mod/photos.php:1024 mod/videos.php:309 -msgid "Access to this item is restricted." -msgstr "Pääsy kohteeseen on rajoitettu." +#: mod/photos.php:716 +#, php-format +msgid "The maximum accepted image size is %s" +msgstr "" -#: mod/photos.php:1078 +#: mod/photos.php:723 msgid "Upload Photos" msgstr "Lähetä kuvia" -#: mod/photos.php:1082 mod/photos.php:1144 +#: mod/photos.php:727 mod/photos.php:813 msgid "New album name: " msgstr "Albumin uusi nimi: " -#: mod/photos.php:1083 -msgid "or existing album name: " -msgstr "tai olemassaolevan albumin nimi: " +#: mod/photos.php:728 +msgid "or select existing album:" +msgstr "" -#: mod/photos.php:1084 +#: mod/photos.php:729 msgid "Do not show a status post for this upload" msgstr "Älä näytä tilaviestiä tälle lähetykselle" -#: mod/photos.php:1094 mod/photos.php:1443 mod/settings.php:1218 -msgid "Show to Groups" -msgstr "Näytä ryhmille" +#: mod/photos.php:731 mod/photos.php:1091 src/Content/Conversation.php:392 +#: src/Module/Calendar/Event/Form.php:253 src/Module/Post/Edit.php:183 +msgid "Permissions" +msgstr "Käyttöoikeudet" -#: mod/photos.php:1095 mod/photos.php:1444 mod/settings.php:1219 -msgid "Show to Contacts" -msgstr "Näytä kontakteille" +#: mod/photos.php:794 +msgid "Do you really want to delete this photo album and all its photos?" +msgstr "Haluatko varmasti poistaa tämän albumin ja kaikki sen kuvat?" -#: mod/photos.php:1155 +#: mod/photos.php:795 mod/photos.php:818 +msgid "Delete Album" +msgstr "Poista albumi" + +#: mod/photos.php:796 mod/photos.php:897 src/Content/Conversation.php:408 +#: src/Module/Contact/Follow.php:173 src/Module/Contact/Revoke.php:109 +#: src/Module/Contact/Unfollow.php:126 +#: src/Module/Media/Attachment/Browser.php:77 +#: src/Module/Media/Photo/Browser.php:88 src/Module/Post/Edit.php:167 +#: src/Module/Post/Tag/Remove.php:109 src/Module/Profile/RemoteFollow.php:134 +#: src/Module/Security/TwoFactor/SignOut.php:125 +msgid "Cancel" +msgstr "Peru" + +#: mod/photos.php:822 msgid "Edit Album" msgstr "Muokkaa albumia" -#: mod/photos.php:1160 +#: mod/photos.php:823 +msgid "Drop Album" +msgstr "" + +#: mod/photos.php:827 msgid "Show Newest First" msgstr "Näytä uusin ensin" -#: mod/photos.php:1162 +#: mod/photos.php:829 msgid "Show Oldest First" msgstr "Näytä vanhin ensin" -#: mod/photos.php:1183 mod/photos.php:1693 +#: mod/photos.php:850 src/Module/Profile/Photos.php:350 msgid "View Photo" msgstr "Näytä kuva" -#: mod/photos.php:1224 +#: mod/photos.php:883 msgid "Permission denied. Access to this item may be restricted." msgstr "Estetty. Tämän kohteen käyttöä on saatettu rajoittaa." -#: mod/photos.php:1226 +#: mod/photos.php:885 msgid "Photo not available" msgstr "Kuva ei ole saatavilla" -#: mod/photos.php:1294 +#: mod/photos.php:895 +msgid "Do you really want to delete this photo?" +msgstr "Haluatko varmasti poistaa kuvan?" + +#: mod/photos.php:896 mod/photos.php:1096 +msgid "Delete Photo" +msgstr "Poista valokuva" + +#: mod/photos.php:994 msgid "View photo" msgstr "Näytä kuva" -#: mod/photos.php:1294 +#: mod/photos.php:996 msgid "Edit photo" msgstr "Muokkaa kuvaa" -#: mod/photos.php:1295 +#: mod/photos.php:997 +msgid "Delete photo" +msgstr "" + +#: mod/photos.php:998 msgid "Use as profile photo" msgstr "Käytä profiilikuvana" -#: mod/photos.php:1301 src/Object/Post.php:149 -msgid "Private Message" -msgstr "Yksityisviesti" +#: mod/photos.php:1005 +msgid "Private Photo" +msgstr "" -#: mod/photos.php:1321 +#: mod/photos.php:1011 msgid "View Full Size" msgstr "Näytä täysikokoisena" -#: mod/photos.php:1408 +#: mod/photos.php:1064 msgid "Tags: " msgstr "Merkinnät:" -#: mod/photos.php:1411 -msgid "[Remove any tag]" -msgstr "[Poista mikä tahansa merkintä]" +#: mod/photos.php:1067 +msgid "[Select tags to remove]" +msgstr "" -#: mod/photos.php:1426 +#: mod/photos.php:1082 msgid "New album name" msgstr "Uusi nimi albumille" -#: mod/photos.php:1427 +#: mod/photos.php:1083 msgid "Caption" msgstr "Kuvateksti" -#: mod/photos.php:1428 +#: mod/photos.php:1084 msgid "Add a Tag" msgstr "Lisää merkintä" -#: mod/photos.php:1428 +#: mod/photos.php:1084 msgid "" "Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" msgstr "Esimerkki: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" -#: mod/photos.php:1429 +#: mod/photos.php:1085 msgid "Do not rotate" msgstr "Älä kierrä" -#: mod/photos.php:1430 +#: mod/photos.php:1086 msgid "Rotate CW (right)" msgstr "Käännä oikealle" -#: mod/photos.php:1431 +#: mod/photos.php:1087 msgid "Rotate CCW (left)" msgstr "Käännä vasemmalle" -#: mod/photos.php:1465 src/Object/Post.php:304 -msgid "I like this (toggle)" -msgstr "Tykkään tästä (vaihda)" +#: mod/photos.php:1133 mod/photos.php:1189 mod/photos.php:1263 +#: src/Module/Contact.php:597 src/Module/Item/Compose.php:188 +#: src/Object/Post.php:1067 +msgid "This is you" +msgstr "Tämä olet sinä" -#: mod/photos.php:1466 src/Object/Post.php:305 -msgid "I don't like this (toggle)" -msgstr "En tykkää tästä (vaihda)" - -#: mod/photos.php:1484 mod/photos.php:1523 mod/photos.php:1596 -#: src/Object/Post.php:407 src/Object/Post.php:803 +#: mod/photos.php:1135 mod/photos.php:1191 mod/photos.php:1265 +#: src/Object/Post.php:551 src/Object/Post.php:1069 msgid "Comment" msgstr "Kommentti" -#: mod/photos.php:1628 +#: mod/photos.php:1137 mod/photos.php:1193 mod/photos.php:1267 +#: src/Content/Conversation.php:405 src/Module/Calendar/Event/Form.php:248 +#: src/Module/Item/Compose.php:200 src/Module/Post/Edit.php:165 +#: src/Object/Post.php:1082 +msgid "Preview" +msgstr "Esikatselu" + +#: mod/photos.php:1138 src/Content/Conversation.php:359 +#: src/Module/Post/Edit.php:130 src/Object/Post.php:1071 +msgid "Loading..." +msgstr "" + +#: mod/photos.php:1224 src/Content/Conversation.php:650 +#: src/Object/Post.php:258 +msgid "Select" +msgstr "Valitse" + +#: mod/photos.php:1225 src/Content/Conversation.php:651 +#: 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:244 +msgid "Delete" +msgstr "Poista" + +#: mod/photos.php:1286 src/Object/Post.php:391 +msgid "Like" +msgstr "" + +#: mod/photos.php:1287 src/Object/Post.php:391 +msgid "I like this (toggle)" +msgstr "Tykkään tästä (vaihda)" + +#: mod/photos.php:1288 src/Object/Post.php:392 +msgid "Dislike" +msgstr "" + +#: mod/photos.php:1290 src/Object/Post.php:392 +msgid "I don't like this (toggle)" +msgstr "En tykkää tästä (vaihda)" + +#: mod/photos.php:1312 msgid "Map" msgstr "Kartta" -#: mod/photos.php:1699 mod/videos.php:387 -msgid "View Album" -msgstr "Näytä albumi" +#: src/App.php:473 +msgid "No system theme config value set." +msgstr "" -#: mod/profile.php:37 src/Model/Profile.php:118 -msgid "Requested profile is not available." -msgstr "Pyydettyä profiilia ei saatavilla." +#: src/App.php:577 +msgid "Apologies but the website is unavailable at the moment." +msgstr "" -#: mod/profile.php:78 mod/profile.php:81 src/Protocol/OStatus.php:1250 +#: src/App/Page.php:247 +msgid "Delete this item?" +msgstr "Poista tämä kohde?" + +#: src/App/Page.php:248 +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 +msgid "" +"Ignore this author? You won't be able to see their posts and their " +"notifications." +msgstr "" + +#: src/App/Page.php:250 +msgid "Collapse this author's posts?" +msgstr "" + +#: src/App/Page.php:252 +msgid "Like not successful" +msgstr "" + +#: src/App/Page.php:253 +msgid "Dislike not successful" +msgstr "" + +#: src/App/Page.php:254 +msgid "Sharing not successful" +msgstr "" + +#: src/App/Page.php:255 +msgid "Attendance unsuccessful" +msgstr "" + +#: src/App/Page.php:256 +msgid "Backend error" +msgstr "" + +#: src/App/Page.php:257 +msgid "Network error" +msgstr "" + +#: src/App/Page.php:260 +msgid "Drop files here to upload" +msgstr "" + +#: src/App/Page.php:261 +msgid "Your browser does not support drag and drop file uploads." +msgstr "" + +#: src/App/Page.php:262 +msgid "" +"Please use the fallback form below to upload your files like in the olden " +"days." +msgstr "" + +#: src/App/Page.php:263 +msgid "File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB." +msgstr "" + +#: src/App/Page.php:264 +msgid "You can't upload files of this type." +msgstr "" + +#: src/App/Page.php:265 +msgid "Server responded with {{statusCode}} code." +msgstr "" + +#: src/App/Page.php:266 +msgid "Cancel upload" +msgstr "" + +#: src/App/Page.php:267 +msgid "Upload canceled." +msgstr "" + +#: src/App/Page.php:268 +msgid "Are you sure you want to cancel this upload?" +msgstr "" + +#: src/App/Page.php:269 +msgid "Remove file" +msgstr "" + +#: src/App/Page.php:270 +msgid "You can't upload any more files." +msgstr "" + +#: src/App/Page.php:348 +msgid "toggle mobile" +msgstr "Mobiilisivusto päälle/pois" + +#: src/App/Router.php:309 #, php-format -msgid "%s's timeline" -msgstr "%s: aikajana" - -#: mod/profile.php:79 src/Protocol/OStatus.php:1251 -#, php-format -msgid "%s's posts" -msgstr "%s: julkaisut" - -#: mod/profile.php:80 src/Protocol/OStatus.php:1252 -#, php-format -msgid "%s's comments" -msgstr "%s: kommentit" - -#: mod/profile.php:195 -msgid "Tips for New Members" -msgstr "Vinkkejä uusille käyttäjille" - -#: mod/profiles.php:58 -msgid "Profile deleted." -msgstr "Profiili poistettiin." - -#: mod/profiles.php:74 mod/profiles.php:110 -msgid "Profile-" -msgstr "Profiili-" - -#: mod/profiles.php:93 mod/profiles.php:132 -msgid "New profile created." -msgstr "Uusi profiili luotu." - -#: mod/profiles.php:116 -msgid "Profile unavailable to clone." -msgstr "Profiili ei saatavilla kloonattavaksi." - -#: mod/profiles.php:206 -msgid "Profile Name is required." -msgstr "Profiilinimi on pakollinen." - -#: mod/profiles.php:347 -msgid "Marital Status" -msgstr "Siviilisääty" - -#: mod/profiles.php:351 -msgid "Romantic Partner" -msgstr "Romanttinen kumppani" - -#: mod/profiles.php:363 -msgid "Work/Employment" -msgstr "Työ" - -#: mod/profiles.php:366 -msgid "Religion" -msgstr "Uskonto" - -#: mod/profiles.php:370 -msgid "Political Views" -msgstr "Poliittiset näkemykset" - -#: mod/profiles.php:374 -msgid "Gender" -msgstr "Sukupuoli" - -#: mod/profiles.php:378 -msgid "Sexual Preference" -msgstr "Seksuaalinen suuntautuminen" - -#: mod/profiles.php:382 -msgid "XMPP" -msgstr "XMPP" - -#: mod/profiles.php:386 -msgid "Homepage" -msgstr "Kotisivu" - -#: mod/profiles.php:390 mod/profiles.php:593 -msgid "Interests" -msgstr "Kiinnostukset" - -#: mod/profiles.php:401 mod/profiles.php:589 -msgid "Location" -msgstr "Sijainti" - -#: mod/profiles.php:483 -msgid "Profile updated." -msgstr "Profiili päivitettiin." - -#: mod/profiles.php:540 -msgid "Hide contacts and friends:" -msgstr "Piilota kontaktit ja kaverit:" - -#: mod/profiles.php:545 -msgid "Hide your contact/friend list from viewers of this profile?" -msgstr "Piilota tämän profiilin kontakti/kaverilista?" - -#: mod/profiles.php:565 -msgid "Show more profile fields:" -msgstr "Näytä lisää profiilikenttiä:" - -#: mod/profiles.php:577 -msgid "Profile Actions" +msgid "Method not allowed for this module. Allowed method(s): %s" msgstr "" -#: mod/profiles.php:578 -msgid "Edit Profile Details" -msgstr "Muokkaa profiilin yksityiskohdat" +#: src/App/Router.php:311 src/Module/HTTPException/PageNotFound.php:49 +msgid "Page not found." +msgstr "Sivua ei löytynyt." -#: mod/profiles.php:580 -msgid "Change Profile Photo" -msgstr "Vaihda profiilikuva" +#: src/App/Router.php:323 +msgid "You must be logged in to use addons. " +msgstr "Sinun pitää kirjautua sisään, jotta voit käyttää lisäosia" -#: mod/profiles.php:581 -msgid "View this profile" -msgstr "Näytä profiilia" - -#: mod/profiles.php:582 mod/profiles.php:677 src/Model/Profile.php:389 -msgid "Edit visibility" -msgstr "Muokkaa näkyvyyttä" - -#: mod/profiles.php:583 -msgid "Create a new profile using these settings" -msgstr "Luo uusi profiili näillä asetuksilla" - -#: mod/profiles.php:584 -msgid "Clone this profile" -msgstr "Kloonaa tämä profiili" - -#: mod/profiles.php:585 -msgid "Delete this profile" -msgstr "Poista tämä profiili" - -#: mod/profiles.php:587 -msgid "Basic information" -msgstr "Perustiedot" - -#: mod/profiles.php:588 -msgid "Profile picture" -msgstr "Profiilikuva" - -#: mod/profiles.php:590 -msgid "Preferences" -msgstr "Mieltymykset" - -#: mod/profiles.php:591 -msgid "Status information" -msgstr "Tilatiedot" - -#: mod/profiles.php:592 -msgid "Additional information" -msgstr "Lisätietoja" - -#: mod/profiles.php:595 -msgid "Relation" -msgstr "Suhde" - -#: mod/profiles.php:596 src/Util/Temporal.php:81 src/Util/Temporal.php:83 -msgid "Miscellaneous" -msgstr "Sekalaista" - -#: mod/profiles.php:599 -msgid "Your Gender:" -msgstr "Sukupuoli:" - -#: mod/profiles.php:600 -msgid " Marital Status:" -msgstr " Siviilisääty:" - -#: mod/profiles.php:601 src/Model/Profile.php:780 -msgid "Sexual Preference:" -msgstr "Seksuaalinen suuntautuminen:" - -#: mod/profiles.php:602 -msgid "Example: fishing photography software" -msgstr "Esimerkki: kalastus valokuvaus ohjelmistot" - -#: mod/profiles.php:607 -msgid "Profile Name:" -msgstr "Profiilinimi:" - -#: mod/profiles.php:609 +#: src/BaseModule.php:400 msgid "" -"This is your public profile.
It may " -"be visible to anybody using the internet." -msgstr "" - -#: mod/profiles.php:610 -msgid "Your Full Name:" -msgstr "Koko nimi:" - -#: mod/profiles.php:611 -msgid "Title/Description:" -msgstr "Otsikko/kuvaus:" - -#: mod/profiles.php:614 -msgid "Street Address:" -msgstr "Katuosoite:" - -#: mod/profiles.php:615 -msgid "Locality/City:" -msgstr "Kaupunki:" - -#: mod/profiles.php:616 -msgid "Region/State:" -msgstr "Alue/osavaltio:" - -#: mod/profiles.php:617 -msgid "Postal/Zip Code:" -msgstr "Postinumero:" - -#: mod/profiles.php:618 -msgid "Country:" -msgstr "Maa:" - -#: mod/profiles.php:619 src/Util/Temporal.php:149 -msgid "Age: " -msgstr "Ikä:" - -#: mod/profiles.php:622 -msgid "Who: (if applicable)" -msgstr "Kuka: (tarvittaessa)" - -#: mod/profiles.php:622 -msgid "Examples: cathy123, Cathy Williams, cathy@example.com" -msgstr "Esimerkkejä: cathy123, Cathy Williams, cathy@example.com" - -#: mod/profiles.php:623 -msgid "Since [date]:" -msgstr "Lähtien [päivämäärä]:" - -#: mod/profiles.php:625 -msgid "Tell us about yourself..." -msgstr "Kerro vähän itsestäsi..." +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "Lomakkeen turvallisuusavain oli väärin. Tämä voi johtua siitä, että lomake on ollut avoinna liian kauan (>3 tuntia) ennen sen lähettämistä." -#: mod/profiles.php:626 -msgid "XMPP (Jabber) address:" -msgstr "XMPP (Jabber) osoite:" - -#: mod/profiles.php:626 -msgid "" -"The XMPP address will be propagated to your contacts so that they can follow" -" you." +#: src/BaseModule.php:427 +msgid "All contacts" msgstr "" -#: mod/profiles.php:627 -msgid "Homepage URL:" -msgstr "Kotisivun URL-osoite:" - -#: mod/profiles.php:628 src/Model/Profile.php:788 -msgid "Hometown:" -msgstr "Kotikaupunki:" - -#: mod/profiles.php:629 src/Model/Profile.php:796 -msgid "Political Views:" -msgstr "Politiikka:" - -#: mod/profiles.php:630 -msgid "Religious Views:" -msgstr "Uskonto:" - -#: mod/profiles.php:631 -msgid "Public Keywords:" -msgstr "Julkiset avainsanat:" - -#: mod/profiles.php:631 -msgid "(Used for suggesting potential friends, can be seen by others)" -msgstr "(Käytetään kaveriehdotuksia varten, näkyy muille)" - -#: mod/profiles.php:632 -msgid "Private Keywords:" -msgstr "Yksityiset avainsanat:" - -#: mod/profiles.php:632 -msgid "(Used for searching profiles, never shown to others)" -msgstr "(Käytetään profiilihakua varten, ei näy muille)" - -#: mod/profiles.php:633 src/Model/Profile.php:812 -msgid "Likes:" -msgstr "Tykkäykset:" - -#: mod/profiles.php:634 src/Model/Profile.php:816 -msgid "Dislikes:" -msgstr "Ei tykkää:" - -#: mod/profiles.php:635 -msgid "Musical interests" -msgstr "Musiikki" - -#: mod/profiles.php:636 -msgid "Books, literature" -msgstr "Kirjat, kirjallisuus" - -#: mod/profiles.php:637 -msgid "Television" -msgstr "Televisio" - -#: mod/profiles.php:638 -msgid "Film/dance/culture/entertainment" -msgstr "Elokuvat/tanssi/kulttuuri/viihde" - -#: mod/profiles.php:639 -msgid "Hobbies/Interests" -msgstr "Harrastukset" - -#: mod/profiles.php:640 -msgid "Love/romance" -msgstr "Rakkaus/romanssi" - -#: mod/profiles.php:641 -msgid "Work/employment" -msgstr "Työ:" - -#: mod/profiles.php:642 -msgid "School/education" -msgstr "Koulutus:" - -#: mod/profiles.php:643 -msgid "Contact information and Social Networks" -msgstr "Yhteystiedot ja sosiaalinen media" - -#: mod/profiles.php:674 src/Model/Profile.php:385 -msgid "Profile Image" -msgstr "Profiilikuva" - -#: mod/profiles.php:676 src/Model/Profile.php:388 -msgid "visible to everybody" -msgstr "näkyvissä kaikille" - -#: mod/profiles.php:683 -msgid "Edit/Manage Profiles" -msgstr "Muokkaa/hallitse profiilit" - -#: mod/profiles.php:684 src/Model/Profile.php:375 src/Model/Profile.php:397 -msgid "Change profile photo" -msgstr "Vaihda profiilikuva" - -#: mod/profiles.php:685 src/Model/Profile.php:376 -msgid "Create New Profile" -msgstr "Luo uusi profiili" - -#: mod/register.php:100 -msgid "" -"Registration successful. Please check your email for further instructions." -msgstr "Rekisteröityminen onnistui. Saat kohta lisäohjeita sähköpostitse." - -#: mod/register.php:104 -#, php-format -msgid "" -"Failed to send email message. Here your accout details:
login: %s
" -"password: %s

You can change your password after login." +#: src/BaseModule.php:432 src/Content/Widget.php:243 src/Core/ACL.php:195 +#: src/Module/Contact.php:415 src/Module/PermissionTooltip.php:127 +#: src/Module/PermissionTooltip.php:149 +msgid "Followers" msgstr "" -#: mod/register.php:111 -msgid "Registration successful." -msgstr "Rekisteröityminen onnistui." - -#: mod/register.php:116 -msgid "Your registration can not be processed." -msgstr "Rekisteröintisi ei voida käsitellä." - -#: mod/register.php:163 -msgid "Your registration is pending approval by the site owner." -msgstr "Rekisteröintisi odottaa ylläpitäjän hyväksyntää." - -#: mod/register.php:221 -msgid "" -"You may (optionally) fill in this form via OpenID by supplying your OpenID " -"and clicking 'Register'." +#: src/BaseModule.php:437 src/Content/Widget.php:244 +#: src/Module/Contact.php:416 +msgid "Following" msgstr "" -#: mod/register.php:222 -msgid "" -"If you are not familiar with OpenID, please leave that field blank and fill " -"in the rest of the items." -msgstr "Jos OpenID ei ole tuttu, jätä kenttä tyhjäksi." - -#: mod/register.php:223 -msgid "Your OpenID (optional): " -msgstr "OpenID -tunnus (valinnainen):" - -#: mod/register.php:235 -msgid "Include your profile in member directory?" -msgstr "Lisää profiilisi jäsenluetteloon?" - -#: mod/register.php:262 -msgid "Note for the admin" -msgstr "Viesti ylläpidolle" - -#: mod/register.php:262 -msgid "Leave a message for the admin, why you want to join this node" -msgstr "Kerro yllåpitäjälle miksi haluat liittyä tähän Friendica -sivustoon" - -#: mod/register.php:263 -msgid "Membership on this site is by invitation only." -msgstr "Tähän sivustoon voi liittyä vain kutsusta." - -#: mod/register.php:264 -msgid "Your invitation code: " -msgstr "Kutsukoodisi:" - -#: mod/register.php:273 -msgid "Your Full Name (e.g. Joe Smith, real or real-looking): " -msgstr "Koko nimi (esim. Matti Meikäläinen, Aku Ankka):" - -#: mod/register.php:274 -msgid "" -"Your Email Address: (Initial information will be send there, so this has to " -"be an existing address.)" -msgstr "Sähköpostiosoite: (pitää olla toimiva osoite että rekisteröityminen onnistuu)" - -#: mod/register.php:276 mod/settings.php:1190 -msgid "New Password:" -msgstr "Uusi salasana:" - -#: mod/register.php:276 -msgid "Leave empty for an auto generated password." -msgstr "Jätä tyhjäksi jos haluat automaattisesti luotu salasanan." - -#: mod/register.php:277 mod/settings.php:1191 -msgid "Confirm:" -msgstr "Vahvista:" - -#: mod/register.php:278 -#, php-format -msgid "" -"Choose a profile nickname. This must begin with a text character. Your " -"profile address on this site will then be 'nickname@%s'." -msgstr "" - -#: mod/register.php:279 -msgid "Choose a nickname: " -msgstr "Valitse lempinimi:" - -#: mod/register.php:282 src/Content/Nav.php:128 src/Module/Login.php:284 -msgid "Register" -msgstr "Rekisteröidy" - -#: mod/register.php:289 -msgid "Import your profile to this friendica instance" -msgstr "Tuo profiilisi tähän Friendica -instanssiin." - -#: mod/removeme.php:45 -msgid "User deleted their account" -msgstr "Käyttäjä poisti tilinsä" - -#: mod/removeme.php:46 -msgid "" -"On your Friendica node an user deleted their account. Please ensure that " -"their data is removed from the backups." -msgstr "Friendica -solmullasi käyttäjä poisti tilinsä. Varmista että hänen tiedot poistetaan myös varmuuskopioista." - -#: mod/removeme.php:47 -#, php-format -msgid "The user id is %d" -msgstr "Käyttäjätunnus on %d" - -#: mod/removeme.php:78 mod/removeme.php:81 -msgid "Remove My Account" -msgstr "Poista tilini" - -#: mod/removeme.php:79 -msgid "" -"This will completely remove your account. Once this has been done it is not " -"recoverable." -msgstr "Tämä poistaa käyttäjätilisi pysyvästi. Poistoa ei voi perua myöhemmin." - -#: mod/removeme.php:80 -msgid "Please enter your password for verification:" -msgstr "Syötä salasanasi varmistusta varten:" - -#: mod/search.php:105 -msgid "Only logged in users are permitted to perform a search." -msgstr "" - -#: mod/search.php:129 -msgid "Too Many Requests" -msgstr "Liian monta pyyntöä" - -#: mod/search.php:130 -msgid "Only one search per minute is permitted for not logged in users." -msgstr "" - -#: mod/search.php:234 -#, php-format -msgid "Items tagged with: %s" -msgstr "Kohteet joilla tunnisteet: %s" - -#: mod/settings.php:56 -msgid "Account" -msgstr "Tili" - -#: mod/settings.php:73 -msgid "Display" -msgstr "Ulkonäkö" - -#: mod/settings.php:80 mod/settings.php:834 -msgid "Social Networks" -msgstr "Sosiaalinen media" - -#: mod/settings.php:94 src/Content/Nav.php:205 -msgid "Delegations" -msgstr "" - -#: mod/settings.php:101 -msgid "Connected apps" -msgstr "Yhdistetyt sovellukset" - -#: mod/settings.php:115 -msgid "Remove account" -msgstr "Poista tili" - -#: mod/settings.php:167 -msgid "Missing some important data!" -msgstr "Tärkeää dataa puuttuu!" - -#: mod/settings.php:278 -msgid "Failed to connect with email account using the settings provided." +#: src/BaseModule.php:442 src/Content/Widget.php:245 +#: src/Module/Contact.php:417 +msgid "Mutual friends" msgstr "" -#: mod/settings.php:283 -msgid "Email settings updated." -msgstr "Sähköpostin asetukset päivitettiin." - -#: mod/settings.php:299 -msgid "Features updated" -msgstr "Ominaisuudet päivitetty" - -#: mod/settings.php:372 -msgid "Relocate message has been send to your contacts" +#: src/BaseModule.php:450 +msgid "Common" msgstr "" -#: mod/settings.php:384 src/Model/User.php:340 -msgid "Passwords do not match. Password unchanged." -msgstr "Salasanat eivät täsmää. Salasana ennallaan." - -#: mod/settings.php:389 -msgid "Empty passwords are not allowed. Password unchanged." -msgstr "Tyhjä salasanakenttä ei ole sallittu. Salasana ennallaan." - -#: mod/settings.php:394 src/Core/Console/NewPassword.php:87 -msgid "" -"The new password has been exposed in a public data dump, please choose " -"another." +#: src/Console/Addon.php:175 src/Console/Addon.php:199 +msgid "Addon not found" msgstr "" -#: mod/settings.php:400 -msgid "Wrong password." -msgstr "Väärä salasana." - -#: mod/settings.php:407 src/Core/Console/NewPassword.php:94 -msgid "Password changed." -msgstr "Salasana vaihdettu." - -#: mod/settings.php:409 src/Core/Console/NewPassword.php:91 -msgid "Password update failed. Please try again." -msgstr "Salasanan vaihto epäonnistui. Yritä uudelleen." - -#: mod/settings.php:493 -msgid " Please use a shorter name." -msgstr "Käytä lyhyempää nimeä." - -#: mod/settings.php:496 -msgid " Name too short." -msgstr "Nimi on liian lyhyt." - -#: mod/settings.php:504 -msgid "Wrong Password" -msgstr "Väärä salasana" - -#: mod/settings.php:509 -msgid "Invalid email." -msgstr "Virheellinen sähköposti." - -#: mod/settings.php:516 -msgid "Cannot change to that email." -msgstr "" - -#: mod/settings.php:566 -msgid "Private forum has no privacy permissions. Using default privacy group." +#: src/Console/Addon.php:179 +msgid "Addon already enabled" msgstr "" -#: mod/settings.php:569 -msgid "Private forum has no privacy permissions and no default privacy group." -msgstr "" - -#: mod/settings.php:609 -msgid "Settings updated." -msgstr "Asetukset päivitetty." - -#: mod/settings.php:668 mod/settings.php:694 mod/settings.php:728 -msgid "Add application" -msgstr "Lisää sovellus" - -#: mod/settings.php:672 mod/settings.php:698 -msgid "Consumer Key" -msgstr "Kuluttajan avain" - -#: mod/settings.php:673 mod/settings.php:699 -msgid "Consumer Secret" -msgstr "Kuluttajasalaisuus" - -#: mod/settings.php:674 mod/settings.php:700 -msgid "Redirect" -msgstr "Uudelleenohjaus" - -#: mod/settings.php:675 mod/settings.php:701 -msgid "Icon url" -msgstr "Kuvakkeen URL-osoite" - -#: mod/settings.php:686 -msgid "You can't edit this application." -msgstr "Et voi muokata tätä sovellusta." - -#: mod/settings.php:727 -msgid "Connected Apps" -msgstr "Yhdistetyt sovellukset" - -#: mod/settings.php:729 src/Object/Post.php:155 src/Object/Post.php:157 -msgid "Edit" -msgstr "Muokkaa" - -#: mod/settings.php:731 -msgid "Client key starts with" -msgstr "Asiakasavain alkaa" - -#: mod/settings.php:732 -msgid "No name" -msgstr "Ei nimeä" - -#: mod/settings.php:733 -msgid "Remove authorization" -msgstr "Poista lupa" - -#: mod/settings.php:744 -msgid "No Addon settings configured" -msgstr "Lisäosa-asetukset puuttuvat" - -#: mod/settings.php:753 -msgid "Addon Settings" -msgstr "Lisäosa-asetukset" - -#: mod/settings.php:774 -msgid "Additional Features" -msgstr "Lisäominaisuuksia" - -#: mod/settings.php:797 src/Content/ContactSelector.php:83 -msgid "Diaspora" -msgstr "Diaspora" - -#: mod/settings.php:797 mod/settings.php:798 -msgid "enabled" -msgstr "käytössä" - -#: mod/settings.php:797 mod/settings.php:798 -msgid "disabled" -msgstr "pois käytöstä" - -#: mod/settings.php:797 mod/settings.php:798 -#, php-format -msgid "Built-in support for %s connectivity is %s" -msgstr "Sisäänrakennettu tuki palvelulle %s on %s" - -#: mod/settings.php:798 -msgid "GNU Social (OStatus)" -msgstr "GNU Social (OStatus)" - -#: mod/settings.php:829 -msgid "Email access is disabled on this site." -msgstr "" - -#: mod/settings.php:839 -msgid "General Social Media Settings" -msgstr "Yleiset some asetukset" - -#: mod/settings.php:840 -msgid "Disable Content Warning" -msgstr "Poista sisältövaroitus käytöstä" - -#: mod/settings.php:840 -msgid "" -"Users on networks like Mastodon or Pleroma are able to set a content warning" -" field which collapse their post by default. This disables the automatic " -"collapsing and sets the content warning as the post title. Doesn't affect " -"any other content filtering you eventually set up." -msgstr "" - -#: mod/settings.php:841 -msgid "Disable intelligent shortening" -msgstr "Poista alykäs lyhentäminen käytöstä" - -#: mod/settings.php:841 -msgid "" -"Normally the system tries to find the best link to add to shortened posts. " -"If this option is enabled then every shortened post will always point to the" -" original friendica post." -msgstr "" - -#: mod/settings.php:842 -msgid "Automatically follow any GNU Social (OStatus) followers/mentioners" -msgstr "Automaattisesti seuraa GNU social (OStatus) seuraajat/mainitsijat" - -#: mod/settings.php:842 -msgid "" -"If you receive a message from an unknown OStatus user, this option decides " -"what to do. If it is checked, a new contact will be created for every " -"unknown user." -msgstr "" - -#: mod/settings.php:843 -msgid "Default group for OStatus contacts" -msgstr "Oletusryhmä OStatus kontakteille" - -#: mod/settings.php:844 -msgid "Your legacy GNU Social account" -msgstr "Vanha GNU social käyttäjätilisi" - -#: mod/settings.php:844 -msgid "" -"If you enter your old 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 "" - -#: mod/settings.php:847 -msgid "Repair OStatus subscriptions" -msgstr "Korjaa OStatus tilaukset" - -#: mod/settings.php:851 -msgid "Email/Mailbox Setup" -msgstr "Sähköpostin asennus" - -#: mod/settings.php:852 -msgid "" -"If you wish to communicate with email contacts using this service " -"(optional), please specify how to connect to your mailbox." -msgstr "" - -#: mod/settings.php:853 -msgid "Last successful email check:" -msgstr "Viimeisin onnistunut sähköpostitarkistus:" - -#: mod/settings.php:855 -msgid "IMAP server name:" -msgstr "IMAP-palvelimen nimi:" - -#: mod/settings.php:856 -msgid "IMAP port:" -msgstr "IMAP-porttti:" - -#: mod/settings.php:857 -msgid "Security:" -msgstr "Turvallisuus:" - -#: mod/settings.php:857 mod/settings.php:862 -msgid "None" -msgstr "Ei mitään" - -#: mod/settings.php:858 -msgid "Email login name:" -msgstr "Sähköpostitilin käyttäjätunnus:" - -#: mod/settings.php:859 -msgid "Email password:" -msgstr "Sähköpostin salasana:" - -#: mod/settings.php:860 -msgid "Reply-to address:" -msgstr "Vastausosoite:" - -#: mod/settings.php:861 -msgid "Send public posts to all email contacts:" -msgstr "Lähetä julkiset julkaisut kaikille kontakteille:" - -#: mod/settings.php:862 -msgid "Action after import:" -msgstr "Toiminta tuonnin jälkeen:" - -#: mod/settings.php:862 src/Content/Nav.php:193 -msgid "Mark as seen" -msgstr "Merkitse luetuksi" - -#: mod/settings.php:862 -msgid "Move to folder" -msgstr "Siirrä kansioon" - -#: mod/settings.php:863 -msgid "Move to folder:" -msgstr "Siirrä kansioon:" - -#: mod/settings.php:906 -#, php-format -msgid "%s - (Unsupported)" -msgstr "%s - (Ei tueta)" - -#: mod/settings.php:908 -#, php-format -msgid "%s - (Experimental)" -msgstr "%s - (Kokeellinen)" - -#: mod/settings.php:951 -msgid "Display Settings" -msgstr "Näyttöasetukset" - -#: mod/settings.php:957 mod/settings.php:981 -msgid "Display Theme:" -msgstr "Käyttöliittymän teema:" - -#: mod/settings.php:958 -msgid "Mobile Theme:" -msgstr "Mobiiliteema:" - -#: mod/settings.php:959 -msgid "Suppress warning of insecure networks" -msgstr "" - -#: mod/settings.php:959 -msgid "" -"Should the system suppress the warning that the current group contains " -"members of networks that can't receive non public postings." -msgstr "" - -#: mod/settings.php:960 -msgid "Update browser every xx seconds" -msgstr "Päivitä selain xx sekunnin välein" - -#: mod/settings.php:960 -msgid "Minimum of 10 seconds. Enter -1 to disable it." -msgstr "Vähintään 10 sekuntia. -1 poistaa ominaisuuden käytöstä." - -#: mod/settings.php:961 -msgid "Number of items to display per page:" -msgstr "" - -#: mod/settings.php:961 mod/settings.php:962 -msgid "Maximum of 100 items" -msgstr "Enintään 100 kohdetta" - -#: mod/settings.php:962 -msgid "Number of items to display per page when viewed from mobile device:" -msgstr "" - -#: mod/settings.php:963 -msgid "Don't show emoticons" -msgstr "Piilota hymiöt" - -#: mod/settings.php:964 -msgid "Calendar" -msgstr "Kalenteri" - -#: mod/settings.php:965 -msgid "Beginning of week:" -msgstr "Viikon alku:" - -#: mod/settings.php:966 -msgid "Don't show notices" -msgstr "" - -#: mod/settings.php:967 -msgid "Infinite scroll" -msgstr "Loputon selaaminen" - -#: mod/settings.php:968 -msgid "Automatic updates only at the top of the network page" -msgstr "" - -#: mod/settings.php:968 -msgid "" -"When disabled, the network page is updated all the time, which could be " -"confusing while reading." -msgstr "" - -#: mod/settings.php:969 -msgid "Bandwidth Saver Mode" -msgstr "" - -#: mod/settings.php:969 -msgid "" -"When enabled, embedded content is not displayed on automatic updates, they " -"only show on page reload." -msgstr "" - -#: mod/settings.php:970 -msgid "Smart Threading" -msgstr "" - -#: mod/settings.php:970 -msgid "" -"When enabled, suppress extraneous thread indentation while keeping it where " -"it matters. Only works if threading is available and enabled." -msgstr "" - -#: mod/settings.php:972 -msgid "General Theme Settings" -msgstr "Yleiset teeman asetukset" - -#: mod/settings.php:973 -msgid "Custom Theme Settings" -msgstr "Mukautetut teema-asetukset" - -#: mod/settings.php:974 -msgid "Content Settings" -msgstr "Sisältöasetukset" - -#: mod/settings.php:975 view/theme/duepuntozero/config.php:73 -#: view/theme/frio/config.php:120 view/theme/quattro/config.php:75 -#: view/theme/vier/config.php:121 -msgid "Theme settings" -msgstr "Teeman asetukset" - -#: mod/settings.php:994 -msgid "Unable to find your profile. Please contact your admin." -msgstr "Profiilisi ei löytynyt. Ota yhteyttä ylläpitäjään." - -#: mod/settings.php:1033 -msgid "Account Types" -msgstr "Tilityypit" - -#: mod/settings.php:1034 -msgid "Personal Page Subtypes" -msgstr "Henkilökohtaisen sivun alatyypit" - -#: mod/settings.php:1035 -msgid "Community Forum Subtypes" -msgstr "Yhteisöfoorumin alatyypit" - -#: mod/settings.php:1043 -msgid "Account for a personal profile." -msgstr "Henkilökohtaisen profiilin käyttäjätili." - -#: mod/settings.php:1047 -msgid "" -"Account for an organisation that automatically approves contact requests as " -"\"Followers\"." -msgstr "" - -#: mod/settings.php:1051 -msgid "" -"Account for a news reflector that automatically approves contact requests as" -" \"Followers\"." -msgstr "" - -#: mod/settings.php:1055 -msgid "Account for community discussions." -msgstr "" - -#: mod/settings.php:1059 -msgid "" -"Account for a regular personal profile that requires manual approval of " -"\"Friends\" and \"Followers\"." -msgstr "" - -#: mod/settings.php:1063 -msgid "" -"Account for a public profile that automatically approves contact requests as" -" \"Followers\"." -msgstr "" - -#: mod/settings.php:1067 -msgid "Automatically approves all contact requests." -msgstr "Automaattisesti hyväksyy kaikki kontaktipyynnöt" - -#: mod/settings.php:1071 -msgid "" -"Account for a popular profile that automatically approves contact requests " -"as \"Friends\"." +#: src/Console/Addon.php:203 +msgid "Addon already disabled" msgstr "" -#: mod/settings.php:1074 -msgid "Private Forum [Experimental]" -msgstr "Yksityisfoorumi [kokeellinen]" - -#: mod/settings.php:1075 -msgid "Requires manual approval of contact requests." -msgstr "" - -#: mod/settings.php:1086 -msgid "OpenID:" -msgstr "OpenID:" - -#: mod/settings.php:1086 -msgid "(Optional) Allow this OpenID to login to this account." -msgstr "" - -#: mod/settings.php:1094 -msgid "Publish your default profile in your local site directory?" -msgstr "Julkaise oletusprofiilisi tämän sivuston paikallisluettelossa?" - -#: mod/settings.php:1094 -#, php-format -msgid "" -"Your profile will be published in this node's local " -"directory. Your profile details may be publicly visible depending on the" -" system settings." -msgstr "" - -#: mod/settings.php:1100 -msgid "Publish your default profile in the global social directory?" -msgstr "Julkaise oletusprofiilisi maailmanlaajuisessa sosiaaliluettelossa?" - -#: mod/settings.php:1100 -#, php-format -msgid "" -"Your profile will be published in the global friendica directories (e.g. %s). Your profile will be visible in public." -msgstr "" - -#: mod/settings.php:1107 -msgid "Hide your contact/friend list from viewers of your default profile?" -msgstr "" - -#: mod/settings.php:1107 -msgid "" -"Your contact list won't be shown in your default profile page. You can " -"decide to show your contact list separately for each additional profile you " -"create" -msgstr "" - -#: mod/settings.php:1111 -msgid "Hide your profile details from anonymous viewers?" -msgstr "" - -#: mod/settings.php:1111 -msgid "" -"Anonymous visitors will only see your profile picture, your display name and" -" the nickname you are using on your profile page. Your public posts and " -"replies will still be accessible by other means." -msgstr "" - -#: mod/settings.php:1115 -msgid "Allow friends to post to your profile page?" -msgstr "Anna kavereiden julkaista profiilisivullasi?" - -#: mod/settings.php:1115 -msgid "" -"Your contacts may write posts on your profile wall. These posts will be " -"distributed to your contacts" -msgstr "" - -#: mod/settings.php:1119 -msgid "Allow friends to tag your posts?" -msgstr "Anna kavereiden lisätä tunnisteita julkaisuusi?" - -#: mod/settings.php:1119 -msgid "Your contacts can add additional tags to your posts." -msgstr "Kontaktisi voi lisätä ylimääräisiä tunnisteita julkaisuusi." - -#: mod/settings.php:1123 -msgid "Allow us to suggest you as a potential friend to new members?" -msgstr "" - -#: mod/settings.php:1123 -msgid "" -"If you like, Friendica may suggest new members to add you as a contact." -msgstr "" - -#: mod/settings.php:1127 -msgid "Permit unknown people to send you private mail?" -msgstr "Salli yksityisviesit tuntemattomilta?" - -#: mod/settings.php:1127 -msgid "" -"Friendica network users may send you private messages even if they are not " -"in your contact list." -msgstr "" - -#: mod/settings.php:1131 -msgid "Profile is not published." -msgstr "Profiili ei ole julkaistu." - -#: mod/settings.php:1137 -#, php-format -msgid "Your Identity Address is '%s' or '%s'." -msgstr "Identiteettisi osoite on '%s' tai '%s'." - -#: mod/settings.php:1144 -msgid "Automatically expire posts after this many days:" -msgstr "" - -#: mod/settings.php:1144 -msgid "If empty, posts will not expire. Expired posts will be deleted" -msgstr "Jos kenttä jää tyhjäksi, julkaisut eivät vanhene. Vanhentuneet julkaisut poistetaan." - -#: mod/settings.php:1145 -msgid "Advanced expiration settings" -msgstr "" - -#: mod/settings.php:1146 -msgid "Advanced Expiration" -msgstr "" - -#: mod/settings.php:1147 -msgid "Expire posts:" -msgstr "Julkaisujen vanheneminen:" - -#: mod/settings.php:1148 -msgid "Expire personal notes:" -msgstr "" - -#: mod/settings.php:1149 -msgid "Expire starred posts:" -msgstr "Tähtimerkityt julkaisut vanhenee:" - -#: mod/settings.php:1150 -msgid "Expire photos:" -msgstr "Kuvat vanhenee:" - -#: mod/settings.php:1151 -msgid "Only expire posts by others:" -msgstr "" - -#: mod/settings.php:1181 -msgid "Account Settings" -msgstr "Tiliasetukset" - -#: mod/settings.php:1189 -msgid "Password Settings" -msgstr "Salasana-asetukset" - -#: mod/settings.php:1191 -msgid "Leave password fields blank unless changing" -msgstr "Jätä salasana kenttää tyhjäksi jos et halua vaihtaa salasanaa" - -#: mod/settings.php:1192 -msgid "Current Password:" -msgstr "Nykyinen salasana:" - -#: mod/settings.php:1192 mod/settings.php:1193 -msgid "Your current password to confirm the changes" -msgstr "Syötä nykyinen salasanasi vahvistaaksesi muutokset" - -#: mod/settings.php:1193 -msgid "Password:" -msgstr "Salasana:" - -#: mod/settings.php:1197 -msgid "Basic Settings" -msgstr "Perusasetukset" - -#: mod/settings.php:1198 src/Model/Profile.php:736 -msgid "Full Name:" -msgstr "Koko nimi:" - -#: mod/settings.php:1199 -msgid "Email Address:" -msgstr "Sähköpostiosoite:" - -#: mod/settings.php:1200 -msgid "Your Timezone:" -msgstr "Aikavyöhyke:" - -#: mod/settings.php:1201 -msgid "Your Language:" -msgstr "Kieli:" - -#: mod/settings.php:1201 -msgid "" -"Set the language we use to show you friendica interface and to send you " -"emails" -msgstr "Aseta Friendican käyttöliittymän ja sähköpostiviestien kieli" - -#: mod/settings.php:1202 -msgid "Default Post Location:" -msgstr "Julkaisun oletussijainti:" - -#: mod/settings.php:1203 -msgid "Use Browser Location:" -msgstr "Käytä selaimen sijainti:" - -#: mod/settings.php:1206 -msgid "Security and Privacy Settings" -msgstr "Turvallisuus ja tietosuoja-asetukset" - -#: mod/settings.php:1208 -msgid "Maximum Friend Requests/Day:" -msgstr "Kaveripyyntöraja päivässä:" - -#: mod/settings.php:1208 mod/settings.php:1237 -msgid "(to prevent spam abuse)" -msgstr "(roskapostin estämiseksi)" - -#: mod/settings.php:1209 -msgid "Default Post Permissions" -msgstr "Julkaisun oletuskäyttöoikeudet:" - -#: mod/settings.php:1210 -msgid "(click to open/close)" -msgstr "(klikkaa auki/kiinni)" - -#: mod/settings.php:1220 -msgid "Default Private Post" -msgstr "" - -#: mod/settings.php:1221 -msgid "Default Public Post" -msgstr "" - -#: mod/settings.php:1225 -msgid "Default Permissions for New Posts" -msgstr "Uuden julkaisun oletuskäyttöoikeudet" - -#: mod/settings.php:1237 -msgid "Maximum private messages per day from unknown people:" -msgstr "Enimmäismäärä yksityisviestejä päivässä tuntemattomilta henkilöiltä:" - -#: mod/settings.php:1240 -msgid "Notification Settings" -msgstr "Huomautusasetukset" - -#: mod/settings.php:1241 -msgid "Send a notification email when:" -msgstr "Lähetä sähköposti-ilmoitus kun:" - -#: mod/settings.php:1242 -msgid "You receive an introduction" -msgstr "Vastaanotat kaverikutsun" - -#: mod/settings.php:1243 -msgid "Your introductions are confirmed" -msgstr "Kaverikutsusi on hyväksytty" - -#: mod/settings.php:1244 -msgid "Someone writes on your profile wall" -msgstr "Joku kirjoittaa profiiliseinällesi" - -#: mod/settings.php:1245 -msgid "Someone writes a followup comment" -msgstr "Joku vastaa kommenttiin" - -#: mod/settings.php:1246 -msgid "You receive a private message" -msgstr "Vastaanotat yksityisviestin" - -#: mod/settings.php:1247 -msgid "You receive a friend suggestion" -msgstr "Vastaanotat kaveriehdotuksen" - -#: mod/settings.php:1248 -msgid "You are tagged in a post" -msgstr "Sinut on merkitty julkaisuun" - -#: mod/settings.php:1249 -msgid "You are poked/prodded/etc. in a post" -msgstr "sinut on tökätty tms. julkaisussa" - -#: mod/settings.php:1251 -msgid "Activate desktop notifications" -msgstr "Ota työpöytäilmoitukset käyttöön" - -#: mod/settings.php:1251 -msgid "Show desktop popup on new notifications" -msgstr "Näytä uudet ilmoitukset ponnahdusikkunassa" - -#: mod/settings.php:1253 -msgid "Text-only notification emails" -msgstr "Ilmoitussähköposteissa vain tekstiä" - -#: mod/settings.php:1255 -msgid "Send text only notification emails, without the html part" -msgstr "Lähetä ilmoitussähköposteissa vain tekstiä ilman HTML-koodia" - -#: mod/settings.php:1257 -msgid "Show detailled notifications" -msgstr "Näytä yksityiskohtaiset ilmoitukset" - -#: mod/settings.php:1259 -msgid "" -"Per default, notifications are condensed to a single notification per item. " -"When enabled every notification is displayed." -msgstr "" - -#: mod/settings.php:1261 -msgid "Advanced Account/Page Type Settings" -msgstr "Käyttäjätili/sivutyyppi lisäasetuksia" - -#: mod/settings.php:1262 -msgid "Change the behaviour of this account for special situations" -msgstr "" - -#: mod/settings.php:1265 -msgid "Relocate" -msgstr "Uudelleensijoitus" - -#: mod/settings.php:1266 -msgid "" -"If you have moved this profile from another server, and some of your " -"contacts don't receive your updates, try pushing this button." -msgstr "" - -#: mod/settings.php:1267 -msgid "Resend relocate message to contacts" -msgstr "" - -#: mod/subthread.php:117 -#, php-format -msgid "%1$s is following %2$s's %3$s" -msgstr "" - -#: mod/update_community.php:27 mod/update_display.php:27 -#: mod/update_network.php:33 mod/update_notes.php:40 mod/update_profile.php:39 -msgid "[Embedded content - reload page to view]" -msgstr "[Upotettu sisältö - näet sen päivittämällä sivun]" - -#: mod/videos.php:139 -msgid "Do you really want to delete this video?" -msgstr "Haluatko varmasti poistaa tämän videon?" - -#: mod/videos.php:144 -msgid "Delete Video" -msgstr "Poista video" - -#: mod/videos.php:207 -msgid "No videos selected" -msgstr "Ei videoita valittuna" - -#: mod/videos.php:396 -msgid "Recent Videos" -msgstr "Viimeisimmät videot" - -#: mod/videos.php:398 -msgid "Upload New Videos" -msgstr "Lataa uusia videoita" - -#: view/theme/duepuntozero/config.php:54 src/Model/User.php:504 -msgid "default" -msgstr "oletus" - -#: view/theme/duepuntozero/config.php:55 -msgid "greenzero" -msgstr "greenzero" - -#: view/theme/duepuntozero/config.php:56 -msgid "purplezero" -msgstr "purplezero" - -#: view/theme/duepuntozero/config.php:57 -msgid "easterbunny" -msgstr "easterbunny" - -#: view/theme/duepuntozero/config.php:58 -msgid "darkzero" -msgstr "darkzero" - -#: view/theme/duepuntozero/config.php:59 -msgid "comix" -msgstr "comix" - -#: view/theme/duepuntozero/config.php:60 -msgid "slackr" -msgstr "slackr" - -#: view/theme/duepuntozero/config.php:74 -msgid "Variations" -msgstr "Muunnelmat" - -#: view/theme/frio/php/Image.php:24 -msgid "Top Banner" -msgstr "Yläpalkki" - -#: view/theme/frio/php/Image.php:24 -msgid "" -"Resize image to the width of the screen and show background color below on " -"long pages." -msgstr "" - -#: view/theme/frio/php/Image.php:25 -msgid "Full screen" -msgstr "Koko näyttö" - -#: view/theme/frio/php/Image.php:25 -msgid "" -"Resize image to fill entire screen, clipping either the right or the bottom." -msgstr "" - -#: view/theme/frio/php/Image.php:26 -msgid "Single row mosaic" -msgstr "" - -#: view/theme/frio/php/Image.php:26 -msgid "" -"Resize image to repeat it on a single row, either vertical or horizontal." -msgstr "" - -#: view/theme/frio/php/Image.php:27 -msgid "Mosaic" -msgstr "Mosaiikki" - -#: view/theme/frio/php/Image.php:27 -msgid "Repeat image to fill the screen." -msgstr "" - -#: view/theme/frio/config.php:102 -msgid "Custom" -msgstr "" - -#: view/theme/frio/config.php:114 -msgid "Note" -msgstr "Muistiinpano" - -#: view/theme/frio/config.php:114 -msgid "Check image permissions if all users are allowed to see the image" -msgstr "" - -#: view/theme/frio/config.php:121 -msgid "Select color scheme" -msgstr "Valitse värimalli" - -#: view/theme/frio/config.php:122 -msgid "Navigation bar background color" -msgstr "Navigointipalkin taustaväri" - -#: view/theme/frio/config.php:123 -msgid "Navigation bar icon color " -msgstr "Navigointipalkin kuvakkeiden väri" - -#: view/theme/frio/config.php:124 -msgid "Link color" -msgstr "Linkin väri" - -#: view/theme/frio/config.php:125 -msgid "Set the background color" -msgstr "Valitse taustaväri" - -#: view/theme/frio/config.php:126 -msgid "Content background opacity" -msgstr "Sisällön taustasameus" - -#: view/theme/frio/config.php:127 -msgid "Set the background image" -msgstr "Valitse taustakuva" - -#: view/theme/frio/config.php:128 -msgid "Background image style" -msgstr "Taustakuvan tyyli" - -#: view/theme/frio/config.php:133 -msgid "Login page background image" -msgstr "Sisäänkirjautumissivun taustakuva" - -#: view/theme/frio/config.php:137 -msgid "Login page background color" -msgstr "Sisäänkirjautumissivun taustaväri" - -#: view/theme/frio/config.php:137 -msgid "Leave background image and color empty for theme defaults" -msgstr "Jätä taustakuva ja väri tyhjäksi käyttääksesi teeman oletuksia" - -#: view/theme/frio/theme.php:238 -msgid "Guest" -msgstr "Vieras" - -#: view/theme/frio/theme.php:243 -msgid "Visitor" -msgstr "Vierailija" - -#: view/theme/frio/theme.php:256 src/Content/Nav.php:97 -#: src/Module/Login.php:312 -msgid "Logout" -msgstr "Kirjaudu ulos" - -#: view/theme/frio/theme.php:256 src/Content/Nav.php:97 -msgid "End this session" -msgstr "Lopeta istunto" - -#: view/theme/frio/theme.php:259 src/Content/Nav.php:100 -#: src/Content/Nav.php:186 -msgid "Your posts and conversations" -msgstr "Omat julkaisut ja keskustelut" - -#: view/theme/frio/theme.php:260 src/Content/Nav.php:101 -msgid "Your profile page" -msgstr "Oma profiilisivu" - -#: view/theme/frio/theme.php:261 src/Content/Nav.php:102 -msgid "Your photos" -msgstr "Omat kuvat" - -#: view/theme/frio/theme.php:262 src/Content/Nav.php:103 -#: src/Model/Profile.php:910 src/Model/Profile.php:913 -msgid "Videos" -msgstr "Videot" - -#: view/theme/frio/theme.php:262 src/Content/Nav.php:103 -msgid "Your videos" -msgstr "Omat videot" - -#: view/theme/frio/theme.php:263 src/Content/Nav.php:104 -msgid "Your events" -msgstr "Omat tapahtumat" - -#: view/theme/frio/theme.php:266 src/Content/Nav.php:183 -msgid "Conversations from your friends" -msgstr "Kavereiden keskustelut" - -#: view/theme/frio/theme.php:267 src/Content/Nav.php:170 -#: src/Model/Profile.php:925 src/Model/Profile.php:936 -msgid "Events and Calendar" -msgstr "Tapahtumat ja kalenteri" - -#: view/theme/frio/theme.php:268 src/Content/Nav.php:196 -msgid "Private mail" -msgstr "Yksityinen posti" - -#: view/theme/frio/theme.php:269 src/Content/Nav.php:207 -msgid "Account settings" -msgstr "Tiliasetukset" - -#: view/theme/frio/theme.php:270 src/Content/Nav.php:213 -msgid "Manage/edit friends and contacts" -msgstr "Hallitse/muokkaa kaverit ja kontaktit" - -#: view/theme/quattro/config.php:76 -msgid "Alignment" -msgstr "Kohdistaminen" - -#: view/theme/quattro/config.php:76 -msgid "Left" -msgstr "Vasemmalle" - -#: view/theme/quattro/config.php:76 -msgid "Center" -msgstr "Keskelle" - -#: view/theme/quattro/config.php:77 -msgid "Color scheme" -msgstr "Värimalli" - -#: view/theme/quattro/config.php:78 -msgid "Posts font size" -msgstr "Julkaisujen fonttikoko" - -#: view/theme/quattro/config.php:79 -msgid "Textareas font size" -msgstr "Tekstikenttien fonttikoko" - -#: view/theme/vier/config.php:75 -msgid "Comma separated list of helper forums" -msgstr "" - -#: view/theme/vier/config.php:115 src/Core/ACL.php:309 -msgid "don't show" -msgstr "älä näytä" - -#: view/theme/vier/config.php:115 src/Core/ACL.php:308 -msgid "show" -msgstr "näytä" - -#: view/theme/vier/config.php:122 -msgid "Set style" -msgstr "Aseta tyyli" - -#: view/theme/vier/config.php:123 -msgid "Community Pages" -msgstr "Yhteisösivut" - -#: view/theme/vier/config.php:124 view/theme/vier/theme.php:150 -msgid "Community Profiles" -msgstr "Yhteisöprofiilit" - -#: view/theme/vier/config.php:125 -msgid "Help or @NewHere ?" -msgstr "" - -#: view/theme/vier/config.php:126 view/theme/vier/theme.php:388 -msgid "Connect Services" -msgstr "Yhdistä palvelut" - -#: view/theme/vier/config.php:127 -msgid "Find Friends" -msgstr "Etsi kavereita" - -#: view/theme/vier/config.php:128 view/theme/vier/theme.php:181 -msgid "Last users" -msgstr "Viimeisimmät käyttäjät" - -#: view/theme/vier/theme.php:199 src/Content/Widget.php:59 -msgid "Find People" -msgstr "Löydä ihmisiä" - -#: view/theme/vier/theme.php:200 src/Content/Widget.php:60 -msgid "Enter name or interest" -msgstr "Syötä nimi tai harrastus" - -#: view/theme/vier/theme.php:202 src/Content/Widget.php:62 -msgid "Examples: Robert Morgenstein, Fishing" -msgstr "Esim. Matti Meikäläinen, kalastus yms." - -#: view/theme/vier/theme.php:205 src/Content/Widget.php:65 -msgid "Similar Interests" -msgstr "Yhteiset harrastukset" - -#: view/theme/vier/theme.php:206 src/Content/Widget.php:66 -msgid "Random Profile" -msgstr "Satunnainen profiili" - -#: view/theme/vier/theme.php:207 src/Content/Widget.php:67 -msgid "Invite Friends" -msgstr "Kutsu kavereita" - -#: view/theme/vier/theme.php:210 src/Content/Widget.php:70 -msgid "Local Directory" -msgstr "Paikallinen hakemisto" - -#: view/theme/vier/theme.php:255 src/Content/ForumManager.php:127 -msgid "External link to forum" -msgstr "Ulkoinen linkki foorumiin" - -#: view/theme/vier/theme.php:291 -msgid "Quick Start" -msgstr "Pika-aloitus" - -#: src/Core/UserImport.php:104 -msgid "Error decoding account file" -msgstr "Tilitiedoston tulkinnassa tapahtui virhe" - -#: src/Core/UserImport.php:110 -msgid "Error! No version data in file! This is not a Friendica account file?" -msgstr "Virhe: tiedostosta puuttuu versiotiedot! Saattaa olla että tämä ei ole Friendica -tilitiedosto?" - -#: src/Core/UserImport.php:118 -#, php-format -msgid "User '%s' already exists on this server!" -msgstr "Käyttäjä '%s' on jo olemassa tällä palvelimella!" - -#: src/Core/UserImport.php:151 -msgid "User creation error" -msgstr "Virhe käyttäjän luomisessa" - -#: src/Core/UserImport.php:169 -msgid "User profile creation error" -msgstr "Virhe käyttäjäprofiilin luomisessa" - -#: src/Core/UserImport.php:213 -#, php-format -msgid "%d contact not imported" -msgid_plural "%d contacts not imported" -msgstr[0] "%d kontakti ei tuotu" -msgstr[1] "%d kontakteja ei tuotu" - -#: src/Core/UserImport.php:278 -msgid "Done. You can now login with your username and password" -msgstr "Suoritettu. Voit nyt kirjautua sisään käyttäjätunnuksellasi." - -#: src/Core/ACL.php:295 -msgid "Post to Email" -msgstr "Viesti sähköpostiin" - -#: src/Core/ACL.php:301 -msgid "Hide your profile details from unknown viewers?" -msgstr "Piilota profiilitietosi tuntemattomilta?" - -#: src/Core/ACL.php:300 -#, php-format -msgid "Connectors disabled, since \"%s\" is enabled." -msgstr "" - -#: src/Core/ACL.php:307 -msgid "Visible to everybody" -msgstr "Näkyvissä kaikille" - -#: src/Core/ACL.php:319 -msgid "Close" -msgstr "Sulje" - -#: src/Core/Console/NewPassword.php:78 -msgid "Enter new password: " -msgstr "Syötä uusi salasana:" - -#: src/Core/Console/NewPassword.php:83 src/Model/User.php:262 -msgid "Password can't be empty" -msgstr "Salasanakenttä ei voi olla tyhjä" - -#: src/Core/Console/ArchiveContact.php:67 +#: src/Console/ArchiveContact.php:106 #, php-format msgid "Could not find any unarchived contact entry for this URL (%s)" msgstr "" -#: src/Core/Console/ArchiveContact.php:72 +#: src/Console/ArchiveContact.php:109 msgid "The contact entries have been archived" msgstr "" -#: src/Core/NotificationsManager.php:171 -msgid "System" -msgstr "Järjestelmä" - -#: src/Core/NotificationsManager.php:192 src/Content/Nav.php:124 -#: src/Content/Nav.php:186 -msgid "Home" -msgstr "Koti" - -#: src/Core/NotificationsManager.php:199 src/Content/Nav.php:190 -msgid "Introductions" -msgstr "Esittelyt" - -#: src/Core/NotificationsManager.php:256 src/Core/NotificationsManager.php:268 +#: src/Console/GlobalCommunityBlock.php:96 +#: src/Module/Moderation/Blocklist/Contact.php:65 #, php-format -msgid "%s commented on %s's post" -msgstr "%s kommentoi julkaisuun jonka kirjoitti %s" - -#: src/Core/NotificationsManager.php:267 -#, php-format -msgid "%s created a new post" -msgstr "%s loi uuden julkaisun" - -#: src/Core/NotificationsManager.php:281 -#, php-format -msgid "%s liked %s's post" -msgstr "%s tykkäsi julkaisusta jonka kirjoitti %s" - -#: src/Core/NotificationsManager.php:294 -#, php-format -msgid "%s disliked %s's post" -msgstr "%s ei tykännyt julkaisusta jonka kirjoitti %s" - -#: src/Core/NotificationsManager.php:307 -#, php-format -msgid "%s is attending %s's event" -msgstr "%s osallistuu tapahtumaan jonka järjestää %s" - -#: src/Core/NotificationsManager.php:320 -#, php-format -msgid "%s is not attending %s's event" -msgstr "%s ei osallistu tapahtumaan jonka järjestää %s" - -#: src/Core/NotificationsManager.php:333 -#, php-format -msgid "%s may attend %s's event" -msgstr "%s ehkä osallistuu tapahtumaan jonka järjestää %s" - -#: src/Core/NotificationsManager.php:350 -#, php-format -msgid "%s is now friends with %s" -msgstr "%s ja %s ovat kavereita" - -#: src/Core/NotificationsManager.php:825 -msgid "Friend Suggestion" -msgstr "Kaveriehdotus" - -#: src/Core/NotificationsManager.php:851 -msgid "Friend/Connect Request" -msgstr "Ystävä/yhteyspyyntö" - -#: src/Core/NotificationsManager.php:851 -msgid "New Follower" -msgstr "Uusi seuraaja" - -#: src/Core/Install.php:157 -msgid "Could not find a command line version of PHP in the web server PATH." -msgstr "Komentoriviversiota PHP:stä ei löytynyt web-palvelimen PATH:ista." - -#: src/Core/Install.php:158 -msgid "" -"If you don't have a command line version of PHP installed on your server, " -"you will not be able to run the background processing. See 'Setup the worker'" +msgid "Could not find any contact entry for this URL (%s)" msgstr "" -#: src/Core/Install.php:162 -msgid "PHP executable path" -msgstr "Polku PHP-ohjelmaan" +#: src/Console/GlobalCommunityBlock.php:101 +#: src/Module/Moderation/Blocklist/Contact.php:82 +msgid "The contact has been blocked from the node" +msgstr "Kontakti on estetty tällä solmulla" -#: src/Core/Install.php:162 -msgid "" -"Enter full path to php executable. You can leave this blank to continue the " -"installation." -msgstr "Kirjoita koko polku PHP-ohjelmaan. Voit jättää sen tyhjäksi, jos haluat jatkaa asennusta." - -#: src/Core/Install.php:167 -msgid "Command line PHP" -msgstr "Komentorivi-PHP" - -#: src/Core/Install.php:176 -msgid "PHP executable is not the php cli binary (could be cgi-fgci version)" -msgstr "" - -#: src/Core/Install.php:177 -msgid "Found PHP version: " -msgstr "PHP-versio löydetty:" - -#: src/Core/Install.php:179 -msgid "PHP cli binary" -msgstr "PHP cli -binääritiedosto" - -#: src/Core/Install.php:189 -msgid "" -"The command line version of PHP on your system does not have " -"\"register_argc_argv\" enabled." -msgstr "Järjestelmäsi komentorivi-PHP:ssä ei ole käytössä asetusta \"register_argc_argv\"." - -#: src/Core/Install.php:190 -msgid "This is required for message delivery to work." -msgstr "Asetus vaaditaan viestien lähettämiseen." - -#: src/Core/Install.php:192 -msgid "PHP register_argc_argv" -msgstr "PHP register_argc_argv" - -#: src/Core/Install.php:220 -msgid "" -"Error: the \"openssl_pkey_new\" function on this system is not able to " -"generate encryption keys" -msgstr "Virhe: järjestelmäsi \"openssl_pkey_new\" -funktio ei pysty generoimaan salausavaimia." - -#: src/Core/Install.php:221 -msgid "" -"If running under Windows, please see " -"\"http://www.php.net/manual/en/openssl.installation.php\"." -msgstr "Jos on kyse Windows-pavelimesta, katso \"http://www.php.net/manual/en/openssl.installation.php\"." - -#: src/Core/Install.php:223 -msgid "Generate encryption keys" -msgstr "Luo salausavaimet" - -#: src/Core/Install.php:244 -msgid "libCurl PHP module" -msgstr "PHP-moduuli libCurl" - -#: src/Core/Install.php:245 -msgid "GD graphics PHP module" -msgstr "PHP-moduuli GD graphics" - -#: src/Core/Install.php:246 -msgid "OpenSSL PHP module" -msgstr "PHP-moduuli OpenSSL" - -#: src/Core/Install.php:247 -msgid "PDO or MySQLi PHP module" -msgstr "PDO tai MySQLi PHP-moduuli" - -#: src/Core/Install.php:248 -msgid "mb_string PHP module" -msgstr "PHP-moduuli mb_string" - -#: src/Core/Install.php:249 -msgid "XML PHP module" -msgstr "XML PHP-moduuli" - -#: src/Core/Install.php:250 -msgid "iconv PHP module" -msgstr "iconv PHP-moduuli" - -#: src/Core/Install.php:251 -msgid "POSIX PHP module" -msgstr "POSIX PHP-moduuli" - -#: src/Core/Install.php:255 src/Core/Install.php:257 -msgid "Apache mod_rewrite module" -msgstr "Apache mod_rewrite -moduuli" - -#: src/Core/Install.php:255 -msgid "" -"Error: Apache webserver mod-rewrite module is required but not installed." -msgstr "Virhe: Apache-palvelimen mod-rewrite -moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:263 -msgid "Error: libCURL PHP module required but not installed." -msgstr "Virhe: libCURL PHP -moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:267 -msgid "" -"Error: GD graphics PHP module with JPEG support required but not installed." -msgstr "Virhe: GD graphics PHP -moduuli JPEG-tuella vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:271 -msgid "Error: openssl PHP module required but not installed." -msgstr "Virhe: openssl PHP -moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:275 -msgid "Error: PDO or MySQLi PHP module required but not installed." -msgstr "Virhe: PDO tai MySQLi PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:279 -msgid "Error: The MySQL driver for PDO is not installed." -msgstr "Virhe: PDO:n MySQL-ajuri ei ole asennettu" - -#: src/Core/Install.php:283 -msgid "Error: mb_string PHP module required but not installed." -msgstr "Virhe: PHP-moduuli mb_string vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:287 -msgid "Error: iconv PHP module required but not installed." -msgstr "Virhe: iconv PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:291 -msgid "Error: POSIX PHP module required but not installed." -msgstr "Virhe: POSIX PHP-moduuli vaadittaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:301 -msgid "Error, XML PHP module required but not installed." -msgstr "Virhe: XML PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." - -#: src/Core/Install.php:320 -msgid "" -"The web installer needs to be able to create a file called \".htconfig.php\"" -" in the top folder of your web server and it is unable to do so." -msgstr "Web-asennuksen pitäisi pystyä luomaan tiedosto nimeltä \".htconfig.php\" palvelimesi ylimpään kansioon, mutta se ei nyt onnistu." - -#: src/Core/Install.php:321 -msgid "" -"This is most often a permission setting, as the web server may not be able " -"to write files in your folder - even if you can." -msgstr "Tämä on yleensä käyttöoikeusasetus, jolloin web-palvelimesi ei pysty kirjoittamaan tiedostoja kansioosi, vaikka itse siihen pystyisit." - -#: src/Core/Install.php:322 -msgid "" -"At the end of this procedure, we will give you a text to save in a file " -"named .htconfig.php in your Friendica top folder." -msgstr "Tämän menettelyn lopussa annamme sinulle tekstin tallennettavaksi tiedostoon nimeltä .htconfig.php Friendican ylätason kansiossa." - -#: src/Core/Install.php:323 -msgid "" -"You can alternatively skip this procedure and perform a manual installation." -" Please see the file \"INSTALL.txt\" for instructions." -msgstr "" - -#: src/Core/Install.php:326 -msgid ".htconfig.php is writable" -msgstr ".htconfig.php on kirjoitettava" - -#: src/Core/Install.php:344 -msgid "" -"Friendica uses the Smarty3 template engine to render its web views. Smarty3 " -"compiles templates to PHP to speed up rendering." -msgstr "" - -#: src/Core/Install.php:345 -msgid "" -"In order to store these compiled templates, the web server needs to have " -"write access to the directory view/smarty3/ under the Friendica top level " -"folder." -msgstr "" - -#: src/Core/Install.php:346 -msgid "" -"Please ensure that the user that your web server runs as (e.g. www-data) has" -" write access to this folder." -msgstr "" - -#: src/Core/Install.php:347 -msgid "" -"Note: as a security measure, you should give the web server write access to " -"view/smarty3/ only--not the template files (.tpl) that it contains." -msgstr "" - -#: src/Core/Install.php:350 -msgid "view/smarty3 is writable" -msgstr "view/smarty3 on kirjoitettava" - -#: src/Core/Install.php:375 -msgid "" -"Url rewrite in .htaccess is not working. Check your server configuration." -msgstr "URL-osoitteen uudelleenkirjoitus .htaccess-tiedostossa ei toimi. Tarkista palvelimen asetukset." - -#: src/Core/Install.php:377 -msgid "Error message from Curl when fetching" -msgstr "" - -#: src/Core/Install.php:381 -msgid "Url rewrite is working" -msgstr "URL-osoitteen uudellenkirjoitus toimii" - -#: src/Core/Install.php:408 -msgid "ImageMagick PHP extension is not installed" -msgstr "ImageMagick PHP-laajennus ei ole asetettu" - -#: src/Core/Install.php:410 -msgid "ImageMagick PHP extension is installed" -msgstr "ImageMagick PHP-laajennus on asetettu" - -#: src/Core/Install.php:412 -msgid "ImageMagick supports GIF" -msgstr "ImageMagik tukee GIF-formaattia" - -#: src/Util/Temporal.php:147 src/Model/Profile.php:756 -msgid "Birthday:" -msgstr "Syntymäpäivä:" - -#: src/Util/Temporal.php:151 -msgid "YYYY-MM-DD or MM-DD" -msgstr "VVVV-KK-PP tai KK-PP" - -#: src/Util/Temporal.php:294 -msgid "never" -msgstr "ei ikinä" - -#: src/Util/Temporal.php:300 -msgid "less than a second ago" -msgstr "alle sekunti sitten" - -#: src/Util/Temporal.php:303 -msgid "year" -msgstr "vuosi" - -#: src/Util/Temporal.php:303 -msgid "years" -msgstr "vuotta" - -#: src/Util/Temporal.php:304 -msgid "months" -msgstr "kuukautta" - -#: src/Util/Temporal.php:305 -msgid "weeks" -msgstr "viikkoa" - -#: src/Util/Temporal.php:306 -msgid "days" -msgstr "päivää" - -#: src/Util/Temporal.php:307 -msgid "hour" -msgstr "tunti" - -#: src/Util/Temporal.php:307 -msgid "hours" -msgstr "tuntia" - -#: src/Util/Temporal.php:308 -msgid "minute" -msgstr "minuutti" - -#: src/Util/Temporal.php:308 -msgid "minutes" -msgstr "inuuttia" - -#: src/Util/Temporal.php:309 -msgid "second" -msgstr "sekunti" - -#: src/Util/Temporal.php:309 -msgid "seconds" -msgstr "sekuntia" - -#: src/Util/Temporal.php:318 +#: src/Console/MergeContacts.php:75 #, php-format -msgid "%1$d %2$s ago" -msgstr "%1$d %2$s sitten" +msgid "%d %s, %d duplicates." +msgstr "" -#: src/Content/Text/BBCode.php:426 -msgid "view full size" -msgstr "näytä täysikokoisena" - -#: src/Content/Text/BBCode.php:852 src/Content/Text/BBCode.php:1621 -#: src/Content/Text/BBCode.php:1622 -msgid "Image/photo" -msgstr "Kuva/valokuva" - -#: src/Content/Text/BBCode.php:990 +#: src/Console/MergeContacts.php:78 #, php-format -msgid "%2$s %3$s" -msgstr "%2$s %3$s" +msgid "uri-id is empty for contact %s." +msgstr "" -#: src/Content/Text/BBCode.php:1548 src/Content/Text/BBCode.php:1570 -msgid "$1 wrote:" -msgstr "$1 kirjoitti:" +#: src/Console/MergeContacts.php:91 +#, php-format +msgid "No valid first contact found for uri-id %d." +msgstr "" -#: src/Content/Text/BBCode.php:1630 src/Content/Text/BBCode.php:1631 -msgid "Encrypted content" -msgstr "Salattu sisältö" +#: src/Console/MergeContacts.php:102 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (url: %s != %s)." +msgstr "" -#: src/Content/Text/BBCode.php:1750 -msgid "Invalid source protocol" -msgstr "Virheellinen lähdeprotokolla" +#: src/Console/MergeContacts.php:106 +#, php-format +msgid "Wrong duplicate found for uri-id %d in %d (nurl: %s != %s)." +msgstr "" -#: src/Content/Text/BBCode.php:1761 -msgid "Invalid link protocol" -msgstr "Virheellinen linkkiprotokolla" +#: src/Console/MergeContacts.php:142 +#, php-format +msgid "Deletion of id %d failed" +msgstr "" -#: src/Content/OEmbed.php:253 -msgid "Embedding disabled" -msgstr "Upottaminen poistettu käytöstä" +#: src/Console/MergeContacts.php:144 +#, php-format +msgid "Deletion of id %d was successful" +msgstr "" -#: src/Content/OEmbed.php:373 -msgid "Embedded content" -msgstr "Upotettu sisältö" +#: src/Console/MergeContacts.php:150 +#, php-format +msgid "Updating \"%s\" in \"%s\" from %d to %d" +msgstr "" -#: src/Content/Widget/CalendarExport.php:61 -msgid "Export" -msgstr "Vie" +#: src/Console/MergeContacts.php:152 +msgid " - found" +msgstr "" -#: src/Content/Widget/CalendarExport.php:62 -msgid "Export calendar as ical" -msgstr "Vie kalenteri ical -tiedostona" +#: src/Console/MergeContacts.php:159 +msgid " - failed" +msgstr "" -#: src/Content/Widget/CalendarExport.php:63 -msgid "Export calendar as csv" -msgstr "Vie kalenteri csv-tiedostona" +#: src/Console/MergeContacts.php:161 +msgid " - success" +msgstr "" -#: src/Content/ContactSelector.php:55 +#: src/Console/MergeContacts.php:165 +msgid " - deleted" +msgstr "" + +#: src/Console/MergeContacts.php:168 +msgid " - done" +msgstr "" + +#: src/Console/MoveToAvatarCache.php:91 +msgid "The avatar cache needs to be enabled to use this command." +msgstr "" + +#: src/Console/MoveToAvatarCache.php:109 +#, php-format +msgid "no resource in photo %s" +msgstr "" + +#: src/Console/MoveToAvatarCache.php:137 +#, php-format +msgid "no photo with id %s" +msgstr "" + +#: src/Console/MoveToAvatarCache.php:146 +#, php-format +msgid "no image data for photo with id %s" +msgstr "" + +#: src/Console/MoveToAvatarCache.php:155 +#, php-format +msgid "invalid image for id %s" +msgstr "" + +#: src/Console/MoveToAvatarCache.php:168 +#, php-format +msgid "Quit on invalid photo %s" +msgstr "" + +#: src/Console/PostUpdate.php:87 +#, php-format +msgid "Post update version number has been set to %s." +msgstr "" + +#: src/Console/PostUpdate.php:95 +msgid "Check for pending update actions." +msgstr "" + +#: src/Console/PostUpdate.php:97 +msgid "Done." +msgstr "" + +#: src/Console/PostUpdate.php:99 +msgid "Execute pending post updates." +msgstr "" + +#: src/Console/PostUpdate.php:105 +msgid "All pending post updates are done." +msgstr "" + +#: src/Console/User.php:158 src/Console/User.php:245 +msgid "Enter user nickname: " +msgstr "" + +#: src/Console/User.php:182 src/Model/User.php:663 +#: src/Module/Api/Twitter/ContactEndpoint.php:74 +#: src/Module/Moderation/Users/Active.php:71 +#: src/Module/Moderation/Users/Blocked.php:71 +#: src/Module/Moderation/Users/Index.php:78 +#: src/Module/Moderation/Users/Pending.php:67 +msgid "User not found" +msgstr "Käyttäjää ei löydy" + +#: src/Console/User.php:202 +msgid "Enter new password: " +msgstr "Syötä uusi salasana:" + +#: src/Console/User.php:210 src/Module/Security/PasswordTooLong.php:69 +#: src/Module/Settings/Account.php:75 +msgid "Password update failed. Please try again." +msgstr "Salasanan vaihto epäonnistui. Yritä uudelleen." + +#: src/Console/User.php:213 src/Module/Security/PasswordTooLong.php:72 +#: src/Module/Settings/Account.php:78 +msgid "Password changed." +msgstr "Salasana vaihdettu." + +#: src/Console/User.php:237 +msgid "Enter user name: " +msgstr "" + +#: src/Console/User.php:253 +msgid "Enter user email address: " +msgstr "" + +#: src/Console/User.php:261 +msgid "Enter a language (optional): " +msgstr "" + +#: src/Console/User.php:286 +msgid "User is not pending." +msgstr "" + +#: src/Console/User.php:318 +msgid "User has already been marked for deletion." +msgstr "" + +#: src/Console/User.php:323 +#, php-format +msgid "Type \"yes\" to delete %s" +msgstr "" + +#: src/Console/User.php:325 +msgid "Deletion aborted." +msgstr "" + +#: src/Console/User.php:450 +msgid "Enter category: " +msgstr "" + +#: src/Console/User.php:460 +msgid "Enter key: " +msgstr "" + +#: src/Console/User.php:494 +msgid "Enter value: " +msgstr "" + +#: src/Content/BoundariesPager.php:116 src/Content/Pager.php:171 +msgid "newer" +msgstr "uudempi" + +#: src/Content/BoundariesPager.php:124 src/Content/Pager.php:176 +msgid "older" +msgstr "vanhempi" + +#: src/Content/ContactSelector.php:51 msgid "Frequently" msgstr "Usein" -#: src/Content/ContactSelector.php:56 +#: src/Content/ContactSelector.php:52 msgid "Hourly" msgstr "Tunneittain" -#: src/Content/ContactSelector.php:57 +#: src/Content/ContactSelector.php:53 msgid "Twice daily" msgstr "Kahdesti päivässä" -#: src/Content/ContactSelector.php:58 +#: src/Content/ContactSelector.php:54 msgid "Daily" msgstr "Päivittäin" -#: src/Content/ContactSelector.php:59 +#: src/Content/ContactSelector.php:55 msgid "Weekly" msgstr "Viikottain" -#: src/Content/ContactSelector.php:60 +#: src/Content/ContactSelector.php:56 msgid "Monthly" msgstr "Kuukausittain" -#: src/Content/ContactSelector.php:80 +#: src/Content/ContactSelector.php:126 +msgid "DFRN" +msgstr "" + +#: src/Content/ContactSelector.php:127 msgid "OStatus" msgstr "OStatus" -#: src/Content/ContactSelector.php:81 +#: src/Content/ContactSelector.php:128 msgid "RSS/Atom" msgstr "RSS/Atom" -#: src/Content/ContactSelector.php:84 -msgid "Facebook" -msgstr "Facebook" +#: src/Content/ContactSelector.php:129 +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Create.php:72 +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:140 +#: src/Module/Moderation/Users/Index.php:160 +#: src/Module/Moderation/Users/Pending.php:99 +msgid "Email" +msgstr "Sähköposti" -#: src/Content/ContactSelector.php:85 +#: src/Content/ContactSelector.php:130 src/Module/Debug/Babel.php:307 +msgid "Diaspora" +msgstr "Diaspora" + +#: src/Content/ContactSelector.php:131 msgid "Zot!" msgstr "Zot!" -#: src/Content/ContactSelector.php:86 +#: src/Content/ContactSelector.php:132 msgid "LinkedIn" msgstr "LinkedIn" -#: src/Content/ContactSelector.php:87 +#: src/Content/ContactSelector.php:133 msgid "XMPP/IM" msgstr "XMPP/IM" -#: src/Content/ContactSelector.php:88 +#: src/Content/ContactSelector.php:134 msgid "MySpace" msgstr "MySpace" -#: src/Content/ContactSelector.php:89 +#: src/Content/ContactSelector.php:135 msgid "Google+" msgstr "Google+" -#: src/Content/ContactSelector.php:90 +#: src/Content/ContactSelector.php:136 msgid "pump.io" msgstr "pump.io" -#: src/Content/ContactSelector.php:91 +#: src/Content/ContactSelector.php:137 msgid "Twitter" msgstr "Twitter" -#: src/Content/ContactSelector.php:92 +#: src/Content/ContactSelector.php:138 +msgid "Discourse" +msgstr "" + +#: src/Content/ContactSelector.php:139 msgid "Diaspora Connector" msgstr "Diaspora -liitin" -#: src/Content/ContactSelector.php:93 +#: src/Content/ContactSelector.php:140 msgid "GNU Social Connector" msgstr "GNU social -liitin" -#: src/Content/ContactSelector.php:94 +#: src/Content/ContactSelector.php:141 +msgid "ActivityPub" +msgstr "" + +#: src/Content/ContactSelector.php:142 msgid "pnut" msgstr "pnut" -#: src/Content/ContactSelector.php:95 -msgid "App.net" -msgstr "App.net" - -#: src/Content/ContactSelector.php:125 -msgid "Male" -msgstr "Mies" - -#: src/Content/ContactSelector.php:125 -msgid "Female" -msgstr "Nainen" - -#: src/Content/ContactSelector.php:125 -msgid "Currently Male" -msgstr "Tällä hetkellä mies" - -#: src/Content/ContactSelector.php:125 -msgid "Currently Female" -msgstr "Tällä hetkellä nainen" - -#: src/Content/ContactSelector.php:125 -msgid "Mostly Male" -msgstr "Enimmäkseen mies" - -#: src/Content/ContactSelector.php:125 -msgid "Mostly Female" -msgstr "Enimmäkseen nainen" - -#: src/Content/ContactSelector.php:125 -msgid "Transgender" -msgstr "Transsukupuolinen" - -#: src/Content/ContactSelector.php:125 -msgid "Intersex" -msgstr "Intersukupuolinen" - -#: src/Content/ContactSelector.php:125 -msgid "Transsexual" -msgstr "Transsukupuolinen" - -#: src/Content/ContactSelector.php:125 -msgid "Hermaphrodite" -msgstr "Hermafrodiitti" - -#: src/Content/ContactSelector.php:125 -msgid "Neuter" -msgstr "Neutri" - -#: src/Content/ContactSelector.php:125 -msgid "Non-specific" -msgstr "Ei-binäärinen" - -#: src/Content/ContactSelector.php:125 -msgid "Other" -msgstr "Toinen" - -#: src/Content/ContactSelector.php:147 -msgid "Males" -msgstr "Miehet" - -#: src/Content/ContactSelector.php:147 -msgid "Females" -msgstr "Naiset" - -#: src/Content/ContactSelector.php:147 -msgid "Gay" -msgstr "Homo" - -#: src/Content/ContactSelector.php:147 -msgid "Lesbian" -msgstr "Lesbo" - -#: src/Content/ContactSelector.php:147 -msgid "No Preference" +#: src/Content/ContactSelector.php:143 +msgid "Tumblr" msgstr "" -#: src/Content/ContactSelector.php:147 -msgid "Bisexual" -msgstr "Biseksuaali" - -#: src/Content/ContactSelector.php:147 -msgid "Autosexual" -msgstr "Autoseksuaalinen" - -#: src/Content/ContactSelector.php:147 -msgid "Abstinent" -msgstr "Selibaatissa elävä" - -#: src/Content/ContactSelector.php:147 -msgid "Virgin" -msgstr "Neitsyt" - -#: src/Content/ContactSelector.php:147 -msgid "Deviant" +#: src/Content/ContactSelector.php:144 +msgid "Bluesky" msgstr "" -#: src/Content/ContactSelector.php:147 -msgid "Fetish" -msgstr "Fetissi" - -#: src/Content/ContactSelector.php:147 -msgid "Oodles" +#: src/Content/ContactSelector.php:180 +#, php-format +msgid "%s (via %s)" msgstr "" -#: src/Content/ContactSelector.php:147 -msgid "Nonsexual" -msgstr "Aseksuaali" +#: src/Content/Conversation.php:218 +msgid "and" +msgstr "ja" -#: src/Content/ContactSelector.php:169 -msgid "Single" -msgstr "Sinkku" +#: src/Content/Conversation.php:221 +#, php-format +msgid "and %d other people" +msgstr "ja %d muuta ihmistä" -#: src/Content/ContactSelector.php:169 -msgid "Lonely" -msgstr "Yksinäinen" +#: src/Content/Conversation.php:227 +#, php-format +msgid "%2$s likes this." +msgid_plural "%2$s like this." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Available" -msgstr "Saatavilla" +#: src/Content/Conversation.php:229 +#, php-format +msgid "%2$s doesn't like this." +msgid_plural "%2$s don't like this." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Unavailable" -msgstr "Ei saatavilla" +#: src/Content/Conversation.php:231 +#, php-format +msgid "%2$s attends." +msgid_plural "%2$s attend." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Has crush" -msgstr "Ihastunut" +#: src/Content/Conversation.php:233 +#, php-format +msgid "%2$s doesn't attend." +msgid_plural "%2$s don't attend." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Infatuated" -msgstr "Hullaantunut" +#: src/Content/Conversation.php:235 +#, php-format +msgid "%2$s attends maybe." +msgid_plural "%2$s attend maybe." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Dating" -msgstr "Seurustelee" +#: src/Content/Conversation.php:237 +#, php-format +msgid "%2$s reshared this." +msgid_plural "%2$s reshared this." +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Unfaithful" -msgstr "Uskoton" +#: src/Content/Conversation.php:266 +#, php-format +msgid " likes this" +msgid_plural " like this" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Sex Addict" -msgstr "Sekririippuvainen" +#: src/Content/Conversation.php:269 +#, php-format +msgid " doesn't like this" +msgid_plural " don't like this" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 src/Model/User.php:521 -msgid "Friends" -msgstr "Kaverit" +#: src/Content/Conversation.php:272 +#, php-format +msgid " attends" +msgid_plural " attend" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Friends/Benefits" -msgstr "Kaverit eduilla" +#: src/Content/Conversation.php:275 +#, php-format +msgid " doesn't attend" +msgid_plural " don't attend" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Casual" -msgstr "Tavallinen" +#: src/Content/Conversation.php:278 +#, php-format +msgid " attends maybe" +msgid_plural " attend maybe" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Engaged" -msgstr "Kihloissa" +#: src/Content/Conversation.php:281 +#, php-format +msgid " reshared this" +msgid_plural " reshared this" +msgstr[0] "" +msgstr[1] "" -#: src/Content/ContactSelector.php:169 -msgid "Married" -msgstr "Naimisissa" +#: src/Content/Conversation.php:328 +msgid "Visible to everybody" +msgstr "Näkyy kaikille" -#: src/Content/ContactSelector.php:169 -msgid "Imaginarily married" +#: src/Content/Conversation.php:329 src/Module/Item/Compose.php:199 +#: src/Object/Post.php:1081 +msgid "Please enter a image/video/audio/webpage URL:" msgstr "" -#: src/Content/ContactSelector.php:169 -msgid "Partners" -msgstr "Kumppanit" +#: src/Content/Conversation.php:330 +msgid "Tag term:" +msgstr "Tunniste:" -#: src/Content/ContactSelector.php:169 -msgid "Cohabiting" -msgstr "Avoliitossa" +#: src/Content/Conversation.php:331 src/Module/Filer/SaveTag.php:73 +msgid "Save to Folder:" +msgstr "Tallenna kansioon:" -#: src/Content/ContactSelector.php:169 -msgid "Common law" -msgstr "Avoliitossa" +#: src/Content/Conversation.php:332 +msgid "Where are you right now?" +msgstr "Mikä on sijaintisi?" -#: src/Content/ContactSelector.php:169 -msgid "Happy" -msgstr "Iloinen" +#: src/Content/Conversation.php:333 +msgid "Delete item(s)?" +msgstr "Poista kohde/kohteet?" -#: src/Content/ContactSelector.php:169 -msgid "Not looking" -msgstr "Ei etsi" - -#: src/Content/ContactSelector.php:169 -msgid "Swinger" -msgstr "Parinvaihtaja" - -#: src/Content/ContactSelector.php:169 -msgid "Betrayed" -msgstr "Petetty" - -#: src/Content/ContactSelector.php:169 -msgid "Separated" -msgstr "Asumuserossa" - -#: src/Content/ContactSelector.php:169 -msgid "Unstable" -msgstr "Epävakaa" - -#: src/Content/ContactSelector.php:169 -msgid "Divorced" -msgstr "Eronnut" - -#: src/Content/ContactSelector.php:169 -msgid "Imaginarily divorced" +#: src/Content/Conversation.php:345 src/Module/Item/Compose.php:175 +msgid "Created at" msgstr "" -#: src/Content/ContactSelector.php:169 -msgid "Widowed" -msgstr "Leski" +#: src/Content/Conversation.php:355 +msgid "New Post" +msgstr "Uusi julkaisu" -#: src/Content/ContactSelector.php:169 -msgid "Uncertain" -msgstr "Epävarma" +#: src/Content/Conversation.php:358 +msgid "Share" +msgstr "Jaa" -#: src/Content/ContactSelector.php:169 -msgid "It's complicated" -msgstr "Se on monimutkaista" +#: src/Content/Conversation.php:361 src/Module/Post/Edit.php:132 +msgid "upload photo" +msgstr "lähetä kuva" -#: src/Content/ContactSelector.php:169 -msgid "Don't care" -msgstr "Ei ole väliä" +#: src/Content/Conversation.php:362 src/Module/Post/Edit.php:133 +msgid "Attach file" +msgstr "Liitä tiedosto" -#: src/Content/ContactSelector.php:169 -msgid "Ask me" -msgstr "Kysy minulta" +#: src/Content/Conversation.php:363 src/Module/Post/Edit.php:134 +msgid "attach file" +msgstr "liitä tiedosto" -#: src/Content/Widget.php:33 +#: src/Content/Conversation.php:364 src/Module/Item/Compose.php:190 +#: src/Module/Post/Edit.php:171 src/Object/Post.php:1072 +msgid "Bold" +msgstr "Lihavoitu" + +#: src/Content/Conversation.php:365 src/Module/Item/Compose.php:191 +#: src/Module/Post/Edit.php:172 src/Object/Post.php:1073 +msgid "Italic" +msgstr "Kursivoitu" + +#: src/Content/Conversation.php:366 src/Module/Item/Compose.php:192 +#: src/Module/Post/Edit.php:173 src/Object/Post.php:1074 +msgid "Underline" +msgstr "Alleviivaus" + +#: src/Content/Conversation.php:367 src/Module/Item/Compose.php:193 +#: src/Module/Post/Edit.php:174 src/Object/Post.php:1075 +msgid "Quote" +msgstr "Lainaus" + +#: src/Content/Conversation.php:368 src/Module/Item/Compose.php:194 +#: src/Module/Post/Edit.php:175 src/Object/Post.php:1076 +msgid "Add emojis" +msgstr "" + +#: src/Content/Conversation.php:369 src/Module/Item/Compose.php:195 +#: src/Module/Post/Edit.php:176 src/Object/Post.php:1077 +msgid "Code" +msgstr "Koodi" + +#: src/Content/Conversation.php:370 src/Module/Item/Compose.php:196 +#: src/Object/Post.php:1078 +msgid "Image" +msgstr "Kuva" + +#: src/Content/Conversation.php:371 src/Module/Item/Compose.php:197 +#: src/Module/Post/Edit.php:177 src/Object/Post.php:1079 +msgid "Link" +msgstr "Linkki" + +#: src/Content/Conversation.php:372 src/Module/Item/Compose.php:198 +#: src/Module/Post/Edit.php:178 src/Object/Post.php:1080 +msgid "Link or Media" +msgstr "" + +#: src/Content/Conversation.php:373 +msgid "Video" +msgstr "" + +#: src/Content/Conversation.php:374 src/Module/Item/Compose.php:201 +#: src/Module/Post/Edit.php:141 +msgid "Set your location" +msgstr "Aseta sijaintisi" + +#: src/Content/Conversation.php:375 src/Module/Post/Edit.php:142 +msgid "set location" +msgstr "aseta sijainti" + +#: src/Content/Conversation.php:376 src/Module/Post/Edit.php:143 +msgid "Clear browser location" +msgstr "Tyhjennä selaimen sijainti" + +#: src/Content/Conversation.php:377 src/Module/Post/Edit.php:144 +msgid "clear location" +msgstr "tyhjennä sijainti" + +#: src/Content/Conversation.php:379 src/Module/Item/Compose.php:206 +#: src/Module/Post/Edit.php:157 +msgid "Set title" +msgstr "Aseta otsikko" + +#: src/Content/Conversation.php:381 src/Module/Item/Compose.php:207 +#: src/Module/Post/Edit.php:159 +msgid "Categories (comma-separated list)" +msgstr "Luokat (pilkuilla eroteltu luettelo)" + +#: src/Content/Conversation.php:386 src/Module/Item/Compose.php:223 +msgid "Scheduled at" +msgstr "" + +#: src/Content/Conversation.php:391 src/Module/Post/Edit.php:146 +msgid "Permission settings" +msgstr "Käyttöoikeusasetukset" + +#: src/Content/Conversation.php:401 src/Module/Post/Edit.php:155 +msgid "Public post" +msgstr "Julkinen viesti" + +#: src/Content/Conversation.php:415 src/Content/Widget/VCard.php:113 +#: src/Model/Profile.php:469 src/Module/Admin/Logs/View.php:92 +#: src/Module/Post/Edit.php:181 +msgid "Message" +msgstr "Viesti" + +#: src/Content/Conversation.php:416 src/Module/Post/Edit.php:182 +#: src/Module/Settings/TwoFactor/Trusted.php:140 +msgid "Browser" +msgstr "Selain" + +#: src/Content/Conversation.php:418 src/Module/Post/Edit.php:185 +msgid "Open Compose page" +msgstr "" + +#: src/Content/Conversation.php:678 src/Object/Post.php:244 +msgid "Pinned item" +msgstr "" + +#: src/Content/Conversation.php:694 src/Object/Post.php:502 +#: src/Object/Post.php:503 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Katso %s-henkilön profiilia @ %s" + +#: src/Content/Conversation.php:707 src/Object/Post.php:490 +msgid "Categories:" +msgstr "Luokat:" + +#: src/Content/Conversation.php:708 src/Object/Post.php:491 +msgid "Filed under:" +msgstr "Arkistoitu kansioon:" + +#: src/Content/Conversation.php:716 src/Object/Post.php:516 +#, php-format +msgid "%s from %s" +msgstr "%s sovelluksesta %s" + +#: src/Content/Conversation.php:732 +msgid "View in context" +msgstr "Näytä kontekstissa" + +#: src/Content/Conversation.php:797 +msgid "remove" +msgstr "poista" + +#: src/Content/Conversation.php:801 +msgid "Delete Selected Items" +msgstr "Poista valitut kohteet" + +#: src/Content/Conversation.php:866 src/Content/Conversation.php:869 +#: src/Content/Conversation.php:872 src/Content/Conversation.php:875 +#: src/Content/Conversation.php:878 +#, php-format +msgid "You had been addressed (%s)." +msgstr "" + +#: src/Content/Conversation.php:881 +#, php-format +msgid "You are following %s." +msgstr "" + +#: src/Content/Conversation.php:884 +msgid "You subscribed to one or more tags in this post." +msgstr "" + +#: src/Content/Conversation.php:897 +#, php-format +msgid "%s reshared this." +msgstr "" + +#: src/Content/Conversation.php:899 +msgid "Reshared" +msgstr "" + +#: src/Content/Conversation.php:899 +#, php-format +msgid "Reshared by %s <%s>" +msgstr "" + +#: src/Content/Conversation.php:902 +#, php-format +msgid "%s is participating in this thread." +msgstr "" + +#: src/Content/Conversation.php:905 +msgid "Stored for general reasons" +msgstr "" + +#: src/Content/Conversation.php:908 +msgid "Global post" +msgstr "" + +#: src/Content/Conversation.php:911 +msgid "Sent via an relay server" +msgstr "" + +#: src/Content/Conversation.php:911 +#, php-format +msgid "Sent via the relay server %s <%s>" +msgstr "" + +#: src/Content/Conversation.php:914 +msgid "Fetched" +msgstr "" + +#: src/Content/Conversation.php:914 +#, php-format +msgid "Fetched because of %s <%s>" +msgstr "" + +#: src/Content/Conversation.php:917 +msgid "Stored because of a child post to complete this thread." +msgstr "" + +#: src/Content/Conversation.php:920 +msgid "Local delivery" +msgstr "" + +#: src/Content/Conversation.php:923 +msgid "Stored because of your activity (like, comment, star, ...)" +msgstr "" + +#: src/Content/Conversation.php:926 +msgid "Distributed" +msgstr "" + +#: src/Content/Conversation.php:929 +msgid "Pushed to us" +msgstr "" + +#: src/Content/Feature.php:96 +msgid "General Features" +msgstr "Yleiset ominaisuudet" + +#: src/Content/Feature.php:98 +msgid "Photo Location" +msgstr "Kuvan sijainti" + +#: src/Content/Feature.php:98 +msgid "" +"Photo metadata is normally stripped. This extracts the location (if present)" +" prior to stripping metadata and links it to a map." +msgstr "Kuvan metadata poistetaan normaalisti. Tämä ottaa paikkatiedon (jos olemassa) ennen poistoa ja linkittää sen karttaan." + +#: src/Content/Feature.php:99 +msgid "Trending Tags" +msgstr "" + +#: src/Content/Feature.php:99 +msgid "" +"Show a community page widget with a list of the most popular tags in recent " +"public posts." +msgstr "" + +#: src/Content/Feature.php:104 +msgid "Post Composition Features" +msgstr "Kirjoittamisen ominaisuudet" + +#: src/Content/Feature.php:105 +msgid "Auto-mention Groups" +msgstr "" + +#: src/Content/Feature.php:105 +msgid "" +"Add/remove mention when a group page is selected/deselected in ACL window." +msgstr "" + +#: src/Content/Feature.php:106 +msgid "Explicit Mentions" +msgstr "" + +#: src/Content/Feature.php:106 +msgid "" +"Add explicit mentions to comment box for manual control over who gets " +"mentioned in replies." +msgstr "" + +#: src/Content/Feature.php:107 +msgid "Add an abstract from ActivityPub content warnings" +msgstr "" + +#: src/Content/Feature.php:107 +msgid "" +"Add an abstract when commenting on ActivityPub posts with a content warning." +" Abstracts are displayed as content warning on systems like Mastodon or " +"Pleroma." +msgstr "" + +#: src/Content/Feature.php:112 +msgid "Post/Comment Tools" +msgstr "Julkaisu/kommentti työkalut" + +#: src/Content/Feature.php:113 +msgid "Post Categories" +msgstr "Julkaisuluokat" + +#: src/Content/Feature.php:113 +msgid "Add categories to your posts" +msgstr "Luokittele julkaisusi" + +#: src/Content/Feature.php:118 +msgid "Advanced Profile Settings" +msgstr "Profiilin lisäasetukset" + +#: src/Content/Feature.php:119 +msgid "List Groups" +msgstr "" + +#: src/Content/Feature.php:119 +msgid "Show visitors public groups at the Advanced Profile Page" +msgstr "" + +#: src/Content/Feature.php:120 +msgid "Tag Cloud" +msgstr "Tunnistepilvi" + +#: src/Content/Feature.php:120 +msgid "Provide a personal tag cloud on your profile page" +msgstr "Näytä henkilökohtainen tunnistepilvi profiilisivullasi" + +#: src/Content/Feature.php:121 +msgid "Display Membership Date" +msgstr "Näytä liittymispäivämäärä" + +#: src/Content/Feature.php:121 +msgid "Display membership date in profile" +msgstr "Näytä liittymispäivämäärä profiilissa" + +#: src/Content/Feature.php:126 +msgid "Advanced Calendar Settings" +msgstr "" + +#: src/Content/Feature.php:127 +msgid "Allow anonymous access to your calendar" +msgstr "" + +#: src/Content/Feature.php:127 +msgid "" +"Allows anonymous visitors to consult your calendar and your public events. " +"Contact birthday events are private to you." +msgstr "" + +#: src/Content/GroupManager.php:151 src/Content/Nav.php:276 +#: src/Content/Text/HTML.php:877 src/Content/Widget.php:533 +msgid "Groups" +msgstr "" + +#: src/Content/GroupManager.php:153 +msgid "External link to group" +msgstr "" + +#: src/Content/GroupManager.php:156 src/Content/Widget.php:512 +msgid "show less" +msgstr "" + +#: src/Content/GroupManager.php:157 src/Content/Widget.php:414 +#: src/Content/Widget.php:513 +msgid "show more" +msgstr "näytä lisää" + +#: src/Content/Item.php:327 src/Model/Item.php:2931 +msgid "event" +msgstr "tapahtuma" + +#: src/Content/Item.php:330 src/Content/Item.php:340 +msgid "status" +msgstr "tila" + +#: src/Content/Item.php:336 src/Model/Item.php:2933 +#: src/Module/Post/Tag/Add.php:123 +msgid "photo" +msgstr "kuva" + +#: src/Content/Item.php:350 src/Module/Post/Tag/Add.php:141 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "" + +#: src/Content/Item.php:418 view/theme/frio/theme.php:262 +msgid "Follow Thread" +msgstr "Seuraa ketjua" + +#: src/Content/Item.php:419 src/Model/Contact.php:1199 +msgid "View Status" +msgstr "Näytä tila" + +#: src/Content/Item.php:420 src/Content/Item.php:440 +#: src/Model/Contact.php:1148 src/Model/Contact.php:1191 +#: src/Model/Contact.php:1200 src/Module/Directory.php:157 +#: src/Module/Settings/Profile/Index.php:233 +msgid "View Profile" +msgstr "Näytä profiilia" + +#: src/Content/Item.php:421 src/Model/Contact.php:1201 +msgid "View Photos" +msgstr "Näytä kuvia" + +#: src/Content/Item.php:422 src/Model/Contact.php:1192 +#: src/Model/Contact.php:1202 +msgid "Network Posts" +msgstr "Uutisvirtajulkaisut" + +#: src/Content/Item.php:423 src/Model/Contact.php:1193 +#: src/Model/Contact.php:1203 +msgid "View Contact" +msgstr "Näytä kontaktia" + +#: src/Content/Item.php:424 src/Model/Contact.php:1204 +msgid "Send PM" +msgstr "Lähetä yksityisviesti" + +#: src/Content/Item.php:425 src/Module/Contact.php:448 +#: src/Module/Contact/Profile.php:477 +#: src/Module/Moderation/Blocklist/Contact.php:116 +#: src/Module/Moderation/Users/Active.php:137 +#: src/Module/Moderation/Users/Index.php:152 +msgid "Block" +msgstr "Estä" + +#: src/Content/Item.php:426 src/Module/Contact.php:449 +#: src/Module/Contact/Profile.php:485 +#: src/Module/Notifications/Introductions.php:134 +#: src/Module/Notifications/Introductions.php:206 +#: src/Module/Notifications/Notification.php:89 +msgid "Ignore" +msgstr "Jätä huomiotta" + +#: src/Content/Item.php:427 src/Module/Contact.php:450 +#: src/Module/Contact/Profile.php:493 +msgid "Collapse" +msgstr "" + +#: src/Content/Item.php:431 src/Object/Post.php:471 +msgid "Languages" +msgstr "" + +#: src/Content/Item.php:437 src/Content/Widget.php:80 +#: src/Model/Contact.php:1194 src/Model/Contact.php:1205 +#: src/Module/Contact/Follow.php:167 view/theme/vier/theme.php:195 +msgid "Connect/Follow" +msgstr "Yhdistä/Seuraa" + +#: src/Content/Item.php:862 +msgid "Unable to fetch user." +msgstr "" + +#: src/Content/Nav.php:120 +msgid "Nothing new here" +msgstr "Täällä ei ole mitään uutta" + +#: src/Content/Nav.php:124 src/Module/Special/HTTPException.php:77 +msgid "Go back" +msgstr "" + +#: src/Content/Nav.php:125 +msgid "Clear notifications" +msgstr "Tyhjennä ilmoitukset" + +#: src/Content/Nav.php:126 src/Content/Text/HTML.php:864 +msgid "@name, !group, #tags, content" +msgstr "" + +#: src/Content/Nav.php:220 src/Module/Security/Login.php:157 +msgid "Logout" +msgstr "Kirjaudu ulos" + +#: src/Content/Nav.php:220 +msgid "End this session" +msgstr "Lopeta istunto" + +#: src/Content/Nav.php:222 src/Module/Bookmarklet.php:44 +#: src/Module/Security/Login.php:158 +msgid "Login" +msgstr "Kirjaudu sisään" + +#: src/Content/Nav.php:222 +msgid "Sign in" +msgstr "Kirjaudu sisään" + +#: src/Content/Nav.php:227 src/Module/BaseProfile.php:57 +#: src/Module/Contact.php:492 +msgid "Conversations" +msgstr "" + +#: src/Content/Nav.php:227 +msgid "Conversations you started" +msgstr "" + +#: src/Content/Nav.php:228 src/Module/BaseProfile.php:49 +#: src/Module/BaseSettings.php:100 src/Module/Contact.php:484 +#: src/Module/Contact/Profile.php:392 src/Module/Profile/Profile.php:268 +#: src/Module/Welcome.php:57 view/theme/frio/theme.php:230 +msgid "Profile" +msgstr "Profiili" + +#: src/Content/Nav.php:228 view/theme/frio/theme.php:230 +msgid "Your profile page" +msgstr "Oma profiilisivu" + +#: src/Content/Nav.php:229 src/Module/BaseProfile.php:65 +#: src/Module/Media/Photo/Browser.php:74 view/theme/frio/theme.php:234 +msgid "Photos" +msgstr "Kuvat" + +#: src/Content/Nav.php:229 view/theme/frio/theme.php:234 +msgid "Your photos" +msgstr "Omat kuvat" + +#: src/Content/Nav.php:230 src/Module/BaseProfile.php:73 +#: src/Module/BaseProfile.php:76 src/Module/Contact.php:508 +#: view/theme/frio/theme.php:235 +msgid "Media" +msgstr "" + +#: src/Content/Nav.php:230 view/theme/frio/theme.php:235 +msgid "Your postings with media" +msgstr "" + +#: src/Content/Nav.php:231 src/Content/Nav.php:291 +#: 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:236 +#: view/theme/frio/theme.php:240 +msgid "Calendar" +msgstr "Kalenteri" + +#: src/Content/Nav.php:231 view/theme/frio/theme.php:236 +msgid "Your calendar" +msgstr "" + +#: src/Content/Nav.php:232 +msgid "Personal notes" +msgstr "Henkilökohtaiset merkinnät" + +#: src/Content/Nav.php:232 +msgid "Your personal notes" +msgstr "Henkilökohtaiset merkintäsi" + +#: src/Content/Nav.php:249 src/Content/Nav.php:306 +msgid "Home" +msgstr "Koti" + +#: src/Content/Nav.php:249 src/Module/Settings/OAuth.php:73 +msgid "Home Page" +msgstr "Kotisivu" + +#: src/Content/Nav.php:253 src/Module/Register.php:168 +#: src/Module/Security/Login.php:124 +msgid "Register" +msgstr "Rekisteröidy" + +#: src/Content/Nav.php:253 +msgid "Create an account" +msgstr "Luo tili" + +#: src/Content/Nav.php:259 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 +#: src/Module/Settings/TwoFactor/Verify.php:146 view/theme/vier/theme.php:240 +msgid "Help" +msgstr "Ohje" + +#: src/Content/Nav.php:259 +msgid "Help and documentation" +msgstr "Ohjeet ja dokmentointi" + +#: src/Content/Nav.php:263 +msgid "Apps" +msgstr "Sovellukset" + +#: src/Content/Nav.php:263 +msgid "Addon applications, utilities, games" +msgstr "Lisäosa sovelluksia, apuohjelmia, pelejä" + +#: src/Content/Nav.php:267 src/Content/Text/HTML.php:862 +#: src/Module/Admin/Logs/View.php:86 src/Module/Search/Index.php:112 +msgid "Search" +msgstr "Haku" + +#: src/Content/Nav.php:267 +msgid "Search site content" +msgstr "Sivustohaku" + +#: src/Content/Nav.php:270 src/Content/Text/HTML.php:871 +msgid "Full Text" +msgstr "Koko teksti" + +#: src/Content/Nav.php:271 src/Content/Text/HTML.php:872 +#: src/Content/Widget/TagCloud.php:68 +msgid "Tags" +msgstr "Tunnisteet" + +#: src/Content/Nav.php:272 src/Content/Nav.php:327 +#: src/Content/Text/HTML.php:873 src/Module/BaseProfile.php:127 +#: src/Module/BaseProfile.php:130 src/Module/Contact.php:419 +#: src/Module/Contact.php:515 view/theme/frio/theme.php:243 +msgid "Contacts" +msgstr "Yhteystiedot" + +#: src/Content/Nav.php:287 +msgid "Community" +msgstr "Yhteisö" + +#: src/Content/Nav.php:287 +msgid "Conversations on this and other servers" +msgstr "Keskustelut täällä ja muilla palvelimilla" + +#: src/Content/Nav.php:294 +msgid "Directory" +msgstr "Luettelo" + +#: src/Content/Nav.php:294 +msgid "People directory" +msgstr "Henkilöluettelo" + +#: src/Content/Nav.php:296 src/Module/BaseAdmin.php:85 +#: src/Module/BaseModeration.php:108 +msgid "Information" +msgstr "Tietoja" + +#: src/Content/Nav.php:296 +msgid "Information about this friendica instance" +msgstr "Lisätietoja tästä Friendica -instanssista" + +#: src/Content/Nav.php:299 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 "Käyttöehdot" + +#: src/Content/Nav.php:299 +msgid "Terms of Service of this Friendica instance" +msgstr "" + +#: src/Content/Nav.php:304 view/theme/frio/theme.php:239 +msgid "Network" +msgstr "Uutisvirta" + +#: src/Content/Nav.php:304 view/theme/frio/theme.php:239 +msgid "Conversations from your friends" +msgstr "Kavereiden keskustelut" + +#: src/Content/Nav.php:306 view/theme/frio/theme.php:229 +msgid "Your posts and conversations" +msgstr "Omat julkaisut ja keskustelut" + +#: src/Content/Nav.php:310 +msgid "Introductions" +msgstr "Esittelyt" + +#: src/Content/Nav.php:310 +msgid "Friend Requests" +msgstr "Kaveripyynnöt" + +#: src/Content/Nav.php:311 src/Module/BaseNotifications.php:149 +#: src/Module/Notifications/Introductions.php:75 +msgid "Notifications" +msgstr "Huomautukset" + +#: src/Content/Nav.php:312 +msgid "See all notifications" +msgstr "Näytä kaikki ilmoitukset" + +#: src/Content/Nav.php:313 src/Module/Settings/Connectors.php:244 +msgid "Mark as seen" +msgstr "Merkitse luetuksi" + +#: src/Content/Nav.php:313 +msgid "Mark all system notifications as seen" +msgstr "" + +#: src/Content/Nav.php:316 view/theme/frio/theme.php:241 +msgid "Private mail" +msgstr "Yksityinen posti" + +#: src/Content/Nav.php:317 +msgid "Inbox" +msgstr "Saapuneet" + +#: src/Content/Nav.php:318 +msgid "Outbox" +msgstr "Lähtevät" + +#: src/Content/Nav.php:322 +msgid "Accounts" +msgstr "" + +#: src/Content/Nav.php:322 +msgid "Manage other pages" +msgstr "Hallitse muita sivuja" + +#: src/Content/Nav.php:325 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:242 +msgid "Settings" +msgstr "Asetukset" + +#: src/Content/Nav.php:325 view/theme/frio/theme.php:242 +msgid "Account settings" +msgstr "Tiliasetukset" + +#: src/Content/Nav.php:327 view/theme/frio/theme.php:243 +msgid "Manage/edit friends and contacts" +msgstr "Hallitse/muokkaa kaverit ja kontaktit" + +#: src/Content/Nav.php:332 src/Module/BaseAdmin.php:119 +msgid "Admin" +msgstr "Ylläpitäjä" + +#: src/Content/Nav.php:332 +msgid "Site setup and configuration" +msgstr "Sivuston asennus ja asetukset" + +#: src/Content/Nav.php:333 src/Module/BaseModeration.php:127 +#: src/Module/Moderation/Blocklist/Contact.php:110 +#: src/Module/Moderation/Blocklist/Server/Add.php:121 +#: src/Module/Moderation/Blocklist/Server/Import.php:118 +#: src/Module/Moderation/Blocklist/Server/Index.php:95 +#: src/Module/Moderation/Item/Delete.php:61 +#: src/Module/Moderation/Summary.php:76 +#: src/Module/Moderation/Users/Active.php:133 +#: src/Module/Moderation/Users/Blocked.php:133 +#: src/Module/Moderation/Users/Deleted.php:80 +#: src/Module/Moderation/Users/Index.php:147 +msgid "Moderation" +msgstr "" + +#: src/Content/Nav.php:333 +msgid "Content and user moderation" +msgstr "" + +#: src/Content/Nav.php:336 +msgid "Navigation" +msgstr "Navigointi" + +#: src/Content/Nav.php:336 +msgid "Site map" +msgstr "Sivustokartta" + +#: src/Content/OEmbed.php:317 +msgid "Embedding disabled" +msgstr "Upottaminen poistettu käytöstä" + +#: src/Content/OEmbed.php:441 +msgid "Embedded content" +msgstr "Upotettu sisältö" + +#: src/Content/Pager.php:216 +msgid "first" +msgstr "ensimmäinen" + +#: src/Content/Pager.php:221 +msgid "prev" +msgstr "edellinen" + +#: src/Content/Pager.php:276 +msgid "next" +msgstr "seuraava" + +#: src/Content/Pager.php:281 +msgid "last" +msgstr "viimeinen" + +#: src/Content/Text/BBCode.php:694 src/Content/Text/BBCode.php:1600 +#: src/Content/Text/BBCode.php:1601 +msgid "Image/photo" +msgstr "Kuva/valokuva" + +#: src/Content/Text/BBCode.php:912 +#, php-format +msgid "%2$s %3$s" +msgstr "" + +#: src/Content/Text/BBCode.php:937 src/Model/Item.php:3649 +#: src/Model/Item.php:3655 src/Model/Item.php:3656 +msgid "Link to source" +msgstr "" + +#: src/Content/Text/BBCode.php:1507 src/Content/Text/HTML.php:901 +msgid "Click to open/close" +msgstr "Klikkaa auki/kiinni" + +#: src/Content/Text/BBCode.php:1540 +msgid "$1 wrote:" +msgstr "$1 kirjoitti:" + +#: src/Content/Text/BBCode.php:1605 src/Content/Text/BBCode.php:1606 +msgid "Encrypted content" +msgstr "Salattu sisältö" + +#: src/Content/Text/BBCode.php:1870 +msgid "Invalid source protocol" +msgstr "Virheellinen lähdeprotokolla" + +#: src/Content/Text/BBCode.php:1889 +msgid "Invalid link protocol" +msgstr "Virheellinen linkkiprotokolla" + +#: src/Content/Text/HTML.php:779 +msgid "Loading more entries..." +msgstr "Merkinnät ladataan..." + +#: src/Content/Text/HTML.php:780 +msgid "The end" +msgstr "Loppu" + +#: src/Content/Text/HTML.php:856 src/Content/Widget/VCard.php:109 +#: src/Model/Profile.php:463 src/Module/Contact/Profile.php:437 +msgid "Follow" +msgstr "Seuraa" + +#: src/Content/Widget.php:51 msgid "Add New Contact" msgstr "Lisää uusi kontakti" -#: src/Content/Widget.php:34 +#: src/Content/Widget.php:52 msgid "Enter address or web location" msgstr "Syötä verkko-osoite" -#: src/Content/Widget.php:35 +#: src/Content/Widget.php:53 msgid "Example: bob@example.com, http://example.com/barbara" msgstr "Esimerkki: bob@example.com, http://example.com/barbara" -#: src/Content/Widget.php:53 +#: src/Content/Widget.php:55 +msgid "Connect" +msgstr "Yhdistä" + +#: src/Content/Widget.php:72 #, php-format msgid "%d invitation available" msgid_plural "%d invitations available" msgstr[0] "%d kutsu saatavilla" msgstr[1] "%d kutsuja saatavilla" -#: src/Content/Widget.php:164 -msgid "Networks" -msgstr "Verkot" +#: src/Content/Widget.php:78 view/theme/vier/theme.php:193 +msgid "Find People" +msgstr "Löydä ihmisiä" -#: src/Content/Widget.php:167 -msgid "All Networks" -msgstr "Kaikki verkot" +#: src/Content/Widget.php:79 view/theme/vier/theme.php:194 +msgid "Enter name or interest" +msgstr "Syötä nimi tai harrastus" -#: src/Content/Widget.php:205 src/Content/Feature.php:118 +#: src/Content/Widget.php:81 view/theme/vier/theme.php:196 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Esim. Matti Meikäläinen, kalastus yms." + +#: src/Content/Widget.php:82 src/Module/Contact.php:441 +#: src/Module/Directory.php:96 view/theme/vier/theme.php:197 +msgid "Find" +msgstr "Etsi" + +#: src/Content/Widget.php:83 src/Module/Contact/Suggestions.php:73 +#: view/theme/vier/theme.php:198 +msgid "Friend Suggestions" +msgstr "Ystäväehdotukset" + +#: src/Content/Widget.php:84 view/theme/vier/theme.php:199 +msgid "Similar Interests" +msgstr "Yhteiset harrastukset" + +#: src/Content/Widget.php:85 view/theme/vier/theme.php:200 +msgid "Random Profile" +msgstr "Satunnainen profiili" + +#: src/Content/Widget.php:86 view/theme/vier/theme.php:201 +msgid "Invite Friends" +msgstr "Kutsu kavereita" + +#: src/Content/Widget.php:87 src/Module/Directory.php:88 +#: view/theme/vier/theme.php:202 +msgid "Global Directory" +msgstr "Maailmanlaajuinen hakemisto" + +#: src/Content/Widget.php:89 view/theme/vier/theme.php:204 +msgid "Local Directory" +msgstr "Paikallinen hakemisto" + +#: src/Content/Widget.php:219 src/Model/Circle.php:596 +#: src/Module/Contact.php:402 src/Module/Welcome.php:76 +msgid "Circles" +msgstr "" + +#: src/Content/Widget.php:221 +msgid "Everyone" +msgstr "" + +#: src/Content/Widget.php:246 src/Module/Contact.php:418 +msgid "No relationship" +msgstr "" + +#: src/Content/Widget.php:251 +msgid "Relationships" +msgstr "" + +#: src/Content/Widget.php:253 src/Module/Circle.php:293 +#: src/Module/Contact.php:346 +msgid "All Contacts" +msgstr "Kaikki yhteystiedot" + +#: src/Content/Widget.php:292 +msgid "Protocols" +msgstr "" + +#: src/Content/Widget.php:294 +msgid "All Protocols" +msgstr "" + +#: src/Content/Widget.php:322 msgid "Saved Folders" msgstr "Tallennetut kansiot" -#: src/Content/Widget.php:208 src/Content/Widget.php:248 +#: src/Content/Widget.php:324 src/Content/Widget.php:355 msgid "Everything" msgstr "Kaikki" -#: src/Content/Widget.php:245 +#: src/Content/Widget.php:353 msgid "Categories" msgstr "Luokat" -#: src/Content/Widget.php:312 +#: src/Content/Widget.php:410 #, php-format msgid "%d contact in common" msgid_plural "%d contacts in common" msgstr[0] "%d yhteinen kontakti" msgstr[1] "%d yhteistä kontaktia" -#: src/Content/Feature.php:79 -msgid "General Features" -msgstr "Yleiset ominaisuudet" +#: src/Content/Widget.php:506 +msgid "Archives" +msgstr "Arkisto" -#: src/Content/Feature.php:81 -msgid "Multiple Profiles" -msgstr "Monia profiileja" +#: src/Content/Widget.php:530 +msgid "Persons" +msgstr "" -#: src/Content/Feature.php:81 -msgid "Ability to create multiple profiles" -msgstr "Mahdollisuus luoda useita profiileja" +#: src/Content/Widget.php:531 +msgid "Organisations" +msgstr "" -#: src/Content/Feature.php:82 -msgid "Photo Location" -msgstr "Kuvan sijainti" +#: src/Content/Widget.php:532 src/Model/Contact.php:1651 +msgid "News" +msgstr "Uutiset" -#: src/Content/Feature.php:82 +#: src/Content/Widget.php:536 src/Module/Settings/Account.php:453 +msgid "Account Types" +msgstr "Tilityypit" + +#: src/Content/Widget.php:537 src/Module/Moderation/BaseUsers.php:69 +msgid "All" +msgstr "" + +#: src/Content/Widget/CalendarExport.php:56 +msgid "Export" +msgstr "Vie" + +#: src/Content/Widget/CalendarExport.php:57 +msgid "Export calendar as ical" +msgstr "Vie kalenteri ical -tiedostona" + +#: src/Content/Widget/CalendarExport.php:58 +msgid "Export calendar as csv" +msgstr "Vie kalenteri csv-tiedostona" + +#: src/Content/Widget/ContactBlock.php:79 +msgid "No contacts" +msgstr "Ei kontakteja" + +#: src/Content/Widget/ContactBlock.php:110 +#, php-format +msgid "%d Contact" +msgid_plural "%d Contacts" +msgstr[0] "%d kontakti" +msgstr[1] "%d kontakteja" + +#: src/Content/Widget/ContactBlock.php:127 +msgid "View Contacts" +msgstr "Näytä kontaktit" + +#: src/Content/Widget/SavedSearches.php:47 +msgid "Remove term" +msgstr "Poista kohde" + +#: src/Content/Widget/SavedSearches.php:60 +msgid "Saved Searches" +msgstr "Tallennetut haut" + +#: src/Content/Widget/TrendingTags.php:52 +#, php-format +msgid "Trending Tags (last %d hour)" +msgid_plural "Trending Tags (last %d hours)" +msgstr[0] "" +msgstr[1] "" + +#: src/Content/Widget/TrendingTags.php:53 +msgid "More Trending Tags" +msgstr "" + +#: src/Content/Widget/VCard.php:102 src/Model/Profile.php:378 +#: src/Module/Contact/Profile.php:381 src/Module/Profile/Profile.php:199 +msgid "XMPP:" +msgstr "XMPP:" + +#: src/Content/Widget/VCard.php:103 src/Model/Profile.php:379 +#: src/Module/Contact/Profile.php:383 src/Module/Profile/Profile.php:203 +msgid "Matrix:" +msgstr "" + +#: src/Content/Widget/VCard.php:104 src/Model/Event.php:82 +#: src/Model/Event.php:109 src/Model/Event.php:473 src/Model/Event.php:958 +#: src/Model/Profile.php:373 src/Module/Contact/Profile.php:379 +#: src/Module/Directory.php:147 src/Module/Notifications/Introductions.php:187 +#: src/Module/Profile/Profile.php:221 +msgid "Location:" +msgstr "Sijainti:" + +#: src/Content/Widget/VCard.php:107 src/Model/Profile.php:476 +#: src/Module/Notifications/Introductions.php:201 +msgid "Network:" +msgstr "Uutisvirta:" + +#: src/Content/Widget/VCard.php:111 src/Model/Contact.php:1195 +#: src/Model/Contact.php:1206 src/Model/Profile.php:465 +#: src/Module/Contact/Profile.php:429 +msgid "Unfollow" +msgstr "" + +#: src/Core/ACL.php:166 src/Module/Profile/Profile.php:269 +msgid "Yourself" +msgstr "" + +#: src/Core/ACL.php:202 src/Module/PermissionTooltip.php:133 +#: src/Module/PermissionTooltip.php:155 +msgid "Mutuals" +msgstr "" + +#: src/Core/ACL.php:294 +msgid "Post to Email" +msgstr "Viesti sähköpostiin" + +#: src/Core/ACL.php:321 src/Module/PermissionTooltip.php:90 +#: src/Module/PermissionTooltip.php:201 +msgid "Public" +msgstr "" + +#: src/Core/ACL.php:322 msgid "" -"Photo metadata is normally stripped. This extracts the location (if present)" -" prior to stripping metadata and links it to a map." -msgstr "Kuvan metadata poistetaan normaalisti. Tämä ottaa paikkatiedon (jos olemassa) ennen poistoa ja linkittää sen karttaan." - -#: src/Content/Feature.php:83 -msgid "Export Public Calendar" -msgstr "Vie julkinen kalenteri" - -#: src/Content/Feature.php:83 -msgid "Ability for visitors to download the public calendar" -msgstr "Vierailijoiden mahdollisuus ladata julkinen kalenteri" - -#: src/Content/Feature.php:88 -msgid "Post Composition Features" -msgstr "Kirjoittamisen ominaisuudet" - -#: src/Content/Feature.php:89 -msgid "Post Preview" -msgstr "Viestin esikatselu" - -#: src/Content/Feature.php:89 -msgid "Allow previewing posts and comments before publishing them" -msgstr "Mahdollistaa viestien esikatselun ennen niiden julkaisua" - -#: src/Content/Feature.php:90 -msgid "Auto-mention Forums" +"This content will be shown to all your followers and can be seen in the " +"community pages and by anyone with its link." msgstr "" -#: src/Content/Feature.php:90 +#: src/Core/ACL.php:323 src/Module/PermissionTooltip.php:98 +msgid "Limited/Private" +msgstr "" + +#: src/Core/ACL.php:324 msgid "" -"Add/remove mention when a forum page is selected/deselected in ACL window." +"This content will be shown only to the people in the first box, to the " +"exception of the people mentioned in the second box. It won't appear " +"anywhere public." msgstr "" -#: src/Content/Feature.php:95 -msgid "Network Sidebar" -msgstr "Uutisvirran sivupalkki" - -#: src/Content/Feature.php:96 -msgid "Ability to select posts by date ranges" -msgstr "Mahdollisuus valita viestejä päivämäärärajauksella" - -#: src/Content/Feature.php:97 src/Content/Feature.php:127 -msgid "List Forums" -msgstr "Näytä foorumit" - -#: src/Content/Feature.php:97 -msgid "Enable widget to display the forums your are connected with" +#: src/Core/ACL.php:324 +msgid "" +"Start typing the name of a contact or a circle to show a filtered list. You " +"can also mention the special circles \"Followers\" and \"Mutuals\"." msgstr "" -#: src/Content/Feature.php:98 -msgid "Group Filter" -msgstr "Ryhmäsuodatin" - -#: src/Content/Feature.php:98 -msgid "Enable widget to display Network posts only from selected group" +#: src/Core/ACL.php:325 +msgid "Show to:" msgstr "" -#: src/Content/Feature.php:99 -msgid "Network Filter" -msgstr "Uutisvirtasuodatin" - -#: src/Content/Feature.php:99 -msgid "Enable widget to display Network posts only from selected network" +#: src/Core/ACL.php:326 +msgid "Except to:" msgstr "" -#: src/Content/Feature.php:100 -msgid "Save search terms for re-use" -msgstr "Tallenna hakutermit myöhempää käyttöä varten" +#: src/Core/ACL.php:327 src/Module/Post/Edit.php:154 +msgid "CC: email addresses" +msgstr "Kopio: sähköpostiosoitteet" -#: src/Content/Feature.php:105 -msgid "Network Tabs" -msgstr "Uutisvirta välilehdet" +#: src/Core/ACL.php:328 src/Module/Post/Edit.php:160 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Esimerkki: bob@example.com, mary@example.com" -#: src/Content/Feature.php:106 -msgid "Network Personal Tab" -msgstr "Henkilökohtainen uutisvirtavälilehti" - -#: src/Content/Feature.php:106 -msgid "Enable tab to display only Network posts that you've interacted on" +#: src/Core/ACL.php:329 +msgid "Connectors" msgstr "" -#: src/Content/Feature.php:107 -msgid "Network New Tab" -msgstr "Uusimmat uutisvirtajulkaisut" - -#: src/Content/Feature.php:107 -msgid "Enable tab to display only new Network posts (from the last 12 hours)" +#: src/Core/Installer.php:180 +msgid "" +"The database configuration file \"config/local.config.php\" could not be " +"written. Please use the enclosed text to create a configuration file in your" +" web server root." msgstr "" -#: src/Content/Feature.php:108 -msgid "Network Shared Links Tab" +#: src/Core/Installer.php:197 +msgid "" +"You may need to import the file \"database.sql\" manually using phpmyadmin " +"or mysql." +msgstr "Sinun on ehkä tuotava tiedosto \"database.sql\" manuaalisesti käyttämällä phpMyAdminia tai MySQL:ää." + +#: src/Core/Installer.php:198 src/Module/Install.php:207 +#: src/Module/Install.php:350 +msgid "Please see the file \"doc/INSTALL.md\"." msgstr "" -#: src/Content/Feature.php:108 -msgid "Enable tab to display only Network posts with links in them" +#: src/Core/Installer.php:259 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Komentoriviversiota PHP:stä ei löytynyt web-palvelimen PATH:ista." + +#: src/Core/Installer.php:260 +msgid "" +"If you don't have a command line version of PHP installed on your server, " +"you will not be able to run the background processing. See 'Setup the worker'" msgstr "" -#: src/Content/Feature.php:113 -msgid "Post/Comment Tools" -msgstr "Julkaisu/kommentti työkalut" +#: src/Core/Installer.php:265 +msgid "PHP executable path" +msgstr "Polku PHP-ohjelmaan" -#: src/Content/Feature.php:114 -msgid "Multiple Deletion" +#: src/Core/Installer.php:265 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Kirjoita koko polku PHP-ohjelmaan. Voit jättää sen tyhjäksi, jos haluat jatkaa asennusta." + +#: src/Core/Installer.php:270 +msgid "Command line PHP" +msgstr "Komentorivi-PHP" + +#: src/Core/Installer.php:279 +msgid "PHP executable is not the php cli binary (could be cgi-fgci version)" msgstr "" -#: src/Content/Feature.php:114 -msgid "Select and delete multiple posts/comments at once" -msgstr "Valitse ja poista monta julkaisua/kommentia yhtaikaa" +#: src/Core/Installer.php:280 +msgid "Found PHP version: " +msgstr "PHP-versio löydetty:" -#: src/Content/Feature.php:115 -msgid "Edit Sent Posts" -msgstr "Muokkaa lähetetyt julkaisut" +#: src/Core/Installer.php:282 +msgid "PHP cli binary" +msgstr "PHP cli -binääritiedosto" -#: src/Content/Feature.php:115 -msgid "Edit and correct posts and comments after sending" -msgstr "Muokkaa ja korjaa julkaisuja ja kommenteja julkaisun jälkeen" +#: src/Core/Installer.php:295 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "Järjestelmäsi komentorivi-PHP:ssä ei ole käytössä asetusta \"register_argc_argv\"." -#: src/Content/Feature.php:116 -msgid "Tagging" -msgstr "Tunnisteet" +#: src/Core/Installer.php:296 +msgid "This is required for message delivery to work." +msgstr "Asetus vaaditaan viestien lähettämiseen." -#: src/Content/Feature.php:116 -msgid "Ability to tag existing posts" -msgstr "Saa merkitä olemassa olevia julkaisuja" +#: src/Core/Installer.php:301 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" -#: src/Content/Feature.php:117 -msgid "Post Categories" -msgstr "Julkaisuluokat" +#: src/Core/Installer.php:333 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Virhe: järjestelmäsi \"openssl_pkey_new\" -funktio ei pysty generoimaan salausavaimia." -#: src/Content/Feature.php:117 -msgid "Add categories to your posts" -msgstr "Luokittele julkaisusi" +#: src/Core/Installer.php:334 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Jos on kyse Windows-pavelimesta, katso \"http://www.php.net/manual/en/openssl.installation.php\"." -#: src/Content/Feature.php:118 -msgid "Ability to file posts under folders" -msgstr "Mahdollisuus tallettaa viestejä kansioihin" +#: src/Core/Installer.php:337 +msgid "Generate encryption keys" +msgstr "Luo salausavaimet" -#: src/Content/Feature.php:119 -msgid "Dislike Posts" -msgstr "Inhoa viestejä" +#: src/Core/Installer.php:389 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Virhe: Apache-palvelimen mod-rewrite -moduuli vaaditaan, mutta sitä ei ole asennettu." -#: src/Content/Feature.php:119 -msgid "Ability to dislike posts/comments" -msgstr "Mahdollisuus inhota viestejä/kommentteja" +#: src/Core/Installer.php:394 +msgid "Apache mod_rewrite module" +msgstr "Apache mod_rewrite -moduuli" -#: src/Content/Feature.php:120 -msgid "Star Posts" -msgstr "Tähtimerkityt julkaisut" +#: src/Core/Installer.php:400 +msgid "Error: PDO or MySQLi PHP module required but not installed." +msgstr "Virhe: PDO tai MySQLi PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." -#: src/Content/Feature.php:120 -msgid "Ability to mark special posts with a star indicator" -msgstr "Salli julkaisujen tähtimerkintä" +#: src/Core/Installer.php:405 +msgid "Error: The MySQL driver for PDO is not installed." +msgstr "Virhe: PDO:n MySQL-ajuri ei ole asennettu" -#: src/Content/Feature.php:121 -msgid "Mute Post Notifications" -msgstr "Mykistä julkaisuilmoitukset" +#: src/Core/Installer.php:409 +msgid "PDO or MySQLi PHP module" +msgstr "PDO tai MySQLi PHP-moduuli" -#: src/Content/Feature.php:121 -msgid "Ability to mute notifications for a thread" +#: src/Core/Installer.php:417 +msgid "Error, XML PHP module required but not installed." +msgstr "Virhe: XML PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:421 +msgid "XML PHP module" +msgstr "XML PHP-moduuli" + +#: src/Core/Installer.php:424 +msgid "libCurl PHP module" +msgstr "PHP-moduuli libCurl" + +#: src/Core/Installer.php:425 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Virhe: libCURL PHP -moduuli vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:431 +msgid "GD graphics PHP module" +msgstr "PHP-moduuli GD graphics" + +#: src/Core/Installer.php:432 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Virhe: GD graphics PHP -moduuli JPEG-tuella vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:438 +msgid "OpenSSL PHP module" +msgstr "PHP-moduuli OpenSSL" + +#: src/Core/Installer.php:439 +msgid "Error: openssl PHP module required but not installed." +msgstr "Virhe: openssl PHP -moduuli vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:445 +msgid "mb_string PHP module" +msgstr "PHP-moduuli mb_string" + +#: src/Core/Installer.php:446 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Virhe: PHP-moduuli mb_string vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:452 +msgid "iconv PHP module" +msgstr "iconv PHP-moduuli" + +#: src/Core/Installer.php:453 +msgid "Error: iconv PHP module required but not installed." +msgstr "Virhe: iconv PHP-moduuli vaaditaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:459 +msgid "POSIX PHP module" +msgstr "POSIX PHP-moduuli" + +#: src/Core/Installer.php:460 +msgid "Error: POSIX PHP module required but not installed." +msgstr "Virhe: POSIX PHP-moduuli vaadittaan, mutta sitä ei ole asennettu." + +#: src/Core/Installer.php:466 +msgid "Program execution functions" msgstr "" -#: src/Content/Feature.php:126 -msgid "Advanced Profile Settings" -msgstr "Profiilin lisäasetukset" - -#: src/Content/Feature.php:127 -msgid "Show visitors public community forums at the Advanced Profile Page" +#: src/Core/Installer.php:467 +msgid "" +"Error: Program execution functions (proc_open) required but not enabled." msgstr "" -#: src/Content/Feature.php:128 -msgid "Tag Cloud" -msgstr "Tunnistepilvi" - -#: src/Content/Feature.php:128 -msgid "Provide a personal tag cloud on your profile page" -msgstr "Näytä henkilökohtainen tunnistepilvi profiilisivullasi" - -#: src/Content/Feature.php:129 -msgid "Display Membership Date" -msgstr "Näytä liittymispäivämäärä" - -#: src/Content/Feature.php:129 -msgid "Display membership date in profile" -msgstr "Näytä liittymispäivämäärä profiilissa" - -#: src/Content/Nav.php:53 -msgid "Nothing new here" -msgstr "Täällä ei ole mitään uutta" - -#: src/Content/Nav.php:57 -msgid "Clear notifications" -msgstr "Tyhjennä ilmoitukset" - -#: src/Content/Nav.php:105 -msgid "Personal notes" -msgstr "Henkilökohtaiset merkinnät" - -#: src/Content/Nav.php:105 -msgid "Your personal notes" -msgstr "Henkilökohtaiset merkintäsi" - -#: src/Content/Nav.php:114 -msgid "Sign in" -msgstr "Kirjaudu sisään" - -#: src/Content/Nav.php:124 -msgid "Home Page" -msgstr "Kotisivu" - -#: src/Content/Nav.php:128 -msgid "Create an account" -msgstr "Luo tili" - -#: src/Content/Nav.php:134 -msgid "Help and documentation" -msgstr "Ohjeet ja dokmentointi" - -#: src/Content/Nav.php:138 -msgid "Apps" -msgstr "Sovellukset" - -#: src/Content/Nav.php:138 -msgid "Addon applications, utilities, games" -msgstr "Lisäosa sovelluksia, apuohjelmia, pelejä" - -#: src/Content/Nav.php:142 -msgid "Search site content" -msgstr "Sivustohaku" - -#: src/Content/Nav.php:166 -msgid "Community" -msgstr "Yhteisö" - -#: src/Content/Nav.php:166 -msgid "Conversations on this and other servers" -msgstr "Keskustelut täällä ja muilla palvelimilla" - -#: src/Content/Nav.php:173 -msgid "Directory" -msgstr "Luettelo" - -#: src/Content/Nav.php:173 -msgid "People directory" -msgstr "Henkilöluettelo" - -#: src/Content/Nav.php:175 -msgid "Information about this friendica instance" -msgstr "Lisätietoja tästä Friendica -instanssista" - -#: src/Content/Nav.php:178 -msgid "Terms of Service of this Friendica instance" +#: src/Core/Installer.php:473 +msgid "JSON PHP module" msgstr "" -#: src/Content/Nav.php:184 -msgid "Network Reset" -msgstr "Verkon nollaus" +#: src/Core/Installer.php:474 +msgid "Error: JSON PHP module required but not installed." +msgstr "" -#: src/Content/Nav.php:184 -msgid "Load Network page with no filters" -msgstr "Lataa verkkosivu ilman suotimia" +#: src/Core/Installer.php:480 +msgid "File Information PHP module" +msgstr "" -#: src/Content/Nav.php:190 -msgid "Friend Requests" -msgstr "Kaveripyynnöt" +#: src/Core/Installer.php:481 +msgid "Error: File Information PHP module required but not installed." +msgstr "" -#: src/Content/Nav.php:192 -msgid "See all notifications" -msgstr "Näytä kaikki ilmoitukset" +#: src/Core/Installer.php:487 +msgid "GNU Multiple Precision PHP module" +msgstr "" -#: src/Content/Nav.php:193 -msgid "Mark all system notifications seen" -msgstr "Merkitse kaikki järjestelmäviestit nähdyiksi" +#: src/Core/Installer.php:488 +msgid "Error: GNU Multiple Precision PHP module required but not installed." +msgstr "" -#: src/Content/Nav.php:197 -msgid "Inbox" -msgstr "Saapuneet" +#: src/Core/Installer.php:511 +msgid "" +"The web installer needs to be able to create a file called " +"\"local.config.php\" in the \"config\" folder of your web server and it is " +"unable to do so." +msgstr "" -#: src/Content/Nav.php:198 -msgid "Outbox" -msgstr "Lähtevät" +#: src/Core/Installer.php:512 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Tämä on yleensä käyttöoikeusasetus, jolloin web-palvelimesi ei pysty kirjoittamaan tiedostoja kansioosi, vaikka itse siihen pystyisit." -#: src/Content/Nav.php:202 -msgid "Manage" -msgstr "Hallitse" +#: src/Core/Installer.php:513 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named local.config.php in your Friendica \"config\" folder." +msgstr "" -#: src/Content/Nav.php:202 -msgid "Manage other pages" -msgstr "Hallitse muita sivuja" +#: src/Core/Installer.php:514 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"doc/INSTALL.md\" for instructions." +msgstr "" -#: src/Content/Nav.php:210 src/Model/Profile.php:368 -msgid "Profiles" -msgstr "Profiilit" +#: src/Core/Installer.php:517 +msgid "config/local.config.php is writable" +msgstr "" -#: src/Content/Nav.php:210 -msgid "Manage/Edit Profiles" -msgstr "Hallitse/muokka profiilit" +#: src/Core/Installer.php:537 +msgid "" +"Friendica uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "" -#: src/Content/Nav.php:218 -msgid "Site setup and configuration" -msgstr "Sivuston asennus ja asetukset" +#: src/Core/Installer.php:538 +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory view/smarty3/ under the Friendica top level " +"folder." +msgstr "" -#: src/Content/Nav.php:221 -msgid "Navigation" -msgstr "Navigointi" +#: src/Core/Installer.php:539 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "" -#: src/Content/Nav.php:221 -msgid "Site map" -msgstr "Sivustokartta" +#: src/Core/Installer.php:540 +msgid "" +"Note: as a security measure, you should give the web server write access to " +"view/smarty3/ only--not the template files (.tpl) that it contains." +msgstr "" -#: src/Database/DBStructure.php:32 -msgid "There are no tables on MyISAM." -msgstr "MyISAMissa ei ole taulukoita." +#: src/Core/Installer.php:543 +msgid "view/smarty3 is writable" +msgstr "view/smarty3 on kirjoitettava" -#: src/Database/DBStructure.php:75 +#: src/Core/Installer.php:571 +msgid "" +"Url rewrite in .htaccess seems not working. Make sure you copied .htaccess-" +"dist to .htaccess." +msgstr "" + +#: src/Core/Installer.php:572 +msgid "" +"In some circumstances (like running inside containers), you can skip this " +"error." +msgstr "" + +#: src/Core/Installer.php:574 +msgid "Error message from Curl when fetching" +msgstr "" + +#: src/Core/Installer.php:580 +msgid "Url rewrite is working" +msgstr "URL-osoitteen uudellenkirjoitus toimii" + +#: src/Core/Installer.php:609 +msgid "" +"The detection of TLS to secure the communication between the browser and the" +" new Friendica server failed." +msgstr "" + +#: src/Core/Installer.php:610 +msgid "" +"It is highly encouraged to use Friendica only over a secure connection as " +"sensitive information like passwords will be transmitted." +msgstr "" + +#: src/Core/Installer.php:611 +msgid "Please ensure that the connection to the server is secure." +msgstr "" + +#: src/Core/Installer.php:612 +msgid "No TLS detected" +msgstr "" + +#: src/Core/Installer.php:614 +msgid "TLS detected" +msgstr "" + +#: src/Core/Installer.php:641 +msgid "ImageMagick PHP extension is not installed" +msgstr "ImageMagick PHP-laajennus ei ole asetettu" + +#: src/Core/Installer.php:643 +msgid "ImageMagick PHP extension is installed" +msgstr "ImageMagick PHP-laajennus on asetettu" + +#: src/Core/Installer.php:645 +msgid "ImageMagick supports GIF" +msgstr "ImageMagik tukee GIF-formaattia" + +#: src/Core/Installer.php:667 +msgid "Database already in use." +msgstr "Tietokanta on jo käytössä." + +#: src/Core/Installer.php:672 +msgid "Could not connect to database." +msgstr "Tietokantaan ei saada yhteyttä." + +#: src/Core/L10n.php:408 src/Model/Event.php:432 +#: src/Module/Settings/Display.php:222 +msgid "Monday" +msgstr "Maanantai" + +#: src/Core/L10n.php:408 src/Model/Event.php:433 +#: src/Module/Settings/Display.php:223 +msgid "Tuesday" +msgstr "Tiistai" + +#: src/Core/L10n.php:408 src/Model/Event.php:434 +#: src/Module/Settings/Display.php:224 +msgid "Wednesday" +msgstr "Keskiviikko" + +#: src/Core/L10n.php:408 src/Model/Event.php:435 +#: src/Module/Settings/Display.php:225 +msgid "Thursday" +msgstr "Torstai" + +#: src/Core/L10n.php:408 src/Model/Event.php:436 +#: src/Module/Settings/Display.php:226 +msgid "Friday" +msgstr "Perjantai" + +#: src/Core/L10n.php:408 src/Model/Event.php:437 +#: src/Module/Settings/Display.php:227 +msgid "Saturday" +msgstr "Lauantai" + +#: src/Core/L10n.php:408 src/Model/Event.php:431 +#: src/Module/Settings/Display.php:221 +msgid "Sunday" +msgstr "Sunnuntai" + +#: src/Core/L10n.php:412 src/Model/Event.php:452 +msgid "January" +msgstr "Tammikuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:453 +msgid "February" +msgstr "Helmikuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:454 +msgid "March" +msgstr "Maaliskuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:455 +msgid "April" +msgstr "Huhtikuu" + +#: src/Core/L10n.php:412 src/Core/L10n.php:431 src/Model/Event.php:443 +msgid "May" +msgstr "Toukokuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:456 +msgid "June" +msgstr "Kesäkuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:457 +msgid "July" +msgstr "Heinäkuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:458 +msgid "August" +msgstr "Elokuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:459 +msgid "September" +msgstr "Syyskuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:460 +msgid "October" +msgstr "Lokakuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:461 +msgid "November" +msgstr "Marraskuu" + +#: src/Core/L10n.php:412 src/Model/Event.php:462 +msgid "December" +msgstr "Joulukuu" + +#: src/Core/L10n.php:427 src/Model/Event.php:424 +msgid "Mon" +msgstr "Ma" + +#: src/Core/L10n.php:427 src/Model/Event.php:425 +msgid "Tue" +msgstr "Ti" + +#: src/Core/L10n.php:427 src/Model/Event.php:426 +msgid "Wed" +msgstr "Ke" + +#: src/Core/L10n.php:427 src/Model/Event.php:427 +msgid "Thu" +msgstr "To" + +#: src/Core/L10n.php:427 src/Model/Event.php:428 +msgid "Fri" +msgstr "Pe" + +#: src/Core/L10n.php:427 src/Model/Event.php:429 +msgid "Sat" +msgstr "La" + +#: src/Core/L10n.php:427 src/Model/Event.php:423 +msgid "Sun" +msgstr "Su" + +#: src/Core/L10n.php:431 src/Model/Event.php:439 +msgid "Jan" +msgstr "Tam." + +#: src/Core/L10n.php:431 src/Model/Event.php:440 +msgid "Feb" +msgstr "Hel." + +#: src/Core/L10n.php:431 src/Model/Event.php:441 +msgid "Mar" +msgstr "Maa." + +#: src/Core/L10n.php:431 src/Model/Event.php:442 +msgid "Apr" +msgstr "Huh." + +#: src/Core/L10n.php:431 src/Model/Event.php:444 +msgid "Jun" +msgstr "Kes." + +#: src/Core/L10n.php:431 src/Model/Event.php:445 +msgid "Jul" +msgstr "Tou." + +#: src/Core/L10n.php:431 src/Model/Event.php:446 +msgid "Aug" +msgstr "Elo." + +#: src/Core/L10n.php:431 +msgid "Sep" +msgstr "Syy." + +#: src/Core/L10n.php:431 src/Model/Event.php:448 +msgid "Oct" +msgstr "Lok." + +#: src/Core/L10n.php:431 src/Model/Event.php:449 +msgid "Nov" +msgstr "Mar." + +#: src/Core/L10n.php:431 src/Model/Event.php:450 +msgid "Dec" +msgstr "Jou." + +#: src/Core/Renderer.php:89 src/Core/Renderer.php:118 +#: src/Core/Renderer.php:147 src/Core/Renderer.php:181 +#: src/Render/FriendicaSmartyEngine.php:60 +msgid "" +"Friendica can't display this page at the moment, please contact the " +"administrator." +msgstr "" + +#: src/Core/Renderer.php:143 +msgid "template engine cannot be registered without a name." +msgstr "" + +#: src/Core/Renderer.php:177 +msgid "template engine is not registered!" +msgstr "" + +#: src/Core/Storage/Type/FilesystemConfig.php:78 +msgid "Storage base path" +msgstr "" + +#: src/Core/Storage/Type/FilesystemConfig.php:80 +msgid "" +"Folder where uploaded files are saved. For maximum security, This should be " +"a path outside web server folder tree" +msgstr "" + +#: src/Core/Storage/Type/FilesystemConfig.php:93 +msgid "Enter a valid existing folder" +msgstr "" + +#: src/Core/Update.php:80 +#, php-format +msgid "" +"Updates from version %s are not supported. Please update at least to version" +" 2021.01 and wait until the postupdate finished version 1383." +msgstr "" + +#: src/Core/Update.php:91 +#, php-format +msgid "" +"Updates from postupdate version %s are not supported. Please update at least" +" to version 2021.01 and wait until the postupdate finished version 1383." +msgstr "" + +#: src/Core/Update.php:183 +#, php-format +msgid "%s: executing pre update %d" +msgstr "" + +#: src/Core/Update.php:225 +#, php-format +msgid "%s: executing post update %d" +msgstr "" + +#: src/Core/Update.php:299 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "%s päivitys epäonnistui, katso virhelokit." + +#: src/Core/Update.php:339 #, php-format msgid "" "\n" @@ -8810,14 +2891,49 @@ msgid "" "\t\t\t\tfriendica developer if you can not help me on your own. My database might be invalid." msgstr "\n\t\t\t\tFriendican kehittäjät askettäin julkaisi %s-päivityksen,\n\t\t\t\tmutta asennuksessa jotain meni pahasti pieleen.\n\t\t\t\tTämä on korjattava pian, ja en voi korjata sitä itse. Ota yhteyttä\n\t\t\t\tFriendica -kehittäjään jos et voi auttaa. Tietokantani saattaa olla virheellinen." -#: src/Database/DBStructure.php:80 +#: src/Core/Update.php:345 +#, php-format +msgid "The error message is\\n[pre]%s[/pre]" +msgstr "" + +#: src/Core/Update.php:349 src/Core/Update.php:377 +msgid "[Friendica Notify] Database update" +msgstr "" + +#: src/Core/Update.php:371 #, php-format msgid "" -"The error message is\n" -"[pre]%s[/pre]" -msgstr "Virheviesti on\n[pre]%s[/pre]" +"\n" +"\t\t\t\tThe friendica database was successfully updated from %s to %s." +msgstr "" -#: src/Database/DBStructure.php:191 +#: src/Database/DBStructure.php:57 +#, php-format +msgid "The database version had been set to %s." +msgstr "" + +#: src/Database/DBStructure.php:82 +#, php-format +msgid "" +"The post update is at version %d, it has to be at %d to safely drop the " +"tables." +msgstr "" + +#: src/Database/DBStructure.php:95 +msgid "No unused tables found." +msgstr "" + +#: src/Database/DBStructure.php:100 +msgid "" +"These tables are not used for friendica and will be deleted when you execute" +" \"dbstructure drop -e\":" +msgstr "" + +#: src/Database/DBStructure.php:137 +msgid "There are no tables on MyISAM or InnoDB with the Antelope file format." +msgstr "" + +#: src/Database/DBStructure.php:161 #, php-format msgid "" "\n" @@ -8825,444 +2941,718 @@ msgid "" "%s\n" msgstr "\n%d virhe tapahtui tietokannan päivityksen aikana:\n%s\n" -#: src/Database/DBStructure.php:194 +#: src/Database/DBStructure.php:164 msgid "Errors encountered performing database changes: " msgstr "Tietokannan muokkauksessa tapahtui virheitä:" -#: src/Database/DBStructure.php:210 +#: src/Database/DBStructure.php:232 +msgid "Another database update is currently running." +msgstr "" + +#: src/Database/DBStructure.php:236 #, php-format msgid "%s: Database update" msgstr "%s: Tietokantapäivitys" -#: src/Database/DBStructure.php:460 +#: src/Database/DBStructure.php:493 #, php-format msgid "%s: updating %s table." msgstr "%s: päivitetään %s-taulukkoa." -#: src/Model/Mail.php:40 src/Model/Mail.php:174 -msgid "[no subject]" -msgstr "[ei aihetta]" - -#: src/Model/Group.php:44 -msgid "" -"A deleted group with this name was revived. Existing item permissions " -"may apply to this group and any future members. If this is " -"not what you intended, please create another group with a different name." +#: src/Factory/Api/Mastodon/Error.php:55 +msgid "Record not found" msgstr "" -#: src/Model/Group.php:341 -msgid "Default privacy group for new contacts" -msgstr "Oletusryhmä uusille kontakteille" +#: src/Factory/Api/Mastodon/Error.php:65 +msgid "Unprocessable Entity" +msgstr "" -#: src/Model/Group.php:374 +#: src/Factory/Api/Mastodon/Error.php:75 +msgid "Unauthorized" +msgstr "" + +#: 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:94 +msgid "Internal Server Error" +msgstr "" + +#: src/LegacyModule.php:63 +#, php-format +msgid "Legacy module file not found: %s" +msgstr "" + +#: src/Model/Circle.php:105 +msgid "" +"A deleted circle with this name was revived. Existing item permissions " +"may apply to this circle and any future members. If this is" +" not what you intended, please create another circle with a different name." +msgstr "" + +#: src/Model/Circle.php:512 +msgid "Default privacy circle for new contacts" +msgstr "" + +#: src/Model/Circle.php:544 msgid "Everybody" msgstr "Kaikki" -#: src/Model/Group.php:394 +#: src/Model/Circle.php:563 msgid "edit" msgstr "muokkaa" -#: src/Model/Group.php:418 -msgid "Edit group" -msgstr "Muokkaa ryhmää" +#: src/Model/Circle.php:595 +msgid "add" +msgstr "lisää" -#: src/Model/Group.php:419 -msgid "Contacts not in any group" -msgstr "Kontaktit ilman ryhmää" +#: src/Model/Circle.php:600 +msgid "Edit circle" +msgstr "" -#: src/Model/Group.php:420 -msgid "Create a new group" -msgstr "Luo uusi ryhmä" +#: src/Model/Circle.php:601 src/Module/Circle.php:194 +msgid "Contacts not in any circle" +msgstr "" -#: src/Model/Group.php:422 -msgid "Edit groups" -msgstr "Muokkaa ryhmiä" +#: src/Model/Circle.php:603 +msgid "Create a new circle" +msgstr "" -#: src/Model/Contact.php:667 -msgid "Drop Contact" -msgstr "Poista kontakti" +#: src/Model/Circle.php:604 src/Module/Circle.php:179 +#: src/Module/Circle.php:202 src/Module/Circle.php:277 +msgid "Circle Name: " +msgstr "" -#: src/Model/Contact.php:1101 +#: src/Model/Circle.php:605 +msgid "Edit circles" +msgstr "" + +#: src/Model/Contact.php:1212 src/Module/Moderation/Users/Pending.php:102 +#: src/Module/Notifications/Introductions.php:132 +#: src/Module/Notifications/Introductions.php:204 +msgid "Approve" +msgstr "Hyväksy" + +#: src/Model/Contact.php:1647 msgid "Organisation" msgstr "Järjestö" -#: src/Model/Contact.php:1104 -msgid "News" -msgstr "Uutiset" +#: src/Model/Contact.php:1655 +msgid "Group" +msgstr "" -#: src/Model/Contact.php:1107 -msgid "Forum" -msgstr "Keskustelupalsta" +#: src/Model/Contact.php:2951 +msgid "Disallowed profile URL." +msgstr "Kielletty profiiliosoite." -#: src/Model/Contact.php:1286 +#: src/Model/Contact.php:2956 src/Module/Friendica.php:83 +msgid "Blocked domain" +msgstr "Estetty verkkotunnus" + +#: src/Model/Contact.php:2961 msgid "Connect URL missing." msgstr "Yhteys URL-linkki puuttuu." -#: src/Model/Contact.php:1295 +#: src/Model/Contact.php:2970 msgid "" "The contact could not be added. Please check the relevant network " "credentials in your Settings -> Social Networks page." msgstr "Kontaktia ei pystytty lisäämään. Tarkista verkkoasetukset omista asetuksistasi (Settings -> Social Networks)." -#: src/Model/Contact.php:1342 -msgid "" -"This site is not configured to allow communications with other networks." -msgstr "Tämä sivusto ei salli yhteyksiä muiden verkkojen kanssa.." +#: src/Model/Contact.php:2988 +#, php-format +msgid "Expected network %s does not match actual network %s" +msgstr "" -#: src/Model/Contact.php:1343 src/Model/Contact.php:1357 -msgid "No compatible communication protocols or feeds were discovered." -msgstr "Yhteensopivia viestintäprotokolleja tai syötteitä ei löytynyt." - -#: src/Model/Contact.php:1355 +#: src/Model/Contact.php:3005 msgid "The profile address specified does not provide adequate information." msgstr "Annettu profiiliosoite ei sisällä riittävästi tietoa." -#: src/Model/Contact.php:1360 +#: src/Model/Contact.php:3007 +msgid "No compatible communication protocols or feeds were discovered." +msgstr "Yhteensopivia viestintäprotokolleja tai syötteitä ei löytynyt." + +#: src/Model/Contact.php:3010 msgid "An author or name was not found." msgstr "Julkaisija tai nimi puuttuu." -#: src/Model/Contact.php:1363 +#: src/Model/Contact.php:3013 msgid "No browser URL could be matched to this address." msgstr "" -#: src/Model/Contact.php:1366 +#: src/Model/Contact.php:3016 msgid "" "Unable to match @-style Identity Address with a known protocol or email " "contact." msgstr "" -#: src/Model/Contact.php:1367 +#: src/Model/Contact.php:3017 msgid "Use mailto: in front of address to force email check." msgstr "Käytä \"mailto:\" osoitteen edessä pakottaaksesi sähköpostin tarkastuksen." -#: src/Model/Contact.php:1373 +#: src/Model/Contact.php:3023 msgid "" "The profile address specified belongs to a network which has been disabled " "on this site." msgstr "Profiilin osoite kuuluu verkkoon, joka on poistettu tältä sivustolta." -#: src/Model/Contact.php:1378 +#: src/Model/Contact.php:3028 msgid "" "Limited profile. This person will be unable to receive direct/personal " "notifications from you." msgstr "Rajoitettu profiili. Tämä henkilö ei pysty/tule saamaan suoria/henkilökohtaisia ilmoituksia sinulta." -#: src/Model/Contact.php:1429 +#: src/Model/Contact.php:3093 msgid "Unable to retrieve contact information." msgstr "Kontaktin tietoja ei voitu hakea." -#: src/Model/Contact.php:1646 src/Protocol/DFRN.php:1515 +#: src/Model/Event.php:54 +msgid "l F d, Y \\@ g:i A \\G\\M\\TP (e)" +msgstr "" + +#: src/Model/Event.php:75 src/Model/Event.php:92 src/Model/Event.php:471 +#: src/Model/Event.php:940 +msgid "Starts:" +msgstr "Alkaa:" + +#: src/Model/Event.php:78 src/Model/Event.php:98 src/Model/Event.php:472 +#: src/Model/Event.php:944 +msgid "Finishes:" +msgstr "Päättyy:" + +#: src/Model/Event.php:421 +msgid "all-day" +msgstr "koko päivä" + +#: src/Model/Event.php:447 +msgid "Sept" +msgstr "Syy." + +#: src/Model/Event.php:464 src/Module/Calendar/Show.php:128 +#: src/Util/Temporal.php:343 +msgid "today" +msgstr "tänään" + +#: src/Model/Event.php:465 src/Module/Calendar/Show.php:129 +#: src/Module/Settings/Display.php:232 src/Util/Temporal.php:353 +msgid "month" +msgstr "kuukausi" + +#: src/Model/Event.php:466 src/Module/Calendar/Show.php:130 +#: src/Module/Settings/Display.php:233 src/Util/Temporal.php:354 +msgid "week" +msgstr "viikko" + +#: src/Model/Event.php:467 src/Module/Calendar/Show.php:131 +#: src/Module/Settings/Display.php:234 src/Util/Temporal.php:355 +msgid "day" +msgstr "päivä" + +#: src/Model/Event.php:469 +msgid "No events to display" +msgstr "Ei näytettäviä tapahtumia." + +#: src/Model/Event.php:518 src/Module/DFRN/Poll.php:47 src/Module/Feed.php:69 +#: src/Module/Update/Profile.php:56 +msgid "Access to this profile has been restricted." +msgstr "Pääsy tähän profiiliin on rajoitettu" + +#: src/Model/Event.php:559 src/Module/Calendar/Event/Show.php:67 +msgid "Event not found." +msgstr "" + +#: src/Model/Event.php:637 +msgid "l, F j" +msgstr "l, F j" + +#: src/Model/Event.php:664 +msgid "Edit event" +msgstr "Muokkaa tapahtumaa" + +#: src/Model/Event.php:665 +msgid "Duplicate event" +msgstr "Monista tapahtuma" + +#: src/Model/Event.php:666 +msgid "Delete event" +msgstr "Poista tapahtuma" + +#: src/Model/Event.php:896 src/Module/Debug/Localtime.php:38 +msgid "l F d, Y \\@ g:i A" +msgstr "l j.n.Y \\@ H:i" + +#: src/Model/Event.php:897 +msgid "D g:i A" +msgstr "D H:i" + +#: src/Model/Event.php:898 +msgid "g:i A" +msgstr "H:i" + +#: src/Model/Event.php:959 src/Model/Event.php:961 +msgid "Show map" +msgstr "Näytä kartta" + +#: src/Model/Event.php:960 +msgid "Hide map" +msgstr "Piilota kartta" + +#: src/Model/Event.php:1053 #, php-format msgid "%s's birthday" msgstr "%s: syntymäpäivä" -#: src/Model/Contact.php:1647 src/Protocol/DFRN.php:1516 +#: src/Model/Event.php:1054 #, php-format msgid "Happy Birthday %s" msgstr "Hyvää syntymäpäivää %s" -#: src/Model/Event.php:53 src/Model/Event.php:70 src/Model/Event.php:419 -#: src/Model/Event.php:882 -msgid "Starts:" -msgstr "Alkaa:" - -#: src/Model/Event.php:56 src/Model/Event.php:76 src/Model/Event.php:420 -#: src/Model/Event.php:886 -msgid "Finishes:" -msgstr "Päättyy:" - -#: src/Model/Event.php:368 -msgid "all-day" -msgstr "koko päivä" - -#: src/Model/Event.php:391 -msgid "Jun" -msgstr "Kes." - -#: src/Model/Event.php:394 -msgid "Sept" -msgstr "Syy." - -#: src/Model/Event.php:417 -msgid "No events to display" -msgstr "Ei näytettäviä tapahtumia." - -#: src/Model/Event.php:543 -msgid "l, F j" -msgstr "l, F j" - -#: src/Model/Event.php:566 -msgid "Edit event" -msgstr "Muokkaa tapahtumaa" - -#: src/Model/Event.php:567 -msgid "Duplicate event" -msgstr "Monista tapahtuma" - -#: src/Model/Event.php:568 -msgid "Delete event" -msgstr "Poista tapahtuma" - -#: src/Model/Event.php:815 -msgid "D g:i A" -msgstr "D H:i" - -#: src/Model/Event.php:816 -msgid "g:i A" -msgstr "H:i" - -#: src/Model/Event.php:901 src/Model/Event.php:903 -msgid "Show map" -msgstr "Näytä kartta" - -#: src/Model/Event.php:902 -msgid "Hide map" -msgstr "Piilota kartta" - -#: src/Model/Item.php:1883 +#: src/Model/Item.php:2023 #, php-format -msgid "%1$s is attending %2$s's %3$s" -msgstr "%1$s osallistuu tapahtumaan %3$s, jonka järjestää %2$s" +msgid "Detected languages in this post:\\n%s" +msgstr "" -#: src/Model/Item.php:1888 +#: src/Model/Item.php:2935 +msgid "activity" +msgstr "toiminta" + +#: src/Model/Item.php:2937 +msgid "comment" +msgstr "" + +#: src/Model/Item.php:2940 src/Module/Post/Tag/Add.php:123 +msgid "post" +msgstr "julkaisu" + +#: src/Model/Item.php:3109 #, php-format -msgid "%1$s is not attending %2$s's %3$s" -msgstr "%1$s ei osallistu tapahtumaan %3$s, jonka järjestää %2$s" +msgid "%s is blocked" +msgstr "" -#: src/Model/Item.php:1893 +#: src/Model/Item.php:3111 #, php-format -msgid "%1$s may attend %2$s's %3$s" -msgstr "%1$s ehkä osallistuu tapahtumaan %3$s, jonka järjestää %2$s" +msgid "%s is ignored" +msgstr "" -#: src/Model/Profile.php:97 -msgid "Requested account is not available." -msgstr "Pyydetty käyttäjätili ei ole saatavilla." +#: src/Model/Item.php:3113 +#, php-format +msgid "Content from %s is collapsed" +msgstr "" -#: src/Model/Profile.php:164 src/Model/Profile.php:395 -#: src/Model/Profile.php:857 +#: src/Model/Item.php:3117 +#, php-format +msgid "Content warning: %s" +msgstr "Sisältövaroitus: %s" + +#: src/Model/Item.php:3561 +msgid "bytes" +msgstr "tavua" + +#: src/Model/Item.php:3592 +#, 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:3594 +#, php-format +msgid "%2$s (%1$d vote)" +msgid_plural "%2$s (%1$d votes)" +msgstr[0] "" +msgstr[1] "" + +#: src/Model/Item.php:3599 +#, php-format +msgid "%d voter. Poll end: %s" +msgid_plural "%d voters. Poll end: %s" +msgstr[0] "" +msgstr[1] "" + +#: src/Model/Item.php:3601 +#, php-format +msgid "%d voter." +msgid_plural "%d voters." +msgstr[0] "" +msgstr[1] "" + +#: src/Model/Item.php:3603 +#, php-format +msgid "Poll end: %s" +msgstr "" + +#: src/Model/Item.php:3637 src/Model/Item.php:3638 +msgid "View on separate page" +msgstr "Katso erillisellä sivulla" + +#: src/Model/Mail.php:137 src/Model/Mail.php:266 +msgid "[no subject]" +msgstr "[ei aihetta]" + +#: src/Model/Photo.php:1184 src/Module/Media/Photo/Upload.php:170 +msgid "Wall Photos" +msgstr "Seinäkuvat" + +#: src/Model/Profile.php:361 src/Module/Profile/Profile.php:283 +#: src/Module/Profile/Profile.php:285 msgid "Edit profile" msgstr "Muokkaa profiilia" -#: src/Model/Profile.php:332 +#: src/Model/Profile.php:363 +msgid "Change profile photo" +msgstr "Vaihda profiilikuva" + +#: src/Model/Profile.php:376 src/Module/Directory.php:152 +#: src/Module/Profile/Profile.php:209 +msgid "Homepage:" +msgstr "Kotisivu:" + +#: src/Model/Profile.php:377 src/Module/Contact/Profile.php:385 +#: src/Module/Notifications/Introductions.php:189 +msgid "About:" +msgstr "Lisätietoja:" + +#: src/Model/Profile.php:467 msgid "Atom feed" msgstr "Atom -syöte" -#: src/Model/Profile.php:368 -msgid "Manage/edit profiles" -msgstr "Hallitse/muokkaa profiilit" +#: src/Model/Profile.php:474 +msgid "This website has been verified to belong to the same person." +msgstr "" -#: src/Model/Profile.php:546 src/Model/Profile.php:639 -msgid "g A l F d" -msgstr "g A l F d" - -#: src/Model/Profile.php:547 +#: src/Model/Profile.php:511 msgid "F d" msgstr "F d" -#: src/Model/Profile.php:604 src/Model/Profile.php:701 +#: src/Model/Profile.php:575 src/Model/Profile.php:664 msgid "[today]" msgstr "[tänään]" -#: src/Model/Profile.php:615 +#: src/Model/Profile.php:584 msgid "Birthday Reminders" msgstr "Syntymäpäivämuistutukset" -#: src/Model/Profile.php:616 +#: src/Model/Profile.php:585 msgid "Birthdays this week:" msgstr "Syntymäpäiviä tällä viikolla:" -#: src/Model/Profile.php:688 +#: src/Model/Profile.php:613 +msgid "g A l F d" +msgstr "g A l F d" + +#: src/Model/Profile.php:651 msgid "[No description]" msgstr "[Ei kuvausta]" -#: src/Model/Profile.php:715 +#: src/Model/Profile.php:677 msgid "Event Reminders" msgstr "Tapahtumamuistutukset" -#: src/Model/Profile.php:716 -msgid "Events this week:" -msgstr "Tapahtumia tällä viikolla:" +#: src/Model/Profile.php:678 +msgid "Upcoming events the next 7 days:" +msgstr "" -#: src/Model/Profile.php:739 -msgid "Member since:" -msgstr "Liittymispäivämäärä:" - -#: src/Model/Profile.php:747 -msgid "j F, Y" -msgstr "j F, Y" - -#: src/Model/Profile.php:748 -msgid "j F" -msgstr "j F" - -#: src/Model/Profile.php:763 -msgid "Age:" -msgstr "Ikä:" - -#: src/Model/Profile.php:776 +#: src/Model/Profile.php:875 #, php-format -msgid "for %1$d %2$s" -msgstr "%1$d%2$s" +msgid "OpenWebAuth: %1$s welcomes %2$s" +msgstr "" -#: src/Model/Profile.php:800 -msgid "Religion:" +#: src/Model/Profile.php:1015 +msgid "Hometown:" +msgstr "Kotikaupunki:" + +#: src/Model/Profile.php:1016 +msgid "Marital Status:" +msgstr "" + +#: src/Model/Profile.php:1017 +msgid "With:" +msgstr "" + +#: src/Model/Profile.php:1018 +msgid "Since:" +msgstr "" + +#: src/Model/Profile.php:1019 +msgid "Sexual Preference:" +msgstr "Seksuaalinen suuntautuminen:" + +#: src/Model/Profile.php:1020 +msgid "Political Views:" +msgstr "Politiikka:" + +#: src/Model/Profile.php:1021 +msgid "Religious Views:" msgstr "Uskonto:" -#: src/Model/Profile.php:808 -msgid "Hobbies/Interests:" -msgstr "Harrastukset:" +#: src/Model/Profile.php:1022 +msgid "Likes:" +msgstr "Tykkäykset:" -#: src/Model/Profile.php:820 -msgid "Contact information and Social Networks:" -msgstr "Yhteystiedot ja sosiaalinen media:" +#: src/Model/Profile.php:1023 +msgid "Dislikes:" +msgstr "Ei tykkää:" -#: src/Model/Profile.php:824 -msgid "Musical interests:" -msgstr "Musiikki:" +#: src/Model/Profile.php:1024 +msgid "Title/Description:" +msgstr "Otsikko/kuvaus:" -#: src/Model/Profile.php:828 -msgid "Books, literature:" -msgstr "Kirjat, kirjallisuus:" +#: src/Model/Profile.php:1025 src/Module/Admin/Summary.php:221 +#: src/Module/Moderation/Summary.php:77 +msgid "Summary" +msgstr "Yhteenveto" -#: src/Model/Profile.php:832 -msgid "Television:" -msgstr "Televisio:" +#: src/Model/Profile.php:1026 +msgid "Musical interests" +msgstr "Musiikki" -#: src/Model/Profile.php:836 -msgid "Film/dance/culture/entertainment:" -msgstr "Elokuvat/tanssit/kulttuuri/viihde:" +#: src/Model/Profile.php:1027 +msgid "Books, literature" +msgstr "Kirjat, kirjallisuus" -#: src/Model/Profile.php:840 -msgid "Love/Romance:" -msgstr "Rakkaus/romanssi:" +#: src/Model/Profile.php:1028 +msgid "Television" +msgstr "Televisio" -#: src/Model/Profile.php:844 -msgid "Work/employment:" +#: src/Model/Profile.php:1029 +msgid "Film/dance/culture/entertainment" +msgstr "Elokuvat/tanssi/kulttuuri/viihde" + +#: src/Model/Profile.php:1030 +msgid "Hobbies/Interests" +msgstr "Harrastukset" + +#: src/Model/Profile.php:1031 +msgid "Love/romance" +msgstr "Rakkaus/romanssi" + +#: src/Model/Profile.php:1032 +msgid "Work/employment" msgstr "Työ:" -#: src/Model/Profile.php:848 -msgid "School/education:" +#: src/Model/Profile.php:1033 +msgid "School/education" msgstr "Koulutus:" -#: src/Model/Profile.php:853 -msgid "Forums:" -msgstr "Foorumit:" +#: src/Model/Profile.php:1034 +msgid "Contact information and Social Networks" +msgstr "Yhteystiedot ja sosiaalinen media" -#: src/Model/Profile.php:947 -msgid "Only You Can See This" -msgstr "Vain sinä näet tämän" +#: src/Model/User.php:214 src/Model/User.php:1124 +msgid "SERIOUS ERROR: Generation of security keys failed." +msgstr "VAKAVA VIRHE: Salausavainten luominen epäonnistui." -#: src/Model/User.php:154 +#: src/Model/User.php:572 src/Model/User.php:605 msgid "Login failed" msgstr "Kirjautuminen epäonnistui" -#: src/Model/User.php:185 +#: src/Model/User.php:637 msgid "Not enough information to authenticate" msgstr "Ei tarpeeksi tietoja kirjautumiseen" -#: src/Model/User.php:347 +#: src/Model/User.php:758 +msgid "Password can't be empty" +msgstr "Salasanakenttä ei voi olla tyhjä" + +#: src/Model/User.php:800 +msgid "Empty passwords are not allowed." +msgstr "" + +#: src/Model/User.php:804 +msgid "" +"The new password has been exposed in a public data dump, please choose " +"another." +msgstr "" + +#: src/Model/User.php:808 +msgid "The password length is limited to 72 characters." +msgstr "" + +#: src/Model/User.php:812 +msgid "The password can't contain white spaces nor accentuated letters" +msgstr "" + +#: src/Model/User.php:1007 +msgid "Passwords do not match. Password unchanged." +msgstr "Salasanat eivät täsmää. Salasana ennallaan." + +#: src/Model/User.php:1014 msgid "An invitation is required." msgstr "Vaaditaa kutsu." -#: src/Model/User.php:351 +#: src/Model/User.php:1018 msgid "Invitation could not be verified." msgstr "Kutsua ei voitu vahvistaa." -#: src/Model/User.php:358 +#: src/Model/User.php:1026 msgid "Invalid OpenID url" msgstr "Virheellinen OpenID url-osoite" -#: src/Model/User.php:371 src/Module/Login.php:101 +#: src/Model/User.php:1039 src/Security/Authentication.php:241 msgid "" "We encountered a problem while logging in with the OpenID you provided. " "Please check the correct spelling of the ID." msgstr "Kohtasimme ongelman antamasi OpenID:n kanssa. Ole hyvä ja tarkista ID:n oikea kirjoitusasu." -#: src/Model/User.php:371 src/Module/Login.php:101 +#: src/Model/User.php:1039 src/Security/Authentication.php:241 msgid "The error message was:" msgstr "Virheviesti oli:" -#: src/Model/User.php:377 +#: src/Model/User.php:1045 msgid "Please enter the required information." msgstr "Syötä tarvittavat tiedot." -#: src/Model/User.php:390 -msgid "Please use a shorter name." -msgstr "Käytä lyhyempää nimeä." +#: src/Model/User.php:1059 +#, php-format +msgid "" +"system.username_min_length (%s) and system.username_max_length (%s) are " +"excluding each other, swapping values." +msgstr "" -#: src/Model/User.php:393 -msgid "Name too short." -msgstr "Nimi on liian lyhyt." +#: src/Model/User.php:1066 +#, php-format +msgid "Username should be at least %s character." +msgid_plural "Username should be at least %s characters." +msgstr[0] "" +msgstr[1] "" -#: src/Model/User.php:401 +#: src/Model/User.php:1070 +#, php-format +msgid "Username should be at most %s character." +msgid_plural "Username should be at most %s characters." +msgstr[0] "" +msgstr[1] "" + +#: src/Model/User.php:1078 msgid "That doesn't appear to be your full (First Last) name." msgstr "Tuo ei vakuta täydeltä nimeltäsi (Etunimi Sukunimi)." -#: src/Model/User.php:406 +#: src/Model/User.php:1083 msgid "Your email domain is not among those allowed on this site." msgstr "Sähköpostiosoitteesi verkkotunnus on tämän sivuston estolistalla." -#: src/Model/User.php:410 +#: src/Model/User.php:1087 msgid "Not a valid email address." msgstr "Virheellinen sähköpostiosoite." -#: src/Model/User.php:414 src/Model/User.php:422 +#: src/Model/User.php:1090 +msgid "The nickname was blocked from registration by the nodes admin." +msgstr "" + +#: src/Model/User.php:1094 src/Model/User.php:1100 msgid "Cannot use that email." msgstr "Sähköpostiosoitetta ei voitu käyttää." -#: src/Model/User.php:429 +#: src/Model/User.php:1106 msgid "Your nickname can only contain a-z, 0-9 and _." msgstr "Nimimerkki voi sisältää a-z, 0-9 ja _." -#: src/Model/User.php:436 src/Model/User.php:493 +#: src/Model/User.php:1114 src/Model/User.php:1171 msgid "Nickname is already registered. Please choose another." msgstr "Valitsemasi nimimerkki on jo käytössä. Valitse toinen nimimerkki." -#: src/Model/User.php:446 -msgid "SERIOUS ERROR: Generation of security keys failed." -msgstr "VAKAVA VIRHE: Salausavainten luominen epäonnistui." - -#: src/Model/User.php:480 src/Model/User.php:484 +#: src/Model/User.php:1158 src/Model/User.php:1162 msgid "An error occurred during registration. Please try again." msgstr "Rekisteröityminen epäonnistui. Yritä uudelleen." -#: src/Model/User.php:509 +#: src/Model/User.php:1185 msgid "An error occurred creating your default profile. Please try again." msgstr "Oletusprofiilin luominen epäonnistui. Yritä uudelleen." -#: src/Model/User.php:516 +#: src/Model/User.php:1192 msgid "An error occurred creating your self contact. Please try again." msgstr "Yhteystietojesi luonti epäonnistui. Yritä uudelleen." -#: src/Model/User.php:525 -msgid "" -"An error occurred creating your default contact group. Please try again." -msgstr "Oletusryhmäsi luonti epäonnistui. Yritä uudelleen." +#: src/Model/User.php:1197 +msgid "Friends" +msgstr "Kaverit" -#: src/Model/User.php:599 +#: src/Model/User.php:1201 +msgid "" +"An error occurred creating your default contact circle. Please try again." +msgstr "" + +#: src/Model/User.php:1240 +msgid "Profile Photos" +msgstr "Profiilin valokuvat" + +#: src/Model/User.php:1435 +#, php-format +msgid "" +"\n" +"\t\tDear %1$s,\n" +"\t\t\tthe administrator of %2$s has set up an account for you." +msgstr "" + +#: src/Model/User.php:1438 +#, php-format +msgid "" +"\n" +"\t\tThe login details are as follows:\n" +"\n" +"\t\tSite Location:\t%1$s\n" +"\t\tLogin Name:\t\t%2$s\n" +"\t\tPassword:\t\t%3$s\n" +"\n" +"\t\tYou may change your password from your account \"Settings\" page after logging\n" +"\t\tin.\n" +"\n" +"\t\tPlease take a few moments to review the other account settings on that page.\n" +"\n" +"\t\tYou may also wish to add some basic information to your default profile\n" +"\t\t(on the \"Profiles\" page) so that other people can easily find you.\n" +"\n" +"\t\tWe recommend setting your full name, adding a profile photo,\n" +"\t\tadding some profile \"keywords\" (very useful in making new friends) - and\n" +"\t\tperhaps what country you live in; if you do not wish to be more specific\n" +"\t\tthan that.\n" +"\n" +"\t\tWe fully respect your right to privacy, and none of these items are necessary.\n" +"\t\tIf you are new and do not know anybody here, they may help\n" +"\t\tyou to make some new and interesting friends.\n" +"\n" +"\t\tIf you ever want to delete your account, you can do so at %1$s/settings/removeme\n" +"\n" +"\t\tThank you and welcome to %4$s." +msgstr "" + +#: src/Model/User.php:1471 src/Model/User.php:1578 +#, php-format +msgid "Registration details for %s" +msgstr "" + +#: src/Model/User.php:1491 #, php-format msgid "" "\n" "\t\t\tDear %1$s,\n" "\t\t\t\tThank you for registering at %2$s. Your account is pending for approval by the administrator.\n" +"\n" +"\t\t\tYour login details are as follows:\n" +"\n" +"\t\t\tSite Location:\t%3$s\n" +"\t\t\tLogin Name:\t\t%4$s\n" +"\t\t\tPassword:\t\t%5$s\n" "\t\t" -msgstr "\n\t\t\tHei %1$s,\n\t\t\t\tKiitoksia rekisteröitymisestä sivustolle %2$s. Tilisi on odottamassa ylläpidon hyväksyntää.\n\t\t" +msgstr "" -#: src/Model/User.php:609 +#: src/Model/User.php:1510 #, php-format msgid "Registration at %s" msgstr "Rekisteröityminen kohteessa %s" -#: src/Model/User.php:627 +#: src/Model/User.php:1534 #, php-format msgid "" "\n" -"\t\t\tDear %1$s,\n" +"\t\t\t\tDear %1$s,\n" "\t\t\t\tThank you for registering at %2$s. Your account has been created.\n" -"\t\t" -msgstr "\n\t\t\tHei %1$s,\n\t\t\t\tKiitoksia rekisteröinnistä sivustolle %2$s. Tilisi on luotu.\n\t\t" +"\t\t\t" +msgstr "" -#: src/Model/User.php:631 +#: src/Model/User.php:1542 #, php-format msgid "" "\n" @@ -9289,82 +3679,6818 @@ msgid "" "\t\t\tIf you are new and do not know anybody here, they may help\n" "\t\t\tyou to make some new and interesting friends.\n" "\n" -"\t\t\tIf you ever want to delete your account, you can do so at %3$s/removeme\n" +"\t\t\tIf you ever want to delete your account, you can do so at %3$s/settings/removeme\n" "\n" "\t\t\tThank you and welcome to %2$s." msgstr "" -#: src/Protocol/Diaspora.php:2521 -msgid "Sharing notification from Diaspora network" -msgstr "Ilmoitus Diaspora -verkosta tapahtuneesta jakamisesta." +#: src/Module/Admin/Addons/Details.php:65 +msgid "Addon not found." +msgstr "" -#: src/Protocol/Diaspora.php:3609 -msgid "Attachments:" -msgstr "Liitteitä:" - -#: src/Protocol/OStatus.php:1798 +#: src/Module/Admin/Addons/Details.php:76 src/Module/Admin/Addons/Index.php:49 #, php-format -msgid "%s is now following %s." -msgstr "%s seuraa %s." +msgid "Addon %s disabled." +msgstr "Lisäosa %s poistettu käytöstä." -#: src/Protocol/OStatus.php:1799 -msgid "following" -msgstr "seuraa" - -#: src/Protocol/OStatus.php:1802 +#: src/Module/Admin/Addons/Details.php:79 src/Module/Admin/Addons/Index.php:51 #, php-format -msgid "%s stopped following %s." -msgstr "%s ei enää seuraa %s." +msgid "Addon %s enabled." +msgstr "Lisäosa %s käytössä." -#: src/Protocol/OStatus.php:1803 -msgid "stopped following" -msgstr "ei enää seuraa" +#: src/Module/Admin/Addons/Details.php:88 +#: src/Module/Admin/Themes/Details.php:46 +msgid "Disable" +msgstr "Poista käytöstä" -#: src/Worker/Delivery.php:415 -msgid "(no subject)" -msgstr "(ei aihetta)" +#: src/Module/Admin/Addons/Details.php:91 +#: src/Module/Admin/Themes/Details.php:49 +msgid "Enable" +msgstr "Ota käyttöön" -#: src/Module/Logout.php:28 -msgid "Logged out." -msgstr "Kirjautunut ulos." +#: src/Module/Admin/Addons/Details.php:111 +#: src/Module/Admin/Addons/Index.php:67 src/Module/Admin/Federation.php:209 +#: src/Module/Admin/Logs/Settings.php:85 src/Module/Admin/Logs/View.php:83 +#: src/Module/Admin/Queue.php:72 src/Module/Admin/Site.php:398 +#: src/Module/Admin/Storage.php:138 src/Module/Admin/Summary.php:220 +#: src/Module/Admin/Themes/Details.php:90 +#: src/Module/Admin/Themes/Index.php:111 src/Module/Admin/Tos.php:77 +#: src/Module/Moderation/Users/Create.php:61 +#: src/Module/Moderation/Users/Pending.php:96 +msgid "Administration" +msgstr "Ylläpito" -#: src/Module/Login.php:283 +#: src/Module/Admin/Addons/Details.php:112 +#: src/Module/Admin/Addons/Index.php:68 src/Module/BaseAdmin.php:92 +#: src/Module/BaseSettings.php:134 +msgid "Addons" +msgstr "Lisäosat" + +#: src/Module/Admin/Addons/Details.php:113 +#: src/Module/Admin/Themes/Details.php:92 +msgid "Toggle" +msgstr "Vaihda" + +#: src/Module/Admin/Addons/Details.php:120 +#: src/Module/Admin/Themes/Details.php:100 +msgid "Author: " +msgstr "Tekijä" + +#: src/Module/Admin/Addons/Details.php:121 +#: src/Module/Admin/Themes/Details.php:101 +msgid "Maintainer: " +msgstr "Ylläpitäjä:" + +#: src/Module/Admin/Addons/Index.php:42 +msgid "Addons reloaded" +msgstr "" + +#: src/Module/Admin/Addons/Index.php:53 +#, php-format +msgid "Addon %s failed to install." +msgstr "" + +#: src/Module/Admin/Addons/Index.php:69 src/Module/Admin/Features.php:86 +#: src/Module/Admin/Logs/Settings.php:87 src/Module/Admin/Site.php:401 +#: src/Module/Admin/Themes/Index.php:113 src/Module/Admin/Tos.php:86 +#: src/Module/Settings/Account.php:560 src/Module/Settings/Addons.php:78 +#: src/Module/Settings/Connectors.php:160 +#: src/Module/Settings/Connectors.php:246 +#: src/Module/Settings/Delegation.php:171 src/Module/Settings/Display.php:247 +#: src/Module/Settings/Features.php:76 +msgid "Save Settings" +msgstr "Tallenna asetukset" + +#: src/Module/Admin/Addons/Index.php:70 +msgid "Reload active addons" +msgstr "" + +#: src/Module/Admin/Addons/Index.php:74 +#, php-format +msgid "" +"There are currently no addons available on your node. You can find the " +"official addon repository at %1$s and might find other interesting addons in" +" the open addon registry at %2$s" +msgstr "" + +#: src/Module/Admin/DBSync.php:51 +msgid "Update has been marked successful" +msgstr "" + +#: src/Module/Admin/DBSync.php:59 +#, php-format +msgid "Database structure update %s was successfully applied." +msgstr "Tietokannan rakenteen %s-päivitys onnistui." + +#: src/Module/Admin/DBSync.php:61 +#, php-format +msgid "Executing of database structure update %s failed with error: %s" +msgstr "Tietokannan rakennepäivitys %s epäonnistui virheviestillä %s" + +#: src/Module/Admin/DBSync.php:76 +#, php-format +msgid "Executing %s failed with error: %s" +msgstr "" + +#: src/Module/Admin/DBSync.php:78 +#, php-format +msgid "Update %s was successfully applied." +msgstr "%s-päivitys onnistui." + +#: src/Module/Admin/DBSync.php:81 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "" + +#: src/Module/Admin/DBSync.php:84 +#, php-format +msgid "There was no additional update function %s that needed to be called." +msgstr "" + +#: src/Module/Admin/DBSync.php:105 +msgid "No failed updates." +msgstr "Ei epäonnistuineita päivityksiä." + +#: src/Module/Admin/DBSync.php:106 +msgid "Check database structure" +msgstr "Tarkista tietokannan rakenne" + +#: src/Module/Admin/DBSync.php:110 +msgid "Failed Updates" +msgstr "Epäonnistuineita päivityksiä" + +#: src/Module/Admin/DBSync.php:111 +msgid "" +"This does not include updates prior to 1139, which did not return a status." +msgstr "" + +#: src/Module/Admin/DBSync.php:112 +msgid "Mark success (if update was manually applied)" +msgstr "" + +#: src/Module/Admin/DBSync.php:113 +msgid "Attempt to execute this update step automatically" +msgstr "" + +#: src/Module/Admin/Features.php:76 +#, php-format +msgid "Lock feature %s" +msgstr "Lukitse ominaisuus %s" + +#: src/Module/Admin/Features.php:84 +msgid "Manage Additional Features" +msgstr "Hallitse lisäominaisuudet" + +#: src/Module/Admin/Federation.php:75 +msgid "Other" +msgstr "Toinen" + +#: src/Module/Admin/Federation.php:149 src/Module/Admin/Federation.php:398 +msgid "unknown" +msgstr "tuntematon" + +#: src/Module/Admin/Federation.php:182 +#, php-format +msgid "%2$s total system" +msgid_plural "%2$s total systems" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:183 +#, php-format +msgid "%2$s active user last month" +msgid_plural "%2$s active users last month" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:184 +#, php-format +msgid "%2$s active user last six months" +msgid_plural "%2$s active users last six months" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:185 +#, php-format +msgid "%2$s registered user" +msgid_plural "%2$s registered users" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:186 +#, php-format +msgid "%2$s locally created post or comment" +msgid_plural "%2$s locally created posts and comments" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:189 +#, php-format +msgid "%2$s post per user" +msgid_plural "%2$s posts per user" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:194 +#, php-format +msgid "%2$s user per system" +msgid_plural "%2$s users per system" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Federation.php:204 +msgid "" +"This page offers you some numbers to the known part of the federated social " +"network your Friendica node is part of. These numbers are not complete but " +"only reflect the part of the network your node is aware of." +msgstr "" + +#: src/Module/Admin/Federation.php:210 src/Module/BaseAdmin.php:87 +msgid "Federation Statistics" +msgstr "Liiton tilastotiedot" + +#: src/Module/Admin/Federation.php:214 +#, php-format +msgid "" +"Currently this node is aware of %2$s node (%3$s active users last month, " +"%4$s active users last six months, %5$s registered users in total) from the " +"following platforms:" +msgid_plural "" +"Currently this node is aware of %2$s nodes (%3$s active users last month, " +"%4$s active users last six months, %5$s registered users in total) from the " +"following platforms:" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Admin/Logs/Settings.php:47 +#, php-format +msgid "The logfile '%s' is not writable. No logging possible" +msgstr "" + +#: src/Module/Admin/Logs/Settings.php:77 +msgid "PHP log currently enabled." +msgstr "PHP-loki käytössä" + +#: src/Module/Admin/Logs/Settings.php:79 +msgid "PHP log currently disabled." +msgstr "PHP-loki pois käytöstä" + +#: src/Module/Admin/Logs/Settings.php:86 src/Module/BaseAdmin.php:102 +#: src/Module/BaseAdmin.php:103 +msgid "Logs" +msgstr "Lokit" + +#: src/Module/Admin/Logs/Settings.php:88 +msgid "Clear" +msgstr "Tyhjennä" + +#: src/Module/Admin/Logs/Settings.php:91 +msgid "Enable Debugging" +msgstr "Ota virheenkorjaustila käyttöön" + +#: src/Module/Admin/Logs/Settings.php:91 src/Module/Admin/Logs/Settings.php:92 +#: src/Module/Admin/Logs/Settings.php:93 src/Module/Admin/Site.php:420 +#: src/Module/Admin/Site.php:428 +msgid "" +"Read-only because it is set by an environment variable" +msgstr "" + +#: src/Module/Admin/Logs/Settings.php:92 +msgid "Log file" +msgstr "Lokitiedosto" + +#: src/Module/Admin/Logs/Settings.php:92 +msgid "" +"Must be writable by web server. Relative to your Friendica top-level " +"directory." +msgstr "" + +#: src/Module/Admin/Logs/Settings.php:93 +msgid "Log level" +msgstr "Lokitaso" + +#: src/Module/Admin/Logs/Settings.php:95 +msgid "PHP logging" +msgstr "PHP-loki" + +#: src/Module/Admin/Logs/Settings.php:96 +msgid "" +"To temporarily enable logging of PHP errors and warnings you can prepend the" +" following to the index.php file of your installation. The filename set in " +"the 'error_log' line is relative to the friendica top-level directory and " +"must be writeable by the web server. The option '1' for 'log_errors' and " +"'display_errors' is to enable these options, set to '0' to disable them." +msgstr "" + +#: src/Module/Admin/Logs/View.php:70 +#, php-format +msgid "" +"Error trying to open %1$s log file.
Check to see if " +"file %1$s exist and is readable." +msgstr "" + +#: src/Module/Admin/Logs/View.php:79 +#, php-format +msgid "" +"Couldn't open %1$s log file.
Check to see if file %1$s " +"is readable." +msgstr "" + +#: src/Module/Admin/Logs/View.php:84 src/Module/BaseAdmin.php:104 +msgid "View Logs" +msgstr "Katso lokit" + +#: src/Module/Admin/Logs/View.php:87 +msgid "Search in logs" +msgstr "" + +#: src/Module/Admin/Logs/View.php:88 +#: src/Module/Notifications/Notifications.php:140 +msgid "Show all" +msgstr "Näytä kaikki" + +#: src/Module/Admin/Logs/View.php:89 +msgid "Date" +msgstr "" + +#: src/Module/Admin/Logs/View.php:90 +msgid "Level" +msgstr "" + +#: src/Module/Admin/Logs/View.php:91 +msgid "Context" +msgstr "" + +#: src/Module/Admin/Logs/View.php:93 +msgid "ALL" +msgstr "" + +#: src/Module/Admin/Logs/View.php:94 +msgid "View details" +msgstr "" + +#: src/Module/Admin/Logs/View.php:95 +msgid "Click to view details" +msgstr "" + +#: src/Module/Admin/Logs/View.php:96 src/Module/Calendar/Event/Form.php:207 +msgid "Event details" +msgstr "Tapahtuman tiedot" + +#: src/Module/Admin/Logs/View.php:97 +msgid "Data" +msgstr "" + +#: src/Module/Admin/Logs/View.php:98 +#: src/Module/Debug/ActivityPubConversion.php:57 +msgid "Source" +msgstr "" + +#: src/Module/Admin/Logs/View.php:99 +msgid "File" +msgstr "" + +#: src/Module/Admin/Logs/View.php:100 +msgid "Line" +msgstr "" + +#: src/Module/Admin/Logs/View.php:101 +msgid "Function" +msgstr "" + +#: src/Module/Admin/Logs/View.php:102 +msgid "UID" +msgstr "" + +#: src/Module/Admin/Logs/View.php:103 +msgid "Process ID" +msgstr "" + +#: src/Module/Admin/Logs/View.php:104 +msgid "Close" +msgstr "" + +#: src/Module/Admin/Queue.php:50 +msgid "Inspect Deferred Worker Queue" +msgstr "" + +#: src/Module/Admin/Queue.php:51 +msgid "" +"This page lists the deferred worker jobs. This are jobs that couldn't be " +"executed at the first time." +msgstr "" + +#: src/Module/Admin/Queue.php:54 +msgid "Inspect Worker Queue" +msgstr "" + +#: src/Module/Admin/Queue.php:55 +msgid "" +"This page lists the currently queued worker jobs. These jobs are handled by " +"the worker cronjob you've set up during install." +msgstr "" + +#: src/Module/Admin/Queue.php:75 +msgid "ID" +msgstr "" + +#: src/Module/Admin/Queue.php:76 +msgid "Command" +msgstr "" + +#: src/Module/Admin/Queue.php:77 +msgid "Job Parameters" +msgstr "" + +#: src/Module/Admin/Queue.php:78 src/Module/Settings/OAuth.php:74 +msgid "Created" +msgstr "Luotu" + +#: src/Module/Admin/Queue.php:79 +msgid "Priority" +msgstr "" + +#: src/Module/Admin/Site.php:212 +#, php-format +msgid "%s is no valid input for maximum image size" +msgstr "" + +#: src/Module/Admin/Site.php:313 src/Module/Settings/Display.php:169 +msgid "No special theme for mobile devices" +msgstr "Ei mobiiliteemaa" + +#: src/Module/Admin/Site.php:330 src/Module/Settings/Display.php:179 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s - (Kokeellinen)" + +#: src/Module/Admin/Site.php:342 +msgid "No community page" +msgstr "Ei yhteisösivua" + +#: src/Module/Admin/Site.php:343 +msgid "No community page for visitors" +msgstr "" + +#: src/Module/Admin/Site.php:344 +msgid "Public postings from users of this site" +msgstr "Julkiset julkaisut tämän sivuston käyttäjiltä" + +#: src/Module/Admin/Site.php:345 +msgid "Public postings from the federated network" +msgstr "Julkiset julkaisut liittoutuneelta verkolta" + +#: src/Module/Admin/Site.php:346 +msgid "Public postings from local users and the federated network" +msgstr "Julkiset julkaisut tältä sivustolta ja liittoutuneelta verkolta" + +#: src/Module/Admin/Site.php:352 +msgid "Multi user instance" +msgstr "Monen käyttäjän instanssi" + +#: src/Module/Admin/Site.php:375 +msgid "Closed" +msgstr "Suljettu" + +#: src/Module/Admin/Site.php:376 +msgid "Requires approval" +msgstr "Edellyttää hyväksyntää" + +#: src/Module/Admin/Site.php:377 +msgid "Open" +msgstr "Avoin" + +#: src/Module/Admin/Site.php:381 +msgid "Don't check" +msgstr "Älä tarkista" + +#: src/Module/Admin/Site.php:382 +msgid "check the stable version" +msgstr "" + +#: src/Module/Admin/Site.php:383 +msgid "check the development version" +msgstr "" + +#: src/Module/Admin/Site.php:387 +msgid "none" +msgstr "" + +#: src/Module/Admin/Site.php:388 +msgid "Local contacts" +msgstr "" + +#: src/Module/Admin/Site.php:389 +msgid "Interactors" +msgstr "" + +#: src/Module/Admin/Site.php:399 src/Module/BaseAdmin.php:90 +msgid "Site" +msgstr "Sivusto" + +#: src/Module/Admin/Site.php:400 +msgid "General Information" +msgstr "" + +#: src/Module/Admin/Site.php:402 +msgid "Republish users to directory" +msgstr "" + +#: src/Module/Admin/Site.php:403 src/Module/Register.php:152 +msgid "Registration" +msgstr "Rekisteröityminen" + +#: src/Module/Admin/Site.php:404 +msgid "File upload" +msgstr "Tiedoston lataus" + +#: src/Module/Admin/Site.php:405 +msgid "Policies" +msgstr "Käytännöt" + +#: src/Module/Admin/Site.php:406 src/Module/Calendar/Event/Form.php:252 +#: src/Module/Contact.php:525 src/Module/Profile/Profile.php:276 +msgid "Advanced" +msgstr "" + +#: src/Module/Admin/Site.php:407 +msgid "Auto Discovered Contact Directory" +msgstr "" + +#: src/Module/Admin/Site.php:408 +msgid "Performance" +msgstr "Suoritus" + +#: src/Module/Admin/Site.php:409 +msgid "Worker" +msgstr "Worker" + +#: src/Module/Admin/Site.php:410 +msgid "Message Relay" +msgstr "Viestirele" + +#: src/Module/Admin/Site.php:411 +msgid "" +"Use the command \"console relay\" in the command line to add or remove " +"relays." +msgstr "" + +#: src/Module/Admin/Site.php:412 +msgid "The system is not subscribed to any relays at the moment." +msgstr "" + +#: src/Module/Admin/Site.php:413 +msgid "The system is currently subscribed to the following relays:" +msgstr "" + +#: src/Module/Admin/Site.php:415 +msgid "Relocate Node" +msgstr "" + +#: src/Module/Admin/Site.php:416 +msgid "" +"Relocating your node enables you to change the DNS domain of this node and " +"keep all the existing users and posts. This process takes a while and can " +"only be started from the relocate console command like this:" +msgstr "" + +#: src/Module/Admin/Site.php:417 +msgid "(Friendica directory)# bin/console relocate https://newdomain.com" +msgstr "" + +#: src/Module/Admin/Site.php:420 +msgid "Site name" +msgstr "Sivuston nimi" + +#: src/Module/Admin/Site.php:421 +msgid "Sender Email" +msgstr "Lähettäjän sähköposti" + +#: src/Module/Admin/Site.php:421 +msgid "" +"The email address your server shall use to send notification emails from." +msgstr "Lähettäjän sähköpostiosoite palvelimen ilmoitussähköposteissa." + +#: src/Module/Admin/Site.php:422 +msgid "Name of the system actor" +msgstr "" + +#: src/Module/Admin/Site.php:422 +msgid "" +"Name of the internal system account that is used to perform ActivityPub " +"requests. This must be an unused username. If set, this can't be changed " +"again." +msgstr "" + +#: src/Module/Admin/Site.php:423 +msgid "Banner/Logo" +msgstr "Banneri/logo" + +#: src/Module/Admin/Site.php:424 +msgid "Email Banner/Logo" +msgstr "" + +#: src/Module/Admin/Site.php:425 +msgid "Shortcut icon" +msgstr "Pikakuvake" + +#: src/Module/Admin/Site.php:425 +msgid "Link to an icon that will be used for browsers." +msgstr "Linkki kuvakkeeseen jota selaimet saa käyttää." + +#: src/Module/Admin/Site.php:426 +msgid "Touch icon" +msgstr "Kosketusnäyttökuvake" + +#: src/Module/Admin/Site.php:426 +msgid "Link to an icon that will be used for tablets and mobiles." +msgstr "Linkki kuvakkeeseen jota tabletit ja matkapuhelimet saa käyttää." + +#: src/Module/Admin/Site.php:427 +msgid "Additional Info" +msgstr "Lisätietoja" + +#: src/Module/Admin/Site.php:427 +#, php-format +msgid "" +"For public servers: you can add additional information here that will be " +"listed at %s/servers." +msgstr "" + +#: src/Module/Admin/Site.php:428 +msgid "System language" +msgstr "Järjestelmän kieli" + +#: src/Module/Admin/Site.php:429 +msgid "System theme" +msgstr "Järjestelmäteema" + +#: src/Module/Admin/Site.php:429 +#, php-format +msgid "" +"Default system theme - may be over-ridden by user profiles - Change default theme settings" +msgstr "" + +#: src/Module/Admin/Site.php:430 +msgid "Mobile system theme" +msgstr "Mobiili järjestelmäteema" + +#: src/Module/Admin/Site.php:430 +msgid "Theme for mobile devices" +msgstr "Mobiiliteema" + +#: src/Module/Admin/Site.php:431 +msgid "Force SSL" +msgstr "Pakoita SSL-yhteyden käyttöä" + +#: src/Module/Admin/Site.php:431 +msgid "" +"Force all Non-SSL requests to SSL - Attention: on some systems it could lead" +" to endless loops." +msgstr "" + +#: src/Module/Admin/Site.php:432 +msgid "Show help entry from navigation menu" +msgstr "" + +#: src/Module/Admin/Site.php:432 +msgid "" +"Displays the menu entry for the Help pages from the navigation menu. It is " +"always accessible by calling /help directly." +msgstr "" + +#: src/Module/Admin/Site.php:433 +msgid "Single user instance" +msgstr "Yksittäisen käyttäjän instanssi" + +#: src/Module/Admin/Site.php:433 +msgid "Make this instance multi-user or single-user for the named user" +msgstr "" + +#: src/Module/Admin/Site.php:435 +msgid "Maximum image size" +msgstr "Suurin kuvakoko" + +#: src/Module/Admin/Site.php:435 +#, php-format +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no limits. You can put k, m, or g behind the desired value for KiB, MiB, GiB, respectively.\n" +"\t\t\t\t\t\t\t\t\t\t\t\t\tThe value of upload_max_filesize in your PHP.ini needs be set to at least the desired limit.\n" +"\t\t\t\t\t\t\t\t\t\t\t\t\tCurrently upload_max_filesize is set to %s (%s byte)" +msgstr "" + +#: src/Module/Admin/Site.php:439 +msgid "Maximum image length" +msgstr "Suurin kuvapituus" + +#: src/Module/Admin/Site.php:439 +msgid "" +"Maximum length in pixels of the longest side of uploaded images. Default is " +"-1, which means no limits." +msgstr "Ladattavan kuvatiedoston enimmäispituus pikseleinä. Oletusarvo on -1, eli ei enimmäispituutta." + +#: src/Module/Admin/Site.php:440 +msgid "JPEG image quality" +msgstr "JPEG-kuvanlaatu" + +#: src/Module/Admin/Site.php:440 +msgid "" +"Uploaded JPEGS will be saved at this quality setting [0-100]. Default is " +"100, which is full quality." +msgstr "Ladatut JPEG-kuvat tallennetaan tällä laatuasetuksella [0-100]. Oletus on 100, eli korkein laatu." + +#: src/Module/Admin/Site.php:442 +msgid "Register policy" +msgstr "Rekisteröintipolitiikka" + +#: src/Module/Admin/Site.php:443 +msgid "Maximum Users" +msgstr "" + +#: src/Module/Admin/Site.php:443 +msgid "" +"If defined, the register policy is automatically closed when the given " +"number of users is reached and reopens the registry when the number drops " +"below the limit. It only works when the policy is set to open or close, but " +"not when the policy is set to approval." +msgstr "" + +#: src/Module/Admin/Site.php:444 +msgid "Maximum Daily Registrations" +msgstr "Päivittäinen rekisteröitymisraja" + +#: src/Module/Admin/Site.php:444 +msgid "" +"If registration is permitted above, this sets the maximum number of new user" +" registrations to accept per day. If register is set to closed, this " +"setting has no effect." +msgstr "Mikäli rekisteröityminen on sallittu, tämä asettaa enimmäismäärä uusia rekisteröitymisiä päivässä. Jos reksiteröityminen ei ole sallittu, tällä asetuksella ei ole vaikutusta." + +#: src/Module/Admin/Site.php:445 +msgid "Register text" +msgstr "Rekisteröitymisteksti" + +#: src/Module/Admin/Site.php:445 +msgid "" +"Will be displayed prominently on the registration page. You can use BBCode " +"here." +msgstr "Näkyvästi esillä rekisteröitymissivulla. Voit käyttää BBCodeia." + +#: src/Module/Admin/Site.php:446 +msgid "Forbidden Nicknames" +msgstr "" + +#: src/Module/Admin/Site.php:446 +msgid "" +"Comma separated list of nicknames that are forbidden from registration. " +"Preset is a list of role names according RFC 2142." +msgstr "" + +#: src/Module/Admin/Site.php:447 +msgid "Accounts abandoned after x days" +msgstr "Käyttäjätilit hylätään X päivän jälkeen" + +#: src/Module/Admin/Site.php:447 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "" + +#: src/Module/Admin/Site.php:448 +msgid "Allowed friend domains" +msgstr "Sallittuja kaveri-verkkotunnuksia" + +#: src/Module/Admin/Site.php:448 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "" + +#: src/Module/Admin/Site.php:449 +msgid "Allowed email domains" +msgstr "Sallittuja sähköposti-verkkotunnuksia" + +#: src/Module/Admin/Site.php:449 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "" + +#: src/Module/Admin/Site.php:450 +msgid "No OEmbed rich content" +msgstr "" + +#: src/Module/Admin/Site.php:450 +msgid "" +"Don't show the rich content (e.g. embedded PDF), except from the domains " +"listed below." +msgstr "" + +#: src/Module/Admin/Site.php:451 +msgid "Trusted third-party domains" +msgstr "" + +#: src/Module/Admin/Site.php:451 +msgid "" +"Comma separated list of domains from which content is allowed to be embedded" +" in posts like with OEmbed. All sub-domains of the listed domains are " +"allowed as well." +msgstr "" + +#: src/Module/Admin/Site.php:452 +msgid "Block public" +msgstr "Estä vierailijat" + +#: src/Module/Admin/Site.php:452 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "" + +#: src/Module/Admin/Site.php:453 +msgid "Force publish" +msgstr "" + +#: src/Module/Admin/Site.php:453 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "" + +#: src/Module/Admin/Site.php:453 +msgid "Enabling this may violate privacy laws like the GDPR" +msgstr "" + +#: src/Module/Admin/Site.php:454 +msgid "Global directory URL" +msgstr "Maailmanlaajuisen hakemiston URL-osoite" + +#: src/Module/Admin/Site.php:454 +msgid "" +"URL to the global directory. If this is not set, the global directory is " +"completely unavailable to the application." +msgstr "" + +#: src/Module/Admin/Site.php:455 +msgid "Private posts by default for new users" +msgstr "" + +#: src/Module/Admin/Site.php:455 +msgid "" +"Set default post permissions for all new members to the default privacy " +"circle rather than public." +msgstr "" + +#: src/Module/Admin/Site.php:456 +msgid "Don't include post content in email notifications" +msgstr "Älä lisää julkaisun sisältö sähköposti-ilmoitukseen" + +#: src/Module/Admin/Site.php:456 +msgid "" +"Don't include the content of a post/comment/private message/etc. in the " +"email notifications that are sent out from this site, as a privacy measure." +msgstr "" + +#: src/Module/Admin/Site.php:457 +msgid "Disallow public access to addons listed in the apps menu." +msgstr "" + +#: src/Module/Admin/Site.php:457 +msgid "" +"Checking this box will restrict addons listed in the apps menu to members " +"only." +msgstr "" + +#: src/Module/Admin/Site.php:458 +msgid "Don't embed private images in posts" +msgstr "Älä upota yksityisiä kuvia julkaisuissa" + +#: src/Module/Admin/Site.php:458 +msgid "" +"Don't replace locally-hosted private photos in posts with an embedded copy " +"of the image. This means that contacts who receive posts containing private " +"photos will have to authenticate and load each image, which may take a " +"while." +msgstr "" + +#: src/Module/Admin/Site.php:459 +msgid "Explicit Content" +msgstr "" + +#: src/Module/Admin/Site.php:459 +msgid "" +"Set this to announce that your node is used mostly for explicit content that" +" might not be suited for minors. This information will be published in the " +"node information and might be used, e.g. by the global directory, to filter " +"your node from listings of nodes to join. Additionally a note about this " +"will be shown at the user registration page." +msgstr "" + +#: src/Module/Admin/Site.php:460 +msgid "Proxify external content" +msgstr "" + +#: src/Module/Admin/Site.php:460 +msgid "" +"Route external content via the proxy functionality. This is used for example" +" for some OEmbed accesses and in some other rare cases." +msgstr "" + +#: src/Module/Admin/Site.php:461 +msgid "Cache contact avatars" +msgstr "" + +#: src/Module/Admin/Site.php:461 +msgid "" +"Locally store the avatar pictures of the contacts. This uses a lot of " +"storage space but it increases the performance." +msgstr "" + +#: src/Module/Admin/Site.php:462 +msgid "Allow Users to set remote_self" +msgstr "" + +#: src/Module/Admin/Site.php:462 +msgid "" +"With checking this, every user is allowed to mark every contact as a " +"remote_self in the repair contact dialog. Setting this flag on a contact " +"causes mirroring every posting of that contact in the users stream." +msgstr "" + +#: src/Module/Admin/Site.php:463 +msgid "Enable multiple registrations" +msgstr "" + +#: src/Module/Admin/Site.php:463 +msgid "Enable users to register additional accounts for use as pages." +msgstr "" + +#: src/Module/Admin/Site.php:464 +msgid "Enable OpenID" +msgstr "" + +#: src/Module/Admin/Site.php:464 +msgid "Enable OpenID support for registration and logins." +msgstr "" + +#: src/Module/Admin/Site.php:465 +msgid "Enable Fullname check" +msgstr "" + +#: src/Module/Admin/Site.php:465 +msgid "" +"Enable check to only allow users to register with a space between the first " +"name and the last name in their full name." +msgstr "" + +#: src/Module/Admin/Site.php:466 +msgid "Email administrators on new registration" +msgstr "" + +#: src/Module/Admin/Site.php:466 +msgid "" +"If enabled and the system is set to an open registration, an email for each " +"new registration is sent to the administrators." +msgstr "" + +#: src/Module/Admin/Site.php:467 +msgid "Community pages for visitors" +msgstr "Yhteisösivu vieraille" + +#: src/Module/Admin/Site.php:467 +msgid "" +"Which community pages should be available for visitors. Local users always " +"see both pages." +msgstr "" + +#: src/Module/Admin/Site.php:468 +msgid "Posts per user on community page" +msgstr "" + +#: src/Module/Admin/Site.php:468 +msgid "" +"The maximum number of posts per user on the community page. (Not valid for " +"\"Global Community\")" +msgstr "" + +#: src/Module/Admin/Site.php:470 +msgid "Enable Mail support" +msgstr "" + +#: src/Module/Admin/Site.php:470 +msgid "" +"Enable built-in mail support to poll IMAP folders and to reply via mail." +msgstr "" + +#: src/Module/Admin/Site.php:471 +msgid "" +"Mail support can't be enabled because the PHP IMAP module is not installed." +msgstr "" + +#: src/Module/Admin/Site.php:472 +msgid "Enable OStatus support" +msgstr "" + +#: src/Module/Admin/Site.php:472 +msgid "" +"Enable built-in OStatus (StatusNet, GNU Social etc.) compatibility. All " +"communications in OStatus are public." +msgstr "" + +#: src/Module/Admin/Site.php:474 +msgid "" +"Diaspora support can't be enabled because Friendica was installed into a sub" +" directory." +msgstr "Diaspora -tukea ei voitu ottaa käyttöön koska Friendica on asennettu alihakemistoon." + +#: src/Module/Admin/Site.php:475 +msgid "Enable Diaspora support" +msgstr "Salli Diaspora-tuki" + +#: src/Module/Admin/Site.php:475 +msgid "" +"Enable built-in Diaspora network compatibility for communicating with " +"diaspora servers." +msgstr "" + +#: src/Module/Admin/Site.php:476 +msgid "Verify SSL" +msgstr "Vahvista SSL" + +#: src/Module/Admin/Site.php:476 +msgid "" +"If you wish, you can turn on strict certificate checking. This will mean you" +" cannot connect (at all) to self-signed SSL sites." +msgstr "" + +#: src/Module/Admin/Site.php:477 +msgid "Proxy user" +msgstr "Välityspalvelimen käyttäjä" + +#: src/Module/Admin/Site.php:477 +msgid "User name for the proxy server." +msgstr "" + +#: src/Module/Admin/Site.php:478 +msgid "Proxy URL" +msgstr "Välityspalvelimen osoite" + +#: src/Module/Admin/Site.php:478 +msgid "" +"If you want to use a proxy server that Friendica should use to connect to " +"the network, put the URL of the proxy here." +msgstr "" + +#: src/Module/Admin/Site.php:479 +msgid "Network timeout" +msgstr "Verkon aikakatkaisu" + +#: src/Module/Admin/Site.php:479 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "" + +#: src/Module/Admin/Site.php:480 +msgid "Maximum Load Average" +msgstr "Kuorman enimmäiskeksiarvo" + +#: src/Module/Admin/Site.php:480 +#, php-format +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default %d." +msgstr "" + +#: src/Module/Admin/Site.php:481 +msgid "Minimal Memory" +msgstr "" + +#: src/Module/Admin/Site.php:481 +msgid "" +"Minimal free memory in MB for the worker. Needs access to /proc/meminfo - " +"default 0 (deactivated)." +msgstr "" + +#: src/Module/Admin/Site.php:482 +msgid "Periodically optimize tables" +msgstr "" + +#: src/Module/Admin/Site.php:482 +msgid "Periodically optimize tables like the cache and the workerqueue" +msgstr "" + +#: src/Module/Admin/Site.php:484 +msgid "Discover followers/followings from contacts" +msgstr "" + +#: src/Module/Admin/Site.php:484 +msgid "" +"If enabled, contacts are checked for their followers and following contacts." +msgstr "" + +#: src/Module/Admin/Site.php:485 +msgid "None - deactivated" +msgstr "" + +#: src/Module/Admin/Site.php:486 +msgid "" +"Local contacts - contacts of our local contacts are discovered for their " +"followers/followings." +msgstr "" + +#: src/Module/Admin/Site.php:487 +msgid "" +"Interactors - contacts of our local contacts and contacts who interacted on " +"locally visible postings are discovered for their followers/followings." +msgstr "" + +#: src/Module/Admin/Site.php:489 +msgid "Synchronize the contacts with the directory server" +msgstr "" + +#: src/Module/Admin/Site.php:489 +msgid "" +"if enabled, the system will check periodically for new contacts on the " +"defined directory server." +msgstr "" + +#: src/Module/Admin/Site.php:491 +msgid "Days between requery" +msgstr "" + +#: src/Module/Admin/Site.php:491 +msgid "Number of days after which a server is requeried for his contacts." +msgstr "" + +#: src/Module/Admin/Site.php:492 +msgid "Discover contacts from other servers" +msgstr "Etsi kontakteja muilta palvelimilta" + +#: src/Module/Admin/Site.php:492 +msgid "" +"Periodically query other servers for contacts. The system queries Friendica," +" Mastodon and Hubzilla servers." +msgstr "" + +#: src/Module/Admin/Site.php:493 +msgid "Search the local directory" +msgstr "Paikallisluettelohaku" + +#: src/Module/Admin/Site.php:493 +msgid "" +"Search the local directory instead of the global directory. When searching " +"locally, every search will be executed on the global directory in the " +"background. This improves the search results when the search is repeated." +msgstr "" + +#: src/Module/Admin/Site.php:495 +msgid "Publish server information" +msgstr "Julkaise palvelintiedot" + +#: src/Module/Admin/Site.php:495 +msgid "" +"If enabled, general server and usage data will be published. The data " +"contains the name and version of the server, number of users with public " +"profiles, number of posts and the activated protocols and connectors. See the-federation.info for details." +msgstr "" + +#: src/Module/Admin/Site.php:497 +msgid "Check upstream version" +msgstr "" + +#: src/Module/Admin/Site.php:497 +msgid "" +"Enables checking for new Friendica versions at github. If there is a new " +"version, you will be informed in the admin panel overview." +msgstr "" + +#: src/Module/Admin/Site.php:498 +msgid "Suppress Tags" +msgstr "Piilota tunnisteet" + +#: src/Module/Admin/Site.php:498 +msgid "Suppress showing a list of hashtags at the end of the posting." +msgstr "Piilota tunnistelista julkaisun lopussa." + +#: src/Module/Admin/Site.php:499 +msgid "Clean database" +msgstr "Siivoa tietokanta" + +#: src/Module/Admin/Site.php:499 +msgid "" +"Remove old remote items, orphaned database records and old content from some" +" other helper tables." +msgstr "" + +#: src/Module/Admin/Site.php:500 +msgid "Lifespan of remote items" +msgstr "" + +#: src/Module/Admin/Site.php:500 +msgid "" +"When the database cleanup is enabled, this defines the days after which " +"remote items will be deleted. Own items, and marked or filed items are " +"always kept. 0 disables this behaviour." +msgstr "" + +#: src/Module/Admin/Site.php:501 +msgid "Lifespan of unclaimed items" +msgstr "" + +#: src/Module/Admin/Site.php:501 +msgid "" +"When the database cleanup is enabled, this defines the days after which " +"unclaimed remote items (mostly content from the relay) will be deleted. " +"Default value is 90 days. Defaults to the general lifespan value of remote " +"items if set to 0." +msgstr "" + +#: src/Module/Admin/Site.php:502 +msgid "Lifespan of raw conversation data" +msgstr "" + +#: src/Module/Admin/Site.php:502 +msgid "" +"The conversation data is used for ActivityPub and OStatus, as well as for " +"debug purposes. It should be safe to remove it after 14 days, default is 90 " +"days." +msgstr "" + +#: src/Module/Admin/Site.php:503 +msgid "Maximum numbers of comments per post" +msgstr "Julkaisun kommentiraja" + +#: src/Module/Admin/Site.php:503 +msgid "How much comments should be shown for each post? Default value is 100." +msgstr "" + +#: src/Module/Admin/Site.php:504 +msgid "Maximum numbers of comments per post on the display page" +msgstr "" + +#: src/Module/Admin/Site.php:504 +msgid "" +"How many comments should be shown on the single view for each post? Default " +"value is 1000." +msgstr "" + +#: src/Module/Admin/Site.php:505 +msgid "Temp path" +msgstr "Väliaikaistiedostojen polku" + +#: src/Module/Admin/Site.php:505 +msgid "" +"If you have a restricted system where the webserver can't access the system " +"temp path, enter another path here." +msgstr "Mikäli verkkopalvelimesi ei voi käyttää järjestelmän väliaikaistiedostojen polkua, syötä toinen polku tähän." + +#: src/Module/Admin/Site.php:506 +msgid "Only search in tags" +msgstr "Tunnistehaku" + +#: src/Module/Admin/Site.php:506 +msgid "On large systems the text search can slow down the system extremely." +msgstr "" + +#: src/Module/Admin/Site.php:507 +msgid "Generate counts per contact circle when calculating network count" +msgstr "" + +#: src/Module/Admin/Site.php:507 +msgid "" +"On systems with users that heavily use contact circles the query can be very" +" expensive." +msgstr "" + +#: src/Module/Admin/Site.php:509 +msgid "Maximum number of parallel workers" +msgstr "Enimmäismäärä rinnakkaisia workereitä" + +#: src/Module/Admin/Site.php:509 +#, php-format +msgid "" +"On shared hosters set this to %d. On larger systems, values of %d are great." +" Default value is %d." +msgstr "" + +#: src/Module/Admin/Site.php:510 +msgid "Enable fastlane" +msgstr "Käytä fastlane" + +#: src/Module/Admin/Site.php:510 +msgid "" +"When enabed, the fastlane mechanism starts an additional worker if processes" +" with higher priority are blocked by processes of lower priority." +msgstr "" + +#: src/Module/Admin/Site.php:512 +msgid "Direct relay transfer" +msgstr "Suora releen siirto" + +#: src/Module/Admin/Site.php:512 +msgid "" +"Enables the direct transfer to other servers without using the relay servers" +msgstr "" + +#: src/Module/Admin/Site.php:513 +msgid "Relay scope" +msgstr "Relen soveltamisala" + +#: src/Module/Admin/Site.php:513 +msgid "" +"Can be \"all\" or \"tags\". \"all\" means that every public post should be " +"received. \"tags\" means that only posts with selected tags should be " +"received." +msgstr "" + +#: src/Module/Admin/Site.php:513 src/Module/Contact/Profile.php:286 +#: src/Module/Settings/TwoFactor/Index.php:125 +msgid "Disabled" +msgstr "Pois käytöstä" + +#: src/Module/Admin/Site.php:513 +msgid "all" +msgstr "kaikki" + +#: src/Module/Admin/Site.php:513 +msgid "tags" +msgstr "tunnisteet" + +#: src/Module/Admin/Site.php:514 +msgid "Server tags" +msgstr "palvelintunnisteet" + +#: src/Module/Admin/Site.php:514 +msgid "Comma separated list of tags for the \"tags\" subscription." +msgstr "" + +#: src/Module/Admin/Site.php:515 +msgid "Deny Server tags" +msgstr "" + +#: src/Module/Admin/Site.php:515 +msgid "Comma separated list of tags that are rejected." +msgstr "" + +#: src/Module/Admin/Site.php:516 +msgid "Allow user tags" +msgstr "Salli käyttäjien tunnisteet" + +#: src/Module/Admin/Site.php:516 +msgid "" +"If enabled, the tags from the saved searches will used for the \"tags\" " +"subscription in addition to the \"relay_server_tags\"." +msgstr "" + +#: src/Module/Admin/Site.php:519 +msgid "Start Relocation" +msgstr "" + +#: src/Module/Admin/Storage.php:46 +#, php-format +msgid "Storage backend, %s is invalid." +msgstr "" + +#: src/Module/Admin/Storage.php:73 +#, php-format +msgid "Storage backend %s error: %s" +msgstr "" + +#: src/Module/Admin/Storage.php:84 src/Module/Admin/Storage.php:87 +msgid "Invalid storage backend setting value." +msgstr "" + +#: src/Module/Admin/Storage.php:139 +msgid "Current Storage Backend" +msgstr "" + +#: src/Module/Admin/Storage.php:140 +msgid "Storage Configuration" +msgstr "" + +#: src/Module/Admin/Storage.php:141 src/Module/BaseAdmin.php:91 +msgid "Storage" +msgstr "" + +#: src/Module/Admin/Storage.php:143 +msgid "Save & Use storage backend" +msgstr "" + +#: src/Module/Admin/Storage.php:144 +msgid "Use storage backend" +msgstr "" + +#: src/Module/Admin/Storage.php:145 +msgid "Save & Reload" +msgstr "" + +#: src/Module/Admin/Storage.php:146 +msgid "This backend doesn't have custom settings" +msgstr "" + +#: src/Module/Admin/Storage.php:148 +msgid "" +"Changing the current backend is prohibited because it is set by an " +"environment variable" +msgstr "" + +#: src/Module/Admin/Storage.php:150 +msgid "Database (legacy)" +msgstr "" + +#: src/Module/Admin/Summary.php:55 +#, php-format +msgid "Template engine (%s) error: %s" +msgstr "" + +#: src/Module/Admin/Summary.php:59 +#, php-format +msgid "" +"Your DB still runs with MyISAM tables. You should change the engine type to " +"InnoDB. As Friendica will use InnoDB only features in the future, you should" +" change this! See here for a guide that may be helpful " +"converting the table engines. You may also use the command php " +"bin/console.php dbstructure toinnodb of your Friendica installation for" +" an automatic conversion.
" +msgstr "" + +#: src/Module/Admin/Summary.php:64 +#, php-format +msgid "" +"Your DB still runs with InnoDB tables in the Antelope file format. You " +"should change the file format to Barracuda. Friendica is using features that" +" are not provided by the Antelope format. See here for a " +"guide that may be helpful converting the table engines. You may also use the" +" command php bin/console.php dbstructure toinnodb of your Friendica" +" installation for an automatic conversion.
" +msgstr "" + +#: src/Module/Admin/Summary.php:74 +#, php-format +msgid "" +"Your table_definition_cache is too low (%d). This can lead to the database " +"error \"Prepared statement needs to be re-prepared\". Please set it at least" +" to %d. See here for more information.
" +msgstr "" + +#: src/Module/Admin/Summary.php:85 +#, php-format +msgid "" +"There is a new version of Friendica available for download. Your current " +"version is %1$s, upstream version is %2$s" +msgstr "" + +#: src/Module/Admin/Summary.php:94 +msgid "" +"The database update failed. Please run \"php bin/console.php dbstructure " +"update\" from the command line and have a look at the errors that might " +"appear." +msgstr "Tietokannan päivitys epäonnistui. Suorita komento \"php bin/console.php dbstructure update\" komentoriviltä ja lue mahdolliset virheviestit." + +#: src/Module/Admin/Summary.php:98 +msgid "" +"The last update failed. Please run \"php bin/console.php dbstructure " +"update\" from the command line and have a look at the errors that might " +"appear. (Some of the errors are possibly inside the logfile.)" +msgstr "" + +#: src/Module/Admin/Summary.php:102 +msgid "" +"The system.url entry is missing. This is a low level setting and can lead to" +" unexpected behavior. Please add a valid entry as soon as possible in the " +"config file or per console command!" +msgstr "" + +#: src/Module/Admin/Summary.php:107 +msgid "The worker was never executed. Please check your database structure!" +msgstr "Workeriä ei ole otettu käyttöön. Tarkista tietokantasi rakenne!" + +#: src/Module/Admin/Summary.php:109 +#, php-format +msgid "" +"The last worker execution was on %s UTC. This is older than one hour. Please" +" check your crontab settings." +msgstr "Viimeisin worker -käynnistys tapahtui klo %s UTC, eli yli tunti sitten. Tarkista crontab -asetukset." + +#: src/Module/Admin/Summary.php:114 +#, php-format +msgid "" +"Friendica's configuration now is stored in config/local.config.php, please " +"copy config/local-sample.config.php and move your config from " +".htconfig.php. See the Config help page for " +"help with the transition." +msgstr "" + +#: src/Module/Admin/Summary.php:118 +#, php-format +msgid "" +"Friendica's configuration now is stored in config/local.config.php, please " +"copy config/local-sample.config.php and move your config from " +"config/local.ini.php. See the Config help " +"page for help with the transition." +msgstr "" + +#: src/Module/Admin/Summary.php:124 +#, php-format +msgid "" +"%s is not reachable on your system. This is a severe " +"configuration issue that prevents server to server communication. See the installation page for help." +msgstr "" + +#: src/Module/Admin/Summary.php:142 +#, php-format +msgid "The logfile '%s' is not usable. No logging possible (error: '%s')" +msgstr "" + +#: src/Module/Admin/Summary.php:156 +#, php-format +msgid "" +"The debug logfile '%s' is not usable. No logging possible (error: '%s')" +msgstr "" + +#: src/Module/Admin/Summary.php:172 +#, php-format +msgid "" +"Friendica's system.basepath was updated from '%s' to '%s'. Please remove the" +" system.basepath from your db to avoid differences." +msgstr "" + +#: src/Module/Admin/Summary.php:180 +#, php-format +msgid "" +"Friendica's current system.basepath '%s' is wrong and the config file '%s' " +"isn't used." +msgstr "" + +#: src/Module/Admin/Summary.php:188 +#, php-format +msgid "" +"Friendica's current system.basepath '%s' is not equal to the config file " +"'%s'. Please fix your configuration." +msgstr "" + +#: src/Module/Admin/Summary.php:199 +msgid "Message queues" +msgstr "Viestijonot" + +#: src/Module/Admin/Summary.php:205 +msgid "Server Settings" +msgstr "" + +#: src/Module/Admin/Summary.php:223 +msgid "Version" +msgstr "Versio" + +#: src/Module/Admin/Summary.php:227 +msgid "Active addons" +msgstr "Käytössäolevat lisäosat" + +#: src/Module/Admin/Themes/Details.php:57 src/Module/Admin/Themes/Index.php:65 +#, php-format +msgid "Theme %s disabled." +msgstr "" + +#: src/Module/Admin/Themes/Details.php:59 src/Module/Admin/Themes/Index.php:67 +#, php-format +msgid "Theme %s successfully enabled." +msgstr "" + +#: src/Module/Admin/Themes/Details.php:61 src/Module/Admin/Themes/Index.php:69 +#, php-format +msgid "Theme %s failed to install." +msgstr "" + +#: src/Module/Admin/Themes/Details.php:83 +msgid "Screenshot" +msgstr "Kuvakaappaus" + +#: src/Module/Admin/Themes/Details.php:91 +#: src/Module/Admin/Themes/Index.php:112 src/Module/BaseAdmin.php:93 +msgid "Themes" +msgstr "Teemat" + +#: src/Module/Admin/Themes/Embed.php:80 +msgid "Unknown theme." +msgstr "" + +#: src/Module/Admin/Themes/Index.php:51 +msgid "Themes reloaded" +msgstr "" + +#: src/Module/Admin/Themes/Index.php:114 +msgid "Reload active themes" +msgstr "Lataa aktiiviset teemat uudelleen" + +#: src/Module/Admin/Themes/Index.php:118 +#, php-format +msgid "No themes found on the system. They should be placed in %1$s" +msgstr "Teemoja ei löytynyt järjestelmästä. Teemat tulisi laittaa kansioon %1$s" + +#: src/Module/Admin/Themes/Index.php:119 +msgid "[Experimental]" +msgstr "[Kokeellinen]" + +#: src/Module/Admin/Themes/Index.php:120 +msgid "[Unsupported]" +msgstr "[Ei tueta]" + +#: src/Module/Admin/Tos.php:79 +msgid "Display Terms of Service" +msgstr "Näytä käyttöehdot" + +#: src/Module/Admin/Tos.php:79 +msgid "" +"Enable the Terms of Service page. If this is enabled a link to the terms " +"will be added to the registration form and the general information page." +msgstr "" + +#: src/Module/Admin/Tos.php:80 +msgid "Display Privacy Statement" +msgstr "Näytä tietosuojalausunto" + +#: src/Module/Admin/Tos.php:80 +#, php-format +msgid "" +"Show some informations regarding the needed information to operate the node " +"according e.g. to EU-GDPR." +msgstr "" + +#: src/Module/Admin/Tos.php:81 +msgid "Privacy Statement Preview" +msgstr "" + +#: src/Module/Admin/Tos.php:83 +msgid "The Terms of Service" +msgstr "Käyttöehdot" + +#: src/Module/Admin/Tos.php:83 +msgid "" +"Enter the Terms of Service for your node here. You can use BBCode. Headers " +"of sections should be [h2] and below." +msgstr "" + +#: src/Module/Admin/Tos.php:84 +msgid "The rules" +msgstr "" + +#: src/Module/Admin/Tos.php:84 +msgid "Enter your system rules here. Each line represents one rule." +msgstr "" + +#: src/Module/Api/ApiResponse.php:279 +#, php-format +msgid "API endpoint %s %s is not implemented but might be in the future." +msgstr "" + +#: src/Module/Api/Mastodon/Apps.php:73 +msgid "Missing parameters" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Bookmark.php:51 +msgid "Only starting posts can be bookmarked" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Mute.php:51 +msgid "Only starting posts can be muted" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Reblog.php:56 +#, php-format +msgid "Posts from %s can't be shared" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unbookmark.php:51 +msgid "Only starting posts can be unbookmarked" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unmute.php:51 +msgid "Only starting posts can be unmuted" +msgstr "" + +#: src/Module/Api/Mastodon/Statuses/Unreblog.php:62 +#, php-format +msgid "Posts from %s can't be unshared" +msgstr "" + +#: src/Module/Api/Twitter/ContactEndpoint.php:66 +msgid "Contact not found" +msgstr "" + +#: src/Module/Apps.php:62 +msgid "No installed applications." +msgstr "Ei asennettuja sovelluksia." + +#: src/Module/Apps.php:67 +msgid "Applications" +msgstr "Sovellukset" + +#: src/Module/Attach.php:49 src/Module/Attach.php:61 +msgid "Item was not found." +msgstr "Kohdetta ei löytynyt." + +#: src/Module/BaseAdmin.php:54 src/Module/BaseAdmin.php:58 +#: src/Module/BaseModeration.php:77 src/Module/BaseModeration.php:81 +msgid "Please login to continue." +msgstr "Ole hyvä ja kirjaudu jatkaaksesi." + +#: src/Module/BaseAdmin.php:63 src/Module/BaseModeration.php:86 +msgid "You don't have access to administration pages." +msgstr "" + +#: src/Module/BaseAdmin.php:67 src/Module/BaseModeration.php:90 +msgid "" +"Submanaged account can't access the administration pages. Please log back in" +" as the main account." +msgstr "" + +#: src/Module/BaseAdmin.php:86 src/Module/BaseModeration.php:109 +msgid "Overview" +msgstr "Yleiskatsaus" + +#: src/Module/BaseAdmin.php:89 src/Module/BaseModeration.php:111 +msgid "Configuration" +msgstr "Kokoonpano" + +#: src/Module/BaseAdmin.php:94 src/Module/BaseSettings.php:112 +msgid "Additional features" +msgstr "Lisäominaisuuksia" + +#: src/Module/BaseAdmin.php:97 +msgid "Database" +msgstr "Tietokanta" + +#: src/Module/BaseAdmin.php:98 +msgid "DB updates" +msgstr "Tietokannan päivitykset" + +#: src/Module/BaseAdmin.php:99 +msgid "Inspect Deferred Workers" +msgstr "" + +#: src/Module/BaseAdmin.php:100 +msgid "Inspect worker Queue" +msgstr "" + +#: src/Module/BaseAdmin.php:106 src/Module/BaseModeration.php:119 +msgid "Diagnostics" +msgstr "Diagnostiikka" + +#: src/Module/BaseAdmin.php:107 +msgid "PHP Info" +msgstr "PHP tietoja" + +#: src/Module/BaseAdmin.php:108 +msgid "probe address" +msgstr "" + +#: src/Module/BaseAdmin.php:109 +msgid "check webfinger" +msgstr "Tarkista webfinger" + +#: src/Module/BaseAdmin.php:110 +msgid "Babel" +msgstr "" + +#: src/Module/BaseAdmin.php:111 src/Module/Debug/ActivityPubConversion.php:137 +msgid "ActivityPub Conversion" +msgstr "" + +#: src/Module/BaseAdmin.php:120 +msgid "Addon Features" +msgstr "Lisäosaominaisuudet" + +#: src/Module/BaseAdmin.php:121 src/Module/BaseModeration.php:128 +msgid "User registrations waiting for confirmation" +msgstr "Käyttäjärekisteröinnit odottavat hyväksyntää" + +#: src/Module/BaseApi.php:451 src/Module/BaseApi.php:467 +#: src/Module/BaseApi.php:483 +msgid "Too Many Requests" +msgstr "" + +#: src/Module/BaseApi.php:452 +#, php-format +msgid "Daily posting limit of %d post reached. The post was rejected." +msgid_plural "Daily posting limit of %d posts reached. The post was rejected." +msgstr[0] "Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." +msgstr[1] "Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." + +#: src/Module/BaseApi.php:468 +#, php-format +msgid "Weekly posting limit of %d post reached. The post was rejected." +msgid_plural "" +"Weekly posting limit of %d posts reached. The post was rejected." +msgstr[0] "Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." +msgstr[1] "Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty." + +#: src/Module/BaseApi.php:484 +#, php-format +msgid "Monthly posting limit of %d post reached. The post was rejected." +msgid_plural "" +"Monthly posting limit of %d posts reached. The post was rejected." +msgstr[0] "" +msgstr[1] "" + +#: src/Module/BaseModeration.php:112 src/Module/Moderation/Users/Index.php:148 +#: src/Module/Moderation/Users/Index.php:158 +msgid "Users" +msgstr "Käyttäjät" + +#: src/Module/BaseModeration.php:114 +msgid "Tools" +msgstr "Työkalut" + +#: src/Module/BaseModeration.php:115 +msgid "Contact Blocklist" +msgstr "Kontaktien estolista" + +#: src/Module/BaseModeration.php:116 +msgid "Server Blocklist" +msgstr "Palvelimien estolista" + +#: src/Module/BaseModeration.php:117 src/Module/Moderation/Item/Delete.php:62 +msgid "Delete Item" +msgstr "Poista kohde" + +#: src/Module/BaseModeration.php:120 src/Module/Moderation/Item/Source.php:76 +msgid "Item Source" +msgstr "" + +#: src/Module/BaseProfile.php:52 src/Module/Contact.php:487 +msgid "Profile Details" +msgstr "Profiilitiedot" + +#: src/Module/BaseProfile.php:60 +msgid "Conversations started" +msgstr "" + +#: src/Module/BaseProfile.php:111 +msgid "Only You Can See This" +msgstr "Vain sinä näet tämän" + +#: src/Module/BaseProfile.php:116 src/Module/Profile/Schedule.php:81 +msgid "Scheduled Posts" +msgstr "" + +#: src/Module/BaseProfile.php:119 +msgid "Posts that are scheduled for publishing" +msgstr "" + +#: src/Module/BaseProfile.php:138 src/Module/BaseProfile.php:141 +msgid "Tips for New Members" +msgstr "Vinkkejä uusille käyttäjille" + +#: src/Module/BaseSearch.php:71 +#, php-format +msgid "People Search - %s" +msgstr "Käyttäjähaku - %s" + +#: src/Module/BaseSearch.php:75 +#, php-format +msgid "Group Search - %s" +msgstr "" + +#: src/Module/BaseSearch.php:121 src/Module/Contact/MatchInterests.php:139 +msgid "No matches" +msgstr "Ei täsmääviä profiileja" + +#: src/Module/BaseSearch.php:147 +#, php-format +msgid "" +"%d result was filtered out because your node blocks the domain it is " +"registered on. You can review the list of domains your node is currently " +"blocking in the About page." +msgid_plural "" +"%d results were filtered out because your node blocks the domain they are " +"registered on. You can review the list of domains your node is currently " +"blocking in the About page." +msgstr[0] "" +msgstr[1] "" + +#: src/Module/BaseSettings.php:80 +msgid "Account" +msgstr "Tili" + +#: src/Module/BaseSettings.php:87 src/Module/Security/TwoFactor/Verify.php:96 +#: src/Module/Settings/TwoFactor/Index.php:117 +msgid "Two-factor authentication" +msgstr "" + +#: src/Module/BaseSettings.php:120 +msgid "Display" +msgstr "Ulkonäkö" + +#: src/Module/BaseSettings.php:127 src/Module/Settings/Connectors.php:204 +msgid "Social Networks" +msgstr "Sosiaalinen media" + +#: src/Module/BaseSettings.php:141 src/Module/Settings/Delegation.php:172 +msgid "Manage Accounts" +msgstr "" + +#: src/Module/BaseSettings.php:148 +msgid "Connected apps" +msgstr "Yhdistetyt sovellukset" + +#: src/Module/BaseSettings.php:155 src/Module/Settings/UserExport.php:98 +msgid "Export personal data" +msgstr "Vie henkilökohtaiset tiedot" + +#: src/Module/BaseSettings.php:162 +msgid "Remove account" +msgstr "Poista tili" + +#: src/Module/Bookmarklet.php:54 +msgid "This page is missing a url parameter." +msgstr "" + +#: src/Module/Bookmarklet.php:66 +msgid "The post was created" +msgstr "Julkaisu luotu" + +#: src/Module/Calendar/Event/API.php:100 src/Module/Calendar/Event/API.php:135 +#: src/Module/Calendar/Event/Form.php:80 +msgid "Invalid Request" +msgstr "" + +#: src/Module/Calendar/Event/API.php:109 +msgid "Event id is missing." +msgstr "" + +#: src/Module/Calendar/Event/API.php:131 +msgid "Failed to remove event" +msgstr "Tapahtuman poisto epäonnistui" + +#: src/Module/Calendar/Event/API.php:186 src/Module/Calendar/Event/API.php:188 +msgid "Event can not end before it has started." +msgstr "Tapahtuma ei voi päättyä ennen kuin on alkanut." + +#: src/Module/Calendar/Event/API.php:195 src/Module/Calendar/Event/API.php:197 +msgid "Event title and start time are required." +msgstr "Tapahtuman nimi ja alkamisaika vaaditaan." + +#: src/Module/Calendar/Event/Form.php:208 +msgid "Starting date and Title are required." +msgstr "Aloituspvm ja otsikko vaaditaan." + +#: src/Module/Calendar/Event/Form.php:209 +#: src/Module/Calendar/Event/Form.php:214 +msgid "Event Starts:" +msgstr "Tapahtuma alkaa:" + +#: src/Module/Calendar/Event/Form.php:209 +#: src/Module/Calendar/Event/Form.php:237 src/Module/Debug/Probe.php:59 +#: src/Module/Install.php:201 src/Module/Install.php:227 +#: src/Module/Install.php:232 src/Module/Install.php:246 +#: src/Module/Install.php:255 src/Module/Install.php:260 +#: src/Module/Install.php:266 src/Module/Install.php:271 +#: src/Module/Install.php:285 src/Module/Install.php:298 +#: src/Module/Install.php:325 +#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Add.php:138 +#: src/Module/Moderation/Blocklist/Server/Import.php:129 +#: src/Module/Moderation/Blocklist/Server/Index.php:86 +#: src/Module/Moderation/Blocklist/Server/Index.php:87 +#: src/Module/Moderation/Blocklist/Server/Index.php:115 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 +#: src/Module/Moderation/Item/Delete.php:67 src/Module/Register.php:148 +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Index.php:140 +#: src/Module/Settings/TwoFactor/Verify.php:155 +msgid "Required" +msgstr "Vaaditaan" + +#: src/Module/Calendar/Event/Form.php:223 +#: src/Module/Calendar/Event/Form.php:247 +msgid "Finish date/time is not known or not relevant" +msgstr "Päättymispvm ja kellonaika ei ole tiedossa tai niillä ei ole merkitystä" + +#: src/Module/Calendar/Event/Form.php:225 +#: src/Module/Calendar/Event/Form.php:230 +msgid "Event Finishes:" +msgstr "Tapahtuma päättyy:" + +#: src/Module/Calendar/Event/Form.php:237 +#: src/Module/Calendar/Event/Form.php:243 +msgid "Title (BBCode not allowed)" +msgstr "" + +#: src/Module/Calendar/Event/Form.php:239 +msgid "Description (BBCode allowed)" +msgstr "" + +#: src/Module/Calendar/Event/Form.php:241 +msgid "Location (BBCode not allowed)" +msgstr "" + +#: src/Module/Calendar/Event/Form.php:244 +#: src/Module/Calendar/Event/Form.php:245 +msgid "Share this event" +msgstr "Jaa tämä tapahtuma" + +#: src/Module/Calendar/Event/Form.php:251 src/Module/Profile/Profile.php:275 +msgid "Basic" +msgstr "" + +#: src/Module/Calendar/Export.php:94 +msgid "This calendar format is not supported" +msgstr "Tätä kalenteriformaattia ei tueta" + +#: src/Module/Calendar/Export.php:96 +msgid "No exportable data found" +msgstr "Vientikelpoista dataa ei löytynyt" + +#: src/Module/Calendar/Export.php:113 +msgid "calendar" +msgstr "kalenteri" + +#: src/Module/Calendar/Show.php:124 +msgid "Events" +msgstr "Tapahtumat" + +#: src/Module/Calendar/Show.php:125 +msgid "View" +msgstr "Katso" + +#: src/Module/Calendar/Show.php:126 +msgid "Create New Event" +msgstr "Luo uusi tapahtuma" + +#: src/Module/Calendar/Show.php:132 src/Module/Settings/Display.php:235 +msgid "list" +msgstr "luettelo" + +#: src/Module/Circle.php:56 +msgid "Could not create circle." +msgstr "" + +#: src/Module/Circle.php:67 src/Module/Circle.php:215 +#: src/Module/Circle.php:239 +msgid "Circle not found." +msgstr "" + +#: src/Module/Circle.php:73 +msgid "Circle name was not changed." +msgstr "" + +#: src/Module/Circle.php:91 +msgid "Unknown circle." +msgstr "" + +#: src/Module/Circle.php:97 src/Module/Circle.php:106 +#: src/Module/Contact/Advanced.php:70 src/Module/Contact/Advanced.php:109 +#: src/Module/Contact/Contacts.php:71 src/Module/Contact/Conversations.php:84 +#: src/Module/Contact/Conversations.php:89 +#: src/Module/Contact/Conversations.php:94 src/Module/Contact/Media.php:43 +#: src/Module/Contact/Posts.php:78 src/Module/Contact/Posts.php:83 +#: src/Module/Contact/Posts.php:88 src/Module/Contact/Profile.php:142 +#: src/Module/Contact/Profile.php:147 src/Module/Contact/Profile.php:152 +#: src/Module/Contact/Redir.php:94 src/Module/Contact/Redir.php:140 +#: src/Module/FriendSuggest.php:71 src/Module/FriendSuggest.php:109 +msgid "Contact not found." +msgstr "Kontaktia ei ole." + +#: src/Module/Circle.php:101 src/Module/Contact/Contacts.php:66 +#: src/Module/Conversation/Network.php:189 +msgid "Invalid contact." +msgstr "Virheellinen kontakti." + +#: src/Module/Circle.php:110 src/Module/Contact/Revoke.php:73 +msgid "Contact is deleted." +msgstr "" + +#: src/Module/Circle.php:116 +msgid "Unable to add the contact to the circle." +msgstr "" + +#: src/Module/Circle.php:119 +msgid "Contact successfully added to circle." +msgstr "" + +#: src/Module/Circle.php:123 +msgid "Unable to remove the contact from the circle." +msgstr "" + +#: src/Module/Circle.php:126 +msgid "Contact successfully removed from circle." +msgstr "" + +#: src/Module/Circle.php:130 +msgid "Bad request." +msgstr "" + +#: src/Module/Circle.php:171 +msgid "Save Circle" +msgstr "" + +#: src/Module/Circle.php:172 +msgid "Filter" +msgstr "" + +#: src/Module/Circle.php:178 +msgid "Create a circle of contacts/friends." +msgstr "" + +#: src/Module/Circle.php:220 +msgid "Unable to remove circle." +msgstr "" + +#: src/Module/Circle.php:271 +msgid "Delete Circle" +msgstr "" + +#: src/Module/Circle.php:281 +msgid "Edit Circle Name" +msgstr "" + +#: src/Module/Circle.php:291 +msgid "Members" +msgstr "Jäsenet" + +#: src/Module/Circle.php:294 +msgid "Circle is empty" +msgstr "" + +#: src/Module/Circle.php:307 +msgid "Remove contact from circle" +msgstr "" + +#: src/Module/Circle.php:328 +msgid "Click on a contact to add or remove." +msgstr "Valitse kontakti, jota haluat poistaa tai lisätä." + +#: src/Module/Circle.php:342 +msgid "Add contact to circle" +msgstr "" + +#: src/Module/Contact.php:97 +#, php-format +msgid "%d contact edited." +msgid_plural "%d contacts edited." +msgstr[0] "%d kontakti muokattu" +msgstr[1] "%d kontakteja muokattu" + +#: src/Module/Contact.php:349 +msgid "Show all contacts" +msgstr "Näytä kaikki yhteystiedot" + +#: src/Module/Contact.php:354 src/Module/Contact.php:423 +#: src/Module/Moderation/BaseUsers.php:85 +msgid "Pending" +msgstr "" + +#: src/Module/Contact.php:357 +msgid "Only show pending contacts" +msgstr "" + +#: src/Module/Contact.php:362 src/Module/Contact.php:424 +#: src/Module/Moderation/BaseUsers.php:93 +msgid "Blocked" +msgstr "Estetty" + +#: src/Module/Contact.php:365 +msgid "Only show blocked contacts" +msgstr "Näytä vain estetyt henkilöt" + +#: src/Module/Contact.php:370 src/Module/Contact.php:426 +#: src/Object/Post.php:351 +msgid "Ignored" +msgstr "Jätetty huomiotta" + +#: src/Module/Contact.php:373 +msgid "Only show ignored contacts" +msgstr "Näytä vain henkilöt, jotka jätetty huomiotta" + +#: src/Module/Contact.php:378 src/Module/Contact.php:427 +msgid "Collapsed" +msgstr "" + +#: src/Module/Contact.php:381 +msgid "Only show collapsed contacts" +msgstr "" + +#: src/Module/Contact.php:386 src/Module/Contact.php:428 +msgid "Archived" +msgstr "Arkistoitu" + +#: src/Module/Contact.php:389 +msgid "Only show archived contacts" +msgstr "Näytä vain arkistoidut henkilöt" + +#: src/Module/Contact.php:394 src/Module/Contact.php:425 +msgid "Hidden" +msgstr "Piilotettu" + +#: src/Module/Contact.php:397 +msgid "Only show hidden contacts" +msgstr "Näytä vain piilotetut henkilöt" + +#: src/Module/Contact.php:405 +msgid "Organize your contact circles" +msgstr "" + +#: src/Module/Contact.php:439 +msgid "Search your contacts" +msgstr "Etsi henkilöitä" + +#: src/Module/Contact.php:440 src/Module/Search/Index.php:207 +#, php-format +msgid "Results for: %s" +msgstr "Tulokset haulla: %s" + +#: src/Module/Contact.php:447 +msgid "Update" +msgstr "Päivitä" + +#: src/Module/Contact.php:448 src/Module/Contact/Profile.php:477 +#: src/Module/Moderation/Blocklist/Contact.php:117 +#: src/Module/Moderation/Users/Blocked.php:138 +#: src/Module/Moderation/Users/Index.php:154 +msgid "Unblock" +msgstr "Salli" + +#: src/Module/Contact.php:449 src/Module/Contact/Profile.php:485 +msgid "Unignore" +msgstr "Ota huomioon" + +#: src/Module/Contact.php:450 src/Module/Contact/Profile.php:493 +msgid "Uncollapse" +msgstr "" + +#: src/Module/Contact.php:452 +msgid "Batch Actions" +msgstr "" + +#: src/Module/Contact.php:495 +msgid "Conversations started by this contact" +msgstr "" + +#: src/Module/Contact.php:500 +msgid "Posts and Comments" +msgstr "" + +#: src/Module/Contact.php:503 +msgid "Individual Posts and Replies" +msgstr "" + +#: src/Module/Contact.php:511 +msgid "Posts containing media objects" +msgstr "" + +#: src/Module/Contact.php:518 +msgid "View all known contacts" +msgstr "" + +#: src/Module/Contact.php:528 +msgid "Advanced Contact Settings" +msgstr "Kontakti-lisäasetukset" + +#: src/Module/Contact.php:564 +msgid "Mutual Friendship" +msgstr "Yhteinen kaveruus" + +#: src/Module/Contact.php:568 +msgid "is a fan of yours" +msgstr "on fanisi" + +#: src/Module/Contact.php:572 +msgid "you are a fan of" +msgstr "fanitat" + +#: src/Module/Contact.php:590 +msgid "Pending outgoing contact request" +msgstr "" + +#: src/Module/Contact.php:592 +msgid "Pending incoming contact request" +msgstr "" + +#: src/Module/Contact.php:605 src/Module/Contact/Profile.php:346 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Näytä %s-käyttäjän profiili [%s]" + +#: src/Module/Contact/Advanced.php:99 +msgid "Contact update failed." +msgstr "Kontaktipäivitys epäonnistui." + +#: src/Module/Contact/Advanced.php:130 +msgid "Return to contact editor" +msgstr "Palaa kontaktin muokkaamiseen" + +#: src/Module/Contact/Advanced.php:134 +#: src/Module/Moderation/Blocklist/Contact.php:122 +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Create.php:70 +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:140 +#: src/Module/Moderation/Users/Index.php:160 +#: src/Module/Moderation/Users/Pending.php:99 src/Module/Settings/OAuth.php:72 +msgid "Name" +msgstr "Nimi" + +#: src/Module/Contact/Advanced.php:135 +msgid "Account Nickname" +msgstr "Tilin lempinimi" + +#: src/Module/Contact/Advanced.php:136 +msgid "Account URL" +msgstr "Tilin URL-osoite" + +#: src/Module/Contact/Advanced.php:137 +msgid "Poll/Feed URL" +msgstr "URL äänestyksiä/syötteitä varten" + +#: src/Module/Contact/Advanced.php:138 +msgid "New photo from this URL" +msgstr "Uusi kuva osoitteesta" + +#: src/Module/Contact/Contacts.php:89 +msgid "No known contacts." +msgstr "" + +#: src/Module/Contact/Contacts.php:103 src/Module/Profile/Common.php:128 +msgid "No common contacts." +msgstr "" + +#: src/Module/Contact/Contacts.php:115 src/Module/Profile/Contacts.php:135 +#, php-format +msgid "Follower (%s)" +msgid_plural "Followers (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Contact/Contacts.php:119 src/Module/Profile/Contacts.php:138 +#, php-format +msgid "Following (%s)" +msgid_plural "Following (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Contact/Contacts.php:123 src/Module/Profile/Contacts.php:141 +#, php-format +msgid "Mutual friend (%s)" +msgid_plural "Mutual friends (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Contact/Contacts.php:125 src/Module/Profile/Contacts.php:143 +#, php-format +msgid "These contacts both follow and are followed by %s." +msgstr "" + +#: src/Module/Contact/Contacts.php:131 src/Module/Profile/Common.php:116 +#, php-format +msgid "Common contact (%s)" +msgid_plural "Common contacts (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Contact/Contacts.php:133 src/Module/Profile/Common.php:118 +#, php-format +msgid "" +"Both %s and yourself have publicly interacted with these " +"contacts (follow, comment or likes on public posts)." +msgstr "" + +#: src/Module/Contact/Contacts.php:139 src/Module/Profile/Contacts.php:149 +#, php-format +msgid "Contact (%s)" +msgid_plural "Contacts (%s)" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Contact/Follow.php:70 src/Module/Contact/Redir.php:62 +#: 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:96 src/Module/Item/Feed.php:59 +#: src/Module/Item/Follow.php:41 src/Module/Item/Ignore.php:41 +#: src/Module/Item/Pin.php:41 src/Module/Item/Pin.php:56 +#: src/Module/Item/Star.php:42 src/Module/Update/Display.php:37 +msgid "Access denied." +msgstr "Käyttö estetty." + +#: src/Module/Contact/Follow.php:105 src/Module/Contact/Unfollow.php:125 +#: src/Module/Profile/RemoteFollow.php:133 +msgid "Submit Request" +msgstr "Lähetä pyyntö" + +#: src/Module/Contact/Follow.php:115 +msgid "You already added this contact." +msgstr "Olet jo lisännyt tämän kontaktin." + +#: src/Module/Contact/Follow.php:130 +msgid "The network type couldn't be detected. Contact can't be added." +msgstr "Verkkotyyppiä ei voitu havaita. Kontaktia ei voitu lisätä." + +#: src/Module/Contact/Follow.php:138 +msgid "Diaspora support isn't enabled. Contact can't be added." +msgstr "Diaspora -tuki ei ole käytössä. Kontaktia ei voi lisätä." + +#: src/Module/Contact/Follow.php:143 +msgid "OStatus support is disabled. Contact can't be added." +msgstr "OStatus -tuki ei ole käytössä. Kontaktia ei voi lisätä." + +#: src/Module/Contact/Follow.php:168 src/Module/Profile/RemoteFollow.php:132 +msgid "Please answer the following:" +msgstr "Vastaa seuraavaan:" + +#: src/Module/Contact/Follow.php:169 src/Module/Contact/Unfollow.php:123 +msgid "Your Identity Address:" +msgstr "Identiteettisi osoite:" + +#: src/Module/Contact/Follow.php:170 src/Module/Contact/Profile.php:375 +#: src/Module/Contact/Unfollow.php:129 +#: src/Module/Moderation/Blocklist/Contact.php:133 +#: src/Module/Notifications/Introductions.php:129 +#: src/Module/Notifications/Introductions.php:198 +msgid "Profile URL" +msgstr "Profiilin URL" + +#: src/Module/Contact/Follow.php:171 src/Module/Contact/Profile.php:387 +#: src/Module/Notifications/Introductions.php:191 +#: src/Module/Profile/Profile.php:234 +msgid "Tags:" +msgstr "Tunnisteet:" + +#: src/Module/Contact/Follow.php:182 +#, php-format +msgid "%s knows you" +msgstr "" + +#: src/Module/Contact/Follow.php:183 +msgid "Add a personal note:" +msgstr "Lisää oma merkintä:" + +#: src/Module/Contact/Follow.php:192 src/Module/Contact/Unfollow.php:138 +msgid "Posts and Replies" +msgstr "" + +#: src/Module/Contact/Follow.php:221 +msgid "The contact could not be added." +msgstr "Kontaktia ei voitu lisätä." + +#: src/Module/Contact/MatchInterests.php:94 +#: src/Module/Media/Attachment/Upload.php:77 +#: src/Module/Media/Attachment/Upload.php:82 +#: src/Module/Media/Photo/Upload.php:81 src/Module/Media/Photo/Upload.php:86 +#: src/Module/Media/Photo/Upload.php:135 +msgid "Invalid request." +msgstr "Virheellinen pyyntö." + +#: src/Module/Contact/MatchInterests.php:101 +msgid "No keywords to match. Please add keywords to your profile." +msgstr "" + +#: src/Module/Contact/MatchInterests.php:144 +msgid "Profile Match" +msgstr "Vastaavien profiilien haku" + +#: src/Module/Contact/Profile.php:128 +msgid "Failed to update contact record." +msgstr "Kontaktitietojen päivitys epäonnistui." + +#: src/Module/Contact/Profile.php:178 +msgid "Contact has been unblocked" +msgstr "Henkilö on jälleen sallittu" + +#: src/Module/Contact/Profile.php:182 +msgid "Contact has been blocked" +msgstr "Henkilö on estetty" + +#: src/Module/Contact/Profile.php:194 +msgid "Contact has been unignored" +msgstr "Henkilö on jälleen huomioituna." + +#: src/Module/Contact/Profile.php:198 +msgid "Contact has been ignored" +msgstr "Henkilöä ei enää huomioida" + +#: src/Module/Contact/Profile.php:210 +msgid "Contact has been uncollapsed" +msgstr "" + +#: src/Module/Contact/Profile.php:214 +msgid "Contact has been collapsed" +msgstr "" + +#: src/Module/Contact/Profile.php:242 +#, php-format +msgid "You are mutual friends with %s" +msgstr "Olet kaveri %s kanssa." + +#: src/Module/Contact/Profile.php:243 +#, php-format +msgid "You are sharing with %s" +msgstr "Olet jakanut jotakin %s:n kanssa" + +#: src/Module/Contact/Profile.php:244 +#, php-format +msgid "%s is sharing with you" +msgstr "%s jakaa sinulle jotakin." + +#: src/Module/Contact/Profile.php:260 +msgid "Private communications are not available for this contact." +msgstr "Yksityiskeskustelu ei ole käytettävissä tälle henkilölle." + +#: src/Module/Contact/Profile.php:262 +msgid "Never" +msgstr "Ei koskaan" + +#: src/Module/Contact/Profile.php:265 +msgid "(Update was not successful)" +msgstr "(Päivitys epäonnistui)" + +#: src/Module/Contact/Profile.php:265 +msgid "(Update was successful)" +msgstr "(Päivitys onnistui)" + +#: src/Module/Contact/Profile.php:267 src/Module/Contact/Profile.php:448 +msgid "Suggest friends" +msgstr "Ehdota ystäviä" + +#: src/Module/Contact/Profile.php:271 +#, php-format +msgid "Network type: %s" +msgstr "Verkkotyyppi: %s" + +#: src/Module/Contact/Profile.php:276 +msgid "Communications lost with this contact!" +msgstr "Yhteys tähän henkilöön menetettiin!" + +#: src/Module/Contact/Profile.php:282 +msgid "Fetch further information for feeds" +msgstr "" + +#: src/Module/Contact/Profile.php:284 +msgid "" +"Fetch information like preview pictures, title and teaser from the feed " +"item. You can activate this if the feed doesn't contain much text. Keywords " +"are taken from the meta header in the feed item and are posted as hash tags." +msgstr "" + +#: src/Module/Contact/Profile.php:287 +msgid "Fetch information" +msgstr "Nouda tiedot" + +#: src/Module/Contact/Profile.php:288 +msgid "Fetch keywords" +msgstr "Nouda avainsanat" + +#: src/Module/Contact/Profile.php:289 +msgid "Fetch information and keywords" +msgstr "Nouda tiedot ja avainsanat" + +#: src/Module/Contact/Profile.php:299 src/Module/Contact/Profile.php:304 +#: src/Module/Contact/Profile.php:309 src/Module/Contact/Profile.php:315 +msgid "No mirroring" +msgstr "Ei peilausta" + +#: src/Module/Contact/Profile.php:300 src/Module/Contact/Profile.php:310 +#: src/Module/Contact/Profile.php:316 +msgid "Mirror as my own posting" +msgstr "Peilaa omana julkaisuna" + +#: src/Module/Contact/Profile.php:305 src/Module/Contact/Profile.php:311 +msgid "Native reshare" +msgstr "" + +#: src/Module/Contact/Profile.php:328 +msgid "Contact Information / Notes" +msgstr "Yhteystiedot / Muistiinpanot" + +#: src/Module/Contact/Profile.php:329 +msgid "Contact Settings" +msgstr "Yhteystietoasetukset" + +#: src/Module/Contact/Profile.php:337 +msgid "Contact" +msgstr "Kontakti" + +#: src/Module/Contact/Profile.php:341 +msgid "Their personal note" +msgstr "" + +#: src/Module/Contact/Profile.php:343 +msgid "Edit contact notes" +msgstr "Muokkaa yhteystietojen muistiinpanoja" + +#: src/Module/Contact/Profile.php:347 +msgid "Block/Unblock contact" +msgstr "Estä/salli henkilö" + +#: src/Module/Contact/Profile.php:348 +msgid "Ignore contact" +msgstr "Jätä henkilö huomiotta" + +#: src/Module/Contact/Profile.php:349 +msgid "View conversations" +msgstr "Katso keskusteluja" + +#: src/Module/Contact/Profile.php:354 +msgid "Last update:" +msgstr "Viimeksi päivitetty:" + +#: src/Module/Contact/Profile.php:356 +msgid "Update public posts" +msgstr "Päivitä julkiset postaukset" + +#: src/Module/Contact/Profile.php:358 src/Module/Contact/Profile.php:458 +msgid "Update now" +msgstr "Päivitä nyt" + +#: src/Module/Contact/Profile.php:360 +msgid "Awaiting connection acknowledge" +msgstr "Odotetaan yhteyden kuittausta" + +#: src/Module/Contact/Profile.php:361 +msgid "Currently blocked" +msgstr "Estetty tällä hetkellä" + +#: src/Module/Contact/Profile.php:362 +msgid "Currently ignored" +msgstr "Jätetty huomiotta tällä hetkellä" + +#: src/Module/Contact/Profile.php:363 +msgid "Currently collapsed" +msgstr "" + +#: src/Module/Contact/Profile.php:364 +msgid "Currently archived" +msgstr "Arkistoitu tällä hetkellä" + +#: src/Module/Contact/Profile.php:367 +#: src/Module/Notifications/Introductions.php:192 +msgid "Hide this contact from others" +msgstr "Piilota kontakti muilta" + +#: src/Module/Contact/Profile.php:367 +msgid "" +"Replies/likes to your public posts may still be visible" +msgstr "" + +#: src/Module/Contact/Profile.php:368 +msgid "Notification for new posts" +msgstr "Uusien postausten ilmoitus" + +#: src/Module/Contact/Profile.php:368 +msgid "Send a notification of every new post of this contact" +msgstr "Lähetä ilmoitus tälle henkilölle kaikista uusista postauksista" + +#: src/Module/Contact/Profile.php:370 +msgid "Keyword Deny List" +msgstr "" + +#: src/Module/Contact/Profile.php:370 +msgid "" +"Comma separated list of keywords that should not be converted to hashtags, " +"when \"Fetch information and keywords\" is selected" +msgstr "" + +#: src/Module/Contact/Profile.php:388 +#: src/Module/Settings/TwoFactor/Index.php:139 +msgid "Actions" +msgstr "Toimenpiteet" + +#: src/Module/Contact/Profile.php:390 +#: src/Module/Settings/TwoFactor/Index.php:119 view/theme/frio/theme.php:229 +msgid "Status" +msgstr "Tila" + +#: src/Module/Contact/Profile.php:396 +msgid "Mirror postings from this contact" +msgstr "Peilaa tämän kontaktin julkaisut" + +#: src/Module/Contact/Profile.php:398 +msgid "" +"Mark this contact as remote_self, this will cause friendica to repost new " +"entries from this contact." +msgstr "" + +#: src/Module/Contact/Profile.php:468 +msgid "Refetch contact data" +msgstr "" + +#: src/Module/Contact/Profile.php:479 +msgid "Toggle Blocked status" +msgstr "Estetty tila päälle/pois" + +#: src/Module/Contact/Profile.php:487 +msgid "Toggle Ignored status" +msgstr "Sivuuta/seuraa" + +#: src/Module/Contact/Profile.php:495 +msgid "Toggle Collapsed status" +msgstr "" + +#: src/Module/Contact/Profile.php:502 src/Module/Contact/Revoke.php:106 +msgid "Revoke Follow" +msgstr "" + +#: src/Module/Contact/Profile.php:504 +msgid "Revoke the follow from this contact" +msgstr "" + +#: src/Module/Contact/Redir.php:134 src/Module/Contact/Redir.php:186 +msgid "Bad Request." +msgstr "" + +#: src/Module/Contact/Revoke.php:63 +msgid "Unknown contact." +msgstr "" + +#: src/Module/Contact/Revoke.php:77 +msgid "Contact is being deleted." +msgstr "" + +#: src/Module/Contact/Revoke.php:91 +msgid "Follow was successfully revoked." +msgstr "" + +#: src/Module/Contact/Revoke.php:107 +msgid "" +"Do you really want to revoke this contact's follow? This cannot be undone " +"and they will have to manually follow you back again." +msgstr "" + +#: src/Module/Contact/Revoke.php:108 +#: src/Module/Notifications/Introductions.php:144 +#: src/Module/OAuth/Acknowledge.php:54 src/Module/Register.php:130 +#: src/Module/Settings/TwoFactor/Trusted.php:126 +msgid "Yes" +msgstr "Kyllä" + +#: src/Module/Contact/Suggestions.php:62 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "Ehdotuksia ei löydy. Jos tämä on uusi sivusto, kokeile uudelleen vuorokauden kuluttua." + +#: src/Module/Contact/Unfollow.php:98 src/Module/Contact/Unfollow.php:167 +msgid "You aren't following this contact." +msgstr "" + +#: src/Module/Contact/Unfollow.php:103 +msgid "Unfollowing is currently not supported by your network." +msgstr "Seuraamisen lopettaminen ei tällä hetkellä tueta verkossasi." + +#: src/Module/Contact/Unfollow.php:121 +msgid "Disconnect/Unfollow" +msgstr "Katkaise / Lopeta seuraaminen" + +#: src/Module/Contact/Unfollow.php:175 +msgid "Contact was successfully unfollowed" +msgstr "" + +#: src/Module/Contact/Unfollow.php:178 +msgid "Unable to unfollow this contact, please contact your administrator" +msgstr "" + +#: 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:87 +msgid "Local Community" +msgstr "Paikallinen yhteisö" + +#: src/Module/Conversation/Community.php:90 +msgid "Posts from local users on this server" +msgstr "Tämän palvelimen julkaisut" + +#: src/Module/Conversation/Community.php:98 +msgid "Global Community" +msgstr "Maailmanlaajuinen yhteisö" + +#: src/Module/Conversation/Community.php:101 +msgid "Posts from users of the whole federated network" +msgstr "Maailmanlaajuisen verkon julkaisut" + +#: src/Module/Conversation/Community.php:134 +msgid "Own Contacts" +msgstr "" + +#: src/Module/Conversation/Community.php:138 +msgid "Include" +msgstr "" + +#: src/Module/Conversation/Community.php:139 +msgid "Hide" +msgstr "" + +#: src/Module/Conversation/Community.php:156 src/Module/Search/Index.php:152 +#: src/Module/Search/Index.php:194 +msgid "No results." +msgstr "Ei tuloksia." + +#: src/Module/Conversation/Community.php:212 +msgid "Community option not available." +msgstr "Yhteisö vaihtoehto ei saatavilla." + +#: src/Module/Conversation/Community.php:228 +msgid "Not available." +msgstr "Ei saatavilla." + +#: src/Module/Conversation/Network.php:175 +msgid "No such circle" +msgstr "" + +#: src/Module/Conversation/Network.php:179 +#, php-format +msgid "Circle: %s" +msgstr "" + +#: src/Module/Conversation/Network.php:257 +msgid "Latest Activity" +msgstr "" + +#: src/Module/Conversation/Network.php:260 +msgid "Sort by latest activity" +msgstr "" + +#: src/Module/Conversation/Network.php:265 +msgid "Latest Posts" +msgstr "" + +#: src/Module/Conversation/Network.php:268 +msgid "Sort by post received date" +msgstr "" + +#: src/Module/Conversation/Network.php:273 +msgid "Latest Creation" +msgstr "" + +#: src/Module/Conversation/Network.php:276 +msgid "Sort by post creation date" +msgstr "" + +#: src/Module/Conversation/Network.php:281 +#: src/Module/Settings/Profile/Index.php:235 +msgid "Personal" +msgstr "Henkilökohtainen" + +#: src/Module/Conversation/Network.php:284 +msgid "Posts that mention or involve you" +msgstr "Julkaisut jotka liittyvät sinuun" + +#: src/Module/Conversation/Network.php:289 src/Object/Post.php:363 +msgid "Starred" +msgstr "Tähtimerkitty" + +#: src/Module/Conversation/Network.php:292 +msgid "Favourite Posts" +msgstr "Lempijulkaisut" + +#: src/Module/Credits.php:44 +msgid "Credits" +msgstr "Lopputekstit" + +#: src/Module/Credits.php:45 +msgid "" +"Friendica is a community project, that would not be possible without the " +"help of many people. Here is a list of those who have contributed to the " +"code or the translation of Friendica. Thank you all!" +msgstr "" + +#: src/Module/Debug/ActivityPubConversion.php:53 +msgid "Formatted" +msgstr "" + +#: src/Module/Debug/ActivityPubConversion.php:65 +msgid "Activity" +msgstr "" + +#: src/Module/Debug/ActivityPubConversion.php:117 +msgid "Object data" +msgstr "" + +#: src/Module/Debug/ActivityPubConversion.php:124 +msgid "Result Item" +msgstr "" + +#: src/Module/Debug/ActivityPubConversion.php:129 +#: src/Module/Debug/Babel.php:293 src/Module/Moderation/Item/Source.php:87 +#: src/Module/Security/TwoFactor/Verify.php:98 +msgid "Error" +msgid_plural "Errors" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Debug/ActivityPubConversion.php:138 +msgid "Source activity" +msgstr "" + +#: src/Module/Debug/Babel.php:51 +msgid "Source input" +msgstr "" + +#: src/Module/Debug/Babel.php:57 +msgid "BBCode::toPlaintext" +msgstr "BBCode::toPlaintext" + +#: src/Module/Debug/Babel.php:63 +msgid "BBCode::convert (raw HTML)" +msgstr "BBCode::convert (raaka HTML)" + +#: src/Module/Debug/Babel.php:68 +msgid "BBCode::convert (hex)" +msgstr "" + +#: src/Module/Debug/Babel.php:73 +msgid "BBCode::convert" +msgstr "BBCode::convert" + +#: src/Module/Debug/Babel.php:79 +msgid "BBCode::convert => HTML::toBBCode" +msgstr "BBCode::convert => HTML::toBBCode" + +#: src/Module/Debug/Babel.php:85 +msgid "BBCode::toMarkdown" +msgstr "BBCode::toMarkdown" + +#: src/Module/Debug/Babel.php:91 +msgid "BBCode::toMarkdown => Markdown::convert (raw HTML)" +msgstr "" + +#: src/Module/Debug/Babel.php:95 +msgid "BBCode::toMarkdown => Markdown::convert" +msgstr "BBCode::toMarkdown => Markdown::convert" + +#: src/Module/Debug/Babel.php:101 +msgid "BBCode::toMarkdown => Markdown::toBBCode" +msgstr "BBCode::toMarkdown => Markdown::toBBCode" + +#: src/Module/Debug/Babel.php:107 +msgid "BBCode::toMarkdown => Markdown::convert => HTML::toBBCode" +msgstr "BBCode::toMarkdown => Markdown::convert => HTML::toBBCode" + +#: src/Module/Debug/Babel.php:115 +msgid "Item Body" +msgstr "" + +#: src/Module/Debug/Babel.php:119 +msgid "Item Tags" +msgstr "" + +#: src/Module/Debug/Babel.php:125 +msgid "PageInfo::appendToBody" +msgstr "" + +#: src/Module/Debug/Babel.php:130 +msgid "PageInfo::appendToBody => BBCode::convert (raw HTML)" +msgstr "" + +#: src/Module/Debug/Babel.php:134 +msgid "PageInfo::appendToBody => BBCode::convert" +msgstr "" + +#: src/Module/Debug/Babel.php:141 +msgid "Source input (Diaspora format)" +msgstr "" + +#: src/Module/Debug/Babel.php:150 +msgid "Source input (Markdown)" +msgstr "" + +#: src/Module/Debug/Babel.php:156 +msgid "Markdown::convert (raw HTML)" +msgstr "" + +#: src/Module/Debug/Babel.php:161 +msgid "Markdown::convert" +msgstr "" + +#: src/Module/Debug/Babel.php:167 +msgid "Markdown::toBBCode" +msgstr "Markdown::toBBCode" + +#: src/Module/Debug/Babel.php:174 +msgid "Raw HTML input" +msgstr "Raaka HTML-syöte" + +#: src/Module/Debug/Babel.php:179 +msgid "HTML Input" +msgstr "HTML-syöte" + +#: src/Module/Debug/Babel.php:186 +msgid "HTML Purified (raw)" +msgstr "" + +#: src/Module/Debug/Babel.php:191 +msgid "HTML Purified (hex)" +msgstr "" + +#: src/Module/Debug/Babel.php:196 +msgid "HTML Purified" +msgstr "" + +#: src/Module/Debug/Babel.php:202 +msgid "HTML::toBBCode" +msgstr "HTML::toBBCode" + +#: src/Module/Debug/Babel.php:208 +msgid "HTML::toBBCode => BBCode::convert" +msgstr "" + +#: src/Module/Debug/Babel.php:213 +msgid "HTML::toBBCode => BBCode::convert (raw HTML)" +msgstr "" + +#: src/Module/Debug/Babel.php:219 +msgid "HTML::toBBCode => BBCode::toPlaintext" +msgstr "" + +#: src/Module/Debug/Babel.php:225 +msgid "HTML::toMarkdown" +msgstr "" + +#: src/Module/Debug/Babel.php:231 +msgid "HTML::toPlaintext" +msgstr "HTML::toPlaintext" + +#: src/Module/Debug/Babel.php:237 +msgid "HTML::toPlaintext (compact)" +msgstr "" + +#: src/Module/Debug/Babel.php:255 +msgid "Decoded post" +msgstr "" + +#: src/Module/Debug/Babel.php:276 +msgid "Post array before expand entities" +msgstr "" + +#: src/Module/Debug/Babel.php:283 +msgid "Post converted" +msgstr "" + +#: src/Module/Debug/Babel.php:288 +msgid "Converted body" +msgstr "" + +#: src/Module/Debug/Babel.php:294 +msgid "Twitter addon is absent from the addon/ folder." +msgstr "" + +#: src/Module/Debug/Babel.php:304 +msgid "Babel Diagnostic" +msgstr "" + +#: src/Module/Debug/Babel.php:305 +msgid "Source text" +msgstr "Lähdeteksti" + +#: src/Module/Debug/Babel.php:306 +msgid "BBCode" +msgstr "BBCode" + +#: src/Module/Debug/Babel.php:308 +msgid "Markdown" +msgstr "Markdown" + +#: src/Module/Debug/Babel.php:309 +msgid "HTML" +msgstr "HTML" + +#: src/Module/Debug/Babel.php:311 +msgid "Twitter Source / Tweet URL (requires API key)" +msgstr "" + +#: src/Module/Debug/Feed.php:52 src/Module/Filer/SaveTag.php:47 +#: src/Module/Settings/Profile/Index.php:144 +msgid "You must be logged in to use this module" +msgstr "Sinun pitää kirjautua sisään, jotta voit käyttää tätä moduulia" + +#: src/Module/Debug/Feed.php:77 +msgid "Source URL" +msgstr "Lähde URL" + +#: src/Module/Debug/Localtime.php:49 +msgid "Time Conversion" +msgstr "Aikamuunnos" + +#: src/Module/Debug/Localtime.php:50 +msgid "" +"Friendica provides this service for sharing events with other networks and " +"friends in unknown timezones." +msgstr "" + +#: src/Module/Debug/Localtime.php:51 +#, php-format +msgid "UTC time: %s" +msgstr "UTC-aika: %s" + +#: src/Module/Debug/Localtime.php:54 +#, php-format +msgid "Current timezone: %s" +msgstr "Aikavyöhyke: %s" + +#: src/Module/Debug/Localtime.php:58 +#, php-format +msgid "Converted localtime: %s" +msgstr "Muunnettu paikallisaika: %s" + +#: src/Module/Debug/Localtime.php:62 +msgid "Please select your timezone:" +msgstr "Valitse aikavyöhykkeesi:" + +#: src/Module/Debug/Probe.php:38 src/Module/Debug/WebFinger.php:37 +msgid "Only logged in users are permitted to perform a probing." +msgstr "" + +#: src/Module/Debug/Probe.php:52 +msgid "Probe Diagnostic" +msgstr "" + +#: src/Module/Debug/Probe.php:53 +msgid "Output" +msgstr "" + +#: src/Module/Debug/Probe.php:56 +msgid "Lookup address" +msgstr "" + +#: src/Module/Debug/WebFinger.php:50 +msgid "Webfinger Diagnostic" +msgstr "" + +#: src/Module/Debug/WebFinger.php:52 +msgid "Lookup address:" +msgstr "" + +#: src/Module/Delegation.php:110 +#, php-format +msgid "You are now logged in as %s" +msgstr "" + +#: src/Module/Delegation.php:142 +msgid "Switch between your accounts" +msgstr "" + +#: src/Module/Delegation.php:143 +msgid "Manage your accounts" +msgstr "" + +#: src/Module/Delegation.php:144 +msgid "" +"Toggle between different identities or community/group pages which share " +"your account details or which you have been granted \"manage\" permissions" +msgstr "" + +#: src/Module/Delegation.php:145 +msgid "Select an identity to manage: " +msgstr "Valitse identiteetti hallitavaksi:" + +#: src/Module/Directory.php:74 +msgid "No entries (some entries may be hidden)." +msgstr "" + +#: src/Module/Directory.php:90 +msgid "Find on this site" +msgstr "" + +#: src/Module/Directory.php:92 +msgid "Results for:" +msgstr "Tulokset haulla:" + +#: src/Module/Directory.php:94 +msgid "Site Directory" +msgstr "Sivuston luettelo" + +#: src/Module/Filer/RemoveTag.php:105 +msgid "Item was not deleted" +msgstr "" + +#: src/Module/Filer/RemoveTag.php:115 +msgid "Item was not removed" +msgstr "" + +#: src/Module/Filer/SaveTag.php:73 +msgid "- select -" +msgstr "- valitse -" + +#: src/Module/FriendSuggest.php:82 +msgid "Suggested contact not found." +msgstr "" + +#: src/Module/FriendSuggest.php:100 +msgid "Friend suggestion sent." +msgstr "Ystäväehdotus lähetettiin." + +#: src/Module/FriendSuggest.php:137 +msgid "Suggest Friends" +msgstr "Ehdota ystäviä" + +#: src/Module/FriendSuggest.php:140 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Ehdota ystävää ystävälle %s" + +#: src/Module/Friendica.php:64 +msgid "Installed addons/apps:" +msgstr "Asennettu lisäosat/sovellukset:" + +#: src/Module/Friendica.php:69 +msgid "No installed addons/apps" +msgstr "Ei asennettuja lisäosia/sovelluksia" + +#: src/Module/Friendica.php:74 +#, php-format +msgid "Read about the Terms of Service of this node." +msgstr "Lue tämän solmun käyttöehdot." + +#: src/Module/Friendica.php:81 +msgid "On this server the following remote servers are blocked." +msgstr "Tällä palvelimella seuraavat etäpalvelimet ovat estetty." + +#: src/Module/Friendica.php:84 +#: src/Module/Moderation/Blocklist/Server/Index.php:87 +#: src/Module/Moderation/Blocklist/Server/Index.php:111 +msgid "Reason for the block" +msgstr "Eston syy" + +#: src/Module/Friendica.php:86 +msgid "Download this list in CSV format" +msgstr "" + +#: src/Module/Friendica.php:100 +#, php-format +msgid "" +"This is Friendica, version %s that is running at the web location %s. The " +"database version is %s, the post update version is %s." +msgstr "" + +#: src/Module/Friendica.php:105 +msgid "" +"Please visit Friendi.ca to learn more " +"about the Friendica project." +msgstr "Vieraile osoitteessa Friendi.ca saadaksesi lisätietoja Friendica- projektista." + +#: src/Module/Friendica.php:106 +msgid "Bug reports and issues: please visit" +msgstr "Bugiraportit ja kysymykset: vieraile osoitteessa" + +#: src/Module/Friendica.php:106 +msgid "the bugtracker at github" +msgstr "githubin bugtrackeri" + +#: src/Module/Friendica.php:107 +msgid "Suggestions, praise, etc. - please email \"info\" at \"friendi - dot - ca" +msgstr "Ehdotukset ja palaute: lähetä sähköposti osoitteeseen \"info\" at \"friendi - piste - ca" + +#: src/Module/HCard.php:45 +msgid "No profile" +msgstr "Ei profiilia" + +#: src/Module/HTTPException/MethodNotAllowed.php:31 +msgid "Method Not Allowed." +msgstr "" + +#: src/Module/Help.php:60 +msgid "Help:" +msgstr "Ohje:" + +#: src/Module/Home.php:63 +#, php-format +msgid "Welcome to %s" +msgstr "Tervetuloa %s" + +#: src/Module/Install.php:189 +msgid "Friendica Communications Server - Setup" +msgstr "" + +#: src/Module/Install.php:200 +msgid "System check" +msgstr "Järjestelmän tarkistus" + +#: src/Module/Install.php:202 src/Module/Install.php:247 +#: src/Module/Install.php:326 +msgid "Requirement not satisfied" +msgstr "" + +#: src/Module/Install.php:203 +msgid "Optional requirement not satisfied" +msgstr "" + +#: src/Module/Install.php:204 +msgid "OK" +msgstr "" + +#: src/Module/Install.php:208 +msgid "Next" +msgstr "Seuraava" + +#: src/Module/Install.php:209 +msgid "Check again" +msgstr "Tarkista uudelleen" + +#: src/Module/Install.php:222 +msgid "Base settings" +msgstr "" + +#: src/Module/Install.php:224 +msgid "Base path to installation" +msgstr "Asennuksen peruspolku" + +#: src/Module/Install.php:226 +msgid "" +"If the system cannot detect the correct path to your installation, enter the" +" correct path here. This setting should only be set if you are using a " +"restricted system and symbolic links to your webroot." +msgstr "" + +#: src/Module/Install.php:229 +msgid "The Friendica system URL" +msgstr "" + +#: src/Module/Install.php:231 +msgid "" +"Overwrite this field in case the system URL determination isn't right, " +"otherwise leave it as is." +msgstr "" + +#: src/Module/Install.php:242 +msgid "Database connection" +msgstr "Tietokantayhteys" + +#: src/Module/Install.php:243 +msgid "" +"In order to install Friendica we need to know how to connect to your " +"database." +msgstr "Jotta voit asentaa Friendican, tarvitaan tieto siitä, miten tietokantaasi saa yhteyden." + +#: src/Module/Install.php:244 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Ota yhteyttä web-palveluntarjoajaasi tai sivuston ylläpitäjään, jos sinulla on näihin asetuksiin liittyviä kysymyksiä." + +#: src/Module/Install.php:245 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "Alla määritetyn tietokannan tulisi olla jo olemassa. Jos se ei ole, luo se ennen kuin jatkat." + +#: src/Module/Install.php:252 +msgid "Database Server Name" +msgstr "Tietokannan palvelimen nimi" + +#: src/Module/Install.php:257 +msgid "Database Login Name" +msgstr "Tietokannan käyttäjän nimi" + +#: src/Module/Install.php:263 +msgid "Database Login Password" +msgstr "Tietokannan käyttäjän salasana" + +#: src/Module/Install.php:265 +msgid "For security reasons the password must not be empty" +msgstr "Turvallisuussyistä salasanakenttä ei saa olla tyhjä" + +#: src/Module/Install.php:268 +msgid "Database Name" +msgstr "Tietokannan nimi" + +#: src/Module/Install.php:272 src/Module/Install.php:300 +msgid "Please select a default timezone for your website" +msgstr "Valitse oletusaikavyöhyke sivustollesi" + +#: src/Module/Install.php:287 +msgid "Site settings" +msgstr "Sivuston asetukset" + +#: src/Module/Install.php:295 +msgid "Site administrator email address" +msgstr "Sivuston ylläpitäjän sähköpostiosoite" + +#: src/Module/Install.php:297 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "Tilisi sähköpostiosoitteen on vastattava tätä, jotta voit käyttää ylläpitokäyttöliittymää." + +#: src/Module/Install.php:304 +msgid "System Language:" +msgstr "Järjestelmän kieli:" + +#: src/Module/Install.php:306 +msgid "" +"Set the default language for your Friendica installation interface and to " +"send emails." +msgstr "Valitse Friendica-sivustosi oletuskieli." + +#: src/Module/Install.php:318 +msgid "Your Friendica site database has been installed." +msgstr "Friendica-sivustosi tietokanta on asennettu." + +#: src/Module/Install.php:328 +msgid "Installation finished" +msgstr "" + +#: src/Module/Install.php:348 +msgid "

What next

" +msgstr "

Mitä seuraavaksi

" + +#: src/Module/Install.php:349 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"worker." +msgstr "TÄRKEÄÄ: Sinun pitää asettaa [manuaalisesti] ajastettu tehtävä Workerille." + +#: src/Module/Install.php:352 +#, php-format +msgid "" +"Go to your new Friendica node registration page " +"and register as new user. Remember to use the same email you have entered as" +" administrator email. This will allow you to enter the site admin panel." +msgstr "" + +#: src/Module/Invite.php:57 +msgid "Total invitation limit exceeded." +msgstr "Kutsuraja ylitetty." + +#: src/Module/Invite.php:82 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s : Virheellinen sähköpostiosoite." + +#: src/Module/Invite.php:108 +msgid "Please join us on Friendica" +msgstr "Tervetuloa Friendicaan" + +#: src/Module/Invite.php:117 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Kutsuraja ylitetty. Ota yhteyttä ylläpitäjään." + +#: src/Module/Invite.php:121 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : Viestin toimitus epäonnistui." + +#: src/Module/Invite.php:125 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d viesti lähetetty." +msgstr[1] "%d viestiä lähetetty." + +#: src/Module/Invite.php:143 +msgid "You have no more invitations available" +msgstr "Sinulla ei ole kutsuja jäljellä" + +#: src/Module/Invite.php:150 +#, php-format +msgid "" +"Visit %s for a list of public sites that you can join. Friendica members on " +"other sites can all connect with each other, as well as with members of many" +" other social networks." +msgstr "" + +#: src/Module/Invite.php:152 +#, php-format +msgid "" +"To accept this invitation, please visit and register at %s or any other " +"public Friendica website." +msgstr "Hyväksyäksesi tämän kutsun, rekisteröidy sivustolla %s tai millä tahansa muulla Friendica -sivustolla." + +#: src/Module/Invite.php:153 +#, php-format +msgid "" +"Friendica sites all inter-connect to create a huge privacy-enhanced social " +"web that is owned and controlled by its members. They can also connect with " +"many traditional social networks. See %s for a list of alternate Friendica " +"sites you can join." +msgstr "" + +#: src/Module/Invite.php:157 +msgid "" +"Our apologies. This system is not currently configured to connect with other" +" public sites or invite members." +msgstr "" + +#: src/Module/Invite.php:160 +msgid "" +"Friendica sites all inter-connect to create a huge privacy-enhanced social " +"web that is owned and controlled by its members. They can also connect with " +"many traditional social networks." +msgstr "" + +#: src/Module/Invite.php:159 +#, php-format +msgid "To accept this invitation, please visit and register at %s." +msgstr "Hyväksyäksesi tämän kutsun, rekisteröidy sivustolla %s." + +#: src/Module/Invite.php:167 +msgid "Send invitations" +msgstr "Lähetä kutsut" + +#: src/Module/Invite.php:168 +msgid "Enter email addresses, one per line:" +msgstr "Syötä sähköpostiosoitteet, yksi riviä kohden:" + +#: src/Module/Invite.php:172 +msgid "" +"You are cordially invited to join me and other close friends on Friendica - " +"and help us to create a better social web." +msgstr "" + +#: src/Module/Invite.php:174 +msgid "You will need to supply this invitation code: $invite_code" +msgstr "" + +#: src/Module/Invite.php:174 +msgid "" +"Once you have registered, please connect with me via my profile page at:" +msgstr "Kun olet rekisteröitynyt, lähetä minulle kaverikutsun profiilisivuni kautta:" + +#: src/Module/Invite.php:176 +msgid "" +"For more information about the Friendica project and why we feel it is " +"important, please visit http://friendi.ca" +msgstr "" + +#: src/Module/Item/Compose.php:85 +msgid "Please enter a post body." +msgstr "" + +#: src/Module/Item/Compose.php:98 +msgid "This feature is only available with the frio theme." +msgstr "" + +#: src/Module/Item/Compose.php:122 +msgid "Compose new personal note" +msgstr "" + +#: src/Module/Item/Compose.php:131 +msgid "Compose new post" +msgstr "" + +#: src/Module/Item/Compose.php:187 +msgid "Visibility" +msgstr "" + +#: src/Module/Item/Compose.php:202 +msgid "Clear the location" +msgstr "" + +#: src/Module/Item/Compose.php:203 +msgid "Location services are unavailable on your device" +msgstr "" + +#: src/Module/Item/Compose.php:204 +msgid "" +"Location services are disabled. Please check the website's permissions on " +"your device" +msgstr "" + +#: src/Module/Item/Compose.php:210 +msgid "" +"You can make this page always open when you use the New Post button in the " +"Theme Customization settings." +msgstr "" + +#: src/Module/Item/Display.php:136 src/Module/Update/Display.php:55 +msgid "The requested item doesn't exist or has been deleted." +msgstr "" + +#: src/Module/Item/Feed.php:86 +msgid "The feed for this item is unavailable." +msgstr "" + +#: src/Module/Item/Follow.php:51 +msgid "Unable to follow this item." +msgstr "" + +#: src/Module/Maintenance.php:48 src/Module/Maintenance.php:53 +msgid "System down for maintenance" +msgstr "Järjestelmä poiskytketty huoltoa varten" + +#: src/Module/Maintenance.php:54 +msgid "" +"This Friendica node is currently in maintenance mode, either automatically " +"because it is self-updating or manually by the node administrator. This " +"condition should be temporary, please come back in a few minutes." +msgstr "" + +#: src/Module/Manifest.php:40 +msgid "A Decentralized Social Network" +msgstr "" + +#: src/Module/Media/Attachment/Browser.php:58 +#: src/Module/Media/Photo/Browser.php:59 +msgid "You need to be logged in to access this page." +msgstr "" + +#: src/Module/Media/Attachment/Browser.php:74 +msgid "Files" +msgstr "Tiedostot" + +#: src/Module/Media/Attachment/Browser.php:79 +#: src/Module/Media/Photo/Browser.php:90 +#: src/Module/Settings/Profile/Photo/Index.php:128 +msgid "Upload" +msgstr "Lähetä" + +#: src/Module/Media/Attachment/Upload.php:97 +msgid "Sorry, maybe your upload is bigger than the PHP configuration allows" +msgstr "" + +#: src/Module/Media/Attachment/Upload.php:97 +msgid "Or - did you try to upload an empty file?" +msgstr "Yrititkö ladata tyhjän tiedoston?" + +#: src/Module/Media/Attachment/Upload.php:104 +#, php-format +msgid "File exceeds size limit of %s" +msgstr "Tiedosto ylittää kokorajoituksen %s" + +#: src/Module/Media/Attachment/Upload.php:114 +msgid "File upload failed." +msgstr "Tiedoston lähettäminen epäonnistui." + +#: src/Module/Media/Photo/Upload.php:152 src/Module/Media/Photo/Upload.php:153 +#: src/Module/Profile/Photos.php:217 +#: src/Module/Settings/Profile/Photo/Index.php:68 +msgid "Unable to process image." +msgstr "Kuvan käsitteleminen epäonnistui." + +#: src/Module/Media/Photo/Upload.php:178 src/Module/Profile/Photos.php:237 +#: src/Module/Settings/Profile/Photo/Index.php:95 +msgid "Image upload failed." +msgstr "Kuvan lähettäminen epäonnistui." + +#: src/Module/Moderation/BaseUsers.php:72 +msgid "List of all users" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:77 +msgid "Active" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:80 +msgid "List of active accounts" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:88 +msgid "List of pending registrations" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:96 +msgid "List of blocked users" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:101 +msgid "Deleted" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:104 +msgid "List of pending user deletions" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:119 src/Module/Settings/Account.php:491 +msgid "Normal Account Page" +msgstr "Tavallinen käyttäjätili" + +#: src/Module/Moderation/BaseUsers.php:120 src/Module/Settings/Account.php:498 +msgid "Soapbox Page" +msgstr "Saarnatuoli sivu" + +#: src/Module/Moderation/BaseUsers.php:121 src/Module/Settings/Account.php:505 +msgid "Public Group" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:122 src/Module/Settings/Account.php:512 +msgid "Automatic Friend Page" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:123 +msgid "Private Group" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:126 src/Module/Settings/Account.php:463 +msgid "Personal Page" +msgstr "Henkilökohtainen sivu" + +#: src/Module/Moderation/BaseUsers.php:127 src/Module/Settings/Account.php:470 +msgid "Organisation Page" +msgstr "Järjestön sivu" + +#: src/Module/Moderation/BaseUsers.php:128 src/Module/Settings/Account.php:477 +msgid "News Page" +msgstr "Uutissivu" + +#: src/Module/Moderation/BaseUsers.php:129 src/Module/Settings/Account.php:484 +msgid "Community Group" +msgstr "" + +#: src/Module/Moderation/BaseUsers.php:130 +msgid "Relay" +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:70 +msgid "You can't block a local contact, please block the user instead" +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:89 +#, php-format +msgid "%s contact unblocked" +msgid_plural "%s contacts unblocked" +msgstr[0] "%s kontakti poistettu estolistalta" +msgstr[1] "%s kontaktia poistettu estolistalta" + +#: src/Module/Moderation/Blocklist/Contact.php:111 +msgid "Remote Contact Blocklist" +msgstr "Etäkontakti estolista" + +#: src/Module/Moderation/Blocklist/Contact.php:112 +msgid "" +"This page allows you to prevent any message from a remote contact to reach " +"your node." +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:113 +msgid "Block Remote Contact" +msgstr "Estä etäkontakti" + +#: src/Module/Moderation/Blocklist/Contact.php:114 +#: src/Module/Moderation/Users/Active.php:135 +#: src/Module/Moderation/Users/Blocked.php:135 +#: src/Module/Moderation/Users/Index.php:149 +#: src/Module/Moderation/Users/Pending.php:98 +msgid "select all" +msgstr "valitse kaikki" + +#: src/Module/Moderation/Blocklist/Contact.php:115 +msgid "select none" +msgstr "älä valitse mitään" + +#: src/Module/Moderation/Blocklist/Contact.php:118 +msgid "No remote contact is blocked from this node." +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:120 +msgid "Blocked Remote Contacts" +msgstr "Estetty etäkontaktit" + +#: src/Module/Moderation/Blocklist/Contact.php:121 +msgid "Block New Remote Contact" +msgstr "Estä uusi etäkontakti" + +#: src/Module/Moderation/Blocklist/Contact.php:122 +msgid "Photo" +msgstr "Kuva" + +#: src/Module/Moderation/Blocklist/Contact.php:122 +msgid "Reason" +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:130 +#, php-format +msgid "%s total blocked contact" +msgid_plural "%s total blocked contacts" +msgstr[0] "Yhteensä %s estetty kontakti" +msgstr[1] "Yhteensä %s estettyjä kontakteja" + +#: src/Module/Moderation/Blocklist/Contact.php:133 +msgid "URL of the remote contact to block." +msgstr "Estettävän etäkontaktin URL-osoite" + +#: src/Module/Moderation/Blocklist/Contact.php:134 +msgid "Also purge contact" +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:134 +msgid "" +"Removes all content related to this contact from the node. Keeps the contact" +" record. This action cannot be undone." +msgstr "" + +#: src/Module/Moderation/Blocklist/Contact.php:135 +#: src/Module/Moderation/Blocklist/Server/Import.php:124 +msgid "Block Reason" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:80 +msgid "Server domain pattern added to the blocklist." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:88 +#, php-format +msgid "%s server scheduled to be purged." +msgid_plural "%s servers scheduled to be purged." +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:120 +#: src/Module/Moderation/Blocklist/Server/Import.php:117 +msgid "← Return to the list" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:122 +msgid "Block A New Server Domain Pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:123 +#: src/Module/Moderation/Blocklist/Server/Index.php:99 +msgid "" +"

The server domain pattern syntax is case-insensitive shell wildcard, comprising the following special characters:

\n" +"
    \n" +"\t
  • *: Any number of characters
  • \n" +"\t
  • ?: Any single character
  • \n" +"
" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:128 +#: src/Module/Moderation/Blocklist/Server/Index.php:107 +msgid "Check pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:129 +msgid "Matching known servers" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:130 +msgid "Server Name" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:131 +msgid "Server Domain" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:132 +msgid "Known Contacts" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:133 +#, php-format +msgid "%d known server" +msgid_plural "%d known servers" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:134 +msgid "Add pattern to the blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 +msgid "Server Domain Pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:136 +#: src/Module/Moderation/Blocklist/Server/Index.php:116 +msgid "" +"The domain pattern of the new server to add to the blocklist. Do not include" +" the protocol." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:137 +msgid "Purge server" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:137 +msgid "" +"Also purges all the locally stored content authored by the known contacts " +"registered on that server. Keeps the contacts and the server records. This " +"action cannot be undone." +msgid_plural "" +"Also purges all the locally stored content authored by the known contacts " +"registered on these servers. Keeps the contacts and the servers records. " +"This action cannot be undone." +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Blocklist/Server/Add.php:138 +msgid "Block reason" +msgstr "Estosyy" + +#: src/Module/Moderation/Blocklist/Server/Add.php:138 +msgid "" +"The reason why you blocked this server domain pattern. This reason will be " +"shown publicly in the server information page." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:74 +#: src/Module/Moderation/Blocklist/Server/Import.php:83 +msgid "Error importing pattern file" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:89 +msgid "Local blocklist replaced with the provided file." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:93 +#, php-format +msgid "%d pattern was added to the local blocklist." +msgid_plural "%d patterns were added to the local blocklist." +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:95 +msgid "No pattern was added to the local blocklist." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:119 +msgid "Import a Server Domain Pattern Blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:120 +msgid "" +"

This file can be downloaded from the /friendica path of any " +"Friendica server.

" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:121 +#: src/Module/Moderation/Blocklist/Server/Index.php:106 +msgid "Upload file" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:122 +msgid "Patterns to import" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:123 +msgid "Domain Pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:125 +msgid "Import Mode" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:126 +msgid "Import Patterns" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:127 +#, php-format +msgid "%d total pattern" +msgid_plural "%d total patterns" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:129 +#: src/Module/Moderation/Blocklist/Server/Index.php:115 +msgid "Server domain pattern blocklist CSV file" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:130 +msgid "Append" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:130 +msgid "" +"Imports patterns from the file that weren't already existing in the current " +"blocklist." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:131 +msgid "Replace" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Import.php:131 +msgid "Replaces the current blocklist by the imported patterns." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:86 +#: src/Module/Moderation/Blocklist/Server/Index.php:110 +msgid "Blocked server domain pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:88 +msgid "Delete server domain pattern" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:88 +msgid "Check to delete this entry from the blocklist" +msgstr "Laita rasti poistaaksesi kohde estolistalta" + +#: src/Module/Moderation/Blocklist/Server/Index.php:96 +msgid "Server Domain Pattern Blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:97 +msgid "" +"This page can be used to define a blocklist of server domain patterns from " +"the federated network that are not allowed to interact with your node. For " +"each domain pattern you should also provide the reason why you block it." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:98 +msgid "" +"The list of blocked server domain patterns will be made publically available" +" on the /friendica page so that your users and " +"people investigating communication problems can find the reason easily." +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:104 +msgid "Import server domain pattern blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:105 +msgid "Add new entry to the blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:108 +msgid "Save changes to the blocklist" +msgstr "Tallenna muutoksia estolistaan" + +#: src/Module/Moderation/Blocklist/Server/Index.php:109 +msgid "Current Entries in the Blocklist" +msgstr "Nykyinen estolista" + +#: src/Module/Moderation/Blocklist/Server/Index.php:112 +msgid "Delete entry from the blocklist" +msgstr "" + +#: src/Module/Moderation/Blocklist/Server/Index.php:113 +msgid "Delete entry from the blocklist?" +msgstr "" + +#: src/Module/Moderation/Item/Delete.php:50 +msgid "Item marked for deletion." +msgstr "Kohde merkitty poistettavaksi." + +#: src/Module/Moderation/Item/Delete.php:63 +msgid "Delete this Item" +msgstr "Poista tämä kohde" + +#: src/Module/Moderation/Item/Delete.php:64 +msgid "" +"On this page you can delete an item from your node. If the item is a top " +"level posting, the entire thread will be deleted." +msgstr "" + +#: src/Module/Moderation/Item/Delete.php:65 +msgid "" +"You need to know the GUID of the item. You can find it e.g. by looking at " +"the display URL. The last part of http://example.com/display/123456 is the " +"GUID, here 123456." +msgstr "" + +#: src/Module/Moderation/Item/Delete.php:67 +msgid "GUID" +msgstr "GUID" + +#: src/Module/Moderation/Item/Delete.php:67 +msgid "The GUID of the item you want to delete." +msgstr "Poistettavan kohteen GUID." + +#: src/Module/Moderation/Item/Source.php:77 +msgid "Item Id" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:78 +msgid "Item URI" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:80 +msgid "Terms" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:81 +msgid "Tag" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:82 +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Index.php:140 +msgid "Type" +msgstr "Tyyppi" + +#: src/Module/Moderation/Item/Source.php:83 +msgid "Term" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:84 +msgid "URL" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:85 +msgid "Mention" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:86 +msgid "Implicit Mention" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:88 +msgid "Item not found" +msgstr "Kohdetta ei löytynyt" + +#: src/Module/Moderation/Item/Source.php:89 +msgid "No source recorded" +msgstr "" + +#: src/Module/Moderation/Item/Source.php:90 +msgid "" +"Please make sure the debug.store_source config key is set in " +"config/local.config.php for future items to have sources." +msgstr "" + +#: src/Module/Moderation/Item/Source.php:92 +msgid "Item Guid" +msgstr "" + +#: src/Module/Moderation/Summary.php:53 +msgid "Normal Account" +msgstr "Perustili" + +#: src/Module/Moderation/Summary.php:54 +msgid "Automatic Follower Account" +msgstr "Automaattinen seuraajatili" + +#: src/Module/Moderation/Summary.php:55 +msgid "Public Group Account" +msgstr "" + +#: src/Module/Moderation/Summary.php:56 +msgid "Automatic Friend Account" +msgstr "Automaattinen kaveritili" + +#: src/Module/Moderation/Summary.php:57 +msgid "Blog Account" +msgstr "Blogitili" + +#: src/Module/Moderation/Summary.php:58 +msgid "Private Group Account" +msgstr "" + +#: src/Module/Moderation/Summary.php:78 +msgid "Registered users" +msgstr "Rekisteröityneet käyttäjät" + +#: src/Module/Moderation/Summary.php:80 +msgid "Pending registrations" +msgstr "Vireillä olevat rekisteröinnit" + +#: src/Module/Moderation/Users/Active.php:43 +#: src/Module/Moderation/Users/Index.php:43 +#, php-format +msgid "%s user blocked" +msgid_plural "%s users blocked" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Users/Active.php:51 +#: src/Module/Moderation/Users/Active.php:85 +#: src/Module/Moderation/Users/Blocked.php:51 +#: src/Module/Moderation/Users/Blocked.php:85 +#: src/Module/Moderation/Users/Index.php:58 +#: src/Module/Moderation/Users/Index.php:92 +msgid "You can't remove yourself" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:55 +#: src/Module/Moderation/Users/Blocked.php:55 +#: src/Module/Moderation/Users/Index.php:62 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s käyttäjä poistettu" +msgstr[1] "%s käyttäjää poistettu" + +#: src/Module/Moderation/Users/Active.php:83 +#: src/Module/Moderation/Users/Blocked.php:83 +#: src/Module/Moderation/Users/Index.php:90 +#, php-format +msgid "User \"%s\" deleted" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:93 +#: src/Module/Moderation/Users/Index.php:100 +#, php-format +msgid "User \"%s\" blocked" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:140 +#: src/Module/Moderation/Users/Index.php:160 +msgid "Register date" +msgstr "Rekisteripäivämäärä" + +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:140 +#: src/Module/Moderation/Users/Index.php:160 +msgid "Last login" +msgstr "Viimeisin kirjautuminen" + +#: src/Module/Moderation/Users/Active.php:126 +#: src/Module/Moderation/Users/Blocked.php:126 +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:140 +#: src/Module/Moderation/Users/Index.php:160 +msgid "Last public item" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:134 +msgid "Active Accounts" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:138 +#: src/Module/Moderation/Users/Blocked.php:137 +#: src/Module/Moderation/Users/Index.php:153 +msgid "User blocked" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:139 +#: src/Module/Moderation/Users/Blocked.php:139 +#: src/Module/Moderation/Users/Index.php:155 +msgid "Site admin" +msgstr "Sivuston ylläpito" + +#: src/Module/Moderation/Users/Active.php:140 +#: src/Module/Moderation/Users/Blocked.php:140 +#: src/Module/Moderation/Users/Index.php:156 +msgid "Account expired" +msgstr "Tili vanhentunut" + +#: src/Module/Moderation/Users/Active.php:141 +#: src/Module/Moderation/Users/Index.php:159 +msgid "Create a new user" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:147 +#: src/Module/Moderation/Users/Blocked.php:146 +#: src/Module/Moderation/Users/Index.php:165 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: src/Module/Moderation/Users/Active.php:148 +#: src/Module/Moderation/Users/Blocked.php:147 +#: src/Module/Moderation/Users/Index.php:166 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: src/Module/Moderation/Users/Blocked.php:43 +#: src/Module/Moderation/Users/Index.php:50 +#, php-format +msgid "%s user unblocked" +msgid_plural "%s users unblocked" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Users/Blocked.php:92 +#: src/Module/Moderation/Users/Index.php:106 +#, php-format +msgid "User \"%s\" unblocked" +msgstr "" + +#: src/Module/Moderation/Users/Blocked.php:134 +msgid "Blocked Users" +msgstr "" + +#: src/Module/Moderation/Users/Create.php:62 +msgid "New User" +msgstr "Uusi käyttäjä" + +#: src/Module/Moderation/Users/Create.php:63 +msgid "Add User" +msgstr "Lisää käyttäjä" + +#: src/Module/Moderation/Users/Create.php:70 +msgid "Name of the new user." +msgstr "Uuden käyttäjän nimi." + +#: src/Module/Moderation/Users/Create.php:71 +msgid "Nickname" +msgstr "Lempinimi" + +#: src/Module/Moderation/Users/Create.php:71 +msgid "Nickname of the new user." +msgstr "Uuden käyttäjän lempinimi" + +#: src/Module/Moderation/Users/Create.php:72 +msgid "Email address of the new user." +msgstr "Uuden käyttäjän sähköpostiosoite." + +#: src/Module/Moderation/Users/Deleted.php:81 +msgid "Users awaiting permanent deletion" +msgstr "" + +#: src/Module/Moderation/Users/Deleted.php:83 +#: src/Module/Moderation/Users/Index.php:160 +msgid "Permanent deletion" +msgstr "" + +#: src/Module/Moderation/Users/Index.php:150 +msgid "User waiting for permanent deletion" +msgstr "" + +#: src/Module/Moderation/Users/Pending.php:44 +#, php-format +msgid "%s user approved" +msgid_plural "%s users approved" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Users/Pending.php:51 +#, php-format +msgid "%s registration revoked" +msgid_plural "%s registrations revoked" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Moderation/Users/Pending.php:76 +msgid "Account approved." +msgstr "Tili hyväksytty." + +#: src/Module/Moderation/Users/Pending.php:82 +msgid "Registration revoked" +msgstr "" + +#: src/Module/Moderation/Users/Pending.php:97 +msgid "User registrations awaiting review" +msgstr "" + +#: src/Module/Moderation/Users/Pending.php:99 +msgid "Request date" +msgstr "Pyynnön päivämäärä" + +#: src/Module/Moderation/Users/Pending.php:100 +msgid "No registrations." +msgstr "Ei rekisteröintejä." + +#: src/Module/Moderation/Users/Pending.php:101 +msgid "Note from the user" +msgstr "" + +#: src/Module/Moderation/Users/Pending.php:103 +msgid "Deny" +msgstr "Kieltäydy" + +#: src/Module/Notifications/Introductions.php:99 +msgid "Show Ignored Requests" +msgstr "Näytä ohitetut pyynnöt" + +#: src/Module/Notifications/Introductions.php:99 +msgid "Hide Ignored Requests" +msgstr "Piilota ohitetut pyynnöt" + +#: src/Module/Notifications/Introductions.php:115 +#: src/Module/Notifications/Introductions.php:178 +msgid "Notification type:" +msgstr "" + +#: src/Module/Notifications/Introductions.php:118 +msgid "Suggested by:" +msgstr "" + +#: src/Module/Notifications/Introductions.php:143 +msgid "Claims to be known to you: " +msgstr "Väittää tuntevansa sinut:" + +#: src/Module/Notifications/Introductions.php:144 +#: src/Module/OAuth/Acknowledge.php:55 src/Module/Register.php:131 +#: src/Module/Settings/TwoFactor/Trusted.php:126 +msgid "No" +msgstr "Ei" + +#: src/Module/Notifications/Introductions.php:152 +msgid "Shall your connection be bidirectional or not?" +msgstr "Kaksisuuntainen yhteys?" + +#: src/Module/Notifications/Introductions.php:153 +#, php-format +msgid "" +"Accepting %s as a friend allows %s to subscribe to your posts, and you will " +"also receive updates from them in your news feed." +msgstr "" + +#: src/Module/Notifications/Introductions.php:154 +#, php-format +msgid "" +"Accepting %s as a subscriber allows them to subscribe to your posts, but you" +" will not receive updates from them in your news feed." +msgstr "" + +#: src/Module/Notifications/Introductions.php:156 +msgid "Friend" +msgstr "Kaveri" + +#: src/Module/Notifications/Introductions.php:157 +msgid "Subscriber" +msgstr "Tilaaja" + +#: src/Module/Notifications/Introductions.php:216 +msgid "No introductions." +msgstr "Ei esittelyjä." + +#: src/Module/Notifications/Introductions.php:217 +#: src/Module/Notifications/Notifications.php:135 +#, php-format +msgid "No more %s notifications." +msgstr "Ei muita %s ilmoituksia." + +#: src/Module/Notifications/Notification.php:135 +msgid "You must be logged in to show this page." +msgstr "" + +#: src/Module/Notifications/Notifications.php:66 +msgid "Network Notifications" +msgstr "Uutisvirtailmoitukset" + +#: src/Module/Notifications/Notifications.php:72 +msgid "System Notifications" +msgstr "Järjestelmäilmoitukset" + +#: src/Module/Notifications/Notifications.php:78 +msgid "Personal Notifications" +msgstr "Henkilökohtaiset ilmoitukset" + +#: src/Module/Notifications/Notifications.php:84 +msgid "Home Notifications" +msgstr "Koti-ilmoitukset" + +#: src/Module/Notifications/Notifications.php:140 +msgid "Show unread" +msgstr "Näytä lukemattomat" + +#: src/Module/Notifications/Ping.php:245 +msgid "{0} requested registration" +msgstr "{0} jätti rekisteröintipyynnön" + +#: src/Module/Notifications/Ping.php:254 +#, php-format +msgid "{0} and %d others requested registration" +msgstr "" + +#: src/Module/OAuth/Acknowledge.php:51 +msgid "Authorize application connection" +msgstr "Vahvista sovellusyhteys" + +#: src/Module/OAuth/Acknowledge.php:53 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Haluatko antaa tälle sovellukselle luvan hakea viestejäsi ja yhteystietojasi ja/tai luoda uusia viestejä?" + +#: src/Module/OAuth/Authorize.php:54 +msgid "Unsupported or missing response type" +msgstr "" + +#: src/Module/OAuth/Authorize.php:59 src/Module/OAuth/Token.php:77 +msgid "Incomplete request data" +msgstr "" + +#: src/Module/OAuth/Authorize.php:106 +#, php-format +msgid "" +"Please copy the following authentication code into your application and " +"close this window: %s" +msgstr "" + +#: src/Module/OAuth/Token.php:82 +msgid "Invalid data or unknown client" +msgstr "" + +#: src/Module/OAuth/Token.php:104 +msgid "Unsupported or missing grant type" +msgstr "" + +#: src/Module/OStatus/Repair.php:83 +msgid "Resubscribing to OStatus contacts" +msgstr "OStatus -kontaktien uudelleentilaus" + +#: src/Module/OStatus/Repair.php:84 src/Module/OStatus/Subscribe.php:158 +msgid "Keep this window open until done." +msgstr "Pidä tämä ikkuna auki kunnes kaikki tehtävät on suoritettu." + +#: src/Module/OStatus/Repair.php:85 +msgid "✔ Done" +msgstr "" + +#: src/Module/OStatus/Repair.php:86 +msgid "No OStatus contacts to resubscribe to." +msgstr "" + +#: src/Module/OStatus/Subscribe.php:70 +msgid "Subscribing to contacts" +msgstr "" + +#: src/Module/OStatus/Subscribe.php:79 +msgid "No contact provided." +msgstr "Kontakti puuttuu." + +#: src/Module/OStatus/Subscribe.php:85 +msgid "Couldn't fetch information for contact." +msgstr "Kontaktin tietoja ei voitu hakea." + +#: src/Module/OStatus/Subscribe.php:96 +msgid "Couldn't fetch friends for contact." +msgstr "Ei voitu hakea kontaktin kaverit." + +#: src/Module/OStatus/Subscribe.php:102 src/Module/OStatus/Subscribe.php:113 +msgid "Couldn't fetch following contacts." +msgstr "" + +#: src/Module/OStatus/Subscribe.php:108 +msgid "Couldn't fetch remote profile." +msgstr "" + +#: src/Module/OStatus/Subscribe.php:118 +msgid "Unsupported network" +msgstr "" + +#: src/Module/OStatus/Subscribe.php:134 +msgid "Done" +msgstr "Valmis" + +#: src/Module/OStatus/Subscribe.php:148 +msgid "success" +msgstr "onnistui" + +#: src/Module/OStatus/Subscribe.php:150 +msgid "failed" +msgstr "epäonnistui" + +#: src/Module/OStatus/Subscribe.php:153 +msgid "ignored" +msgstr "ohitettu" + +#: src/Module/PermissionTooltip.php:49 +#, php-format +msgid "Wrong type \"%s\", expected one of: %s" +msgstr "" + +#: src/Module/PermissionTooltip.php:79 +msgid "Model not found" +msgstr "" + +#: src/Module/PermissionTooltip.php:94 +msgid "Unlisted" +msgstr "" + +#: src/Module/PermissionTooltip.php:112 +msgid "Remote privacy information not available." +msgstr "Yksityisyyden etätietoja ei saatavilla." + +#: src/Module/PermissionTooltip.php:121 +msgid "Visible to:" +msgstr "Näkyvissä:" + +#: src/Module/PermissionTooltip.php:204 +#, php-format +msgid "Collection (%s)" +msgstr "" + +#: src/Module/PermissionTooltip.php:208 +#, php-format +msgid "Followers (%s)" +msgstr "" + +#: src/Module/PermissionTooltip.php:227 +#, php-format +msgid "%d more" +msgstr "" + +#: src/Module/PermissionTooltip.php:231 +#, php-format +msgid "To: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:234 +#, php-format +msgid "CC: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:237 +#, php-format +msgid "BCC: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:240 +#, php-format +msgid "Audience: %s
" +msgstr "" + +#: src/Module/PermissionTooltip.php:243 +#, php-format +msgid "Attributed To: %s
" +msgstr "" + +#: src/Module/Photo.php:129 +msgid "The Photo is not available." +msgstr "" + +#: src/Module/Photo.php:154 +#, php-format +msgid "The Photo with id %s is not available." +msgstr "" + +#: src/Module/Photo.php:191 +#, php-format +msgid "Invalid external resource with url %s." +msgstr "" + +#: src/Module/Photo.php:193 +#, php-format +msgid "Invalid photo with id %s." +msgstr "" + +#: src/Module/Post/Edit.php:82 src/Module/Post/Edit.php:96 +msgid "Post not found." +msgstr "" + +#: src/Module/Post/Edit.php:102 +msgid "Edit post" +msgstr "Muokkaa viestiä" + +#: src/Module/Post/Edit.php:136 +msgid "web link" +msgstr "WWW-linkki" + +#: src/Module/Post/Edit.php:137 +msgid "Insert video link" +msgstr "Lisää videolinkki" + +#: src/Module/Post/Edit.php:138 +msgid "video link" +msgstr "videolinkki" + +#: src/Module/Post/Edit.php:139 +msgid "Insert audio link" +msgstr "Lisää äänilinkki" + +#: src/Module/Post/Edit.php:140 +msgid "audio link" +msgstr "äänilinkki" + +#: src/Module/Post/Tag/Remove.php:106 +msgid "Remove Item Tag" +msgstr "Poista tägi" + +#: src/Module/Post/Tag/Remove.php:107 +msgid "Select a tag to remove: " +msgstr "Valitse tägi poistamista varten:" + +#: src/Module/Post/Tag/Remove.php:108 src/Module/Settings/Delegation.php:180 +#: src/Module/Settings/TwoFactor/Trusted.php:144 +msgid "Remove" +msgstr "Poista" + +#: src/Module/Profile/Contacts.php:159 +msgid "No contacts." +msgstr "Ei kontakteja." + +#: src/Module/Profile/Conversations.php:106 +#: src/Module/Profile/Conversations.php:109 src/Module/Profile/Profile.php:351 +#: src/Module/Profile/Profile.php:354 src/Protocol/Feed.php:1090 +#: src/Protocol/OStatus.php:1007 +#, php-format +msgid "%s's timeline" +msgstr "%s: aikajana" + +#: src/Module/Profile/Conversations.php:107 src/Module/Profile/Profile.php:352 +#: src/Protocol/Feed.php:1094 src/Protocol/OStatus.php:1012 +#, php-format +msgid "%s's posts" +msgstr "%s: julkaisut" + +#: src/Module/Profile/Conversations.php:108 src/Module/Profile/Profile.php:353 +#: src/Protocol/Feed.php:1097 src/Protocol/OStatus.php:1016 +#, php-format +msgid "%s's comments" +msgstr "%s: kommentit" + +#: src/Module/Profile/Photos.php:164 src/Module/Profile/Photos.php:167 +#: src/Module/Profile/Photos.php:194 +#: src/Module/Settings/Profile/Photo/Index.php:59 +#, php-format +msgid "Image exceeds size limit of %s" +msgstr "Kuva ylittää kokorajoituksen %s" + +#: src/Module/Profile/Photos.php:170 +msgid "Image upload didn't complete, please try again" +msgstr "Kuvan lataus ei onnistunut, yritä uudelleen" + +#: src/Module/Profile/Photos.php:173 +msgid "Image file is missing" +msgstr "Kuvatiedosto puuttuu" + +#: src/Module/Profile/Photos.php:178 +msgid "" +"Server can't accept new file upload at this time, please contact your " +"administrator" +msgstr "" + +#: src/Module/Profile/Photos.php:202 +msgid "Image file is empty." +msgstr "Kuvatiedosto on tyhjä." + +#: src/Module/Profile/Photos.php:356 +msgid "View Album" +msgstr "Näytä albumi" + +#: src/Module/Profile/Profile.php:112 src/Module/Profile/Restricted.php:50 +msgid "Profile not found." +msgstr "Profiilia ei löytynyt." + +#: src/Module/Profile/Profile.php:158 +#, php-format +msgid "" +"You're currently viewing your profile as %s Cancel" +msgstr "" + +#: src/Module/Profile/Profile.php:167 src/Module/Settings/Account.php:575 +msgid "Full Name:" +msgstr "Koko nimi:" + +#: src/Module/Profile/Profile.php:172 +msgid "Member since:" +msgstr "Liittymispäivämäärä:" + +#: src/Module/Profile/Profile.php:178 +msgid "j F, Y" +msgstr "j F, Y" + +#: src/Module/Profile/Profile.php:179 +msgid "j F" +msgstr "j F" + +#: src/Module/Profile/Profile.php:187 src/Util/Temporal.php:168 +msgid "Birthday:" +msgstr "Syntymäpäivä:" + +#: src/Module/Profile/Profile.php:190 +#: src/Module/Settings/Profile/Index.php:253 src/Util/Temporal.php:170 +msgid "Age: " +msgstr "Ikä:" + +#: src/Module/Profile/Profile.php:190 +#: src/Module/Settings/Profile/Index.php:253 src/Util/Temporal.php:170 +#, php-format +msgid "%d year old" +msgid_plural "%d years old" +msgstr[0] "" +msgstr[1] "" + +#: src/Module/Profile/Profile.php:195 +#: src/Module/Settings/Profile/Index.php:246 +msgid "Description:" +msgstr "Kuvaus:" + +#: src/Module/Profile/Profile.php:261 +msgid "Groups:" +msgstr "" + +#: src/Module/Profile/Profile.php:273 +msgid "View profile as:" +msgstr "" + +#: src/Module/Profile/Profile.php:290 +msgid "View as" +msgstr "" + +#: src/Module/Profile/RemoteFollow.php:82 +msgid "Profile unavailable." +msgstr "Profiili ei saatavilla." + +#: src/Module/Profile/RemoteFollow.php:88 +msgid "Invalid locator" +msgstr "Viallinen paikannin" + +#: src/Module/Profile/RemoteFollow.php:95 +msgid "The provided profile link doesn't seem to be valid" +msgstr "" + +#: src/Module/Profile/RemoteFollow.php:100 +msgid "" +"Remote subscription can't be done for your network. Please subscribe " +"directly on your system." +msgstr "" + +#: src/Module/Profile/RemoteFollow.php:128 +msgid "Friend/Connection Request" +msgstr "Ystävä/yhteyspyyntö" + +#: src/Module/Profile/RemoteFollow.php:129 +#, php-format +msgid "" +"Enter your Webfinger address (user@domain.tld) or profile URL here. If this " +"isn't supported by your system, you have to subscribe to %s" +" or %s directly on your system." +msgstr "" + +#: src/Module/Profile/RemoteFollow.php:130 +#, php-format +msgid "" +"If you are not yet a member of the free social web, follow " +"this link to find a public Friendica node and join us today." +msgstr "" + +#: src/Module/Profile/RemoteFollow.php:131 +msgid "Your Webfinger address or profile URL:" +msgstr "" + +#: src/Module/Profile/Restricted.php:59 +msgid "Restricted profile" +msgstr "" + +#: src/Module/Profile/Restricted.php:60 +msgid "" +"This profile has been restricted which prevents access to their public " +"content from anonymous visitors." +msgstr "" + +#: src/Module/Profile/Schedule.php:83 +msgid "Scheduled" +msgstr "" + +#: src/Module/Profile/Schedule.php:84 +msgid "Content" +msgstr "" + +#: src/Module/Profile/Schedule.php:85 +msgid "Remove post" +msgstr "" + +#: src/Module/Profile/UnkMail.php:78 +msgid "Empty message body." +msgstr "" + +#: src/Module/Profile/UnkMail.php:103 +msgid "Unable to check your home location." +msgstr "Kotisijaintisi ei voitu tarkistaa." + +#: src/Module/Profile/UnkMail.php:127 +msgid "Recipient not found." +msgstr "" + +#: src/Module/Profile/UnkMail.php:138 +#, php-format +msgid "Number of daily wall messages for %s exceeded. Message failed." +msgstr "%s-käyttäjän päivittäinen seinäviestiraja ylitetty. Viestin lähettäminen epäonnistui." + +#: src/Module/Profile/UnkMail.php:152 +#, php-format +msgid "" +"If you wish for %s to respond, please check that the privacy settings on " +"your site allow private mail from unknown senders." +msgstr "" + +#: src/Module/Profile/UnkMail.php:160 +msgid "To" +msgstr "" + +#: src/Module/Profile/UnkMail.php:161 +msgid "Subject" +msgstr "" + +#: src/Module/Profile/UnkMail.php:162 +msgid "Your message" +msgstr "" + +#: src/Module/Register.php:84 +msgid "Only parent users can create additional accounts." +msgstr "" + +#: src/Module/Register.php:99 src/Module/User/Import.php:111 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "Sivuston päivittäinen rekisteröintiraja ylitetty. Yritä uudelleen huomenna." + +#: src/Module/Register.php:116 +msgid "" +"You may (optionally) fill in this form via OpenID by supplying your OpenID " +"and clicking \"Register\"." +msgstr "" + +#: src/Module/Register.php:117 +msgid "" +"If you are not familiar with OpenID, please leave that field blank and fill " +"in the rest of the items." +msgstr "Jos OpenID ei ole tuttu, jätä kenttä tyhjäksi." + +#: src/Module/Register.php:118 +msgid "Your OpenID (optional): " +msgstr "OpenID -tunnus (valinnainen):" + +#: src/Module/Register.php:127 +msgid "Include your profile in member directory?" +msgstr "Lisää profiilisi jäsenluetteloon?" + +#: src/Module/Register.php:148 +msgid "Note for the admin" +msgstr "Viesti ylläpidolle" + +#: src/Module/Register.php:148 +msgid "Leave a message for the admin, why you want to join this node" +msgstr "Kerro yllåpitäjälle miksi haluat liittyä tähän Friendica -sivustoon" + +#: src/Module/Register.php:149 +msgid "Membership on this site is by invitation only." +msgstr "Tähän sivustoon voi liittyä vain kutsusta." + +#: src/Module/Register.php:150 +msgid "Your invitation code: " +msgstr "Kutsukoodisi:" + +#: src/Module/Register.php:158 +msgid "Your Full Name (e.g. Joe Smith, real or real-looking): " +msgstr "Koko nimi (esim. Matti Meikäläinen, Aku Ankka):" + +#: src/Module/Register.php:159 +msgid "" +"Your Email Address: (Initial information will be send there, so this has to " +"be an existing address.)" +msgstr "Sähköpostiosoite: (pitää olla toimiva osoite että rekisteröityminen onnistuu)" + +#: src/Module/Register.php:160 +msgid "Please repeat your e-mail address:" +msgstr "" + +#: src/Module/Register.php:162 src/Module/Security/PasswordTooLong.php:100 +#: src/Module/Settings/Account.php:566 +msgid "New Password:" +msgstr "Uusi salasana:" + +#: src/Module/Register.php:162 +msgid "Leave empty for an auto generated password." +msgstr "Jätä tyhjäksi jos haluat automaattisesti luotu salasanan." + +#: src/Module/Register.php:163 src/Module/Security/PasswordTooLong.php:101 +#: src/Module/Settings/Account.php:567 +msgid "Confirm:" +msgstr "Vahvista:" + +#: src/Module/Register.php:164 +#, php-format +msgid "" +"Choose a profile nickname. This must begin with a text character. Your " +"profile address on this site will then be \"nickname@%s\"." +msgstr "" + +#: src/Module/Register.php:165 +msgid "Choose a nickname: " +msgstr "Valitse lempinimi:" + +#: src/Module/Register.php:173 src/Module/User/Import.php:117 +msgid "Import" +msgstr "Tuo" + +#: src/Module/Register.php:174 +msgid "Import your profile to this friendica instance" +msgstr "Tuo profiilisi tähän Friendica -instanssiin." + +#: src/Module/Register.php:181 +msgid "Note: This node explicitly contains adult content" +msgstr "" + +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 +msgid "Parent Password:" +msgstr "" + +#: src/Module/Register.php:183 src/Module/Settings/Delegation.php:156 +msgid "" +"Please enter the password of the parent account to legitimize your request." +msgstr "" + +#: src/Module/Register.php:212 +msgid "Password doesn't match." +msgstr "" + +#: src/Module/Register.php:218 +msgid "Please enter your password." +msgstr "" + +#: src/Module/Register.php:260 +msgid "You have entered too much information." +msgstr "" + +#: src/Module/Register.php:283 +msgid "Please enter the identical mail address in the second field." +msgstr "" + +#: src/Module/Register.php:310 +msgid "The additional account was created." +msgstr "" + +#: src/Module/Register.php:335 +msgid "" +"Registration successful. Please check your email for further instructions." +msgstr "Rekisteröityminen onnistui. Saat kohta lisäohjeita sähköpostitse." + +#: src/Module/Register.php:342 +#, php-format +msgid "" +"Failed to send email message. Here your accout details:
login: %s
" +"password: %s

You can change your password after login." +msgstr "" + +#: src/Module/Register.php:348 +msgid "Registration successful." +msgstr "Rekisteröityminen onnistui." + +#: src/Module/Register.php:357 src/Module/Register.php:364 +#: src/Module/Register.php:374 +msgid "Your registration can not be processed." +msgstr "Rekisteröintisi ei voida käsitellä." + +#: src/Module/Register.php:363 +msgid "You have to leave a request note for the admin." +msgstr "" + +#: src/Module/Register.php:373 +msgid "An internal error occured." +msgstr "" + +#: src/Module/Register.php:395 +msgid "Your registration is pending approval by the site owner." +msgstr "Rekisteröintisi odottaa ylläpitäjän hyväksyntää." + +#: src/Module/Search/Acl.php:73 +msgid "You must be logged in to use this module." +msgstr "" + +#: src/Module/Search/Index.php:69 +msgid "Only logged in users are permitted to perform a search." +msgstr "" + +#: 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:205 +#, php-format +msgid "Items tagged with: %s" +msgstr "Kohteet joilla tunnisteet: %s" + +#: src/Module/Search/Saved.php:59 +msgid "Search term was not saved." +msgstr "" + +#: src/Module/Search/Saved.php:62 +msgid "Search term already saved." +msgstr "" + +#: src/Module/Search/Saved.php:68 +msgid "Search term was not removed." +msgstr "" + +#: src/Module/Security/Login.php:123 msgid "Create a New Account" msgstr "Luo uusi käyttäjätili" -#: src/Module/Login.php:316 -msgid "Password: " -msgstr "Salasana:" +#: src/Module/Security/Login.php:142 +msgid "Your OpenID: " +msgstr "" -#: src/Module/Login.php:317 -msgid "Remember me" -msgstr "Muista minut" +#: src/Module/Security/Login.php:145 +msgid "" +"Please enter your username and password to add the OpenID to your existing " +"account." +msgstr "" -#: src/Module/Login.php:320 +#: src/Module/Security/Login.php:147 msgid "Or login using OpenID: " msgstr "Kirjaudu sisään OpenID -tunnuksella:" -#: src/Module/Login.php:326 +#: src/Module/Security/Login.php:161 +msgid "Password: " +msgstr "Salasana:" + +#: src/Module/Security/Login.php:162 +msgid "Remember me" +msgstr "Muista minut" + +#: src/Module/Security/Login.php:171 msgid "Forgot your password?" msgstr "Unohditko salasanasi?" -#: src/Module/Login.php:329 +#: src/Module/Security/Login.php:174 msgid "Website Terms of Service" msgstr "Verkkosivun käyttöehdot" -#: src/Module/Login.php:330 +#: src/Module/Security/Login.php:175 msgid "terms of service" msgstr "käyttöehdot" -#: src/Module/Login.php:332 +#: src/Module/Security/Login.php:177 msgid "Website Privacy Policy" msgstr "Sivuston tietosuojakäytäntö" -#: src/Module/Login.php:333 +#: src/Module/Security/Login.php:178 msgid "privacy policy" msgstr "tietosuojakäytäntö" -#: src/Module/Tos.php:34 src/Module/Tos.php:74 +#: src/Module/Security/Logout.php:84 +#: src/Module/Security/TwoFactor/SignOut.php:78 +#: src/Module/Security/TwoFactor/SignOut.php:86 +#: src/Module/Security/TwoFactor/SignOut.php:108 +#: src/Module/Security/TwoFactor/SignOut.php:115 +msgid "Logged out." +msgstr "Kirjautunut ulos." + +#: src/Module/Security/OpenID.php:54 +msgid "OpenID protocol error. No ID returned" +msgstr "" + +#: src/Module/Security/OpenID.php:90 +msgid "" +"Account not found. Please login to your existing account to add the OpenID " +"to it." +msgstr "" + +#: src/Module/Security/OpenID.php:92 +msgid "" +"Account not found. Please register a new account or login to your existing " +"account to add the OpenID to it." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:57 +#: src/Module/Settings/Account.php:67 +msgid "Passwords do not match." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:64 +msgid "Password does not need changing." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:77 +#: src/Module/Settings/Account.php:81 +msgid "Password unchanged." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:91 +msgid "Password Too Long" +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:92 +msgid "" +"Since version 2022.09, we've realized that any password longer than 72 " +"characters is truncated during hashing. To prevent any confusion about this " +"behavior, please update your password to be fewer or equal to 72 characters." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:93 +msgid "Update Password" +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:99 +#: src/Module/Settings/Account.php:568 +msgid "Current Password:" +msgstr "Nykyinen salasana:" + +#: src/Module/Security/PasswordTooLong.php:99 +#: src/Module/Settings/Account.php:568 +msgid "Your current password to confirm the changes" +msgstr "Syötä nykyinen salasanasi vahvistaaksesi muutokset" + +#: src/Module/Security/PasswordTooLong.php:100 +#: src/Module/Settings/Account.php:552 +msgid "" +"Allowed characters are a-z, A-Z, 0-9 and special characters except white " +"spaces and accentuated letters." +msgstr "" + +#: src/Module/Security/PasswordTooLong.php:100 +#: src/Module/Settings/Account.php:553 +msgid "Password length is limited to 72 characters." +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:74 +#, php-format +msgid "Remaining recovery codes: %d" +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:80 +#: src/Module/Security/TwoFactor/Verify.php:77 +#: src/Module/Settings/TwoFactor/Verify.php:95 +msgid "Invalid code, please retry." +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:99 +msgid "Two-factor recovery" +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:100 +msgid "" +"

You can enter one of your one-time recovery codes in case you lost access" +" to your mobile device.

" +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:101 +#, php-format +msgid "Don’t have your phone? Enter a two-factor recovery code" +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:102 +msgid "Please enter a recovery code" +msgstr "" + +#: src/Module/Security/TwoFactor/Recovery.php:103 +msgid "Submit recovery code and complete login" +msgstr "" + +#: src/Module/Security/TwoFactor/SignOut.php:122 +msgid "Sign out of this browser?" +msgstr "" + +#: src/Module/Security/TwoFactor/SignOut.php:123 +msgid "" +"

If you trust this browser, you will not be asked for verification code " +"the next time you sign in.

" +msgstr "" + +#: src/Module/Security/TwoFactor/SignOut.php:124 +msgid "Sign out" +msgstr "" + +#: src/Module/Security/TwoFactor/SignOut.php:126 +msgid "Trust and sign out" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:96 +msgid "Couldn't save browser to Cookie." +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:141 +msgid "Trust this browser?" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:142 +msgid "" +"

If you choose to trust this browser, you will not be asked for a " +"verification code the next time you sign in.

" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:143 +msgid "Not now" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:144 +msgid "Don't trust" +msgstr "" + +#: src/Module/Security/TwoFactor/Trust.php:145 +msgid "Trust" +msgstr "" + +#: src/Module/Security/TwoFactor/Verify.php:97 +msgid "" +"

Open the two-factor authentication app on your device to get an " +"authentication code and verify your identity.

" +msgstr "" + +#: src/Module/Security/TwoFactor/Verify.php:100 +#, php-format +msgid "" +"If you do not have access to your authentication code you can use a two-factor recovery code." +msgstr "" + +#: src/Module/Security/TwoFactor/Verify.php:101 +#: src/Module/Settings/TwoFactor/Verify.php:155 +msgid "Please enter a code from your authentication app" +msgstr "" + +#: src/Module/Security/TwoFactor/Verify.php:102 +msgid "Verify code and complete login" +msgstr "" + +#: src/Module/Settings/Account.php:96 +msgid "Please use a shorter name." +msgstr "" + +#: src/Module/Settings/Account.php:99 +msgid "Name too short." +msgstr "" + +#: src/Module/Settings/Account.php:108 +msgid "Wrong Password." +msgstr "" + +#: src/Module/Settings/Account.php:113 +msgid "Invalid email." +msgstr "Virheellinen sähköposti." + +#: src/Module/Settings/Account.php:117 +msgid "Cannot change to that email." +msgstr "" + +#: src/Module/Settings/Account.php:146 src/Module/Settings/Account.php:198 +#: src/Module/Settings/Account.php:218 src/Module/Settings/Account.php:302 +#: src/Module/Settings/Account.php:351 +msgid "Settings were not updated." +msgstr "" + +#: src/Module/Settings/Account.php:363 +msgid "Contact CSV file upload error" +msgstr "" + +#: src/Module/Settings/Account.php:382 +msgid "Importing Contacts done" +msgstr "" + +#: src/Module/Settings/Account.php:395 +msgid "Relocate message has been send to your contacts" +msgstr "" + +#: src/Module/Settings/Account.php:412 +msgid "Unable to find your profile. Please contact your admin." +msgstr "Profiilisi ei löytynyt. Ota yhteyttä ylläpitäjään." + +#: src/Module/Settings/Account.php:454 +msgid "Personal Page Subtypes" +msgstr "Henkilökohtaisen sivun alatyypit" + +#: src/Module/Settings/Account.php:455 +msgid "Community Group Subtypes" +msgstr "" + +#: src/Module/Settings/Account.php:465 +msgid "Account for a personal profile." +msgstr "Henkilökohtaisen profiilin käyttäjätili." + +#: src/Module/Settings/Account.php:472 +msgid "" +"Account for an organisation that automatically approves contact requests as " +"\"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:479 +msgid "" +"Account for a news reflector that automatically approves contact requests as" +" \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:486 +msgid "Account for community discussions." +msgstr "" + +#: src/Module/Settings/Account.php:493 +msgid "" +"Account for a regular personal profile that requires manual approval of " +"\"Friends\" and \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:500 +msgid "" +"Account for a public profile that automatically approves contact requests as" +" \"Followers\"." +msgstr "" + +#: src/Module/Settings/Account.php:507 +msgid "Automatically approves all contact requests." +msgstr "Automaattisesti hyväksyy kaikki kontaktipyynnöt" + +#: src/Module/Settings/Account.php:514 +msgid "" +"Account for a popular profile that automatically approves contact requests " +"as \"Friends\"." +msgstr "" + +#: src/Module/Settings/Account.php:519 +msgid "Private Group [Experimental]" +msgstr "" + +#: src/Module/Settings/Account.php:521 +msgid "Requires manual approval of contact requests." +msgstr "" + +#: src/Module/Settings/Account.php:530 +msgid "OpenID:" +msgstr "OpenID:" + +#: src/Module/Settings/Account.php:530 +msgid "(Optional) Allow this OpenID to login to this account." +msgstr "" + +#: src/Module/Settings/Account.php:538 +msgid "Publish your profile in your local site directory?" +msgstr "" + +#: src/Module/Settings/Account.php:538 +#, php-format +msgid "" +"Your profile will be published in this node's local " +"directory. Your profile details may be publicly visible depending on the" +" system settings." +msgstr "" + +#: src/Module/Settings/Account.php:544 +#, php-format +msgid "" +"Your profile will also be published in the global friendica directories " +"(e.g. %s)." +msgstr "" + +#: src/Module/Settings/Account.php:557 +msgid "Account Settings" +msgstr "Tiliasetukset" + +#: src/Module/Settings/Account.php:558 +#, php-format +msgid "Your Identity Address is '%s' or '%s'." +msgstr "Identiteettisi osoite on '%s' tai '%s'." + +#: src/Module/Settings/Account.php:565 +msgid "Password Settings" +msgstr "Salasana-asetukset" + +#: src/Module/Settings/Account.php:567 +msgid "Leave password fields blank unless changing" +msgstr "Jätä salasana kenttää tyhjäksi jos et halua vaihtaa salasanaa" + +#: src/Module/Settings/Account.php:569 +msgid "Password:" +msgstr "Salasana:" + +#: src/Module/Settings/Account.php:569 +msgid "Your current password to confirm the changes of the email address" +msgstr "" + +#: src/Module/Settings/Account.php:572 +msgid "Delete OpenID URL" +msgstr "" + +#: src/Module/Settings/Account.php:574 +msgid "Basic Settings" +msgstr "Perusasetukset" + +#: src/Module/Settings/Account.php:576 +msgid "Email Address:" +msgstr "Sähköpostiosoite:" + +#: src/Module/Settings/Account.php:577 +msgid "Your Timezone:" +msgstr "Aikavyöhyke:" + +#: src/Module/Settings/Account.php:578 +msgid "Your Language:" +msgstr "Kieli:" + +#: src/Module/Settings/Account.php:578 +msgid "" +"Set the language we use to show you friendica interface and to send you " +"emails" +msgstr "Aseta Friendican käyttöliittymän ja sähköpostiviestien kieli" + +#: src/Module/Settings/Account.php:579 +msgid "Default Post Location:" +msgstr "Julkaisun oletussijainti:" + +#: src/Module/Settings/Account.php:580 +msgid "Use Browser Location:" +msgstr "Käytä selaimen sijainti:" + +#: src/Module/Settings/Account.php:582 +msgid "Security and Privacy Settings" +msgstr "Turvallisuus ja tietosuoja-asetukset" + +#: src/Module/Settings/Account.php:584 +msgid "Maximum Friend Requests/Day:" +msgstr "Kaveripyyntöraja päivässä:" + +#: src/Module/Settings/Account.php:584 src/Module/Settings/Account.php:594 +msgid "(to prevent spam abuse)" +msgstr "(roskapostin estämiseksi)" + +#: src/Module/Settings/Account.php:586 +msgid "Allow your profile to be searchable globally?" +msgstr "" + +#: src/Module/Settings/Account.php:586 +msgid "" +"Activate this setting if you want others to easily find and follow you. Your" +" profile will be searchable on remote systems. This setting also determines " +"whether Friendica will inform search engines that your profile should be " +"indexed or not." +msgstr "" + +#: src/Module/Settings/Account.php:587 +msgid "Hide your contact/friend list from viewers of your profile?" +msgstr "" + +#: src/Module/Settings/Account.php:587 +msgid "" +"A list of your contacts is displayed on your profile page. Activate this " +"option to disable the display of your contact list." +msgstr "" + +#: src/Module/Settings/Account.php:588 +msgid "Hide your public content from anonymous viewers" +msgstr "" + +#: src/Module/Settings/Account.php:588 +msgid "" +"Anonymous visitors will only see your basic profile details. Your public " +"posts and replies will still be freely accessible on the remote servers of " +"your followers and through relays." +msgstr "" + +#: src/Module/Settings/Account.php:589 +msgid "Make public posts unlisted" +msgstr "" + +#: src/Module/Settings/Account.php:589 +msgid "" +"Your public posts will not appear on the community pages or in search " +"results, nor be sent to relay servers. However they can still appear on " +"public feeds on remote servers." +msgstr "" + +#: src/Module/Settings/Account.php:590 +msgid "Make all posted pictures accessible" +msgstr "" + +#: src/Module/Settings/Account.php:590 +msgid "" +"This option makes every posted picture accessible via the direct link. This " +"is a workaround for the problem that most other networks can't handle " +"permissions on pictures. Non public pictures still won't be visible for the " +"public on your photo albums though." +msgstr "" + +#: src/Module/Settings/Account.php:591 +msgid "Allow friends to post to your profile page?" +msgstr "Anna kavereiden julkaista profiilisivullasi?" + +#: src/Module/Settings/Account.php:591 +msgid "" +"Your contacts may write posts on your profile wall. These posts will be " +"distributed to your contacts" +msgstr "" + +#: src/Module/Settings/Account.php:592 +msgid "Allow friends to tag your posts?" +msgstr "Anna kavereiden lisätä tunnisteita julkaisuusi?" + +#: src/Module/Settings/Account.php:592 +msgid "Your contacts can add additional tags to your posts." +msgstr "Kontaktisi voi lisätä ylimääräisiä tunnisteita julkaisuusi." + +#: src/Module/Settings/Account.php:593 +msgid "Permit unknown people to send you private mail?" +msgstr "Salli yksityisviesit tuntemattomilta?" + +#: src/Module/Settings/Account.php:593 +msgid "" +"Friendica network users may send you private messages even if they are not " +"in your contact list." +msgstr "" + +#: src/Module/Settings/Account.php:594 +msgid "Maximum private messages per day from unknown people:" +msgstr "Enimmäismäärä yksityisviestejä päivässä tuntemattomilta henkilöiltä:" + +#: src/Module/Settings/Account.php:596 +msgid "Default Post Permissions" +msgstr "Julkaisun oletuskäyttöoikeudet:" + +#: src/Module/Settings/Account.php:600 +msgid "Expiration settings" +msgstr "" + +#: src/Module/Settings/Account.php:601 +msgid "Automatically expire posts after this many days:" +msgstr "" + +#: src/Module/Settings/Account.php:601 +msgid "If empty, posts will not expire. Expired posts will be deleted" +msgstr "Jos kenttä jää tyhjäksi, julkaisut eivät vanhene. Vanhentuneet julkaisut poistetaan." + +#: src/Module/Settings/Account.php:602 +msgid "Expire posts" +msgstr "" + +#: src/Module/Settings/Account.php:602 +msgid "When activated, posts and comments will be expired." +msgstr "" + +#: src/Module/Settings/Account.php:603 +msgid "Expire personal notes" +msgstr "" + +#: src/Module/Settings/Account.php:603 +msgid "" +"When activated, the personal notes on your profile page will be expired." +msgstr "" + +#: src/Module/Settings/Account.php:604 +msgid "Expire starred posts" +msgstr "" + +#: src/Module/Settings/Account.php:604 +msgid "" +"Starring posts keeps them from being expired. That behaviour is overwritten " +"by this setting." +msgstr "" + +#: src/Module/Settings/Account.php:605 +msgid "Only expire posts by others" +msgstr "" + +#: src/Module/Settings/Account.php:605 +msgid "" +"When activated, your own posts never expire. Then the settings above are " +"only valid for posts you received." +msgstr "" + +#: src/Module/Settings/Account.php:608 +msgid "Notification Settings" +msgstr "Huomautusasetukset" + +#: src/Module/Settings/Account.php:609 +msgid "Send a notification email when:" +msgstr "Lähetä sähköposti-ilmoitus kun:" + +#: src/Module/Settings/Account.php:610 +msgid "You receive an introduction" +msgstr "Vastaanotat kaverikutsun" + +#: src/Module/Settings/Account.php:611 +msgid "Your introductions are confirmed" +msgstr "Kaverikutsusi on hyväksytty" + +#: src/Module/Settings/Account.php:612 +msgid "Someone writes on your profile wall" +msgstr "Joku kirjoittaa profiiliseinällesi" + +#: src/Module/Settings/Account.php:613 +msgid "Someone writes a followup comment" +msgstr "Joku vastaa kommenttiin" + +#: src/Module/Settings/Account.php:614 +msgid "You receive a private message" +msgstr "Vastaanotat yksityisviestin" + +#: src/Module/Settings/Account.php:615 +msgid "You receive a friend suggestion" +msgstr "Vastaanotat kaveriehdotuksen" + +#: src/Module/Settings/Account.php:616 +msgid "You are tagged in a post" +msgstr "Sinut on merkitty julkaisuun" + +#: src/Module/Settings/Account.php:618 +msgid "Create a desktop notification when:" +msgstr "" + +#: src/Module/Settings/Account.php:619 +msgid "Someone tagged you" +msgstr "" + +#: src/Module/Settings/Account.php:620 +msgid "Someone directly commented on your post" +msgstr "" + +#: src/Module/Settings/Account.php:621 +msgid "Someone liked your content" +msgstr "" + +#: src/Module/Settings/Account.php:621 src/Module/Settings/Account.php:622 +msgid "Can only be enabled, when the direct comment notification is enabled." +msgstr "" + +#: src/Module/Settings/Account.php:622 +msgid "Someone shared your content" +msgstr "" + +#: src/Module/Settings/Account.php:623 +msgid "Someone commented in your thread" +msgstr "" + +#: src/Module/Settings/Account.php:624 +msgid "Someone commented in a thread where you commented" +msgstr "" + +#: src/Module/Settings/Account.php:625 +msgid "Someone commented in a thread where you interacted" +msgstr "" + +#: src/Module/Settings/Account.php:627 +msgid "Activate desktop notifications" +msgstr "Ota työpöytäilmoitukset käyttöön" + +#: src/Module/Settings/Account.php:627 +msgid "Show desktop popup on new notifications" +msgstr "Näytä uudet ilmoitukset ponnahdusikkunassa" + +#: src/Module/Settings/Account.php:631 +msgid "Text-only notification emails" +msgstr "Ilmoitussähköposteissa vain tekstiä" + +#: src/Module/Settings/Account.php:633 +msgid "Send text only notification emails, without the html part" +msgstr "Lähetä ilmoitussähköposteissa vain tekstiä ilman HTML-koodia" + +#: src/Module/Settings/Account.php:637 +msgid "Show detailled notifications" +msgstr "Näytä yksityiskohtaiset ilmoitukset" + +#: src/Module/Settings/Account.php:639 +msgid "" +"Per default, notifications are condensed to a single notification per item. " +"When enabled every notification is displayed." +msgstr "" + +#: src/Module/Settings/Account.php:643 +msgid "Show notifications of ignored contacts" +msgstr "" + +#: src/Module/Settings/Account.php:645 +msgid "" +"You don't see posts from ignored contacts. But you still see their comments." +" This setting controls if you want to still receive regular notifications " +"that are caused by ignored contacts or not." +msgstr "" + +#: src/Module/Settings/Account.php:648 +msgid "Advanced Account/Page Type Settings" +msgstr "Käyttäjätili/sivutyyppi lisäasetuksia" + +#: src/Module/Settings/Account.php:649 +msgid "Change the behaviour of this account for special situations" +msgstr "" + +#: src/Module/Settings/Account.php:652 +msgid "Import Contacts" +msgstr "" + +#: src/Module/Settings/Account.php:653 +msgid "" +"Upload a CSV file that contains the handle of your followed accounts in the " +"first column you exported from the old account." +msgstr "" + +#: src/Module/Settings/Account.php:654 +msgid "Upload File" +msgstr "" + +#: src/Module/Settings/Account.php:657 +msgid "Relocate" +msgstr "Uudelleensijoitus" + +#: src/Module/Settings/Account.php:658 +msgid "" +"If you have moved this profile from another server, and some of your " +"contacts don't receive your updates, try pushing this button." +msgstr "" + +#: src/Module/Settings/Account.php:659 +msgid "Resend relocate message to contacts" +msgstr "" + +#: src/Module/Settings/Addons.php:86 +msgid "Addon Settings" +msgstr "Lisäosa-asetukset" + +#: src/Module/Settings/Addons.php:87 +msgid "No Addon settings configured" +msgstr "Lisäosa-asetukset puuttuvat" + +#: src/Module/Settings/Connectors.php:120 +msgid "Failed to connect with email account using the settings provided." +msgstr "" + +#: src/Module/Settings/Connectors.php:166 +#: src/Module/Settings/Connectors.php:167 +msgid "Diaspora (Socialhome, Hubzilla)" +msgstr "Diaspora (Socialhome, Hubzilla)" + +#: src/Module/Settings/Connectors.php:166 +#: src/Module/Settings/Connectors.php:170 +#, php-format +msgid "Built-in support for %s connectivity is enabled" +msgstr "" + +#: src/Module/Settings/Connectors.php:167 +#: src/Module/Settings/Connectors.php:169 +#, php-format +msgid "Built-in support for %s connectivity is disabled" +msgstr "" + +#: src/Module/Settings/Connectors.php:169 +#: src/Module/Settings/Connectors.php:170 +msgid "OStatus (GNU Social)" +msgstr "" + +#: src/Module/Settings/Connectors.php:182 +msgid "Email access is disabled on this site." +msgstr "" + +#: src/Module/Settings/Connectors.php:197 +#: src/Module/Settings/Connectors.php:244 +msgid "None" +msgstr "Ei mitään" + +#: src/Module/Settings/Connectors.php:209 +msgid "General Social Media Settings" +msgstr "Yleiset some asetukset" + +#: src/Module/Settings/Connectors.php:212 +msgid "Followed content scope" +msgstr "" + +#: src/Module/Settings/Connectors.php:214 +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:216 +msgid "Only conversations my follows started" +msgstr "" + +#: src/Module/Settings/Connectors.php:217 +msgid "Conversations my follows started or commented on (default)" +msgstr "" + +#: src/Module/Settings/Connectors.php:218 +msgid "Any conversation my follows interacted with, including likes" +msgstr "" + +#: src/Module/Settings/Connectors.php:221 +msgid "Enable Content Warning" +msgstr "" + +#: src/Module/Settings/Connectors.php:221 +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 " +"collapsing instead of setting the content warning as the post title. Doesn't" +" affect any other content filtering you eventually set up." +msgstr "" + +#: src/Module/Settings/Connectors.php:222 +msgid "Enable intelligent shortening" +msgstr "" + +#: src/Module/Settings/Connectors.php:222 +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:223 +msgid "Enable simple text shortening" +msgstr "" + +#: src/Module/Settings/Connectors.php:223 +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:224 +msgid "Attach the link title" +msgstr "" + +#: src/Module/Settings/Connectors.php:224 +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:225 +msgid "API: Use spoiler field as title" +msgstr "" + +#: src/Module/Settings/Connectors.php:225 +msgid "" +"When activated, the \"spoiler_text\" field in the API will be used for the " +"title on standalone posts. When deactivated it will be used for spoiler " +"text. For comments it will always be used for spoiler text." +msgstr "" + +#: src/Module/Settings/Connectors.php:226 +msgid "API: Automatically links at the end of the post as attached posts" +msgstr "" + +#: src/Module/Settings/Connectors.php:226 +msgid "" +"When activated, added links at the end of the post react the same way as " +"added links in the web interface." +msgstr "" + +#: src/Module/Settings/Connectors.php:227 +msgid "Your legacy ActivityPub/GNU Social account" +msgstr "" + +#: src/Module/Settings/Connectors.php:227 +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:229 +msgid "Repair OStatus subscriptions" +msgstr "Korjaa OStatus tilaukset" + +#: src/Module/Settings/Connectors.php:233 +msgid "Email/Mailbox Setup" +msgstr "Sähköpostin asennus" + +#: src/Module/Settings/Connectors.php:234 +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:235 +msgid "Last successful email check:" +msgstr "Viimeisin onnistunut sähköpostitarkistus:" + +#: src/Module/Settings/Connectors.php:237 +msgid "IMAP server name:" +msgstr "IMAP-palvelimen nimi:" + +#: src/Module/Settings/Connectors.php:238 +msgid "IMAP port:" +msgstr "IMAP-porttti:" + +#: src/Module/Settings/Connectors.php:239 +msgid "Security:" +msgstr "Turvallisuus:" + +#: src/Module/Settings/Connectors.php:240 +msgid "Email login name:" +msgstr "Sähköpostitilin käyttäjätunnus:" + +#: src/Module/Settings/Connectors.php:241 +msgid "Email password:" +msgstr "Sähköpostin salasana:" + +#: src/Module/Settings/Connectors.php:242 +msgid "Reply-to address:" +msgstr "Vastausosoite:" + +#: src/Module/Settings/Connectors.php:243 +msgid "Send public posts to all email contacts:" +msgstr "Lähetä julkiset julkaisut kaikille kontakteille:" + +#: src/Module/Settings/Connectors.php:244 +msgid "Action after import:" +msgstr "Toiminta tuonnin jälkeen:" + +#: src/Module/Settings/Connectors.php:244 +msgid "Move to folder" +msgstr "Siirrä kansioon" + +#: src/Module/Settings/Connectors.php:245 +msgid "Move to folder:" +msgstr "Siirrä kansioon:" + +#: src/Module/Settings/Delegation.php:54 +msgid "Delegation successfully granted." +msgstr "" + +#: src/Module/Settings/Delegation.php:56 +msgid "Parent user not found, unavailable or password doesn't match." +msgstr "" + +#: src/Module/Settings/Delegation.php:60 +msgid "Delegation successfully revoked." +msgstr "" + +#: src/Module/Settings/Delegation.php:82 +#: src/Module/Settings/Delegation.php:104 +msgid "" +"Delegated administrators can view but not change delegation permissions." +msgstr "" + +#: src/Module/Settings/Delegation.php:96 +msgid "Delegate user not found." +msgstr "" + +#: src/Module/Settings/Delegation.php:144 +msgid "No parent user" +msgstr "" + +#: src/Module/Settings/Delegation.php:155 +#: src/Module/Settings/Delegation.php:166 +msgid "Parent User" +msgstr "" + +#: src/Module/Settings/Delegation.php:163 +msgid "Additional Accounts" +msgstr "" + +#: src/Module/Settings/Delegation.php:164 +msgid "" +"Register additional accounts that are automatically connected to your " +"existing account so you can manage them from this account." +msgstr "" + +#: src/Module/Settings/Delegation.php:165 +msgid "Register an additional account" +msgstr "" + +#: src/Module/Settings/Delegation.php:169 +msgid "" +"Parent users have total control about this account, including the account " +"settings. Please double check whom you give this access." +msgstr "" + +#: src/Module/Settings/Delegation.php:173 +msgid "Delegates" +msgstr "Valtuutetut" + +#: src/Module/Settings/Delegation.php:175 +msgid "" +"Delegates are able to manage all aspects of this account/page except for " +"basic account settings. Please do not delegate your personal account to " +"anybody that you do not trust completely." +msgstr "" + +#: src/Module/Settings/Delegation.php:176 +msgid "Existing Page Delegates" +msgstr "Sivun valtuutetut" + +#: src/Module/Settings/Delegation.php:178 +msgid "Potential Delegates" +msgstr "Mahdolliset valtuutetut" + +#: src/Module/Settings/Delegation.php:181 +msgid "Add" +msgstr "Lisää" + +#: src/Module/Settings/Delegation.php:182 +msgid "No entries." +msgstr "Ei kohteita." + +#: src/Module/Settings/Display.php:137 +msgid "The theme you chose isn't available." +msgstr "" + +#: src/Module/Settings/Display.php:177 +#, php-format +msgid "%s - (Unsupported)" +msgstr "%s - (Ei tueta)" + +#: src/Module/Settings/Display.php:212 +msgid "No preview" +msgstr "" + +#: src/Module/Settings/Display.php:213 +msgid "No image" +msgstr "" + +#: src/Module/Settings/Display.php:214 +msgid "Small Image" +msgstr "" + +#: src/Module/Settings/Display.php:215 +msgid "Large Image" +msgstr "" + +#: src/Module/Settings/Display.php:246 +msgid "Display Settings" +msgstr "Näyttöasetukset" + +#: src/Module/Settings/Display.php:248 +msgid "General Theme Settings" +msgstr "Yleiset teeman asetukset" + +#: src/Module/Settings/Display.php:249 +msgid "Custom Theme Settings" +msgstr "Mukautetut teema-asetukset" + +#: src/Module/Settings/Display.php:250 +msgid "Content Settings" +msgstr "Sisältöasetukset" + +#: src/Module/Settings/Display.php:251 view/theme/duepuntozero/config.php:86 +#: view/theme/frio/config.php:172 view/theme/quattro/config.php:88 +#: view/theme/vier/config.php:136 +msgid "Theme settings" +msgstr "Teeman asetukset" + +#: src/Module/Settings/Display.php:257 +msgid "Display Theme:" +msgstr "Käyttöliittymän teema:" + +#: src/Module/Settings/Display.php:258 +msgid "Mobile Theme:" +msgstr "Mobiiliteema:" + +#: src/Module/Settings/Display.php:261 +msgid "Number of items to display per page:" +msgstr "" + +#: src/Module/Settings/Display.php:261 src/Module/Settings/Display.php:262 +msgid "Maximum of 100 items" +msgstr "Enintään 100 kohdetta" + +#: src/Module/Settings/Display.php:262 +msgid "Number of items to display per page when viewed from mobile device:" +msgstr "" + +#: src/Module/Settings/Display.php:263 +msgid "Update browser every xx seconds" +msgstr "Päivitä selain xx sekunnin välein" + +#: src/Module/Settings/Display.php:263 +msgid "Minimum of 10 seconds. Enter -1 to disable it." +msgstr "Vähintään 10 sekuntia. -1 poistaa ominaisuuden käytöstä." + +#: src/Module/Settings/Display.php:264 +msgid "Display emoticons" +msgstr "" + +#: src/Module/Settings/Display.php:264 +msgid "When enabled, emoticons are replaced with matching symbols." +msgstr "" + +#: src/Module/Settings/Display.php:265 +msgid "Infinite scroll" +msgstr "Loputon selaaminen" + +#: src/Module/Settings/Display.php:265 +msgid "Automatic fetch new items when reaching the page end." +msgstr "" + +#: src/Module/Settings/Display.php:266 +msgid "Enable Smart Threading" +msgstr "" + +#: src/Module/Settings/Display.php:266 +msgid "Enable the automatic suppression of extraneous thread indentation." +msgstr "" + +#: src/Module/Settings/Display.php:267 +msgid "Display the Dislike feature" +msgstr "" + +#: src/Module/Settings/Display.php:267 +msgid "" +"Display the Dislike button and dislike reactions on posts and comments." +msgstr "" + +#: src/Module/Settings/Display.php:268 +msgid "Display the resharer" +msgstr "" + +#: src/Module/Settings/Display.php:268 +msgid "Display the first resharer as icon and text on a reshared item." +msgstr "" + +#: src/Module/Settings/Display.php:269 +msgid "Stay local" +msgstr "" + +#: src/Module/Settings/Display.php:269 +msgid "Don't go to a remote system when following a contact link." +msgstr "" + +#: src/Module/Settings/Display.php:270 +msgid "Link preview mode" +msgstr "" + +#: src/Module/Settings/Display.php:270 +msgid "Appearance of the link preview that is added to each post with a link." +msgstr "" + +#: src/Module/Settings/Display.php:272 +msgid "Beginning of week:" +msgstr "Viikon alku:" + +#: src/Module/Settings/Display.php:273 +msgid "Default calendar view:" +msgstr "" + +#: src/Module/Settings/Features.php:74 +msgid "Additional Features" +msgstr "Lisäominaisuuksia" + +#: src/Module/Settings/OAuth.php:71 +msgid "Connected Apps" +msgstr "Yhdistetyt sovellukset" + +#: src/Module/Settings/OAuth.php:75 +msgid "Remove authorization" +msgstr "Poista lupa" + +#: src/Module/Settings/Profile/Index.php:84 +msgid "Profile Name is required." +msgstr "Profiilinimi on pakollinen." + +#: src/Module/Settings/Profile/Index.php:134 +msgid "Profile couldn't be updated." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:175 +#: src/Module/Settings/Profile/Index.php:195 +msgid "Label:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:176 +#: src/Module/Settings/Profile/Index.php:196 +msgid "Value:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:186 +#: src/Module/Settings/Profile/Index.php:206 +msgid "Field Permissions" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:187 +#: src/Module/Settings/Profile/Index.php:207 +msgid "(click to open/close)" +msgstr "(klikkaa auki/kiinni)" + +#: src/Module/Settings/Profile/Index.php:193 +msgid "Add a new profile field" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:216 +msgid "" +"The homepage is verified. A rel=\"me\" link back to your Friendica profile " +"page was found on the homepage." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:218 +#, php-format +msgid "" +"To verify your homepage, add a rel=\"me\" link to it, pointing to your " +"profile URL (%s)." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:228 +msgid "Profile Actions" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:229 +msgid "Edit Profile Details" +msgstr "Muokkaa profiilin yksityiskohdat" + +#: src/Module/Settings/Profile/Index.php:231 +msgid "Change Profile Photo" +msgstr "Vaihda profiilikuva" + +#: src/Module/Settings/Profile/Index.php:236 +msgid "Profile picture" +msgstr "Profiilikuva" + +#: src/Module/Settings/Profile/Index.php:237 +msgid "Location" +msgstr "Sijainti" + +#: src/Module/Settings/Profile/Index.php:238 src/Util/Temporal.php:97 +#: src/Util/Temporal.php:99 +msgid "Miscellaneous" +msgstr "Sekalaista" + +#: src/Module/Settings/Profile/Index.php:239 +msgid "Custom Profile Fields" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:241 src/Module/Welcome.php:58 +msgid "Upload Profile Photo" +msgstr "Lataa profiilikuva" + +#: src/Module/Settings/Profile/Index.php:245 +msgid "Display name:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:248 +msgid "Street Address:" +msgstr "Katuosoite:" + +#: src/Module/Settings/Profile/Index.php:249 +msgid "Locality/City:" +msgstr "Kaupunki:" + +#: src/Module/Settings/Profile/Index.php:250 +msgid "Region/State:" +msgstr "Alue/osavaltio:" + +#: src/Module/Settings/Profile/Index.php:251 +msgid "Postal/Zip Code:" +msgstr "Postinumero:" + +#: src/Module/Settings/Profile/Index.php:252 +msgid "Country:" +msgstr "Maa:" + +#: src/Module/Settings/Profile/Index.php:254 +msgid "XMPP (Jabber) address:" +msgstr "XMPP (Jabber) osoite:" + +#: src/Module/Settings/Profile/Index.php:254 +msgid "" +"The XMPP address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:255 +msgid "Matrix (Element) address:" +msgstr "" + +#: src/Module/Settings/Profile/Index.php:255 +msgid "" +"The Matrix address will be published so that people can follow you there." +msgstr "" + +#: src/Module/Settings/Profile/Index.php:256 +msgid "Homepage URL:" +msgstr "Kotisivun URL-osoite:" + +#: src/Module/Settings/Profile/Index.php:257 +msgid "Public Keywords:" +msgstr "Julkiset avainsanat:" + +#: src/Module/Settings/Profile/Index.php:257 +msgid "(Used for suggesting potential friends, can be seen by others)" +msgstr "(Käytetään kaveriehdotuksia varten, näkyy muille)" + +#: src/Module/Settings/Profile/Index.php:258 +msgid "Private Keywords:" +msgstr "Yksityiset avainsanat:" + +#: src/Module/Settings/Profile/Index.php:258 +msgid "(Used for searching profiles, never shown to others)" +msgstr "(Käytetään profiilihakua varten, ei näy muille)" + +#: src/Module/Settings/Profile/Index.php:259 +#, php-format +msgid "" +"

Custom fields appear on your profile page.

\n" +"\t\t\t\t

You can use BBCodes in the field values.

\n" +"\t\t\t\t

Reorder by dragging the field title.

\n" +"\t\t\t\t

Empty the label field to remove a custom field.

\n" +"\t\t\t\t

Non-public fields can only be seen by the selected Friendica contacts or the Friendica contacts in the selected circles.

" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Crop.php:107 +#: src/Module/Settings/Profile/Photo/Crop.php:125 +#: src/Module/Settings/Profile/Photo/Crop.php:143 +#: src/Module/Settings/Profile/Photo/Index.php:101 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "Kuvan pienentäminen [%s] epäonnistui." + +#: src/Module/Settings/Profile/Photo/Crop.php:150 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Jos kuva ei näy heti, lataa sivu uudelleen tai tyhjennä selaimen välimuisti." + +#: src/Module/Settings/Profile/Photo/Crop.php:155 +msgid "Unable to process image" +msgstr "Kuvan käsitteleminen epäonnistui" + +#: src/Module/Settings/Profile/Photo/Crop.php:174 +msgid "Photo not found." +msgstr "" + +#: src/Module/Settings/Profile/Photo/Crop.php:196 +msgid "Profile picture successfully updated." +msgstr "" + +#: src/Module/Settings/Profile/Photo/Crop.php:222 +#: src/Module/Settings/Profile/Photo/Crop.php:226 +msgid "Crop Image" +msgstr "Rajaa kuva" + +#: src/Module/Settings/Profile/Photo/Crop.php:223 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Rajaa kuva sopivasti." + +#: src/Module/Settings/Profile/Photo/Crop.php:225 +msgid "Use Image As Is" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:45 +msgid "Missing uploaded image." +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:124 +msgid "Profile Picture Settings" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:125 +msgid "Current Profile Picture" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:126 +msgid "Upload Profile Picture" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:127 +msgid "Upload Picture:" +msgstr "" + +#: src/Module/Settings/Profile/Photo/Index.php:132 +msgid "or" +msgstr "tai" + +#: src/Module/Settings/Profile/Photo/Index.php:134 +msgid "skip this step" +msgstr "ohita tämä vaihe" + +#: src/Module/Settings/Profile/Photo/Index.php:136 +msgid "select a photo from your photo albums" +msgstr "valitse kuva albumeistasi" + +#: src/Module/Settings/RemoveMe.php:94 +#: src/Navigation/Notifications/Repository/Notify.php:471 +#: src/Navigation/Notifications/Repository/Notify.php:492 +msgid "[Friendica System Notify]" +msgstr "[Friendica Järjestelmäilmoitus]" + +#: src/Module/Settings/RemoveMe.php:94 +msgid "User deleted their account" +msgstr "Käyttäjä poisti tilinsä" + +#: src/Module/Settings/RemoveMe.php:95 +msgid "" +"On your Friendica node an user deleted their account. Please ensure that " +"their data is removed from the backups." +msgstr "Friendica -solmullasi käyttäjä poisti tilinsä. Varmista että hänen tiedot poistetaan myös varmuuskopioista." + +#: src/Module/Settings/RemoveMe.php:96 +#, php-format +msgid "The user id is %d" +msgstr "Käyttäjätunnus on %d" + +#: src/Module/Settings/RemoveMe.php:108 +msgid "Your user account has been successfully removed. Bye bye!" +msgstr "" + +#: src/Module/Settings/RemoveMe.php:128 +msgid "Remove My Account" +msgstr "Poista tilini" + +#: src/Module/Settings/RemoveMe.php:129 +msgid "" +"This will completely remove your account. Once this has been done it is not " +"recoverable." +msgstr "Tämä poistaa käyttäjätilisi pysyvästi. Poistoa ei voi perua myöhemmin." + +#: src/Module/Settings/RemoveMe.php:131 +msgid "Please enter your password for verification:" +msgstr "Syötä salasanasi varmistusta varten:" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:66 +#: src/Module/Settings/TwoFactor/Recovery.php:64 +#: src/Module/Settings/TwoFactor/Trusted.php:67 +#: src/Module/Settings/TwoFactor/Verify.php:69 +msgid "Please enter your password to access this page." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:84 +msgid "App-specific password generation failed: The description is empty." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:87 +msgid "" +"App-specific password generation failed: This description already exists." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:91 +msgid "New app-specific password generated." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:97 +msgid "App-specific passwords successfully revoked." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:107 +msgid "App-specific password successfully revoked." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:128 +msgid "Two-factor app-specific passwords" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:130 +msgid "" +"

App-specific passwords are randomly generated passwords used instead your" +" regular password to authenticate your account on third-party applications " +"that don't support two-factor authentication.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:131 +msgid "" +"Make sure to copy your new app-specific password now. You won’t be able to " +"see it again!" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:134 +msgid "Description" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:135 +msgid "Last Used" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:136 +msgid "Revoke" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:137 +msgid "Revoke All" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:140 +msgid "" +"When you generate a new app-specific password, you must use it right away, " +"it will be shown to you once after you generate it." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:141 +msgid "Generate new app-specific password" +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:142 +msgid "Friendiqa on my Fairphone 2..." +msgstr "" + +#: src/Module/Settings/TwoFactor/AppSpecific.php:143 +msgid "Generate" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:68 +msgid "Two-factor authentication successfully disabled." +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:120 +msgid "" +"

Use an application on a mobile device to get two-factor authentication " +"codes when prompted on login.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:124 +msgid "Authenticator app" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:125 +msgid "Configured" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:125 +msgid "Not Configured" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:126 +msgid "

You haven't finished configuring your authenticator app.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:127 +msgid "

Your authenticator app is correctly configured.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:129 +msgid "Recovery codes" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:130 +msgid "Remaining valid codes" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:132 +msgid "" +"

These one-use codes can replace an authenticator app code in case you " +"have lost access to it.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:134 +msgid "App-specific passwords" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:135 +msgid "Generated app-specific passwords" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:137 +msgid "" +"

These randomly generated passwords allow you to authenticate on apps not " +"supporting two-factor authentication.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:140 +msgid "Current password:" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:140 +msgid "" +"You need to provide your current password to change two-factor " +"authentication settings." +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:141 +msgid "Enable two-factor authentication" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:142 +msgid "Disable two-factor authentication" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:143 +msgid "Show recovery codes" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:144 +msgid "Manage app-specific passwords" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:145 +msgid "Manage trusted browsers" +msgstr "" + +#: src/Module/Settings/TwoFactor/Index.php:146 +msgid "Finish app configuration" +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:80 +msgid "New recovery codes successfully generated." +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:106 +msgid "Two-factor recovery codes" +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:108 +msgid "" +"

Recovery codes can be used to access your account in the event you lose " +"access to your device and cannot receive two-factor authentication " +"codes.

Put these in a safe spot! If you lose your " +"device and don’t have the recovery codes you will lose access to your " +"account.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:110 +msgid "" +"When you generate new recovery codes, you must copy the new codes. Your old " +"codes won’t work anymore." +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:111 +msgid "Generate new recovery codes" +msgstr "" + +#: src/Module/Settings/TwoFactor/Recovery.php:113 +msgid "Next: Verification" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:84 +msgid "Trusted browsers successfully removed." +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:94 +msgid "Trusted browser successfully removed." +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:136 +msgid "Two-factor Trusted Browsers" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:137 +msgid "" +"Trusted browsers are individual browsers you chose to skip two-factor " +"authentication to access Friendica. Please use this feature sparingly, as it" +" can negate the benefit of two-factor authentication." +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:138 +msgid "Device" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:139 +msgid "OS" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:141 +msgid "Trusted" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:142 +msgid "Created At" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:143 +msgid "Last Use" +msgstr "" + +#: src/Module/Settings/TwoFactor/Trusted.php:145 +msgid "Remove All" +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:91 +msgid "Two-factor authentication successfully activated." +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:125 +#, php-format +msgid "" +"

Or you can submit the authentication settings manually:

\n" +"
\n" +"\t
Issuer
\n" +"\t
%s
\n" +"\t
Account Name
\n" +"\t
%s
\n" +"\t
Secret Key
\n" +"\t
%s
\n" +"\t
Type
\n" +"\t
Time-based
\n" +"\t
Number of digits
\n" +"\t
6
\n" +"\t
Hashing algorithm
\n" +"\t
SHA-1
\n" +"
" +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:145 +msgid "Two-factor code verification" +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:147 +msgid "" +"

Please scan this QR Code with your authenticator app and submit the " +"provided code.

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:149 +#, php-format +msgid "" +"

Or you can open the following URL in your mobile device:

%s

" +msgstr "" + +#: src/Module/Settings/TwoFactor/Verify.php:156 +msgid "Verify code and enable two-factor authentication" +msgstr "" + +#: src/Module/Settings/UserExport.php:90 +msgid "Export account" +msgstr "Vie tili" + +#: src/Module/Settings/UserExport.php:90 +msgid "" +"Export your account info and contacts. Use this to make a backup of your " +"account and/or to move it to another server." +msgstr "Vie tilin tiedot ja yhteystiedot. Käytä tätä tilisi varmuuskopiointiin ja/tai siirtämiseen toiselle palvelimelle." + +#: src/Module/Settings/UserExport.php:91 +msgid "Export all" +msgstr "Vie kaikki" + +#: src/Module/Settings/UserExport.php:91 +msgid "" +"Export your account info, contacts and all your items as json. Could be a " +"very big file, and could take a lot of time. Use this to make a full backup " +"of your account (photos are not exported)" +msgstr "" + +#: src/Module/Settings/UserExport.php:92 +msgid "Export Contacts to CSV" +msgstr "" + +#: src/Module/Settings/UserExport.php:92 +msgid "" +"Export the list of the accounts you are following as CSV file. Compatible to" +" e.g. Mastodon." +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:37 +msgid "Not Found" +msgstr "" + +#: src/Module/Special/DisplayNotFound.php:38 +msgid "" +"

Unfortunately, the requested conversation isn't available to you.

\n" +"

Possible reasons include:

\n" +"
    \n" +"\t
  • The top-level post isn't visible.
  • \n" +"\t
  • The top-level post was deleted.
  • \n" +"\t
  • The node has blocked the top-level author or the author of the shared post.
  • \n" +"\t
  • You have ignored or blocked the top-level author or the author of the shared post.
  • \n" +"
" +msgstr "" + +#: src/Module/Special/HTTPException.php:78 +msgid "Stack trace:" +msgstr "" + +#: src/Module/Special/HTTPException.php:83 +#, php-format +msgid "Exception thrown in %s:%d" +msgstr "" + +#: src/Module/Tos.php:57 src/Module/Tos.php:106 msgid "" "At the time of registration, and for providing communications between the " "user account and their contacts, the user has to provide a display name (pen" @@ -9377,181 +10503,1415 @@ msgid "" "settings, it is not necessary for communication." msgstr "" -#: src/Module/Tos.php:35 src/Module/Tos.php:75 +#: src/Module/Tos.php:58 src/Module/Tos.php:107 msgid "" "This data is required for communication and is passed on to the nodes of the" " communication partners and is stored there. Users can enter additional " "private data that may be transmitted to the communication partners accounts." msgstr "" -#: src/Module/Tos.php:36 src/Module/Tos.php:76 +#: src/Module/Tos.php:59 src/Module/Tos.php:108 #, php-format msgid "" "At any point in time a logged in user can export their account data from the" -" account settings. If the user wants " -"to delete their account they can do so at %1$s/removeme. The deletion of the account will " -"be permanent. Deletion of the data will also be requested from the nodes of " -"the communication partners." +" account settings. If the user " +"wants to delete their account they can do so at %1$s/settings/removeme. The deletion of " +"the account will be permanent. Deletion of the data will also be requested " +"from the nodes of the communication partners." msgstr "" -#: src/Module/Tos.php:39 src/Module/Tos.php:73 +#: src/Module/Tos.php:62 src/Module/Tos.php:105 msgid "Privacy Statement" msgstr "Tietosuojalausunto" -#: src/Object/Post.php:128 +#: src/Module/Tos.php:102 +msgid "Rules" +msgstr "" + +#: src/Module/Update/Display.php:45 +msgid "Parameter uri_id is missing." +msgstr "" + +#: src/Module/User/Import.php:103 +msgid "User imports on closed servers can only be done by an administrator." +msgstr "" + +#: src/Module/User/Import.php:119 +msgid "Move account" +msgstr "Siirrä tili" + +#: src/Module/User/Import.php:120 +msgid "You can import an account from another Friendica server." +msgstr "Voit tuoda käyttäjätilin toiselta Friendica -palvelimelta." + +#: src/Module/User/Import.php:121 +msgid "" +"You need to export your account from the old server and upload it here. We " +"will recreate your old account here with all your contacts. We will try also" +" to inform your friends that you moved here." +msgstr "" + +#: src/Module/User/Import.php:122 +msgid "" +"This feature is experimental. We can't import contacts from the OStatus " +"network (GNU Social/Statusnet) or from Diaspora" +msgstr "Tämä on kokeellinen ominaisuus. Emme voi tuoda kontakteja OStatus-verkolta (GNU social/Statusnet) tai Diasporalta." + +#: src/Module/User/Import.php:123 +msgid "Account file" +msgstr "Tilitiedosto" + +#: src/Module/User/Import.php:123 +msgid "" +"To export your account, go to \"Settings->Export your personal data\" and " +"select \"Export account\"" +msgstr "" + +#: src/Module/User/Import.php:217 +msgid "Error decoding account file" +msgstr "Tilitiedoston tulkinnassa tapahtui virhe" + +#: src/Module/User/Import.php:222 +msgid "Error! No version data in file! This is not a Friendica account file?" +msgstr "Virhe: tiedostosta puuttuu versiotiedot! Saattaa olla että tämä ei ole Friendica -tilitiedosto?" + +#: src/Module/User/Import.php:230 +#, php-format +msgid "User '%s' already exists on this server!" +msgstr "Käyttäjä '%s' on jo olemassa tällä palvelimella!" + +#: src/Module/User/Import.php:267 +msgid "User creation error" +msgstr "Virhe käyttäjän luomisessa" + +#: src/Module/User/Import.php:316 +#, php-format +msgid "%d contact not imported" +msgid_plural "%d contacts not imported" +msgstr[0] "%d kontakti ei tuotu" +msgstr[1] "%d kontakteja ei tuotu" + +#: src/Module/User/Import.php:365 +msgid "User profile creation error" +msgstr "Virhe käyttäjäprofiilin luomisessa" + +#: src/Module/User/Import.php:416 +msgid "Done. You can now login with your username and password" +msgstr "Suoritettu. Voit nyt kirjautua sisään käyttäjätunnuksellasi." + +#: src/Module/Welcome.php:44 +msgid "Welcome to Friendica" +msgstr "Tervetuloa Friendicaan" + +#: src/Module/Welcome.php:45 +msgid "New Member Checklist" +msgstr "Uuden jäsenen tarkistuslista" + +#: src/Module/Welcome.php:46 +msgid "" +"We would like to offer some tips and links to help make your experience " +"enjoyable. Click any item to visit the relevant page. A link to this page " +"will be visible from your home page for two weeks after your initial " +"registration and then will quietly disappear." +msgstr "" + +#: src/Module/Welcome.php:48 +msgid "Getting Started" +msgstr "Ensiaskeleet" + +#: src/Module/Welcome.php:49 +msgid "Friendica Walk-Through" +msgstr "Friendica -läpikäynti" + +#: src/Module/Welcome.php:50 +msgid "" +"On your Quick Start page - find a brief introduction to your " +"profile and network tabs, make some new connections, and find some groups to" +" join." +msgstr "" + +#: src/Module/Welcome.php:53 +msgid "Go to Your Settings" +msgstr "Omat Asetukset" + +#: src/Module/Welcome.php:54 +msgid "" +"On your Settings page - change your initial password. Also make a " +"note of your Identity Address. This looks just like an email address - and " +"will be useful in making friends on the free social web." +msgstr "" + +#: src/Module/Welcome.php:55 +msgid "" +"Review the other settings, particularly the privacy settings. An unpublished" +" directory listing is like having an unlisted phone number. In general, you " +"should probably publish your listing - unless all of your friends and " +"potential friends know exactly how to find you." +msgstr "" + +#: src/Module/Welcome.php:59 +msgid "" +"Upload a profile photo if you have not done so already. Studies have shown " +"that people with real photos of themselves are ten times more likely to make" +" friends than people who do not." +msgstr "" + +#: src/Module/Welcome.php:60 +msgid "Edit Your Profile" +msgstr "Muokkaa profiilisi" + +#: src/Module/Welcome.php:61 +msgid "" +"Edit your default profile to your liking. Review the " +"settings for hiding your list of friends and hiding the profile from unknown" +" visitors." +msgstr "" + +#: src/Module/Welcome.php:62 +msgid "Profile Keywords" +msgstr "Profiilin avainsanat" + +#: src/Module/Welcome.php:63 +msgid "" +"Set some public keywords for your profile which describe your interests. We " +"may be able to find other people with similar interests and suggest " +"friendships." +msgstr "" + +#: src/Module/Welcome.php:65 +msgid "Connecting" +msgstr "Yhdistetään" + +#: src/Module/Welcome.php:67 +msgid "Importing Emails" +msgstr "Sähköpostin tuominen" + +#: src/Module/Welcome.php:68 +msgid "" +"Enter your email access information on your Connector Settings page if you " +"wish to import and interact with friends or mailing lists from your email " +"INBOX" +msgstr "" + +#: src/Module/Welcome.php:69 +msgid "Go to Your Contacts Page" +msgstr "Näytä minun kontaktit" + +#: src/Module/Welcome.php:70 +msgid "" +"Your Contacts page is your gateway to managing friendships and connecting " +"with friends on other networks. Typically you enter their address or site " +"URL in the Add New Contact dialog." +msgstr "" + +#: src/Module/Welcome.php:71 +msgid "Go to Your Site's Directory" +msgstr "Näytä oman sivuston luettelo" + +#: src/Module/Welcome.php:72 +msgid "" +"The Directory page lets you find other people in this network or other " +"federated sites. Look for a Connect or Follow link on " +"their profile page. Provide your own Identity Address if requested." +msgstr "" + +#: src/Module/Welcome.php:73 +msgid "Finding New People" +msgstr "Kavereiden hankkiminen" + +#: src/Module/Welcome.php:74 +msgid "" +"On the side panel of the Contacts page are several tools to find new " +"friends. We can match people by interest, look up people by name or " +"interest, and provide suggestions based on network relationships. On a brand" +" new site, friend suggestions will usually begin to be populated within 24 " +"hours." +msgstr "" + +#: src/Module/Welcome.php:77 +msgid "Add Your Contacts To Circle" +msgstr "" + +#: src/Module/Welcome.php:78 +msgid "" +"Once you have made some friends, organize them into private conversation " +"circles from the sidebar of your Contacts page and then you can interact " +"with each circle privately on your Network page." +msgstr "" + +#: src/Module/Welcome.php:80 +msgid "Why Aren't My Posts Public?" +msgstr "Miksi julkaisuni eivät ole julkisia?" + +#: src/Module/Welcome.php:81 +msgid "" +"Friendica respects your privacy. By default, your posts will only show up to" +" people you've added as friends. For more information, see the help section " +"from the link above." +msgstr "" + +#: src/Module/Welcome.php:83 +msgid "Getting Help" +msgstr "Avun saaminen" + +#: src/Module/Welcome.php:84 +msgid "Go to the Help Section" +msgstr "Näytä ohjeet" + +#: src/Module/Welcome.php:85 +msgid "" +"Our help pages may be consulted for detail on other program" +" features and resources." +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:161 +msgid "{0} wants to follow you" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNavNotification.php:163 +msgid "{0} has started following you" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:96 +#, php-format +msgid "%s liked %s's post" +msgstr "%s tykkäsi julkaisusta jonka kirjoitti %s" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:108 +#, php-format +msgid "%s disliked %s's post" +msgstr "%s ei tykännyt julkaisusta jonka kirjoitti %s" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:120 +#, php-format +msgid "%s is attending %s's event" +msgstr "%s osallistuu tapahtumaan jonka järjestää %s" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:132 +#, php-format +msgid "%s is not attending %s's event" +msgstr "%s ei osallistu tapahtumaan jonka järjestää %s" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:144 +#, php-format +msgid "%s may attending %s's event" +msgstr "" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:174 +#, php-format +msgid "%s is now friends with %s" +msgstr "%s ja %s ovat kavereita" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:341 +#: src/Navigation/Notifications/Factory/FormattedNotify.php:379 +#, php-format +msgid "%s commented on %s's post" +msgstr "%s kommentoi julkaisuun jonka kirjoitti %s" + +#: src/Navigation/Notifications/Factory/FormattedNotify.php:378 +#, php-format +msgid "%s created a new post" +msgstr "%s loi uuden julkaisun" + +#: src/Navigation/Notifications/Factory/Introduction.php:133 +msgid "Friend Suggestion" +msgstr "Kaveriehdotus" + +#: src/Navigation/Notifications/Factory/Introduction.php:159 +msgid "Friend/Connect Request" +msgstr "Ystävä/yhteyspyyntö" + +#: src/Navigation/Notifications/Factory/Introduction.php:159 +msgid "New Follower" +msgstr "Uusi seuraaja" + +#: src/Navigation/Notifications/Factory/Notification.php:134 +#, php-format +msgid "%1$s wants to follow you" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:136 +#, php-format +msgid "%1$s has started following you" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:208 +#, php-format +msgid "%1$s liked your comment on %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:211 +#, php-format +msgid "%1$s liked your post %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:218 +#, php-format +msgid "%1$s disliked your comment on %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:221 +#, php-format +msgid "%1$s disliked your post %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:228 +#, php-format +msgid "%1$s shared your comment %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:231 +#: src/Navigation/Notifications/Factory/Notification.php:316 +#, php-format +msgid "%1$s shared your post %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:235 +#: src/Navigation/Notifications/Factory/Notification.php:305 +#, php-format +msgid "%1$s shared the post %2$s from %3$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:237 +#: src/Navigation/Notifications/Factory/Notification.php:307 +#, php-format +msgid "%1$s shared a post from %3$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:239 +#: src/Navigation/Notifications/Factory/Notification.php:309 +#, php-format +msgid "%1$s shared the post %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:241 +#: src/Navigation/Notifications/Factory/Notification.php:311 +#, php-format +msgid "%1$s shared a post" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:249 +#, php-format +msgid "%1$s wants to attend your event %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:256 +#, php-format +msgid "%1$s does not want to attend your event %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:263 +#, php-format +msgid "%1$s maybe wants to attend your event %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:270 +#, php-format +msgid "%1$s tagged you on %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:274 +#, php-format +msgid "%1$s replied to you on %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:278 +#, php-format +msgid "%1$s commented in your thread %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:282 +#, php-format +msgid "%1$s commented on your comment %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:289 +#, php-format +msgid "%1$s commented in their thread %2$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:291 +#, php-format +msgid "%1$s commented in their thread" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:293 +#, php-format +msgid "%1$s commented in the thread %2$s from %3$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:295 +#, php-format +msgid "%1$s commented in the thread from %3$s" +msgstr "" + +#: src/Navigation/Notifications/Factory/Notification.php:300 +#, php-format +msgid "%1$s commented on your thread %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:225 +#: src/Navigation/Notifications/Repository/Notify.php:752 +msgid "[Friendica:Notify]" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:293 +#, php-format +msgid "%s New mail received at %s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:295 +#, php-format +msgid "%1$s sent you a new private message at %2$s." +msgstr "%1$s lähetti sinulle uuden yksityisviestin kohteessa %2$s." + +#: src/Navigation/Notifications/Repository/Notify.php:296 +msgid "a private message" +msgstr "yksityisviesti" + +#: src/Navigation/Notifications/Repository/Notify.php:296 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s lähetti sinulle %2$s." + +#: src/Navigation/Notifications/Repository/Notify.php:298 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Katso yksityisviestisi kohteessa %s." + +#: src/Navigation/Notifications/Repository/Notify.php:328 +#, php-format +msgid "%1$s commented on %2$s's %3$s %4$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:333 +#, php-format +msgid "%1$s commented on your %2$s %3$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:337 +#, php-format +msgid "%1$s commented on their %2$s %3$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:341 +#: src/Navigation/Notifications/Repository/Notify.php:786 +#, php-format +msgid "%1$s Comment to conversation #%2$d by %3$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:343 +#, php-format +msgid "%s commented on an item/conversation you have been following." +msgstr "%s kommentoi kohteessa/keskustelussa jota seuraat." + +#: src/Navigation/Notifications/Repository/Notify.php:347 +#: src/Navigation/Notifications/Repository/Notify.php:362 +#: src/Navigation/Notifications/Repository/Notify.php:812 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Käy %s nähdäksesi keskustelun ja/tai vastataksesi siihen" + +#: src/Navigation/Notifications/Repository/Notify.php:354 +#, php-format +msgid "%s %s posted to your profile wall" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:356 +#, php-format +msgid "%1$s posted to your profile wall at %2$s" +msgstr "%1$s kirjoitti seinällesi kohteessa %2$s" + +#: src/Navigation/Notifications/Repository/Notify.php:357 +#, php-format +msgid "%1$s posted to [url=%2$s]your wall[/url]" +msgstr "%1$s kirjoitti [url=%2$s]seinällesi[/url]" + +#: src/Navigation/Notifications/Repository/Notify.php:370 +#, php-format +msgid "%s Introduction received" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:372 +#, php-format +msgid "You've received an introduction from '%1$s' at %2$s" +msgstr "Olet vastaanottanut kaverikutsun henkilöltä '%1$s' kohteessa %2$s" + +#: src/Navigation/Notifications/Repository/Notify.php:373 +#, php-format +msgid "You've received [url=%1$s]an introduction[/url] from %2$s." +msgstr "Olet vastaanottanut [url=%1$s]kaverikutsun[/url] henkilöltä %2$s." + +#: src/Navigation/Notifications/Repository/Notify.php:378 +#: src/Navigation/Notifications/Repository/Notify.php:424 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Voit vierailla hänen profiilissaan kohteessa %s" + +#: src/Navigation/Notifications/Repository/Notify.php:380 +#, php-format +msgid "Please visit %s to approve or reject the introduction." +msgstr "Hyväksy tai hylkää esittely %s-sivustossa" + +#: src/Navigation/Notifications/Repository/Notify.php:387 +#, php-format +msgid "%s A new person is sharing with you" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:389 +#: src/Navigation/Notifications/Repository/Notify.php:390 +#, php-format +msgid "%1$s is sharing with you at %2$s" +msgstr "%1$s jakaa päivityksensä kanssasi kohteessa %2$s" + +#: src/Navigation/Notifications/Repository/Notify.php:397 +#, php-format +msgid "%s You have a new follower" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:399 +#: src/Navigation/Notifications/Repository/Notify.php:400 +#, php-format +msgid "You have a new follower at %2$s : %1$s" +msgstr "Sinulla on uusi seuraaja sivustolla %2$s : %1$s" + +#: src/Navigation/Notifications/Repository/Notify.php:413 +#, php-format +msgid "%s Friend suggestion received" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:415 +#, php-format +msgid "You've received a friend suggestion from '%1$s' at %2$s" +msgstr "Sait kaverikutsun henkilöltä '%1$s' (%2$s)" + +#: src/Navigation/Notifications/Repository/Notify.php:416 +#, php-format +msgid "" +"You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." +msgstr "Sait [url=%1$s] kaveriehdotuksen[/url] %2$s käyttäjältä %3$s." + +#: src/Navigation/Notifications/Repository/Notify.php:422 +msgid "Name:" +msgstr "Nimi:" + +#: src/Navigation/Notifications/Repository/Notify.php:423 +msgid "Photo:" +msgstr "Kuva:" + +#: src/Navigation/Notifications/Repository/Notify.php:426 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Hyväksy tai hylkää ehdotus %s-sivustossa" + +#: src/Navigation/Notifications/Repository/Notify.php:434 +#: src/Navigation/Notifications/Repository/Notify.php:449 +#, php-format +msgid "%s Connection accepted" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:436 +#: src/Navigation/Notifications/Repository/Notify.php:451 +#, php-format +msgid "'%1$s' has accepted your connection request at %2$s" +msgstr "'%1$s' on hyväksynyt kaverikutsusi kohteessa %2$s" + +#: src/Navigation/Notifications/Repository/Notify.php:437 +#: src/Navigation/Notifications/Repository/Notify.php:452 +#, php-format +msgid "%2$s has accepted your [url=%1$s]connection request[/url]." +msgstr "%2$s hyväksyi [url=%1$s]kaverikutsusi[/url]." + +#: src/Navigation/Notifications/Repository/Notify.php:442 +msgid "" +"You are now mutual friends and may exchange status updates, photos, and " +"email without restriction." +msgstr "Olette nyt yhteiset ystävät ja voitte lähettää toisillenne tilapäivityksiä, kuvia ja sähköposteja ilman rajoituksia." + +#: src/Navigation/Notifications/Repository/Notify.php:444 +#, php-format +msgid "Please visit %s if you wish to make any changes to this relationship." +msgstr "Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta." + +#: src/Navigation/Notifications/Repository/Notify.php:457 +#, php-format +msgid "" +"'%1$s' has chosen to accept you a fan, which restricts some forms of " +"communication - such as private messaging and some profile interactions. If " +"this is a celebrity or community page, these settings were applied " +"automatically." +msgstr "'%1$s' on hyväksynyt sinut faniksi. Tämä rajoittaa joitain kommunikointitapoja - kuten yksityisviestiettely ja joitain profiilitoimintoja. Jos tämä on julkisuuden henkilö tai yhteisösivu, asetukset on valittu automaattisesti." + +#: src/Navigation/Notifications/Repository/Notify.php:459 +#, php-format +msgid "" +"'%1$s' may choose to extend this into a two-way or more permissive " +"relationship in the future." +msgstr "'%1$s' voi halutessaan laajentaa suhteenne kahdenväliseksi." + +#: src/Navigation/Notifications/Repository/Notify.php:461 +#, php-format +msgid "Please visit %s if you wish to make any changes to this relationship." +msgstr "Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta." + +#: src/Navigation/Notifications/Repository/Notify.php:471 +msgid "registration request" +msgstr "rekisteröintipyyntö" + +#: src/Navigation/Notifications/Repository/Notify.php:473 +#, php-format +msgid "You've received a registration request from '%1$s' at %2$s" +msgstr "Olet vastaanottanut rekisteröintipyynnön henkilöltä '%1$s' kohteessa %2$s" + +#: src/Navigation/Notifications/Repository/Notify.php:474 +#, php-format +msgid "You've received a [url=%1$s]registration request[/url] from %2$s." +msgstr "Olet vastaanottanut [url=%1$s]rekisteröintipyynnön[/url] henkilöltä %2$s." + +#: src/Navigation/Notifications/Repository/Notify.php:479 +#: src/Navigation/Notifications/Repository/Notify.php:500 +#, php-format +msgid "" +"Full Name:\t%s\n" +"Site Location:\t%s\n" +"Login Name:\t%s (%s)" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:485 +#, php-format +msgid "Please visit %s to approve or reject the request." +msgstr "Hyväksy tai hylkää pyyntö %s-sivustossa." + +#: src/Navigation/Notifications/Repository/Notify.php:492 +msgid "new registration" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:494 +#, php-format +msgid "You've received a new registration from '%1$s' at %2$s" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:495 +#, php-format +msgid "You've received a [url=%1$s]new registration[/url] from %2$s." +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:506 +#, php-format +msgid "Please visit %s to have a look at the new registration." +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:780 +#, php-format +msgid "%s %s tagged you" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:783 +#, php-format +msgid "%s %s shared a new post" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:791 +#, php-format +msgid "%1$s %2$s liked your post #%3$d" +msgstr "" + +#: src/Navigation/Notifications/Repository/Notify.php:794 +#, php-format +msgid "%1$s %2$s liked your comment on #%3$d" +msgstr "" + +#: src/Object/EMail/ItemCCEMail.php:42 +#, php-format +msgid "" +"This message was sent to you by %s, a member of the Friendica social " +"network." +msgstr "Viestin lähetti %s Friendica sosiaaliverkoston kautta." + +#: src/Object/EMail/ItemCCEMail.php:44 +#, php-format +msgid "You may visit them online at %s" +msgstr "" + +#: src/Object/EMail/ItemCCEMail.php:45 +msgid "" +"Please contact the sender by replying to this post if you do not wish to " +"receive these messages." +msgstr "" + +#: src/Object/EMail/ItemCCEMail.php:49 +#, php-format +msgid "%s posted an update." +msgstr "%s julkaisi päivityksen." + +#: src/Object/Post.php:135 +msgid "Private Message" +msgstr "Yksityisviesti" + +#: src/Object/Post.php:139 +msgid "Public Message" +msgstr "" + +#: src/Object/Post.php:143 +msgid "Unlisted Message" +msgstr "" + +#: src/Object/Post.php:178 msgid "This entry was edited" msgstr "Tämä kohde oli muokattu" -#: src/Object/Post.php:187 +#: src/Object/Post.php:206 +msgid "Connector Message" +msgstr "" + +#: src/Object/Post.php:222 src/Object/Post.php:224 +msgid "Edit" +msgstr "Muokkaa" + +#: src/Object/Post.php:248 msgid "Delete globally" msgstr "" -#: src/Object/Post.php:187 +#: src/Object/Post.php:248 msgid "Remove locally" msgstr "" -#: src/Object/Post.php:200 -msgid "save to folder" -msgstr "tallenna kansioon" +#: src/Object/Post.php:266 +#, php-format +msgid "Block %s" +msgstr "" -#: src/Object/Post.php:243 +#: src/Object/Post.php:271 +#, php-format +msgid "Ignore %s" +msgstr "" + +#: src/Object/Post.php:276 +#, php-format +msgid "Collapse %s" +msgstr "" + +#: src/Object/Post.php:281 +msgid "Save to folder" +msgstr "" + +#: src/Object/Post.php:316 msgid "I will attend" msgstr "Osallistun" -#: src/Object/Post.php:243 +#: src/Object/Post.php:316 msgid "I will not attend" msgstr "En aio osallistua" -#: src/Object/Post.php:243 +#: src/Object/Post.php:316 msgid "I might attend" msgstr "Ehkä osallistun" -#: src/Object/Post.php:271 -msgid "add star" -msgstr "lisää tähti" +#: src/Object/Post.php:346 +msgid "Ignore thread" +msgstr "" -#: src/Object/Post.php:272 -msgid "remove star" -msgstr "poista tähti" +#: src/Object/Post.php:347 +msgid "Unignore thread" +msgstr "" -#: src/Object/Post.php:273 -msgid "toggle star status" -msgstr "Tähtitila päälle/pois" +#: src/Object/Post.php:348 +msgid "Toggle ignore status" +msgstr "" -#: src/Object/Post.php:276 -msgid "starred" -msgstr "tähtimerkitty" +#: src/Object/Post.php:358 +msgid "Add star" +msgstr "" -#: src/Object/Post.php:282 -msgid "ignore thread" -msgstr "Sivuuta keskustelu" +#: src/Object/Post.php:359 +msgid "Remove star" +msgstr "" -#: src/Object/Post.php:283 -msgid "unignore thread" -msgstr "Seuraa keskustelua" +#: src/Object/Post.php:360 +msgid "Toggle star status" +msgstr "" -#: src/Object/Post.php:284 -msgid "toggle ignore status" -msgstr "Sivuuta/seuraa" +#: src/Object/Post.php:371 +msgid "Pin" +msgstr "" -#: src/Object/Post.php:293 -msgid "add tag" -msgstr "lisää tägi" - -#: src/Object/Post.php:304 -msgid "like" -msgstr "tykkää" - -#: src/Object/Post.php:305 -msgid "dislike" -msgstr "en tykkää" - -#: src/Object/Post.php:308 -msgid "Share this" -msgstr "Jaa tämä" - -#: src/Object/Post.php:308 -msgid "share" -msgstr "jaa" +#: src/Object/Post.php:372 +msgid "Unpin" +msgstr "" #: src/Object/Post.php:373 +msgid "Toggle pin status" +msgstr "" + +#: src/Object/Post.php:376 +msgid "Pinned" +msgstr "" + +#: src/Object/Post.php:381 +msgid "Add tag" +msgstr "" + +#: src/Object/Post.php:394 +msgid "Quote share this" +msgstr "" + +#: src/Object/Post.php:394 +msgid "Quote Share" +msgstr "" + +#: src/Object/Post.php:397 +msgid "Reshare this" +msgstr "" + +#: src/Object/Post.php:397 +msgid "Reshare" +msgstr "" + +#: src/Object/Post.php:398 +msgid "Cancel your Reshare" +msgstr "" + +#: src/Object/Post.php:398 +msgid "Unshare" +msgstr "" + +#: src/Object/Post.php:449 +#, php-format +msgid "%s (Received %s)" +msgstr "" + +#: src/Object/Post.php:454 +msgid "Comment this item on your system" +msgstr "" + +#: src/Object/Post.php:454 +msgid "Remote comment" +msgstr "" + +#: src/Object/Post.php:475 +msgid "Share via ..." +msgstr "" + +#: src/Object/Post.php:475 +msgid "Share via external services" +msgstr "" + +#: src/Object/Post.php:504 msgid "to" msgstr "henkilölle" -#: src/Object/Post.php:374 +#: src/Object/Post.php:505 msgid "via" msgstr "kautta" -#: src/Object/Post.php:375 +#: src/Object/Post.php:506 msgid "Wall-to-Wall" msgstr "Seinäjulkaisu" -#: src/Object/Post.php:376 +#: src/Object/Post.php:507 msgid "via Wall-To-Wall:" msgstr "seinäjulkaisun kautta" -#: src/Object/Post.php:435 +#: src/Object/Post.php:552 +#, php-format +msgid "Reply to %s" +msgstr "" + +#: src/Object/Post.php:555 +msgid "More" +msgstr "" + +#: src/Object/Post.php:573 +msgid "Notifier task is pending" +msgstr "" + +#: src/Object/Post.php:574 +msgid "Delivery to remote servers is pending" +msgstr "" + +#: src/Object/Post.php:575 +msgid "Delivery to remote servers is underway" +msgstr "" + +#: src/Object/Post.php:576 +msgid "Delivery to remote servers is mostly done" +msgstr "" + +#: src/Object/Post.php:577 +msgid "Delivery to remote servers is done" +msgstr "" + +#: src/Object/Post.php:597 #, php-format msgid "%d comment" msgid_plural "%d comments" msgstr[0] "%d kommentti" msgstr[1] "%d kommentteja" -#: src/Object/Post.php:805 -msgid "Bold" -msgstr "Lihavoitu" - -#: src/Object/Post.php:806 -msgid "Italic" -msgstr "Kursivoitu" - -#: src/Object/Post.php:807 -msgid "Underline" -msgstr "Alleviivaus" - -#: src/Object/Post.php:808 -msgid "Quote" -msgstr "Lainaus" - -#: src/Object/Post.php:809 -msgid "Code" -msgstr "Koodi" - -#: src/Object/Post.php:810 -msgid "Image" -msgstr "Kuva" - -#: src/Object/Post.php:811 -msgid "Link" -msgstr "Linkki" - -#: src/Object/Post.php:812 -msgid "Video" -msgstr "Video" - -#: src/App.php:526 -msgid "Delete this item?" -msgstr "Poista tämä kohde?" - -#: src/App.php:528 -msgid "show fewer" -msgstr "näytä vähemmän" - -#: src/App.php:1117 -msgid "No system theme config value set." +#: src/Object/Post.php:598 +msgid "Show more" msgstr "" -#: index.php:464 -msgid "toggle mobile" -msgstr "Mobiilisivusto päälle/pois" - -#: boot.php:796 -#, php-format -msgid "Update %s failed. See error logs." -msgstr "%s päivitys epäonnistui, katso virhelokit." - -#: update.php:193 -#, php-format -msgid "%s: Updating author-id and owner-id in item and thread table. " +#: src/Object/Post.php:599 +msgid "Show fewer" +msgstr "" + +#: src/Object/Post.php:635 +#, php-format +msgid "Reshared by: %s" +msgstr "" + +#: src/Object/Post.php:640 +#, php-format +msgid "Viewed by: %s" +msgstr "" + +#: src/Object/Post.php:645 +#, php-format +msgid "Liked by: %s" +msgstr "" + +#: src/Object/Post.php:650 +#, php-format +msgid "Disliked by: %s" +msgstr "" + +#: src/Object/Post.php:655 +#, php-format +msgid "Attended by: %s" +msgstr "" + +#: src/Object/Post.php:660 +#, php-format +msgid "Maybe attended by: %s" +msgstr "" + +#: src/Object/Post.php:665 +#, php-format +msgid "Not attended by: %s" +msgstr "" + +#: src/Object/Post.php:670 +#, php-format +msgid "Reacted with %s by: %s" +msgstr "" + +#: src/Protocol/Delivery.php:547 +msgid "(no subject)" +msgstr "" + +#: src/Protocol/OStatus.php:1388 +#, php-format +msgid "%s is now following %s." +msgstr "%s seuraa %s." + +#: src/Protocol/OStatus.php:1389 +msgid "following" +msgstr "seuraa" + +#: src/Protocol/OStatus.php:1392 +#, php-format +msgid "%s stopped following %s." +msgstr "%s ei enää seuraa %s." + +#: src/Protocol/OStatus.php:1393 +msgid "stopped following" +msgstr "ei enää seuraa" + +#: src/Render/FriendicaSmartyEngine.php:56 +#, php-format +msgid "The folder %s must be writable by webserver." +msgstr "" + +#: src/Security/Authentication.php:227 +msgid "Login failed." +msgstr "Kirjautuminen epäonnistui" + +#: src/Security/Authentication.php:272 +msgid "Login failed. Please check your credentials." +msgstr "" + +#: src/Security/Authentication.php:391 +#, php-format +msgid "Welcome %s" +msgstr "" + +#: src/Security/Authentication.php:392 +msgid "Please upload a profile photo." +msgstr "Lataa profiilikuva." + +#: src/Util/EMailer/MailBuilder.php:260 +msgid "Friendica Notification" +msgstr "" + +#: src/Util/EMailer/NotifyMailBuilder.php:78 +#: src/Util/EMailer/SystemMailBuilder.php:54 +#, php-format +msgid "%1$s, %2$s Administrator" +msgstr "" + +#: src/Util/EMailer/NotifyMailBuilder.php:80 +#: src/Util/EMailer/SystemMailBuilder.php:56 +#, php-format +msgid "%s Administrator" +msgstr "" + +#: src/Util/EMailer/NotifyMailBuilder.php:193 +#: src/Util/EMailer/NotifyMailBuilder.php:217 +#: src/Util/EMailer/SystemMailBuilder.php:101 +#: src/Util/EMailer/SystemMailBuilder.php:118 +msgid "thanks" +msgstr "" + +#: src/Util/Temporal.php:172 +msgid "YYYY-MM-DD or MM-DD" +msgstr "" + +#: src/Util/Temporal.php:280 +#, php-format +msgid "Time zone: %s Change in Settings" +msgstr "" + +#: src/Util/Temporal.php:320 src/Util/Temporal.php:329 +msgid "never" +msgstr "" + +#: src/Util/Temporal.php:343 +msgid "less than a second ago" +msgstr "" + +#: src/Util/Temporal.php:352 +msgid "year" +msgstr "" + +#: src/Util/Temporal.php:352 +msgid "years" +msgstr "" + +#: src/Util/Temporal.php:353 +msgid "months" +msgstr "" + +#: src/Util/Temporal.php:354 +msgid "weeks" +msgstr "" + +#: src/Util/Temporal.php:355 +msgid "days" +msgstr "" + +#: src/Util/Temporal.php:356 +msgid "hour" +msgstr "" + +#: src/Util/Temporal.php:356 +msgid "hours" +msgstr "" + +#: src/Util/Temporal.php:357 +msgid "minute" +msgstr "" + +#: src/Util/Temporal.php:357 +msgid "minutes" +msgstr "minuuttia" + +#: src/Util/Temporal.php:358 +msgid "second" +msgstr "" + +#: src/Util/Temporal.php:358 +msgid "seconds" +msgstr "" + +#: src/Util/Temporal.php:367 +#, php-format +msgid "in %1$d %2$s" +msgstr "" + +#: src/Util/Temporal.php:370 +#, php-format +msgid "%1$d %2$s ago" +msgstr "" + +#: src/Worker/PushSubscription.php:110 +msgid "Notification from Friendica" +msgstr "" + +#: src/Worker/PushSubscription.php:111 +msgid "Empty Post" +msgstr "" + +#: view/theme/duepuntozero/config.php:68 +msgid "default" +msgstr "" + +#: view/theme/duepuntozero/config.php:69 +msgid "greenzero" +msgstr "" + +#: view/theme/duepuntozero/config.php:70 +msgid "purplezero" +msgstr "" + +#: view/theme/duepuntozero/config.php:71 +msgid "easterbunny" +msgstr "" + +#: view/theme/duepuntozero/config.php:72 +msgid "darkzero" +msgstr "" + +#: view/theme/duepuntozero/config.php:73 +msgid "comix" +msgstr "" + +#: view/theme/duepuntozero/config.php:74 +msgid "slackr" +msgstr "" + +#: view/theme/duepuntozero/config.php:87 +msgid "Variations" +msgstr "" + +#: view/theme/frio/config.php:153 +msgid "Light (Accented)" +msgstr "" + +#: view/theme/frio/config.php:154 +msgid "Dark (Accented)" +msgstr "" + +#: view/theme/frio/config.php:155 +msgid "Black (Accented)" +msgstr "" + +#: view/theme/frio/config.php:167 +msgid "Note" +msgstr "" + +#: view/theme/frio/config.php:167 +msgid "Check image permissions if all users are allowed to see the image" +msgstr "" + +#: view/theme/frio/config.php:173 +msgid "Custom" +msgstr "" + +#: view/theme/frio/config.php:174 +msgid "Legacy" +msgstr "" + +#: view/theme/frio/config.php:175 +msgid "Accented" +msgstr "" + +#: view/theme/frio/config.php:176 +msgid "Select color scheme" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Select scheme accent" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Blue" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Red" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Purple" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Green" +msgstr "" + +#: view/theme/frio/config.php:177 +msgid "Pink" +msgstr "" + +#: view/theme/frio/config.php:178 +msgid "Copy or paste schemestring" +msgstr "" + +#: view/theme/frio/config.php:178 +msgid "" +"You can copy this string to share your theme with others. Pasting here " +"applies the schemestring" +msgstr "" + +#: view/theme/frio/config.php:179 +msgid "Navigation bar background color" +msgstr "" + +#: view/theme/frio/config.php:180 +msgid "Navigation bar icon color " +msgstr "" + +#: view/theme/frio/config.php:181 +msgid "Link color" +msgstr "" + +#: view/theme/frio/config.php:182 +msgid "Set the background color" +msgstr "" + +#: view/theme/frio/config.php:183 +msgid "Content background opacity" +msgstr "" + +#: view/theme/frio/config.php:184 +msgid "Set the background image" +msgstr "" + +#: view/theme/frio/config.php:185 +msgid "Background image style" +msgstr "" + +#: view/theme/frio/config.php:188 +msgid "Always open Compose page" +msgstr "" + +#: view/theme/frio/config.php:188 +msgid "" +"The New Post button always open the Compose page " +"instead of the modal form. When this is disabled, the Compose page can be " +"accessed with a middle click on the link or from the modal." +msgstr "" + +#: view/theme/frio/config.php:192 +msgid "Login page background image" +msgstr "" + +#: view/theme/frio/config.php:196 +msgid "Login page background color" +msgstr "" + +#: view/theme/frio/config.php:196 +msgid "Leave background image and color empty for theme defaults" +msgstr "" + +#: view/theme/frio/php/Image.php:39 +msgid "Top Banner" +msgstr "" + +#: view/theme/frio/php/Image.php:39 +msgid "" +"Resize image to the width of the screen and show background color below on " +"long pages." +msgstr "" + +#: view/theme/frio/php/Image.php:40 +msgid "Full screen" +msgstr "" + +#: view/theme/frio/php/Image.php:40 +msgid "" +"Resize image to fill entire screen, clipping either the right or the bottom." +msgstr "" + +#: view/theme/frio/php/Image.php:41 +msgid "Single row mosaic" +msgstr "" + +#: view/theme/frio/php/Image.php:41 +msgid "" +"Resize image to repeat it on a single row, either vertical or horizontal." +msgstr "" + +#: view/theme/frio/php/Image.php:42 +msgid "Mosaic" +msgstr "" + +#: view/theme/frio/php/Image.php:42 +msgid "Repeat image to fill the screen." +msgstr "" + +#: view/theme/frio/php/default.php:81 view/theme/frio/php/standard.php:40 +msgid "Skip to main content" +msgstr "" + +#: view/theme/frio/php/default.php:152 view/theme/frio/php/standard.php:75 +msgid "Back to top" +msgstr "" + +#: view/theme/frio/theme.php:211 +msgid "Guest" +msgstr "" + +#: view/theme/frio/theme.php:214 +msgid "Visitor" +msgstr "" + +#: view/theme/quattro/config.php:89 +msgid "Alignment" +msgstr "" + +#: view/theme/quattro/config.php:89 +msgid "Left" +msgstr "" + +#: view/theme/quattro/config.php:89 +msgid "Center" +msgstr "" + +#: view/theme/quattro/config.php:90 +msgid "Color scheme" +msgstr "" + +#: view/theme/quattro/config.php:91 +msgid "Posts font size" +msgstr "" + +#: view/theme/quattro/config.php:92 +msgid "Textareas font size" +msgstr "" + +#: view/theme/vier/config.php:91 +msgid "Comma separated list of helper groups" +msgstr "" + +#: view/theme/vier/config.php:131 +msgid "don't show" +msgstr "" + +#: view/theme/vier/config.php:131 +msgid "show" +msgstr "" + +#: view/theme/vier/config.php:137 +msgid "Set style" +msgstr "" + +#: view/theme/vier/config.php:138 +msgid "Community Pages" +msgstr "" + +#: view/theme/vier/config.php:139 view/theme/vier/theme.php:148 +msgid "Community Profiles" +msgstr "" + +#: view/theme/vier/config.php:140 +msgid "Help or @NewHere ?" +msgstr "" + +#: view/theme/vier/config.php:141 view/theme/vier/theme.php:319 +msgid "Connect Services" +msgstr "" + +#: view/theme/vier/config.php:142 +msgid "Find Friends" +msgstr "" + +#: view/theme/vier/config.php:143 view/theme/vier/theme.php:175 +msgid "Last users" +msgstr "" + +#: view/theme/vier/theme.php:234 +msgid "Quick Start" msgstr "" diff --git a/view/lang/fi-fi/strings.php b/view/lang/fi-fi/strings.php index cc02c4d2c..b9cd894a2 100644 --- a/view/lang/fi-fi/strings.php +++ b/view/lang/fi-fi/strings.php @@ -5,571 +5,10 @@ function string_plural_select_fi_fi($n){ $n = intval($n); return intval($n != 1); }} -$a->strings['Friendica Notification'] = 'Friendica-huomautus'; -$a->strings['Thank You,'] = 'Kiitos,'; -$a->strings['%s Administrator'] = '%s Ylläpitäjä'; -$a->strings['%1$s, %2$s Administrator'] = '%1$s, %2$s Ylläpitäjä'; -$a->strings['[Friendica:Notify] New mail received at %s'] = '[Friendica:Notify] Uusi viesti, katso %s'; -$a->strings['%1$s sent you a new private message at %2$s.'] = '%1$s lähetti sinulle uuden yksityisviestin kohteessa %2$s.'; -$a->strings['a private message'] = 'yksityisviesti'; -$a->strings['%1$s sent you %2$s.'] = '%1$s lähetti sinulle %2$s.'; -$a->strings['Please visit %s to view and/or reply to your private messages.'] = 'Katso yksityisviestisi kohteessa %s.'; -$a->strings['%1$s commented on [url=%2$s]a %3$s[/url]'] = '%1$s kommentoi [url=%2$s] %3$s[/url]'; -$a->strings['[Friendica:Notify] Comment to conversation #%1$d by %2$s'] = '[Friendica:Notify] %2$s kommentoi keskustelussa #%1$d'; -$a->strings['%s commented on an item/conversation you have been following.'] = '%s kommentoi kohteessa/keskustelussa jota seuraat.'; -$a->strings['Please visit %s to view and/or reply to the conversation.'] = 'Käy %s nähdäksesi keskustelun ja/tai vastataksesi siihen'; -$a->strings['[Friendica:Notify] %s posted to your profile wall'] = '[Friendica:Notify] %s kirjoitti profiiliseinällesi'; -$a->strings['%1$s posted to your profile wall at %2$s'] = '%1$s kirjoitti seinällesi kohteessa %2$s'; -$a->strings['%1$s posted to [url=%2$s]your wall[/url]'] = '%1$s kirjoitti [url=%2$s]seinällesi[/url]'; -$a->strings['[Friendica:Notify] %s tagged you'] = '[Friendica:Notify] %s merkitsi sinut'; -$a->strings['%1$s tagged you at %2$s'] = '%1$s merkitsi sinut kohteessa %2$s'; -$a->strings['%1$s [url=%2$s]tagged you[/url].'] = '%1$s [url=%2$s]merkitsi sinut[/url].'; -$a->strings['[Friendica:Notify] %s shared a new post'] = '[Friendica:Notify] %s jakoi uuden julkaisun'; -$a->strings['%1$s shared a new post at %2$s'] = '%1$s jakoi uuden julkaisun %2$s'; -$a->strings['%1$s [url=%2$s]shared a post[/url].'] = '%1$s [url=%2$s]jakoi julkaisun[/url].'; -$a->strings['[Friendica:Notify] %1$s poked you'] = '[Friendica:Notify] %1$s tökkäsi sinua.'; -$a->strings['%1$s poked you at %2$s'] = '%1$s tökkäsi sinua kohteessa %2$s'; -$a->strings['%1$s [url=%2$s]poked you[/url].'] = '%1$s [url=%2$s]tökkasi sinua[/url].'; -$a->strings['[Friendica:Notify] %s tagged your post'] = '[Friendica:Notify] %s merkitsi julkaisusi'; -$a->strings['%1$s tagged your post at %2$s'] = '%1$s merkitsi julkaisusi kohteessa %2$s'; -$a->strings['%1$s tagged [url=%2$s]your post[/url]'] = '%1$s merkitsi [url=%2$s]julkaisusi[/url]'; -$a->strings['[Friendica:Notify] Introduction received'] = '[Friendica:Notify] Esittely vastaanotettu'; -$a->strings['You\'ve received an introduction from \'%1$s\' at %2$s'] = 'Olet vastaanottanut kaverikutsun henkilöltä \'%1$s\' kohteessa %2$s'; -$a->strings['You\'ve received [url=%1$s]an introduction[/url] from %2$s.'] = 'Olet vastaanottanut [url=%1$s]kaverikutsun[/url] henkilöltä %2$s.'; -$a->strings['You may visit their profile at %s'] = 'Voit vierailla hänen profiilissaan kohteessa %s'; -$a->strings['Please visit %s to approve or reject the introduction.'] = 'Hyväksy tai hylkää esittely %s-sivustossa'; -$a->strings['[Friendica:Notify] A new person is sharing with you'] = '[Friendica:Notify] Uusi henkilö jakaa päivityksensä kanssasi'; -$a->strings['%1$s is sharing with you at %2$s'] = '%1$s jakaa päivityksensä kanssasi kohteessa %2$s'; -$a->strings['[Friendica:Notify] You have a new follower'] = '[Friendica:Notify] Sinulla on uusi seuraaja'; -$a->strings['You have a new follower at %2$s : %1$s'] = 'Sinulla on uusi seuraaja sivustolla %2$s : %1$s'; -$a->strings['[Friendica:Notify] Friend suggestion received'] = '[Friendica:Notify] Kaveripyyntö vastaanotettu'; -$a->strings['You\'ve received a friend suggestion from \'%1$s\' at %2$s'] = 'Sait kaverikutsun henkilöltä \'%1$s\' (%2$s)'; -$a->strings['You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.'] = 'Sait [url=%1$s] kaveriehdotuksen[/url] %2$s käyttäjältä %3$s.'; -$a->strings['Name:'] = 'Nimi:'; -$a->strings['Photo:'] = 'Kuva:'; -$a->strings['Please visit %s to approve or reject the suggestion.'] = 'Hyväksy tai hylkää ehdotus %s-sivustossa'; -$a->strings['[Friendica:Notify] Connection accepted'] = '[Friendica:Notify] Yhteys hyväksytty'; -$a->strings['\'%1$s\' has accepted your connection request at %2$s'] = '\'%1$s\' on hyväksynyt kaverikutsusi kohteessa %2$s'; -$a->strings['%2$s has accepted your [url=%1$s]connection request[/url].'] = '%2$s hyväksyi [url=%1$s]kaverikutsusi[/url].'; -$a->strings['You are now mutual friends and may exchange status updates, photos, and email without restriction.'] = 'Olette nyt yhteiset ystävät ja voitte lähettää toisillenne tilapäivityksiä, kuvia ja sähköposteja ilman rajoituksia.'; -$a->strings['Please visit %s if you wish to make any changes to this relationship.'] = 'Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta.'; -$a->strings['\'%1$s\' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically.'] = '\'%1$s\' on hyväksynyt sinut faniksi. Tämä rajoittaa joitain kommunikointitapoja - kuten yksityisviestiettely ja joitain profiilitoimintoja. Jos tämä on julkisuuden henkilö tai yhteisösivu, asetukset on valittu automaattisesti.'; -$a->strings['\'%1$s\' may choose to extend this into a two-way or more permissive relationship in the future.'] = '\'%1$s\' voi halutessaan laajentaa suhteenne kahdenväliseksi.'; -$a->strings['Please visit %s if you wish to make any changes to this relationship.'] = 'Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta.'; -$a->strings['[Friendica System Notify]'] = '[Friendica Järjestelmäilmoitus]'; -$a->strings['registration request'] = 'rekisteröintipyyntö'; -$a->strings['You\'ve received a registration request from \'%1$s\' at %2$s'] = 'Olet vastaanottanut rekisteröintipyynnön henkilöltä \'%1$s\' kohteessa %2$s'; -$a->strings['You\'ve received a [url=%1$s]registration request[/url] from %2$s.'] = 'Olet vastaanottanut [url=%1$s]rekisteröintipyynnön[/url] henkilöltä %2$s.'; -$a->strings['Full Name: %1$s\nSite Location: %2$s\nLogin Name: %3$s (%4$s)'] = 'Koko nimi: %1$s\nSivusto: %2$s\nKäyttäjätunnus: %3$s (%4$s)'; -$a->strings['Please visit %s to approve or reject the request.'] = 'Hyväksy tai hylkää pyyntö %s-sivustossa.'; -$a->strings['Daily posting limit of %d post reached. The post was rejected.'] = [ - 0 => 'Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', - 1 => 'Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', -]; -$a->strings['Weekly posting limit of %d post reached. The post was rejected.'] = [ - 0 => 'Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', - 1 => 'Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', -]; -$a->strings['Monthly posting limit of %d post reached. The post was rejected.'] = 'Kuukausittainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.'; -$a->strings['Profile Photos'] = 'Profiilin valokuvat'; -$a->strings['event'] = 'tapahtuma'; -$a->strings['status'] = 'tila'; -$a->strings['photo'] = 'kuva'; -$a->strings['%1$s likes %2$s\'s %3$s'] = '%1$s tykkää käyttäjän %2$s %3$s'; -$a->strings['%1$s attends %2$s\'s %3$s'] = '%1$s osallistuu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['%1$s doesn\'t attend %2$s\'s %3$s'] = '%1$s ei osallistu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['%1$s attends maybe %2$s\'s %3$s'] = '%1$s ehkä osallistuu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['%1$s is now friends with %2$s'] = '%1$s ja %2$s ovat kavereita'; -$a->strings['%1$s poked %2$s'] = '%1$s tökkäsi %2$s'; -$a->strings['post/item'] = 'julkaisu/kohde'; -$a->strings['Likes'] = 'Tykkäyksiä'; -$a->strings['Dislikes'] = 'Inhokit'; -$a->strings['Attending'] = [ - 0 => 'Osallistuu', - 1 => 'Osallistuu', -]; -$a->strings['Not attending'] = 'Ei osallistu'; -$a->strings['Might attend'] = 'Ehkä'; -$a->strings['Select'] = 'Valitse'; -$a->strings['Delete'] = 'Poista'; -$a->strings['View %s\'s profile @ %s'] = 'Katso %s-henkilön profiilia @ %s'; -$a->strings['Categories:'] = 'Luokat:'; -$a->strings['Filed under:'] = 'Arkistoitu kansioon:'; -$a->strings['%s from %s'] = '%s sovelluksesta %s'; -$a->strings['View in context'] = 'Näytä kontekstissa'; -$a->strings['Please wait'] = 'Odota'; -$a->strings['remove'] = 'poista'; -$a->strings['Delete Selected Items'] = 'Poista valitut kohteet'; -$a->strings['Follow Thread'] = 'Seuraa ketjua'; -$a->strings['View Status'] = 'Näytä tila'; -$a->strings['View Profile'] = 'Näytä profiilia'; -$a->strings['View Photos'] = 'Näytä kuvia'; -$a->strings['Network Posts'] = 'Uutisvirtajulkaisut'; -$a->strings['View Contact'] = 'Näytä kontaktia'; -$a->strings['Send PM'] = 'Lähetä yksityisviesti'; -$a->strings['Poke'] = 'Tökkää'; -$a->strings['Connect/Follow'] = 'Yhdistä/Seuraa'; -$a->strings['%s likes this.'] = '%s tykkää tästä.'; -$a->strings['%s doesn\'t like this.'] = '%s ei tykkää tästä.'; -$a->strings['%s attends.'] = '%s osallistuu.'; -$a->strings['%s doesn\'t attend.'] = '%s ei osallistu.'; -$a->strings['%s attends maybe.'] = '%s ehkä osallistuu.'; -$a->strings['and'] = 'ja'; -$a->strings['and %d other people'] = 'ja %d muuta ihmistä'; -$a->strings['%2$d people like this'] = '%2$d ihmistä tykkää tästä'; -$a->strings['%s like this.'] = '%s tykkää tästä.'; -$a->strings['%2$d people don\'t like this'] = '%2$d ihmistä ei tykkää tästä.'; -$a->strings['%s don\'t like this.'] = '%s ei tykkää tästä.'; -$a->strings['%2$d people attend'] = '%2$d ihmistä osallistuu'; -$a->strings['%s attend.'] = '%s osallistuu.'; -$a->strings['%2$d people don\'t attend'] = '%2$d ihmistä ei osallistu'; -$a->strings['%s don\'t attend.'] = '%s ei osallistu.'; -$a->strings['%2$d people attend maybe'] = '%2$d ihmistä ehkä osallistuu'; -$a->strings['%s attend maybe.'] = '%s ehkä osallistuu.'; -$a->strings['Visible to everybody'] = 'Näkyy kaikille'; -$a->strings['Please enter a link URL:'] = 'Lisää URL-linkki:'; -$a->strings['Please enter a video link/URL:'] = 'Lisää video URL-linkki:'; -$a->strings['Please enter an audio link/URL:'] = 'Lisää ääni URL-linkki:'; -$a->strings['Tag term:'] = 'Tunniste:'; -$a->strings['Save to Folder:'] = 'Tallenna kansioon:'; -$a->strings['Where are you right now?'] = 'Mikä on sijaintisi?'; -$a->strings['Delete item(s)?'] = 'Poista kohde/kohteet?'; -$a->strings['New Post'] = 'Uusi julkaisu'; -$a->strings['Share'] = 'Jaa'; -$a->strings['Upload photo'] = 'Lähetä kuva'; -$a->strings['upload photo'] = 'lähetä kuva'; -$a->strings['Attach file'] = 'Liitä tiedosto'; -$a->strings['attach file'] = 'liitä tiedosto'; -$a->strings['Insert web link'] = 'Lisää linkki'; -$a->strings['web link'] = 'WWW-linkki'; -$a->strings['Insert video link'] = 'Lisää videolinkki'; -$a->strings['video link'] = 'videolinkki'; -$a->strings['Insert audio link'] = 'Lisää äänilinkki'; -$a->strings['audio link'] = 'äänilinkki'; -$a->strings['Set your location'] = 'Aseta sijaintisi'; -$a->strings['set location'] = 'aseta sijainti'; -$a->strings['Clear browser location'] = 'Tyhjennä selaimen sijainti'; -$a->strings['clear location'] = 'tyhjennä sijainti'; -$a->strings['Set title'] = 'Aseta otsikko'; -$a->strings['Categories (comma-separated list)'] = 'Luokat (pilkuilla eroteltu luettelo)'; -$a->strings['Permission settings'] = 'Käyttöoikeusasetukset'; -$a->strings['permissions'] = 'käyttöoikeudet'; -$a->strings['Public post'] = 'Julkinen viesti'; -$a->strings['Preview'] = 'Esikatselu'; -$a->strings['Cancel'] = 'Peru'; -$a->strings['Post to Groups'] = 'Lähetä ryhmiin'; -$a->strings['Post to Contacts'] = 'Lähetä kontakteille'; -$a->strings['Private post'] = 'Yksityinen julkaisu'; -$a->strings['Message'] = 'Viesti'; -$a->strings['Browser'] = 'Selain'; -$a->strings['View all'] = 'Näytä kaikki'; -$a->strings['Like'] = [ - 0 => 'Tykkäys', - 1 => 'Tykkäyksiä', -]; -$a->strings['Dislike'] = [ - 0 => 'Inhokki', - 1 => 'Inhokit', -]; -$a->strings['Not Attending'] = [ - 0 => 'Ei osallistu', - 1 => 'Ei osallistu', -]; -$a->strings['Undecided'] = [ - 0 => 'En ole varma', - 1 => 'En ole varma', -]; +$a->strings['Unable to locate original post.'] = 'Alkuperäinen julkaisu ei löydy.'; +$a->strings['Empty post discarded.'] = 'Tyhjä julkaisu hylätty.'; $a->strings['Item not found.'] = 'Kohdetta ei löytynyt.'; -$a->strings['Do you really want to delete this item?'] = 'Haluatko varmasti poistaa tämän kohteen?'; -$a->strings['Yes'] = 'Kyllä'; $a->strings['Permission denied.'] = 'Käyttöoikeus evätty.'; -$a->strings['Archives'] = 'Arkisto'; -$a->strings['show more'] = 'näytä lisää'; -$a->strings['Welcome '] = 'Tervetuloa'; -$a->strings['Please upload a profile photo.'] = 'Lataa profiilikuva.'; -$a->strings['Welcome back '] = 'Tervetuloa takaisin'; -$a->strings['The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it.'] = 'Lomakkeen turvallisuusavain oli väärin. Tämä voi johtua siitä, että lomake on ollut avoinna liian kauan (>3 tuntia) ennen sen lähettämistä.'; -$a->strings['newer'] = 'uudempi'; -$a->strings['older'] = 'vanhempi'; -$a->strings['first'] = 'ensimmäinen'; -$a->strings['prev'] = 'edellinen'; -$a->strings['next'] = 'seuraava'; -$a->strings['last'] = 'viimeinen'; -$a->strings['Loading more entries...'] = 'Merkinnät ladataan...'; -$a->strings['The end'] = 'Loppu'; -$a->strings['No contacts'] = 'Ei kontakteja'; -$a->strings['%d Contact'] = [ - 0 => '%d kontakti', - 1 => '%d kontakteja', -]; -$a->strings['View Contacts'] = 'Näytä kontaktit'; -$a->strings['Save'] = 'Tallenna'; -$a->strings['Follow'] = 'Seuraa'; -$a->strings['Search'] = 'Haku'; -$a->strings['@name, !forum, #tags, content'] = '@nimi, !foorumi, #tunnisteet, sisältö'; -$a->strings['Full Text'] = 'Koko teksti'; -$a->strings['Tags'] = 'Tunnisteet'; -$a->strings['Contacts'] = 'Yhteystiedot'; -$a->strings['Forums'] = 'Foorumit'; -$a->strings['poke'] = 'töki'; -$a->strings['poked'] = 'tökkäsi'; -$a->strings['ping'] = 'pingaa'; -$a->strings['pinged'] = 'pingasi'; -$a->strings['prod'] = 'töki'; -$a->strings['prodded'] = 'tökkäsi'; -$a->strings['slap'] = 'läimäytä'; -$a->strings['slapped'] = 'läimäsi'; -$a->strings['finger'] = 'näytä keskisormea'; -$a->strings['fingered'] = 'näytti keskisormea'; -$a->strings['rebuff'] = 'torju'; -$a->strings['rebuffed'] = 'torjui'; -$a->strings['Monday'] = 'Maanantai'; -$a->strings['Tuesday'] = 'Tiistai'; -$a->strings['Wednesday'] = 'Keskiviikko'; -$a->strings['Thursday'] = 'Torstai'; -$a->strings['Friday'] = 'Perjantai'; -$a->strings['Saturday'] = 'Lauantai'; -$a->strings['Sunday'] = 'Sunnuntai'; -$a->strings['January'] = 'Tammikuu'; -$a->strings['February'] = 'Helmikuu'; -$a->strings['March'] = 'Maaliskuu'; -$a->strings['April'] = 'Huhtikuu'; -$a->strings['May'] = 'Toukokuu'; -$a->strings['June'] = 'Kesäkuu'; -$a->strings['July'] = 'Heinäkuu'; -$a->strings['August'] = 'Elokuu'; -$a->strings['September'] = 'Syyskuu'; -$a->strings['October'] = 'Lokakuu'; -$a->strings['November'] = 'Marraskuu'; -$a->strings['December'] = 'Joulukuu'; -$a->strings['Mon'] = 'Ma'; -$a->strings['Tue'] = 'Ti'; -$a->strings['Wed'] = 'Ke'; -$a->strings['Thu'] = 'To'; -$a->strings['Fri'] = 'Pe'; -$a->strings['Sat'] = 'La'; -$a->strings['Sun'] = 'Su'; -$a->strings['Jan'] = 'Tam.'; -$a->strings['Feb'] = 'Hel.'; -$a->strings['Mar'] = 'Maa.'; -$a->strings['Apr'] = 'Huh.'; -$a->strings['Jul'] = 'Tou.'; -$a->strings['Aug'] = 'Elo.'; -$a->strings['Sep'] = 'Syy.'; -$a->strings['Oct'] = 'Lok.'; -$a->strings['Nov'] = 'Mar.'; -$a->strings['Dec'] = 'Jou.'; -$a->strings['Content warning: %s'] = 'Sisältövaroitus: %s'; -$a->strings['View Video'] = 'Katso video'; -$a->strings['bytes'] = 'tavua'; -$a->strings['Click to open/close'] = 'Klikkaa auki/kiinni'; -$a->strings['View on separate page'] = 'Katso erillisellä sivulla'; -$a->strings['view on separate page'] = 'katso erillisellä sivulla'; -$a->strings['link to source'] = 'linkki lähteeseen'; -$a->strings['activity'] = 'toiminta'; -$a->strings['comment'] = [ - 0 => 'kommentoi', - 1 => 'kommentoi', -]; -$a->strings['post'] = 'julkaisu'; -$a->strings['Item filed'] = 'Kohde arkistoitu'; -$a->strings['No friends to display.'] = 'Ei näytettäviä kavereita.'; -$a->strings['Connect'] = 'Yhdistä'; -$a->strings['Authorize application connection'] = 'Vahvista sovellusyhteys'; -$a->strings['Return to your app and insert this Securty Code:'] = 'Palaa takaisin sovellukseen ja lisää tämä turvakoodi:'; -$a->strings['Please login to continue.'] = 'Ole hyvä ja kirjaudu jatkaaksesi.'; -$a->strings['Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'] = 'Haluatko antaa tälle sovellukselle luvan hakea viestejäsi ja yhteystietojasi ja/tai luoda uusia viestejä?'; -$a->strings['No'] = 'Ei'; -$a->strings['You must be logged in to use addons. '] = 'Sinun pitää kirjautua sisään, jotta voit käyttää lisäosia'; -$a->strings['Applications'] = 'Sovellukset'; -$a->strings['No installed applications.'] = 'Ei asennettuja sovelluksia.'; -$a->strings['Item not available.'] = 'Kohde ei saatavilla.'; -$a->strings['Item was not found.'] = 'Kohdetta ei löytynyt.'; -$a->strings['No contacts in common.'] = 'Ei yhteisiä kontakteja.'; -$a->strings['Common Friends'] = 'Yhteisiä kavereita'; -$a->strings['Credits'] = 'Lopputekstit'; -$a->strings['Photos'] = 'Kuvat'; -$a->strings['Contact Photos'] = 'Kontaktin valokuvat'; -$a->strings['Upload'] = 'Lähetä'; -$a->strings['Files'] = 'Tiedostot'; -$a->strings['Not Found'] = 'Ei löydetty'; -$a->strings['No profile'] = 'Ei profiilia'; -$a->strings['Welcome to %s'] = 'Tervetuloa %s'; -$a->strings['Remote privacy information not available.'] = 'Yksityisyyden etätietoja ei saatavilla.'; -$a->strings['Visible to:'] = 'Näkyvissä:'; -$a->strings['System down for maintenance'] = 'Järjestelmä poiskytketty huoltoa varten'; -$a->strings['Welcome to Friendica'] = 'Tervetuloa Friendicaan'; -$a->strings['New Member Checklist'] = 'Uuden jäsenen tarkistuslista'; -$a->strings['Getting Started'] = 'Ensiaskeleet'; -$a->strings['Friendica Walk-Through'] = 'Friendica -läpikäynti'; -$a->strings['Settings'] = 'Asetukset'; -$a->strings['Go to Your Settings'] = 'Omat Asetukset'; -$a->strings['Profile'] = 'Profiili'; -$a->strings['Upload Profile Photo'] = 'Lataa profiilikuva'; -$a->strings['Edit Your Profile'] = 'Muokkaa profiilisi'; -$a->strings['Profile Keywords'] = 'Profiilin avainsanat'; -$a->strings['Connecting'] = 'Yhdistetään'; -$a->strings['Importing Emails'] = 'Sähköpostin tuominen'; -$a->strings['Go to Your Contacts Page'] = 'Näytä minun kontaktit'; -$a->strings['Go to Your Site\'s Directory'] = 'Näytä oman sivuston luettelo'; -$a->strings['Finding New People'] = 'Kavereiden hankkiminen'; -$a->strings['Groups'] = 'Ryhmät'; -$a->strings['Group Your Contacts'] = 'Järjestä kontaktit ryhmiin'; -$a->strings['Why Aren\'t My Posts Public?'] = 'Miksi julkaisuni eivät ole julkisia?'; -$a->strings['Getting Help'] = 'Avun saaminen'; -$a->strings['Go to the Help Section'] = 'Näytä ohjeet'; -$a->strings['Visit %s\'s profile [%s]'] = 'Näytä %s-käyttäjän profiili [%s]'; -$a->strings['Edit contact'] = 'Muokkaa kontaktia'; -$a->strings['Contacts who are not members of a group'] = 'Kontaktit jotka eivät kuulu ryhmään'; -$a->strings['Not Extended'] = 'Ei laajennettu'; -$a->strings['Resubscribing to OStatus contacts'] = 'OStatus -kontaktien uudelleentilaus'; -$a->strings['Error'] = 'Virhe'; -$a->strings['Done'] = 'Valmis'; -$a->strings['Keep this window open until done.'] = 'Pidä tämä ikkuna auki kunnes kaikki tehtävät on suoritettu.'; -$a->strings['Do you really want to delete this suggestion?'] = 'Haluatko varmasti poistaa ehdotuksen?'; -$a->strings['No suggestions available. If this is a new site, please try again in 24 hours.'] = 'Ehdotuksia ei löydy. Jos tämä on uusi sivusto, kokeile uudelleen vuorokauden kuluttua.'; -$a->strings['Ignore/Hide'] = 'Jätä huomiotta/piilota'; -$a->strings['Friend Suggestions'] = 'Ystäväehdotukset'; -$a->strings['This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'] = 'Sivuston päivittäinen rekisteröintiraja ylitetty. Yritä uudelleen huomenna.'; -$a->strings['Import'] = 'Tuo'; -$a->strings['Move account'] = 'Siirrä tili'; -$a->strings['You can import an account from another Friendica server.'] = 'Voit tuoda käyttäjätilin toiselta Friendica -palvelimelta.'; -$a->strings['This feature is experimental. We can\'t import contacts from the OStatus network (GNU Social/Statusnet) or from Diaspora'] = 'Tämä on kokeellinen ominaisuus. Emme voi tuoda kontakteja OStatus-verkolta (GNU social/Statusnet) tai Diasporalta.'; -$a->strings['Account file'] = 'Tilitiedosto'; -$a->strings['No keywords to match. Please add keywords to your default profile.'] = 'Avainsanat puuttuu. Lisää avainsanoja oletusprofiiliisi.'; -$a->strings['is interested in:'] = 'on kiinnostunut seuraavista aiheista:'; -$a->strings['Profile Match'] = 'Vastaavien profiilien haku'; -$a->strings['No matches'] = 'Ei täsmääviä profiileja'; -$a->strings['Manage Identities and/or Pages'] = 'Hallitse identiteetit ja/tai sivut'; -$a->strings['Select an identity to manage: '] = 'Valitse identiteetti hallitavaksi:'; -$a->strings['Submit'] = 'Lähetä'; -$a->strings['Invalid request.'] = 'Virheellinen pyyntö.'; -$a->strings['Or - did you try to upload an empty file?'] = 'Yrititkö ladata tyhjän tiedoston?'; -$a->strings['File exceeds size limit of %s'] = 'Tiedosto ylittää kokorajoituksen %s'; -$a->strings['File upload failed.'] = 'Tiedoston lähettäminen epäonnistui.'; -$a->strings['- select -'] = '- valitse -'; -$a->strings['l F d, Y \@ g:i A'] = 'l j.n.Y \@ H:i'; -$a->strings['Time Conversion'] = 'Aikamuunnos'; -$a->strings['UTC time: %s'] = 'UTC-aika: %s'; -$a->strings['Current timezone: %s'] = 'Aikavyöhyke: %s'; -$a->strings['Converted localtime: %s'] = 'Muunnettu paikallisaika: %s'; -$a->strings['Please select your timezone:'] = 'Valitse aikavyöhykkeesi:'; -$a->strings['No more system notifications.'] = 'Ei enää järjestelmäilmoituksia.'; -$a->strings['System Notifications'] = 'Järjestelmäilmoitukset'; -$a->strings['{0} wants to be your friend'] = '{0} lähetti kaveripyynnön'; -$a->strings['{0} sent you a message'] = '{0} lähetti sinulle viestin'; -$a->strings['{0} requested registration'] = '{0} jätti rekisteröintipyynnön'; -$a->strings['Poke/Prod'] = 'Tökkää'; -$a->strings['Recipient'] = 'Vastaanottaja'; -$a->strings['Choose what you wish to do to recipient'] = 'Valitse mitä haluat tehdä vastaanottajalle'; -$a->strings['Make this post private'] = 'Muuta julkaisu yksityiseksi'; -$a->strings['Public access denied.'] = 'Julkinen käyttö estetty.'; -$a->strings['Permission denied'] = 'Käyttöoikeus evätty'; -$a->strings['Invalid profile identifier.'] = 'Virheellinen profiilitunniste.'; -$a->strings['Profile Visibility Editor'] = 'Profiilin näkyvyyden muokkaaminen'; -$a->strings['Click on a contact to add or remove.'] = 'Valitse kontakti, jota haluat poistaa tai lisätä.'; -$a->strings['Visible To'] = 'Näkyvyys'; -$a->strings['Account approved.'] = 'Tili hyväksytty.'; -$a->strings['Please login.'] = 'Ole hyvä ja kirjaudu.'; -$a->strings['Tag removed'] = 'Tägi poistettiin'; -$a->strings['Remove Item Tag'] = 'Poista tägi'; -$a->strings['Select a tag to remove: '] = 'Valitse tägi poistamista varten:'; -$a->strings['Remove'] = 'Poista'; -$a->strings['Export account'] = 'Vie tili'; -$a->strings['Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.'] = 'Vie tilin tiedot ja yhteystiedot. Käytä tätä tilisi varmuuskopiointiin ja/tai siirtämiseen toiselle palvelimelle.'; -$a->strings['Export all'] = 'Vie kaikki'; -$a->strings['Export your accout info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account (photos are not exported)'] = 'Vie tilin tiedot, yhteystiedot ja kaikki nimikkeesi json-muodossa. Saattaa luoda hyvin suuren tiedoston ja kestää todella pitkään. Tämän avulla voit ottaa täydellisen varmuuskopion tilistäsi (valokuvia ei viedä)'; -$a->strings['Export personal data'] = 'Vie henkilökohtaiset tiedot'; -$a->strings['No contacts.'] = 'Ei kontakteja.'; -$a->strings['Access denied.'] = 'Käyttö estetty.'; -$a->strings['Image exceeds size limit of %s'] = 'Kuva ylittää kokorajoituksen %s'; -$a->strings['Unable to process image.'] = 'Kuvan käsitteleminen epäonnistui.'; -$a->strings['Wall Photos'] = 'Seinäkuvat'; -$a->strings['Image upload failed.'] = 'Kuvan lähettäminen epäonnistui.'; -$a->strings['Number of daily wall messages for %s exceeded. Message failed.'] = '%s-käyttäjän päivittäinen seinäviestiraja ylitetty. Viestin lähettäminen epäonnistui.'; -$a->strings['No recipient selected.'] = 'Vastaanottaja puuttuu.'; -$a->strings['Unable to check your home location.'] = 'Kotisijaintisi ei voitu tarkistaa.'; -$a->strings['Message could not be sent.'] = 'Viestiä ei voitu lähettää.'; -$a->strings['Message collection failure.'] = 'Viestin noutaminen epäonnistui.'; -$a->strings['Message sent.'] = 'Viesti lähetetty.'; -$a->strings['No recipient.'] = 'Vastaanottaja puuttuu.'; -$a->strings['Send Private Message'] = 'Lähetä yksityisviesti'; -$a->strings['To:'] = 'Vastaanottaja:'; -$a->strings['Subject:'] = 'Aihe:'; -$a->strings['Your message:'] = 'Viestisi:'; -$a->strings['Login'] = 'Kirjaudu sisään'; -$a->strings['The post was created'] = 'Julkaisu luotu'; -$a->strings['Item not found'] = 'Kohdetta ei löytynyt'; -$a->strings['Edit post'] = 'Muokkaa viestiä'; -$a->strings['CC: email addresses'] = 'Kopio: sähköpostiosoitteet'; -$a->strings['Example: bob@example.com, mary@example.com'] = 'Esimerkki: bob@example.com, mary@example.com'; -$a->strings['Contact not found.'] = 'Kontaktia ei ole.'; -$a->strings['Friend suggestion sent.'] = 'Ystäväehdotus lähetettiin.'; -$a->strings['Suggest Friends'] = 'Ehdota ystäviä'; -$a->strings['Suggest a friend for %s'] = 'Ehdota ystävää ystävälle %s'; -$a->strings['Access to this profile has been restricted.'] = 'Pääsy tähän profiiliin on rajoitettu'; -$a->strings['Events'] = 'Tapahtumat'; -$a->strings['View'] = 'Katso'; -$a->strings['Previous'] = 'Edellinen'; -$a->strings['Next'] = 'Seuraava'; -$a->strings['today'] = 'tänään'; -$a->strings['month'] = 'kuukausi'; -$a->strings['week'] = 'viikko'; -$a->strings['day'] = 'päivä'; -$a->strings['list'] = 'luettelo'; -$a->strings['User not found'] = 'Käyttäjää ei löydy'; -$a->strings['This calendar format is not supported'] = 'Tätä kalenteriformaattia ei tueta'; -$a->strings['No exportable data found'] = 'Vientikelpoista dataa ei löytynyt'; -$a->strings['calendar'] = 'kalenteri'; -$a->strings['Network:'] = 'Uutisvirta:'; -$a->strings['%d contact edited.'] = [ - 0 => '%d kontakti muokattu', - 1 => '%d kontakteja muokattu', -]; -$a->strings['Could not access contact record.'] = 'Yhteystietoon ei päästä käsiksi.'; -$a->strings['Could not locate selected profile.'] = 'Valittua profiilia ei löydy.'; -$a->strings['Contact updated.'] = 'Yhteystietopäivitys onnistui.'; -$a->strings['Failed to update contact record.'] = 'Kontaktitietojen päivitys epäonnistui.'; -$a->strings['Contact has been blocked'] = 'Henkilö on estetty'; -$a->strings['Contact has been unblocked'] = 'Henkilö on jälleen sallittu'; -$a->strings['Contact has been ignored'] = 'Henkilöä ei enää huomioida'; -$a->strings['Contact has been unignored'] = 'Henkilö on jälleen huomioituna.'; -$a->strings['Contact has been archived'] = 'Henkilö on arkistoitu.'; -$a->strings['Contact has been unarchived'] = 'Henkilö on otettu pois arkistosta.'; -$a->strings['Drop contact'] = 'Poista kontakti'; -$a->strings['Do you really want to delete this contact?'] = 'Haluatko todella poistaa tämän yhteystiedon?'; -$a->strings['Contact has been removed.'] = 'Yhteystieto on poistettu.'; -$a->strings['You are mutual friends with %s'] = 'Olet kaveri %s kanssa.'; -$a->strings['You are sharing with %s'] = 'Olet jakanut jotakin %s:n kanssa'; -$a->strings['%s is sharing with you'] = '%s jakaa sinulle jotakin.'; -$a->strings['Private communications are not available for this contact.'] = 'Yksityiskeskustelu ei ole käytettävissä tälle henkilölle.'; -$a->strings['Never'] = 'Ei koskaan'; -$a->strings['(Update was successful)'] = '(Päivitys onnistui)'; -$a->strings['(Update was not successful)'] = '(Päivitys epäonnistui)'; -$a->strings['Suggest friends'] = 'Ehdota ystäviä'; -$a->strings['Network type: %s'] = 'Verkkotyyppi: %s'; -$a->strings['Communications lost with this contact!'] = 'Yhteys tähän henkilöön menetettiin!'; -$a->strings['Disabled'] = 'Pois käytöstä'; -$a->strings['Fetch information'] = 'Nouda tiedot'; -$a->strings['Fetch keywords'] = 'Nouda avainsanat'; -$a->strings['Fetch information and keywords'] = 'Nouda tiedot ja avainsanat'; -$a->strings['Disconnect/Unfollow'] = 'Katkaise / Lopeta seuraaminen'; -$a->strings['Contact'] = 'Kontakti'; -$a->strings['Profile Visibility'] = 'Profiilin näkyvyys'; -$a->strings['Please choose the profile you would like to display to %s when viewing your profile securely.'] = 'Valitse profiili, jonka haluat näyttää %s:lle, kun hän haluaa katsoa profiiliasi turvallisesti.'; -$a->strings['Contact Information / Notes'] = 'Yhteystiedot / Muistiinpanot'; -$a->strings['Edit contact notes'] = 'Muokkaa yhteystietojen muistiinpanoja'; -$a->strings['Block/Unblock contact'] = 'Estä/salli henkilö'; -$a->strings['Ignore contact'] = 'Jätä henkilö huomiotta'; -$a->strings['Repair URL settings'] = 'Korjaa URL-asetukset'; -$a->strings['View conversations'] = 'Katso keskusteluja'; -$a->strings['Last update:'] = 'Viimeksi päivitetty:'; -$a->strings['Update public posts'] = 'Päivitä julkiset postaukset'; -$a->strings['Update now'] = 'Päivitä nyt'; -$a->strings['Unblock'] = 'Salli'; -$a->strings['Block'] = 'Estä'; -$a->strings['Unignore'] = 'Ota huomioon'; -$a->strings['Ignore'] = 'Jätä huomiotta'; -$a->strings['Currently blocked'] = 'Estetty tällä hetkellä'; -$a->strings['Currently ignored'] = 'Jätetty huomiotta tällä hetkellä'; -$a->strings['Currently archived'] = 'Arkistoitu tällä hetkellä'; -$a->strings['Awaiting connection acknowledge'] = 'Odotetaan yhteyden kuittausta'; -$a->strings['Hide this contact from others'] = 'Piilota kontakti muilta'; -$a->strings['Notification for new posts'] = 'Uusien postausten ilmoitus'; -$a->strings['Send a notification of every new post of this contact'] = 'Lähetä ilmoitus tälle henkilölle kaikista uusista postauksista'; -$a->strings['Blacklisted keywords'] = 'Kielletyt avainsanat'; -$a->strings['Profile URL'] = 'Profiilin URL'; -$a->strings['Location:'] = 'Sijainti:'; -$a->strings['XMPP:'] = 'XMPP:'; -$a->strings['About:'] = 'Lisätietoja:'; -$a->strings['Tags:'] = 'Tunnisteet:'; -$a->strings['Actions'] = 'Toimenpiteet'; -$a->strings['Status'] = 'Tila'; -$a->strings['Contact Settings'] = 'Yhteystietoasetukset'; -$a->strings['Suggestions'] = 'Ehdotukset'; -$a->strings['Suggest potential friends'] = 'Ehdota mahdollisille ystäville'; -$a->strings['All Contacts'] = 'Kaikki yhteystiedot'; -$a->strings['Show all contacts'] = 'Näytä kaikki yhteystiedot'; -$a->strings['Unblocked'] = 'Sallittu'; -$a->strings['Only show unblocked contacts'] = 'Näytä vain sallitut henkilöt'; -$a->strings['Blocked'] = 'Estetty'; -$a->strings['Only show blocked contacts'] = 'Näytä vain estetyt henkilöt'; -$a->strings['Ignored'] = 'Jätetty huomiotta'; -$a->strings['Only show ignored contacts'] = 'Näytä vain henkilöt, jotka jätetty huomiotta'; -$a->strings['Archived'] = 'Arkistoitu'; -$a->strings['Only show archived contacts'] = 'Näytä vain arkistoidut henkilöt'; -$a->strings['Hidden'] = 'Piilotettu'; -$a->strings['Only show hidden contacts'] = 'Näytä vain piilotetut henkilöt'; -$a->strings['Search your contacts'] = 'Etsi henkilöitä'; -$a->strings['Results for: %s'] = 'Tulokset haulla: %s'; -$a->strings['Find'] = 'Etsi'; -$a->strings['Update'] = 'Päivitä'; -$a->strings['Archive'] = 'Arkistoi'; -$a->strings['Unarchive'] = 'Poista arkistosta'; -$a->strings['Status Messages and Posts'] = 'Statusviestit ja postaukset'; -$a->strings['Profile Details'] = 'Profiilitiedot'; -$a->strings['View all contacts'] = 'Näytä kaikki kontaktit'; -$a->strings['View all common friends'] = 'Näytä kaikki yhteiset kaverit'; -$a->strings['Advanced Contact Settings'] = 'Kontakti-lisäasetukset'; -$a->strings['Mutual Friendship'] = 'Yhteinen kaveruus'; -$a->strings['is a fan of yours'] = 'on fanisi'; -$a->strings['you are a fan of'] = 'fanitat'; -$a->strings['This is you'] = 'Tämä olet sinä'; -$a->strings['Toggle Blocked status'] = 'Estetty tila päälle/pois'; -$a->strings['Toggle Ignored status'] = 'Sivuuta/seuraa'; -$a->strings['Toggle Archive status'] = 'Arkistotila päälle/pois'; -$a->strings['Delete contact'] = 'Poista kontakti'; -$a->strings['Save Settings'] = 'Tallenna asetukset'; -$a->strings['Delegate Page Management'] = 'Delegoi sivunhallinta'; -$a->strings['Delegates'] = 'Valtuutetut'; -$a->strings['Existing Page Delegates'] = 'Sivun valtuutetut'; -$a->strings['Potential Delegates'] = 'Mahdolliset valtuutetut'; -$a->strings['Add'] = 'Lisää'; -$a->strings['No entries.'] = 'Ei kohteita.'; -$a->strings['You must be logged in to use this module'] = 'Sinun pitää kirjautua sisään, jotta voit käyttää tätä moduulia'; -$a->strings['Source URL'] = 'Lähde URL'; -$a->strings['Post successful.'] = 'Viestin lähetys onnistui.'; -$a->strings['Subscribing to OStatus contacts'] = 'OStatus -kontaktien tilaaminen'; -$a->strings['No contact provided.'] = 'Kontakti puuttuu.'; -$a->strings['Couldn\'t fetch information for contact.'] = 'Kontaktin tietoja ei voitu hakea.'; -$a->strings['Couldn\'t fetch friends for contact.'] = 'Ei voitu hakea kontaktin kaverit.'; -$a->strings['success'] = 'onnistui'; -$a->strings['failed'] = 'epäonnistui'; -$a->strings['ignored'] = 'ohitettu'; -$a->strings['Image uploaded but image cropping failed.'] = 'Kuva ladattu mutta kuvan rajaus epäonnistui.'; -$a->strings['Image size reduction [%s] failed.'] = 'Kuvan pienentäminen [%s] epäonnistui.'; -$a->strings['Shift-reload the page or clear browser cache if the new photo does not display immediately.'] = 'Jos kuva ei näy heti, lataa sivu uudelleen tai tyhjennä selaimen välimuisti.'; -$a->strings['Unable to process image'] = 'Kuvan käsitteleminen epäonnistui'; -$a->strings['Upload File:'] = 'Lähetä tiedosto:'; -$a->strings['Select a profile:'] = 'Valitse profiili:'; -$a->strings['or'] = 'tai'; -$a->strings['skip this step'] = 'ohita tämä vaihe'; -$a->strings['select a photo from your photo albums'] = 'valitse kuva albumeistasi'; -$a->strings['Crop Image'] = 'Rajaa kuva'; -$a->strings['Please adjust the image cropping for optimum viewing.'] = 'Rajaa kuva sopivasti.'; -$a->strings['Done Editing'] = 'Lopeta muokkaus'; -$a->strings['Image uploaded successfully.'] = 'Kuvan lähettäminen onnistui.'; -$a->strings['Contact unfollowed'] = 'Kontaktia ei enää seurata'; -$a->strings['Submit Request'] = 'Lähetä pyyntö'; -$a->strings['You aren\'t a friend of this contact.'] = 'Et ole kontaktin kaveri.'; -$a->strings['Unfollowing is currently not supported by your network.'] = 'Seuraamisen lopettaminen ei tällä hetkellä tueta verkossasi.'; -$a->strings['Your Identity Address:'] = 'Identiteettisi osoite:'; -$a->strings['Gender:'] = 'Sukupuoli:'; -$a->strings['Status:'] = 'Tila:'; -$a->strings['Homepage:'] = 'Kotisivu:'; -$a->strings['Global Directory'] = 'Maailmanlaajuinen hakemisto'; -$a->strings['Results for:'] = 'Tulokset haulla:'; -$a->strings['Site Directory'] = 'Sivuston luettelo'; -$a->strings['People Search - %s'] = 'Käyttäjähaku - %s'; -$a->strings['Forum Search - %s'] = 'Foorumihaku - %s'; -$a->strings['The contact could not be added.'] = 'Kontaktia ei voitu lisätä.'; -$a->strings['You already added this contact.'] = 'Olet jo lisännyt tämän kontaktin.'; -$a->strings['Diaspora support isn\'t enabled. Contact can\'t be added.'] = 'Diaspora -tuki ei ole käytössä. Kontaktia ei voi lisätä.'; -$a->strings['OStatus support is disabled. Contact can\'t be added.'] = 'OStatus -tuki ei ole käytössä. Kontaktia ei voi lisätä.'; -$a->strings['The network type couldn\'t be detected. Contact can\'t be added.'] = 'Verkkotyyppiä ei voitu havaita. Kontaktia ei voitu lisätä.'; -$a->strings['Please answer the following:'] = 'Vastaa seuraavaan:'; -$a->strings['Does %s know you?'] = 'Tunteeko %s sinut?'; -$a->strings['Add a personal note:'] = 'Lisää oma merkintä:'; $a->strings['No valid account found.'] = 'Voimassa olevaa tiliä ei löytynyt.'; $a->strings['Password reset request issued. Check your email.'] = 'Salasanan nollauspyyntö lähetetty. Tarkista sähköpostisi.'; $a->strings['Password reset requested at %s'] = 'Salasanan nollauspyyntö kohteessa %s'; @@ -603,6 +42,768 @@ $a->strings[' Voit vaihtaa salasanasi kirjautumisen jälkeen asetussivulta. '; $a->strings['Your password has been changed at %s'] = 'Salasanasi on vaihdettu sivustolla %s'; +$a->strings['New Message'] = 'Uusi viesti'; +$a->strings['No recipient selected.'] = 'Vastaanottaja puuttuu.'; +$a->strings['Unable to locate contact information.'] = 'Kontaktin tiedot ei löydy.'; +$a->strings['Message could not be sent.'] = 'Viestiä ei voitu lähettää.'; +$a->strings['Message collection failure.'] = 'Viestin noutaminen epäonnistui.'; +$a->strings['Discard'] = 'Hylkää'; +$a->strings['Messages'] = 'Viestit'; +$a->strings['Please enter a link URL:'] = 'Lisää URL-linkki:'; +$a->strings['Send Private Message'] = 'Lähetä yksityisviesti'; +$a->strings['To:'] = 'Vastaanottaja:'; +$a->strings['Subject:'] = 'Aihe:'; +$a->strings['Your message:'] = 'Viestisi:'; +$a->strings['Upload photo'] = 'Lähetä kuva'; +$a->strings['Insert web link'] = 'Lisää linkki'; +$a->strings['Please wait'] = 'Odota'; +$a->strings['Submit'] = 'Lähetä'; +$a->strings['No messages.'] = 'Ei viestejä.'; +$a->strings['Message not available.'] = 'Viesti ei saatavilla.'; +$a->strings['Delete message'] = 'Poista viesti'; +$a->strings['D, d M Y - g:i A'] = 'D, j.n.Y - H:i'; +$a->strings['Delete conversation'] = 'Poista keskustelu'; +$a->strings['Send Reply'] = 'Lähetä vastaus'; +$a->strings['Unknown sender - %s'] = 'Tuntematon lähettäjä - %s'; +$a->strings['You and %s'] = 'Sinä ja %s'; +$a->strings['%s and You'] = '%s ja sinä'; +$a->strings['%d message'] = [ + 0 => '%d viesti', + 1 => '%d viestiä', +]; +$a->strings['Personal Notes'] = 'Henkilökohtaiset tiedot'; +$a->strings['Save'] = 'Tallenna'; +$a->strings['Photo Albums'] = 'Valokuva-albumit'; +$a->strings['Recent Photos'] = 'Viimeaikaisia kuvia'; +$a->strings['Upload New Photos'] = 'Lähetä uusia kuvia'; +$a->strings['everybody'] = 'kaikki'; +$a->strings['Contact information unavailable'] = 'Kontaktin tietoja ei saatavilla'; +$a->strings['Album not found.'] = 'Albumia ei ole.'; +$a->strings['a photo'] = 'valokuva'; +$a->strings['%1$s was tagged in %2$s by %3$s'] = '%1$s merkattiin kuvaan %2$s ystävän %3$s toimesta'; +$a->strings['Public access denied.'] = 'Julkinen käyttö estetty.'; +$a->strings['No photos selected'] = 'Ei valittuja kuvia'; +$a->strings['Upload Photos'] = 'Lähetä kuvia'; +$a->strings['New album name: '] = 'Albumin uusi nimi: '; +$a->strings['Do not show a status post for this upload'] = 'Älä näytä tilaviestiä tälle lähetykselle'; +$a->strings['Permissions'] = 'Käyttöoikeudet'; +$a->strings['Do you really want to delete this photo album and all its photos?'] = 'Haluatko varmasti poistaa tämän albumin ja kaikki sen kuvat?'; +$a->strings['Delete Album'] = 'Poista albumi'; +$a->strings['Cancel'] = 'Peru'; +$a->strings['Edit Album'] = 'Muokkaa albumia'; +$a->strings['Show Newest First'] = 'Näytä uusin ensin'; +$a->strings['Show Oldest First'] = 'Näytä vanhin ensin'; +$a->strings['View Photo'] = 'Näytä kuva'; +$a->strings['Permission denied. Access to this item may be restricted.'] = 'Estetty. Tämän kohteen käyttöä on saatettu rajoittaa.'; +$a->strings['Photo not available'] = 'Kuva ei ole saatavilla'; +$a->strings['Do you really want to delete this photo?'] = 'Haluatko varmasti poistaa kuvan?'; +$a->strings['Delete Photo'] = 'Poista valokuva'; +$a->strings['View photo'] = 'Näytä kuva'; +$a->strings['Edit photo'] = 'Muokkaa kuvaa'; +$a->strings['Use as profile photo'] = 'Käytä profiilikuvana'; +$a->strings['View Full Size'] = 'Näytä täysikokoisena'; +$a->strings['Tags: '] = 'Merkinnät:'; +$a->strings['New album name'] = 'Uusi nimi albumille'; +$a->strings['Caption'] = 'Kuvateksti'; +$a->strings['Add a Tag'] = 'Lisää merkintä'; +$a->strings['Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'] = 'Esimerkki: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'; +$a->strings['Do not rotate'] = 'Älä kierrä'; +$a->strings['Rotate CW (right)'] = 'Käännä oikealle'; +$a->strings['Rotate CCW (left)'] = 'Käännä vasemmalle'; +$a->strings['This is you'] = 'Tämä olet sinä'; +$a->strings['Comment'] = 'Kommentti'; +$a->strings['Preview'] = 'Esikatselu'; +$a->strings['Select'] = 'Valitse'; +$a->strings['Delete'] = 'Poista'; +$a->strings['I like this (toggle)'] = 'Tykkään tästä (vaihda)'; +$a->strings['I don\'t like this (toggle)'] = 'En tykkää tästä (vaihda)'; +$a->strings['Map'] = 'Kartta'; +$a->strings['Delete this item?'] = 'Poista tämä kohde?'; +$a->strings['toggle mobile'] = 'Mobiilisivusto päälle/pois'; +$a->strings['Page not found.'] = 'Sivua ei löytynyt.'; +$a->strings['You must be logged in to use addons. '] = 'Sinun pitää kirjautua sisään, jotta voit käyttää lisäosia'; +$a->strings['The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it.'] = 'Lomakkeen turvallisuusavain oli väärin. Tämä voi johtua siitä, että lomake on ollut avoinna liian kauan (>3 tuntia) ennen sen lähettämistä.'; +$a->strings['The contact has been blocked from the node'] = 'Kontakti on estetty tällä solmulla'; +$a->strings['User not found'] = 'Käyttäjää ei löydy'; +$a->strings['Enter new password: '] = 'Syötä uusi salasana:'; +$a->strings['Password update failed. Please try again.'] = 'Salasanan vaihto epäonnistui. Yritä uudelleen.'; +$a->strings['Password changed.'] = 'Salasana vaihdettu.'; +$a->strings['newer'] = 'uudempi'; +$a->strings['older'] = 'vanhempi'; +$a->strings['Frequently'] = 'Usein'; +$a->strings['Hourly'] = 'Tunneittain'; +$a->strings['Twice daily'] = 'Kahdesti päivässä'; +$a->strings['Daily'] = 'Päivittäin'; +$a->strings['Weekly'] = 'Viikottain'; +$a->strings['Monthly'] = 'Kuukausittain'; +$a->strings['OStatus'] = 'OStatus'; +$a->strings['RSS/Atom'] = 'RSS/Atom'; +$a->strings['Email'] = 'Sähköposti'; +$a->strings['Diaspora'] = 'Diaspora'; +$a->strings['Zot!'] = 'Zot!'; +$a->strings['LinkedIn'] = 'LinkedIn'; +$a->strings['XMPP/IM'] = 'XMPP/IM'; +$a->strings['MySpace'] = 'MySpace'; +$a->strings['Google+'] = 'Google+'; +$a->strings['pump.io'] = 'pump.io'; +$a->strings['Twitter'] = 'Twitter'; +$a->strings['Diaspora Connector'] = 'Diaspora -liitin'; +$a->strings['GNU Social Connector'] = 'GNU social -liitin'; +$a->strings['pnut'] = 'pnut'; +$a->strings['and'] = 'ja'; +$a->strings['and %d other people'] = 'ja %d muuta ihmistä'; +$a->strings['Visible to everybody'] = 'Näkyy kaikille'; +$a->strings['Tag term:'] = 'Tunniste:'; +$a->strings['Save to Folder:'] = 'Tallenna kansioon:'; +$a->strings['Where are you right now?'] = 'Mikä on sijaintisi?'; +$a->strings['Delete item(s)?'] = 'Poista kohde/kohteet?'; +$a->strings['New Post'] = 'Uusi julkaisu'; +$a->strings['Share'] = 'Jaa'; +$a->strings['upload photo'] = 'lähetä kuva'; +$a->strings['Attach file'] = 'Liitä tiedosto'; +$a->strings['attach file'] = 'liitä tiedosto'; +$a->strings['Bold'] = 'Lihavoitu'; +$a->strings['Italic'] = 'Kursivoitu'; +$a->strings['Underline'] = 'Alleviivaus'; +$a->strings['Quote'] = 'Lainaus'; +$a->strings['Code'] = 'Koodi'; +$a->strings['Image'] = 'Kuva'; +$a->strings['Link'] = 'Linkki'; +$a->strings['Set your location'] = 'Aseta sijaintisi'; +$a->strings['set location'] = 'aseta sijainti'; +$a->strings['Clear browser location'] = 'Tyhjennä selaimen sijainti'; +$a->strings['clear location'] = 'tyhjennä sijainti'; +$a->strings['Set title'] = 'Aseta otsikko'; +$a->strings['Categories (comma-separated list)'] = 'Luokat (pilkuilla eroteltu luettelo)'; +$a->strings['Permission settings'] = 'Käyttöoikeusasetukset'; +$a->strings['Public post'] = 'Julkinen viesti'; +$a->strings['Message'] = 'Viesti'; +$a->strings['Browser'] = 'Selain'; +$a->strings['View %s\'s profile @ %s'] = 'Katso %s-henkilön profiilia @ %s'; +$a->strings['Categories:'] = 'Luokat:'; +$a->strings['Filed under:'] = 'Arkistoitu kansioon:'; +$a->strings['%s from %s'] = '%s sovelluksesta %s'; +$a->strings['View in context'] = 'Näytä kontekstissa'; +$a->strings['remove'] = 'poista'; +$a->strings['Delete Selected Items'] = 'Poista valitut kohteet'; +$a->strings['General Features'] = 'Yleiset ominaisuudet'; +$a->strings['Photo Location'] = 'Kuvan sijainti'; +$a->strings['Photo metadata is normally stripped. This extracts the location (if present) prior to stripping metadata and links it to a map.'] = 'Kuvan metadata poistetaan normaalisti. Tämä ottaa paikkatiedon (jos olemassa) ennen poistoa ja linkittää sen karttaan.'; +$a->strings['Post Composition Features'] = 'Kirjoittamisen ominaisuudet'; +$a->strings['Post/Comment Tools'] = 'Julkaisu/kommentti työkalut'; +$a->strings['Post Categories'] = 'Julkaisuluokat'; +$a->strings['Add categories to your posts'] = 'Luokittele julkaisusi'; +$a->strings['Advanced Profile Settings'] = 'Profiilin lisäasetukset'; +$a->strings['Tag Cloud'] = 'Tunnistepilvi'; +$a->strings['Provide a personal tag cloud on your profile page'] = 'Näytä henkilökohtainen tunnistepilvi profiilisivullasi'; +$a->strings['Display Membership Date'] = 'Näytä liittymispäivämäärä'; +$a->strings['Display membership date in profile'] = 'Näytä liittymispäivämäärä profiilissa'; +$a->strings['show more'] = 'näytä lisää'; +$a->strings['event'] = 'tapahtuma'; +$a->strings['status'] = 'tila'; +$a->strings['photo'] = 'kuva'; +$a->strings['Follow Thread'] = 'Seuraa ketjua'; +$a->strings['View Status'] = 'Näytä tila'; +$a->strings['View Profile'] = 'Näytä profiilia'; +$a->strings['View Photos'] = 'Näytä kuvia'; +$a->strings['Network Posts'] = 'Uutisvirtajulkaisut'; +$a->strings['View Contact'] = 'Näytä kontaktia'; +$a->strings['Send PM'] = 'Lähetä yksityisviesti'; +$a->strings['Block'] = 'Estä'; +$a->strings['Ignore'] = 'Jätä huomiotta'; +$a->strings['Connect/Follow'] = 'Yhdistä/Seuraa'; +$a->strings['Nothing new here'] = 'Täällä ei ole mitään uutta'; +$a->strings['Clear notifications'] = 'Tyhjennä ilmoitukset'; +$a->strings['Logout'] = 'Kirjaudu ulos'; +$a->strings['End this session'] = 'Lopeta istunto'; +$a->strings['Login'] = 'Kirjaudu sisään'; +$a->strings['Sign in'] = 'Kirjaudu sisään'; +$a->strings['Profile'] = 'Profiili'; +$a->strings['Your profile page'] = 'Oma profiilisivu'; +$a->strings['Photos'] = 'Kuvat'; +$a->strings['Your photos'] = 'Omat kuvat'; +$a->strings['Calendar'] = 'Kalenteri'; +$a->strings['Personal notes'] = 'Henkilökohtaiset merkinnät'; +$a->strings['Your personal notes'] = 'Henkilökohtaiset merkintäsi'; +$a->strings['Home'] = 'Koti'; +$a->strings['Home Page'] = 'Kotisivu'; +$a->strings['Register'] = 'Rekisteröidy'; +$a->strings['Create an account'] = 'Luo tili'; +$a->strings['Help'] = 'Ohje'; +$a->strings['Help and documentation'] = 'Ohjeet ja dokmentointi'; +$a->strings['Apps'] = 'Sovellukset'; +$a->strings['Addon applications, utilities, games'] = 'Lisäosa sovelluksia, apuohjelmia, pelejä'; +$a->strings['Search'] = 'Haku'; +$a->strings['Search site content'] = 'Sivustohaku'; +$a->strings['Full Text'] = 'Koko teksti'; +$a->strings['Tags'] = 'Tunnisteet'; +$a->strings['Contacts'] = 'Yhteystiedot'; +$a->strings['Community'] = 'Yhteisö'; +$a->strings['Conversations on this and other servers'] = 'Keskustelut täällä ja muilla palvelimilla'; +$a->strings['Directory'] = 'Luettelo'; +$a->strings['People directory'] = 'Henkilöluettelo'; +$a->strings['Information'] = 'Tietoja'; +$a->strings['Information about this friendica instance'] = 'Lisätietoja tästä Friendica -instanssista'; +$a->strings['Terms of Service'] = 'Käyttöehdot'; +$a->strings['Network'] = 'Uutisvirta'; +$a->strings['Conversations from your friends'] = 'Kavereiden keskustelut'; +$a->strings['Your posts and conversations'] = 'Omat julkaisut ja keskustelut'; +$a->strings['Introductions'] = 'Esittelyt'; +$a->strings['Friend Requests'] = 'Kaveripyynnöt'; +$a->strings['Notifications'] = 'Huomautukset'; +$a->strings['See all notifications'] = 'Näytä kaikki ilmoitukset'; +$a->strings['Mark as seen'] = 'Merkitse luetuksi'; +$a->strings['Private mail'] = 'Yksityinen posti'; +$a->strings['Inbox'] = 'Saapuneet'; +$a->strings['Outbox'] = 'Lähtevät'; +$a->strings['Manage other pages'] = 'Hallitse muita sivuja'; +$a->strings['Settings'] = 'Asetukset'; +$a->strings['Account settings'] = 'Tiliasetukset'; +$a->strings['Manage/edit friends and contacts'] = 'Hallitse/muokkaa kaverit ja kontaktit'; +$a->strings['Admin'] = 'Ylläpitäjä'; +$a->strings['Site setup and configuration'] = 'Sivuston asennus ja asetukset'; +$a->strings['Navigation'] = 'Navigointi'; +$a->strings['Site map'] = 'Sivustokartta'; +$a->strings['Embedding disabled'] = 'Upottaminen poistettu käytöstä'; +$a->strings['Embedded content'] = 'Upotettu sisältö'; +$a->strings['first'] = 'ensimmäinen'; +$a->strings['prev'] = 'edellinen'; +$a->strings['next'] = 'seuraava'; +$a->strings['last'] = 'viimeinen'; +$a->strings['Image/photo'] = 'Kuva/valokuva'; +$a->strings['Click to open/close'] = 'Klikkaa auki/kiinni'; +$a->strings['$1 wrote:'] = '$1 kirjoitti:'; +$a->strings['Encrypted content'] = 'Salattu sisältö'; +$a->strings['Invalid source protocol'] = 'Virheellinen lähdeprotokolla'; +$a->strings['Invalid link protocol'] = 'Virheellinen linkkiprotokolla'; +$a->strings['Loading more entries...'] = 'Merkinnät ladataan...'; +$a->strings['The end'] = 'Loppu'; +$a->strings['Follow'] = 'Seuraa'; +$a->strings['Add New Contact'] = 'Lisää uusi kontakti'; +$a->strings['Enter address or web location'] = 'Syötä verkko-osoite'; +$a->strings['Example: bob@example.com, http://example.com/barbara'] = 'Esimerkki: bob@example.com, http://example.com/barbara'; +$a->strings['Connect'] = 'Yhdistä'; +$a->strings['%d invitation available'] = [ + 0 => '%d kutsu saatavilla', + 1 => '%d kutsuja saatavilla', +]; +$a->strings['Find People'] = 'Löydä ihmisiä'; +$a->strings['Enter name or interest'] = 'Syötä nimi tai harrastus'; +$a->strings['Examples: Robert Morgenstein, Fishing'] = 'Esim. Matti Meikäläinen, kalastus yms.'; +$a->strings['Find'] = 'Etsi'; +$a->strings['Friend Suggestions'] = 'Ystäväehdotukset'; +$a->strings['Similar Interests'] = 'Yhteiset harrastukset'; +$a->strings['Random Profile'] = 'Satunnainen profiili'; +$a->strings['Invite Friends'] = 'Kutsu kavereita'; +$a->strings['Global Directory'] = 'Maailmanlaajuinen hakemisto'; +$a->strings['Local Directory'] = 'Paikallinen hakemisto'; +$a->strings['All Contacts'] = 'Kaikki yhteystiedot'; +$a->strings['Saved Folders'] = 'Tallennetut kansiot'; +$a->strings['Everything'] = 'Kaikki'; +$a->strings['Categories'] = 'Luokat'; +$a->strings['%d contact in common'] = [ + 0 => '%d yhteinen kontakti', + 1 => '%d yhteistä kontaktia', +]; +$a->strings['Archives'] = 'Arkisto'; +$a->strings['News'] = 'Uutiset'; +$a->strings['Account Types'] = 'Tilityypit'; +$a->strings['Export'] = 'Vie'; +$a->strings['Export calendar as ical'] = 'Vie kalenteri ical -tiedostona'; +$a->strings['Export calendar as csv'] = 'Vie kalenteri csv-tiedostona'; +$a->strings['No contacts'] = 'Ei kontakteja'; +$a->strings['%d Contact'] = [ + 0 => '%d kontakti', + 1 => '%d kontakteja', +]; +$a->strings['View Contacts'] = 'Näytä kontaktit'; +$a->strings['Remove term'] = 'Poista kohde'; +$a->strings['Saved Searches'] = 'Tallennetut haut'; +$a->strings['XMPP:'] = 'XMPP:'; +$a->strings['Location:'] = 'Sijainti:'; +$a->strings['Network:'] = 'Uutisvirta:'; +$a->strings['Post to Email'] = 'Viesti sähköpostiin'; +$a->strings['CC: email addresses'] = 'Kopio: sähköpostiosoitteet'; +$a->strings['Example: bob@example.com, mary@example.com'] = 'Esimerkki: bob@example.com, mary@example.com'; +$a->strings['You may need to import the file "database.sql" manually using phpmyadmin or mysql.'] = 'Sinun on ehkä tuotava tiedosto "database.sql" manuaalisesti käyttämällä phpMyAdminia tai MySQL:ää.'; +$a->strings['Could not find a command line version of PHP in the web server PATH.'] = 'Komentoriviversiota PHP:stä ei löytynyt web-palvelimen PATH:ista.'; +$a->strings['PHP executable path'] = 'Polku PHP-ohjelmaan'; +$a->strings['Enter full path to php executable. You can leave this blank to continue the installation.'] = 'Kirjoita koko polku PHP-ohjelmaan. Voit jättää sen tyhjäksi, jos haluat jatkaa asennusta.'; +$a->strings['Command line PHP'] = 'Komentorivi-PHP'; +$a->strings['Found PHP version: '] = 'PHP-versio löydetty:'; +$a->strings['PHP cli binary'] = 'PHP cli -binääritiedosto'; +$a->strings['The command line version of PHP on your system does not have "register_argc_argv" enabled.'] = 'Järjestelmäsi komentorivi-PHP:ssä ei ole käytössä asetusta "register_argc_argv".'; +$a->strings['This is required for message delivery to work.'] = 'Asetus vaaditaan viestien lähettämiseen.'; +$a->strings['PHP register_argc_argv'] = 'PHP register_argc_argv'; +$a->strings['Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'] = 'Virhe: järjestelmäsi "openssl_pkey_new" -funktio ei pysty generoimaan salausavaimia.'; +$a->strings['If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'] = 'Jos on kyse Windows-pavelimesta, katso "http://www.php.net/manual/en/openssl.installation.php".'; +$a->strings['Generate encryption keys'] = 'Luo salausavaimet'; +$a->strings['Error: Apache webserver mod-rewrite module is required but not installed.'] = 'Virhe: Apache-palvelimen mod-rewrite -moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['Apache mod_rewrite module'] = 'Apache mod_rewrite -moduuli'; +$a->strings['Error: PDO or MySQLi PHP module required but not installed.'] = 'Virhe: PDO tai MySQLi PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['Error: The MySQL driver for PDO is not installed.'] = 'Virhe: PDO:n MySQL-ajuri ei ole asennettu'; +$a->strings['PDO or MySQLi PHP module'] = 'PDO tai MySQLi PHP-moduuli'; +$a->strings['Error, XML PHP module required but not installed.'] = 'Virhe: XML PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['XML PHP module'] = 'XML PHP-moduuli'; +$a->strings['libCurl PHP module'] = 'PHP-moduuli libCurl'; +$a->strings['Error: libCURL PHP module required but not installed.'] = 'Virhe: libCURL PHP -moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['GD graphics PHP module'] = 'PHP-moduuli GD graphics'; +$a->strings['Error: GD graphics PHP module with JPEG support required but not installed.'] = 'Virhe: GD graphics PHP -moduuli JPEG-tuella vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['OpenSSL PHP module'] = 'PHP-moduuli OpenSSL'; +$a->strings['Error: openssl PHP module required but not installed.'] = 'Virhe: openssl PHP -moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['mb_string PHP module'] = 'PHP-moduuli mb_string'; +$a->strings['Error: mb_string PHP module required but not installed.'] = 'Virhe: PHP-moduuli mb_string vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['iconv PHP module'] = 'iconv PHP-moduuli'; +$a->strings['Error: iconv PHP module required but not installed.'] = 'Virhe: iconv PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; +$a->strings['POSIX PHP module'] = 'POSIX PHP-moduuli'; +$a->strings['Error: POSIX PHP module required but not installed.'] = 'Virhe: POSIX PHP-moduuli vaadittaan, mutta sitä ei ole asennettu.'; +$a->strings['This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.'] = 'Tämä on yleensä käyttöoikeusasetus, jolloin web-palvelimesi ei pysty kirjoittamaan tiedostoja kansioosi, vaikka itse siihen pystyisit.'; +$a->strings['view/smarty3 is writable'] = 'view/smarty3 on kirjoitettava'; +$a->strings['Url rewrite is working'] = 'URL-osoitteen uudellenkirjoitus toimii'; +$a->strings['ImageMagick PHP extension is not installed'] = 'ImageMagick PHP-laajennus ei ole asetettu'; +$a->strings['ImageMagick PHP extension is installed'] = 'ImageMagick PHP-laajennus on asetettu'; +$a->strings['ImageMagick supports GIF'] = 'ImageMagik tukee GIF-formaattia'; +$a->strings['Database already in use.'] = 'Tietokanta on jo käytössä.'; +$a->strings['Could not connect to database.'] = 'Tietokantaan ei saada yhteyttä.'; +$a->strings['Monday'] = 'Maanantai'; +$a->strings['Tuesday'] = 'Tiistai'; +$a->strings['Wednesday'] = 'Keskiviikko'; +$a->strings['Thursday'] = 'Torstai'; +$a->strings['Friday'] = 'Perjantai'; +$a->strings['Saturday'] = 'Lauantai'; +$a->strings['Sunday'] = 'Sunnuntai'; +$a->strings['January'] = 'Tammikuu'; +$a->strings['February'] = 'Helmikuu'; +$a->strings['March'] = 'Maaliskuu'; +$a->strings['April'] = 'Huhtikuu'; +$a->strings['May'] = 'Toukokuu'; +$a->strings['June'] = 'Kesäkuu'; +$a->strings['July'] = 'Heinäkuu'; +$a->strings['August'] = 'Elokuu'; +$a->strings['September'] = 'Syyskuu'; +$a->strings['October'] = 'Lokakuu'; +$a->strings['November'] = 'Marraskuu'; +$a->strings['December'] = 'Joulukuu'; +$a->strings['Mon'] = 'Ma'; +$a->strings['Tue'] = 'Ti'; +$a->strings['Wed'] = 'Ke'; +$a->strings['Thu'] = 'To'; +$a->strings['Fri'] = 'Pe'; +$a->strings['Sat'] = 'La'; +$a->strings['Sun'] = 'Su'; +$a->strings['Jan'] = 'Tam.'; +$a->strings['Feb'] = 'Hel.'; +$a->strings['Mar'] = 'Maa.'; +$a->strings['Apr'] = 'Huh.'; +$a->strings['Jun'] = 'Kes.'; +$a->strings['Jul'] = 'Tou.'; +$a->strings['Aug'] = 'Elo.'; +$a->strings['Sep'] = 'Syy.'; +$a->strings['Oct'] = 'Lok.'; +$a->strings['Nov'] = 'Mar.'; +$a->strings['Dec'] = 'Jou.'; +$a->strings['Update %s failed. See error logs.'] = '%s päivitys epäonnistui, katso virhelokit.'; +$a->strings[' + The friendica developers released update %s recently, + but when I tried to install it, something went terribly wrong. + This needs to be fixed soon and I can\'t do it alone. Please contact a + friendica developer if you can not help me on your own. My database might be invalid.'] = ' + Friendican kehittäjät askettäin julkaisi %s-päivityksen, + mutta asennuksessa jotain meni pahasti pieleen. + Tämä on korjattava pian, ja en voi korjata sitä itse. Ota yhteyttä + Friendica -kehittäjään jos et voi auttaa. Tietokantani saattaa olla virheellinen.'; +$a->strings[' +Error %d occurred during database update: +%s +'] = ' +%d virhe tapahtui tietokannan päivityksen aikana: +%s +'; +$a->strings['Errors encountered performing database changes: '] = 'Tietokannan muokkauksessa tapahtui virheitä:'; +$a->strings['%s: Database update'] = '%s: Tietokantapäivitys'; +$a->strings['%s: updating %s table.'] = '%s: päivitetään %s-taulukkoa.'; +$a->strings['Everybody'] = 'Kaikki'; +$a->strings['edit'] = 'muokkaa'; +$a->strings['add'] = 'lisää'; +$a->strings['Approve'] = 'Hyväksy'; +$a->strings['Organisation'] = 'Järjestö'; +$a->strings['Disallowed profile URL.'] = 'Kielletty profiiliosoite.'; +$a->strings['Blocked domain'] = 'Estetty verkkotunnus'; +$a->strings['Connect URL missing.'] = 'Yhteys URL-linkki puuttuu.'; +$a->strings['The contact could not be added. Please check the relevant network credentials in your Settings -> Social Networks page.'] = 'Kontaktia ei pystytty lisäämään. Tarkista verkkoasetukset omista asetuksistasi (Settings -> Social Networks).'; +$a->strings['The profile address specified does not provide adequate information.'] = 'Annettu profiiliosoite ei sisällä riittävästi tietoa.'; +$a->strings['No compatible communication protocols or feeds were discovered.'] = 'Yhteensopivia viestintäprotokolleja tai syötteitä ei löytynyt.'; +$a->strings['An author or name was not found.'] = 'Julkaisija tai nimi puuttuu.'; +$a->strings['Use mailto: in front of address to force email check.'] = 'Käytä "mailto:" osoitteen edessä pakottaaksesi sähköpostin tarkastuksen.'; +$a->strings['The profile address specified belongs to a network which has been disabled on this site.'] = 'Profiilin osoite kuuluu verkkoon, joka on poistettu tältä sivustolta.'; +$a->strings['Limited profile. This person will be unable to receive direct/personal notifications from you.'] = 'Rajoitettu profiili. Tämä henkilö ei pysty/tule saamaan suoria/henkilökohtaisia ilmoituksia sinulta.'; +$a->strings['Unable to retrieve contact information.'] = 'Kontaktin tietoja ei voitu hakea.'; +$a->strings['Starts:'] = 'Alkaa:'; +$a->strings['Finishes:'] = 'Päättyy:'; +$a->strings['all-day'] = 'koko päivä'; +$a->strings['Sept'] = 'Syy.'; +$a->strings['today'] = 'tänään'; +$a->strings['month'] = 'kuukausi'; +$a->strings['week'] = 'viikko'; +$a->strings['day'] = 'päivä'; +$a->strings['No events to display'] = 'Ei näytettäviä tapahtumia.'; +$a->strings['Access to this profile has been restricted.'] = 'Pääsy tähän profiiliin on rajoitettu'; +$a->strings['l, F j'] = 'l, F j'; +$a->strings['Edit event'] = 'Muokkaa tapahtumaa'; +$a->strings['Duplicate event'] = 'Monista tapahtuma'; +$a->strings['Delete event'] = 'Poista tapahtuma'; +$a->strings['l F d, Y \@ g:i A'] = 'l j.n.Y \@ H:i'; +$a->strings['D g:i A'] = 'D H:i'; +$a->strings['g:i A'] = 'H:i'; +$a->strings['Show map'] = 'Näytä kartta'; +$a->strings['Hide map'] = 'Piilota kartta'; +$a->strings['%s\'s birthday'] = '%s: syntymäpäivä'; +$a->strings['Happy Birthday %s'] = 'Hyvää syntymäpäivää %s'; +$a->strings['activity'] = 'toiminta'; +$a->strings['post'] = 'julkaisu'; +$a->strings['Content warning: %s'] = 'Sisältövaroitus: %s'; +$a->strings['bytes'] = 'tavua'; +$a->strings['View on separate page'] = 'Katso erillisellä sivulla'; +$a->strings['[no subject]'] = '[ei aihetta]'; +$a->strings['Wall Photos'] = 'Seinäkuvat'; +$a->strings['Edit profile'] = 'Muokkaa profiilia'; +$a->strings['Change profile photo'] = 'Vaihda profiilikuva'; +$a->strings['Homepage:'] = 'Kotisivu:'; +$a->strings['About:'] = 'Lisätietoja:'; +$a->strings['Atom feed'] = 'Atom -syöte'; +$a->strings['F d'] = 'F d'; +$a->strings['[today]'] = '[tänään]'; +$a->strings['Birthday Reminders'] = 'Syntymäpäivämuistutukset'; +$a->strings['Birthdays this week:'] = 'Syntymäpäiviä tällä viikolla:'; +$a->strings['g A l F d'] = 'g A l F d'; +$a->strings['[No description]'] = '[Ei kuvausta]'; +$a->strings['Event Reminders'] = 'Tapahtumamuistutukset'; +$a->strings['Hometown:'] = 'Kotikaupunki:'; +$a->strings['Sexual Preference:'] = 'Seksuaalinen suuntautuminen:'; +$a->strings['Political Views:'] = 'Politiikka:'; +$a->strings['Religious Views:'] = 'Uskonto:'; +$a->strings['Likes:'] = 'Tykkäykset:'; +$a->strings['Dislikes:'] = 'Ei tykkää:'; +$a->strings['Title/Description:'] = 'Otsikko/kuvaus:'; +$a->strings['Summary'] = 'Yhteenveto'; +$a->strings['Musical interests'] = 'Musiikki'; +$a->strings['Books, literature'] = 'Kirjat, kirjallisuus'; +$a->strings['Television'] = 'Televisio'; +$a->strings['Film/dance/culture/entertainment'] = 'Elokuvat/tanssi/kulttuuri/viihde'; +$a->strings['Hobbies/Interests'] = 'Harrastukset'; +$a->strings['Love/romance'] = 'Rakkaus/romanssi'; +$a->strings['Work/employment'] = 'Työ:'; +$a->strings['School/education'] = 'Koulutus:'; +$a->strings['Contact information and Social Networks'] = 'Yhteystiedot ja sosiaalinen media'; +$a->strings['SERIOUS ERROR: Generation of security keys failed.'] = 'VAKAVA VIRHE: Salausavainten luominen epäonnistui.'; +$a->strings['Login failed'] = 'Kirjautuminen epäonnistui'; +$a->strings['Not enough information to authenticate'] = 'Ei tarpeeksi tietoja kirjautumiseen'; +$a->strings['Password can\'t be empty'] = 'Salasanakenttä ei voi olla tyhjä'; +$a->strings['Passwords do not match. Password unchanged.'] = 'Salasanat eivät täsmää. Salasana ennallaan.'; +$a->strings['An invitation is required.'] = 'Vaaditaa kutsu.'; +$a->strings['Invitation could not be verified.'] = 'Kutsua ei voitu vahvistaa.'; +$a->strings['Invalid OpenID url'] = 'Virheellinen OpenID url-osoite'; +$a->strings['We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.'] = 'Kohtasimme ongelman antamasi OpenID:n kanssa. Ole hyvä ja tarkista ID:n oikea kirjoitusasu.'; +$a->strings['The error message was:'] = 'Virheviesti oli:'; +$a->strings['Please enter the required information.'] = 'Syötä tarvittavat tiedot.'; +$a->strings['That doesn\'t appear to be your full (First Last) name.'] = 'Tuo ei vakuta täydeltä nimeltäsi (Etunimi Sukunimi).'; +$a->strings['Your email domain is not among those allowed on this site.'] = 'Sähköpostiosoitteesi verkkotunnus on tämän sivuston estolistalla.'; +$a->strings['Not a valid email address.'] = 'Virheellinen sähköpostiosoite.'; +$a->strings['Cannot use that email.'] = 'Sähköpostiosoitetta ei voitu käyttää.'; +$a->strings['Your nickname can only contain a-z, 0-9 and _.'] = 'Nimimerkki voi sisältää a-z, 0-9 ja _.'; +$a->strings['Nickname is already registered. Please choose another.'] = 'Valitsemasi nimimerkki on jo käytössä. Valitse toinen nimimerkki.'; +$a->strings['An error occurred during registration. Please try again.'] = 'Rekisteröityminen epäonnistui. Yritä uudelleen.'; +$a->strings['An error occurred creating your default profile. Please try again.'] = 'Oletusprofiilin luominen epäonnistui. Yritä uudelleen.'; +$a->strings['An error occurred creating your self contact. Please try again.'] = 'Yhteystietojesi luonti epäonnistui. Yritä uudelleen.'; +$a->strings['Friends'] = 'Kaverit'; +$a->strings['Profile Photos'] = 'Profiilin valokuvat'; +$a->strings['Registration at %s'] = 'Rekisteröityminen kohteessa %s'; +$a->strings['Addon %s disabled.'] = 'Lisäosa %s poistettu käytöstä.'; +$a->strings['Addon %s enabled.'] = 'Lisäosa %s käytössä.'; +$a->strings['Disable'] = 'Poista käytöstä'; +$a->strings['Enable'] = 'Ota käyttöön'; +$a->strings['Administration'] = 'Ylläpito'; +$a->strings['Addons'] = 'Lisäosat'; +$a->strings['Toggle'] = 'Vaihda'; +$a->strings['Author: '] = 'Tekijä'; +$a->strings['Maintainer: '] = 'Ylläpitäjä:'; +$a->strings['Save Settings'] = 'Tallenna asetukset'; +$a->strings['Database structure update %s was successfully applied.'] = 'Tietokannan rakenteen %s-päivitys onnistui.'; +$a->strings['Executing of database structure update %s failed with error: %s'] = 'Tietokannan rakennepäivitys %s epäonnistui virheviestillä %s'; +$a->strings['Update %s was successfully applied.'] = '%s-päivitys onnistui.'; +$a->strings['No failed updates.'] = 'Ei epäonnistuineita päivityksiä.'; +$a->strings['Check database structure'] = 'Tarkista tietokannan rakenne'; +$a->strings['Failed Updates'] = 'Epäonnistuineita päivityksiä'; +$a->strings['Lock feature %s'] = 'Lukitse ominaisuus %s'; +$a->strings['Manage Additional Features'] = 'Hallitse lisäominaisuudet'; +$a->strings['Other'] = 'Toinen'; +$a->strings['unknown'] = 'tuntematon'; +$a->strings['Federation Statistics'] = 'Liiton tilastotiedot'; +$a->strings['PHP log currently enabled.'] = 'PHP-loki käytössä'; +$a->strings['PHP log currently disabled.'] = 'PHP-loki pois käytöstä'; +$a->strings['Logs'] = 'Lokit'; +$a->strings['Clear'] = 'Tyhjennä'; +$a->strings['Enable Debugging'] = 'Ota virheenkorjaustila käyttöön'; +$a->strings['Log file'] = 'Lokitiedosto'; +$a->strings['Log level'] = 'Lokitaso'; +$a->strings['PHP logging'] = 'PHP-loki'; +$a->strings['View Logs'] = 'Katso lokit'; +$a->strings['Show all'] = 'Näytä kaikki'; +$a->strings['Event details'] = 'Tapahtuman tiedot'; +$a->strings['Created'] = 'Luotu'; +$a->strings['No special theme for mobile devices'] = 'Ei mobiiliteemaa'; +$a->strings['%s - (Experimental)'] = '%s - (Kokeellinen)'; +$a->strings['No community page'] = 'Ei yhteisösivua'; +$a->strings['Public postings from users of this site'] = 'Julkiset julkaisut tämän sivuston käyttäjiltä'; +$a->strings['Public postings from the federated network'] = 'Julkiset julkaisut liittoutuneelta verkolta'; +$a->strings['Public postings from local users and the federated network'] = 'Julkiset julkaisut tältä sivustolta ja liittoutuneelta verkolta'; +$a->strings['Multi user instance'] = 'Monen käyttäjän instanssi'; +$a->strings['Closed'] = 'Suljettu'; +$a->strings['Requires approval'] = 'Edellyttää hyväksyntää'; +$a->strings['Open'] = 'Avoin'; +$a->strings['Don\'t check'] = 'Älä tarkista'; +$a->strings['Site'] = 'Sivusto'; +$a->strings['Registration'] = 'Rekisteröityminen'; +$a->strings['File upload'] = 'Tiedoston lataus'; +$a->strings['Policies'] = 'Käytännöt'; +$a->strings['Performance'] = 'Suoritus'; +$a->strings['Worker'] = 'Worker'; +$a->strings['Message Relay'] = 'Viestirele'; +$a->strings['Site name'] = 'Sivuston nimi'; +$a->strings['Sender Email'] = 'Lähettäjän sähköposti'; +$a->strings['The email address your server shall use to send notification emails from.'] = 'Lähettäjän sähköpostiosoite palvelimen ilmoitussähköposteissa.'; +$a->strings['Banner/Logo'] = 'Banneri/logo'; +$a->strings['Shortcut icon'] = 'Pikakuvake'; +$a->strings['Link to an icon that will be used for browsers.'] = 'Linkki kuvakkeeseen jota selaimet saa käyttää.'; +$a->strings['Touch icon'] = 'Kosketusnäyttökuvake'; +$a->strings['Link to an icon that will be used for tablets and mobiles.'] = 'Linkki kuvakkeeseen jota tabletit ja matkapuhelimet saa käyttää.'; +$a->strings['Additional Info'] = 'Lisätietoja'; +$a->strings['System language'] = 'Järjestelmän kieli'; +$a->strings['System theme'] = 'Järjestelmäteema'; +$a->strings['Mobile system theme'] = 'Mobiili järjestelmäteema'; +$a->strings['Theme for mobile devices'] = 'Mobiiliteema'; +$a->strings['Force SSL'] = 'Pakoita SSL-yhteyden käyttöä'; +$a->strings['Single user instance'] = 'Yksittäisen käyttäjän instanssi'; +$a->strings['Maximum image size'] = 'Suurin kuvakoko'; +$a->strings['Maximum image length'] = 'Suurin kuvapituus'; +$a->strings['Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.'] = 'Ladattavan kuvatiedoston enimmäispituus pikseleinä. Oletusarvo on -1, eli ei enimmäispituutta.'; +$a->strings['JPEG image quality'] = 'JPEG-kuvanlaatu'; +$a->strings['Uploaded JPEGS will be saved at this quality setting [0-100]. Default is 100, which is full quality.'] = 'Ladatut JPEG-kuvat tallennetaan tällä laatuasetuksella [0-100]. Oletus on 100, eli korkein laatu.'; +$a->strings['Register policy'] = 'Rekisteröintipolitiikka'; +$a->strings['Maximum Daily Registrations'] = 'Päivittäinen rekisteröitymisraja'; +$a->strings['If registration is permitted above, this sets the maximum number of new user registrations to accept per day. If register is set to closed, this setting has no effect.'] = 'Mikäli rekisteröityminen on sallittu, tämä asettaa enimmäismäärä uusia rekisteröitymisiä päivässä. Jos reksiteröityminen ei ole sallittu, tällä asetuksella ei ole vaikutusta.'; +$a->strings['Register text'] = 'Rekisteröitymisteksti'; +$a->strings['Will be displayed prominently on the registration page. You can use BBCode here.'] = 'Näkyvästi esillä rekisteröitymissivulla. Voit käyttää BBCodeia.'; +$a->strings['Accounts abandoned after x days'] = 'Käyttäjätilit hylätään X päivän jälkeen'; +$a->strings['Allowed friend domains'] = 'Sallittuja kaveri-verkkotunnuksia'; +$a->strings['Allowed email domains'] = 'Sallittuja sähköposti-verkkotunnuksia'; +$a->strings['Block public'] = 'Estä vierailijat'; +$a->strings['Global directory URL'] = 'Maailmanlaajuisen hakemiston URL-osoite'; +$a->strings['Don\'t include post content in email notifications'] = 'Älä lisää julkaisun sisältö sähköposti-ilmoitukseen'; +$a->strings['Don\'t embed private images in posts'] = 'Älä upota yksityisiä kuvia julkaisuissa'; +$a->strings['Community pages for visitors'] = 'Yhteisösivu vieraille'; +$a->strings['Diaspora support can\'t be enabled because Friendica was installed into a sub directory.'] = 'Diaspora -tukea ei voitu ottaa käyttöön koska Friendica on asennettu alihakemistoon.'; +$a->strings['Enable Diaspora support'] = 'Salli Diaspora-tuki'; +$a->strings['Verify SSL'] = 'Vahvista SSL'; +$a->strings['Proxy user'] = 'Välityspalvelimen käyttäjä'; +$a->strings['Proxy URL'] = 'Välityspalvelimen osoite'; +$a->strings['Network timeout'] = 'Verkon aikakatkaisu'; +$a->strings['Maximum Load Average'] = 'Kuorman enimmäiskeksiarvo'; +$a->strings['Discover contacts from other servers'] = 'Etsi kontakteja muilta palvelimilta'; +$a->strings['Search the local directory'] = 'Paikallisluettelohaku'; +$a->strings['Publish server information'] = 'Julkaise palvelintiedot'; +$a->strings['Suppress Tags'] = 'Piilota tunnisteet'; +$a->strings['Suppress showing a list of hashtags at the end of the posting.'] = 'Piilota tunnistelista julkaisun lopussa.'; +$a->strings['Clean database'] = 'Siivoa tietokanta'; +$a->strings['Maximum numbers of comments per post'] = 'Julkaisun kommentiraja'; +$a->strings['Temp path'] = 'Väliaikaistiedostojen polku'; +$a->strings['If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.'] = 'Mikäli verkkopalvelimesi ei voi käyttää järjestelmän väliaikaistiedostojen polkua, syötä toinen polku tähän.'; +$a->strings['Only search in tags'] = 'Tunnistehaku'; +$a->strings['Maximum number of parallel workers'] = 'Enimmäismäärä rinnakkaisia workereitä'; +$a->strings['Enable fastlane'] = 'Käytä fastlane'; +$a->strings['Direct relay transfer'] = 'Suora releen siirto'; +$a->strings['Relay scope'] = 'Relen soveltamisala'; +$a->strings['Disabled'] = 'Pois käytöstä'; +$a->strings['all'] = 'kaikki'; +$a->strings['tags'] = 'tunnisteet'; +$a->strings['Server tags'] = 'palvelintunnisteet'; +$a->strings['Allow user tags'] = 'Salli käyttäjien tunnisteet'; +$a->strings['The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.'] = 'Tietokannan päivitys epäonnistui. Suorita komento "php bin/console.php dbstructure update" komentoriviltä ja lue mahdolliset virheviestit.'; +$a->strings['The worker was never executed. Please check your database structure!'] = 'Workeriä ei ole otettu käyttöön. Tarkista tietokantasi rakenne!'; +$a->strings['The last worker execution was on %s UTC. This is older than one hour. Please check your crontab settings.'] = 'Viimeisin worker -käynnistys tapahtui klo %s UTC, eli yli tunti sitten. Tarkista crontab -asetukset.'; +$a->strings['Message queues'] = 'Viestijonot'; +$a->strings['Version'] = 'Versio'; +$a->strings['Active addons'] = 'Käytössäolevat lisäosat'; +$a->strings['Screenshot'] = 'Kuvakaappaus'; +$a->strings['Themes'] = 'Teemat'; +$a->strings['Reload active themes'] = 'Lataa aktiiviset teemat uudelleen'; +$a->strings['No themes found on the system. They should be placed in %1$s'] = 'Teemoja ei löytynyt järjestelmästä. Teemat tulisi laittaa kansioon %1$s'; +$a->strings['[Experimental]'] = '[Kokeellinen]'; +$a->strings['[Unsupported]'] = '[Ei tueta]'; +$a->strings['Display Terms of Service'] = 'Näytä käyttöehdot'; +$a->strings['Display Privacy Statement'] = 'Näytä tietosuojalausunto'; +$a->strings['The Terms of Service'] = 'Käyttöehdot'; +$a->strings['No installed applications.'] = 'Ei asennettuja sovelluksia.'; +$a->strings['Applications'] = 'Sovellukset'; +$a->strings['Item was not found.'] = 'Kohdetta ei löytynyt.'; +$a->strings['Please login to continue.'] = 'Ole hyvä ja kirjaudu jatkaaksesi.'; +$a->strings['Overview'] = 'Yleiskatsaus'; +$a->strings['Configuration'] = 'Kokoonpano'; +$a->strings['Additional features'] = 'Lisäominaisuuksia'; +$a->strings['Database'] = 'Tietokanta'; +$a->strings['DB updates'] = 'Tietokannan päivitykset'; +$a->strings['Diagnostics'] = 'Diagnostiikka'; +$a->strings['PHP Info'] = 'PHP tietoja'; +$a->strings['check webfinger'] = 'Tarkista webfinger'; +$a->strings['Addon Features'] = 'Lisäosaominaisuudet'; +$a->strings['User registrations waiting for confirmation'] = 'Käyttäjärekisteröinnit odottavat hyväksyntää'; +$a->strings['Daily posting limit of %d post reached. The post was rejected.'] = [ + 0 => 'Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', + 1 => 'Päivittäinen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', +]; +$a->strings['Weekly posting limit of %d post reached. The post was rejected.'] = [ + 0 => 'Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', + 1 => 'Viikottainen julkaisuraja (%d) on tullut täyteen. Julkaisu hylätty.', +]; +$a->strings['Users'] = 'Käyttäjät'; +$a->strings['Tools'] = 'Työkalut'; +$a->strings['Contact Blocklist'] = 'Kontaktien estolista'; +$a->strings['Server Blocklist'] = 'Palvelimien estolista'; +$a->strings['Delete Item'] = 'Poista kohde'; +$a->strings['Profile Details'] = 'Profiilitiedot'; +$a->strings['Only You Can See This'] = 'Vain sinä näet tämän'; +$a->strings['Tips for New Members'] = 'Vinkkejä uusille käyttäjille'; +$a->strings['People Search - %s'] = 'Käyttäjähaku - %s'; +$a->strings['No matches'] = 'Ei täsmääviä profiileja'; +$a->strings['Account'] = 'Tili'; +$a->strings['Display'] = 'Ulkonäkö'; +$a->strings['Social Networks'] = 'Sosiaalinen media'; +$a->strings['Connected apps'] = 'Yhdistetyt sovellukset'; +$a->strings['Export personal data'] = 'Vie henkilökohtaiset tiedot'; +$a->strings['Remove account'] = 'Poista tili'; +$a->strings['The post was created'] = 'Julkaisu luotu'; +$a->strings['Failed to remove event'] = 'Tapahtuman poisto epäonnistui'; +$a->strings['Event can not end before it has started.'] = 'Tapahtuma ei voi päättyä ennen kuin on alkanut.'; +$a->strings['Event title and start time are required.'] = 'Tapahtuman nimi ja alkamisaika vaaditaan.'; +$a->strings['Starting date and Title are required.'] = 'Aloituspvm ja otsikko vaaditaan.'; +$a->strings['Event Starts:'] = 'Tapahtuma alkaa:'; +$a->strings['Required'] = 'Vaaditaan'; +$a->strings['Finish date/time is not known or not relevant'] = 'Päättymispvm ja kellonaika ei ole tiedossa tai niillä ei ole merkitystä'; +$a->strings['Event Finishes:'] = 'Tapahtuma päättyy:'; +$a->strings['Share this event'] = 'Jaa tämä tapahtuma'; +$a->strings['This calendar format is not supported'] = 'Tätä kalenteriformaattia ei tueta'; +$a->strings['No exportable data found'] = 'Vientikelpoista dataa ei löytynyt'; +$a->strings['calendar'] = 'kalenteri'; +$a->strings['Events'] = 'Tapahtumat'; +$a->strings['View'] = 'Katso'; +$a->strings['Create New Event'] = 'Luo uusi tapahtuma'; +$a->strings['list'] = 'luettelo'; +$a->strings['Contact not found.'] = 'Kontaktia ei ole.'; +$a->strings['Invalid contact.'] = 'Virheellinen kontakti.'; +$a->strings['Members'] = 'Jäsenet'; +$a->strings['Click on a contact to add or remove.'] = 'Valitse kontakti, jota haluat poistaa tai lisätä.'; +$a->strings['%d contact edited.'] = [ + 0 => '%d kontakti muokattu', + 1 => '%d kontakteja muokattu', +]; +$a->strings['Show all contacts'] = 'Näytä kaikki yhteystiedot'; +$a->strings['Blocked'] = 'Estetty'; +$a->strings['Only show blocked contacts'] = 'Näytä vain estetyt henkilöt'; +$a->strings['Ignored'] = 'Jätetty huomiotta'; +$a->strings['Only show ignored contacts'] = 'Näytä vain henkilöt, jotka jätetty huomiotta'; +$a->strings['Archived'] = 'Arkistoitu'; +$a->strings['Only show archived contacts'] = 'Näytä vain arkistoidut henkilöt'; +$a->strings['Hidden'] = 'Piilotettu'; +$a->strings['Only show hidden contacts'] = 'Näytä vain piilotetut henkilöt'; +$a->strings['Search your contacts'] = 'Etsi henkilöitä'; +$a->strings['Results for: %s'] = 'Tulokset haulla: %s'; +$a->strings['Update'] = 'Päivitä'; +$a->strings['Unblock'] = 'Salli'; +$a->strings['Unignore'] = 'Ota huomioon'; +$a->strings['Advanced Contact Settings'] = 'Kontakti-lisäasetukset'; +$a->strings['Mutual Friendship'] = 'Yhteinen kaveruus'; +$a->strings['is a fan of yours'] = 'on fanisi'; +$a->strings['you are a fan of'] = 'fanitat'; +$a->strings['Visit %s\'s profile [%s]'] = 'Näytä %s-käyttäjän profiili [%s]'; +$a->strings['Contact update failed.'] = 'Kontaktipäivitys epäonnistui.'; +$a->strings['Return to contact editor'] = 'Palaa kontaktin muokkaamiseen'; +$a->strings['Name'] = 'Nimi'; +$a->strings['Account Nickname'] = 'Tilin lempinimi'; +$a->strings['Account URL'] = 'Tilin URL-osoite'; +$a->strings['Poll/Feed URL'] = 'URL äänestyksiä/syötteitä varten'; +$a->strings['New photo from this URL'] = 'Uusi kuva osoitteesta'; +$a->strings['Access denied.'] = 'Käyttö estetty.'; +$a->strings['Submit Request'] = 'Lähetä pyyntö'; +$a->strings['You already added this contact.'] = 'Olet jo lisännyt tämän kontaktin.'; +$a->strings['The network type couldn\'t be detected. Contact can\'t be added.'] = 'Verkkotyyppiä ei voitu havaita. Kontaktia ei voitu lisätä.'; +$a->strings['Diaspora support isn\'t enabled. Contact can\'t be added.'] = 'Diaspora -tuki ei ole käytössä. Kontaktia ei voi lisätä.'; +$a->strings['OStatus support is disabled. Contact can\'t be added.'] = 'OStatus -tuki ei ole käytössä. Kontaktia ei voi lisätä.'; +$a->strings['Please answer the following:'] = 'Vastaa seuraavaan:'; +$a->strings['Your Identity Address:'] = 'Identiteettisi osoite:'; +$a->strings['Profile URL'] = 'Profiilin URL'; +$a->strings['Tags:'] = 'Tunnisteet:'; +$a->strings['Add a personal note:'] = 'Lisää oma merkintä:'; +$a->strings['The contact could not be added.'] = 'Kontaktia ei voitu lisätä.'; +$a->strings['Invalid request.'] = 'Virheellinen pyyntö.'; +$a->strings['Profile Match'] = 'Vastaavien profiilien haku'; +$a->strings['Failed to update contact record.'] = 'Kontaktitietojen päivitys epäonnistui.'; +$a->strings['Contact has been unblocked'] = 'Henkilö on jälleen sallittu'; +$a->strings['Contact has been blocked'] = 'Henkilö on estetty'; +$a->strings['Contact has been unignored'] = 'Henkilö on jälleen huomioituna.'; +$a->strings['Contact has been ignored'] = 'Henkilöä ei enää huomioida'; +$a->strings['You are mutual friends with %s'] = 'Olet kaveri %s kanssa.'; +$a->strings['You are sharing with %s'] = 'Olet jakanut jotakin %s:n kanssa'; +$a->strings['%s is sharing with you'] = '%s jakaa sinulle jotakin.'; +$a->strings['Private communications are not available for this contact.'] = 'Yksityiskeskustelu ei ole käytettävissä tälle henkilölle.'; +$a->strings['Never'] = 'Ei koskaan'; +$a->strings['(Update was not successful)'] = '(Päivitys epäonnistui)'; +$a->strings['(Update was successful)'] = '(Päivitys onnistui)'; +$a->strings['Suggest friends'] = 'Ehdota ystäviä'; +$a->strings['Network type: %s'] = 'Verkkotyyppi: %s'; +$a->strings['Communications lost with this contact!'] = 'Yhteys tähän henkilöön menetettiin!'; +$a->strings['Fetch information'] = 'Nouda tiedot'; +$a->strings['Fetch keywords'] = 'Nouda avainsanat'; +$a->strings['Fetch information and keywords'] = 'Nouda tiedot ja avainsanat'; +$a->strings['No mirroring'] = 'Ei peilausta'; +$a->strings['Mirror as my own posting'] = 'Peilaa omana julkaisuna'; +$a->strings['Contact Information / Notes'] = 'Yhteystiedot / Muistiinpanot'; +$a->strings['Contact Settings'] = 'Yhteystietoasetukset'; +$a->strings['Contact'] = 'Kontakti'; +$a->strings['Edit contact notes'] = 'Muokkaa yhteystietojen muistiinpanoja'; +$a->strings['Block/Unblock contact'] = 'Estä/salli henkilö'; +$a->strings['Ignore contact'] = 'Jätä henkilö huomiotta'; +$a->strings['View conversations'] = 'Katso keskusteluja'; +$a->strings['Last update:'] = 'Viimeksi päivitetty:'; +$a->strings['Update public posts'] = 'Päivitä julkiset postaukset'; +$a->strings['Update now'] = 'Päivitä nyt'; +$a->strings['Awaiting connection acknowledge'] = 'Odotetaan yhteyden kuittausta'; +$a->strings['Currently blocked'] = 'Estetty tällä hetkellä'; +$a->strings['Currently ignored'] = 'Jätetty huomiotta tällä hetkellä'; +$a->strings['Currently archived'] = 'Arkistoitu tällä hetkellä'; +$a->strings['Hide this contact from others'] = 'Piilota kontakti muilta'; +$a->strings['Notification for new posts'] = 'Uusien postausten ilmoitus'; +$a->strings['Send a notification of every new post of this contact'] = 'Lähetä ilmoitus tälle henkilölle kaikista uusista postauksista'; +$a->strings['Actions'] = 'Toimenpiteet'; +$a->strings['Status'] = 'Tila'; +$a->strings['Mirror postings from this contact'] = 'Peilaa tämän kontaktin julkaisut'; +$a->strings['Toggle Blocked status'] = 'Estetty tila päälle/pois'; +$a->strings['Toggle Ignored status'] = 'Sivuuta/seuraa'; +$a->strings['Yes'] = 'Kyllä'; +$a->strings['No suggestions available. If this is a new site, please try again in 24 hours.'] = 'Ehdotuksia ei löydy. Jos tämä on uusi sivusto, kokeile uudelleen vuorokauden kuluttua.'; +$a->strings['Unfollowing is currently not supported by your network.'] = 'Seuraamisen lopettaminen ei tällä hetkellä tueta verkossasi.'; +$a->strings['Disconnect/Unfollow'] = 'Katkaise / Lopeta seuraaminen'; +$a->strings['Local Community'] = 'Paikallinen yhteisö'; +$a->strings['Posts from local users on this server'] = 'Tämän palvelimen julkaisut'; +$a->strings['Global Community'] = 'Maailmanlaajuinen yhteisö'; +$a->strings['Posts from users of the whole federated network'] = 'Maailmanlaajuisen verkon julkaisut'; +$a->strings['No results.'] = 'Ei tuloksia.'; +$a->strings['Community option not available.'] = 'Yhteisö vaihtoehto ei saatavilla.'; +$a->strings['Not available.'] = 'Ei saatavilla.'; +$a->strings['Personal'] = 'Henkilökohtainen'; +$a->strings['Posts that mention or involve you'] = 'Julkaisut jotka liittyvät sinuun'; +$a->strings['Starred'] = 'Tähtimerkitty'; +$a->strings['Favourite Posts'] = 'Lempijulkaisut'; +$a->strings['Credits'] = 'Lopputekstit'; $a->strings['BBCode::toPlaintext'] = 'BBCode::toPlaintext'; $a->strings['BBCode::convert (raw HTML)'] = 'BBCode::convert (raaka HTML)'; $a->strings['BBCode::convert'] = 'BBCode::convert'; @@ -620,18 +821,54 @@ $a->strings['Source text'] = 'Lähdeteksti'; $a->strings['BBCode'] = 'BBCode'; $a->strings['Markdown'] = 'Markdown'; $a->strings['HTML'] = 'HTML'; -$a->strings['This is Friendica, version'] = 'Tämä on Friendica, versio'; -$a->strings['running at web location'] = 'käynnissä osoitteessa'; -$a->strings['Please visit Friendi.ca to learn more about the Friendica project.'] = 'Vieraile osoitteessa Friendi.ca saadaksesi lisätietoja Friendica- projektista.'; -$a->strings['Bug reports and issues: please visit'] = 'Bugiraportit ja kysymykset: vieraile osoitteessa'; -$a->strings['the bugtracker at github'] = 'githubin bugtrackeri'; -$a->strings['Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'] = 'Ehdotukset ja palaute: lähetä sähköposti osoitteeseen "info" at "friendi - piste - ca'; +$a->strings['You must be logged in to use this module'] = 'Sinun pitää kirjautua sisään, jotta voit käyttää tätä moduulia'; +$a->strings['Source URL'] = 'Lähde URL'; +$a->strings['Time Conversion'] = 'Aikamuunnos'; +$a->strings['UTC time: %s'] = 'UTC-aika: %s'; +$a->strings['Current timezone: %s'] = 'Aikavyöhyke: %s'; +$a->strings['Converted localtime: %s'] = 'Muunnettu paikallisaika: %s'; +$a->strings['Please select your timezone:'] = 'Valitse aikavyöhykkeesi:'; +$a->strings['Select an identity to manage: '] = 'Valitse identiteetti hallitavaksi:'; +$a->strings['Results for:'] = 'Tulokset haulla:'; +$a->strings['Site Directory'] = 'Sivuston luettelo'; +$a->strings['- select -'] = '- valitse -'; +$a->strings['Friend suggestion sent.'] = 'Ystäväehdotus lähetettiin.'; +$a->strings['Suggest Friends'] = 'Ehdota ystäviä'; +$a->strings['Suggest a friend for %s'] = 'Ehdota ystävää ystävälle %s'; $a->strings['Installed addons/apps:'] = 'Asennettu lisäosat/sovellukset:'; $a->strings['No installed addons/apps'] = 'Ei asennettuja lisäosia/sovelluksia'; $a->strings['Read about the Terms of Service of this node.'] = 'Lue tämän solmun käyttöehdot.'; $a->strings['On this server the following remote servers are blocked.'] = 'Tällä palvelimella seuraavat etäpalvelimet ovat estetty.'; -$a->strings['Blocked domain'] = 'Estetty verkkotunnus'; $a->strings['Reason for the block'] = 'Eston syy'; +$a->strings['Please visit Friendi.ca to learn more about the Friendica project.'] = 'Vieraile osoitteessa Friendi.ca saadaksesi lisätietoja Friendica- projektista.'; +$a->strings['Bug reports and issues: please visit'] = 'Bugiraportit ja kysymykset: vieraile osoitteessa'; +$a->strings['the bugtracker at github'] = 'githubin bugtrackeri'; +$a->strings['Suggestions, praise, etc. - please email "info" at "friendi - dot - ca'] = 'Ehdotukset ja palaute: lähetä sähköposti osoitteeseen "info" at "friendi - piste - ca'; +$a->strings['No profile'] = 'Ei profiilia'; +$a->strings['Help:'] = 'Ohje:'; +$a->strings['Welcome to %s'] = 'Tervetuloa %s'; +$a->strings['System check'] = 'Järjestelmän tarkistus'; +$a->strings['Next'] = 'Seuraava'; +$a->strings['Check again'] = 'Tarkista uudelleen'; +$a->strings['Base path to installation'] = 'Asennuksen peruspolku'; +$a->strings['Database connection'] = 'Tietokantayhteys'; +$a->strings['In order to install Friendica we need to know how to connect to your database.'] = 'Jotta voit asentaa Friendican, tarvitaan tieto siitä, miten tietokantaasi saa yhteyden.'; +$a->strings['Please contact your hosting provider or site administrator if you have questions about these settings.'] = 'Ota yhteyttä web-palveluntarjoajaasi tai sivuston ylläpitäjään, jos sinulla on näihin asetuksiin liittyviä kysymyksiä.'; +$a->strings['The database you specify below should already exist. If it does not, please create it before continuing.'] = 'Alla määritetyn tietokannan tulisi olla jo olemassa. Jos se ei ole, luo se ennen kuin jatkat.'; +$a->strings['Database Server Name'] = 'Tietokannan palvelimen nimi'; +$a->strings['Database Login Name'] = 'Tietokannan käyttäjän nimi'; +$a->strings['Database Login Password'] = 'Tietokannan käyttäjän salasana'; +$a->strings['For security reasons the password must not be empty'] = 'Turvallisuussyistä salasanakenttä ei saa olla tyhjä'; +$a->strings['Database Name'] = 'Tietokannan nimi'; +$a->strings['Please select a default timezone for your website'] = 'Valitse oletusaikavyöhyke sivustollesi'; +$a->strings['Site settings'] = 'Sivuston asetukset'; +$a->strings['Site administrator email address'] = 'Sivuston ylläpitäjän sähköpostiosoite'; +$a->strings['Your account email address must match this in order to use the web admin panel.'] = 'Tilisi sähköpostiosoitteen on vastattava tätä, jotta voit käyttää ylläpitokäyttöliittymää.'; +$a->strings['System Language:'] = 'Järjestelmän kieli:'; +$a->strings['Set the default language for your Friendica installation interface and to send emails.'] = 'Valitse Friendica-sivustosi oletuskieli.'; +$a->strings['Your Friendica site database has been installed.'] = 'Friendica-sivustosi tietokanta on asennettu.'; +$a->strings['

What next

'] = '

Mitä seuraavaksi

'; +$a->strings['IMPORTANT: You will need to [manually] setup a scheduled task for the worker.'] = 'TÄRKEÄÄ: Sinun pitää asettaa [manuaalisesti] ajastettu tehtävä Workerille.'; $a->strings['Total invitation limit exceeded.'] = 'Kutsuraja ylitetty.'; $a->strings['%s : Not a valid email address.'] = '%s : Virheellinen sähköpostiosoite.'; $a->strings['Please join us on Friendica'] = 'Tervetuloa Friendicaan'; @@ -647,119 +884,19 @@ $a->strings['To accept this invitation, please visit and register at %s.'] = 'Hy $a->strings['Send invitations'] = 'Lähetä kutsut'; $a->strings['Enter email addresses, one per line:'] = 'Syötä sähköpostiosoitteet, yksi riviä kohden:'; $a->strings['Once you have registered, please connect with me via my profile page at:'] = 'Kun olet rekisteröitynyt, lähetä minulle kaverikutsun profiilisivuni kautta:'; -$a->strings['Contact settings applied.'] = 'Kontaktiasetukset tallennettu.'; -$a->strings['Contact update failed.'] = 'Kontaktipäivitys epäonnistui.'; -$a->strings['WARNING: This is highly advanced and if you enter incorrect information your communications with this contact may stop working.'] = 'VAROITUS: Tämä on erittäin vaativaa ja jos kirjoitat virheellisiä tietoja, viestintäsi tämän henkilön kanssa voi lakata toimimasta.'; -$a->strings['Please use your browser \'Back\' button now if you are uncertain what to do on this page.'] = 'Ole hyvä ja paina selaimesi \'Takaisin\'-painiketta nyt, jos olet epävarma tämän sivun toiminnoista.'; -$a->strings['No mirroring'] = 'Ei peilausta'; -$a->strings['Mirror as forwarded posting'] = 'Peilaa välitettynä julkaisuna'; -$a->strings['Mirror as my own posting'] = 'Peilaa omana julkaisuna'; -$a->strings['Return to contact editor'] = 'Palaa kontaktin muokkaamiseen'; -$a->strings['Mirror postings from this contact'] = 'Peilaa tämän kontaktin julkaisut'; -$a->strings['Name'] = 'Nimi'; -$a->strings['Account Nickname'] = 'Tilin lempinimi'; -$a->strings['@Tagname - overrides Name/Nickname'] = '@Tagname - ohittaa Nimen/Nimimerkin'; -$a->strings['Account URL'] = 'Tilin URL-osoite'; -$a->strings['Friend Request URL'] = 'URL kaveripyyntöä varten'; -$a->strings['Friend Confirm URL'] = 'URL kaverin vahvistusta varten'; -$a->strings['Notification Endpoint URL'] = 'URL huomautuksia varten'; -$a->strings['Poll/Feed URL'] = 'URL äänestyksiä/syötteitä varten'; -$a->strings['New photo from this URL'] = 'Uusi kuva osoitteesta'; -$a->strings['%1$s welcomes %2$s'] = '%1$s toivottaa tervetulleeksi ystävän %2$s'; -$a->strings['Help:'] = 'Ohje:'; -$a->strings['Help'] = 'Ohje'; -$a->strings['Page not found.'] = 'Sivua ei löytynyt.'; -$a->strings['Friendica Communications Server - Setup'] = 'Friendica viestinnän palvelin - asetukset'; -$a->strings['Could not connect to database.'] = 'Tietokantaan ei saada yhteyttä.'; -$a->strings['Could not create table.'] = 'Taulun luominen epäonnistui.'; -$a->strings['Your Friendica site database has been installed.'] = 'Friendica-sivustosi tietokanta on asennettu.'; -$a->strings['You may need to import the file "database.sql" manually using phpmyadmin or mysql.'] = 'Sinun on ehkä tuotava tiedosto "database.sql" manuaalisesti käyttämällä phpMyAdminia tai MySQL:ää.'; -$a->strings['Please see the file "INSTALL.txt".'] = 'Lue tiedosto "INSTALL.txt".'; -$a->strings['Database already in use.'] = 'Tietokanta on jo käytössä.'; -$a->strings['System check'] = 'Järjestelmän tarkistus'; -$a->strings['Check again'] = 'Tarkista uudelleen'; -$a->strings['Database connection'] = 'Tietokantayhteys'; -$a->strings['In order to install Friendica we need to know how to connect to your database.'] = 'Jotta voit asentaa Friendican, tarvitaan tieto siitä, miten tietokantaasi saa yhteyden.'; -$a->strings['Please contact your hosting provider or site administrator if you have questions about these settings.'] = 'Ota yhteyttä web-palveluntarjoajaasi tai sivuston ylläpitäjään, jos sinulla on näihin asetuksiin liittyviä kysymyksiä.'; -$a->strings['The database you specify below should already exist. If it does not, please create it before continuing.'] = 'Alla määritetyn tietokannan tulisi olla jo olemassa. Jos se ei ole, luo se ennen kuin jatkat.'; -$a->strings['Database Server Name'] = 'Tietokannan palvelimen nimi'; -$a->strings['Database Login Name'] = 'Tietokannan käyttäjän nimi'; -$a->strings['Database Login Password'] = 'Tietokannan käyttäjän salasana'; -$a->strings['For security reasons the password must not be empty'] = 'Turvallisuussyistä salasanakenttä ei saa olla tyhjä'; -$a->strings['Database Name'] = 'Tietokannan nimi'; -$a->strings['Site administrator email address'] = 'Sivuston ylläpitäjän sähköpostiosoite'; -$a->strings['Your account email address must match this in order to use the web admin panel.'] = 'Tilisi sähköpostiosoitteen on vastattava tätä, jotta voit käyttää ylläpitokäyttöliittymää.'; -$a->strings['Please select a default timezone for your website'] = 'Valitse oletusaikavyöhyke sivustollesi'; -$a->strings['Site settings'] = 'Sivuston asetukset'; -$a->strings['System Language:'] = 'Järjestelmän kieli:'; -$a->strings['Set the default language for your Friendica installation interface and to send emails.'] = 'Valitse Friendica-sivustosi oletuskieli.'; -$a->strings['The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'] = 'Tietokannan asetustiedostoa ".htconfig.php" ei pystytty kirjoittamaan. Käytä mukaanliitettyä tekstiä luomaan asetustiedosto web-palvelimesi juureen.'; -$a->strings['

What next

'] = '

Mitä seuraavaksi

'; -$a->strings['IMPORTANT: You will need to [manually] setup a scheduled task for the worker.'] = 'TÄRKEÄÄ: Sinun pitää asettaa [manuaalisesti] ajastettu tehtävä Workerille.'; -$a->strings['New Message'] = 'Uusi viesti'; -$a->strings['Unable to locate contact information.'] = 'Kontaktin tiedot ei löydy.'; -$a->strings['Messages'] = 'Viestit'; -$a->strings['Do you really want to delete this message?'] = 'Haluatko varmasti poistaa viestin?'; -$a->strings['Message deleted.'] = 'Viesti poistettu.'; -$a->strings['Conversation removed.'] = 'Keskustelu poistettu.'; -$a->strings['No messages.'] = 'Ei viestejä.'; -$a->strings['Message not available.'] = 'Viesti ei saatavilla.'; -$a->strings['Delete message'] = 'Poista viesti'; -$a->strings['D, d M Y - g:i A'] = 'D, j.n.Y - H:i'; -$a->strings['Delete conversation'] = 'Poista keskustelu'; -$a->strings['Send Reply'] = 'Lähetä vastaus'; -$a->strings['Unknown sender - %s'] = 'Tuntematon lähettäjä - %s'; -$a->strings['You and %s'] = 'Sinä ja %s'; -$a->strings['%s and You'] = '%s ja sinä'; -$a->strings['%d message'] = [ - 0 => '%d viesti', - 1 => '%d viestiä', -]; -$a->strings['Theme settings updated.'] = 'Teeman asetukset päivitetty.'; -$a->strings['Information'] = 'Tietoja'; -$a->strings['Overview'] = 'Yleiskatsaus'; -$a->strings['Federation Statistics'] = 'Liiton tilastotiedot'; -$a->strings['Configuration'] = 'Kokoonpano'; -$a->strings['Site'] = 'Sivusto'; -$a->strings['Users'] = 'Käyttäjät'; -$a->strings['Addons'] = 'Lisäosat'; -$a->strings['Themes'] = 'Teemat'; -$a->strings['Additional features'] = 'Lisäominaisuuksia'; -$a->strings['Terms of Service'] = 'Käyttöehdot'; -$a->strings['Database'] = 'Tietokanta'; -$a->strings['DB updates'] = 'Tietokannan päivitykset'; -$a->strings['Inspect Queue'] = 'Tarkista jono'; -$a->strings['Tools'] = 'Työkalut'; -$a->strings['Contact Blocklist'] = 'Kontaktien estolista'; -$a->strings['Server Blocklist'] = 'Palvelimien estolista'; -$a->strings['Delete Item'] = 'Poista kohde'; -$a->strings['Logs'] = 'Lokit'; -$a->strings['View Logs'] = 'Katso lokit'; -$a->strings['Diagnostics'] = 'Diagnostiikka'; -$a->strings['PHP Info'] = 'PHP tietoja'; -$a->strings['check webfinger'] = 'Tarkista webfinger'; -$a->strings['Admin'] = 'Ylläpitäjä'; -$a->strings['Addon Features'] = 'Lisäosaominaisuudet'; -$a->strings['User registrations waiting for confirmation'] = 'Käyttäjärekisteröinnit odottavat hyväksyntää'; -$a->strings['Administration'] = 'Ylläpito'; -$a->strings['Display Terms of Service'] = 'Näytä käyttöehdot'; -$a->strings['Display Privacy Statement'] = 'Näytä tietosuojalausunto'; -$a->strings['The Terms of Service'] = 'Käyttöehdot'; -$a->strings['The blocked domain'] = 'Estetty verkkotunnus'; -$a->strings['The reason why you blocked this domain.'] = 'Verkkotunnuksen estosyy.'; -$a->strings['Delete domain'] = 'Poista verkkotunnus'; -$a->strings['Check to delete this entry from the blocklist'] = 'Laita rasti poistaaksesi kohde estolistalta'; -$a->strings['Add new entry to block list'] = 'Lisää uusi kohde estolistaan'; -$a->strings['Server Domain'] = 'Palvelimen verkkotunnus'; -$a->strings['Block reason'] = 'Estosyy'; -$a->strings['Add Entry'] = 'Lisää merkintä'; -$a->strings['Save changes to the blocklist'] = 'Tallenna muutoksia estolistaan'; -$a->strings['Current Entries in the Blocklist'] = 'Nykyinen estolista'; -$a->strings['Delete entry from blocklist'] = 'Poista kohde estolistalta'; -$a->strings['Delete entry from blocklist?'] = 'Poista kohde estolistalta?'; -$a->strings['Server added to blocklist.'] = 'Palvelin lisätty estolistalle'; -$a->strings['Site blocklist updated.'] = 'Sivuston estolista päivitetty.'; -$a->strings['The contact has been blocked from the node'] = 'Kontakti on estetty tällä solmulla'; +$a->strings['System down for maintenance'] = 'Järjestelmä poiskytketty huoltoa varten'; +$a->strings['Files'] = 'Tiedostot'; +$a->strings['Upload'] = 'Lähetä'; +$a->strings['Or - did you try to upload an empty file?'] = 'Yrititkö ladata tyhjän tiedoston?'; +$a->strings['File exceeds size limit of %s'] = 'Tiedosto ylittää kokorajoituksen %s'; +$a->strings['File upload failed.'] = 'Tiedoston lähettäminen epäonnistui.'; +$a->strings['Unable to process image.'] = 'Kuvan käsitteleminen epäonnistui.'; +$a->strings['Image upload failed.'] = 'Kuvan lähettäminen epäonnistui.'; +$a->strings['Normal Account Page'] = 'Tavallinen käyttäjätili'; +$a->strings['Soapbox Page'] = 'Saarnatuoli sivu'; +$a->strings['Personal Page'] = 'Henkilökohtainen sivu'; +$a->strings['Organisation Page'] = 'Järjestön sivu'; +$a->strings['News Page'] = 'Uutissivu'; $a->strings['%s contact unblocked'] = [ 0 => '%s kontakti poistettu estolistalta', 1 => '%s kontaktia poistettu estolistalta', @@ -771,476 +908,105 @@ $a->strings['select none'] = 'älä valitse mitään'; $a->strings['Blocked Remote Contacts'] = 'Estetty etäkontaktit'; $a->strings['Block New Remote Contact'] = 'Estä uusi etäkontakti'; $a->strings['Photo'] = 'Kuva'; -$a->strings['Address'] = 'Osoite'; $a->strings['%s total blocked contact'] = [ 0 => 'Yhteensä %s estetty kontakti', 1 => 'Yhteensä %s estettyjä kontakteja', ]; $a->strings['URL of the remote contact to block.'] = 'Estettävän etäkontaktin URL-osoite'; +$a->strings['Block reason'] = 'Estosyy'; +$a->strings['Check to delete this entry from the blocklist'] = 'Laita rasti poistaaksesi kohde estolistalta'; +$a->strings['Save changes to the blocklist'] = 'Tallenna muutoksia estolistaan'; +$a->strings['Current Entries in the Blocklist'] = 'Nykyinen estolista'; +$a->strings['Item marked for deletion.'] = 'Kohde merkitty poistettavaksi.'; $a->strings['Delete this Item'] = 'Poista tämä kohde'; $a->strings['GUID'] = 'GUID'; $a->strings['The GUID of the item you want to delete.'] = 'Poistettavan kohteen GUID.'; -$a->strings['Item marked for deletion.'] = 'Kohde merkitty poistettavaksi.'; -$a->strings['unknown'] = 'tuntematon'; -$a->strings['Currently this node is aware of %d nodes with %d registered users from the following platforms:'] = 'Tällä hetkellä tämä solmu havaitsee %d muita solmuja joissa %d rekisteröityneitä käyttäjiä. Tarkemmat tiedot:'; -$a->strings['Recipient Name'] = 'Vastaanottajan nimi'; -$a->strings['Recipient Profile'] = 'Vastaanottajan profiili'; -$a->strings['Network'] = 'Uutisvirta'; -$a->strings['Created'] = 'Luotu'; -$a->strings['Last Tried'] = 'Viimeksi yritetty'; -$a->strings['The database update failed. Please run "php bin/console.php dbstructure update" from the command line and have a look at the errors that might appear.'] = 'Tietokannan päivitys epäonnistui. Suorita komento "php bin/console.php dbstructure update" komentoriviltä ja lue mahdolliset virheviestit.'; -$a->strings['The worker was never executed. Please check your database structure!'] = 'Workeriä ei ole otettu käyttöön. Tarkista tietokantasi rakenne!'; -$a->strings['The last worker execution was on %s UTC. This is older than one hour. Please check your crontab settings.'] = 'Viimeisin worker -käynnistys tapahtui klo %s UTC, eli yli tunti sitten. Tarkista crontab -asetukset.'; +$a->strings['Type'] = 'Tyyppi'; +$a->strings['Item not found'] = 'Kohdetta ei löytynyt'; $a->strings['Normal Account'] = 'Perustili'; $a->strings['Automatic Follower Account'] = 'Automaattinen seuraajatili'; -$a->strings['Public Forum Account'] = 'Julkinen foorumitili'; $a->strings['Automatic Friend Account'] = 'Automaattinen kaveritili'; $a->strings['Blog Account'] = 'Blogitili'; -$a->strings['Private Forum Account'] = 'Yksityinen foorumitili'; -$a->strings['Message queues'] = 'Viestijonot'; -$a->strings['Summary'] = 'Yhteenveto'; $a->strings['Registered users'] = 'Rekisteröityneet käyttäjät'; $a->strings['Pending registrations'] = 'Vireillä olevat rekisteröinnit'; -$a->strings['Version'] = 'Versio'; -$a->strings['Active addons'] = 'Käytössäolevat lisäosat'; -$a->strings['Can not parse base url. Must have at least ://'] = 'Ei voitu jäsentää perusosoitetta. Täytyy sisältää ainakin ://'; -$a->strings['Site settings updated.'] = 'Sivuston asetukset päivitettiin.'; -$a->strings['No special theme for mobile devices'] = 'Ei mobiiliteemaa'; -$a->strings['No community page'] = 'Ei yhteisösivua'; -$a->strings['Public postings from users of this site'] = 'Julkiset julkaisut tämän sivuston käyttäjiltä'; -$a->strings['Public postings from the federated network'] = 'Julkiset julkaisut liittoutuneelta verkolta'; -$a->strings['Public postings from local users and the federated network'] = 'Julkiset julkaisut tältä sivustolta ja liittoutuneelta verkolta'; -$a->strings['Users, Global Contacts'] = 'Käyttäjät, maailmanlaajuiset kontaktit'; -$a->strings['One month'] = 'Yksi kuukausi'; -$a->strings['Three months'] = 'Kolme kuukautta'; -$a->strings['Half a year'] = 'Puoli vuotta'; -$a->strings['One year'] = 'Yksi vuosi'; -$a->strings['Multi user instance'] = 'Monen käyttäjän instanssi'; -$a->strings['Closed'] = 'Suljettu'; -$a->strings['Requires approval'] = 'Edellyttää hyväksyntää'; -$a->strings['Open'] = 'Avoin'; -$a->strings['Force all links to use SSL'] = 'Pakota kaikki linkit käyttämään SSL-yhteyttä'; -$a->strings['Don\'t check'] = 'Älä tarkista'; -$a->strings['Registration'] = 'Rekisteröityminen'; -$a->strings['File upload'] = 'Tiedoston lataus'; -$a->strings['Policies'] = 'Käytännöt'; -$a->strings['Performance'] = 'Suoritus'; -$a->strings['Worker'] = 'Worker'; -$a->strings['Message Relay'] = 'Viestirele'; -$a->strings['Site name'] = 'Sivuston nimi'; -$a->strings['Host name'] = 'Palvelimen nimi'; -$a->strings['Sender Email'] = 'Lähettäjän sähköposti'; -$a->strings['The email address your server shall use to send notification emails from.'] = 'Lähettäjän sähköpostiosoite palvelimen ilmoitussähköposteissa.'; -$a->strings['Banner/Logo'] = 'Banneri/logo'; -$a->strings['Shortcut icon'] = 'Pikakuvake'; -$a->strings['Link to an icon that will be used for browsers.'] = 'Linkki kuvakkeeseen jota selaimet saa käyttää.'; -$a->strings['Touch icon'] = 'Kosketusnäyttökuvake'; -$a->strings['Link to an icon that will be used for tablets and mobiles.'] = 'Linkki kuvakkeeseen jota tabletit ja matkapuhelimet saa käyttää.'; -$a->strings['Additional Info'] = 'Lisätietoja'; -$a->strings['System language'] = 'Järjestelmän kieli'; -$a->strings['System theme'] = 'Järjestelmäteema'; -$a->strings['Mobile system theme'] = 'Mobiili järjestelmäteema'; -$a->strings['Theme for mobile devices'] = 'Mobiiliteema'; -$a->strings['SSL link policy'] = 'SSL-linkkikäytäntö'; -$a->strings['Determines whether generated links should be forced to use SSL'] = 'Määrittää pakotetaanko tuotetut linkit käyttämään SSL-yhteyttä.'; -$a->strings['Force SSL'] = 'Pakoita SSL-yhteyden käyttöä'; -$a->strings['Single user instance'] = 'Yksittäisen käyttäjän instanssi'; -$a->strings['Maximum image size'] = 'Suurin kuvakoko'; -$a->strings['Maximum size in bytes of uploaded images. Default is 0, which means no limits.'] = 'Ladattavan kuvatiedoston enimmäiskoko tavuina. Oletusarvo on 0, eli ei enimmäiskokoa.'; -$a->strings['Maximum image length'] = 'Suurin kuvapituus'; -$a->strings['Maximum length in pixels of the longest side of uploaded images. Default is -1, which means no limits.'] = 'Ladattavan kuvatiedoston enimmäispituus pikseleinä. Oletusarvo on -1, eli ei enimmäispituutta.'; -$a->strings['JPEG image quality'] = 'JPEG-kuvanlaatu'; -$a->strings['Uploaded JPEGS will be saved at this quality setting [0-100]. Default is 100, which is full quality.'] = 'Ladatut JPEG-kuvat tallennetaan tällä laatuasetuksella [0-100]. Oletus on 100, eli korkein laatu.'; -$a->strings['Register policy'] = 'Rekisteröintipolitiikka'; -$a->strings['Maximum Daily Registrations'] = 'Päivittäinen rekisteröitymisraja'; -$a->strings['If registration is permitted above, this sets the maximum number of new user registrations to accept per day. If register is set to closed, this setting has no effect.'] = 'Mikäli rekisteröityminen on sallittu, tämä asettaa enimmäismäärä uusia rekisteröitymisiä päivässä. Jos reksiteröityminen ei ole sallittu, tällä asetuksella ei ole vaikutusta.'; -$a->strings['Register text'] = 'Rekisteröitymisteksti'; -$a->strings['Will be displayed prominently on the registration page. You can use BBCode here.'] = 'Näkyvästi esillä rekisteröitymissivulla. Voit käyttää BBCodeia.'; -$a->strings['Accounts abandoned after x days'] = 'Käyttäjätilit hylätään X päivän jälkeen'; -$a->strings['Allowed friend domains'] = 'Sallittuja kaveri-verkkotunnuksia'; -$a->strings['Allowed email domains'] = 'Sallittuja sähköposti-verkkotunnuksia'; -$a->strings['Allowed OEmbed domains'] = 'Sallittuja OEmbed -verkkotunnuksia'; -$a->strings['Block public'] = 'Estä vierailijat'; -$a->strings['Global directory URL'] = 'Maailmanlaajuisen hakemiston URL-osoite'; -$a->strings['Don\'t include post content in email notifications'] = 'Älä lisää julkaisun sisältö sähköposti-ilmoitukseen'; -$a->strings['Don\'t embed private images in posts'] = 'Älä upota yksityisiä kuvia julkaisuissa'; -$a->strings['OpenID support'] = 'OpenID-tuki'; -$a->strings['OpenID support for registration and logins.'] = 'OpenID-tuki rekisteröitymiseen ja kirjautumiseen'; -$a->strings['Fullname check'] = 'Koko nimi tarkistus'; -$a->strings['Community pages for visitors'] = 'Yhteisösivu vieraille'; -$a->strings['The maximum number of posts per user on the community page. (Not valid for \'Global Community\')'] = 'Enimmäismäärä julkaisuja käyttäjää kohden yhteisösivulla. (Ei koske maailmanlaajuista yhteisösivua.)'; -$a->strings['Enable OStatus support'] = 'Salli OStatus-tuki'; -$a->strings['Only import OStatus threads from our contacts'] = 'Ainoastaan tuo OStatus -ketjuja kontakteiltamme'; -$a->strings['OStatus support can only be enabled if threading is enabled.'] = 'OStatus-tuki voidaan ottaa käyttöön ainoastaan jos ketjuttaminen on jo otettu käyttöön.'; -$a->strings['Diaspora support can\'t be enabled because Friendica was installed into a sub directory.'] = 'Diaspora -tukea ei voitu ottaa käyttöön koska Friendica on asennettu alihakemistoon.'; -$a->strings['Enable Diaspora support'] = 'Salli Diaspora-tuki'; -$a->strings['Provide built-in Diaspora network compatibility.'] = 'Ota käyttöön Diaspora-yhteensopivuus'; -$a->strings['Only allow Friendica contacts'] = 'Salli ainoastaan Friendica -kontakteja'; -$a->strings['All contacts must use Friendica protocols. All other built-in communication protocols disabled.'] = 'Kaikkien kontaktien on käytettävä Friendica-protokollaa. Kaikki muut protokollat poistetaan käytöstä.'; -$a->strings['Verify SSL'] = 'Vahvista SSL'; -$a->strings['Proxy user'] = 'Välityspalvelimen käyttäjä'; -$a->strings['Proxy URL'] = 'Välityspalvelimen osoite'; -$a->strings['Network timeout'] = 'Verkon aikakatkaisu'; -$a->strings['Maximum Load Average'] = 'Kuorman enimmäiskeksiarvo'; -$a->strings['Maximum system load before delivery and poll processes are deferred - default 50.'] = 'Järjestelmäkuormitus jolloin lähetys- ja kyselyprosessit lykätään (oletusarvo 50).'; -$a->strings['Maximum Load Average (Frontend)'] = 'Kuorman enimmäiskeskiarvo (Frontend)'; -$a->strings['Maximum system load before the frontend quits service - default 50.'] = 'Järjestelmäkuormitus jolloin Frontend poistetaan käytöstä (oletusarvo 50).'; -$a->strings['Maximum table size for optimization'] = 'Taulukon enimmäiskoko optimointia varten'; -$a->strings['Discover contacts from other servers'] = 'Etsi kontakteja muilta palvelimilta'; -$a->strings['Search the local directory'] = 'Paikallisluettelohaku'; -$a->strings['Publish server information'] = 'Julkaise palvelintiedot'; -$a->strings['Suppress Tags'] = 'Piilota tunnisteet'; -$a->strings['Suppress showing a list of hashtags at the end of the posting.'] = 'Piilota tunnistelista julkaisun lopussa.'; -$a->strings['Clean database'] = 'Siivoa tietokanta'; -$a->strings['Cache duration in seconds'] = 'Välimuistin kesto sekunteina'; -$a->strings['Maximum numbers of comments per post'] = 'Julkaisun kommentiraja'; -$a->strings['Temp path'] = 'Väliaikaistiedostojen polku'; -$a->strings['If you have a restricted system where the webserver can\'t access the system temp path, enter another path here.'] = 'Mikäli verkkopalvelimesi ei voi käyttää järjestelmän väliaikaistiedostojen polkua, syötä toinen polku tähän.'; -$a->strings['Base path to installation'] = 'Asennuksen peruspolku'; -$a->strings['Only search in tags'] = 'Tunnistehaku'; -$a->strings['New base url'] = 'Uusi perusosoite'; -$a->strings['Change base url for this server. Sends relocate message to all Friendica and Diaspora* contacts of all users.'] = 'Vaihtaa tämän palvelimen perus-URL-osoitteen. Lähettää uudelleensijoitusviestit käyttäjien kaikille kontakteille Friendicassa ja Diasporassa*.'; -$a->strings['RINO Encryption'] = 'RINO-salaus'; -$a->strings['Encryption layer between nodes.'] = 'Salauskerros solmujen välillä.'; -$a->strings['Enabled'] = 'Käytössä'; -$a->strings['Maximum number of parallel workers'] = 'Enimmäismäärä rinnakkaisia workereitä'; -$a->strings['Enable fastlane'] = 'Käytä fastlane'; -$a->strings['Enable frontend worker'] = 'Ota Frontend Worker käyttöön'; -$a->strings['Subscribe to relay'] = 'Relen tilaus'; -$a->strings['Relay server'] = 'Relepalvelin'; -$a->strings['Direct relay transfer'] = 'Suora releen siirto'; -$a->strings['Relay scope'] = 'Relen soveltamisala'; -$a->strings['all'] = 'kaikki'; -$a->strings['tags'] = 'tunnisteet'; -$a->strings['Server tags'] = 'palvelintunnisteet'; -$a->strings['Comma separated list of tags for the \'tags\' subscription.'] = 'Pilkulla erotettu tunnistelista tunnistetilausta varten.'; -$a->strings['Allow user tags'] = 'Salli käyttäjien tunnisteet'; -$a->strings['If enabled, the tags from the saved searches will used for the \'tags\' subscription in addition to the \'relay_server_tags\'.'] = 'Jos otettu käyttöön, tunnisteet tallennetuista hauista käytetään tunnistetilaukseen \'relay_server_tags\'in lisäksi.'; -$a->strings['Database structure update %s was successfully applied.'] = 'Tietokannan rakenteen %s-päivitys onnistui.'; -$a->strings['Executing of database structure update %s failed with error: %s'] = 'Tietokannan rakennepäivitys %s epäonnistui virheviestillä %s'; -$a->strings['Update %s was successfully applied.'] = '%s-päivitys onnistui.'; -$a->strings['No failed updates.'] = 'Ei epäonnistuineita päivityksiä.'; -$a->strings['Check database structure'] = 'Tarkista tietokannan rakenne'; -$a->strings['Failed Updates'] = 'Epäonnistuineita päivityksiä'; -$a->strings['%s user blocked/unblocked'] = [ - 0 => '%s käyttäjä estetty / poistettu estolistalta', - 1 => '%s käyttäjää estetty / poistettu estolistalta', -]; $a->strings['%s user deleted'] = [ 0 => '%s käyttäjä poistettu', 1 => '%s käyttäjää poistettu', ]; -$a->strings['User \'%s\' deleted'] = 'Käyttäjä \'%s\' poistettu'; -$a->strings['User \'%s\' unblocked'] = 'Käyttäjä \'%s\' poistettu estolistalta'; -$a->strings['User \'%s\' blocked'] = 'Käyttäjä \'%s\' estetty'; -$a->strings['Normal Account Page'] = 'Tavallinen käyttäjätili'; -$a->strings['Soapbox Page'] = 'Saarnatuoli sivu'; -$a->strings['Public Forum'] = 'Julkinen foorumi'; -$a->strings['Private Forum'] = 'Yksityisfoorumi'; -$a->strings['Personal Page'] = 'Henkilökohtainen sivu'; -$a->strings['Organisation Page'] = 'Järjestön sivu'; -$a->strings['News Page'] = 'Uutissivu'; -$a->strings['Community Forum'] = 'Yhteisöfoorumi'; -$a->strings['Email'] = 'Sähköposti'; $a->strings['Register date'] = 'Rekisteripäivämäärä'; $a->strings['Last login'] = 'Viimeisin kirjautuminen'; -$a->strings['Last item'] = 'Viimeisin kohde'; -$a->strings['Type'] = 'Tyyppi'; -$a->strings['Add User'] = 'Lisää käyttäjä'; -$a->strings['Request date'] = 'Pyynnön päivämäärä'; -$a->strings['No registrations.'] = 'Ei rekisteröintejä.'; -$a->strings['Approve'] = 'Hyväksy'; -$a->strings['Deny'] = 'Kieltäydy'; $a->strings['Site admin'] = 'Sivuston ylläpito'; $a->strings['Account expired'] = 'Tili vanhentunut'; $a->strings['New User'] = 'Uusi käyttäjä'; -$a->strings['Deleted since'] = 'Poistettu'; +$a->strings['Add User'] = 'Lisää käyttäjä'; $a->strings['Name of the new user.'] = 'Uuden käyttäjän nimi.'; $a->strings['Nickname'] = 'Lempinimi'; $a->strings['Nickname of the new user.'] = 'Uuden käyttäjän lempinimi'; $a->strings['Email address of the new user.'] = 'Uuden käyttäjän sähköpostiosoite.'; -$a->strings['Addon %s disabled.'] = 'Lisäosa %s poistettu käytöstä.'; -$a->strings['Addon %s enabled.'] = 'Lisäosa %s käytössä.'; -$a->strings['Disable'] = 'Poista käytöstä'; -$a->strings['Enable'] = 'Ota käyttöön'; -$a->strings['Toggle'] = 'Vaihda'; -$a->strings['Author: '] = 'Tekijä'; -$a->strings['Maintainer: '] = 'Ylläpitäjä:'; -$a->strings['No themes found.'] = 'Teemoja ei löytynyt.'; -$a->strings['Screenshot'] = 'Kuvakaappaus'; -$a->strings['Reload active themes'] = 'Lataa aktiiviset teemat uudelleen'; -$a->strings['No themes found on the system. They should be placed in %1$s'] = 'Teemoja ei löytynyt järjestelmästä. Teemat tulisi laittaa kansioon %1$s'; -$a->strings['[Experimental]'] = '[Kokeellinen]'; -$a->strings['[Unsupported]'] = '[Ei tueta]'; -$a->strings['Log settings updated.'] = 'Lokiasetukset päivitetty.'; -$a->strings['PHP log currently enabled.'] = 'PHP-loki käytössä'; -$a->strings['PHP log currently disabled.'] = 'PHP-loki pois käytöstä'; -$a->strings['Clear'] = 'Tyhjennä'; -$a->strings['Enable Debugging'] = 'Ota virheenkorjaustila käyttöön'; -$a->strings['Log file'] = 'Lokitiedosto'; -$a->strings['Log level'] = 'Lokitaso'; -$a->strings['PHP logging'] = 'PHP-loki'; -$a->strings['Off'] = 'Pois päältä'; -$a->strings['On'] = 'Päällä'; -$a->strings['Lock feature %s'] = 'Lukitse ominaisuus %s'; -$a->strings['Manage Additional Features'] = 'Hallitse lisäominaisuudet'; -$a->strings['Community option not available.'] = 'Yhteisö vaihtoehto ei saatavilla.'; -$a->strings['Not available.'] = 'Ei saatavilla.'; -$a->strings['Local Community'] = 'Paikallinen yhteisö'; -$a->strings['Posts from local users on this server'] = 'Tämän palvelimen julkaisut'; -$a->strings['Global Community'] = 'Maailmanlaajuinen yhteisö'; -$a->strings['Posts from users of the whole federated network'] = 'Maailmanlaajuisen verkon julkaisut'; -$a->strings['No results.'] = 'Ei tuloksia.'; -$a->strings['Profile not found.'] = 'Profiilia ei löytynyt.'; -$a->strings['Response from remote site was not understood.'] = 'Etäsivuston vastaus oli epäselvä.'; -$a->strings['Unexpected response from remote site: '] = 'Odottamaton vastaus etäsivustolta:'; -$a->strings['Confirmation completed successfully.'] = 'Vahvistus onnistui.'; -$a->strings['Temporary failure. Please wait and try again.'] = 'Tilapäinen vika. Yritä myöhemmin uudelleen.'; -$a->strings['Introduction failed or was revoked.'] = 'Kaverikutsu epäonnistui tai oli peruutettu.'; -$a->strings['Unable to set contact photo.'] = 'Kontaktin kuvaa ei voitu asettaa'; -$a->strings['Our site encryption key is apparently messed up.'] = 'Sivustomme salausavain on sekaisin.'; -$a->strings['[Name Withheld]'] = '[Nimi jätetty pois]'; -$a->strings['This introduction has already been accepted.'] = 'Tämä esittely on jo hyväksytty.'; -$a->strings['Profile location is not valid or does not contain profile information.'] = 'Profiilin sijainti on viallinen tai se ei sisällä profiilitietoja.'; -$a->strings['Warning: profile location has no identifiable owner name.'] = 'Varoitus: profiilin sijainnissa ei ole tunnistettavaa omistajan nimeä.'; -$a->strings['Warning: profile location has no profile photo.'] = 'Varoitus: profiilin sijainnissa ei ole profiilikuvaa.'; -$a->strings['Introduction complete.'] = 'Esittely valmis.'; -$a->strings['Unrecoverable protocol error.'] = 'Vakava protokollavirhe.'; -$a->strings['Profile unavailable.'] = 'Profiili ei saatavilla.'; -$a->strings['%s has received too many connection requests today.'] = '%s on saanut liikaa yhteyspyyntöjä tänään.'; -$a->strings['Spam protection measures have been invoked.'] = 'Roskapostisuojaukset otettu käyttöön.'; -$a->strings['Friends are advised to please try again in 24 hours.'] = 'Ystäviä suositellaan yrittämään uudelleen vuorokauden sisällä.'; -$a->strings['Invalid locator'] = 'Viallinen paikannin'; -$a->strings['You have already introduced yourself here.'] = 'Olet jo esitellyt itsesi täällä.'; -$a->strings['Apparently you are already friends with %s.'] = 'Ilmeisesti olet jo ystävystynyt henkilön %s kanssa.'; -$a->strings['Invalid profile URL.'] = 'Viallinen profiiliosoite.'; -$a->strings['Disallowed profile URL.'] = 'Kielletty profiiliosoite.'; -$a->strings['Your introduction has been sent.'] = 'Esittelysi lähetettiin.'; -$a->strings['Please login to confirm introduction.'] = 'Kirjaudu vahvistaaksesi esittelysi.'; -$a->strings['Incorrect identity currently logged in. Please login to this profile.'] = 'Väärä identiteetti kirjautuneena sisään. Kirjaudu tähän profiiliin.'; -$a->strings['Confirm'] = 'Vahvista'; -$a->strings['Hide this contact'] = 'Piilota kontakti'; -$a->strings['Welcome home %s.'] = 'Tervetuloa kotiin %s.'; -$a->strings['Please confirm your introduction/connection request to %s.'] = 'Vahvista esittelysi/yhteyspyyntösi henkilölle %s.'; -$a->strings['Please enter your \'Identity Address\' from one of the following supported communications networks:'] = 'Anna "henkilöllisyysosoitteesi" joissakin seuraavista tuetuista viestintäverkoista:'; -$a->strings['Friend/Connection Request'] = 'Ystävä/yhteyspyyntö'; -$a->strings['Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@gnusocial.de'] = 'Esim. jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@gnusocial.de'; -$a->strings['Friendica'] = 'Friendica'; -$a->strings['GNU Social (Pleroma, Mastodon)'] = 'GNU Social (Pleroma, Mastodon)'; -$a->strings['Diaspora (Socialhome, Hubzilla)'] = 'Diaspora (Socialhome, Hubzilla)'; -$a->strings[' - please do not use this form. Instead, enter %s into your Diaspora search bar.'] = ' - älä käytä tätä lomaketta. Kirjoita sen sijaan %s Diaspora-hakupalkkiisi.'; -$a->strings['Event can not end before it has started.'] = 'Tapahtuma ei voi päättyä ennen kuin on alkanut.'; -$a->strings['Event title and start time are required.'] = 'Tapahtuman nimi ja alkamisaika vaaditaan.'; -$a->strings['Create New Event'] = 'Luo uusi tapahtuma'; -$a->strings['Event details'] = 'Tapahtuman tiedot'; -$a->strings['Starting date and Title are required.'] = 'Aloituspvm ja otsikko vaaditaan.'; -$a->strings['Event Starts:'] = 'Tapahtuma alkaa:'; -$a->strings['Required'] = 'Vaaditaan'; -$a->strings['Finish date/time is not known or not relevant'] = 'Päättymispvm ja kellonaika ei ole tiedossa tai niillä ei ole merkitystä'; -$a->strings['Event Finishes:'] = 'Tapahtuma päättyy:'; -$a->strings['Adjust for viewer timezone'] = 'Ota huomioon katsojan aikavyöhyke'; -$a->strings['Description:'] = 'Kuvaus:'; -$a->strings['Title:'] = 'Otsikko:'; -$a->strings['Share this event'] = 'Jaa tämä tapahtuma'; -$a->strings['Permissions'] = 'Käyttöoikeudet'; -$a->strings['Failed to remove event'] = 'Tapahtuman poisto epäonnistui'; -$a->strings['Event removed'] = 'Tapahtuma poistettu'; -$a->strings['Group created.'] = 'Ryhmä luotu.'; -$a->strings['Could not create group.'] = 'Ryhmää ei voitu luoda.'; -$a->strings['Group not found.'] = 'Ryhmää ei löytynyt.'; -$a->strings['Group name changed.'] = 'Ryhmän nimi muutettu.'; -$a->strings['Save Group'] = 'Tallenna ryhmä'; -$a->strings['Create a group of contacts/friends.'] = 'Luo kontakti/kaveriryhmä'; -$a->strings['Group Name: '] = 'Ryhmän nimi:'; -$a->strings['Group removed.'] = 'Ryhmä poistettu.'; -$a->strings['Unable to remove group.'] = 'Ryhmää ei voida poistaa.'; -$a->strings['Delete Group'] = 'Poista ryhmä'; -$a->strings['Group Editor'] = 'Ryhmien muokkausta'; -$a->strings['Edit Group Name'] = 'Muokkaa ryhmän nimeä'; -$a->strings['Members'] = 'Jäsenet'; -$a->strings['Group is empty'] = 'Ryhmä on tyhjä'; -$a->strings['Remove contact from group'] = 'Poista kontakti ryhmästä'; -$a->strings['Add contact to group'] = 'Lisää kontakti ryhmään'; -$a->strings['Unable to locate original post.'] = 'Alkuperäinen julkaisu ei löydy.'; -$a->strings['Empty post discarded.'] = 'Tyhjä julkaisu hylätty.'; -$a->strings['This message was sent to you by %s, a member of the Friendica social network.'] = 'Viestin lähetti %s Friendica sosiaaliverkoston kautta.'; -$a->strings['%s posted an update.'] = '%s julkaisi päivityksen.'; -$a->strings['Remove term'] = 'Poista kohde'; -$a->strings['Saved Searches'] = 'Tallennetut haut'; -$a->strings['add'] = 'lisää'; -$a->strings['No such group'] = 'Ryhmä ei ole olemassa'; -$a->strings['Group: %s'] = 'Ryhmä: %s'; -$a->strings['Private messages to this person are at risk of public disclosure.'] = 'Yksityisviestit lähetetty tälle henkilölle saattaa näkyä muillekin.'; -$a->strings['Invalid contact.'] = 'Virheellinen kontakti.'; -$a->strings['Commented Order'] = 'Järjestä viimeisimpien kommenttien mukaan'; -$a->strings['Sort by Comment Date'] = 'Kommentit päivämäärän mukaan'; -$a->strings['Posted Order'] = 'Järjestä julkaisupäivämäärän mukaan'; -$a->strings['Sort by Post Date'] = 'Julkaisut päivämäärän mukaan'; -$a->strings['Personal'] = 'Henkilökohtainen'; -$a->strings['Posts that mention or involve you'] = 'Julkaisut jotka liittyvät sinuun'; -$a->strings['New'] = 'Uusi'; -$a->strings['Shared Links'] = 'Jaetut linkit'; -$a->strings['Interesting Links'] = 'Kiinnostavat linkit'; -$a->strings['Starred'] = 'Tähtimerkitty'; -$a->strings['Favourite Posts'] = 'Lempijulkaisut'; -$a->strings['Personal Notes'] = 'Henkilökohtaiset tiedot'; -$a->strings['Invalid request identifier.'] = 'Virheellinen pyyntötunniste.'; -$a->strings['Discard'] = 'Hylkää'; -$a->strings['Notifications'] = 'Huomautukset'; -$a->strings['Network Notifications'] = 'Uutisvirtailmoitukset'; -$a->strings['Personal Notifications'] = 'Henkilökohtaiset ilmoitukset'; -$a->strings['Home Notifications'] = 'Koti-ilmoitukset'; +$a->strings['Account approved.'] = 'Tili hyväksytty.'; +$a->strings['Request date'] = 'Pyynnön päivämäärä'; +$a->strings['No registrations.'] = 'Ei rekisteröintejä.'; +$a->strings['Deny'] = 'Kieltäydy'; $a->strings['Show Ignored Requests'] = 'Näytä ohitetut pyynnöt'; $a->strings['Hide Ignored Requests'] = 'Piilota ohitetut pyynnöt'; -$a->strings['Notification type: '] = 'Ilmoitustyyppi:'; -$a->strings['suggested by %s'] = 'ehdottaa %s'; $a->strings['Claims to be known to you: '] = 'Väittää tuntevansa sinut:'; -$a->strings['yes'] = 'kyllä'; -$a->strings['no'] = 'ei'; +$a->strings['No'] = 'Ei'; $a->strings['Shall your connection be bidirectional or not?'] = 'Kaksisuuntainen yhteys?'; $a->strings['Friend'] = 'Kaveri'; -$a->strings['Sharer'] = 'Jakaja'; $a->strings['Subscriber'] = 'Tilaaja'; $a->strings['No introductions.'] = 'Ei esittelyjä.'; -$a->strings['Show unread'] = 'Näytä lukemattomat'; -$a->strings['Show all'] = 'Näytä kaikki'; $a->strings['No more %s notifications.'] = 'Ei muita %s ilmoituksia.'; -$a->strings['OpenID protocol error. No ID returned.'] = 'OpenID -protokollavirhe. Tunnusta ei vastaanotettu.'; -$a->strings['Account not found and OpenID registration is not permitted on this site.'] = 'Käyttäjätiliä ei löytynyt. Rekisteröityminen OpenID:n kautta ei ole sallittua tällä sivustolla.'; -$a->strings['Login failed.'] = 'Kirjautuminen epäonnistui'; -$a->strings['Photo Albums'] = 'Valokuva-albumit'; -$a->strings['Recent Photos'] = 'Viimeaikaisia kuvia'; -$a->strings['Upload New Photos'] = 'Lähetä uusia kuvia'; -$a->strings['everybody'] = 'kaikki'; -$a->strings['Contact information unavailable'] = 'Kontaktin tietoja ei saatavilla'; -$a->strings['Album not found.'] = 'Albumia ei ole.'; -$a->strings['Delete Album'] = 'Poista albumi'; -$a->strings['Do you really want to delete this photo album and all its photos?'] = 'Haluatko varmasti poistaa tämän albumin ja kaikki sen kuvat?'; -$a->strings['Delete Photo'] = 'Poista valokuva'; -$a->strings['Do you really want to delete this photo?'] = 'Haluatko varmasti poistaa kuvan?'; -$a->strings['a photo'] = 'valokuva'; -$a->strings['%1$s was tagged in %2$s by %3$s'] = '%1$s merkattiin kuvaan %2$s ystävän %3$s toimesta'; -$a->strings['Image upload didn\'t complete, please try again'] = 'Kuvan lataus ei onnistunut, yritä uudelleen'; -$a->strings['Image file is missing'] = 'Kuvatiedosto puuttuu'; -$a->strings['Image file is empty.'] = 'Kuvatiedosto on tyhjä.'; -$a->strings['No photos selected'] = 'Ei valittuja kuvia'; -$a->strings['Access to this item is restricted.'] = 'Pääsy kohteeseen on rajoitettu.'; -$a->strings['Upload Photos'] = 'Lähetä kuvia'; -$a->strings['New album name: '] = 'Albumin uusi nimi: '; -$a->strings['or existing album name: '] = 'tai olemassaolevan albumin nimi: '; -$a->strings['Do not show a status post for this upload'] = 'Älä näytä tilaviestiä tälle lähetykselle'; -$a->strings['Show to Groups'] = 'Näytä ryhmille'; -$a->strings['Show to Contacts'] = 'Näytä kontakteille'; -$a->strings['Edit Album'] = 'Muokkaa albumia'; -$a->strings['Show Newest First'] = 'Näytä uusin ensin'; -$a->strings['Show Oldest First'] = 'Näytä vanhin ensin'; -$a->strings['View Photo'] = 'Näytä kuva'; -$a->strings['Permission denied. Access to this item may be restricted.'] = 'Estetty. Tämän kohteen käyttöä on saatettu rajoittaa.'; -$a->strings['Photo not available'] = 'Kuva ei ole saatavilla'; -$a->strings['View photo'] = 'Näytä kuva'; -$a->strings['Edit photo'] = 'Muokkaa kuvaa'; -$a->strings['Use as profile photo'] = 'Käytä profiilikuvana'; -$a->strings['Private Message'] = 'Yksityisviesti'; -$a->strings['View Full Size'] = 'Näytä täysikokoisena'; -$a->strings['Tags: '] = 'Merkinnät:'; -$a->strings['[Remove any tag]'] = '[Poista mikä tahansa merkintä]'; -$a->strings['New album name'] = 'Uusi nimi albumille'; -$a->strings['Caption'] = 'Kuvateksti'; -$a->strings['Add a Tag'] = 'Lisää merkintä'; -$a->strings['Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'] = 'Esimerkki: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping'; -$a->strings['Do not rotate'] = 'Älä kierrä'; -$a->strings['Rotate CW (right)'] = 'Käännä oikealle'; -$a->strings['Rotate CCW (left)'] = 'Käännä vasemmalle'; -$a->strings['I like this (toggle)'] = 'Tykkään tästä (vaihda)'; -$a->strings['I don\'t like this (toggle)'] = 'En tykkää tästä (vaihda)'; -$a->strings['Comment'] = 'Kommentti'; -$a->strings['Map'] = 'Kartta'; -$a->strings['View Album'] = 'Näytä albumi'; -$a->strings['Requested profile is not available.'] = 'Pyydettyä profiilia ei saatavilla.'; +$a->strings['Network Notifications'] = 'Uutisvirtailmoitukset'; +$a->strings['System Notifications'] = 'Järjestelmäilmoitukset'; +$a->strings['Personal Notifications'] = 'Henkilökohtaiset ilmoitukset'; +$a->strings['Home Notifications'] = 'Koti-ilmoitukset'; +$a->strings['Show unread'] = 'Näytä lukemattomat'; +$a->strings['{0} requested registration'] = '{0} jätti rekisteröintipyynnön'; +$a->strings['Authorize application connection'] = 'Vahvista sovellusyhteys'; +$a->strings['Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'] = 'Haluatko antaa tälle sovellukselle luvan hakea viestejäsi ja yhteystietojasi ja/tai luoda uusia viestejä?'; +$a->strings['Resubscribing to OStatus contacts'] = 'OStatus -kontaktien uudelleentilaus'; +$a->strings['Keep this window open until done.'] = 'Pidä tämä ikkuna auki kunnes kaikki tehtävät on suoritettu.'; +$a->strings['No contact provided.'] = 'Kontakti puuttuu.'; +$a->strings['Couldn\'t fetch information for contact.'] = 'Kontaktin tietoja ei voitu hakea.'; +$a->strings['Couldn\'t fetch friends for contact.'] = 'Ei voitu hakea kontaktin kaverit.'; +$a->strings['Done'] = 'Valmis'; +$a->strings['success'] = 'onnistui'; +$a->strings['failed'] = 'epäonnistui'; +$a->strings['ignored'] = 'ohitettu'; +$a->strings['Remote privacy information not available.'] = 'Yksityisyyden etätietoja ei saatavilla.'; +$a->strings['Visible to:'] = 'Näkyvissä:'; +$a->strings['Edit post'] = 'Muokkaa viestiä'; +$a->strings['web link'] = 'WWW-linkki'; +$a->strings['Insert video link'] = 'Lisää videolinkki'; +$a->strings['video link'] = 'videolinkki'; +$a->strings['Insert audio link'] = 'Lisää äänilinkki'; +$a->strings['audio link'] = 'äänilinkki'; +$a->strings['Remove Item Tag'] = 'Poista tägi'; +$a->strings['Select a tag to remove: '] = 'Valitse tägi poistamista varten:'; +$a->strings['Remove'] = 'Poista'; +$a->strings['No contacts.'] = 'Ei kontakteja.'; $a->strings['%s\'s timeline'] = '%s: aikajana'; $a->strings['%s\'s posts'] = '%s: julkaisut'; $a->strings['%s\'s comments'] = '%s: kommentit'; -$a->strings['Tips for New Members'] = 'Vinkkejä uusille käyttäjille'; -$a->strings['Profile deleted.'] = 'Profiili poistettiin.'; -$a->strings['Profile-'] = 'Profiili-'; -$a->strings['New profile created.'] = 'Uusi profiili luotu.'; -$a->strings['Profile unavailable to clone.'] = 'Profiili ei saatavilla kloonattavaksi.'; -$a->strings['Profile Name is required.'] = 'Profiilinimi on pakollinen.'; -$a->strings['Marital Status'] = 'Siviilisääty'; -$a->strings['Romantic Partner'] = 'Romanttinen kumppani'; -$a->strings['Work/Employment'] = 'Työ'; -$a->strings['Religion'] = 'Uskonto'; -$a->strings['Political Views'] = 'Poliittiset näkemykset'; -$a->strings['Gender'] = 'Sukupuoli'; -$a->strings['Sexual Preference'] = 'Seksuaalinen suuntautuminen'; -$a->strings['XMPP'] = 'XMPP'; -$a->strings['Homepage'] = 'Kotisivu'; -$a->strings['Interests'] = 'Kiinnostukset'; -$a->strings['Location'] = 'Sijainti'; -$a->strings['Profile updated.'] = 'Profiili päivitettiin.'; -$a->strings['Hide contacts and friends:'] = 'Piilota kontaktit ja kaverit:'; -$a->strings['Hide your contact/friend list from viewers of this profile?'] = 'Piilota tämän profiilin kontakti/kaverilista?'; -$a->strings['Show more profile fields:'] = 'Näytä lisää profiilikenttiä:'; -$a->strings['Edit Profile Details'] = 'Muokkaa profiilin yksityiskohdat'; -$a->strings['Change Profile Photo'] = 'Vaihda profiilikuva'; -$a->strings['View this profile'] = 'Näytä profiilia'; -$a->strings['Edit visibility'] = 'Muokkaa näkyvyyttä'; -$a->strings['Create a new profile using these settings'] = 'Luo uusi profiili näillä asetuksilla'; -$a->strings['Clone this profile'] = 'Kloonaa tämä profiili'; -$a->strings['Delete this profile'] = 'Poista tämä profiili'; -$a->strings['Basic information'] = 'Perustiedot'; -$a->strings['Profile picture'] = 'Profiilikuva'; -$a->strings['Preferences'] = 'Mieltymykset'; -$a->strings['Status information'] = 'Tilatiedot'; -$a->strings['Additional information'] = 'Lisätietoja'; -$a->strings['Relation'] = 'Suhde'; -$a->strings['Miscellaneous'] = 'Sekalaista'; -$a->strings['Your Gender:'] = 'Sukupuoli:'; -$a->strings[' Marital Status:'] = ' Siviilisääty:'; -$a->strings['Sexual Preference:'] = 'Seksuaalinen suuntautuminen:'; -$a->strings['Example: fishing photography software'] = 'Esimerkki: kalastus valokuvaus ohjelmistot'; -$a->strings['Profile Name:'] = 'Profiilinimi:'; -$a->strings['Your Full Name:'] = 'Koko nimi:'; -$a->strings['Title/Description:'] = 'Otsikko/kuvaus:'; -$a->strings['Street Address:'] = 'Katuosoite:'; -$a->strings['Locality/City:'] = 'Kaupunki:'; -$a->strings['Region/State:'] = 'Alue/osavaltio:'; -$a->strings['Postal/Zip Code:'] = 'Postinumero:'; -$a->strings['Country:'] = 'Maa:'; +$a->strings['Image exceeds size limit of %s'] = 'Kuva ylittää kokorajoituksen %s'; +$a->strings['Image upload didn\'t complete, please try again'] = 'Kuvan lataus ei onnistunut, yritä uudelleen'; +$a->strings['Image file is missing'] = 'Kuvatiedosto puuttuu'; +$a->strings['Image file is empty.'] = 'Kuvatiedosto on tyhjä.'; +$a->strings['View Album'] = 'Näytä albumi'; +$a->strings['Profile not found.'] = 'Profiilia ei löytynyt.'; +$a->strings['Full Name:'] = 'Koko nimi:'; +$a->strings['Member since:'] = 'Liittymispäivämäärä:'; +$a->strings['j F, Y'] = 'j F, Y'; +$a->strings['j F'] = 'j F'; +$a->strings['Birthday:'] = 'Syntymäpäivä:'; $a->strings['Age: '] = 'Ikä:'; -$a->strings['Who: (if applicable)'] = 'Kuka: (tarvittaessa)'; -$a->strings['Examples: cathy123, Cathy Williams, cathy@example.com'] = 'Esimerkkejä: cathy123, Cathy Williams, cathy@example.com'; -$a->strings['Since [date]:'] = 'Lähtien [päivämäärä]:'; -$a->strings['Tell us about yourself...'] = 'Kerro vähän itsestäsi...'; -$a->strings['XMPP (Jabber) address:'] = 'XMPP (Jabber) osoite:'; -$a->strings['Homepage URL:'] = 'Kotisivun URL-osoite:'; -$a->strings['Hometown:'] = 'Kotikaupunki:'; -$a->strings['Political Views:'] = 'Politiikka:'; -$a->strings['Religious Views:'] = 'Uskonto:'; -$a->strings['Public Keywords:'] = 'Julkiset avainsanat:'; -$a->strings['(Used for suggesting potential friends, can be seen by others)'] = '(Käytetään kaveriehdotuksia varten, näkyy muille)'; -$a->strings['Private Keywords:'] = 'Yksityiset avainsanat:'; -$a->strings['(Used for searching profiles, never shown to others)'] = '(Käytetään profiilihakua varten, ei näy muille)'; -$a->strings['Likes:'] = 'Tykkäykset:'; -$a->strings['Dislikes:'] = 'Ei tykkää:'; -$a->strings['Musical interests'] = 'Musiikki'; -$a->strings['Books, literature'] = 'Kirjat, kirjallisuus'; -$a->strings['Television'] = 'Televisio'; -$a->strings['Film/dance/culture/entertainment'] = 'Elokuvat/tanssi/kulttuuri/viihde'; -$a->strings['Hobbies/Interests'] = 'Harrastukset'; -$a->strings['Love/romance'] = 'Rakkaus/romanssi'; -$a->strings['Work/employment'] = 'Työ:'; -$a->strings['School/education'] = 'Koulutus:'; -$a->strings['Contact information and Social Networks'] = 'Yhteystiedot ja sosiaalinen media'; -$a->strings['Profile Image'] = 'Profiilikuva'; -$a->strings['visible to everybody'] = 'näkyvissä kaikille'; -$a->strings['Edit/Manage Profiles'] = 'Muokkaa/hallitse profiilit'; -$a->strings['Change profile photo'] = 'Vaihda profiilikuva'; -$a->strings['Create New Profile'] = 'Luo uusi profiili'; -$a->strings['Registration successful. Please check your email for further instructions.'] = 'Rekisteröityminen onnistui. Saat kohta lisäohjeita sähköpostitse.'; -$a->strings['Registration successful.'] = 'Rekisteröityminen onnistui.'; -$a->strings['Your registration can not be processed.'] = 'Rekisteröintisi ei voida käsitellä.'; -$a->strings['Your registration is pending approval by the site owner.'] = 'Rekisteröintisi odottaa ylläpitäjän hyväksyntää.'; +$a->strings['Description:'] = 'Kuvaus:'; +$a->strings['Profile unavailable.'] = 'Profiili ei saatavilla.'; +$a->strings['Invalid locator'] = 'Viallinen paikannin'; +$a->strings['Friend/Connection Request'] = 'Ystävä/yhteyspyyntö'; +$a->strings['Unable to check your home location.'] = 'Kotisijaintisi ei voitu tarkistaa.'; +$a->strings['Number of daily wall messages for %s exceeded. Message failed.'] = '%s-käyttäjän päivittäinen seinäviestiraja ylitetty. Viestin lähettäminen epäonnistui.'; +$a->strings['This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.'] = 'Sivuston päivittäinen rekisteröintiraja ylitetty. Yritä uudelleen huomenna.'; $a->strings['If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items.'] = 'Jos OpenID ei ole tuttu, jätä kenttä tyhjäksi.'; $a->strings['Your OpenID (optional): '] = 'OpenID -tunnus (valinnainen):'; $a->strings['Include your profile in member directory?'] = 'Lisää profiilisi jäsenluetteloon?'; @@ -1254,118 +1020,37 @@ $a->strings['New Password:'] = 'Uusi salasana:'; $a->strings['Leave empty for an auto generated password.'] = 'Jätä tyhjäksi jos haluat automaattisesti luotu salasanan.'; $a->strings['Confirm:'] = 'Vahvista:'; $a->strings['Choose a nickname: '] = 'Valitse lempinimi:'; -$a->strings['Register'] = 'Rekisteröidy'; +$a->strings['Import'] = 'Tuo'; $a->strings['Import your profile to this friendica instance'] = 'Tuo profiilisi tähän Friendica -instanssiin.'; -$a->strings['User deleted their account'] = 'Käyttäjä poisti tilinsä'; -$a->strings['On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'] = 'Friendica -solmullasi käyttäjä poisti tilinsä. Varmista että hänen tiedot poistetaan myös varmuuskopioista.'; -$a->strings['The user id is %d'] = 'Käyttäjätunnus on %d'; -$a->strings['Remove My Account'] = 'Poista tilini'; -$a->strings['This will completely remove your account. Once this has been done it is not recoverable.'] = 'Tämä poistaa käyttäjätilisi pysyvästi. Poistoa ei voi perua myöhemmin.'; -$a->strings['Please enter your password for verification:'] = 'Syötä salasanasi varmistusta varten:'; -$a->strings['Too Many Requests'] = 'Liian monta pyyntöä'; +$a->strings['Registration successful. Please check your email for further instructions.'] = 'Rekisteröityminen onnistui. Saat kohta lisäohjeita sähköpostitse.'; +$a->strings['Registration successful.'] = 'Rekisteröityminen onnistui.'; +$a->strings['Your registration can not be processed.'] = 'Rekisteröintisi ei voida käsitellä.'; +$a->strings['Your registration is pending approval by the site owner.'] = 'Rekisteröintisi odottaa ylläpitäjän hyväksyntää.'; $a->strings['Items tagged with: %s'] = 'Kohteet joilla tunnisteet: %s'; -$a->strings['Account'] = 'Tili'; -$a->strings['Display'] = 'Ulkonäkö'; -$a->strings['Social Networks'] = 'Sosiaalinen media'; -$a->strings['Connected apps'] = 'Yhdistetyt sovellukset'; -$a->strings['Remove account'] = 'Poista tili'; -$a->strings['Missing some important data!'] = 'Tärkeää dataa puuttuu!'; -$a->strings['Email settings updated.'] = 'Sähköpostin asetukset päivitettiin.'; -$a->strings['Features updated'] = 'Ominaisuudet päivitetty'; -$a->strings['Passwords do not match. Password unchanged.'] = 'Salasanat eivät täsmää. Salasana ennallaan.'; -$a->strings['Empty passwords are not allowed. Password unchanged.'] = 'Tyhjä salasanakenttä ei ole sallittu. Salasana ennallaan.'; -$a->strings['Wrong password.'] = 'Väärä salasana.'; -$a->strings['Password changed.'] = 'Salasana vaihdettu.'; -$a->strings['Password update failed. Please try again.'] = 'Salasanan vaihto epäonnistui. Yritä uudelleen.'; -$a->strings[' Please use a shorter name.'] = 'Käytä lyhyempää nimeä.'; -$a->strings[' Name too short.'] = 'Nimi on liian lyhyt.'; -$a->strings['Wrong Password'] = 'Väärä salasana'; -$a->strings['Invalid email.'] = 'Virheellinen sähköposti.'; -$a->strings['Settings updated.'] = 'Asetukset päivitetty.'; -$a->strings['Add application'] = 'Lisää sovellus'; -$a->strings['Consumer Key'] = 'Kuluttajan avain'; -$a->strings['Consumer Secret'] = 'Kuluttajasalaisuus'; -$a->strings['Redirect'] = 'Uudelleenohjaus'; -$a->strings['Icon url'] = 'Kuvakkeen URL-osoite'; -$a->strings['You can\'t edit this application.'] = 'Et voi muokata tätä sovellusta.'; -$a->strings['Connected Apps'] = 'Yhdistetyt sovellukset'; -$a->strings['Edit'] = 'Muokkaa'; -$a->strings['Client key starts with'] = 'Asiakasavain alkaa'; -$a->strings['No name'] = 'Ei nimeä'; -$a->strings['Remove authorization'] = 'Poista lupa'; -$a->strings['No Addon settings configured'] = 'Lisäosa-asetukset puuttuvat'; -$a->strings['Addon Settings'] = 'Lisäosa-asetukset'; -$a->strings['Additional Features'] = 'Lisäominaisuuksia'; -$a->strings['Diaspora'] = 'Diaspora'; -$a->strings['enabled'] = 'käytössä'; -$a->strings['disabled'] = 'pois käytöstä'; -$a->strings['Built-in support for %s connectivity is %s'] = 'Sisäänrakennettu tuki palvelulle %s on %s'; -$a->strings['GNU Social (OStatus)'] = 'GNU Social (OStatus)'; -$a->strings['General Social Media Settings'] = 'Yleiset some asetukset'; -$a->strings['Disable Content Warning'] = 'Poista sisältövaroitus käytöstä'; -$a->strings['Disable intelligent shortening'] = 'Poista alykäs lyhentäminen käytöstä'; -$a->strings['Automatically follow any GNU Social (OStatus) followers/mentioners'] = 'Automaattisesti seuraa GNU social (OStatus) seuraajat/mainitsijat'; -$a->strings['Default group for OStatus contacts'] = 'Oletusryhmä OStatus kontakteille'; -$a->strings['Your legacy GNU Social account'] = 'Vanha GNU social käyttäjätilisi'; -$a->strings['Repair OStatus subscriptions'] = 'Korjaa OStatus tilaukset'; -$a->strings['Email/Mailbox Setup'] = 'Sähköpostin asennus'; -$a->strings['Last successful email check:'] = 'Viimeisin onnistunut sähköpostitarkistus:'; -$a->strings['IMAP server name:'] = 'IMAP-palvelimen nimi:'; -$a->strings['IMAP port:'] = 'IMAP-porttti:'; -$a->strings['Security:'] = 'Turvallisuus:'; -$a->strings['None'] = 'Ei mitään'; -$a->strings['Email login name:'] = 'Sähköpostitilin käyttäjätunnus:'; -$a->strings['Email password:'] = 'Sähköpostin salasana:'; -$a->strings['Reply-to address:'] = 'Vastausosoite:'; -$a->strings['Send public posts to all email contacts:'] = 'Lähetä julkiset julkaisut kaikille kontakteille:'; -$a->strings['Action after import:'] = 'Toiminta tuonnin jälkeen:'; -$a->strings['Mark as seen'] = 'Merkitse luetuksi'; -$a->strings['Move to folder'] = 'Siirrä kansioon'; -$a->strings['Move to folder:'] = 'Siirrä kansioon:'; -$a->strings['%s - (Unsupported)'] = '%s - (Ei tueta)'; -$a->strings['%s - (Experimental)'] = '%s - (Kokeellinen)'; -$a->strings['Display Settings'] = 'Näyttöasetukset'; -$a->strings['Display Theme:'] = 'Käyttöliittymän teema:'; -$a->strings['Mobile Theme:'] = 'Mobiiliteema:'; -$a->strings['Update browser every xx seconds'] = 'Päivitä selain xx sekunnin välein'; -$a->strings['Minimum of 10 seconds. Enter -1 to disable it.'] = 'Vähintään 10 sekuntia. -1 poistaa ominaisuuden käytöstä.'; -$a->strings['Maximum of 100 items'] = 'Enintään 100 kohdetta'; -$a->strings['Don\'t show emoticons'] = 'Piilota hymiöt'; -$a->strings['Calendar'] = 'Kalenteri'; -$a->strings['Beginning of week:'] = 'Viikon alku:'; -$a->strings['Infinite scroll'] = 'Loputon selaaminen'; -$a->strings['General Theme Settings'] = 'Yleiset teeman asetukset'; -$a->strings['Custom Theme Settings'] = 'Mukautetut teema-asetukset'; -$a->strings['Content Settings'] = 'Sisältöasetukset'; -$a->strings['Theme settings'] = 'Teeman asetukset'; -$a->strings['Unable to find your profile. Please contact your admin.'] = 'Profiilisi ei löytynyt. Ota yhteyttä ylläpitäjään.'; -$a->strings['Account Types'] = 'Tilityypit'; -$a->strings['Personal Page Subtypes'] = 'Henkilökohtaisen sivun alatyypit'; -$a->strings['Community Forum Subtypes'] = 'Yhteisöfoorumin alatyypit'; -$a->strings['Account for a personal profile.'] = 'Henkilökohtaisen profiilin käyttäjätili.'; -$a->strings['Automatically approves all contact requests.'] = 'Automaattisesti hyväksyy kaikki kontaktipyynnöt'; -$a->strings['Private Forum [Experimental]'] = 'Yksityisfoorumi [kokeellinen]'; -$a->strings['OpenID:'] = 'OpenID:'; -$a->strings['Publish your default profile in your local site directory?'] = 'Julkaise oletusprofiilisi tämän sivuston paikallisluettelossa?'; -$a->strings['Publish your default profile in the global social directory?'] = 'Julkaise oletusprofiilisi maailmanlaajuisessa sosiaaliluettelossa?'; -$a->strings['Allow friends to post to your profile page?'] = 'Anna kavereiden julkaista profiilisivullasi?'; -$a->strings['Allow friends to tag your posts?'] = 'Anna kavereiden lisätä tunnisteita julkaisuusi?'; -$a->strings['Your contacts can add additional tags to your posts.'] = 'Kontaktisi voi lisätä ylimääräisiä tunnisteita julkaisuusi.'; -$a->strings['Permit unknown people to send you private mail?'] = 'Salli yksityisviesit tuntemattomilta?'; -$a->strings['Profile is not published.'] = 'Profiili ei ole julkaistu.'; -$a->strings['Your Identity Address is \'%s\' or \'%s\'.'] = 'Identiteettisi osoite on \'%s\' tai \'%s\'.'; -$a->strings['If empty, posts will not expire. Expired posts will be deleted'] = 'Jos kenttä jää tyhjäksi, julkaisut eivät vanhene. Vanhentuneet julkaisut poistetaan.'; -$a->strings['Expire posts:'] = 'Julkaisujen vanheneminen:'; -$a->strings['Expire starred posts:'] = 'Tähtimerkityt julkaisut vanhenee:'; -$a->strings['Expire photos:'] = 'Kuvat vanhenee:'; -$a->strings['Account Settings'] = 'Tiliasetukset'; -$a->strings['Password Settings'] = 'Salasana-asetukset'; -$a->strings['Leave password fields blank unless changing'] = 'Jätä salasana kenttää tyhjäksi jos et halua vaihtaa salasanaa'; +$a->strings['Create a New Account'] = 'Luo uusi käyttäjätili'; +$a->strings['Or login using OpenID: '] = 'Kirjaudu sisään OpenID -tunnuksella:'; +$a->strings['Password: '] = 'Salasana:'; +$a->strings['Remember me'] = 'Muista minut'; +$a->strings['Forgot your password?'] = 'Unohditko salasanasi?'; +$a->strings['Website Terms of Service'] = 'Verkkosivun käyttöehdot'; +$a->strings['terms of service'] = 'käyttöehdot'; +$a->strings['Website Privacy Policy'] = 'Sivuston tietosuojakäytäntö'; +$a->strings['privacy policy'] = 'tietosuojakäytäntö'; +$a->strings['Logged out.'] = 'Kirjautunut ulos.'; $a->strings['Current Password:'] = 'Nykyinen salasana:'; $a->strings['Your current password to confirm the changes'] = 'Syötä nykyinen salasanasi vahvistaaksesi muutokset'; +$a->strings['Invalid email.'] = 'Virheellinen sähköposti.'; +$a->strings['Unable to find your profile. Please contact your admin.'] = 'Profiilisi ei löytynyt. Ota yhteyttä ylläpitäjään.'; +$a->strings['Personal Page Subtypes'] = 'Henkilökohtaisen sivun alatyypit'; +$a->strings['Account for a personal profile.'] = 'Henkilökohtaisen profiilin käyttäjätili.'; +$a->strings['Automatically approves all contact requests.'] = 'Automaattisesti hyväksyy kaikki kontaktipyynnöt'; +$a->strings['OpenID:'] = 'OpenID:'; +$a->strings['Account Settings'] = 'Tiliasetukset'; +$a->strings['Your Identity Address is \'%s\' or \'%s\'.'] = 'Identiteettisi osoite on \'%s\' tai \'%s\'.'; +$a->strings['Password Settings'] = 'Salasana-asetukset'; +$a->strings['Leave password fields blank unless changing'] = 'Jätä salasana kenttää tyhjäksi jos et halua vaihtaa salasanaa'; $a->strings['Password:'] = 'Salasana:'; $a->strings['Basic Settings'] = 'Perusasetukset'; -$a->strings['Full Name:'] = 'Koko nimi:'; $a->strings['Email Address:'] = 'Sähköpostiosoite:'; $a->strings['Your Timezone:'] = 'Aikavyöhyke:'; $a->strings['Your Language:'] = 'Kieli:'; @@ -1375,10 +1060,13 @@ $a->strings['Use Browser Location:'] = 'Käytä selaimen sijainti:'; $a->strings['Security and Privacy Settings'] = 'Turvallisuus ja tietosuoja-asetukset'; $a->strings['Maximum Friend Requests/Day:'] = 'Kaveripyyntöraja päivässä:'; $a->strings['(to prevent spam abuse)'] = '(roskapostin estämiseksi)'; -$a->strings['Default Post Permissions'] = 'Julkaisun oletuskäyttöoikeudet:'; -$a->strings['(click to open/close)'] = '(klikkaa auki/kiinni)'; -$a->strings['Default Permissions for New Posts'] = 'Uuden julkaisun oletuskäyttöoikeudet'; +$a->strings['Allow friends to post to your profile page?'] = 'Anna kavereiden julkaista profiilisivullasi?'; +$a->strings['Allow friends to tag your posts?'] = 'Anna kavereiden lisätä tunnisteita julkaisuusi?'; +$a->strings['Your contacts can add additional tags to your posts.'] = 'Kontaktisi voi lisätä ylimääräisiä tunnisteita julkaisuusi.'; +$a->strings['Permit unknown people to send you private mail?'] = 'Salli yksityisviesit tuntemattomilta?'; $a->strings['Maximum private messages per day from unknown people:'] = 'Enimmäismäärä yksityisviestejä päivässä tuntemattomilta henkilöiltä:'; +$a->strings['Default Post Permissions'] = 'Julkaisun oletuskäyttöoikeudet:'; +$a->strings['If empty, posts will not expire. Expired posts will be deleted'] = 'Jos kenttä jää tyhjäksi, julkaisut eivät vanhene. Vanhentuneet julkaisut poistetaan.'; $a->strings['Notification Settings'] = 'Huomautusasetukset'; $a->strings['Send a notification email when:'] = 'Lähetä sähköposti-ilmoitus kun:'; $a->strings['You receive an introduction'] = 'Vastaanotat kaverikutsun'; @@ -1388,7 +1076,6 @@ $a->strings['Someone writes a followup comment'] = 'Joku vastaa kommenttiin'; $a->strings['You receive a private message'] = 'Vastaanotat yksityisviestin'; $a->strings['You receive a friend suggestion'] = 'Vastaanotat kaveriehdotuksen'; $a->strings['You are tagged in a post'] = 'Sinut on merkitty julkaisuun'; -$a->strings['You are poked/prodded/etc. in a post'] = 'sinut on tökätty tms. julkaisussa'; $a->strings['Activate desktop notifications'] = 'Ota työpöytäilmoitukset käyttöön'; $a->strings['Show desktop popup on new notifications'] = 'Näytä uudet ilmoitukset ponnahdusikkunassa'; $a->strings['Text-only notification emails'] = 'Ilmoitussähköposteissa vain tekstiä'; @@ -1396,492 +1083,160 @@ $a->strings['Send text only notification emails, without the html part'] = 'Läh $a->strings['Show detailled notifications'] = 'Näytä yksityiskohtaiset ilmoitukset'; $a->strings['Advanced Account/Page Type Settings'] = 'Käyttäjätili/sivutyyppi lisäasetuksia'; $a->strings['Relocate'] = 'Uudelleensijoitus'; -$a->strings['[Embedded content - reload page to view]'] = '[Upotettu sisältö - näet sen päivittämällä sivun]'; -$a->strings['Do you really want to delete this video?'] = 'Haluatko varmasti poistaa tämän videon?'; -$a->strings['Delete Video'] = 'Poista video'; -$a->strings['No videos selected'] = 'Ei videoita valittuna'; -$a->strings['Recent Videos'] = 'Viimeisimmät videot'; -$a->strings['Upload New Videos'] = 'Lataa uusia videoita'; -$a->strings['default'] = 'oletus'; -$a->strings['greenzero'] = 'greenzero'; -$a->strings['purplezero'] = 'purplezero'; -$a->strings['easterbunny'] = 'easterbunny'; -$a->strings['darkzero'] = 'darkzero'; -$a->strings['comix'] = 'comix'; -$a->strings['slackr'] = 'slackr'; -$a->strings['Variations'] = 'Muunnelmat'; -$a->strings['Top Banner'] = 'Yläpalkki'; -$a->strings['Full screen'] = 'Koko näyttö'; -$a->strings['Mosaic'] = 'Mosaiikki'; -$a->strings['Note'] = 'Muistiinpano'; -$a->strings['Select color scheme'] = 'Valitse värimalli'; -$a->strings['Navigation bar background color'] = 'Navigointipalkin taustaväri'; -$a->strings['Navigation bar icon color '] = 'Navigointipalkin kuvakkeiden väri'; -$a->strings['Link color'] = 'Linkin väri'; -$a->strings['Set the background color'] = 'Valitse taustaväri'; -$a->strings['Content background opacity'] = 'Sisällön taustasameus'; -$a->strings['Set the background image'] = 'Valitse taustakuva'; -$a->strings['Background image style'] = 'Taustakuvan tyyli'; -$a->strings['Login page background image'] = 'Sisäänkirjautumissivun taustakuva'; -$a->strings['Login page background color'] = 'Sisäänkirjautumissivun taustaväri'; -$a->strings['Leave background image and color empty for theme defaults'] = 'Jätä taustakuva ja väri tyhjäksi käyttääksesi teeman oletuksia'; -$a->strings['Guest'] = 'Vieras'; -$a->strings['Visitor'] = 'Vierailija'; -$a->strings['Logout'] = 'Kirjaudu ulos'; -$a->strings['End this session'] = 'Lopeta istunto'; -$a->strings['Your posts and conversations'] = 'Omat julkaisut ja keskustelut'; -$a->strings['Your profile page'] = 'Oma profiilisivu'; -$a->strings['Your photos'] = 'Omat kuvat'; -$a->strings['Videos'] = 'Videot'; -$a->strings['Your videos'] = 'Omat videot'; -$a->strings['Your events'] = 'Omat tapahtumat'; -$a->strings['Conversations from your friends'] = 'Kavereiden keskustelut'; -$a->strings['Events and Calendar'] = 'Tapahtumat ja kalenteri'; -$a->strings['Private mail'] = 'Yksityinen posti'; -$a->strings['Account settings'] = 'Tiliasetukset'; -$a->strings['Manage/edit friends and contacts'] = 'Hallitse/muokkaa kaverit ja kontaktit'; -$a->strings['Alignment'] = 'Kohdistaminen'; -$a->strings['Left'] = 'Vasemmalle'; -$a->strings['Center'] = 'Keskelle'; -$a->strings['Color scheme'] = 'Värimalli'; -$a->strings['Posts font size'] = 'Julkaisujen fonttikoko'; -$a->strings['Textareas font size'] = 'Tekstikenttien fonttikoko'; -$a->strings['don\'t show'] = 'älä näytä'; -$a->strings['show'] = 'näytä'; -$a->strings['Set style'] = 'Aseta tyyli'; -$a->strings['Community Pages'] = 'Yhteisösivut'; -$a->strings['Community Profiles'] = 'Yhteisöprofiilit'; -$a->strings['Connect Services'] = 'Yhdistä palvelut'; -$a->strings['Find Friends'] = 'Etsi kavereita'; -$a->strings['Last users'] = 'Viimeisimmät käyttäjät'; -$a->strings['Find People'] = 'Löydä ihmisiä'; -$a->strings['Enter name or interest'] = 'Syötä nimi tai harrastus'; -$a->strings['Examples: Robert Morgenstein, Fishing'] = 'Esim. Matti Meikäläinen, kalastus yms.'; -$a->strings['Similar Interests'] = 'Yhteiset harrastukset'; -$a->strings['Random Profile'] = 'Satunnainen profiili'; -$a->strings['Invite Friends'] = 'Kutsu kavereita'; -$a->strings['Local Directory'] = 'Paikallinen hakemisto'; -$a->strings['External link to forum'] = 'Ulkoinen linkki foorumiin'; -$a->strings['Quick Start'] = 'Pika-aloitus'; +$a->strings['Addon Settings'] = 'Lisäosa-asetukset'; +$a->strings['No Addon settings configured'] = 'Lisäosa-asetukset puuttuvat'; +$a->strings['Diaspora (Socialhome, Hubzilla)'] = 'Diaspora (Socialhome, Hubzilla)'; +$a->strings['None'] = 'Ei mitään'; +$a->strings['General Social Media Settings'] = 'Yleiset some asetukset'; +$a->strings['Repair OStatus subscriptions'] = 'Korjaa OStatus tilaukset'; +$a->strings['Email/Mailbox Setup'] = 'Sähköpostin asennus'; +$a->strings['Last successful email check:'] = 'Viimeisin onnistunut sähköpostitarkistus:'; +$a->strings['IMAP server name:'] = 'IMAP-palvelimen nimi:'; +$a->strings['IMAP port:'] = 'IMAP-porttti:'; +$a->strings['Security:'] = 'Turvallisuus:'; +$a->strings['Email login name:'] = 'Sähköpostitilin käyttäjätunnus:'; +$a->strings['Email password:'] = 'Sähköpostin salasana:'; +$a->strings['Reply-to address:'] = 'Vastausosoite:'; +$a->strings['Send public posts to all email contacts:'] = 'Lähetä julkiset julkaisut kaikille kontakteille:'; +$a->strings['Action after import:'] = 'Toiminta tuonnin jälkeen:'; +$a->strings['Move to folder'] = 'Siirrä kansioon'; +$a->strings['Move to folder:'] = 'Siirrä kansioon:'; +$a->strings['Delegates'] = 'Valtuutetut'; +$a->strings['Existing Page Delegates'] = 'Sivun valtuutetut'; +$a->strings['Potential Delegates'] = 'Mahdolliset valtuutetut'; +$a->strings['Add'] = 'Lisää'; +$a->strings['No entries.'] = 'Ei kohteita.'; +$a->strings['%s - (Unsupported)'] = '%s - (Ei tueta)'; +$a->strings['Display Settings'] = 'Näyttöasetukset'; +$a->strings['General Theme Settings'] = 'Yleiset teeman asetukset'; +$a->strings['Custom Theme Settings'] = 'Mukautetut teema-asetukset'; +$a->strings['Content Settings'] = 'Sisältöasetukset'; +$a->strings['Theme settings'] = 'Teeman asetukset'; +$a->strings['Display Theme:'] = 'Käyttöliittymän teema:'; +$a->strings['Mobile Theme:'] = 'Mobiiliteema:'; +$a->strings['Maximum of 100 items'] = 'Enintään 100 kohdetta'; +$a->strings['Update browser every xx seconds'] = 'Päivitä selain xx sekunnin välein'; +$a->strings['Minimum of 10 seconds. Enter -1 to disable it.'] = 'Vähintään 10 sekuntia. -1 poistaa ominaisuuden käytöstä.'; +$a->strings['Infinite scroll'] = 'Loputon selaaminen'; +$a->strings['Beginning of week:'] = 'Viikon alku:'; +$a->strings['Additional Features'] = 'Lisäominaisuuksia'; +$a->strings['Connected Apps'] = 'Yhdistetyt sovellukset'; +$a->strings['Remove authorization'] = 'Poista lupa'; +$a->strings['Profile Name is required.'] = 'Profiilinimi on pakollinen.'; +$a->strings['(click to open/close)'] = '(klikkaa auki/kiinni)'; +$a->strings['Edit Profile Details'] = 'Muokkaa profiilin yksityiskohdat'; +$a->strings['Change Profile Photo'] = 'Vaihda profiilikuva'; +$a->strings['Profile picture'] = 'Profiilikuva'; +$a->strings['Location'] = 'Sijainti'; +$a->strings['Miscellaneous'] = 'Sekalaista'; +$a->strings['Upload Profile Photo'] = 'Lataa profiilikuva'; +$a->strings['Street Address:'] = 'Katuosoite:'; +$a->strings['Locality/City:'] = 'Kaupunki:'; +$a->strings['Region/State:'] = 'Alue/osavaltio:'; +$a->strings['Postal/Zip Code:'] = 'Postinumero:'; +$a->strings['Country:'] = 'Maa:'; +$a->strings['XMPP (Jabber) address:'] = 'XMPP (Jabber) osoite:'; +$a->strings['Homepage URL:'] = 'Kotisivun URL-osoite:'; +$a->strings['Public Keywords:'] = 'Julkiset avainsanat:'; +$a->strings['(Used for suggesting potential friends, can be seen by others)'] = '(Käytetään kaveriehdotuksia varten, näkyy muille)'; +$a->strings['Private Keywords:'] = 'Yksityiset avainsanat:'; +$a->strings['(Used for searching profiles, never shown to others)'] = '(Käytetään profiilihakua varten, ei näy muille)'; +$a->strings['Image size reduction [%s] failed.'] = 'Kuvan pienentäminen [%s] epäonnistui.'; +$a->strings['Shift-reload the page or clear browser cache if the new photo does not display immediately.'] = 'Jos kuva ei näy heti, lataa sivu uudelleen tai tyhjennä selaimen välimuisti.'; +$a->strings['Unable to process image'] = 'Kuvan käsitteleminen epäonnistui'; +$a->strings['Crop Image'] = 'Rajaa kuva'; +$a->strings['Please adjust the image cropping for optimum viewing.'] = 'Rajaa kuva sopivasti.'; +$a->strings['or'] = 'tai'; +$a->strings['skip this step'] = 'ohita tämä vaihe'; +$a->strings['select a photo from your photo albums'] = 'valitse kuva albumeistasi'; +$a->strings['[Friendica System Notify]'] = '[Friendica Järjestelmäilmoitus]'; +$a->strings['User deleted their account'] = 'Käyttäjä poisti tilinsä'; +$a->strings['On your Friendica node an user deleted their account. Please ensure that their data is removed from the backups.'] = 'Friendica -solmullasi käyttäjä poisti tilinsä. Varmista että hänen tiedot poistetaan myös varmuuskopioista.'; +$a->strings['The user id is %d'] = 'Käyttäjätunnus on %d'; +$a->strings['Remove My Account'] = 'Poista tilini'; +$a->strings['This will completely remove your account. Once this has been done it is not recoverable.'] = 'Tämä poistaa käyttäjätilisi pysyvästi. Poistoa ei voi perua myöhemmin.'; +$a->strings['Please enter your password for verification:'] = 'Syötä salasanasi varmistusta varten:'; +$a->strings['Export account'] = 'Vie tili'; +$a->strings['Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.'] = 'Vie tilin tiedot ja yhteystiedot. Käytä tätä tilisi varmuuskopiointiin ja/tai siirtämiseen toiselle palvelimelle.'; +$a->strings['Export all'] = 'Vie kaikki'; +$a->strings['Privacy Statement'] = 'Tietosuojalausunto'; +$a->strings['Move account'] = 'Siirrä tili'; +$a->strings['You can import an account from another Friendica server.'] = 'Voit tuoda käyttäjätilin toiselta Friendica -palvelimelta.'; +$a->strings['This feature is experimental. We can\'t import contacts from the OStatus network (GNU Social/Statusnet) or from Diaspora'] = 'Tämä on kokeellinen ominaisuus. Emme voi tuoda kontakteja OStatus-verkolta (GNU social/Statusnet) tai Diasporalta.'; +$a->strings['Account file'] = 'Tilitiedosto'; $a->strings['Error decoding account file'] = 'Tilitiedoston tulkinnassa tapahtui virhe'; $a->strings['Error! No version data in file! This is not a Friendica account file?'] = 'Virhe: tiedostosta puuttuu versiotiedot! Saattaa olla että tämä ei ole Friendica -tilitiedosto?'; $a->strings['User \'%s\' already exists on this server!'] = 'Käyttäjä \'%s\' on jo olemassa tällä palvelimella!'; $a->strings['User creation error'] = 'Virhe käyttäjän luomisessa'; -$a->strings['User profile creation error'] = 'Virhe käyttäjäprofiilin luomisessa'; $a->strings['%d contact not imported'] = [ 0 => '%d kontakti ei tuotu', 1 => '%d kontakteja ei tuotu', ]; +$a->strings['User profile creation error'] = 'Virhe käyttäjäprofiilin luomisessa'; $a->strings['Done. You can now login with your username and password'] = 'Suoritettu. Voit nyt kirjautua sisään käyttäjätunnuksellasi.'; -$a->strings['Post to Email'] = 'Viesti sähköpostiin'; -$a->strings['Hide your profile details from unknown viewers?'] = 'Piilota profiilitietosi tuntemattomilta?'; -$a->strings['Visible to everybody'] = 'Näkyvissä kaikille'; -$a->strings['Close'] = 'Sulje'; -$a->strings['Enter new password: '] = 'Syötä uusi salasana:'; -$a->strings['Password can\'t be empty'] = 'Salasanakenttä ei voi olla tyhjä'; -$a->strings['System'] = 'Järjestelmä'; -$a->strings['Home'] = 'Koti'; -$a->strings['Introductions'] = 'Esittelyt'; -$a->strings['%s commented on %s\'s post'] = '%s kommentoi julkaisuun jonka kirjoitti %s'; -$a->strings['%s created a new post'] = '%s loi uuden julkaisun'; +$a->strings['Welcome to Friendica'] = 'Tervetuloa Friendicaan'; +$a->strings['New Member Checklist'] = 'Uuden jäsenen tarkistuslista'; +$a->strings['Getting Started'] = 'Ensiaskeleet'; +$a->strings['Friendica Walk-Through'] = 'Friendica -läpikäynti'; +$a->strings['Go to Your Settings'] = 'Omat Asetukset'; +$a->strings['Edit Your Profile'] = 'Muokkaa profiilisi'; +$a->strings['Profile Keywords'] = 'Profiilin avainsanat'; +$a->strings['Connecting'] = 'Yhdistetään'; +$a->strings['Importing Emails'] = 'Sähköpostin tuominen'; +$a->strings['Go to Your Contacts Page'] = 'Näytä minun kontaktit'; +$a->strings['Go to Your Site\'s Directory'] = 'Näytä oman sivuston luettelo'; +$a->strings['Finding New People'] = 'Kavereiden hankkiminen'; +$a->strings['Why Aren\'t My Posts Public?'] = 'Miksi julkaisuni eivät ole julkisia?'; +$a->strings['Getting Help'] = 'Avun saaminen'; +$a->strings['Go to the Help Section'] = 'Näytä ohjeet'; $a->strings['%s liked %s\'s post'] = '%s tykkäsi julkaisusta jonka kirjoitti %s'; $a->strings['%s disliked %s\'s post'] = '%s ei tykännyt julkaisusta jonka kirjoitti %s'; $a->strings['%s is attending %s\'s event'] = '%s osallistuu tapahtumaan jonka järjestää %s'; $a->strings['%s is not attending %s\'s event'] = '%s ei osallistu tapahtumaan jonka järjestää %s'; -$a->strings['%s may attend %s\'s event'] = '%s ehkä osallistuu tapahtumaan jonka järjestää %s'; $a->strings['%s is now friends with %s'] = '%s ja %s ovat kavereita'; +$a->strings['%s commented on %s\'s post'] = '%s kommentoi julkaisuun jonka kirjoitti %s'; +$a->strings['%s created a new post'] = '%s loi uuden julkaisun'; $a->strings['Friend Suggestion'] = 'Kaveriehdotus'; $a->strings['Friend/Connect Request'] = 'Ystävä/yhteyspyyntö'; $a->strings['New Follower'] = 'Uusi seuraaja'; -$a->strings['Could not find a command line version of PHP in the web server PATH.'] = 'Komentoriviversiota PHP:stä ei löytynyt web-palvelimen PATH:ista.'; -$a->strings['PHP executable path'] = 'Polku PHP-ohjelmaan'; -$a->strings['Enter full path to php executable. You can leave this blank to continue the installation.'] = 'Kirjoita koko polku PHP-ohjelmaan. Voit jättää sen tyhjäksi, jos haluat jatkaa asennusta.'; -$a->strings['Command line PHP'] = 'Komentorivi-PHP'; -$a->strings['Found PHP version: '] = 'PHP-versio löydetty:'; -$a->strings['PHP cli binary'] = 'PHP cli -binääritiedosto'; -$a->strings['The command line version of PHP on your system does not have "register_argc_argv" enabled.'] = 'Järjestelmäsi komentorivi-PHP:ssä ei ole käytössä asetusta "register_argc_argv".'; -$a->strings['This is required for message delivery to work.'] = 'Asetus vaaditaan viestien lähettämiseen.'; -$a->strings['PHP register_argc_argv'] = 'PHP register_argc_argv'; -$a->strings['Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'] = 'Virhe: järjestelmäsi "openssl_pkey_new" -funktio ei pysty generoimaan salausavaimia.'; -$a->strings['If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'] = 'Jos on kyse Windows-pavelimesta, katso "http://www.php.net/manual/en/openssl.installation.php".'; -$a->strings['Generate encryption keys'] = 'Luo salausavaimet'; -$a->strings['libCurl PHP module'] = 'PHP-moduuli libCurl'; -$a->strings['GD graphics PHP module'] = 'PHP-moduuli GD graphics'; -$a->strings['OpenSSL PHP module'] = 'PHP-moduuli OpenSSL'; -$a->strings['PDO or MySQLi PHP module'] = 'PDO tai MySQLi PHP-moduuli'; -$a->strings['mb_string PHP module'] = 'PHP-moduuli mb_string'; -$a->strings['XML PHP module'] = 'XML PHP-moduuli'; -$a->strings['iconv PHP module'] = 'iconv PHP-moduuli'; -$a->strings['POSIX PHP module'] = 'POSIX PHP-moduuli'; -$a->strings['Apache mod_rewrite module'] = 'Apache mod_rewrite -moduuli'; -$a->strings['Error: Apache webserver mod-rewrite module is required but not installed.'] = 'Virhe: Apache-palvelimen mod-rewrite -moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: libCURL PHP module required but not installed.'] = 'Virhe: libCURL PHP -moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: GD graphics PHP module with JPEG support required but not installed.'] = 'Virhe: GD graphics PHP -moduuli JPEG-tuella vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: openssl PHP module required but not installed.'] = 'Virhe: openssl PHP -moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: PDO or MySQLi PHP module required but not installed.'] = 'Virhe: PDO tai MySQLi PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: The MySQL driver for PDO is not installed.'] = 'Virhe: PDO:n MySQL-ajuri ei ole asennettu'; -$a->strings['Error: mb_string PHP module required but not installed.'] = 'Virhe: PHP-moduuli mb_string vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: iconv PHP module required but not installed.'] = 'Virhe: iconv PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['Error: POSIX PHP module required but not installed.'] = 'Virhe: POSIX PHP-moduuli vaadittaan, mutta sitä ei ole asennettu.'; -$a->strings['Error, XML PHP module required but not installed.'] = 'Virhe: XML PHP-moduuli vaaditaan, mutta sitä ei ole asennettu.'; -$a->strings['The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.'] = 'Web-asennuksen pitäisi pystyä luomaan tiedosto nimeltä ".htconfig.php" palvelimesi ylimpään kansioon, mutta se ei nyt onnistu.'; -$a->strings['This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.'] = 'Tämä on yleensä käyttöoikeusasetus, jolloin web-palvelimesi ei pysty kirjoittamaan tiedostoja kansioosi, vaikka itse siihen pystyisit.'; -$a->strings['At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Friendica top folder.'] = 'Tämän menettelyn lopussa annamme sinulle tekstin tallennettavaksi tiedostoon nimeltä .htconfig.php Friendican ylätason kansiossa.'; -$a->strings['.htconfig.php is writable'] = '.htconfig.php on kirjoitettava'; -$a->strings['view/smarty3 is writable'] = 'view/smarty3 on kirjoitettava'; -$a->strings['Url rewrite in .htaccess is not working. Check your server configuration.'] = 'URL-osoitteen uudelleenkirjoitus .htaccess-tiedostossa ei toimi. Tarkista palvelimen asetukset.'; -$a->strings['Url rewrite is working'] = 'URL-osoitteen uudellenkirjoitus toimii'; -$a->strings['ImageMagick PHP extension is not installed'] = 'ImageMagick PHP-laajennus ei ole asetettu'; -$a->strings['ImageMagick PHP extension is installed'] = 'ImageMagick PHP-laajennus on asetettu'; -$a->strings['ImageMagick supports GIF'] = 'ImageMagik tukee GIF-formaattia'; -$a->strings['Birthday:'] = 'Syntymäpäivä:'; -$a->strings['YYYY-MM-DD or MM-DD'] = 'VVVV-KK-PP tai KK-PP'; -$a->strings['never'] = 'ei ikinä'; -$a->strings['less than a second ago'] = 'alle sekunti sitten'; -$a->strings['year'] = 'vuosi'; -$a->strings['years'] = 'vuotta'; -$a->strings['months'] = 'kuukautta'; -$a->strings['weeks'] = 'viikkoa'; -$a->strings['days'] = 'päivää'; -$a->strings['hour'] = 'tunti'; -$a->strings['hours'] = 'tuntia'; -$a->strings['minute'] = 'minuutti'; -$a->strings['minutes'] = 'inuuttia'; -$a->strings['second'] = 'sekunti'; -$a->strings['seconds'] = 'sekuntia'; -$a->strings['%1$d %2$s ago'] = '%1$d %2$s sitten'; -$a->strings['view full size'] = 'näytä täysikokoisena'; -$a->strings['Image/photo'] = 'Kuva/valokuva'; -$a->strings['%2$s %3$s'] = '%2$s %3$s'; -$a->strings['$1 wrote:'] = '$1 kirjoitti:'; -$a->strings['Encrypted content'] = 'Salattu sisältö'; -$a->strings['Invalid source protocol'] = 'Virheellinen lähdeprotokolla'; -$a->strings['Invalid link protocol'] = 'Virheellinen linkkiprotokolla'; -$a->strings['Embedding disabled'] = 'Upottaminen poistettu käytöstä'; -$a->strings['Embedded content'] = 'Upotettu sisältö'; -$a->strings['Export'] = 'Vie'; -$a->strings['Export calendar as ical'] = 'Vie kalenteri ical -tiedostona'; -$a->strings['Export calendar as csv'] = 'Vie kalenteri csv-tiedostona'; -$a->strings['Frequently'] = 'Usein'; -$a->strings['Hourly'] = 'Tunneittain'; -$a->strings['Twice daily'] = 'Kahdesti päivässä'; -$a->strings['Daily'] = 'Päivittäin'; -$a->strings['Weekly'] = 'Viikottain'; -$a->strings['Monthly'] = 'Kuukausittain'; -$a->strings['OStatus'] = 'OStatus'; -$a->strings['RSS/Atom'] = 'RSS/Atom'; -$a->strings['Facebook'] = 'Facebook'; -$a->strings['Zot!'] = 'Zot!'; -$a->strings['LinkedIn'] = 'LinkedIn'; -$a->strings['XMPP/IM'] = 'XMPP/IM'; -$a->strings['MySpace'] = 'MySpace'; -$a->strings['Google+'] = 'Google+'; -$a->strings['pump.io'] = 'pump.io'; -$a->strings['Twitter'] = 'Twitter'; -$a->strings['Diaspora Connector'] = 'Diaspora -liitin'; -$a->strings['GNU Social Connector'] = 'GNU social -liitin'; -$a->strings['pnut'] = 'pnut'; -$a->strings['App.net'] = 'App.net'; -$a->strings['Male'] = 'Mies'; -$a->strings['Female'] = 'Nainen'; -$a->strings['Currently Male'] = 'Tällä hetkellä mies'; -$a->strings['Currently Female'] = 'Tällä hetkellä nainen'; -$a->strings['Mostly Male'] = 'Enimmäkseen mies'; -$a->strings['Mostly Female'] = 'Enimmäkseen nainen'; -$a->strings['Transgender'] = 'Transsukupuolinen'; -$a->strings['Intersex'] = 'Intersukupuolinen'; -$a->strings['Transsexual'] = 'Transsukupuolinen'; -$a->strings['Hermaphrodite'] = 'Hermafrodiitti'; -$a->strings['Neuter'] = 'Neutri'; -$a->strings['Non-specific'] = 'Ei-binäärinen'; -$a->strings['Other'] = 'Toinen'; -$a->strings['Males'] = 'Miehet'; -$a->strings['Females'] = 'Naiset'; -$a->strings['Gay'] = 'Homo'; -$a->strings['Lesbian'] = 'Lesbo'; -$a->strings['Bisexual'] = 'Biseksuaali'; -$a->strings['Autosexual'] = 'Autoseksuaalinen'; -$a->strings['Abstinent'] = 'Selibaatissa elävä'; -$a->strings['Virgin'] = 'Neitsyt'; -$a->strings['Fetish'] = 'Fetissi'; -$a->strings['Nonsexual'] = 'Aseksuaali'; -$a->strings['Single'] = 'Sinkku'; -$a->strings['Lonely'] = 'Yksinäinen'; -$a->strings['Available'] = 'Saatavilla'; -$a->strings['Unavailable'] = 'Ei saatavilla'; -$a->strings['Has crush'] = 'Ihastunut'; -$a->strings['Infatuated'] = 'Hullaantunut'; -$a->strings['Dating'] = 'Seurustelee'; -$a->strings['Unfaithful'] = 'Uskoton'; -$a->strings['Sex Addict'] = 'Sekririippuvainen'; -$a->strings['Friends'] = 'Kaverit'; -$a->strings['Friends/Benefits'] = 'Kaverit eduilla'; -$a->strings['Casual'] = 'Tavallinen'; -$a->strings['Engaged'] = 'Kihloissa'; -$a->strings['Married'] = 'Naimisissa'; -$a->strings['Partners'] = 'Kumppanit'; -$a->strings['Cohabiting'] = 'Avoliitossa'; -$a->strings['Common law'] = 'Avoliitossa'; -$a->strings['Happy'] = 'Iloinen'; -$a->strings['Not looking'] = 'Ei etsi'; -$a->strings['Swinger'] = 'Parinvaihtaja'; -$a->strings['Betrayed'] = 'Petetty'; -$a->strings['Separated'] = 'Asumuserossa'; -$a->strings['Unstable'] = 'Epävakaa'; -$a->strings['Divorced'] = 'Eronnut'; -$a->strings['Widowed'] = 'Leski'; -$a->strings['Uncertain'] = 'Epävarma'; -$a->strings['It\'s complicated'] = 'Se on monimutkaista'; -$a->strings['Don\'t care'] = 'Ei ole väliä'; -$a->strings['Ask me'] = 'Kysy minulta'; -$a->strings['Add New Contact'] = 'Lisää uusi kontakti'; -$a->strings['Enter address or web location'] = 'Syötä verkko-osoite'; -$a->strings['Example: bob@example.com, http://example.com/barbara'] = 'Esimerkki: bob@example.com, http://example.com/barbara'; -$a->strings['%d invitation available'] = [ - 0 => '%d kutsu saatavilla', - 1 => '%d kutsuja saatavilla', -]; -$a->strings['Networks'] = 'Verkot'; -$a->strings['All Networks'] = 'Kaikki verkot'; -$a->strings['Saved Folders'] = 'Tallennetut kansiot'; -$a->strings['Everything'] = 'Kaikki'; -$a->strings['Categories'] = 'Luokat'; -$a->strings['%d contact in common'] = [ - 0 => '%d yhteinen kontakti', - 1 => '%d yhteistä kontaktia', -]; -$a->strings['General Features'] = 'Yleiset ominaisuudet'; -$a->strings['Multiple Profiles'] = 'Monia profiileja'; -$a->strings['Ability to create multiple profiles'] = 'Mahdollisuus luoda useita profiileja'; -$a->strings['Photo Location'] = 'Kuvan sijainti'; -$a->strings['Photo metadata is normally stripped. This extracts the location (if present) prior to stripping metadata and links it to a map.'] = 'Kuvan metadata poistetaan normaalisti. Tämä ottaa paikkatiedon (jos olemassa) ennen poistoa ja linkittää sen karttaan.'; -$a->strings['Export Public Calendar'] = 'Vie julkinen kalenteri'; -$a->strings['Ability for visitors to download the public calendar'] = 'Vierailijoiden mahdollisuus ladata julkinen kalenteri'; -$a->strings['Post Composition Features'] = 'Kirjoittamisen ominaisuudet'; -$a->strings['Post Preview'] = 'Viestin esikatselu'; -$a->strings['Allow previewing posts and comments before publishing them'] = 'Mahdollistaa viestien esikatselun ennen niiden julkaisua'; -$a->strings['Network Sidebar'] = 'Uutisvirran sivupalkki'; -$a->strings['Ability to select posts by date ranges'] = 'Mahdollisuus valita viestejä päivämäärärajauksella'; -$a->strings['List Forums'] = 'Näytä foorumit'; -$a->strings['Group Filter'] = 'Ryhmäsuodatin'; -$a->strings['Network Filter'] = 'Uutisvirtasuodatin'; -$a->strings['Save search terms for re-use'] = 'Tallenna hakutermit myöhempää käyttöä varten'; -$a->strings['Network Tabs'] = 'Uutisvirta välilehdet'; -$a->strings['Network Personal Tab'] = 'Henkilökohtainen uutisvirtavälilehti'; -$a->strings['Network New Tab'] = 'Uusimmat uutisvirtajulkaisut'; -$a->strings['Post/Comment Tools'] = 'Julkaisu/kommentti työkalut'; -$a->strings['Select and delete multiple posts/comments at once'] = 'Valitse ja poista monta julkaisua/kommentia yhtaikaa'; -$a->strings['Edit Sent Posts'] = 'Muokkaa lähetetyt julkaisut'; -$a->strings['Edit and correct posts and comments after sending'] = 'Muokkaa ja korjaa julkaisuja ja kommenteja julkaisun jälkeen'; -$a->strings['Tagging'] = 'Tunnisteet'; -$a->strings['Ability to tag existing posts'] = 'Saa merkitä olemassa olevia julkaisuja'; -$a->strings['Post Categories'] = 'Julkaisuluokat'; -$a->strings['Add categories to your posts'] = 'Luokittele julkaisusi'; -$a->strings['Ability to file posts under folders'] = 'Mahdollisuus tallettaa viestejä kansioihin'; -$a->strings['Dislike Posts'] = 'Inhoa viestejä'; -$a->strings['Ability to dislike posts/comments'] = 'Mahdollisuus inhota viestejä/kommentteja'; -$a->strings['Star Posts'] = 'Tähtimerkityt julkaisut'; -$a->strings['Ability to mark special posts with a star indicator'] = 'Salli julkaisujen tähtimerkintä'; -$a->strings['Mute Post Notifications'] = 'Mykistä julkaisuilmoitukset'; -$a->strings['Advanced Profile Settings'] = 'Profiilin lisäasetukset'; -$a->strings['Tag Cloud'] = 'Tunnistepilvi'; -$a->strings['Provide a personal tag cloud on your profile page'] = 'Näytä henkilökohtainen tunnistepilvi profiilisivullasi'; -$a->strings['Display Membership Date'] = 'Näytä liittymispäivämäärä'; -$a->strings['Display membership date in profile'] = 'Näytä liittymispäivämäärä profiilissa'; -$a->strings['Nothing new here'] = 'Täällä ei ole mitään uutta'; -$a->strings['Clear notifications'] = 'Tyhjennä ilmoitukset'; -$a->strings['Personal notes'] = 'Henkilökohtaiset merkinnät'; -$a->strings['Your personal notes'] = 'Henkilökohtaiset merkintäsi'; -$a->strings['Sign in'] = 'Kirjaudu sisään'; -$a->strings['Home Page'] = 'Kotisivu'; -$a->strings['Create an account'] = 'Luo tili'; -$a->strings['Help and documentation'] = 'Ohjeet ja dokmentointi'; -$a->strings['Apps'] = 'Sovellukset'; -$a->strings['Addon applications, utilities, games'] = 'Lisäosa sovelluksia, apuohjelmia, pelejä'; -$a->strings['Search site content'] = 'Sivustohaku'; -$a->strings['Community'] = 'Yhteisö'; -$a->strings['Conversations on this and other servers'] = 'Keskustelut täällä ja muilla palvelimilla'; -$a->strings['Directory'] = 'Luettelo'; -$a->strings['People directory'] = 'Henkilöluettelo'; -$a->strings['Information about this friendica instance'] = 'Lisätietoja tästä Friendica -instanssista'; -$a->strings['Network Reset'] = 'Verkon nollaus'; -$a->strings['Load Network page with no filters'] = 'Lataa verkkosivu ilman suotimia'; -$a->strings['Friend Requests'] = 'Kaveripyynnöt'; -$a->strings['See all notifications'] = 'Näytä kaikki ilmoitukset'; -$a->strings['Mark all system notifications seen'] = 'Merkitse kaikki järjestelmäviestit nähdyiksi'; -$a->strings['Inbox'] = 'Saapuneet'; -$a->strings['Outbox'] = 'Lähtevät'; -$a->strings['Manage'] = 'Hallitse'; -$a->strings['Manage other pages'] = 'Hallitse muita sivuja'; -$a->strings['Profiles'] = 'Profiilit'; -$a->strings['Manage/Edit Profiles'] = 'Hallitse/muokka profiilit'; -$a->strings['Site setup and configuration'] = 'Sivuston asennus ja asetukset'; -$a->strings['Navigation'] = 'Navigointi'; -$a->strings['Site map'] = 'Sivustokartta'; -$a->strings['There are no tables on MyISAM.'] = 'MyISAMissa ei ole taulukoita.'; -$a->strings[' - The friendica developers released update %s recently, - but when I tried to install it, something went terribly wrong. - This needs to be fixed soon and I can\'t do it alone. Please contact a - friendica developer if you can not help me on your own. My database might be invalid.'] = ' - Friendican kehittäjät askettäin julkaisi %s-päivityksen, - mutta asennuksessa jotain meni pahasti pieleen. - Tämä on korjattava pian, ja en voi korjata sitä itse. Ota yhteyttä - Friendica -kehittäjään jos et voi auttaa. Tietokantani saattaa olla virheellinen.'; -$a->strings['The error message is -[pre]%s[/pre]'] = 'Virheviesti on -[pre]%s[/pre]'; -$a->strings[' -Error %d occurred during database update: -%s -'] = ' -%d virhe tapahtui tietokannan päivityksen aikana: -%s -'; -$a->strings['Errors encountered performing database changes: '] = 'Tietokannan muokkauksessa tapahtui virheitä:'; -$a->strings['%s: Database update'] = '%s: Tietokantapäivitys'; -$a->strings['%s: updating %s table.'] = '%s: päivitetään %s-taulukkoa.'; -$a->strings['[no subject]'] = '[ei aihetta]'; -$a->strings['Default privacy group for new contacts'] = 'Oletusryhmä uusille kontakteille'; -$a->strings['Everybody'] = 'Kaikki'; -$a->strings['edit'] = 'muokkaa'; -$a->strings['Edit group'] = 'Muokkaa ryhmää'; -$a->strings['Contacts not in any group'] = 'Kontaktit ilman ryhmää'; -$a->strings['Create a new group'] = 'Luo uusi ryhmä'; -$a->strings['Edit groups'] = 'Muokkaa ryhmiä'; -$a->strings['Drop Contact'] = 'Poista kontakti'; -$a->strings['Organisation'] = 'Järjestö'; -$a->strings['News'] = 'Uutiset'; -$a->strings['Forum'] = 'Keskustelupalsta'; -$a->strings['Connect URL missing.'] = 'Yhteys URL-linkki puuttuu.'; -$a->strings['The contact could not be added. Please check the relevant network credentials in your Settings -> Social Networks page.'] = 'Kontaktia ei pystytty lisäämään. Tarkista verkkoasetukset omista asetuksistasi (Settings -> Social Networks).'; -$a->strings['This site is not configured to allow communications with other networks.'] = 'Tämä sivusto ei salli yhteyksiä muiden verkkojen kanssa..'; -$a->strings['No compatible communication protocols or feeds were discovered.'] = 'Yhteensopivia viestintäprotokolleja tai syötteitä ei löytynyt.'; -$a->strings['The profile address specified does not provide adequate information.'] = 'Annettu profiiliosoite ei sisällä riittävästi tietoa.'; -$a->strings['An author or name was not found.'] = 'Julkaisija tai nimi puuttuu.'; -$a->strings['Use mailto: in front of address to force email check.'] = 'Käytä "mailto:" osoitteen edessä pakottaaksesi sähköpostin tarkastuksen.'; -$a->strings['The profile address specified belongs to a network which has been disabled on this site.'] = 'Profiilin osoite kuuluu verkkoon, joka on poistettu tältä sivustolta.'; -$a->strings['Limited profile. This person will be unable to receive direct/personal notifications from you.'] = 'Rajoitettu profiili. Tämä henkilö ei pysty/tule saamaan suoria/henkilökohtaisia ilmoituksia sinulta.'; -$a->strings['Unable to retrieve contact information.'] = 'Kontaktin tietoja ei voitu hakea.'; -$a->strings['%s\'s birthday'] = '%s: syntymäpäivä'; -$a->strings['Happy Birthday %s'] = 'Hyvää syntymäpäivää %s'; -$a->strings['Starts:'] = 'Alkaa:'; -$a->strings['Finishes:'] = 'Päättyy:'; -$a->strings['all-day'] = 'koko päivä'; -$a->strings['Jun'] = 'Kes.'; -$a->strings['Sept'] = 'Syy.'; -$a->strings['No events to display'] = 'Ei näytettäviä tapahtumia.'; -$a->strings['l, F j'] = 'l, F j'; -$a->strings['Edit event'] = 'Muokkaa tapahtumaa'; -$a->strings['Duplicate event'] = 'Monista tapahtuma'; -$a->strings['Delete event'] = 'Poista tapahtuma'; -$a->strings['D g:i A'] = 'D H:i'; -$a->strings['g:i A'] = 'H:i'; -$a->strings['Show map'] = 'Näytä kartta'; -$a->strings['Hide map'] = 'Piilota kartta'; -$a->strings['%1$s is attending %2$s\'s %3$s'] = '%1$s osallistuu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['%1$s is not attending %2$s\'s %3$s'] = '%1$s ei osallistu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['%1$s may attend %2$s\'s %3$s'] = '%1$s ehkä osallistuu tapahtumaan %3$s, jonka järjestää %2$s'; -$a->strings['Requested account is not available.'] = 'Pyydetty käyttäjätili ei ole saatavilla.'; -$a->strings['Edit profile'] = 'Muokkaa profiilia'; -$a->strings['Atom feed'] = 'Atom -syöte'; -$a->strings['Manage/edit profiles'] = 'Hallitse/muokkaa profiilit'; -$a->strings['g A l F d'] = 'g A l F d'; -$a->strings['F d'] = 'F d'; -$a->strings['[today]'] = '[tänään]'; -$a->strings['Birthday Reminders'] = 'Syntymäpäivämuistutukset'; -$a->strings['Birthdays this week:'] = 'Syntymäpäiviä tällä viikolla:'; -$a->strings['[No description]'] = '[Ei kuvausta]'; -$a->strings['Event Reminders'] = 'Tapahtumamuistutukset'; -$a->strings['Events this week:'] = 'Tapahtumia tällä viikolla:'; -$a->strings['Member since:'] = 'Liittymispäivämäärä:'; -$a->strings['j F, Y'] = 'j F, Y'; -$a->strings['j F'] = 'j F'; -$a->strings['Age:'] = 'Ikä:'; -$a->strings['for %1$d %2$s'] = '%1$d%2$s'; -$a->strings['Religion:'] = 'Uskonto:'; -$a->strings['Hobbies/Interests:'] = 'Harrastukset:'; -$a->strings['Contact information and Social Networks:'] = 'Yhteystiedot ja sosiaalinen media:'; -$a->strings['Musical interests:'] = 'Musiikki:'; -$a->strings['Books, literature:'] = 'Kirjat, kirjallisuus:'; -$a->strings['Television:'] = 'Televisio:'; -$a->strings['Film/dance/culture/entertainment:'] = 'Elokuvat/tanssit/kulttuuri/viihde:'; -$a->strings['Love/Romance:'] = 'Rakkaus/romanssi:'; -$a->strings['Work/employment:'] = 'Työ:'; -$a->strings['School/education:'] = 'Koulutus:'; -$a->strings['Forums:'] = 'Foorumit:'; -$a->strings['Only You Can See This'] = 'Vain sinä näet tämän'; -$a->strings['Login failed'] = 'Kirjautuminen epäonnistui'; -$a->strings['Not enough information to authenticate'] = 'Ei tarpeeksi tietoja kirjautumiseen'; -$a->strings['An invitation is required.'] = 'Vaaditaa kutsu.'; -$a->strings['Invitation could not be verified.'] = 'Kutsua ei voitu vahvistaa.'; -$a->strings['Invalid OpenID url'] = 'Virheellinen OpenID url-osoite'; -$a->strings['We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.'] = 'Kohtasimme ongelman antamasi OpenID:n kanssa. Ole hyvä ja tarkista ID:n oikea kirjoitusasu.'; -$a->strings['The error message was:'] = 'Virheviesti oli:'; -$a->strings['Please enter the required information.'] = 'Syötä tarvittavat tiedot.'; -$a->strings['Please use a shorter name.'] = 'Käytä lyhyempää nimeä.'; -$a->strings['Name too short.'] = 'Nimi on liian lyhyt.'; -$a->strings['That doesn\'t appear to be your full (First Last) name.'] = 'Tuo ei vakuta täydeltä nimeltäsi (Etunimi Sukunimi).'; -$a->strings['Your email domain is not among those allowed on this site.'] = 'Sähköpostiosoitteesi verkkotunnus on tämän sivuston estolistalla.'; -$a->strings['Not a valid email address.'] = 'Virheellinen sähköpostiosoite.'; -$a->strings['Cannot use that email.'] = 'Sähköpostiosoitetta ei voitu käyttää.'; -$a->strings['Your nickname can only contain a-z, 0-9 and _.'] = 'Nimimerkki voi sisältää a-z, 0-9 ja _.'; -$a->strings['Nickname is already registered. Please choose another.'] = 'Valitsemasi nimimerkki on jo käytössä. Valitse toinen nimimerkki.'; -$a->strings['SERIOUS ERROR: Generation of security keys failed.'] = 'VAKAVA VIRHE: Salausavainten luominen epäonnistui.'; -$a->strings['An error occurred during registration. Please try again.'] = 'Rekisteröityminen epäonnistui. Yritä uudelleen.'; -$a->strings['An error occurred creating your default profile. Please try again.'] = 'Oletusprofiilin luominen epäonnistui. Yritä uudelleen.'; -$a->strings['An error occurred creating your self contact. Please try again.'] = 'Yhteystietojesi luonti epäonnistui. Yritä uudelleen.'; -$a->strings['An error occurred creating your default contact group. Please try again.'] = 'Oletusryhmäsi luonti epäonnistui. Yritä uudelleen.'; -$a->strings[' - Dear %1$s, - Thank you for registering at %2$s. Your account is pending for approval by the administrator. - '] = ' - Hei %1$s, - Kiitoksia rekisteröitymisestä sivustolle %2$s. Tilisi on odottamassa ylläpidon hyväksyntää. - '; -$a->strings['Registration at %s'] = 'Rekisteröityminen kohteessa %s'; -$a->strings[' - Dear %1$s, - Thank you for registering at %2$s. Your account has been created. - '] = ' - Hei %1$s, - Kiitoksia rekisteröinnistä sivustolle %2$s. Tilisi on luotu. - '; -$a->strings['Sharing notification from Diaspora network'] = 'Ilmoitus Diaspora -verkosta tapahtuneesta jakamisesta.'; -$a->strings['Attachments:'] = 'Liitteitä:'; -$a->strings['%s is now following %s.'] = '%s seuraa %s.'; -$a->strings['following'] = 'seuraa'; -$a->strings['%s stopped following %s.'] = '%s ei enää seuraa %s.'; -$a->strings['stopped following'] = 'ei enää seuraa'; -$a->strings['(no subject)'] = '(ei aihetta)'; -$a->strings['Logged out.'] = 'Kirjautunut ulos.'; -$a->strings['Create a New Account'] = 'Luo uusi käyttäjätili'; -$a->strings['Password: '] = 'Salasana:'; -$a->strings['Remember me'] = 'Muista minut'; -$a->strings['Or login using OpenID: '] = 'Kirjaudu sisään OpenID -tunnuksella:'; -$a->strings['Forgot your password?'] = 'Unohditko salasanasi?'; -$a->strings['Website Terms of Service'] = 'Verkkosivun käyttöehdot'; -$a->strings['terms of service'] = 'käyttöehdot'; -$a->strings['Website Privacy Policy'] = 'Sivuston tietosuojakäytäntö'; -$a->strings['privacy policy'] = 'tietosuojakäytäntö'; -$a->strings['Privacy Statement'] = 'Tietosuojalausunto'; +$a->strings['%1$s sent you a new private message at %2$s.'] = '%1$s lähetti sinulle uuden yksityisviestin kohteessa %2$s.'; +$a->strings['a private message'] = 'yksityisviesti'; +$a->strings['%1$s sent you %2$s.'] = '%1$s lähetti sinulle %2$s.'; +$a->strings['Please visit %s to view and/or reply to your private messages.'] = 'Katso yksityisviestisi kohteessa %s.'; +$a->strings['%s commented on an item/conversation you have been following.'] = '%s kommentoi kohteessa/keskustelussa jota seuraat.'; +$a->strings['Please visit %s to view and/or reply to the conversation.'] = 'Käy %s nähdäksesi keskustelun ja/tai vastataksesi siihen'; +$a->strings['%1$s posted to your profile wall at %2$s'] = '%1$s kirjoitti seinällesi kohteessa %2$s'; +$a->strings['%1$s posted to [url=%2$s]your wall[/url]'] = '%1$s kirjoitti [url=%2$s]seinällesi[/url]'; +$a->strings['You\'ve received an introduction from \'%1$s\' at %2$s'] = 'Olet vastaanottanut kaverikutsun henkilöltä \'%1$s\' kohteessa %2$s'; +$a->strings['You\'ve received [url=%1$s]an introduction[/url] from %2$s.'] = 'Olet vastaanottanut [url=%1$s]kaverikutsun[/url] henkilöltä %2$s.'; +$a->strings['You may visit their profile at %s'] = 'Voit vierailla hänen profiilissaan kohteessa %s'; +$a->strings['Please visit %s to approve or reject the introduction.'] = 'Hyväksy tai hylkää esittely %s-sivustossa'; +$a->strings['%1$s is sharing with you at %2$s'] = '%1$s jakaa päivityksensä kanssasi kohteessa %2$s'; +$a->strings['You have a new follower at %2$s : %1$s'] = 'Sinulla on uusi seuraaja sivustolla %2$s : %1$s'; +$a->strings['You\'ve received a friend suggestion from \'%1$s\' at %2$s'] = 'Sait kaverikutsun henkilöltä \'%1$s\' (%2$s)'; +$a->strings['You\'ve received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s.'] = 'Sait [url=%1$s] kaveriehdotuksen[/url] %2$s käyttäjältä %3$s.'; +$a->strings['Name:'] = 'Nimi:'; +$a->strings['Photo:'] = 'Kuva:'; +$a->strings['Please visit %s to approve or reject the suggestion.'] = 'Hyväksy tai hylkää ehdotus %s-sivustossa'; +$a->strings['\'%1$s\' has accepted your connection request at %2$s'] = '\'%1$s\' on hyväksynyt kaverikutsusi kohteessa %2$s'; +$a->strings['%2$s has accepted your [url=%1$s]connection request[/url].'] = '%2$s hyväksyi [url=%1$s]kaverikutsusi[/url].'; +$a->strings['You are now mutual friends and may exchange status updates, photos, and email without restriction.'] = 'Olette nyt yhteiset ystävät ja voitte lähettää toisillenne tilapäivityksiä, kuvia ja sähköposteja ilman rajoituksia.'; +$a->strings['Please visit %s if you wish to make any changes to this relationship.'] = 'Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta.'; +$a->strings['\'%1$s\' has chosen to accept you a fan, which restricts some forms of communication - such as private messaging and some profile interactions. If this is a celebrity or community page, these settings were applied automatically.'] = '\'%1$s\' on hyväksynyt sinut faniksi. Tämä rajoittaa joitain kommunikointitapoja - kuten yksityisviestiettely ja joitain profiilitoimintoja. Jos tämä on julkisuuden henkilö tai yhteisösivu, asetukset on valittu automaattisesti.'; +$a->strings['\'%1$s\' may choose to extend this into a two-way or more permissive relationship in the future.'] = '\'%1$s\' voi halutessaan laajentaa suhteenne kahdenväliseksi.'; +$a->strings['Please visit %s if you wish to make any changes to this relationship.'] = 'Käy osoitteessa %s muokkaamaan tätä kaverisuhdetta.'; +$a->strings['registration request'] = 'rekisteröintipyyntö'; +$a->strings['You\'ve received a registration request from \'%1$s\' at %2$s'] = 'Olet vastaanottanut rekisteröintipyynnön henkilöltä \'%1$s\' kohteessa %2$s'; +$a->strings['You\'ve received a [url=%1$s]registration request[/url] from %2$s.'] = 'Olet vastaanottanut [url=%1$s]rekisteröintipyynnön[/url] henkilöltä %2$s.'; +$a->strings['Please visit %s to approve or reject the request.'] = 'Hyväksy tai hylkää pyyntö %s-sivustossa.'; +$a->strings['This message was sent to you by %s, a member of the Friendica social network.'] = 'Viestin lähetti %s Friendica sosiaaliverkoston kautta.'; +$a->strings['%s posted an update.'] = '%s julkaisi päivityksen.'; +$a->strings['Private Message'] = 'Yksityisviesti'; $a->strings['This entry was edited'] = 'Tämä kohde oli muokattu'; -$a->strings['save to folder'] = 'tallenna kansioon'; +$a->strings['Edit'] = 'Muokkaa'; $a->strings['I will attend'] = 'Osallistun'; $a->strings['I will not attend'] = 'En aio osallistua'; $a->strings['I might attend'] = 'Ehkä osallistun'; -$a->strings['add star'] = 'lisää tähti'; -$a->strings['remove star'] = 'poista tähti'; -$a->strings['toggle star status'] = 'Tähtitila päälle/pois'; -$a->strings['starred'] = 'tähtimerkitty'; -$a->strings['ignore thread'] = 'Sivuuta keskustelu'; -$a->strings['unignore thread'] = 'Seuraa keskustelua'; -$a->strings['toggle ignore status'] = 'Sivuuta/seuraa'; -$a->strings['add tag'] = 'lisää tägi'; -$a->strings['like'] = 'tykkää'; -$a->strings['dislike'] = 'en tykkää'; -$a->strings['Share this'] = 'Jaa tämä'; -$a->strings['share'] = 'jaa'; $a->strings['to'] = 'henkilölle'; $a->strings['via'] = 'kautta'; $a->strings['Wall-to-Wall'] = 'Seinäjulkaisu'; @@ -1890,15 +1245,10 @@ $a->strings['%d comment'] = [ 0 => '%d kommentti', 1 => '%d kommentteja', ]; -$a->strings['Bold'] = 'Lihavoitu'; -$a->strings['Italic'] = 'Kursivoitu'; -$a->strings['Underline'] = 'Alleviivaus'; -$a->strings['Quote'] = 'Lainaus'; -$a->strings['Code'] = 'Koodi'; -$a->strings['Image'] = 'Kuva'; -$a->strings['Link'] = 'Linkki'; -$a->strings['Video'] = 'Video'; -$a->strings['Delete this item?'] = 'Poista tämä kohde?'; -$a->strings['show fewer'] = 'näytä vähemmän'; -$a->strings['toggle mobile'] = 'Mobiilisivusto päälle/pois'; -$a->strings['Update %s failed. See error logs.'] = '%s päivitys epäonnistui, katso virhelokit.'; +$a->strings['%s is now following %s.'] = '%s seuraa %s.'; +$a->strings['following'] = 'seuraa'; +$a->strings['%s stopped following %s.'] = '%s ei enää seuraa %s.'; +$a->strings['stopped following'] = 'ei enää seuraa'; +$a->strings['Login failed.'] = 'Kirjautuminen epäonnistui'; +$a->strings['Please upload a profile photo.'] = 'Lataa profiilikuva.'; +$a->strings['minutes'] = 'minuuttia'; diff --git a/view/templates/acl/full_selector.tpl b/view/templates/acl/full_selector.tpl index a2329614e..fe8c856f1 100644 --- a/view/templates/acl/full_selector.tpl +++ b/view/templates/acl/full_selector.tpl @@ -41,9 +41,9 @@ {{$custom_title}}
- + - +

{{$custom_desc}}

@@ -75,10 +75,10 @@ $(function() { let $acl_allow_input = $('#acl_allow-{{$input_group_id}}'); let $contact_allow_input = $('[name="{{$input_names.contact_allow}}"]'); - let $group_allow_input = $('[name="{{$input_names.group_allow}}"]'); + let $circle_allow_input = $('[name="{{$input_names.circle_allow}}"]'); let $acl_deny_input = $('#acl_deny-{{$input_group_id}}'); let $contact_deny_input = $('[name="{{$input_names.contact_deny}}"]'); - let $group_deny_input = $('[name="{{$input_names.group_deny}}"]'); + let $circle_deny_input = $('[name="{{$input_names.circle_deny}}"]'); let $visibility_public_panel = $('#visibility-public-panel-{{$input_group_id}}'); let $visibility_custom_panel = $('#visibility-custom-panel-{{$input_group_id}}'); let $visibility_public_radio = $('#visibility-public-{{$input_group_id}}'); @@ -125,8 +125,8 @@ }); // Custom visibility tags inputs - let acl_groups = new Bloodhound({ - local: {{$acl_groups nofilter}}, + let acl_circles = new Bloodhound({ + local: {{$acl_circles nofilter}}, identify: function(obj) { return obj.type + '-' + obj.id.toString(); }, datumTokenizer: Bloodhound.tokenizers.obj.whitespace(['name']), queryTokenizer: Bloodhound.tokenizers.whitespace, @@ -163,7 +163,7 @@ freeInput: false, tagClass: function(item) { switch (item.type) { - case 'group' : return 'label label-primary'; + case 'circle' : return 'label label-primary'; case 'contact' : default: return 'label label-info'; @@ -191,7 +191,7 @@ freeInput: false, tagClass: function(item) { switch (item.type) { - case 'group' : return 'label label-primary'; + case 'circle' : return 'label label-primary'; case 'contact' : default: return 'label label-info'; @@ -215,14 +215,14 @@ // Import existing ACL into the tags input fields. - $group_allow_input.val().split(',').forEach(function (group_id) { - $acl_allow_input.tagsinput('add', acl_groups.get('group-' + group_id)[0]); + $circle_allow_input.val().split(',').forEach(function (circle_id) { + $acl_allow_input.tagsinput('add', acl_circles.get('circle-' + circle_id)[0]); }); $contact_allow_input.val().split(',').forEach(function (contact_id) { $acl_allow_input.tagsinput('add', acl_contacts.get('contact-' + contact_id)[0]); }); - $group_deny_input.val().split(',').forEach(function (group_id) { - $acl_deny_input.tagsinput('add', acl_groups.get('group-' + group_id)[0]); + $circle_deny_input.val().split(',').forEach(function (circle_id) { + $acl_deny_input.tagsinput('add', acl_circles.get('circle-' + circle_id)[0]); }); $contact_deny_input.val().split(',').forEach(function (contact_id) { $acl_deny_input.tagsinput('add', acl_contacts.get('contact-' + contact_id)[0]); @@ -237,11 +237,11 @@ } // Update the real acl field - $group_allow_input.val(''); + $circle_allow_input.val(''); $contact_allow_input.val(''); [].forEach.call($acl_allow_input.tagsinput('items'), function (item) { - if (item.type === 'group') { - $group_allow_input.val($group_allow_input.val() + ',' + item.id); + if (item.type === 'circle') { + $circle_allow_input.val($circle_allow_input.val() + ',' + item.id); } else { $contact_allow_input.val($contact_allow_input.val() + ',' + item.id); } @@ -255,11 +255,11 @@ } // Update the real acl field - $group_deny_input.val(''); + $circle_deny_input.val(''); $contact_deny_input.val(''); [].forEach.call($acl_deny_input.tagsinput('items'), function (item) { - if (item.type === 'group') { - $group_deny_input.val($group_deny_input.val() + ',' + item.id); + if (item.type === 'circle') { + $circle_deny_input.val($circle_deny_input.val() + ',' + item.id); } else { $contact_deny_input.val($contact_deny_input.val() + ',' + item.id); } diff --git a/view/templates/acl/self_only.tpl b/view/templates/acl/self_only.tpl index d1c5a00de..03ad6a7c3 100644 --- a/view/templates/acl/self_only.tpl +++ b/view/templates/acl/self_only.tpl @@ -1,5 +1,5 @@ - + - - \ No newline at end of file + + diff --git a/view/templates/admin/federation.tpl b/view/templates/admin/federation.tpl index dbee2ec3e..8f8d70cd2 100644 --- a/view/templates/admin/federation.tpl +++ b/view/templates/admin/federation.tpl @@ -57,7 +57,7 @@ {{if $c[0]['total'] > 0}} {{$c[0]['platform']}} - {{$c[0]['total']}} + {{$c[0]['total']}} {{$c[0]['network']}} diff --git a/view/templates/admin/site.tpl b/view/templates/admin/site.tpl index 3cf072994..17c318907 100644 --- a/view/templates/admin/site.tpl +++ b/view/templates/admin/site.tpl @@ -108,7 +108,7 @@

{{$performance}}

- {{include file="field_checkbox.tpl" field=$compute_group_counts}} + {{include file="field_checkbox.tpl" field=$compute_circle_counts}} {{include file="field_checkbox.tpl" field=$only_tag_search}} {{include file="field_input.tpl" field=$max_comments}} {{include file="field_input.tpl" field=$max_display_comments}} diff --git a/view/templates/calendar/calendar_head.tpl b/view/templates/calendar/calendar_head.tpl index b5bf8f6fe..9266cecf7 100644 --- a/view/templates/calendar/calendar_head.tpl +++ b/view/templates/calendar/calendar_head.tpl @@ -153,9 +153,9 @@ } }).trigger('change'); - $('#contact_allow, #contact_deny, #group_allow, #group_deny').change(function() { + $('#contact_allow, #contact_deny, #circle_allow, #circle_deny').change(function() { let selstr; - $('#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected').each( function() { + $('#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected').each( function() { selstr = $(this).html(); $('#jot-public').hide(); }); diff --git a/view/templates/circle_drop.tpl b/view/templates/circle_drop.tpl new file mode 100644 index 000000000..e37d1e0e0 --- /dev/null +++ b/view/templates/circle_drop.tpl @@ -0,0 +1,12 @@ + +
+ + +
+
diff --git a/view/templates/circle_edit.tpl b/view/templates/circle_edit.tpl new file mode 100644 index 000000000..aa7ef8b76 --- /dev/null +++ b/view/templates/circle_edit.tpl @@ -0,0 +1,26 @@ + +

{{$title}}

+ + +{{if $editable == 1}} +
+
+ + + {{include file="field_input.tpl" field=$gname}} + {{if $drop}}{{$drop nofilter}}{{/if}} +
+ +
+
+
+
+{{/if}} + + +{{if $circle_editor}} +
+ {{include file="circle_editor.tpl"}} +
+{{/if}} +{{if $desc}}
{{$desc nofilter}}
{{/if}} diff --git a/view/templates/circle_editor.tpl b/view/templates/circle_editor.tpl new file mode 100644 index 000000000..4f3a30eea --- /dev/null +++ b/view/templates/circle_editor.tpl @@ -0,0 +1,62 @@ + +{{* Template for the contact circle list *}} + +{{if $editable == 1}} +{{* The contacts who are already members of the contact circle *}} +
+

{{$circle_editor.label_members}}

+
+ + {{if $circle_editor.members }} + + {{foreach $circle_editor.members as $c}} + {{* If there are too many contacts we use another view mode *}} + {{if $shortmode}} + + {{else}} + {{* The normal view mode *}} +
+ + {{$c.name}} + +
+ {{/if}} + {{/foreach}} + + {{else}} + {{$circle_editor.circle_is_empty}} + {{/if}} +
+ +
+
+
+{{/if}} + +{{* The contacts who are not members of the contact circle *}} +
+

{{$circle_editor.label_contacts}}

+ +
+
diff --git a/view/templates/circle_selection.tpl b/view/templates/circle_selection.tpl new file mode 100644 index 000000000..db3e7b88a --- /dev/null +++ b/view/templates/circle_selection.tpl @@ -0,0 +1,9 @@ + +
+ + +
diff --git a/view/templates/circle_side.tpl b/view/templates/circle_side.tpl new file mode 100644 index 000000000..c33638130 --- /dev/null +++ b/view/templates/circle_side.tpl @@ -0,0 +1,48 @@ + +

{{$title}}

+
+
+ +

{{$title}}

+
+ + + + {{if $new_circle}} + + {{else}} + + {{/if}} + + {{if $uncircled}}{{/if}} +
+ diff --git a/view/templates/field_combobox.tpl b/view/templates/field_combobox.tpl index 3e6e06052..b62bf2dba 100644 --- a/view/templates/field_combobox.tpl +++ b/view/templates/field_combobox.tpl @@ -1,4 +1,3 @@ -
{{* html5 don't work on Chrome, Safari and IE9 @@ -6,13 +5,13 @@ {{foreach $field.4 as $opt=>$val}} *}} - - + + - + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/templates/field_openid.tpl b/view/templates/field_openid.tpl index 3c7d02bb8..033a1f8e5 100644 --- a/view/templates/field_openid.tpl +++ b/view/templates/field_openid.tpl @@ -1,7 +1,6 @@ -
- + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/templates/field_password.tpl b/view/templates/field_password.tpl index 07241fb11..57149fe52 100644 --- a/view/templates/field_password.tpl +++ b/view/templates/field_password.tpl @@ -1,7 +1,6 @@ -
- + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/templates/field_textarea.tpl b/view/templates/field_textarea.tpl index edd48d1d0..f5221b569 100644 --- a/view/templates/field_textarea.tpl +++ b/view/templates/field_textarea.tpl @@ -1,7 +1,7 @@
- + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/templates/group_drop.tpl b/view/templates/group_drop.tpl deleted file mode 100644 index e28411d03..000000000 --- a/view/templates/group_drop.tpl +++ /dev/null @@ -1,12 +0,0 @@ - -
- - -
-
diff --git a/view/templates/group_edit.tpl b/view/templates/group_edit.tpl deleted file mode 100644 index 1984dc197..000000000 --- a/view/templates/group_edit.tpl +++ /dev/null @@ -1,26 +0,0 @@ - -

{{$title}}

- - -{{if $editable == 1}} -
-
- - - {{include file="field_input.tpl" field=$gname}} - {{if $drop}}{{$drop nofilter}}{{/if}} -
- -
-
-
-
-{{/if}} - - -{{if $groupeditor}} -
- {{include file="groupeditor.tpl"}} -
-{{/if}} -{{if $desc}}
{{$desc nofilter}}
{{/if}} diff --git a/view/templates/group_selection.tpl b/view/templates/group_selection.tpl deleted file mode 100644 index 7d01df7a7..000000000 --- a/view/templates/group_selection.tpl +++ /dev/null @@ -1,9 +0,0 @@ - -
- - -
diff --git a/view/templates/group_side.tpl b/view/templates/group_side.tpl deleted file mode 100644 index 2aca4cdf4..000000000 --- a/view/templates/group_side.tpl +++ /dev/null @@ -1,48 +0,0 @@ - -

{{$title}}

-
-
- -

{{$title}}

-
- - - - {{if $newgroup}} - - {{else}} - - {{/if}} - - {{if $ungrouped}}{{/if}} -
- diff --git a/view/templates/groupeditor.tpl b/view/templates/groupeditor.tpl deleted file mode 100644 index 0168a7a2d..000000000 --- a/view/templates/groupeditor.tpl +++ /dev/null @@ -1,62 +0,0 @@ - -{{* Template for the contact group list *}} - -{{if $editable == 1}} -{{* The contacts who are already members of the contact group *}} -
-

{{$groupeditor.label_members}}

-
- - {{if $groupeditor.members }} - - {{foreach $groupeditor.members as $c}} - {{* If there are too many contacts we use another view mode *}} - {{if $shortmode}} - - {{else}} - {{* The normal view mode *}} -
- - {{$c.name}} - -
- {{/if}} - {{/foreach}} - - {{else}} - {{$groupeditor.group_is_empty}} - {{/if}} -
- -
-
-
-{{/if}} - -{{* The contacts who are not members of the contact group *}} -
-

{{$groupeditor.label_contacts}}

- -
-
diff --git a/view/templates/item/compose.tpl b/view/templates/item/compose.tpl index c491a0fcf..fa311bc66 100644 --- a/view/templates/item/compose.tpl +++ b/view/templates/item/compose.tpl @@ -47,6 +47,9 @@ +

@@ -90,14 +93,14 @@ {{if $scheduled_at}}{{$scheduled_at nofilter}}{{/if}} {{if $created_at}}{{$created_at nofilter}}{{/if}} {{else}} - + - + {{/if}}
\ No newline at end of file + dzFactory.setupDropzone('#dropzone-{{$id}}', 'comment-edit-text-{{$id}}'); + diff --git a/view/templates/moderation/report/create/aside.tpl b/view/templates/moderation/report/create/aside.tpl new file mode 100644 index 000000000..f590433f8 --- /dev/null +++ b/view/templates/moderation/report/create/aside.tpl @@ -0,0 +1,25 @@ +
+

{{$l10n.contact_title}}

+{{if $contact}} + {{include file="contact/entry.tpl"}} +{{/if}} +

{{$l10n.category_title}}

+{{if $category}} +

{{$category}}

+{{/if}} +{{if $rules}} +

{{$l10n.rules_title}}

+
    +{{foreach $rules as $rule_id => $rule_text}} +
  1. {{$rule_text}}
  2. +{{/foreach}} +
+{{/if}} +{{if $comment}} +

{{$l10n.comment_title}}

+

{{$comment nofilter}}

+{{/if}} +{{if $posts}} +

{{$l10n.posts_title}} ({{$posts}})

+{{/if}} +
\ No newline at end of file diff --git a/view/templates/moderation/report/create/pick_category.tpl b/view/templates/moderation/report/create/pick_category.tpl new file mode 100644 index 000000000..66d4a275b --- /dev/null +++ b/view/templates/moderation/report/create/pick_category.tpl @@ -0,0 +1,16 @@ +
+

{{$l10n.title}} - {{$l10n.page}}

+

{{$l10n.description}}

+ +
+ {{include file="field_radio.tpl" field=$category_spam}} + {{include file="field_radio.tpl" field=$category_illegal}} + {{include file="field_radio.tpl" field=$category_safety}} + {{include file="field_radio.tpl" field=$category_unwanted}} + {{include file="field_radio.tpl" field=$category_violation}} + {{include file="field_radio.tpl" field=$category_other}} + + {{include file="field_textarea.tpl" field=$comment}} +

+
+
diff --git a/view/templates/moderation/report/create/pick_contact.tpl b/view/templates/moderation/report/create/pick_contact.tpl new file mode 100644 index 000000000..38c41e7f1 --- /dev/null +++ b/view/templates/moderation/report/create/pick_contact.tpl @@ -0,0 +1,9 @@ +
+

{{$l10n.title}} - {{$l10n.page}}

+

{{$l10n.description}}

+ +
+ {{include file="field_input.tpl" field=$url}} +

+
+
diff --git a/view/templates/moderation/report/create/pick_posts.tpl b/view/templates/moderation/report/create/pick_posts.tpl new file mode 100644 index 000000000..4dca61a8d --- /dev/null +++ b/view/templates/moderation/report/create/pick_posts.tpl @@ -0,0 +1,24 @@ +
+

{{$l10n.title}} - {{$l10n.page}}

+

{{$l10n.description}}

+ +
+ +{{foreach $threads as $thread}} + + + + +{{/foreach}} +
+
+ {{foreach $thread.items as $item}} + {{include file="{{$item.template}}"}} + {{/foreach}} +
+
+ +
+

+
+
diff --git a/view/templates/moderation/report/create/pick_rules.tpl b/view/templates/moderation/report/create/pick_rules.tpl new file mode 100644 index 000000000..e9996c386 --- /dev/null +++ b/view/templates/moderation/report/create/pick_rules.tpl @@ -0,0 +1,16 @@ +
+

{{$l10n.title}} - {{$l10n.page}}

+

{{$l10n.description}}

+ +
+ {{foreach $rules as $rule}} +
+ + +
+ {{/foreach}} +

+
+
diff --git a/view/templates/moderation/report/create/summary.tpl b/view/templates/moderation/report/create/summary.tpl new file mode 100644 index 000000000..3de520681 --- /dev/null +++ b/view/templates/moderation/report/create/summary.tpl @@ -0,0 +1,28 @@ +
+

{{$l10n.title}} - {{$l10n.page}}

+

{{$l10n.description}}

+ +
+ {{$summary nofilter}} +
+ +

{{$l10n.contact_action_title}}

+

{{$l10n.contact_action_desc}}

+
+ + + + + + {{include file="field_radio.tpl" field=$nothing}} + {{include file="field_radio.tpl" field=$collapse}} + {{include file="field_radio.tpl" field=$ignore}} + {{include file="field_radio.tpl" field=$block}} + +{{if $display_forward}} + {{include file="field_checkbox.tpl" field=$forward}} +{{/if}} + +

+
+
diff --git a/view/templates/photos_head.tpl b/view/templates/photos_head.tpl index 1d693e103..b633ee76d 100644 --- a/view/templates/photos_head.tpl +++ b/view/templates/photos_head.tpl @@ -7,14 +7,14 @@ $(document).ready(function() { - $('#contact_allow, #contact_deny, #group_allow, #group_deny').change(function() { + $('#contact_allow, #contact_deny, #circle_allow, #circle_deny').change(function() { var selstr; - $('#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected').each( function() { + $('#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected').each( function() { selstr = $(this).html(); $('#jot-perms-icon').removeClass('unlock').addClass('lock'); $('#jot-public').hide(); }); - if(selstr == null) { + if(selstr == null) { $('#jot-perms-icon').removeClass('lock').addClass('unlock'); $('#jot-public').show(); } diff --git a/view/templates/search_item.tpl b/view/templates/search_item.tpl index fc322be95..4320ec6cf 100644 --- a/view/templates/search_item.tpl +++ b/view/templates/search_item.tpl @@ -7,8 +7,8 @@
-
{{$item.name}} @@ -19,17 +19,17 @@
-
+
{{if $item.lock}}
{{$item.lock}}
- {{else}}
{{/if}} + {{else}}
{{/if}}
{{$item.location_html nofilter}}
{{$item.name}} -
{{$item.pinned}}
-
+
{{$item.pinned}}
+
{{$item.title}}
@@ -46,7 +46,7 @@
- {{if $item.drop && $item.drop.dropping}}{{/if}} + {{if $item.drop && $item.drop.dropping}}{{/if}}
{{if $item.drop && $item.drop.pagedrop}}{{/if}}
diff --git a/view/templates/settings/account.tpl b/view/templates/settings/account.tpl index 8e9f80dc3..6480c0de1 100644 --- a/view/templates/settings/account.tpl +++ b/view/templates/settings/account.tpl @@ -59,7 +59,8 @@ {{include file="field_checkbox.tpl" field=$unkmail}} {{include file="field_input.tpl" field=$cntunkmail}} - {{$group_select nofilter}} + {{$circle_select nofilter}} + {{$circle_select_group nofilter}} {{if not $is_community}}

{{$permissions}}

@@ -194,4 +195,4 @@
-
\ No newline at end of file +
diff --git a/view/templates/settings/head.tpl b/view/templates/settings/head.tpl index 6d58e54a6..ff85f2cb9 100644 --- a/view/templates/settings/head.tpl +++ b/view/templates/settings/head.tpl @@ -6,20 +6,20 @@ $(document).ready(function() { - $('#contact_allow, #contact_deny, #group_allow, #group_deny').change(function() { + $('#contact_allow, #contact_deny, #circle_allow, #circle_deny').change(function() { var selstr; - $('#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected').each( function() { + $('#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected').each( function() { selstr = $(this).html(); $('#jot-perms-icon').removeClass('unlock').addClass('lock'); $('#jot-public').hide(); }); - if(selstr == null) { + if(selstr == null) { $('#jot-perms-icon').removeClass('lock').addClass('unlock'); $('#jot-public').show(); } }).trigger('change'); - + $('.settings-content-block').hide(); $('.settings-heading').click(function(){ $('.settings-content-block').hide(); diff --git a/view/templates/settings/profile/index.tpl b/view/templates/settings/profile/index.tpl index 69812c5a8..64c9daee0 100644 --- a/view/templates/settings/profile/index.tpl +++ b/view/templates/settings/profile/index.tpl @@ -1,121 +1,131 @@ -

{{$banner}}

+ -{{$default nofilter}} +

{{$l10n.banner}}

-
-
+ + + + +
+

{{$l10n.picture_section}} »

+ +
+
+ +
-
- - -
-
-
- - -
-
-
- {{$dob nofilter}} -
-
- {{$hide_friends nofilter}} -
- -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- - -
-
-
- -
-
-
- - -
-
{{$homepage.3}}
-
-
- - -
-
{{$xmpp.3}}
-
-
- - -
-
{{$matrix.3}}
-
-
- - -
-
{{$pub_keywords.3}}
-
-
- - -
-
{{$prv_keywords.3}}
-
-
- -
-
+ +
+

{{$l10n.personal_section}} »

+ + +
+

{{$l10n.location_section}} »

+ +
+ +
+

{{$l10n.custom_fields_section}} »

+
-
+ + +

{{$title}}

+
+
+ + +
+
+ diff --git a/view/templates/widget/posted_date.tpl b/view/templates/widget/posted_date.tpl index ad40bcb02..3c2380c60 100644 --- a/view/templates/widget/posted_date.tpl +++ b/view/templates/widget/posted_date.tpl @@ -31,10 +31,16 @@ function showHideDates() { diff --git a/view/templates/widget_forumlist.tpl b/view/templates/widget_forumlist.tpl deleted file mode 100644 index 7d250a01a..000000000 --- a/view/templates/widget_forumlist.tpl +++ /dev/null @@ -1,53 +0,0 @@ - - - -

{{$title}}

-
-
- -

{{$title}}

-
- -
-
- diff --git a/view/theme/duepuntozero/deriv/darkzero.css b/view/theme/duepuntozero/deriv/darkzero.css index 2e236e5df..50b78aecb 100644 --- a/view/theme/duepuntozero/deriv/darkzero.css +++ b/view/theme/duepuntozero/deriv/darkzero.css @@ -23,13 +23,13 @@ nav #banner #logo-text a { color: #ffffff; } /* Contact-Header for the Network Stream */ #viewcontact_wrapper-network {background-image: url('imgdarkzero/head.jpg');} -.wall-item-content-wrapper { - border: 1px solid #444444; - background: #444444; +.wall-item-content-wrapper { + border: 1px solid #444444; + background: #444444; } .wall-item-outside-wrapper.threaded > .wall-item-content-wrapper { -moz-border-radius: 3px 3px 0px; - border-radius: 3px 3px 0px; + border-radius: 3px 3px 0px; } .wall-item-tools { background-color: #444444; background-image: none;} .comment-wwedit-wrapper{ @@ -39,7 +39,7 @@ nav #banner #logo-text a { color: #ffffff; } border: solid #444444; border-width: 0px 3px 3px; -moz-border-radius: 0px 0px 3px 3px; - border-radius: 0px 0px 3px 3px; + border-radius: 0px 0px 3px 3px; } .editicon { background-color: #333; @@ -91,7 +91,7 @@ footer { background-image: url('imgdarkzero/sectionend.jpg'); background-position: top left; background-repeat: repeat-x; - height: 25px; + height: 25px; } @@ -117,13 +117,13 @@ input#dfrn-url { #jot-title:-moz-placeholder{color: #555555!important;} #jot-category::-webkit-input-placeholder{ color: #555555!important;} #jot-category:-moz-placeholder{color: #555555!important;} - - + + #jot-title:hover, #jot-title:focus, #jot-category:hover, #jot-category:focus { - border: 1px solid #cccccc; + border: 1px solid #cccccc; } #profile-jot-email-label, div#jot-preview-content, div.profile-jot-net { @@ -149,7 +149,7 @@ input#dfrn-url { background:#2e2f2e; } -.widget .selected, .group-selected { +.widget .selected, .circle-selected { background:#2e2f2e; } diff --git a/view/theme/duepuntozero/deriv/slackr.css b/view/theme/duepuntozero/deriv/slackr.css index c096ffa7d..179b6259c 100644 --- a/view/theme/duepuntozero/deriv/slackr.css +++ b/view/theme/duepuntozero/deriv/slackr.css @@ -90,7 +90,7 @@ nav #site-location { box-shadow: 4px 4px 3px 0 #444444; } -.forumlist-img { +.group-list-img { border-radius: 3px; -moz-border-radius: 3px; box-shadow: 4px 4px 3px 0 #444444; @@ -126,7 +126,7 @@ nav #site-location { } -.contact-entry-photo img, .profile-match-photo img, #photo-photo img, .directory-photo-img, .photo-album-photo, .photo-top-photo, .profile-jot-text, .group-selected, .widget .selected, #profile-jot-submit { +.contact-entry-photo img, .profile-match-photo img, #photo-photo img, .directory-photo-img, .photo-album-photo, .photo-top-photo, .profile-jot-text, .circle-selected, .widget .selected, #profile-jot-submit { border-radius: 3px; -moz-border-radius: 3px; box-shadow: 4px 4px 3px 0 #444444; diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index f5b526c48..802aaf16f 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -382,11 +382,11 @@ div.wall-item-content-wrapper.shiny { cursor: pointer; } -#group-sidebar { +#circle-sidebar { margin-bottom: 10px; } -.widget .selected, .group-selected, .forum-selected { +.widget .selected, .circle-selected, .group-selected { padding: 3px; -moz-border-radius: 3px; border-radius: 3px; @@ -1695,46 +1695,46 @@ input#dfrn-url { overflow: auto; } -#group-new-submit-wrapper { +#circle-new-submit-wrapper { margin-top: 30px; } -#group-edit-name-label { +#circle-edit-name-label { float: left; width: 175px; margin-top: 20px; margin-bottom: 20px; } -#group-edit-name { +#circle-edit-name { float: left; width: 225px; margin-top: 20px; margin-bottom: 20px; } -#group-edit-name-wrapper { +#circle-edit-name-wrapper { } -#group_members_select_label { +#circle_members_select_label { display: block; float: left; width: 175px; } -.group_members_select { +.circle_members_select { float: left; width: 230px; overflow: auto; } -#group_members_select_end { +#circle_members_select_end { clear: both; } -#group-edit-name-end { +#circle-edit-name-end { clear: both; } @@ -1856,10 +1856,10 @@ a.mail-list-link { clear: both; } -#sidebar-group-list ul { +#sidebar-circle-list ul { list-style-type: none; } -.sidebar-group-li .notify, .forum-widget-entry .notify { +.sidebar-circle-li .notify, .group-widget-entry .notify { display: none; font-size: 9px; border: 1px solid rgb(221, 221, 221); @@ -1867,21 +1867,21 @@ a.mail-list-link { float: right; background-color: #BABDB6; } -.sidebar-group-li .notify.show, .forum-widget-entry .notify.show { +.sidebar-circle-li .notify.show, .group-widget-entry .notify.show { display: block; } -#sidebar-group-list .icon, #sidebar-group-list .iconspacer { +#sidebar-circle-list .icon, #sidebar-circle-list .iconspacer { display: inline-block; height: 12px; width: 12px; } -#sidebar-group-list li { +#sidebar-circle-list li { margin-top: 10px; } -#forumlist-sidebar ul { +#group-list-sidebar ul { list-style: none; } @@ -1911,7 +1911,7 @@ a.mail-list-link { #search-save { margin-left: 5px; } -.groupsideedit { +.circlesideedit { margin-right: 10px; } #saved-search-ul { @@ -2180,7 +2180,7 @@ aside input[type='text'] { margin-left: 200px; } -.group-delete-wrapper { +.circle-delete-wrapper { float: right; margin-right: 50px; } @@ -2546,7 +2546,7 @@ aside input[type='text'] { margin-bottom: 15px; } -#group-members { +#circle-members { margin-top: 20px; padding: 10px; height: 250px; @@ -2554,28 +2554,28 @@ aside input[type='text'] { border: 1px solid #ddd; } -#group-members-end { +#circle-members-end { clear: both; } -#group-separator { +#circle-separator { margin-top: 10px; margin-bottom: 10px; } -#group-all-contacts { +#circle-all-contacts { padding: 10px; height: 450px; overflow: auto; border: 1px solid #ddd; } -#group-all-contacts-end { +#circle-all-contacts-end { clear: both; margin-bottom: 10px; } -#group-edit-desc { +#circle-edit-desc { margin-top: 15px; } diff --git a/view/theme/duepuntozero/theme.php b/view/theme/duepuntozero/theme.php index 985e062ac..71278c659 100644 --- a/view/theme/duepuntozero/theme.php +++ b/view/theme/duepuntozero/theme.php @@ -69,14 +69,14 @@ $(document).ready(function() { $('html').click(function() { $("#nav-notifications-menu" ).hide(); }); - $('.group-edit-icon').hover( + $('.circle-edit-icon').hover( function() { $(this).addClass('icon'); $(this).removeClass('iconspacer');}, function() { $(this).removeClass('icon'); $(this).addClass('iconspacer');} ); - $('.sidebar-group-element').hover( + $('.sidebar-circle-element').hover( function() { id = $(this).attr('id'); $('#edit-' + id).addClass('icon'); $('#edit-' + id).removeClass('iconspacer');}, diff --git a/view/theme/frio/README.md b/view/theme/frio/README.md index 4bf530007..db739a0aa 100644 --- a/view/theme/frio/README.md +++ b/view/theme/frio/README.md @@ -20,7 +20,7 @@ This theme should be the start of a discussion in the friendica community (users What frameworks do we want to use? How should default friendica look like? And how do we want to use friendica? What do we need in the core code (At the present time some stuff this is done with ugly javascript hacks and own php code)? Coding a theme is much work but you will get a really good insight of the limitations of friendica and can start a discussion about doing things differently. -So join the discussion at the friendica forums ;-) +So join the discussion at the friendica groups ;-) If anyone wants to contribute to this theme he/she is welcome to do this. diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 0758988fc..aacebdbe4 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -367,8 +367,8 @@ btn-eventnav:hover { aside .badge { opacity: 0.7; } -.forum-widget-entry .badge, -.sidebar-group-li .badge { +.group-widget-entry .badge, +.sidebar-circle-li .badge { margin-top: 6px; } @@ -1102,7 +1102,7 @@ aside .widget li a:hover { color: $font_color_darker; } -/* forumlist widget */ +/* group-list widget */ aside > #datebrowse-sidebar li.posted-date-selector-months { margin-bottom: 10px; padding: 0; @@ -1122,7 +1122,7 @@ aside > #datebrowse-sidebar .posted-date-selector-months > ul > li:hover { padding-left: 27px; } -.forumlist-img { +.group-list-img { -webkit-filter: grayscale(100%); filter: grayscale(100%); opacity: 0.5; @@ -1133,7 +1133,7 @@ aside > #datebrowse-sidebar .posted-date-selector-months > ul > li:hover { -ms-transition: all 0.2s ease-in-out; transition: all 0.2s ease-in-out; } -#forumlist-sidebar-ul li:hover a > .forumlist-img { +#group-list-sidebar-ul li:hover a > .group-list-img { -webkit-filter: unset; filter: unset; opacity: unset; @@ -1303,23 +1303,27 @@ aside #follow-sidebar .form-group-search .form-button-search { padding: 2px 8px; } +div#sidebar-circle-header h3, div#sidebar-group-header h3 { float: left; } +div#sidebar-circle-list, div#sidebar-group-list { clear: both; } -.group-new-form { +.circle-new-form { clear: both; } -.group-edit-tool { +.circle-edit-tool, +.group-new-tool { padding-top: 0; color: $font_color_darker; } -.sidebar-widget-header .group-edit-tool { +.sidebar-widget-header .circle-edit-tool, +.group-new-tool { margin-top: -5px; } @@ -1339,24 +1343,26 @@ div#sidebar-group-list { aside .widget-action { padding: 5px 10px; } -aside #group-sidebar .sidebar-group-li .group-edit-tool.faded-icon:hover, +aside #circle-sidebar .sidebar-circle-li .circle-edit-tool.faded-icon:hover, +aside #group-sidebar .group-new-tool.faded-icon:hover, aside #saved-search-list .saved-search-li .savedsearchdrop.faded-icon:hover, aside .widget.widget-action.faded-icon:hover { opacity: 0.8; transition: all 0.25s ease-in-out; } -aside #group-sidebar .sidebar-group-li .group-edit-tool.faded-icon:hover, +aside #circle-sidebar .sidebar-circle-li .circle-edit-tool.faded-icon:hover, +aside #group-sidebar .group-new-tool.faded-icon:hover, aside #saved-search-list .saved-search-li .savedsearchdrop.faded-icon:hover, aside .widget .widget-action.faded-icon:hover { opacity: 1; } -aside #group-sidebar li .group-checkbox { +aside #circle-sidebar li .circle-checkbox { margin: 6px 0 0; } -aside #group-sidebar li .group-edit-tool { +aside #circle-sidebar li .circle-edit-tool { padding-right: 10px; } -aside #group-sidebar li .group-edit-tool:first-child { +aside #circle-sidebar li .circle-edit-tool:first-child { padding-right: 0px; } @@ -2192,7 +2198,7 @@ nav .acpopup { border-left: 3px solid $link_color; padding-left: 17px !important; } -.textcomplete-item a .forum { +.textcomplete-item a .group { color: $link_color; } img.acpopup-img { @@ -2448,7 +2454,7 @@ section > .generic-page-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, -.nogroup-content-wrapper, +.nocircle-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, @@ -2494,7 +2500,7 @@ body.mod-login .navbar #nav-login { margin-top: 20px; margin-bottom: 20px; } -.contact-block-div.forumlist-profile-advanced { +.contact-block-div.group-list-profile-advanced { float: left; } @@ -2597,70 +2603,70 @@ ul li:hover .contact-wrapper .contact-action-link:hover { padding-top: 10px; } -/* group edit page */ -.group-actions { +/* circle edit page */ +.circle-actions { margin-top: 4px; margin-bottom: 10px; font-size: 30px; } -.group-actions button, -.group-actions a { +.circle-actions button, +.circle-actions a { font-size: 18px; } -.contact-group-actions .fa-times-circle { +.contact-circle-actions .fa-times-circle { color: #d00000; } -.contact-group-actions .fa-plus-circle { +.contact-circle-actions .fa-plus-circle { color: #008000; } -#group-edit-wrapper { +#circle-edit-wrapper { margin-top: 14px; display: none; } -#group-edit-header { +#circle-edit-header { display: block; } -#group-update-wrapper .contact-photo-overlay { +#circle-update-wrapper .contact-photo-overlay { display: none; } -#group-update-wrapper .viewcontact_wrapper .contact-group-actions { +#circle-update-wrapper .viewcontact_wrapper .contact-circle-actions { height: 100%; display: flex; flex-direction: column; justify-content: center; } -#group-update-wrapper .viewcontact_wrapper .contact-group-link { +#circle-update-wrapper .viewcontact_wrapper .contact-circle-link { opacity: 0.8; font-size: 20px; } -#group-update-wrapper .viewcontact_wrapper .contact-action-link:hover { +#circle-update-wrapper .viewcontact_wrapper .contact-action-link:hover { opacity: 1; } -#group-update-wrapper .shortmode { +#circle-update-wrapper .shortmode { height: 53px; overflow: hidden; } -#group-update-wrapper .shortmode .contact-photo { +#circle-update-wrapper .shortmode .contact-photo { height: 32px; width: 32px; } -#group-update-wrapper .shortmode .media { +#circle-update-wrapper .shortmode .media { overflow: hidden; } -#group-update-wrapper .shortmode .contact-entry-desc { +#circle-update-wrapper .shortmode .contact-entry-desc { font-size: 12px !important; } -#group-update-wrapper .shortmode .contact-entry-desc h4.media-heading { +#circle-update-wrapper .shortmode .contact-entry-desc h4.media-heading { margin: 0; } -#group-update-wrapper .shortmode .contact-entry-desc h4.media-heading a { +#circle-update-wrapper .shortmode .contact-entry-desc h4.media-heading a { font-size: 13px !important; white-space: nowrap; } -#group-update-wrapper .shortmode .contact-entry-desc .contact-entry-rel, -#group-update-wrapper .shortmode .contact-entry-desc .contact-entry-network { +#circle-update-wrapper .shortmode .contact-entry-desc .contact-entry-rel, +#circle-update-wrapper .shortmode .contact-entry-desc .contact-entry-network { display: none; } @@ -3063,6 +3069,7 @@ details.profile-jot-net[open] summary:before { content: "\f0da"; /* Right Plain Pointer */ } .widget > .fakelink > h3:before, +#sidebar-circle-header > .fakelink > h3:before, #sidebar-group-header > .fakelink > h3:before { font-family: ForkAwesome; content: "\f0d7"; /* Bottom Plain Pointer */ @@ -3804,7 +3811,7 @@ section .profile-match-wrapper { .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, - .nogroup-content-wrapper, + .nocircle-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, diff --git a/view/theme/frio/js/mod_group.js b/view/theme/frio/js/mod_circle.js similarity index 52% rename from view/theme/frio/js/mod_group.js rename to view/theme/frio/js/mod_circle.js index 3e69d581a..49b7db17c 100644 --- a/view/theme/frio/js/mod_group.js +++ b/view/theme/frio/js/mod_circle.js @@ -1,67 +1,67 @@ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later /** - * @file view/theme/frio/js/mod_group.js - * The javascript for the group module + * @file view/theme/frio/js/mod_circle.js + * The javascript for the circle module */ $(document).ready(function () { // Add an event listeners on buttons for switching the contact list view - $("body").on("click", ".group-list-switcher", function () { - switchGroupViewMode(this); + $("body").on("click", ".circle-list-switcher", function () { + switchCircleViewMode(this); }); }); /** - * Change the group membership of the contacts and fetch the new grup list + * Change the circle membership of the contacts and fetch the new grup list * as html * - * @param {int} gid The group ID + * @param {int} gid The circle ID * @param {int} cid The contact ID * @param {string} sec_token The security token * * @returns {undefined} */ -function groupChangeMember(gid, cid, sec_token) { +function circleChangeMember(gid, cid, sec_token) { $("#contact-entry-wrapper-" + cid).fadeTo("fast", 0.33); $(".tooltip").tooltip("hide"); $("body").css("cursor", "wait"); - $.get("group/" + gid + "/" + cid + "?t=" + sec_token, function (data) { - // Insert the new group member list - $("#group-update-wrapper").html(data); + $.get("circle/" + gid + "/" + cid + "?t=" + sec_token, function (data) { + // Insert the new circle member list + $("#circle-update-wrapper").html(data); - // Apply the actual group list view mode to the new - // group list html - var activeMode = $(".group-list-switcher.active"); - switchGroupViewMode(activeMode[0]); + // Apply the actual circle list view mode to the new + // circle list html + var activeMode = $(".circle-list-switcher.active"); + switchCircleViewMode(activeMode[0]); $("body").css("cursor", "auto"); }); } /** - * Change the group list view mode + * Change the circle list view mode * * @param {object} elm The button element of the view mode switcher * @returns {undefined} */ -function switchGroupViewMode(elm) { - // Remove the active class from group list switcher buttons - $(".group-list-switcher").removeClass("active"); +function switchCircleViewMode(elm) { + // Remove the active class from circle list switcher buttons + $(".circle-list-switcher").removeClass("active"); // And add it to the active button element $(elm).addClass("active"); - // Add or remove the css classes for the group list with regard to the active view mode - if (elm.id === "group-list-small") { - $("#contact-group-list > li").addClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12"); + // Add or remove the css classes for the circle list with regard to the active view mode + if (elm.id === "circle-list-small") { + $("#contact-circle-list > li").addClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12"); } else { - $("#contact-group-list > li").removeClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12"); + $("#contact-circle-list > li").removeClass("shortmode col-lg-6 col-md-6 col-sm-6 col-xs-12"); } } /** - * Filter the group member list for contacts + * Filter the circle member list for contacts * * @returns {undefined} */ @@ -70,7 +70,7 @@ function filterList() { var input, filter, ul, li, a, i; input = document.getElementById("contacts-search"); filter = input.value.toUpperCase(); - li = document.querySelectorAll("#contact-group-list>li"); + li = document.querySelectorAll("#contact-circle-list>li"); // Loop through all list items, and hide those who don't match the search query for (i = 0; i < li.length; i++) { diff --git a/view/theme/frio/js/mod_events.js b/view/theme/frio/js/mod_events.js index 4ac669a35..c811760fb 100644 --- a/view/theme/frio/js/mod_events.js +++ b/view/theme/frio/js/mod_events.js @@ -136,11 +136,11 @@ $(document).ready(function () { .trigger("change"); // JS for the permission section. - $("#contact_allow, #contact_deny, #group_allow, #group_deny") + $("#contact_allow, #contact_deny, #circle_allow, #circle_deny") .change(function () { var selstr; $( - "#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected", + "#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected", ).each(function () { selstr = $(this).html(); $("#jot-public").hide(); diff --git a/view/theme/frio/js/mod_photos.js b/view/theme/frio/js/mod_photos.js index 89a7ba758..165b422ba 100644 --- a/view/theme/frio/js/mod_photos.js +++ b/view/theme/frio/js/mod_photos.js @@ -1,11 +1,11 @@ // @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPLv3-or-later $(document).ready(function () { - $("#contact_allow, #contact_deny, #group_allow, #group_deny") + $("#contact_allow, #contact_deny, #circle_allow, #circle_deny") .change(function () { var selstr; $( - "#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected", + "#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected", ).each(function () { selstr = $(this).html(); $("#jot-perms-icon").removeClass("unlock").addClass("lock"); diff --git a/view/theme/frio/js/textedit.js b/view/theme/frio/js/textedit.js index 94f1dd158..3a384bbb2 100644 --- a/view/theme/frio/js/textedit.js +++ b/view/theme/frio/js/textedit.js @@ -210,6 +210,10 @@ function confirmCollapse() { return confirm(aStr.collapseAuthor); } +function confirmIgnoreServer() { + return confirm(aStr.ignoreServer + "\n" + aStr.ignoreServerDesc); +} + /** * Hide and removes an item element from the DOM after the deletion url is * successful, restore it else. @@ -325,4 +329,34 @@ function collapseAuthor(url, elementId) { }); } } + + +/** + * Ignore author server + * + * @param {string} url The server ignore URL + * @param {string} elementId The DOM id of the item element + * @returns {undefined} + */ +function ignoreServer(url, elementId) { + if (confirmIgnoreServer()) { + $("body").css("cursor", "wait"); + + var $el = $(document.getElementById(elementId)); + + $el.fadeTo("fast", 0.33, function () { + $.post(url) + .then(function () { + $el.remove(); + }) + .fail(function () { + // @todo Show related error message + $el.fadeTo("fast", 1); + }) + .always(function () { + $("body").css("cursor", "auto"); + }); + }); + } +} // @license-end diff --git a/view/theme/frio/js/theme.js b/view/theme/frio/js/theme.js index 3846c2c3e..ef71b8c1d 100644 --- a/view/theme/frio/js/theme.js +++ b/view/theme/frio/js/theme.js @@ -36,14 +36,14 @@ $(document).ready(function () { return false; }); - // add the class "selected" to group widgets li if li > a does have the class group-selected - if ($("#sidebar-group-ul li a").hasClass("group-selected")) { - $("#sidebar-group-ul li a.group-selected").parent("li").addClass("selected"); + // add the class "selected" to circle widgets li if li > a does have the class circle-selected + if ($("#sidebar-circle-ul li a").hasClass("circle-selected")) { + $("#sidebar-circle-ul li a.circle-selected").parent("li").addClass("selected"); } - // add the class "selected" to forums widgets li if li > a does have the class forum-selected - if ($("#forumlist-sidebar-ul li a").hasClass("forum-selected")) { - $("#forumlist-sidebar-ul li a.forum-selected").parent("li").addClass("selected"); + // add the class "selected" to groups widgets li if li > a does have the class group-selected + if ($("#group-list-sidebar-ul li a").hasClass("group-selected")) { + $("#group-list-sidebar-ul li a.group-selected").parent("li").addClass("selected"); } // add the class "active" to tabmenuli if li > a does have the class active @@ -206,7 +206,7 @@ $(document).ready(function () { }); } - // move the forum contact information of the network page into the second navbar + // move the group contact information of the network page into the second navbar if ($(".network-content-wrapper > #viewcontact_wrapper-network").length) { // get the contact-wrapper element and append it to the second nav bar // Note: We need the first() element with this class since at the present time we diff --git a/view/theme/frio/php/default.php b/view/theme/frio/php/default.php index a75207a20..74c30f6f7 100644 --- a/view/theme/frio/php/default.php +++ b/view/theme/frio/php/default.php @@ -137,12 +137,12 @@ $is_singleuser_class = $is_singleuser ? "is-singleuser" : "is-not-singleuser"; '; } else { echo ' -
'; +
'; if (!empty($page['content'])) { echo $page['content']; } echo ' -
+ '; } ?> diff --git a/view/theme/frio/scheme/black.css b/view/theme/frio/scheme/black.css index e6026b4de..debf9d99b 100644 --- a/view/theme/frio/scheme/black.css +++ b/view/theme/frio/scheme/black.css @@ -351,7 +351,7 @@ section > .generic-page-wrapper, .dfrn_request-content-wrapper, .friendica-content-wrapper, .credits-content-wrapper, -.nogroup-content-wrapper, +.nocircle-content-wrapper, .profperm-content-wrapper, .invite-content-wrapper, .tos-content-wrapper, diff --git a/view/theme/frio/templates/admin/site.tpl b/view/theme/frio/templates/admin/site.tpl index 4d0553b0c..e440451a6 100644 --- a/view/theme/frio/templates/admin/site.tpl +++ b/view/theme/frio/templates/admin/site.tpl @@ -242,7 +242,7 @@
- {{include file="field_checkbox.tpl" field=$compute_group_counts}} + {{include file="field_checkbox.tpl" field=$compute_circle_counts}} {{include file="field_checkbox.tpl" field=$only_tag_search}} {{include file="field_input.tpl" field=$max_comments}} {{include file="field_input.tpl" field=$max_display_comments}} diff --git a/view/theme/frio/templates/circle_drop.tpl b/view/theme/frio/templates/circle_drop.tpl new file mode 100644 index 000000000..169b1e6ed --- /dev/null +++ b/view/theme/frio/templates/circle_drop.tpl @@ -0,0 +1,5 @@ + +{{* Link for deleting contact circles *}} + + + diff --git a/view/theme/frio/templates/group_edit.tpl b/view/theme/frio/templates/circle_edit.tpl similarity index 53% rename from view/theme/frio/templates/group_edit.tpl rename to view/theme/frio/templates/circle_edit.tpl index 0a8dc3d2d..49c41f201 100644 --- a/view/theme/frio/templates/group_edit.tpl +++ b/view/theme/frio/templates/circle_edit.tpl @@ -1,15 +1,15 @@ -{{* This template is for the "group" module. It provides the user the possibility to - modify a specific contact group (remove contact group, edit contact group name, - add or remove contacts to the contact group. +{{* This template is for the "circle" module. It provides the user the possibility to + modify a specific contact circle (remove contact circle, edit contact circle name, + add or remove contacts to the contact circle. *}} - +
{{if $editable == 1}} - {{* The buttons for editing the contact group (edit name / remove contact group) *}} -
- {{if $drop}}{{$drop nofilter}}{{/if}} @@ -17,20 +17,20 @@ {{/if}}
-
+

{{$title}}

- {{* Edit the name of the group *}} -
+ {{* Edit the name of the circle *}} +
-
+
{{include file="field_input.tpl" field=$gname label=false}}
-
+
@@ -55,21 +55,21 @@
- {{if $groupeditor}} + {{if $circle_editor}} {{* The buttons to switch between the different view modes *}} -
- -
- {{* The contact group list *}} -
- {{include file="groupeditor.tpl"}} + {{* The contact circle list *}} +
+ {{include file="circle_editor.tpl"}}
{{/if}}
diff --git a/view/theme/frio/templates/circle_editor.tpl b/view/theme/frio/templates/circle_editor.tpl new file mode 100644 index 000000000..a013359f5 --- /dev/null +++ b/view/theme/frio/templates/circle_editor.tpl @@ -0,0 +1,19 @@ + +{{* Template for the contact circle list *}} +
+ +
    + + {{* The contacts who are already members of the contact circle *}} + {{foreach $circle_editor.members as $contact}} +
  • {{include file="contact/entry.tpl"}}
  • + {{/foreach}} + + {{* The contacts who are not members of the contact circle *}} + {{foreach $circle_editor.contacts as $contact}} +
  • {{include file="contact/entry.tpl"}}
  • + {{/foreach}} + +
+
+
diff --git a/view/theme/frio/templates/circle_side.tpl b/view/theme/frio/templates/circle_side.tpl new file mode 100644 index 000000000..d24ce0c81 --- /dev/null +++ b/view/theme/frio/templates/circle_side.tpl @@ -0,0 +1,60 @@ + +

{{$title}}

+
+
+ + +
+ diff --git a/view/theme/frio/templates/comment_item.tpl b/view/theme/frio/templates/comment_item.tpl index b5fc13deb..c81d259b4 100644 --- a/view/theme/frio/templates/comment_item.tpl +++ b/view/theme/frio/templates/comment_item.tpl @@ -39,6 +39,9 @@ +

diff --git a/view/theme/frio/templates/contact/entry.tpl b/view/theme/frio/templates/contact/entry.tpl index d4796a7ee..75f0d6d9e 100644 --- a/view/theme/frio/templates/contact/entry.tpl +++ b/view/theme/frio/templates/contact/entry.tpl @@ -76,7 +76,7 @@ {{* The button to add or remove contacts from a contact group - group edit page *}} {{if $contact.change_member}} {{* End of contact-edit-status-wrapper *}} diff --git a/view/theme/frio/templates/field_colorinput.tpl b/view/theme/frio/templates/field_colorinput.tpl index 2c530a2e4..f812ff234 100644 --- a/view/theme/frio/templates/field_colorinput.tpl +++ b/view/theme/frio/templates/field_colorinput.tpl @@ -1,9 +1,8 @@ -
- +
{{if $field.3}} {{$field.3 nofilter}} diff --git a/view/theme/frio/templates/field_fileinput.tpl b/view/theme/frio/templates/field_fileinput.tpl index dd6825f2e..96ae45596 100644 --- a/view/theme/frio/templates/field_fileinput.tpl +++ b/view/theme/frio/templates/field_fileinput.tpl @@ -1,8 +1,7 @@ -
- +
{{if $field.3}} diff --git a/view/theme/frio/templates/field_openid.tpl b/view/theme/frio/templates/field_openid.tpl index bae9cb4fc..c36dbfabc 100644 --- a/view/theme/frio/templates/field_openid.tpl +++ b/view/theme/frio/templates/field_openid.tpl @@ -1,7 +1,6 @@ -
- + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/theme/frio/templates/field_password.tpl b/view/theme/frio/templates/field_password.tpl index 25a7d0c4c..0fb27ca88 100644 --- a/view/theme/frio/templates/field_password.tpl +++ b/view/theme/frio/templates/field_password.tpl @@ -1,7 +1,6 @@ -
- + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/theme/frio/templates/field_textarea.tpl b/view/theme/frio/templates/field_textarea.tpl index 72bcc232a..ef9838f56 100644 --- a/view/theme/frio/templates/field_textarea.tpl +++ b/view/theme/frio/templates/field_textarea.tpl @@ -2,7 +2,7 @@ {{if $field.1}} {{/if}} - + {{if $field.3}} {{$field.3 nofilter}} {{/if}} diff --git a/view/theme/frio/templates/group_drop.tpl b/view/theme/frio/templates/group_drop.tpl deleted file mode 100644 index edd27cc64..000000000 --- a/view/theme/frio/templates/group_drop.tpl +++ /dev/null @@ -1,5 +0,0 @@ - -{{* Link for deleting contact groups *}} - - - diff --git a/view/theme/frio/templates/group_side.tpl b/view/theme/frio/templates/group_side.tpl deleted file mode 100644 index f9027e612..000000000 --- a/view/theme/frio/templates/group_side.tpl +++ /dev/null @@ -1,60 +0,0 @@ - -

{{$title}}

-
-
- - -
- diff --git a/view/theme/frio/templates/groupeditor.tpl b/view/theme/frio/templates/groupeditor.tpl deleted file mode 100644 index 5ec157114..000000000 --- a/view/theme/frio/templates/groupeditor.tpl +++ /dev/null @@ -1,19 +0,0 @@ - -{{* Template for the contact group list *}} -
- -
    - - {{* The contacts who are already members of the contact group *}} - {{foreach $groupeditor.members as $contact}} -
  • {{include file="contact/entry.tpl"}}
  • - {{/foreach}} - - {{* The contacts who are not members of the contact group *}} - {{foreach $groupeditor.contacts as $contact}} -
  • {{include file="contact/entry.tpl"}}
  • - {{/foreach}} - -
-
-
diff --git a/view/theme/frio/templates/head.tpl b/view/theme/frio/templates/head.tpl index 9e960bdc9..742a5203b 100644 --- a/view/theme/frio/templates/head.tpl +++ b/view/theme/frio/templates/head.tpl @@ -51,8 +51,6 @@ type="text/css" media="screen" /> - {{* own css files *}}
  • +
  • diff --git a/view/theme/frio/templates/js_strings.tpl b/view/theme/frio/templates/js_strings.tpl index f979355d7..8077ceb9e 100644 --- a/view/theme/frio/templates/js_strings.tpl +++ b/view/theme/frio/templates/js_strings.tpl @@ -3,10 +3,12 @@ They are loaded into the html so that js functions can use them *}} + +
    +

    {{$title}}

    + + +
    diff --git a/view/theme/quattro/templates/widget_forumlist.tpl b/view/theme/quattro/templates/widget_forumlist.tpl deleted file mode 100644 index 1902358f9..000000000 --- a/view/theme/quattro/templates/widget_forumlist.tpl +++ /dev/null @@ -1,46 +0,0 @@ - - -
    -

    {{$title}}

    - - -
    diff --git a/view/theme/smoothly/style.css b/view/theme/smoothly/style.css index 3489de031..3e38030b9 100644 --- a/view/theme/smoothly/style.css +++ b/view/theme/smoothly/style.css @@ -843,7 +843,7 @@ h3 #search:before { -moz-border-radius: 5px; } -#group-sidebar { +#circle-sidebar { vertical-align: middle; margin: auto; margin-top: 20px; @@ -877,20 +877,20 @@ h3 #search:before { margin-left: 10px; } -#sidebar-group-list { +#sidebar-circle-list { margin-left: 0px; margin-right: 30px; } -#sidebar-ungrouped { +#sidebar-uncircled { margin: 10px; } -#sidebar-group-list a { +#sidebar-circle-list a { } -#sidebar-group-list .icon, -#sidebar-group-list .iconspacer { +#sidebar-circle-list .icon, +#sidebar-circle-list .iconspacer { display: inline-block; height: 12px; width: 12px; @@ -930,8 +930,9 @@ li.widget-list { padding: 3px 24px; } -#sidebar-new-group, -#sidebar-edit-groups { +#sidebar-new-circle, +#sidebar-edit-circles, +#sidebar-new-group { padding: 7px; width: 165px; margin: auto; @@ -951,7 +952,7 @@ li.widget-list { } -#sidebar-new-group:hover { +#sidebar-new-circle:hover { background: -webkit-gradient( linear, left top, left bottom, color-stop(0.05, #1873a2), color-stop(1, #6da6c4) ); background: -moz-linear-gradient( center top, #1873a2 5%, #6da6c4 100% ); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1873a2', endColorstr='#6da6c4'); @@ -965,14 +966,14 @@ li.widget-list { -webkit-border-radius: 5px; } -#sidebar-new-group:active { +#sidebar-new-circle:active { position: relative; top: 1px; } .widget .selected, -.group-selected { +.circle-selected { padding-bottom: 0px; padding-left: 2px; padding-right: 2px; @@ -995,19 +996,19 @@ li.widget-list { font-weight: bold; } -#sidebar-new-group a { +#sidebar-new-circle a { color: #efefef; font-size: 14px; text-align: center; margin: auto; } -ul .sidebar-group-li { +ul .sidebar-circle-li { list-style: disc; font-size: 1.0em; } -ul .sidebar-group-li .icon { +ul .sidebar-circle-li .icon { display: inline-block; height: 12px; width: 12px; @@ -1067,8 +1068,8 @@ ul .sidebar-group-li .icon { margin-left: 10px; } -#group-sidebar h3:before { - content: url("images/groups.png"); +#circle-sidebar h3:before { + content: url("images/circles.png"); padding-right: 10px; vertical-align: middle; } @@ -1364,8 +1365,8 @@ ul .sidebar-group-li .icon { #profile-nolocation-wrapper { } -#group_allow_wrapper, -#group_deny_wrapper, +#circle_allow_wrapper, +#circle_deny_wrapper, #acl-permit-outer-wrapper { width: 47%; float: left; @@ -3357,22 +3358,22 @@ margin-left: 0px; /* = Contacts Selector = */ /* ===================== */ -#group-edit-wrapper { +#circle-edit-wrapper { margin-bottom: 10px; } -#group-edit-name-wrapper { +#circle-edit-name-wrapper { margin-bottom: 0px; display: inline; } -#group-edit-submit-wrapper { +#circle-edit-submit-wrapper { margin-bottom: 10px; margin-right: 400px; float: right; display: inline; } -.group-delete-wrapper { +.circle-delete-wrapper { width: 90px; display: inline; padding: 5px; @@ -3389,34 +3390,34 @@ margin-left: 0px; -webkit-border-radius: 5px; } -.group-delete-wrapper:hover { +.circle-delete-wrapper:hover { background: -webkit-gradient( linear, left top, left bottom, color-stop(0.05, #1873a2), color-stop(1, #6da6c4) ); background: -moz-linear-gradient( center top, #1873a2 5%, #6da6c4 100% ); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1873a2', endColorstr='#6da6c4'); background-color: #1873a2; } -.group-delete-wrapper:active { +.circle-delete-wrapper:active { background: -webkit-gradient( linear, left top, left bottom, color-stop(0.05, #1873a2), color-stop(1, #6da6c4) ); background: -moz-linear-gradient( center top, #1873a2 5%, #6da6c4 100% ); filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#1873a2', endColorstr='#6da6c4'); background-color: #1873a2; } -.group-delete-wrapper a { +.circle-delete-wrapper a { color: #efefef; font-size: 0.9em; } -#group-edit-desc { +#circle-edit-desc { margin: 10px 0xp; } -#group-new-text { +#circle-new-text { font-size: 1.1em; } -#group-members, +#circle-members, #prof-members { width: 83%; height: 200px; @@ -3429,7 +3430,7 @@ margin-left: 0px; padding: 10px; } -#group-all-contacts, +#circle-all-contacts, #prof-all-contacts { width: 83%; height: 200px; @@ -3439,8 +3440,8 @@ margin-left: 0px; padding: 10px; } -#group-members h3, -#group-all-contacts h3, +#circle-members h3, +#circle-all-contacts h3, #prof-members h3, #prof-all-contacts h3 { color: #555753; @@ -3448,7 +3449,7 @@ margin-left: 0px; padding: 5px; } -#group-separator, +#circle-separator, #prof-separator { display: none; } diff --git a/view/theme/smoothly/templates/jot-header.tpl b/view/theme/smoothly/templates/jot-header.tpl index 69233b926..d55d65fec 100644 --- a/view/theme/smoothly/templates/jot-header.tpl +++ b/view/theme/smoothly/templates/jot-header.tpl @@ -84,9 +84,9 @@ function enableOnUser(){ } } ); - $('#contact_allow, #contact_deny, #group_allow, #group_deny').change(function() { + $('#contact_allow, #contact_deny, #circle_allow, #circle_deny').change(function() { var selstr; - $('#contact_allow option:selected, #contact_deny option:selected, #group_allow option:selected, #group_deny option:selected').each( function() { + $('#contact_allow option:selected, #contact_deny option:selected, #circle_allow option:selected, #circle_deny option:selected').each( function() { selstr = $(this).html(); $('#jot-perms-icon').removeClass('unlock').addClass('lock'); $('#jot-public').hide(); diff --git a/view/theme/smoothly/templates/search_item.tpl b/view/theme/smoothly/templates/search_item.tpl index 94d713267..89d51701a 100644 --- a/view/theme/smoothly/templates/search_item.tpl +++ b/view/theme/smoothly/templates/search_item.tpl @@ -5,8 +5,8 @@
    -
    {{$item.name}} @@ -17,16 +17,16 @@
    -
    +
    {{if $item.location_html}}{{$item.location_html nofilter}} {{/if}}
    {{if $item.lock}}
    {{$item.lock}}
    - {{else}}
    {{/if}} + {{else}}
    {{/if}}
    - {{if $item.drop && $item.drop.dropping}}{{/if}} + {{if $item.drop && $item.drop.dropping}}{{/if}}
    {{if $item.drop && $item.drop.pagedrop}}{{/if}}
    @@ -39,9 +39,9 @@
    {{$item.name}}
    {{$item.ago}}
    - -
    - + +
    +
    diff --git a/view/theme/smoothly/templates/wall_thread.tpl b/view/theme/smoothly/templates/wall_thread.tpl index 53602cc8f..594799f6b 100644 --- a/view/theme/smoothly/templates/wall_thread.tpl +++ b/view/theme/smoothly/templates/wall_thread.tpl @@ -136,7 +136,7 @@
    {{if $item.drop && $item.drop.dropping}} - + {{/if}}
    diff --git a/view/theme/smoothly/theme.php b/view/theme/smoothly/theme.php index 73ff81441..48bfbfee6 100644 --- a/view/theme/smoothly/theme.php +++ b/view/theme/smoothly/theme.php @@ -59,14 +59,14 @@ $(document).ready(function() { $('html').click(function() { $("#nav-notifications-menu" ).hide(); }); - $('.group-edit-icon').hover( + $('.circle-edit-icon').hover( function() { $(this).addClass('icon'); $(this).removeClass('iconspacer');}, function() { $(this).removeClass('icon'); $(this).addClass('iconspacer');} ); - $('.sidebar-group-element').hover( + $('.sidebar-circle-element').hover( function() { id = $(this).attr('id'); $('#edit-' + id).addClass('icon'); $('#edit-' + id).removeClass('iconspacer');}, diff --git a/view/theme/vier/config.php b/view/theme/vier/config.php index 0a559c45c..fceed7b1f 100644 --- a/view/theme/vier/config.php +++ b/view/theme/vier/config.php @@ -88,7 +88,7 @@ function theme_admin(App $a) { $t = Renderer::getMarkupTemplate("theme_admin_settings.tpl"); $o = Renderer::replaceMacros($t, [ - '$helperlist' => ['vier_helperlist', DI::l10n()->t('Comma separated list of helper forums'), $helperlist, '', ''], + '$helperlist' => ['vier_helperlist', DI::l10n()->t('Comma separated list of helper groups'), $helperlist, '', ''], ]); $show_pages = get_vier_config('show_pages', true, true); diff --git a/view/theme/vier/style.css b/view/theme/vier/style.css index a1713a604..b2ef72f5f 100644 --- a/view/theme/vier/style.css +++ b/view/theme/vier/style.css @@ -393,10 +393,10 @@ pre code { } #saved-search-ul .tool:hover, #nets-sidebar .tool:hover, -#sidebar-group-list .tool:hover { +#sidebar-circle-list .tool:hover { background: #EEE; } -/*#sidebar-group-list .notify { +/*#sidebar-circle-list .notify { min-width: 10px; text-align: center; color: #FFF; @@ -406,10 +406,10 @@ pre code { border-radius: 10px; display: none; }*/ -#sidebar-group-list .notify { +#sidebar-circle-list .notify { display: none; } -#sidebar-group-list .notify.show { +#sidebar-circle-list .notify.show { display: inline-block; } .tool .label { @@ -421,22 +421,22 @@ pre code { .tool a { /* color: #000; */ } -.tool a:hover, .widget a:hover, #nets-sidebar a:hover, #forum-widget-collapse:hover, .admin.link a:hover, aside h4 a:hover, right_aside h4 a:hover { +.tool a:hover, .widget a:hover, #nets-sidebar a:hover, #group-widget-collapse:hover, .admin.link a:hover, aside h4 a:hover, right_aside h4 a:hover { /* text-decoration: underline; */ text-decoration: none; color: black; } -.groupsideedit, .savedsearchdrop { +.circlesideedit, .savedsearchdrop { float: right; opacity: 0.3; } -.groupsideedit:hover, .savedsearchdrop:hover { +.circlesideedit:hover, .savedsearchdrop:hover { opacity: 1; } -.sidebar-group-li:hover, #sidebar-new-group:hover, #sidebar-edit-groups:hover,#forum-widget-collapse:hover, -#sidebar-ungrouped:hover, .side-link:hover, .nets-ul li:hover, #forumlist-sidebar li:hover, #forumlist-sidebar-right li:hover, +.sidebar-circle-li:hover, #sidebar-new-circle:hover, #sidebar-edit-circles:hover, #sidebar-new-group:hover, #group-widget-collapse:hover, +#sidebar-uncircled:hover, .side-link:hover, .nets-ul li:hover, #group-list-sidebar li:hover, #group-list-sidebar-right li:hover, .nets-all:hover, .saved-search-li:hover, li.tool:hover, .admin.link:hover, aside h4 a:hover, right_aside h4 a:hover, #message-new:hover, #sidebar-photos-albums li:hover, .photos-upload-link:hover, .textcomplete-item.active { /* background-color: #ddd; */ @@ -448,15 +448,15 @@ pre code { color: black; } -.sidebar-group-element { +.sidebar-circle-element { /* color: #000; */ } -.widget .selected, .forum-selected { +.widget .selected, .group-selected { font-weight: bold; } -#forum-widget-showmore, #sidebar-new-group, #sidebar-edit-groups, #forum-widget-collapse, #forumlist-rsidebar-right, #sidebar-ungrouped, +#group-widget-showmore, #sidebar-new-circle, #sidebar-edit-circles, #sidebar-new-group, #group-widget-collapse, #group-list-rsidebar-right, #sidebar-uncircled, .side-link, #peoplefind-desc, #connect-desc, .nets-all, .admin.link, #message-new { padding-left: 10px; padding-top: 3px; @@ -471,31 +471,31 @@ pre code { display: block; } -#forumlist-sidebar { +#group-list-sidebar { padding-top: 3px; padding-bottom: 3px; display: block; } -.forum-widget-entry { +.group-widget-entry { padding-left: 10px; padding-right: 5px; } -#forumlist-sidebar .notify, #forumlist-sidebar-right .notify { +#group-list-sidebar .notify, #group-list-sidebar-right .notify { display: none; } -#forumlist-sidebar .notify.show, #forumlist-sidebar-right .notify.show { +#group-list-sidebar .notify.show, #group-list-sidebar-right .notify.show { display: inline-block; } -a.nets-link, .side-link a, #sidebar-new-group a, #sidebar-edit-groups a, a.savedsearchterm,a.fileas-link, aside h4 a, right_aside h4 a { +a.nets-link, .side-link a, #sidebar-new-circle a, #sidebar-edit-circles a, #sidebar-new-group a, a.savedsearchterm,a.fileas-link, aside h4 a, right_aside h4 a { display: block; color: #737373; } -a.sidebar-group-element { +a.sidebar-circle-element { color: #737373; } @@ -509,19 +509,19 @@ a.sidebar-group-element { padding: 0; margin-left: 10px; } -#sidebar-ungrouped, .side-link { +#sidebar-uncircled, .side-link { padding-top: 5px; } -#sidebar-ungrouped a { +#sidebar-uncircled a { color: black; } -#forumlist-sidebar a, #forumlist-sidebar-right a, .tool a, .admin.link a, #sidebar-photos-albums a { +#group-list-sidebar a, #group-list-sidebar-right a, .tool a, .admin.link a, #sidebar-photos-albums a { color: #737373; } -#forumlist-sidebar, #forumlist-sidebar-right { +#group-list-sidebar, #group-list-sidebar-right { margin-top: 2px; } @@ -941,11 +941,11 @@ nav .acpopup { color: #000; padding: 3px 20px; } -.textcomplete-item a .forum, .forum .acpopup-sub-text { +.textcomplete-item a .group, .group .acpopup-sub-text { color: #36C; opacity: 0.8; } -.textcomplete-item a .forum:hover { +.textcomplete-item a .group:hover { opacity: 1.0; } img.acpopup-img { @@ -1213,13 +1213,13 @@ aside img { width: 48px; height: 48px; } -.group_selected { +.circle_selected { background: url("../../../view/theme/diabook/icons/selected.png") no-repeat left center; float: left; height: 22px; width: 22px; } -.group_unselected { +.circle_unselected { background: url("../../../view/theme/diabook/icons/unselected.png") no-repeat left center; float: left; height: 22px; @@ -2581,16 +2581,16 @@ blockquote { .contact-block-textdiv {width: 150px; height: 34px; float: left; } #contact-block-end {clear: both; } -#group-edit-wrapper { +#circle-edit-wrapper { margin-bottom: 10px; } -#group-members-end { +#circle-members-end { clear: both; } /* -#group-separator, +#circle-separator, #prof-separator {display: none;} */ @@ -3281,3 +3281,7 @@ fbrowser.photo .photo-album-image-wrapper { margin-left: 10px; } #colorbox img { max-width: 100%; } + +#settings-server td + td { + text-align: center; +} diff --git a/view/theme/vier/templates/nav.tpl b/view/theme/vier/templates/nav.tpl index 7cbc2eb1b..e8b9109ca 100644 --- a/view/theme/vier/templates/nav.tpl +++ b/view/theme/vier/templates/nav.tpl @@ -121,7 +121,7 @@ - {{if $nav.searchoption.3}}{{/if}} + {{if $nav.searchoption.3}}{{/if}} diff --git a/view/theme/vier/templates/search_item.tpl b/view/theme/vier/templates/search_item.tpl index e556335a5..51de297d3 100644 --- a/view/theme/vier/templates/search_item.tpl +++ b/view/theme/vier/templates/search_item.tpl @@ -80,7 +80,7 @@ {{/if}} {{if $item.drop && $item.drop.dropping}} - {{$item.drop.delete}} + {{$item.drop.label}} {{/if}} {{if $item.edpost}} diff --git a/view/theme/vier/templates/settings/profile/index.tpl b/view/theme/vier/templates/settings/profile/index.tpl deleted file mode 100644 index f52de3703..000000000 --- a/view/theme/vier/templates/settings/profile/index.tpl +++ /dev/null @@ -1,179 +0,0 @@ - - -

    {{$banner}}

    - - - - -
    -
    - - - -
    -

    {{$lbl_picture_section}} »

    - -
    -
    - -
    - - - -
    -

    {{$lbl_personal_section}} »

    - -
    - -
    -

    {{$lbl_location_section}} »

    - -
    - -
    -

    {{$lbl_custom_fields_section}} »

    - -
    -
    -
    - diff --git a/view/theme/vier/templates/wall_item_tag.tpl b/view/theme/vier/templates/wall_item_tag.tpl index c12cb7085..92cfaf914 100644 --- a/view/theme/vier/templates/wall_item_tag.tpl +++ b/view/theme/vier/templates/wall_item_tag.tpl @@ -3,12 +3,12 @@ {{else}} {{if $item.comment_firstcollapsed}}
    - {{$item.num_comments}} - {{$item.hide_text}} - {{if $item.thread_level==3}} - + {{if $item.thread_level==3}} - expand / @@ -32,7 +32,7 @@ - +
    {{$item.location_html nofilter}}
    @@ -44,7 +44,7 @@ {{/if}} {{if $item.drop && $item.drop.dropping}} - {{$item.drop.delete}} + {{$item.drop.label}} {{/if}}
    diff --git a/view/theme/vier/templates/widget_forumlist_right.tpl b/view/theme/vier/templates/widget_forumlist_right.tpl deleted file mode 100644 index 5716a6fb8..000000000 --- a/view/theme/vier/templates/widget_forumlist_right.tpl +++ /dev/null @@ -1,47 +0,0 @@ - - -
    -

    {{$title}}

    - - -
    diff --git a/view/theme/vier/theme.php b/view/theme/vier/theme.php index 95cc9bb1f..e26425162 100644 --- a/view/theme/vier/theme.php +++ b/view/theme/vier/theme.php @@ -27,7 +27,7 @@ */ use Friendica\App; -use Friendica\Content\ForumManager; +use Friendica\Content\GroupManager; use Friendica\Core\Addon; use Friendica\Core\Renderer; use Friendica\Core\Search; @@ -208,7 +208,7 @@ function vier_community_info() //Community_Pages at right_aside if ($show_pages && DI::userSession()->getLocalUserId()) { - $aside['$page'] = ForumManager::widget('network/forum', DI::userSession()->getLocalUserId());; + $aside['$page'] = GroupManager::widget('network/group', DI::userSession()->getLocalUserId());; } // END Community Page diff --git a/view/theme/vier/wide.css b/view/theme/vier/wide.css index 66aaf9221..6b62655b8 100644 --- a/view/theme/vier/wide.css +++ b/view/theme/vier/wide.css @@ -2,9 +2,9 @@ right_aside { display: block; } -aside #forumlist-sidebar-frame, -aside #forumlist-sidebar, -#forumlist-sidebar-inflated { +aside #group-list-sidebar-frame, +aside #group-list-sidebar, +#group-list-sidebar-inflated { display: none; }